m97j commited on
Commit
3ec134e
·
1 Parent(s): d7df365

Initial commit

Browse files
.dockerignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ node_modules
2
+ npm-debug.log
3
+ Dockerfile
4
+ .dockerignore
5
+ .git
6
+ .gitignore
7
+ frontend/.next/cache
.gitignore ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Node.js
2
+ node_modules
3
+ npm-debug.log*
4
+ yarn-debug.log*
5
+ yarn-error.log*
6
+ pnpm-debug.log*
7
+
8
+ # Build output
9
+ dist
10
+ .next
11
+ out
12
+
13
+ # Prisma
14
+ /prisma/generated/
15
+
16
+ # Environment variables
17
+ .env
18
+ .env.local
19
+ .env.development.local
20
+ .env.test.local
21
+ .env.production.local
22
+
23
+ # Logs
24
+ *.log
25
+
26
+ # OS / Editor files
27
+ .DS_Store
28
+ Thumbs.db
29
+ *.swp
30
+
31
+ # Temporary files
32
+ tmp.md
33
+ tmp
Dockerfile ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -----------------------------
2
+ # 빌드 단계
3
+ FROM node:20 AS build
4
+ WORKDIR /app
5
+
6
+ # 패키지 설치
7
+ COPY package*.json ./
8
+ RUN npm install
9
+
10
+ # 소스 복사
11
+ COPY . .
12
+
13
+ # Prisma Client 생성
14
+ RUN npx prisma generate
15
+
16
+ # TypeScript 빌드 + dist 확인
17
+ RUN npm run build && ls -al dist
18
+
19
+ # -----------------------------
20
+ # 런타임 단계
21
+ FROM node:20
22
+ WORKDIR /app
23
+
24
+ # package.json만 복사해서 prod deps 설치
25
+ COPY package*.json ./
26
+ RUN npm install --omit=dev
27
+
28
+ # 빌드 산출물과 Prisma Client 복사
29
+ COPY --from=build /app/dist ./dist
30
+ COPY --from=build /app/node_modules/.prisma ./node_modules/.prisma
31
+ COPY --from=build /app/prisma ./prisma
32
+
33
+ # 환경 변수 및 포트 설정
34
+ ENV NODE_ENV=production
35
+ EXPOSE 80
36
+
37
+ # 앱 실행
38
+ CMD ["node", "dist/index.js"]
check-env.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ // check-env.js
2
+ require('dotenv').config();
3
+ console.log("DATABASE_URL:", process.env.DATABASE_URL);
package-lock.json ADDED
@@ -0,0 +1,2195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "portfolio-backend",
3
+ "lockfileVersion": 3,
4
+ "requires": true,
5
+ "packages": {
6
+ "": {
7
+ "name": "portfolio-backend",
8
+ "dependencies": {
9
+ "@azure/storage-blob": "^12.17.0",
10
+ "@prisma/client": "^5.16.1",
11
+ "cookie-parser": "^1.4.7",
12
+ "cors": "^2.8.5",
13
+ "dotenv": "^17.2.3",
14
+ "express": "^4.19.2",
15
+ "jsonwebtoken": "^9.0.2"
16
+ },
17
+ "devDependencies": {
18
+ "@types/cookie-parser": "^1.4.9",
19
+ "@types/cors": "^2.8.19",
20
+ "@types/express": "^5.0.3",
21
+ "@types/jsonwebtoken": "^9.0.5",
22
+ "@types/node": "^24.7.2",
23
+ "@types/react": "^19.2.2",
24
+ "@types/react-dom": "^19.2.1",
25
+ "prisma": "^5.16.1",
26
+ "tsx": "^4.19.0",
27
+ "typescript": "^5.4.3"
28
+ }
29
+ },
30
+ "node_modules/@azure/abort-controller": {
31
+ "version": "2.1.2",
32
+ "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
33
+ "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
34
+ "license": "MIT",
35
+ "dependencies": {
36
+ "tslib": "^2.6.2"
37
+ },
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ }
41
+ },
42
+ "node_modules/@azure/core-auth": {
43
+ "version": "1.10.1",
44
+ "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz",
45
+ "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==",
46
+ "license": "MIT",
47
+ "dependencies": {
48
+ "@azure/abort-controller": "^2.1.2",
49
+ "@azure/core-util": "^1.13.0",
50
+ "tslib": "^2.6.2"
51
+ },
52
+ "engines": {
53
+ "node": ">=20.0.0"
54
+ }
55
+ },
56
+ "node_modules/@azure/core-client": {
57
+ "version": "1.10.1",
58
+ "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz",
59
+ "integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==",
60
+ "license": "MIT",
61
+ "dependencies": {
62
+ "@azure/abort-controller": "^2.1.2",
63
+ "@azure/core-auth": "^1.10.0",
64
+ "@azure/core-rest-pipeline": "^1.22.0",
65
+ "@azure/core-tracing": "^1.3.0",
66
+ "@azure/core-util": "^1.13.0",
67
+ "@azure/logger": "^1.3.0",
68
+ "tslib": "^2.6.2"
69
+ },
70
+ "engines": {
71
+ "node": ">=20.0.0"
72
+ }
73
+ },
74
+ "node_modules/@azure/core-http-compat": {
75
+ "version": "2.3.1",
76
+ "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.3.1.tgz",
77
+ "integrity": "sha512-az9BkXND3/d5VgdRRQVkiJb2gOmDU8Qcq4GvjtBmDICNiQ9udFmDk4ZpSB5Qq1OmtDJGlQAfBaS4palFsazQ5g==",
78
+ "license": "MIT",
79
+ "dependencies": {
80
+ "@azure/abort-controller": "^2.1.2",
81
+ "@azure/core-client": "^1.10.0",
82
+ "@azure/core-rest-pipeline": "^1.22.0"
83
+ },
84
+ "engines": {
85
+ "node": ">=20.0.0"
86
+ }
87
+ },
88
+ "node_modules/@azure/core-lro": {
89
+ "version": "2.7.2",
90
+ "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz",
91
+ "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==",
92
+ "license": "MIT",
93
+ "dependencies": {
94
+ "@azure/abort-controller": "^2.0.0",
95
+ "@azure/core-util": "^1.2.0",
96
+ "@azure/logger": "^1.0.0",
97
+ "tslib": "^2.6.2"
98
+ },
99
+ "engines": {
100
+ "node": ">=18.0.0"
101
+ }
102
+ },
103
+ "node_modules/@azure/core-paging": {
104
+ "version": "1.6.2",
105
+ "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz",
106
+ "integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==",
107
+ "license": "MIT",
108
+ "dependencies": {
109
+ "tslib": "^2.6.2"
110
+ },
111
+ "engines": {
112
+ "node": ">=18.0.0"
113
+ }
114
+ },
115
+ "node_modules/@azure/core-rest-pipeline": {
116
+ "version": "1.22.1",
117
+ "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.1.tgz",
118
+ "integrity": "sha512-UVZlVLfLyz6g3Hy7GNDpooMQonUygH7ghdiSASOOHy97fKj/mPLqgDX7aidOijn+sCMU+WU8NjlPlNTgnvbcGA==",
119
+ "license": "MIT",
120
+ "dependencies": {
121
+ "@azure/abort-controller": "^2.1.2",
122
+ "@azure/core-auth": "^1.10.0",
123
+ "@azure/core-tracing": "^1.3.0",
124
+ "@azure/core-util": "^1.13.0",
125
+ "@azure/logger": "^1.3.0",
126
+ "@typespec/ts-http-runtime": "^0.3.0",
127
+ "tslib": "^2.6.2"
128
+ },
129
+ "engines": {
130
+ "node": ">=20.0.0"
131
+ }
132
+ },
133
+ "node_modules/@azure/core-tracing": {
134
+ "version": "1.3.1",
135
+ "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz",
136
+ "integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==",
137
+ "license": "MIT",
138
+ "dependencies": {
139
+ "tslib": "^2.6.2"
140
+ },
141
+ "engines": {
142
+ "node": ">=20.0.0"
143
+ }
144
+ },
145
+ "node_modules/@azure/core-util": {
146
+ "version": "1.13.1",
147
+ "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz",
148
+ "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==",
149
+ "license": "MIT",
150
+ "dependencies": {
151
+ "@azure/abort-controller": "^2.1.2",
152
+ "@typespec/ts-http-runtime": "^0.3.0",
153
+ "tslib": "^2.6.2"
154
+ },
155
+ "engines": {
156
+ "node": ">=20.0.0"
157
+ }
158
+ },
159
+ "node_modules/@azure/core-xml": {
160
+ "version": "1.5.0",
161
+ "resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.5.0.tgz",
162
+ "integrity": "sha512-D/sdlJBMJfx7gqoj66PKVmhDDaU6TKA49ptcolxdas29X7AfvLTmfAGLjAcIMBK7UZ2o4lygHIqVckOlQU3xWw==",
163
+ "license": "MIT",
164
+ "dependencies": {
165
+ "fast-xml-parser": "^5.0.7",
166
+ "tslib": "^2.8.1"
167
+ },
168
+ "engines": {
169
+ "node": ">=20.0.0"
170
+ }
171
+ },
172
+ "node_modules/@azure/logger": {
173
+ "version": "1.3.0",
174
+ "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz",
175
+ "integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==",
176
+ "license": "MIT",
177
+ "dependencies": {
178
+ "@typespec/ts-http-runtime": "^0.3.0",
179
+ "tslib": "^2.6.2"
180
+ },
181
+ "engines": {
182
+ "node": ">=20.0.0"
183
+ }
184
+ },
185
+ "node_modules/@azure/storage-blob": {
186
+ "version": "12.28.0",
187
+ "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.28.0.tgz",
188
+ "integrity": "sha512-VhQHITXXO03SURhDiGuHhvc/k/sD2WvJUS7hqhiVNbErVCuQoLtWql7r97fleBlIRKHJaa9R7DpBjfE0pfLYcA==",
189
+ "license": "MIT",
190
+ "dependencies": {
191
+ "@azure/abort-controller": "^2.1.2",
192
+ "@azure/core-auth": "^1.9.0",
193
+ "@azure/core-client": "^1.9.3",
194
+ "@azure/core-http-compat": "^2.2.0",
195
+ "@azure/core-lro": "^2.2.0",
196
+ "@azure/core-paging": "^1.6.2",
197
+ "@azure/core-rest-pipeline": "^1.19.1",
198
+ "@azure/core-tracing": "^1.2.0",
199
+ "@azure/core-util": "^1.11.0",
200
+ "@azure/core-xml": "^1.4.5",
201
+ "@azure/logger": "^1.1.4",
202
+ "@azure/storage-common": "^12.0.0-beta.2",
203
+ "events": "^3.0.0",
204
+ "tslib": "^2.8.1"
205
+ },
206
+ "engines": {
207
+ "node": ">=20.0.0"
208
+ }
209
+ },
210
+ "node_modules/@azure/storage-common": {
211
+ "version": "12.0.0",
212
+ "resolved": "https://registry.npmjs.org/@azure/storage-common/-/storage-common-12.0.0.tgz",
213
+ "integrity": "sha512-QyEWXgi4kdRo0wc1rHum9/KnaWZKCdQGZK1BjU4fFL6Jtedp7KLbQihgTTVxldFy1z1ZPtuDPx8mQ5l3huPPbA==",
214
+ "license": "MIT",
215
+ "dependencies": {
216
+ "@azure/abort-controller": "^2.1.2",
217
+ "@azure/core-auth": "^1.9.0",
218
+ "@azure/core-http-compat": "^2.2.0",
219
+ "@azure/core-rest-pipeline": "^1.19.1",
220
+ "@azure/core-tracing": "^1.2.0",
221
+ "@azure/core-util": "^1.11.0",
222
+ "@azure/logger": "^1.1.4",
223
+ "events": "^3.3.0",
224
+ "tslib": "^2.8.1"
225
+ },
226
+ "engines": {
227
+ "node": ">=20.0.0"
228
+ }
229
+ },
230
+ "node_modules/@esbuild/aix-ppc64": {
231
+ "version": "0.25.10",
232
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz",
233
+ "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==",
234
+ "cpu": [
235
+ "ppc64"
236
+ ],
237
+ "dev": true,
238
+ "license": "MIT",
239
+ "optional": true,
240
+ "os": [
241
+ "aix"
242
+ ],
243
+ "engines": {
244
+ "node": ">=18"
245
+ }
246
+ },
247
+ "node_modules/@esbuild/android-arm": {
248
+ "version": "0.25.10",
249
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz",
250
+ "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==",
251
+ "cpu": [
252
+ "arm"
253
+ ],
254
+ "dev": true,
255
+ "license": "MIT",
256
+ "optional": true,
257
+ "os": [
258
+ "android"
259
+ ],
260
+ "engines": {
261
+ "node": ">=18"
262
+ }
263
+ },
264
+ "node_modules/@esbuild/android-arm64": {
265
+ "version": "0.25.10",
266
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz",
267
+ "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==",
268
+ "cpu": [
269
+ "arm64"
270
+ ],
271
+ "dev": true,
272
+ "license": "MIT",
273
+ "optional": true,
274
+ "os": [
275
+ "android"
276
+ ],
277
+ "engines": {
278
+ "node": ">=18"
279
+ }
280
+ },
281
+ "node_modules/@esbuild/android-x64": {
282
+ "version": "0.25.10",
283
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz",
284
+ "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==",
285
+ "cpu": [
286
+ "x64"
287
+ ],
288
+ "dev": true,
289
+ "license": "MIT",
290
+ "optional": true,
291
+ "os": [
292
+ "android"
293
+ ],
294
+ "engines": {
295
+ "node": ">=18"
296
+ }
297
+ },
298
+ "node_modules/@esbuild/darwin-arm64": {
299
+ "version": "0.25.10",
300
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz",
301
+ "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==",
302
+ "cpu": [
303
+ "arm64"
304
+ ],
305
+ "dev": true,
306
+ "license": "MIT",
307
+ "optional": true,
308
+ "os": [
309
+ "darwin"
310
+ ],
311
+ "engines": {
312
+ "node": ">=18"
313
+ }
314
+ },
315
+ "node_modules/@esbuild/darwin-x64": {
316
+ "version": "0.25.10",
317
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz",
318
+ "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==",
319
+ "cpu": [
320
+ "x64"
321
+ ],
322
+ "dev": true,
323
+ "license": "MIT",
324
+ "optional": true,
325
+ "os": [
326
+ "darwin"
327
+ ],
328
+ "engines": {
329
+ "node": ">=18"
330
+ }
331
+ },
332
+ "node_modules/@esbuild/freebsd-arm64": {
333
+ "version": "0.25.10",
334
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz",
335
+ "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==",
336
+ "cpu": [
337
+ "arm64"
338
+ ],
339
+ "dev": true,
340
+ "license": "MIT",
341
+ "optional": true,
342
+ "os": [
343
+ "freebsd"
344
+ ],
345
+ "engines": {
346
+ "node": ">=18"
347
+ }
348
+ },
349
+ "node_modules/@esbuild/freebsd-x64": {
350
+ "version": "0.25.10",
351
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz",
352
+ "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==",
353
+ "cpu": [
354
+ "x64"
355
+ ],
356
+ "dev": true,
357
+ "license": "MIT",
358
+ "optional": true,
359
+ "os": [
360
+ "freebsd"
361
+ ],
362
+ "engines": {
363
+ "node": ">=18"
364
+ }
365
+ },
366
+ "node_modules/@esbuild/linux-arm": {
367
+ "version": "0.25.10",
368
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz",
369
+ "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==",
370
+ "cpu": [
371
+ "arm"
372
+ ],
373
+ "dev": true,
374
+ "license": "MIT",
375
+ "optional": true,
376
+ "os": [
377
+ "linux"
378
+ ],
379
+ "engines": {
380
+ "node": ">=18"
381
+ }
382
+ },
383
+ "node_modules/@esbuild/linux-arm64": {
384
+ "version": "0.25.10",
385
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz",
386
+ "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==",
387
+ "cpu": [
388
+ "arm64"
389
+ ],
390
+ "dev": true,
391
+ "license": "MIT",
392
+ "optional": true,
393
+ "os": [
394
+ "linux"
395
+ ],
396
+ "engines": {
397
+ "node": ">=18"
398
+ }
399
+ },
400
+ "node_modules/@esbuild/linux-ia32": {
401
+ "version": "0.25.10",
402
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz",
403
+ "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==",
404
+ "cpu": [
405
+ "ia32"
406
+ ],
407
+ "dev": true,
408
+ "license": "MIT",
409
+ "optional": true,
410
+ "os": [
411
+ "linux"
412
+ ],
413
+ "engines": {
414
+ "node": ">=18"
415
+ }
416
+ },
417
+ "node_modules/@esbuild/linux-loong64": {
418
+ "version": "0.25.10",
419
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz",
420
+ "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==",
421
+ "cpu": [
422
+ "loong64"
423
+ ],
424
+ "dev": true,
425
+ "license": "MIT",
426
+ "optional": true,
427
+ "os": [
428
+ "linux"
429
+ ],
430
+ "engines": {
431
+ "node": ">=18"
432
+ }
433
+ },
434
+ "node_modules/@esbuild/linux-mips64el": {
435
+ "version": "0.25.10",
436
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz",
437
+ "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==",
438
+ "cpu": [
439
+ "mips64el"
440
+ ],
441
+ "dev": true,
442
+ "license": "MIT",
443
+ "optional": true,
444
+ "os": [
445
+ "linux"
446
+ ],
447
+ "engines": {
448
+ "node": ">=18"
449
+ }
450
+ },
451
+ "node_modules/@esbuild/linux-ppc64": {
452
+ "version": "0.25.10",
453
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz",
454
+ "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==",
455
+ "cpu": [
456
+ "ppc64"
457
+ ],
458
+ "dev": true,
459
+ "license": "MIT",
460
+ "optional": true,
461
+ "os": [
462
+ "linux"
463
+ ],
464
+ "engines": {
465
+ "node": ">=18"
466
+ }
467
+ },
468
+ "node_modules/@esbuild/linux-riscv64": {
469
+ "version": "0.25.10",
470
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz",
471
+ "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==",
472
+ "cpu": [
473
+ "riscv64"
474
+ ],
475
+ "dev": true,
476
+ "license": "MIT",
477
+ "optional": true,
478
+ "os": [
479
+ "linux"
480
+ ],
481
+ "engines": {
482
+ "node": ">=18"
483
+ }
484
+ },
485
+ "node_modules/@esbuild/linux-s390x": {
486
+ "version": "0.25.10",
487
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz",
488
+ "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==",
489
+ "cpu": [
490
+ "s390x"
491
+ ],
492
+ "dev": true,
493
+ "license": "MIT",
494
+ "optional": true,
495
+ "os": [
496
+ "linux"
497
+ ],
498
+ "engines": {
499
+ "node": ">=18"
500
+ }
501
+ },
502
+ "node_modules/@esbuild/linux-x64": {
503
+ "version": "0.25.10",
504
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz",
505
+ "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==",
506
+ "cpu": [
507
+ "x64"
508
+ ],
509
+ "dev": true,
510
+ "license": "MIT",
511
+ "optional": true,
512
+ "os": [
513
+ "linux"
514
+ ],
515
+ "engines": {
516
+ "node": ">=18"
517
+ }
518
+ },
519
+ "node_modules/@esbuild/netbsd-arm64": {
520
+ "version": "0.25.10",
521
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz",
522
+ "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==",
523
+ "cpu": [
524
+ "arm64"
525
+ ],
526
+ "dev": true,
527
+ "license": "MIT",
528
+ "optional": true,
529
+ "os": [
530
+ "netbsd"
531
+ ],
532
+ "engines": {
533
+ "node": ">=18"
534
+ }
535
+ },
536
+ "node_modules/@esbuild/netbsd-x64": {
537
+ "version": "0.25.10",
538
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz",
539
+ "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==",
540
+ "cpu": [
541
+ "x64"
542
+ ],
543
+ "dev": true,
544
+ "license": "MIT",
545
+ "optional": true,
546
+ "os": [
547
+ "netbsd"
548
+ ],
549
+ "engines": {
550
+ "node": ">=18"
551
+ }
552
+ },
553
+ "node_modules/@esbuild/openbsd-arm64": {
554
+ "version": "0.25.10",
555
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz",
556
+ "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==",
557
+ "cpu": [
558
+ "arm64"
559
+ ],
560
+ "dev": true,
561
+ "license": "MIT",
562
+ "optional": true,
563
+ "os": [
564
+ "openbsd"
565
+ ],
566
+ "engines": {
567
+ "node": ">=18"
568
+ }
569
+ },
570
+ "node_modules/@esbuild/openbsd-x64": {
571
+ "version": "0.25.10",
572
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz",
573
+ "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==",
574
+ "cpu": [
575
+ "x64"
576
+ ],
577
+ "dev": true,
578
+ "license": "MIT",
579
+ "optional": true,
580
+ "os": [
581
+ "openbsd"
582
+ ],
583
+ "engines": {
584
+ "node": ">=18"
585
+ }
586
+ },
587
+ "node_modules/@esbuild/openharmony-arm64": {
588
+ "version": "0.25.10",
589
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz",
590
+ "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==",
591
+ "cpu": [
592
+ "arm64"
593
+ ],
594
+ "dev": true,
595
+ "license": "MIT",
596
+ "optional": true,
597
+ "os": [
598
+ "openharmony"
599
+ ],
600
+ "engines": {
601
+ "node": ">=18"
602
+ }
603
+ },
604
+ "node_modules/@esbuild/sunos-x64": {
605
+ "version": "0.25.10",
606
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz",
607
+ "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==",
608
+ "cpu": [
609
+ "x64"
610
+ ],
611
+ "dev": true,
612
+ "license": "MIT",
613
+ "optional": true,
614
+ "os": [
615
+ "sunos"
616
+ ],
617
+ "engines": {
618
+ "node": ">=18"
619
+ }
620
+ },
621
+ "node_modules/@esbuild/win32-arm64": {
622
+ "version": "0.25.10",
623
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz",
624
+ "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==",
625
+ "cpu": [
626
+ "arm64"
627
+ ],
628
+ "dev": true,
629
+ "license": "MIT",
630
+ "optional": true,
631
+ "os": [
632
+ "win32"
633
+ ],
634
+ "engines": {
635
+ "node": ">=18"
636
+ }
637
+ },
638
+ "node_modules/@esbuild/win32-ia32": {
639
+ "version": "0.25.10",
640
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz",
641
+ "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==",
642
+ "cpu": [
643
+ "ia32"
644
+ ],
645
+ "dev": true,
646
+ "license": "MIT",
647
+ "optional": true,
648
+ "os": [
649
+ "win32"
650
+ ],
651
+ "engines": {
652
+ "node": ">=18"
653
+ }
654
+ },
655
+ "node_modules/@esbuild/win32-x64": {
656
+ "version": "0.25.10",
657
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz",
658
+ "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==",
659
+ "cpu": [
660
+ "x64"
661
+ ],
662
+ "dev": true,
663
+ "license": "MIT",
664
+ "optional": true,
665
+ "os": [
666
+ "win32"
667
+ ],
668
+ "engines": {
669
+ "node": ">=18"
670
+ }
671
+ },
672
+ "node_modules/@prisma/client": {
673
+ "version": "5.22.0",
674
+ "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.22.0.tgz",
675
+ "integrity": "sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==",
676
+ "hasInstallScript": true,
677
+ "license": "Apache-2.0",
678
+ "engines": {
679
+ "node": ">=16.13"
680
+ },
681
+ "peerDependencies": {
682
+ "prisma": "*"
683
+ },
684
+ "peerDependenciesMeta": {
685
+ "prisma": {
686
+ "optional": true
687
+ }
688
+ }
689
+ },
690
+ "node_modules/@prisma/debug": {
691
+ "version": "5.22.0",
692
+ "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.22.0.tgz",
693
+ "integrity": "sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==",
694
+ "devOptional": true,
695
+ "license": "Apache-2.0"
696
+ },
697
+ "node_modules/@prisma/engines": {
698
+ "version": "5.22.0",
699
+ "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.22.0.tgz",
700
+ "integrity": "sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==",
701
+ "devOptional": true,
702
+ "hasInstallScript": true,
703
+ "license": "Apache-2.0",
704
+ "dependencies": {
705
+ "@prisma/debug": "5.22.0",
706
+ "@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2",
707
+ "@prisma/fetch-engine": "5.22.0",
708
+ "@prisma/get-platform": "5.22.0"
709
+ }
710
+ },
711
+ "node_modules/@prisma/engines-version": {
712
+ "version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2",
713
+ "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2.tgz",
714
+ "integrity": "sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==",
715
+ "devOptional": true,
716
+ "license": "Apache-2.0"
717
+ },
718
+ "node_modules/@prisma/fetch-engine": {
719
+ "version": "5.22.0",
720
+ "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.22.0.tgz",
721
+ "integrity": "sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==",
722
+ "devOptional": true,
723
+ "license": "Apache-2.0",
724
+ "dependencies": {
725
+ "@prisma/debug": "5.22.0",
726
+ "@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2",
727
+ "@prisma/get-platform": "5.22.0"
728
+ }
729
+ },
730
+ "node_modules/@prisma/get-platform": {
731
+ "version": "5.22.0",
732
+ "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.22.0.tgz",
733
+ "integrity": "sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==",
734
+ "devOptional": true,
735
+ "license": "Apache-2.0",
736
+ "dependencies": {
737
+ "@prisma/debug": "5.22.0"
738
+ }
739
+ },
740
+ "node_modules/@types/body-parser": {
741
+ "version": "1.19.6",
742
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
743
+ "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
744
+ "dev": true,
745
+ "license": "MIT",
746
+ "dependencies": {
747
+ "@types/connect": "*",
748
+ "@types/node": "*"
749
+ }
750
+ },
751
+ "node_modules/@types/connect": {
752
+ "version": "3.4.38",
753
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
754
+ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
755
+ "dev": true,
756
+ "license": "MIT",
757
+ "dependencies": {
758
+ "@types/node": "*"
759
+ }
760
+ },
761
+ "node_modules/@types/cookie-parser": {
762
+ "version": "1.4.9",
763
+ "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.9.tgz",
764
+ "integrity": "sha512-tGZiZ2Gtc4m3wIdLkZ8mkj1T6CEHb35+VApbL2T14Dew8HA7c+04dmKqsKRNC+8RJPm16JEK0tFSwdZqubfc4g==",
765
+ "dev": true,
766
+ "license": "MIT",
767
+ "peerDependencies": {
768
+ "@types/express": "*"
769
+ }
770
+ },
771
+ "node_modules/@types/cors": {
772
+ "version": "2.8.19",
773
+ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
774
+ "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
775
+ "dev": true,
776
+ "license": "MIT",
777
+ "dependencies": {
778
+ "@types/node": "*"
779
+ }
780
+ },
781
+ "node_modules/@types/express": {
782
+ "version": "5.0.3",
783
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz",
784
+ "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==",
785
+ "dev": true,
786
+ "license": "MIT",
787
+ "dependencies": {
788
+ "@types/body-parser": "*",
789
+ "@types/express-serve-static-core": "^5.0.0",
790
+ "@types/serve-static": "*"
791
+ }
792
+ },
793
+ "node_modules/@types/express-serve-static-core": {
794
+ "version": "5.1.0",
795
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz",
796
+ "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==",
797
+ "dev": true,
798
+ "license": "MIT",
799
+ "dependencies": {
800
+ "@types/node": "*",
801
+ "@types/qs": "*",
802
+ "@types/range-parser": "*",
803
+ "@types/send": "*"
804
+ }
805
+ },
806
+ "node_modules/@types/http-errors": {
807
+ "version": "2.0.5",
808
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
809
+ "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
810
+ "dev": true,
811
+ "license": "MIT"
812
+ },
813
+ "node_modules/@types/jsonwebtoken": {
814
+ "version": "9.0.10",
815
+ "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
816
+ "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==",
817
+ "dev": true,
818
+ "license": "MIT",
819
+ "dependencies": {
820
+ "@types/ms": "*",
821
+ "@types/node": "*"
822
+ }
823
+ },
824
+ "node_modules/@types/mime": {
825
+ "version": "1.3.5",
826
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
827
+ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
828
+ "dev": true,
829
+ "license": "MIT"
830
+ },
831
+ "node_modules/@types/ms": {
832
+ "version": "2.1.0",
833
+ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
834
+ "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
835
+ "dev": true,
836
+ "license": "MIT"
837
+ },
838
+ "node_modules/@types/node": {
839
+ "version": "24.7.2",
840
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.2.tgz",
841
+ "integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==",
842
+ "dev": true,
843
+ "license": "MIT",
844
+ "dependencies": {
845
+ "undici-types": "~7.14.0"
846
+ }
847
+ },
848
+ "node_modules/@types/qs": {
849
+ "version": "6.14.0",
850
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
851
+ "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
852
+ "dev": true,
853
+ "license": "MIT"
854
+ },
855
+ "node_modules/@types/range-parser": {
856
+ "version": "1.2.7",
857
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
858
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
859
+ "dev": true,
860
+ "license": "MIT"
861
+ },
862
+ "node_modules/@types/react": {
863
+ "version": "19.2.2",
864
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
865
+ "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
866
+ "dev": true,
867
+ "license": "MIT",
868
+ "dependencies": {
869
+ "csstype": "^3.0.2"
870
+ }
871
+ },
872
+ "node_modules/@types/react-dom": {
873
+ "version": "19.2.1",
874
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.1.tgz",
875
+ "integrity": "sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==",
876
+ "dev": true,
877
+ "license": "MIT",
878
+ "peerDependencies": {
879
+ "@types/react": "^19.2.0"
880
+ }
881
+ },
882
+ "node_modules/@types/send": {
883
+ "version": "1.2.0",
884
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.0.tgz",
885
+ "integrity": "sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ==",
886
+ "dev": true,
887
+ "license": "MIT",
888
+ "dependencies": {
889
+ "@types/node": "*"
890
+ }
891
+ },
892
+ "node_modules/@types/serve-static": {
893
+ "version": "1.15.9",
894
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.9.tgz",
895
+ "integrity": "sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA==",
896
+ "dev": true,
897
+ "license": "MIT",
898
+ "dependencies": {
899
+ "@types/http-errors": "*",
900
+ "@types/node": "*",
901
+ "@types/send": "<1"
902
+ }
903
+ },
904
+ "node_modules/@types/serve-static/node_modules/@types/send": {
905
+ "version": "0.17.5",
906
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz",
907
+ "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==",
908
+ "dev": true,
909
+ "license": "MIT",
910
+ "dependencies": {
911
+ "@types/mime": "^1",
912
+ "@types/node": "*"
913
+ }
914
+ },
915
+ "node_modules/@typespec/ts-http-runtime": {
916
+ "version": "0.3.1",
917
+ "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.1.tgz",
918
+ "integrity": "sha512-SnbaqayTVFEA6/tYumdF0UmybY0KHyKwGPBXnyckFlrrKdhWFrL3a2HIPXHjht5ZOElKGcXfD2D63P36btb+ww==",
919
+ "license": "MIT",
920
+ "dependencies": {
921
+ "http-proxy-agent": "^7.0.0",
922
+ "https-proxy-agent": "^7.0.0",
923
+ "tslib": "^2.6.2"
924
+ },
925
+ "engines": {
926
+ "node": ">=20.0.0"
927
+ }
928
+ },
929
+ "node_modules/accepts": {
930
+ "version": "1.3.8",
931
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
932
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
933
+ "license": "MIT",
934
+ "dependencies": {
935
+ "mime-types": "~2.1.34",
936
+ "negotiator": "0.6.3"
937
+ },
938
+ "engines": {
939
+ "node": ">= 0.6"
940
+ }
941
+ },
942
+ "node_modules/agent-base": {
943
+ "version": "7.1.4",
944
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
945
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
946
+ "license": "MIT",
947
+ "engines": {
948
+ "node": ">= 14"
949
+ }
950
+ },
951
+ "node_modules/array-flatten": {
952
+ "version": "1.1.1",
953
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
954
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
955
+ "license": "MIT"
956
+ },
957
+ "node_modules/body-parser": {
958
+ "version": "1.20.3",
959
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
960
+ "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
961
+ "license": "MIT",
962
+ "dependencies": {
963
+ "bytes": "3.1.2",
964
+ "content-type": "~1.0.5",
965
+ "debug": "2.6.9",
966
+ "depd": "2.0.0",
967
+ "destroy": "1.2.0",
968
+ "http-errors": "2.0.0",
969
+ "iconv-lite": "0.4.24",
970
+ "on-finished": "2.4.1",
971
+ "qs": "6.13.0",
972
+ "raw-body": "2.5.2",
973
+ "type-is": "~1.6.18",
974
+ "unpipe": "1.0.0"
975
+ },
976
+ "engines": {
977
+ "node": ">= 0.8",
978
+ "npm": "1.2.8000 || >= 1.4.16"
979
+ }
980
+ },
981
+ "node_modules/buffer-equal-constant-time": {
982
+ "version": "1.0.1",
983
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
984
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
985
+ "license": "BSD-3-Clause"
986
+ },
987
+ "node_modules/bytes": {
988
+ "version": "3.1.2",
989
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
990
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
991
+ "license": "MIT",
992
+ "engines": {
993
+ "node": ">= 0.8"
994
+ }
995
+ },
996
+ "node_modules/call-bind-apply-helpers": {
997
+ "version": "1.0.2",
998
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
999
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
1000
+ "license": "MIT",
1001
+ "dependencies": {
1002
+ "es-errors": "^1.3.0",
1003
+ "function-bind": "^1.1.2"
1004
+ },
1005
+ "engines": {
1006
+ "node": ">= 0.4"
1007
+ }
1008
+ },
1009
+ "node_modules/call-bound": {
1010
+ "version": "1.0.4",
1011
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
1012
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
1013
+ "license": "MIT",
1014
+ "dependencies": {
1015
+ "call-bind-apply-helpers": "^1.0.2",
1016
+ "get-intrinsic": "^1.3.0"
1017
+ },
1018
+ "engines": {
1019
+ "node": ">= 0.4"
1020
+ },
1021
+ "funding": {
1022
+ "url": "https://github.com/sponsors/ljharb"
1023
+ }
1024
+ },
1025
+ "node_modules/content-disposition": {
1026
+ "version": "0.5.4",
1027
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
1028
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
1029
+ "license": "MIT",
1030
+ "dependencies": {
1031
+ "safe-buffer": "5.2.1"
1032
+ },
1033
+ "engines": {
1034
+ "node": ">= 0.6"
1035
+ }
1036
+ },
1037
+ "node_modules/content-type": {
1038
+ "version": "1.0.5",
1039
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
1040
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
1041
+ "license": "MIT",
1042
+ "engines": {
1043
+ "node": ">= 0.6"
1044
+ }
1045
+ },
1046
+ "node_modules/cookie": {
1047
+ "version": "0.7.1",
1048
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
1049
+ "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
1050
+ "license": "MIT",
1051
+ "engines": {
1052
+ "node": ">= 0.6"
1053
+ }
1054
+ },
1055
+ "node_modules/cookie-parser": {
1056
+ "version": "1.4.7",
1057
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
1058
+ "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
1059
+ "license": "MIT",
1060
+ "dependencies": {
1061
+ "cookie": "0.7.2",
1062
+ "cookie-signature": "1.0.6"
1063
+ },
1064
+ "engines": {
1065
+ "node": ">= 0.8.0"
1066
+ }
1067
+ },
1068
+ "node_modules/cookie-parser/node_modules/cookie": {
1069
+ "version": "0.7.2",
1070
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
1071
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
1072
+ "license": "MIT",
1073
+ "engines": {
1074
+ "node": ">= 0.6"
1075
+ }
1076
+ },
1077
+ "node_modules/cookie-signature": {
1078
+ "version": "1.0.6",
1079
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
1080
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
1081
+ "license": "MIT"
1082
+ },
1083
+ "node_modules/cors": {
1084
+ "version": "2.8.5",
1085
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
1086
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
1087
+ "license": "MIT",
1088
+ "dependencies": {
1089
+ "object-assign": "^4",
1090
+ "vary": "^1"
1091
+ },
1092
+ "engines": {
1093
+ "node": ">= 0.10"
1094
+ }
1095
+ },
1096
+ "node_modules/csstype": {
1097
+ "version": "3.1.3",
1098
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
1099
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
1100
+ "dev": true,
1101
+ "license": "MIT"
1102
+ },
1103
+ "node_modules/debug": {
1104
+ "version": "2.6.9",
1105
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
1106
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
1107
+ "license": "MIT",
1108
+ "dependencies": {
1109
+ "ms": "2.0.0"
1110
+ }
1111
+ },
1112
+ "node_modules/depd": {
1113
+ "version": "2.0.0",
1114
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
1115
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
1116
+ "license": "MIT",
1117
+ "engines": {
1118
+ "node": ">= 0.8"
1119
+ }
1120
+ },
1121
+ "node_modules/destroy": {
1122
+ "version": "1.2.0",
1123
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
1124
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
1125
+ "license": "MIT",
1126
+ "engines": {
1127
+ "node": ">= 0.8",
1128
+ "npm": "1.2.8000 || >= 1.4.16"
1129
+ }
1130
+ },
1131
+ "node_modules/dotenv": {
1132
+ "version": "17.2.3",
1133
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
1134
+ "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
1135
+ "license": "BSD-2-Clause",
1136
+ "engines": {
1137
+ "node": ">=12"
1138
+ },
1139
+ "funding": {
1140
+ "url": "https://dotenvx.com"
1141
+ }
1142
+ },
1143
+ "node_modules/dunder-proto": {
1144
+ "version": "1.0.1",
1145
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
1146
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
1147
+ "license": "MIT",
1148
+ "dependencies": {
1149
+ "call-bind-apply-helpers": "^1.0.1",
1150
+ "es-errors": "^1.3.0",
1151
+ "gopd": "^1.2.0"
1152
+ },
1153
+ "engines": {
1154
+ "node": ">= 0.4"
1155
+ }
1156
+ },
1157
+ "node_modules/ecdsa-sig-formatter": {
1158
+ "version": "1.0.11",
1159
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
1160
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
1161
+ "license": "Apache-2.0",
1162
+ "dependencies": {
1163
+ "safe-buffer": "^5.0.1"
1164
+ }
1165
+ },
1166
+ "node_modules/ee-first": {
1167
+ "version": "1.1.1",
1168
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
1169
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
1170
+ "license": "MIT"
1171
+ },
1172
+ "node_modules/encodeurl": {
1173
+ "version": "2.0.0",
1174
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
1175
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
1176
+ "license": "MIT",
1177
+ "engines": {
1178
+ "node": ">= 0.8"
1179
+ }
1180
+ },
1181
+ "node_modules/es-define-property": {
1182
+ "version": "1.0.1",
1183
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
1184
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
1185
+ "license": "MIT",
1186
+ "engines": {
1187
+ "node": ">= 0.4"
1188
+ }
1189
+ },
1190
+ "node_modules/es-errors": {
1191
+ "version": "1.3.0",
1192
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
1193
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
1194
+ "license": "MIT",
1195
+ "engines": {
1196
+ "node": ">= 0.4"
1197
+ }
1198
+ },
1199
+ "node_modules/es-object-atoms": {
1200
+ "version": "1.1.1",
1201
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
1202
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
1203
+ "license": "MIT",
1204
+ "dependencies": {
1205
+ "es-errors": "^1.3.0"
1206
+ },
1207
+ "engines": {
1208
+ "node": ">= 0.4"
1209
+ }
1210
+ },
1211
+ "node_modules/esbuild": {
1212
+ "version": "0.25.10",
1213
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz",
1214
+ "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==",
1215
+ "dev": true,
1216
+ "hasInstallScript": true,
1217
+ "license": "MIT",
1218
+ "bin": {
1219
+ "esbuild": "bin/esbuild"
1220
+ },
1221
+ "engines": {
1222
+ "node": ">=18"
1223
+ },
1224
+ "optionalDependencies": {
1225
+ "@esbuild/aix-ppc64": "0.25.10",
1226
+ "@esbuild/android-arm": "0.25.10",
1227
+ "@esbuild/android-arm64": "0.25.10",
1228
+ "@esbuild/android-x64": "0.25.10",
1229
+ "@esbuild/darwin-arm64": "0.25.10",
1230
+ "@esbuild/darwin-x64": "0.25.10",
1231
+ "@esbuild/freebsd-arm64": "0.25.10",
1232
+ "@esbuild/freebsd-x64": "0.25.10",
1233
+ "@esbuild/linux-arm": "0.25.10",
1234
+ "@esbuild/linux-arm64": "0.25.10",
1235
+ "@esbuild/linux-ia32": "0.25.10",
1236
+ "@esbuild/linux-loong64": "0.25.10",
1237
+ "@esbuild/linux-mips64el": "0.25.10",
1238
+ "@esbuild/linux-ppc64": "0.25.10",
1239
+ "@esbuild/linux-riscv64": "0.25.10",
1240
+ "@esbuild/linux-s390x": "0.25.10",
1241
+ "@esbuild/linux-x64": "0.25.10",
1242
+ "@esbuild/netbsd-arm64": "0.25.10",
1243
+ "@esbuild/netbsd-x64": "0.25.10",
1244
+ "@esbuild/openbsd-arm64": "0.25.10",
1245
+ "@esbuild/openbsd-x64": "0.25.10",
1246
+ "@esbuild/openharmony-arm64": "0.25.10",
1247
+ "@esbuild/sunos-x64": "0.25.10",
1248
+ "@esbuild/win32-arm64": "0.25.10",
1249
+ "@esbuild/win32-ia32": "0.25.10",
1250
+ "@esbuild/win32-x64": "0.25.10"
1251
+ }
1252
+ },
1253
+ "node_modules/escape-html": {
1254
+ "version": "1.0.3",
1255
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
1256
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
1257
+ "license": "MIT"
1258
+ },
1259
+ "node_modules/etag": {
1260
+ "version": "1.8.1",
1261
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
1262
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
1263
+ "license": "MIT",
1264
+ "engines": {
1265
+ "node": ">= 0.6"
1266
+ }
1267
+ },
1268
+ "node_modules/events": {
1269
+ "version": "3.3.0",
1270
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
1271
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
1272
+ "license": "MIT",
1273
+ "engines": {
1274
+ "node": ">=0.8.x"
1275
+ }
1276
+ },
1277
+ "node_modules/express": {
1278
+ "version": "4.21.2",
1279
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
1280
+ "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
1281
+ "license": "MIT",
1282
+ "dependencies": {
1283
+ "accepts": "~1.3.8",
1284
+ "array-flatten": "1.1.1",
1285
+ "body-parser": "1.20.3",
1286
+ "content-disposition": "0.5.4",
1287
+ "content-type": "~1.0.4",
1288
+ "cookie": "0.7.1",
1289
+ "cookie-signature": "1.0.6",
1290
+ "debug": "2.6.9",
1291
+ "depd": "2.0.0",
1292
+ "encodeurl": "~2.0.0",
1293
+ "escape-html": "~1.0.3",
1294
+ "etag": "~1.8.1",
1295
+ "finalhandler": "1.3.1",
1296
+ "fresh": "0.5.2",
1297
+ "http-errors": "2.0.0",
1298
+ "merge-descriptors": "1.0.3",
1299
+ "methods": "~1.1.2",
1300
+ "on-finished": "2.4.1",
1301
+ "parseurl": "~1.3.3",
1302
+ "path-to-regexp": "0.1.12",
1303
+ "proxy-addr": "~2.0.7",
1304
+ "qs": "6.13.0",
1305
+ "range-parser": "~1.2.1",
1306
+ "safe-buffer": "5.2.1",
1307
+ "send": "0.19.0",
1308
+ "serve-static": "1.16.2",
1309
+ "setprototypeof": "1.2.0",
1310
+ "statuses": "2.0.1",
1311
+ "type-is": "~1.6.18",
1312
+ "utils-merge": "1.0.1",
1313
+ "vary": "~1.1.2"
1314
+ },
1315
+ "engines": {
1316
+ "node": ">= 0.10.0"
1317
+ },
1318
+ "funding": {
1319
+ "type": "opencollective",
1320
+ "url": "https://opencollective.com/express"
1321
+ }
1322
+ },
1323
+ "node_modules/fast-xml-parser": {
1324
+ "version": "5.3.0",
1325
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.0.tgz",
1326
+ "integrity": "sha512-gkWGshjYcQCF+6qtlrqBqELqNqnt4CxruY6UVAWWnqb3DQ6qaNFEIKqzYep1XzHLM/QtrHVCxyPOtTk4LTQ7Aw==",
1327
+ "funding": [
1328
+ {
1329
+ "type": "github",
1330
+ "url": "https://github.com/sponsors/NaturalIntelligence"
1331
+ }
1332
+ ],
1333
+ "license": "MIT",
1334
+ "dependencies": {
1335
+ "strnum": "^2.1.0"
1336
+ },
1337
+ "bin": {
1338
+ "fxparser": "src/cli/cli.js"
1339
+ }
1340
+ },
1341
+ "node_modules/finalhandler": {
1342
+ "version": "1.3.1",
1343
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
1344
+ "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
1345
+ "license": "MIT",
1346
+ "dependencies": {
1347
+ "debug": "2.6.9",
1348
+ "encodeurl": "~2.0.0",
1349
+ "escape-html": "~1.0.3",
1350
+ "on-finished": "2.4.1",
1351
+ "parseurl": "~1.3.3",
1352
+ "statuses": "2.0.1",
1353
+ "unpipe": "~1.0.0"
1354
+ },
1355
+ "engines": {
1356
+ "node": ">= 0.8"
1357
+ }
1358
+ },
1359
+ "node_modules/forwarded": {
1360
+ "version": "0.2.0",
1361
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
1362
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
1363
+ "license": "MIT",
1364
+ "engines": {
1365
+ "node": ">= 0.6"
1366
+ }
1367
+ },
1368
+ "node_modules/fresh": {
1369
+ "version": "0.5.2",
1370
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
1371
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
1372
+ "license": "MIT",
1373
+ "engines": {
1374
+ "node": ">= 0.6"
1375
+ }
1376
+ },
1377
+ "node_modules/fsevents": {
1378
+ "version": "2.3.3",
1379
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1380
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1381
+ "dev": true,
1382
+ "hasInstallScript": true,
1383
+ "license": "MIT",
1384
+ "optional": true,
1385
+ "os": [
1386
+ "darwin"
1387
+ ],
1388
+ "engines": {
1389
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1390
+ }
1391
+ },
1392
+ "node_modules/function-bind": {
1393
+ "version": "1.1.2",
1394
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
1395
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
1396
+ "license": "MIT",
1397
+ "funding": {
1398
+ "url": "https://github.com/sponsors/ljharb"
1399
+ }
1400
+ },
1401
+ "node_modules/get-intrinsic": {
1402
+ "version": "1.3.0",
1403
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
1404
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
1405
+ "license": "MIT",
1406
+ "dependencies": {
1407
+ "call-bind-apply-helpers": "^1.0.2",
1408
+ "es-define-property": "^1.0.1",
1409
+ "es-errors": "^1.3.0",
1410
+ "es-object-atoms": "^1.1.1",
1411
+ "function-bind": "^1.1.2",
1412
+ "get-proto": "^1.0.1",
1413
+ "gopd": "^1.2.0",
1414
+ "has-symbols": "^1.1.0",
1415
+ "hasown": "^2.0.2",
1416
+ "math-intrinsics": "^1.1.0"
1417
+ },
1418
+ "engines": {
1419
+ "node": ">= 0.4"
1420
+ },
1421
+ "funding": {
1422
+ "url": "https://github.com/sponsors/ljharb"
1423
+ }
1424
+ },
1425
+ "node_modules/get-proto": {
1426
+ "version": "1.0.1",
1427
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
1428
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
1429
+ "license": "MIT",
1430
+ "dependencies": {
1431
+ "dunder-proto": "^1.0.1",
1432
+ "es-object-atoms": "^1.0.0"
1433
+ },
1434
+ "engines": {
1435
+ "node": ">= 0.4"
1436
+ }
1437
+ },
1438
+ "node_modules/get-tsconfig": {
1439
+ "version": "4.12.0",
1440
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.12.0.tgz",
1441
+ "integrity": "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==",
1442
+ "dev": true,
1443
+ "license": "MIT",
1444
+ "dependencies": {
1445
+ "resolve-pkg-maps": "^1.0.0"
1446
+ },
1447
+ "funding": {
1448
+ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
1449
+ }
1450
+ },
1451
+ "node_modules/gopd": {
1452
+ "version": "1.2.0",
1453
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
1454
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
1455
+ "license": "MIT",
1456
+ "engines": {
1457
+ "node": ">= 0.4"
1458
+ },
1459
+ "funding": {
1460
+ "url": "https://github.com/sponsors/ljharb"
1461
+ }
1462
+ },
1463
+ "node_modules/has-symbols": {
1464
+ "version": "1.1.0",
1465
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
1466
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
1467
+ "license": "MIT",
1468
+ "engines": {
1469
+ "node": ">= 0.4"
1470
+ },
1471
+ "funding": {
1472
+ "url": "https://github.com/sponsors/ljharb"
1473
+ }
1474
+ },
1475
+ "node_modules/hasown": {
1476
+ "version": "2.0.2",
1477
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
1478
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
1479
+ "license": "MIT",
1480
+ "dependencies": {
1481
+ "function-bind": "^1.1.2"
1482
+ },
1483
+ "engines": {
1484
+ "node": ">= 0.4"
1485
+ }
1486
+ },
1487
+ "node_modules/http-errors": {
1488
+ "version": "2.0.0",
1489
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
1490
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
1491
+ "license": "MIT",
1492
+ "dependencies": {
1493
+ "depd": "2.0.0",
1494
+ "inherits": "2.0.4",
1495
+ "setprototypeof": "1.2.0",
1496
+ "statuses": "2.0.1",
1497
+ "toidentifier": "1.0.1"
1498
+ },
1499
+ "engines": {
1500
+ "node": ">= 0.8"
1501
+ }
1502
+ },
1503
+ "node_modules/http-proxy-agent": {
1504
+ "version": "7.0.2",
1505
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
1506
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
1507
+ "license": "MIT",
1508
+ "dependencies": {
1509
+ "agent-base": "^7.1.0",
1510
+ "debug": "^4.3.4"
1511
+ },
1512
+ "engines": {
1513
+ "node": ">= 14"
1514
+ }
1515
+ },
1516
+ "node_modules/http-proxy-agent/node_modules/debug": {
1517
+ "version": "4.4.3",
1518
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
1519
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
1520
+ "license": "MIT",
1521
+ "dependencies": {
1522
+ "ms": "^2.1.3"
1523
+ },
1524
+ "engines": {
1525
+ "node": ">=6.0"
1526
+ },
1527
+ "peerDependenciesMeta": {
1528
+ "supports-color": {
1529
+ "optional": true
1530
+ }
1531
+ }
1532
+ },
1533
+ "node_modules/http-proxy-agent/node_modules/ms": {
1534
+ "version": "2.1.3",
1535
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1536
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1537
+ "license": "MIT"
1538
+ },
1539
+ "node_modules/https-proxy-agent": {
1540
+ "version": "7.0.6",
1541
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
1542
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
1543
+ "license": "MIT",
1544
+ "dependencies": {
1545
+ "agent-base": "^7.1.2",
1546
+ "debug": "4"
1547
+ },
1548
+ "engines": {
1549
+ "node": ">= 14"
1550
+ }
1551
+ },
1552
+ "node_modules/https-proxy-agent/node_modules/debug": {
1553
+ "version": "4.4.3",
1554
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
1555
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
1556
+ "license": "MIT",
1557
+ "dependencies": {
1558
+ "ms": "^2.1.3"
1559
+ },
1560
+ "engines": {
1561
+ "node": ">=6.0"
1562
+ },
1563
+ "peerDependenciesMeta": {
1564
+ "supports-color": {
1565
+ "optional": true
1566
+ }
1567
+ }
1568
+ },
1569
+ "node_modules/https-proxy-agent/node_modules/ms": {
1570
+ "version": "2.1.3",
1571
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1572
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1573
+ "license": "MIT"
1574
+ },
1575
+ "node_modules/iconv-lite": {
1576
+ "version": "0.4.24",
1577
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
1578
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
1579
+ "license": "MIT",
1580
+ "dependencies": {
1581
+ "safer-buffer": ">= 2.1.2 < 3"
1582
+ },
1583
+ "engines": {
1584
+ "node": ">=0.10.0"
1585
+ }
1586
+ },
1587
+ "node_modules/inherits": {
1588
+ "version": "2.0.4",
1589
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1590
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
1591
+ "license": "ISC"
1592
+ },
1593
+ "node_modules/ipaddr.js": {
1594
+ "version": "1.9.1",
1595
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
1596
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
1597
+ "license": "MIT",
1598
+ "engines": {
1599
+ "node": ">= 0.10"
1600
+ }
1601
+ },
1602
+ "node_modules/jsonwebtoken": {
1603
+ "version": "9.0.2",
1604
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
1605
+ "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
1606
+ "license": "MIT",
1607
+ "dependencies": {
1608
+ "jws": "^3.2.2",
1609
+ "lodash.includes": "^4.3.0",
1610
+ "lodash.isboolean": "^3.0.3",
1611
+ "lodash.isinteger": "^4.0.4",
1612
+ "lodash.isnumber": "^3.0.3",
1613
+ "lodash.isplainobject": "^4.0.6",
1614
+ "lodash.isstring": "^4.0.1",
1615
+ "lodash.once": "^4.0.0",
1616
+ "ms": "^2.1.1",
1617
+ "semver": "^7.5.4"
1618
+ },
1619
+ "engines": {
1620
+ "node": ">=12",
1621
+ "npm": ">=6"
1622
+ }
1623
+ },
1624
+ "node_modules/jsonwebtoken/node_modules/ms": {
1625
+ "version": "2.1.3",
1626
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1627
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1628
+ "license": "MIT"
1629
+ },
1630
+ "node_modules/jwa": {
1631
+ "version": "1.4.2",
1632
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
1633
+ "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
1634
+ "license": "MIT",
1635
+ "dependencies": {
1636
+ "buffer-equal-constant-time": "^1.0.1",
1637
+ "ecdsa-sig-formatter": "1.0.11",
1638
+ "safe-buffer": "^5.0.1"
1639
+ }
1640
+ },
1641
+ "node_modules/jws": {
1642
+ "version": "3.2.2",
1643
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
1644
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
1645
+ "license": "MIT",
1646
+ "dependencies": {
1647
+ "jwa": "^1.4.1",
1648
+ "safe-buffer": "^5.0.1"
1649
+ }
1650
+ },
1651
+ "node_modules/lodash.includes": {
1652
+ "version": "4.3.0",
1653
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
1654
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
1655
+ "license": "MIT"
1656
+ },
1657
+ "node_modules/lodash.isboolean": {
1658
+ "version": "3.0.3",
1659
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
1660
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
1661
+ "license": "MIT"
1662
+ },
1663
+ "node_modules/lodash.isinteger": {
1664
+ "version": "4.0.4",
1665
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
1666
+ "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
1667
+ "license": "MIT"
1668
+ },
1669
+ "node_modules/lodash.isnumber": {
1670
+ "version": "3.0.3",
1671
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
1672
+ "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
1673
+ "license": "MIT"
1674
+ },
1675
+ "node_modules/lodash.isplainobject": {
1676
+ "version": "4.0.6",
1677
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
1678
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
1679
+ "license": "MIT"
1680
+ },
1681
+ "node_modules/lodash.isstring": {
1682
+ "version": "4.0.1",
1683
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
1684
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
1685
+ "license": "MIT"
1686
+ },
1687
+ "node_modules/lodash.once": {
1688
+ "version": "4.1.1",
1689
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
1690
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
1691
+ "license": "MIT"
1692
+ },
1693
+ "node_modules/math-intrinsics": {
1694
+ "version": "1.1.0",
1695
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
1696
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
1697
+ "license": "MIT",
1698
+ "engines": {
1699
+ "node": ">= 0.4"
1700
+ }
1701
+ },
1702
+ "node_modules/media-typer": {
1703
+ "version": "0.3.0",
1704
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
1705
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
1706
+ "license": "MIT",
1707
+ "engines": {
1708
+ "node": ">= 0.6"
1709
+ }
1710
+ },
1711
+ "node_modules/merge-descriptors": {
1712
+ "version": "1.0.3",
1713
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
1714
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
1715
+ "license": "MIT",
1716
+ "funding": {
1717
+ "url": "https://github.com/sponsors/sindresorhus"
1718
+ }
1719
+ },
1720
+ "node_modules/methods": {
1721
+ "version": "1.1.2",
1722
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
1723
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
1724
+ "license": "MIT",
1725
+ "engines": {
1726
+ "node": ">= 0.6"
1727
+ }
1728
+ },
1729
+ "node_modules/mime": {
1730
+ "version": "1.6.0",
1731
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
1732
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
1733
+ "license": "MIT",
1734
+ "bin": {
1735
+ "mime": "cli.js"
1736
+ },
1737
+ "engines": {
1738
+ "node": ">=4"
1739
+ }
1740
+ },
1741
+ "node_modules/mime-db": {
1742
+ "version": "1.52.0",
1743
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
1744
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
1745
+ "license": "MIT",
1746
+ "engines": {
1747
+ "node": ">= 0.6"
1748
+ }
1749
+ },
1750
+ "node_modules/mime-types": {
1751
+ "version": "2.1.35",
1752
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
1753
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
1754
+ "license": "MIT",
1755
+ "dependencies": {
1756
+ "mime-db": "1.52.0"
1757
+ },
1758
+ "engines": {
1759
+ "node": ">= 0.6"
1760
+ }
1761
+ },
1762
+ "node_modules/ms": {
1763
+ "version": "2.0.0",
1764
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
1765
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
1766
+ "license": "MIT"
1767
+ },
1768
+ "node_modules/negotiator": {
1769
+ "version": "0.6.3",
1770
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
1771
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
1772
+ "license": "MIT",
1773
+ "engines": {
1774
+ "node": ">= 0.6"
1775
+ }
1776
+ },
1777
+ "node_modules/object-assign": {
1778
+ "version": "4.1.1",
1779
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1780
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
1781
+ "license": "MIT",
1782
+ "engines": {
1783
+ "node": ">=0.10.0"
1784
+ }
1785
+ },
1786
+ "node_modules/object-inspect": {
1787
+ "version": "1.13.4",
1788
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
1789
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
1790
+ "license": "MIT",
1791
+ "engines": {
1792
+ "node": ">= 0.4"
1793
+ },
1794
+ "funding": {
1795
+ "url": "https://github.com/sponsors/ljharb"
1796
+ }
1797
+ },
1798
+ "node_modules/on-finished": {
1799
+ "version": "2.4.1",
1800
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1801
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1802
+ "license": "MIT",
1803
+ "dependencies": {
1804
+ "ee-first": "1.1.1"
1805
+ },
1806
+ "engines": {
1807
+ "node": ">= 0.8"
1808
+ }
1809
+ },
1810
+ "node_modules/parseurl": {
1811
+ "version": "1.3.3",
1812
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1813
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
1814
+ "license": "MIT",
1815
+ "engines": {
1816
+ "node": ">= 0.8"
1817
+ }
1818
+ },
1819
+ "node_modules/path-to-regexp": {
1820
+ "version": "0.1.12",
1821
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
1822
+ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
1823
+ "license": "MIT"
1824
+ },
1825
+ "node_modules/prisma": {
1826
+ "version": "5.22.0",
1827
+ "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.22.0.tgz",
1828
+ "integrity": "sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==",
1829
+ "devOptional": true,
1830
+ "hasInstallScript": true,
1831
+ "license": "Apache-2.0",
1832
+ "dependencies": {
1833
+ "@prisma/engines": "5.22.0"
1834
+ },
1835
+ "bin": {
1836
+ "prisma": "build/index.js"
1837
+ },
1838
+ "engines": {
1839
+ "node": ">=16.13"
1840
+ },
1841
+ "optionalDependencies": {
1842
+ "fsevents": "2.3.3"
1843
+ }
1844
+ },
1845
+ "node_modules/proxy-addr": {
1846
+ "version": "2.0.7",
1847
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1848
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1849
+ "license": "MIT",
1850
+ "dependencies": {
1851
+ "forwarded": "0.2.0",
1852
+ "ipaddr.js": "1.9.1"
1853
+ },
1854
+ "engines": {
1855
+ "node": ">= 0.10"
1856
+ }
1857
+ },
1858
+ "node_modules/qs": {
1859
+ "version": "6.13.0",
1860
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
1861
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
1862
+ "license": "BSD-3-Clause",
1863
+ "dependencies": {
1864
+ "side-channel": "^1.0.6"
1865
+ },
1866
+ "engines": {
1867
+ "node": ">=0.6"
1868
+ },
1869
+ "funding": {
1870
+ "url": "https://github.com/sponsors/ljharb"
1871
+ }
1872
+ },
1873
+ "node_modules/range-parser": {
1874
+ "version": "1.2.1",
1875
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1876
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
1877
+ "license": "MIT",
1878
+ "engines": {
1879
+ "node": ">= 0.6"
1880
+ }
1881
+ },
1882
+ "node_modules/raw-body": {
1883
+ "version": "2.5.2",
1884
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
1885
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
1886
+ "license": "MIT",
1887
+ "dependencies": {
1888
+ "bytes": "3.1.2",
1889
+ "http-errors": "2.0.0",
1890
+ "iconv-lite": "0.4.24",
1891
+ "unpipe": "1.0.0"
1892
+ },
1893
+ "engines": {
1894
+ "node": ">= 0.8"
1895
+ }
1896
+ },
1897
+ "node_modules/resolve-pkg-maps": {
1898
+ "version": "1.0.0",
1899
+ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
1900
+ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
1901
+ "dev": true,
1902
+ "license": "MIT",
1903
+ "funding": {
1904
+ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
1905
+ }
1906
+ },
1907
+ "node_modules/safe-buffer": {
1908
+ "version": "5.2.1",
1909
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1910
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1911
+ "funding": [
1912
+ {
1913
+ "type": "github",
1914
+ "url": "https://github.com/sponsors/feross"
1915
+ },
1916
+ {
1917
+ "type": "patreon",
1918
+ "url": "https://www.patreon.com/feross"
1919
+ },
1920
+ {
1921
+ "type": "consulting",
1922
+ "url": "https://feross.org/support"
1923
+ }
1924
+ ],
1925
+ "license": "MIT"
1926
+ },
1927
+ "node_modules/safer-buffer": {
1928
+ "version": "2.1.2",
1929
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1930
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
1931
+ "license": "MIT"
1932
+ },
1933
+ "node_modules/semver": {
1934
+ "version": "7.7.3",
1935
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
1936
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
1937
+ "license": "ISC",
1938
+ "bin": {
1939
+ "semver": "bin/semver.js"
1940
+ },
1941
+ "engines": {
1942
+ "node": ">=10"
1943
+ }
1944
+ },
1945
+ "node_modules/send": {
1946
+ "version": "0.19.0",
1947
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
1948
+ "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
1949
+ "license": "MIT",
1950
+ "dependencies": {
1951
+ "debug": "2.6.9",
1952
+ "depd": "2.0.0",
1953
+ "destroy": "1.2.0",
1954
+ "encodeurl": "~1.0.2",
1955
+ "escape-html": "~1.0.3",
1956
+ "etag": "~1.8.1",
1957
+ "fresh": "0.5.2",
1958
+ "http-errors": "2.0.0",
1959
+ "mime": "1.6.0",
1960
+ "ms": "2.1.3",
1961
+ "on-finished": "2.4.1",
1962
+ "range-parser": "~1.2.1",
1963
+ "statuses": "2.0.1"
1964
+ },
1965
+ "engines": {
1966
+ "node": ">= 0.8.0"
1967
+ }
1968
+ },
1969
+ "node_modules/send/node_modules/encodeurl": {
1970
+ "version": "1.0.2",
1971
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
1972
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
1973
+ "license": "MIT",
1974
+ "engines": {
1975
+ "node": ">= 0.8"
1976
+ }
1977
+ },
1978
+ "node_modules/send/node_modules/ms": {
1979
+ "version": "2.1.3",
1980
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1981
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1982
+ "license": "MIT"
1983
+ },
1984
+ "node_modules/serve-static": {
1985
+ "version": "1.16.2",
1986
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
1987
+ "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
1988
+ "license": "MIT",
1989
+ "dependencies": {
1990
+ "encodeurl": "~2.0.0",
1991
+ "escape-html": "~1.0.3",
1992
+ "parseurl": "~1.3.3",
1993
+ "send": "0.19.0"
1994
+ },
1995
+ "engines": {
1996
+ "node": ">= 0.8.0"
1997
+ }
1998
+ },
1999
+ "node_modules/setprototypeof": {
2000
+ "version": "1.2.0",
2001
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
2002
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
2003
+ "license": "ISC"
2004
+ },
2005
+ "node_modules/side-channel": {
2006
+ "version": "1.1.0",
2007
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
2008
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
2009
+ "license": "MIT",
2010
+ "dependencies": {
2011
+ "es-errors": "^1.3.0",
2012
+ "object-inspect": "^1.13.3",
2013
+ "side-channel-list": "^1.0.0",
2014
+ "side-channel-map": "^1.0.1",
2015
+ "side-channel-weakmap": "^1.0.2"
2016
+ },
2017
+ "engines": {
2018
+ "node": ">= 0.4"
2019
+ },
2020
+ "funding": {
2021
+ "url": "https://github.com/sponsors/ljharb"
2022
+ }
2023
+ },
2024
+ "node_modules/side-channel-list": {
2025
+ "version": "1.0.0",
2026
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
2027
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
2028
+ "license": "MIT",
2029
+ "dependencies": {
2030
+ "es-errors": "^1.3.0",
2031
+ "object-inspect": "^1.13.3"
2032
+ },
2033
+ "engines": {
2034
+ "node": ">= 0.4"
2035
+ },
2036
+ "funding": {
2037
+ "url": "https://github.com/sponsors/ljharb"
2038
+ }
2039
+ },
2040
+ "node_modules/side-channel-map": {
2041
+ "version": "1.0.1",
2042
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
2043
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
2044
+ "license": "MIT",
2045
+ "dependencies": {
2046
+ "call-bound": "^1.0.2",
2047
+ "es-errors": "^1.3.0",
2048
+ "get-intrinsic": "^1.2.5",
2049
+ "object-inspect": "^1.13.3"
2050
+ },
2051
+ "engines": {
2052
+ "node": ">= 0.4"
2053
+ },
2054
+ "funding": {
2055
+ "url": "https://github.com/sponsors/ljharb"
2056
+ }
2057
+ },
2058
+ "node_modules/side-channel-weakmap": {
2059
+ "version": "1.0.2",
2060
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
2061
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
2062
+ "license": "MIT",
2063
+ "dependencies": {
2064
+ "call-bound": "^1.0.2",
2065
+ "es-errors": "^1.3.0",
2066
+ "get-intrinsic": "^1.2.5",
2067
+ "object-inspect": "^1.13.3",
2068
+ "side-channel-map": "^1.0.1"
2069
+ },
2070
+ "engines": {
2071
+ "node": ">= 0.4"
2072
+ },
2073
+ "funding": {
2074
+ "url": "https://github.com/sponsors/ljharb"
2075
+ }
2076
+ },
2077
+ "node_modules/statuses": {
2078
+ "version": "2.0.1",
2079
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
2080
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
2081
+ "license": "MIT",
2082
+ "engines": {
2083
+ "node": ">= 0.8"
2084
+ }
2085
+ },
2086
+ "node_modules/strnum": {
2087
+ "version": "2.1.1",
2088
+ "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz",
2089
+ "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==",
2090
+ "funding": [
2091
+ {
2092
+ "type": "github",
2093
+ "url": "https://github.com/sponsors/NaturalIntelligence"
2094
+ }
2095
+ ],
2096
+ "license": "MIT"
2097
+ },
2098
+ "node_modules/toidentifier": {
2099
+ "version": "1.0.1",
2100
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
2101
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
2102
+ "license": "MIT",
2103
+ "engines": {
2104
+ "node": ">=0.6"
2105
+ }
2106
+ },
2107
+ "node_modules/tslib": {
2108
+ "version": "2.8.1",
2109
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
2110
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
2111
+ "license": "0BSD"
2112
+ },
2113
+ "node_modules/tsx": {
2114
+ "version": "4.20.6",
2115
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz",
2116
+ "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==",
2117
+ "dev": true,
2118
+ "license": "MIT",
2119
+ "dependencies": {
2120
+ "esbuild": "~0.25.0",
2121
+ "get-tsconfig": "^4.7.5"
2122
+ },
2123
+ "bin": {
2124
+ "tsx": "dist/cli.mjs"
2125
+ },
2126
+ "engines": {
2127
+ "node": ">=18.0.0"
2128
+ },
2129
+ "optionalDependencies": {
2130
+ "fsevents": "~2.3.3"
2131
+ }
2132
+ },
2133
+ "node_modules/type-is": {
2134
+ "version": "1.6.18",
2135
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
2136
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
2137
+ "license": "MIT",
2138
+ "dependencies": {
2139
+ "media-typer": "0.3.0",
2140
+ "mime-types": "~2.1.24"
2141
+ },
2142
+ "engines": {
2143
+ "node": ">= 0.6"
2144
+ }
2145
+ },
2146
+ "node_modules/typescript": {
2147
+ "version": "5.9.3",
2148
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
2149
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
2150
+ "dev": true,
2151
+ "license": "Apache-2.0",
2152
+ "bin": {
2153
+ "tsc": "bin/tsc",
2154
+ "tsserver": "bin/tsserver"
2155
+ },
2156
+ "engines": {
2157
+ "node": ">=14.17"
2158
+ }
2159
+ },
2160
+ "node_modules/undici-types": {
2161
+ "version": "7.14.0",
2162
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
2163
+ "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
2164
+ "dev": true,
2165
+ "license": "MIT"
2166
+ },
2167
+ "node_modules/unpipe": {
2168
+ "version": "1.0.0",
2169
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
2170
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
2171
+ "license": "MIT",
2172
+ "engines": {
2173
+ "node": ">= 0.8"
2174
+ }
2175
+ },
2176
+ "node_modules/utils-merge": {
2177
+ "version": "1.0.1",
2178
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
2179
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
2180
+ "license": "MIT",
2181
+ "engines": {
2182
+ "node": ">= 0.4.0"
2183
+ }
2184
+ },
2185
+ "node_modules/vary": {
2186
+ "version": "1.1.2",
2187
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
2188
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
2189
+ "license": "MIT",
2190
+ "engines": {
2191
+ "node": ">= 0.8"
2192
+ }
2193
+ }
2194
+ }
2195
+ }
package.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "portfolio-backend",
3
+ "private": true,
4
+ "scripts": {
5
+ "dev": "tsx src/index.ts",
6
+ "build": "tsc",
7
+ "start": "node dist/index.js",
8
+ "prisma:generate": "prisma generate",
9
+ "prisma:migrate": "prisma migrate deploy"
10
+ },
11
+ "dependencies": {
12
+ "@azure/storage-blob": "^12.17.0",
13
+ "@prisma/client": "^5.16.1",
14
+ "cookie-parser": "^1.4.7",
15
+ "cors": "^2.8.5",
16
+ "dotenv": "^17.2.3",
17
+ "express": "^4.19.2",
18
+ "jsonwebtoken": "^9.0.2"
19
+ },
20
+ "devDependencies": {
21
+ "@types/cookie-parser": "^1.4.9",
22
+ "@types/cors": "^2.8.19",
23
+ "@types/express": "^5.0.3",
24
+ "@types/jsonwebtoken": "^9.0.5",
25
+ "@types/node": "^24.7.2",
26
+ "@types/react": "^19.2.2",
27
+ "@types/react-dom": "^19.2.1",
28
+ "prisma": "^5.16.1",
29
+ "tsx": "^4.19.0",
30
+ "typescript": "^5.4.3"
31
+ }
32
+ }
prisma/migrations/20251013165838_init/migration.sql ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -- CreateEnum
2
+ CREATE TYPE "Category" AS ENUM ('projects', 'vlogs', 'notes');
3
+
4
+ -- CreateTable
5
+ CREATE TABLE "Post" (
6
+ "id" TEXT NOT NULL,
7
+ "slug" TEXT NOT NULL,
8
+ "title" TEXT NOT NULL,
9
+ "subtitle" TEXT,
10
+ "category" "Category" NOT NULL,
11
+ "contentMd" TEXT NOT NULL,
12
+ "coverUrl" TEXT,
13
+ "visibility" TEXT NOT NULL DEFAULT 'public',
14
+ "language" TEXT,
15
+ "description" TEXT,
16
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
17
+ "updatedAt" TIMESTAMP(3) NOT NULL,
18
+
19
+ CONSTRAINT "Post_pkey" PRIMARY KEY ("id")
20
+ );
21
+
22
+ -- CreateTable
23
+ CREATE TABLE "Tag" (
24
+ "id" TEXT NOT NULL,
25
+ "emoji" TEXT NOT NULL,
26
+ "label" TEXT NOT NULL,
27
+ "description" TEXT NOT NULL,
28
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
29
+ "updatedAt" TIMESTAMP(3) NOT NULL,
30
+
31
+ CONSTRAINT "Tag_pkey" PRIMARY KEY ("id")
32
+ );
33
+
34
+ -- CreateTable
35
+ CREATE TABLE "TagOnPost" (
36
+ "id" TEXT NOT NULL,
37
+ "postId" TEXT NOT NULL,
38
+ "tagId" TEXT NOT NULL,
39
+
40
+ CONSTRAINT "TagOnPost_pkey" PRIMARY KEY ("id")
41
+ );
42
+
43
+ -- CreateIndex
44
+ CREATE UNIQUE INDEX "Post_slug_key" ON "Post"("slug");
45
+
46
+ -- CreateIndex
47
+ CREATE UNIQUE INDEX "Tag_emoji_key" ON "Tag"("emoji");
48
+
49
+ -- CreateIndex
50
+ CREATE UNIQUE INDEX "TagOnPost_postId_tagId_key" ON "TagOnPost"("postId", "tagId");
51
+
52
+ -- AddForeignKey
53
+ ALTER TABLE "TagOnPost" ADD CONSTRAINT "TagOnPost_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post"("id") ON DELETE CASCADE ON UPDATE CASCADE;
54
+
55
+ -- AddForeignKey
56
+ ALTER TABLE "TagOnPost" ADD CONSTRAINT "TagOnPost_tagId_fkey" FOREIGN KEY ("tagId") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
prisma/migrations/migration_lock.toml ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # Please do not edit this file manually
2
+ # It should be added in your version-control system (i.e. Git)
3
+ provider = "postgresql"
prisma/schema.prisma ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/prisma/schema.prisma
2
+ datasource db {
3
+ provider = "postgresql"
4
+ url = env("DATABASE_URL")
5
+ }
6
+
7
+ generator client {
8
+ provider = "prisma-client-js"
9
+ }
10
+
11
+ enum Category {
12
+ projects
13
+ vlogs
14
+ notes
15
+ }
16
+
17
+ model Post {
18
+ id String @id @default(cuid())
19
+ slug String @unique
20
+ title String
21
+ subtitle String?
22
+ category Category
23
+ contentMd String
24
+ coverUrl String?
25
+ visibility String @default("public")
26
+ language String?
27
+ description String?
28
+ createdAt DateTime @default(now())
29
+ updatedAt DateTime @updatedAt
30
+
31
+ tags TagOnPost[]
32
+ }
33
+
34
+ model Tag {
35
+ id String @id @default(cuid())
36
+ emoji String @unique
37
+ label String
38
+ description String
39
+ createdAt DateTime @default(now())
40
+ updatedAt DateTime @updatedAt
41
+
42
+ posts TagOnPost[]
43
+ }
44
+
45
+ model TagOnPost {
46
+ id String @id @default(cuid())
47
+ postId String
48
+ tagId String
49
+
50
+ post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
51
+ tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
52
+
53
+
54
+ @@unique([postId, tagId])
55
+ }
src/app.ts ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/app.ts
2
+ import express from 'express';
3
+ import cors from 'cors';
4
+ import cookieParser from 'cookie-parser';
5
+ import { errorHandler } from './utils/errorHandler';
6
+ import { postsRouter } from './posts/router';
7
+ import { notesRouter } from './notes/router';
8
+ import { blogsRouter } from './blogs/router';
9
+ import { projectsRouter } from './projects/router';
10
+ import { uploadsRouter } from './uploads/router';
11
+ import { tagsRouter } from './tags/router';
12
+ import { authRouter } from './auth/router';
13
+
14
+ export const app = express();
15
+
16
+ // CORS 설정 (프론트엔드 도메인 명시)
17
+ app.use(cors({
18
+ origin: process.env.FRONTEND_ORIGIN, // 프론트엔드 App Service 도메인
19
+ credentials: true, // 쿠키 허용
20
+ }));
21
+
22
+ // JSON 파서
23
+ app.use(express.json({ limit: '5mb' }));
24
+
25
+ // 쿠키 파서
26
+ app.use(cookieParser());
27
+
28
+ // 라우터 연결
29
+ app.use('/api/posts', postsRouter);
30
+ app.use('/api/notes', notesRouter);
31
+ app.use('/api/blogs', blogsRouter);
32
+ app.use('/api/projects', projectsRouter);
33
+ app.use('/api/uploads', uploadsRouter);
34
+ app.use('/api/tags', tagsRouter);
35
+ app.use('/api/auth', authRouter);
36
+
37
+ // 에러 핸들러
38
+ app.use(errorHandler);
src/auth/controller.ts ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/auth/controller.ts
2
+ import { Request, Response } from "express";
3
+ import jwt from "jsonwebtoken";
4
+
5
+ const ACCESS_SECRET = process.env.JWT_SECRET!;
6
+ const REFRESH_SECRET = process.env.JWT_REFRESH_SECRET!;
7
+
8
+ export function login(req: Request, res: Response) {
9
+ const { id, password } = req.body;
10
+ if (id !== process.env.ADMIN_ID || password !== process.env.ADMIN_PASSWORD) {
11
+ return res.status(401).json({ error: "Invalid credentials" });
12
+ }
13
+
14
+ const payload = { id };
15
+
16
+ // Access Token (1시간)
17
+ const accessToken = jwt.sign(payload, ACCESS_SECRET, { expiresIn: "1h" });
18
+
19
+ // Refresh Token (7일)
20
+ const refreshToken = jwt.sign(payload, REFRESH_SECRET, { expiresIn: "7d" });
21
+
22
+ // Refresh Token은 HttpOnly 쿠키에 저장
23
+ res.cookie("refreshToken", refreshToken, {
24
+ httpOnly: true,
25
+ secure: true,
26
+ sameSite: "none",
27
+ path: "/api/auth/refresh",
28
+ maxAge: 7 * 24 * 60 * 60 * 1000,
29
+ });
30
+
31
+ return res.json({ token: accessToken });
32
+ }
33
+
34
+ export function verify(req: Request, res: Response) {
35
+ if (!req.user) {
36
+ return res.status(401).json({ valid: false, error: "Invalid or expired token" });
37
+ }
38
+ return res.json({ valid: true, user: req.user });
39
+ }
40
+
41
+ export function refresh(req: Request, res: Response) {
42
+ const token = req.cookies.refreshToken;
43
+ if (!token) {
44
+ return res.status(401).json({ error: "Missing refresh token" });
45
+ }
46
+
47
+ try {
48
+ const decoded = jwt.verify(token, REFRESH_SECRET) as any;
49
+ const payload = { id: decoded.id };
50
+
51
+ // 새 Access Token 발급
52
+ const newAccessToken = jwt.sign(payload, ACCESS_SECRET, { expiresIn: "1h" });
53
+
54
+ return res.json({ token: newAccessToken });
55
+ } catch (err) {
56
+ return res.status(401).json({ error: "Refresh token invalid or expired" });
57
+ }
58
+ }
src/auth/middleware.ts ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/auth/middleware.ts
2
+ import { Request, Response, NextFunction } from "express";
3
+ import jwt from "jsonwebtoken";
4
+
5
+ const ACCESS_SECRET = process.env.JWT_SECRET!;
6
+
7
+ export function adminAuth(req: Request, res: Response, next: NextFunction) {
8
+ const authHeader = req.headers.authorization;
9
+ if (!authHeader?.startsWith("Bearer ")) {
10
+ return res.status(401).json({ error: "Missing or invalid token" });
11
+ }
12
+
13
+ const token = authHeader.split(" ")[1];
14
+ try {
15
+ const decoded = jwt.verify(token, ACCESS_SECRET);
16
+ req.user = decoded;
17
+ next();
18
+ } catch (err: any) {
19
+ return res.status(401).json({ error: "Token verification failed", details: err.message });
20
+ }
21
+ }
src/auth/router.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/auth/router.ts
2
+ import { Router } from "express";
3
+ import { login, verify, refresh } from "./controller";
4
+ import { adminAuth } from "./middleware";
5
+
6
+ export const authRouter = Router();
7
+
8
+ authRouter.post("/login", login);
9
+ authRouter.get("/verify", adminAuth, verify);
10
+ authRouter.post("/refresh", refresh);
src/auth/service.ts ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ // backend/src/auth/service.ts
2
+ // Reserved for future: token issue/refresh if needed
3
+ export {};
src/blogs/router.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/blogs/router.ts
2
+ import { Router } from 'express';
3
+ import { list, bySlug, create, update, remove } from '../posts/controller';
4
+ import { adminAuth } from '../auth/middleware';
5
+
6
+ export const blogsRouter = Router();
7
+ blogsRouter.get('/', (req, _res, next) => { req.query.category = 'vlogs'; next(); }, list);
8
+ blogsRouter.get('/:slug', bySlug);
9
+ blogsRouter.post('/', adminAuth, (req, _res, next) => { req.body.category = 'vlogs'; next(); }, create);
10
+ blogsRouter.put('/:slug', adminAuth, (req, _res, next) => { req.body.category = 'vlogs'; next(); }, update);
11
+ blogsRouter.delete('/:slug', adminAuth, remove);
src/index.ts ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/index.ts
2
+ import { execSync } from 'child_process';
3
+ import { app } from './app';
4
+
5
+ // DB URL 조합
6
+ if (!process.env.DATABASE_URL) {
7
+ const user = process.env.POSTGRES_USER;
8
+ const pass = process.env.POSTGRES_PASSWORD;
9
+ const host = process.env.POSTGRES_NAME;
10
+ const db = process.env.POSTGRES_DB;
11
+ process.env.DATABASE_URL = `postgresql://${user}:${pass}@${host}:5432/${db}?sslmode=require`;
12
+ }
13
+
14
+ // 마이그레이션 실행
15
+ try {
16
+ execSync('npx prisma migrate deploy', { stdio: 'inherit' });
17
+ } catch (err) {
18
+ console.error('Migration failed', err);
19
+ process.exit(1);
20
+ }
21
+
22
+ // 서버 시작
23
+ const port = process.env.PORT || 8080;
24
+ app.listen(port, () => console.log(`Backend running on port ${port}`));
src/notes/router.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/notes/router.ts
2
+ import { Router } from 'express';
3
+ import { list, bySlug, create, update, remove } from '../posts/controller';
4
+ import { adminAuth } from '../auth/middleware';
5
+
6
+ export const notesRouter = Router();
7
+ notesRouter.get('/', (req, _res, next) => { req.query.category = 'notes'; next(); }, list);
8
+ notesRouter.get('/:slug', bySlug);
9
+ notesRouter.post('/', adminAuth, (req, _res, next) => { req.body.category = 'notes'; next(); }, create);
10
+ notesRouter.put('/:slug', adminAuth, (req, _res, next) => { req.body.category = 'notes'; next(); }, update);
11
+ notesRouter.delete('/:slug', adminAuth, remove);
src/posts/controller.ts ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/posts/controller.ts
2
+ import { Request, Response } from 'express';
3
+ import { Category } from '@prisma/client';
4
+ import { listPosts, getPostBySlug, createPost, updatePostBySlug, deletePostBySlug } from './service';
5
+
6
+ export async function list(req: Request, res: Response) {
7
+ const { category, keyword, limit, offset, emojis } = req.query as any;
8
+ const emojiTags = typeof emojis === 'string' ? emojis.split(',') : (emojis || []);
9
+ const result = await listPosts({
10
+ category: category as Category | undefined,
11
+ keyword,
12
+ emojiTags,
13
+ limit: limit ? Number(limit) : undefined,
14
+ offset: offset ? Number(offset) : undefined,
15
+ });
16
+ res.json(result);
17
+ }
18
+
19
+ export async function bySlug(req: Request, res: Response) {
20
+ const post = await getPostBySlug(req.params.slug);
21
+ if (!post) return res.status(404).json({ error: 'Not found' });
22
+ res.json(post);
23
+ }
24
+
25
+ export async function create(req: Request, res: Response) {
26
+ const body = req.body;
27
+ const created = await createPost({
28
+ slug: body.slug,
29
+ title: body.title,
30
+ subtitle: body.subtitle,
31
+ category: body.category,
32
+ contentMd: body.contentMd,
33
+ coverUrl: body.coverUrl,
34
+ visibility: body.visibility,
35
+ language: body.language,
36
+ description: body.description,
37
+ emojis: body.emojis || [],
38
+ });
39
+ res.status(201).json(created);
40
+ }
41
+
42
+ export async function update(req: Request, res: Response) {
43
+ const body = req.body;
44
+ try {
45
+ const updated = await updatePostBySlug(req.params.slug, {
46
+ slug: body.slug,
47
+ title: body.title,
48
+ subtitle: body.subtitle,
49
+ category: body.category,
50
+ contentMd: body.contentMd,
51
+ coverUrl: body.coverUrl,
52
+ visibility: body.visibility,
53
+ language: body.language,
54
+ description: body.description,
55
+ emojis: body.emojis || [],
56
+ });
57
+ res.json(updated);
58
+ } catch (e: any) {
59
+ if (e.code === 'P2002') {
60
+ return res.status(409).json({ error: 'Slug already exists' });
61
+ }
62
+ return res.status(500).json({ error: 'Update failed' });
63
+ }
64
+ }
65
+
66
+ export async function remove(req: Request, res: Response) {
67
+ try {
68
+ await deletePostBySlug(req.params.slug);
69
+ res.status(204).send();
70
+ } catch (e: any) {
71
+ return res.status(404).json({ error: 'Not found' });
72
+ }
73
+ }
src/posts/router.ts ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/posts/router.ts
2
+ import { Router } from 'express';
3
+ import { list, bySlug, create, update, remove } from './controller';
4
+ import { adminAuth } from '../auth/middleware';
5
+
6
+ export const postsRouter = Router();
7
+
8
+ postsRouter.get('/', list);
9
+ postsRouter.get('/:slug', bySlug);
10
+ postsRouter.post('/', adminAuth, create);
11
+
12
+ postsRouter.put('/:slug', adminAuth, update);
13
+ postsRouter.delete('/:slug', adminAuth, remove);
src/posts/service.ts ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/posts/service.ts
2
+ import { prisma } from '../utils/prisma';
3
+ import { Category, Prisma } from '@prisma/client';
4
+
5
+ export async function listPosts(params: {
6
+ category?: Category;
7
+ keyword?: string;
8
+ emojiTags?: string[];
9
+ limit?: number;
10
+ offset?: number;
11
+ }) {
12
+ const { category, keyword, emojiTags, limit = 20, offset = 0 } = params;
13
+ const where: Prisma.PostWhereInput = {
14
+ visibility: 'public',
15
+ ...(category ? { category } : {}),
16
+ ...(keyword ? {
17
+ OR: [
18
+ { title: { contains: keyword, mode: 'insensitive' } },
19
+ { subtitle: { contains: keyword, mode: 'insensitive' } },
20
+ { contentMd: { contains: keyword, mode: 'insensitive' } },
21
+ { description: { contains: keyword, mode: 'insensitive' } },
22
+ ]
23
+ } : {}),
24
+ ...(emojiTags?.length ? {
25
+ tags: { some: { tag: { emoji: { in: emojiTags } } } }
26
+ } : {}),
27
+ };
28
+ const [items, total] = await Promise.all([
29
+ prisma.post.findMany({
30
+ where,
31
+ orderBy: { createdAt: 'desc' },
32
+ include: { tags: { include: { tag: true } } },
33
+ skip: offset, take: limit,
34
+ }),
35
+ prisma.post.count({ where }),
36
+ ]);
37
+ return { items, total };
38
+ }
39
+
40
+ export async function getPostBySlug(slug: string) {
41
+ return prisma.post.findUnique({
42
+ where: { slug },
43
+ include: { tags: { include: { tag: true } } },
44
+ });
45
+ }
46
+
47
+ export async function connectTagsByEmojis(postId: string, emojis: string[]) {
48
+ if (!emojis?.length) {
49
+ await prisma.tagOnPost.deleteMany({ where: { postId } });
50
+ return;
51
+ }
52
+ const tagRecords = await prisma.tag.findMany({ where: { emoji: { in: emojis } } });
53
+ await prisma.tagOnPost.deleteMany({ where: { postId } });
54
+ await prisma.tagOnPost.createMany({
55
+ data: tagRecords.map(t => ({ postId, tagId: t.id })),
56
+ skipDuplicates: true,
57
+ });
58
+ }
59
+
60
+ export async function createPost(data: {
61
+ slug: string;
62
+ title: string;
63
+ subtitle?: string;
64
+ category: Category;
65
+ contentMd: string;
66
+ coverUrl?: string;
67
+ visibility?: string;
68
+ language?: string;
69
+ description?: string;
70
+ emojis?: string[];
71
+ }) {
72
+ const post = await prisma.post.create({
73
+ data: {
74
+ slug: data.slug,
75
+ title: data.title,
76
+ subtitle: data.subtitle,
77
+ category: data.category,
78
+ contentMd: data.contentMd,
79
+ coverUrl: data.coverUrl,
80
+ visibility: data.visibility ?? 'public',
81
+ language: data.language,
82
+ description: data.description,
83
+ },
84
+ });
85
+ await connectTagsByEmojis(post.id, data.emojis || []);
86
+ return await getPostBySlug(post.slug);
87
+ }
88
+
89
+ export async function updatePostBySlug(slug: string, data: {
90
+ slug?: string;
91
+ title?: string;
92
+ subtitle?: string;
93
+ category?: Category;
94
+ contentMd?: string;
95
+ coverUrl?: string;
96
+ visibility?: string;
97
+ language?: string;
98
+ description?: string;
99
+ emojis?: string[];
100
+ }) {
101
+ const post = await prisma.post.update({
102
+ where: { slug },
103
+ data: {
104
+ slug: data.slug,
105
+ title: data.title,
106
+ subtitle: data.subtitle,
107
+ category: data.category,
108
+ contentMd: data.contentMd,
109
+ coverUrl: data.coverUrl,
110
+ visibility: data.visibility,
111
+ language: data.language,
112
+ description: data.description,
113
+ },
114
+ });
115
+ if (data.emojis) await connectTagsByEmojis(post.id, data.emojis);
116
+ return await getPostBySlug(post.slug);
117
+ }
118
+
119
+ export async function deletePostBySlug(slug: string) {
120
+ await prisma.post.delete({ where: { slug } });
121
+ }
src/projects/router.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/projects/router.ts
2
+ import { Router } from 'express';
3
+ import { list, bySlug, create, update, remove } from '../posts/controller';
4
+ import { adminAuth } from '../auth/middleware';
5
+
6
+ export const projectsRouter = Router();
7
+ projectsRouter.get('/', (req, _res, next) => { req.query.category = 'projects'; next(); }, list);
8
+ projectsRouter.get('/:slug', bySlug);
9
+ projectsRouter.post('/', adminAuth, (req, _res, next) => { req.body.category = 'projects'; next(); }, create);
10
+ projectsRouter.put('/:slug', adminAuth, (req, _res, next) => { req.body.category = 'projects'; next(); }, update);
11
+ projectsRouter.delete('/:slug', adminAuth, remove);
src/tags/controller.ts ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/tags/controller.ts
2
+ import { Request, Response } from 'express';
3
+ import { listTags, getTagByEmoji, upsertTag, deleteTag } from './service';
4
+
5
+ export async function list(req: Request, res: Response) {
6
+ const tags = await listTags();
7
+ res.json({ items: tags });
8
+ }
9
+
10
+ export async function byEmoji(req: Request, res: Response) {
11
+ const tag = await getTagByEmoji(req.params.emoji);
12
+ if (!tag) return res.status(404).json({ error: 'Not found' });
13
+ res.json(tag);
14
+ }
15
+
16
+ export async function upsert(req: Request, res: Response) {
17
+ const { emoji, label, description } = req.body;
18
+ if (!emoji || !label || !description) return res.status(400).json({ error: 'emoji, label, description required' });
19
+ const t = await upsertTag({ emoji, label, description });
20
+ res.status(201).json(t);
21
+ }
22
+
23
+ export async function remove(req: Request, res: Response) {
24
+ await deleteTag(req.params.emoji);
25
+ res.status(204).send();
26
+ }
src/tags/router.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/tags/router.ts
2
+ import { Router } from 'express';
3
+ import { adminAuth } from '../auth/middleware';
4
+ import { list, byEmoji, upsert, remove } from './controller';
5
+
6
+ export const tagsRouter = Router();
7
+ tagsRouter.get('/', list);
8
+ tagsRouter.get('/:emoji', byEmoji);
9
+ tagsRouter.post('/', adminAuth, upsert);
10
+ tagsRouter.put('/:emoji', adminAuth, upsert);
11
+ tagsRouter.delete('/:emoji', adminAuth, remove);
src/tags/seed.ts ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/tags/seed.ts
2
+ import { prisma } from '../utils/prisma';
3
+
4
+ const TAG_GUIDE: Record<string, { label: string; description: string }> = {
5
+ '🔷': { label: 'Game Client', description: '게임 클라이언트 전반' },
6
+ '🔴': { label: 'AI Development', description: 'AI 개발 전반' },
7
+ '🟣': { label: 'XR / Creative Tech', description: 'VR/AR/그래픽/시네마틱' },
8
+ '🟠': { label: 'Web / API Development', description: '웹/프론트/API/데이터 시각화' },
9
+ '⚫': { label: 'Backend / Infra', description: '서버/DB/보안/네트워크' },
10
+ '🟢': { label: 'Cloud / DevOps', description: '클라우드/CI/CD/컨테이너' },
11
+ '🎮': { label: 'Gameplay', description: '스토리·전투·퀘스트·규칙 시스템' },
12
+ '🕹': { label: 'Interaction', description: '입력·UI·오브젝트 상호작용' },
13
+ '🎯': { label: 'Actor/Pawn AI', description: 'FSM·BT·RL·경로 탐색' },
14
+ '🗺': { label: 'Level/Scene', description: '씬 구성·오브젝트 배치·최적화' },
15
+ '🗣': { label: 'NLP', description: '자연어 처리' },
16
+ '📷': { label: 'CV', description: '컴퓨터 비전' },
17
+ '🖇': { label: 'Multimodal AI', description: '멀티모달 AI' },
18
+ '🎨': { label: 'Generative AI', description: '생성형 AI' },
19
+ '🤖': { label: 'Unified Intelligence', description: 'AGI-like 시스템' },
20
+ '🧠': { label: 'AGI Research', description: '단일모델 AGI 연구' },
21
+ '🥽': { label: 'VR', description: '가상현실' },
22
+ '📱': { label: 'AR', description: '증강현실' },
23
+ '🖌': { label: 'VFX/Graphics', description: '비주얼 이펙트/그래픽' },
24
+ '🎬': { label: 'Cinematic', description: '시네마틱' },
25
+ '🌐': { label: 'Frontend', description: '웹 프론트엔드' },
26
+ '🔌': { label: 'API', description: 'API 개발' },
27
+ '📊': { label: 'Data Viz', description: '데이터 시각화' },
28
+ '🗄': { label: 'Database', description: 'DB 설계/운영' },
29
+ '🔒': { label: 'Security', description: '보안' },
30
+ '⚡': { label: 'Realtime', description: '실시간 처리' },
31
+ '📡': { label: 'Networking', description: '네트워크' },
32
+ '☁️': { label: 'Cloud', description: '클라우드' },
33
+ '🔄': { label: 'CI/CD', description: '지속적 통합/배포' },
34
+ '🐳': { label: 'Docker/K8s', description: '컨테이너/쿠버네티스' },
35
+ };
36
+
37
+ async function main() {
38
+ for (const [emoji, meta] of Object.entries(TAG_GUIDE)) {
39
+ await prisma.tag.upsert({
40
+ where: { emoji },
41
+ update: { label: meta.label, description: meta.description },
42
+ create: { emoji, label: meta.label, description: meta.description },
43
+ });
44
+ }
45
+ console.log('Tag guide seeded.');
46
+ }
47
+ main().catch(e => { console.error(e); process.exit(1); }).finally(async () => prisma.$disconnect());
src/tags/service.ts ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/tags/service.ts
2
+ import { prisma } from '../utils/prisma';
3
+ import { Tag } from '@prisma/client';
4
+
5
+ export async function listTags() {
6
+ return prisma.tag.findMany({ orderBy: { label: 'asc' } });
7
+ }
8
+
9
+ export async function getTagByEmoji(emoji: string) {
10
+ return prisma.tag.findUnique({ where: { emoji } });
11
+ }
12
+
13
+ export async function upsertTag(input: { emoji: string; label: string; description: string }) {
14
+ return prisma.tag.upsert({
15
+ where: { emoji: input.emoji },
16
+ update: { label: input.label, description: input.description },
17
+ create: { emoji: input.emoji, label: input.label, description: input.description },
18
+ });
19
+ }
20
+
21
+ export async function deleteTag(emoji: string) {
22
+ return prisma.tag.delete({ where: { emoji } });
23
+ }
src/types/express/index.d.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ // src/types/express/index.d.ts
2
+ import { JwtPayload } from "jsonwebtoken";
3
+
4
+ declare global {
5
+ namespace Express {
6
+ interface Request {
7
+ user?: string | JwtPayload;
8
+ }
9
+ }
10
+ }
src/types/post.ts ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export type CreatePostDto = {
2
+ title: string;
3
+ slug: string;
4
+ category: "projects" | "vlogs" | "notes";
5
+ tags: string[];
6
+ tagString?: string;
7
+ summary?: string;
8
+ contentMd: string;
9
+ visibility: "public" | "private";
10
+ language: "ko" | "en";
11
+ githubUrl?: string;
12
+ coverUrl?: string;
13
+ };
14
+ export type UpdatePostDto = Partial<CreatePostDto>;
src/uploads/controller.ts ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/uploads/controller.ts
2
+ import { Request, Response } from 'express';
3
+ import { ensureContainer, getUploadSas } from '../utils/azureBlob';
4
+
5
+ export async function getSas(req: Request, res: Response) {
6
+ const { filename } = req.body;
7
+ if (!filename) return res.status(400).json({ error: 'filename required' });
8
+ await ensureContainer();
9
+ const { uploadUrl, expiresOn } = getUploadSas(filename);
10
+ res.json({ uploadUrl, expiresOn });
11
+ }
src/uploads/router.ts ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ // backend/src/uploads/router.ts
2
+ import { Router } from 'express';
3
+ import { adminAuth } from '../auth/middleware';
4
+ import { getSas } from './controller';
5
+
6
+ export const uploadsRouter = Router();
7
+ uploadsRouter.post('/get-sas', adminAuth, getSas);
src/utils/azureBlob.ts ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // backend/src/utils/azureBlob.ts
2
+ import {
3
+ BlobServiceClient,
4
+ StorageSharedKeyCredential,
5
+ generateBlobSASQueryParameters,
6
+ BlobSASPermissions,
7
+ SASProtocol,
8
+ } from '@azure/storage-blob';
9
+
10
+ const accountName = process.env.AZURE_STORAGE_ACCOUNT!;
11
+ const accountKey = process.env.AZURE_STORAGE_KEY!;
12
+ const containerName = process.env.AZURE_CONTAINER || 'portfolio-media';
13
+
14
+ const sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);
15
+ const blobServiceClient = new BlobServiceClient(`https://${accountName}.blob.core.windows.net`, sharedKeyCredential);
16
+ export const containerClient = blobServiceClient.getContainerClient(containerName);
17
+
18
+ export async function ensureContainer() {
19
+ await containerClient.createIfNotExists({ access: 'blob' });
20
+ }
21
+
22
+ export function getUploadSas(blobName: string, minutes = 10) {
23
+ const expiresOn = new Date(Date.now() + minutes * 60 * 1000);
24
+ const sas = generateBlobSASQueryParameters(
25
+ {
26
+ containerName,
27
+ blobName,
28
+ expiresOn,
29
+ permissions: BlobSASPermissions.parse('rwl'),
30
+ protocol: SASProtocol.Https,
31
+ },
32
+ sharedKeyCredential
33
+ ).toString();
34
+
35
+ const url = `${containerClient.url}/${blobName}?${sas}`;
36
+ return { uploadUrl: url, expiresOn };
37
+ }
src/utils/errorHandler.ts ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ // backend/src/utils/errorHandler.ts
2
+ import { NextFunction, Request, Response } from 'express';
3
+ export function errorHandler(err: any, _req: Request, res: Response, _next: NextFunction) {
4
+ const status = err.status || 500;
5
+ const message = err.message || 'Internal Server Error';
6
+ console.error('[Error]', status, message, err.stack || err);
7
+ res.status(status).json({ error: message });
8
+ }
src/utils/logger.ts ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ // backend/src/utils/logger.ts
2
+ export const logger = {
3
+ info: (...a: any[]) => console.log('[INFO]', ...a),
4
+ warn: (...a: any[]) => console.warn('[WARN]', ...a),
5
+ error: (...a: any[]) => console.error('[ERROR]', ...a),
6
+ };
src/utils/prisma.ts ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ // backend/src/utils/prisma.ts
2
+ import { PrismaClient } from '@prisma/client';
3
+ export const prisma = new PrismaClient();
tsconfig.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "lib": ["ES2020"],
5
+ "module": "CommonJS",
6
+ "moduleResolution": "Node",
7
+ "esModuleInterop": true,
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "baseUrl": ".",
11
+ "outDir": "dist",
12
+ "rootDir": "src",
13
+ "paths": {
14
+ "@/*": ["src/*"]
15
+ }
16
+ },
17
+ "include": ["src"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }