db-json-cli 1.0.5 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/.next/BUILD_ID +1 -0
  2. package/.next/app-build-manifest.json +26 -0
  3. package/.next/app-path-routes-manifest.json +1 -0
  4. package/.next/build-manifest.json +32 -0
  5. package/.next/cache/webpack/client-production/0.pack +0 -0
  6. package/.next/cache/webpack/client-production/1.pack +0 -0
  7. package/.next/cache/webpack/client-production/2.pack +0 -0
  8. package/.next/cache/webpack/client-production/3.pack +0 -0
  9. package/.next/cache/webpack/client-production/4.pack +0 -0
  10. package/.next/cache/webpack/client-production/index.pack +0 -0
  11. package/.next/cache/webpack/client-production/index.pack.old +0 -0
  12. package/.next/cache/webpack/edge-server-production/0.pack +0 -0
  13. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  14. package/.next/cache/webpack/server-production/0.pack +0 -0
  15. package/.next/cache/webpack/server-production/1.pack +0 -0
  16. package/.next/cache/webpack/server-production/2.pack +0 -0
  17. package/.next/cache/webpack/server-production/3.pack +0 -0
  18. package/.next/cache/webpack/server-production/index.pack +0 -0
  19. package/.next/cache/webpack/server-production/index.pack.old +0 -0
  20. package/.next/export-marker.json +1 -0
  21. package/.next/images-manifest.json +1 -0
  22. package/.next/next-minimal-server.js.nft.json +1 -0
  23. package/.next/next-server.js.nft.json +1 -0
  24. package/.next/package.json +1 -0
  25. package/.next/prerender-manifest.json +1 -0
  26. package/.next/react-loadable-manifest.json +1 -0
  27. package/.next/required-server-files.json +1 -0
  28. package/.next/routes-manifest.json +1 -0
  29. package/.next/server/app/_not-found/page.js +1 -0
  30. package/.next/server/app/_not-found/page.js.nft.json +1 -0
  31. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  32. package/.next/server/app/_not-found.html +1 -0
  33. package/.next/server/app/_not-found.meta +6 -0
  34. package/.next/server/app/_not-found.rsc +9 -0
  35. package/.next/server/app/api/[resource]/[id]/route.js +1 -0
  36. package/.next/server/app/api/[resource]/[id]/route.js.nft.json +1 -0
  37. package/.next/server/app/api/[resource]/route.js +1 -0
  38. package/.next/server/app/api/[resource]/route.js.nft.json +1 -0
  39. package/.next/server/app/api/info/route.js +1 -0
  40. package/.next/server/app/api/info/route.js.nft.json +1 -0
  41. package/.next/server/app/api/info.body +1 -0
  42. package/.next/server/app/api/info.meta +1 -0
  43. package/.next/server/app/api/login/route.js +1 -0
  44. package/.next/server/app/api/login/route.js.nft.json +1 -0
  45. package/.next/server/app/api/register/route.js +1 -0
  46. package/.next/server/app/api/register/route.js.nft.json +1 -0
  47. package/.next/server/app/index.html +1 -0
  48. package/.next/server/app/index.meta +5 -0
  49. package/.next/server/app/index.rsc +7 -0
  50. package/.next/server/app/page.js +1 -0
  51. package/.next/server/app/page.js.nft.json +1 -0
  52. package/.next/server/app/page_client-reference-manifest.js +1 -0
  53. package/.next/server/app-paths-manifest.json +9 -0
  54. package/.next/server/chunks/276.js +2 -0
  55. package/.next/server/chunks/471.js +2 -0
  56. package/.next/server/chunks/610.js +12 -0
  57. package/.next/server/chunks/682.js +6 -0
  58. package/.next/server/chunks/944.js +1 -0
  59. package/.next/server/chunks/font-manifest.json +1 -0
  60. package/.next/server/font-manifest.json +1 -0
  61. package/.next/server/functions-config-manifest.json +1 -0
  62. package/.next/server/interception-route-rewrite-manifest.js +1 -0
  63. package/.next/server/middleware-build-manifest.js +1 -0
  64. package/.next/server/middleware-manifest.json +6 -0
  65. package/.next/server/middleware-react-loadable-manifest.js +1 -0
  66. package/.next/server/next-font-manifest.js +1 -0
  67. package/.next/server/next-font-manifest.json +1 -0
  68. package/.next/server/pages/404.html +1 -0
  69. package/.next/server/pages/500.html +1 -0
  70. package/.next/server/pages/_app.js +1 -0
  71. package/.next/server/pages/_app.js.nft.json +1 -0
  72. package/.next/server/pages/_document.js +1 -0
  73. package/.next/server/pages/_document.js.nft.json +1 -0
  74. package/.next/server/pages/_error.js +1 -0
  75. package/.next/server/pages/_error.js.nft.json +1 -0
  76. package/.next/server/pages-manifest.json +1 -0
  77. package/.next/server/server-reference-manifest.js +1 -0
  78. package/.next/server/server-reference-manifest.json +1 -0
  79. package/.next/server/webpack-runtime.js +1 -0
  80. package/.next/static/chunks/117-9bcfe95f89d4b2e1.js +2 -0
  81. package/.next/static/chunks/29-984b7c92c950b64f.js +1 -0
  82. package/.next/static/chunks/app/_not-found/page-32c70da5a397ed57.js +1 -0
  83. package/.next/static/chunks/app/layout-cbd3ebdc4ecc5247.js +1 -0
  84. package/.next/static/chunks/app/page-448ab87af648362a.js +1 -0
  85. package/.next/static/chunks/fd9d1056-9f91b5e418130764.js +1 -0
  86. package/.next/static/chunks/framework-f66176bb897dc684.js +1 -0
  87. package/.next/static/chunks/main-a3aef5995f5a9328.js +1 -0
  88. package/.next/static/chunks/main-app-9982ced3bf7037dc.js +1 -0
  89. package/.next/static/chunks/pages/_app-72b849fbd24ac258.js +1 -0
  90. package/.next/static/chunks/pages/_error-7ba65e1336b92748.js +1 -0
  91. package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  92. package/.next/static/chunks/webpack-35b091ca5c5192ac.js +1 -0
  93. package/.next/static/vSEQaRlm1A99jSM80ZjFU/_buildManifest.js +1 -0
  94. package/.next/static/vSEQaRlm1A99jSM80ZjFU/_ssgManifest.js +1 -0
  95. package/.next/trace +2 -0
  96. package/.next/types/app/api/[resource]/[id]/route.ts +343 -0
  97. package/.next/types/app/api/[resource]/route.ts +343 -0
  98. package/.next/types/app/api/info/route.ts +343 -0
  99. package/.next/types/app/api/login/route.ts +343 -0
  100. package/.next/types/app/api/register/route.ts +343 -0
  101. package/.next/types/app/layout.ts +79 -0
  102. package/.next/types/app/page.ts +79 -0
  103. package/.next/types/package.json +1 -0
  104. package/app/api/[resource]/[id]/route.js +34 -0
  105. package/app/api/[resource]/route.js +74 -0
  106. package/app/api/info/route.js +26 -0
  107. package/app/api/login/route.js +27 -0
  108. package/app/api/register/route.js +32 -0
  109. package/app/layout.jsx +7 -0
  110. package/app/page.jsx +321 -0
  111. package/bin/cli.js +37 -0
  112. package/jsconfig.json +8 -0
  113. package/{src → lib}/auth.js +13 -11
  114. package/lib/db.js +47 -0
  115. package/next.config.js +21 -0
  116. package/package.json +24 -13
  117. package/bin/db-json-cli.js +0 -30
  118. package/src/index.ejs +0 -261
  119. package/src/server.js +0 -146
@@ -0,0 +1,32 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getDB, saveDB } from "@/lib/db";
3
+ import { hashPassword, generateTokens } from "@/lib/auth";
4
+
5
+ export async function POST(request) {
6
+ try {
7
+ const { email, password, name } = await request.json();
8
+
9
+ if (!email || !password) {
10
+ return NextResponse.json({ message: "Email/password required" }, { status: 400 });
11
+ }
12
+
13
+ const db = await getDB();
14
+ const exists = db.users.find((u) => u.email === email);
15
+
16
+ if (exists) {
17
+ return NextResponse.json({ message: "User already exists" }, { status: 409 });
18
+ }
19
+
20
+ const hashed = await hashPassword(password);
21
+ const id = db.users.length ? Math.max(...db.users.map((u) => u.id)) + 1 : 1;
22
+ const newUser = { id, email, name: name || "", password: hashed };
23
+
24
+ db.users.push(newUser);
25
+ await saveDB(db);
26
+
27
+ const tokens = generateTokens({ id, email });
28
+ return NextResponse.json(tokens);
29
+ } catch (error) {
30
+ return NextResponse.json({ message: "Registration failed" }, { status: 500 });
31
+ }
32
+ }
package/app/layout.jsx ADDED
@@ -0,0 +1,7 @@
1
+ export default function RootLayout({ children }) {
2
+ return (
3
+ <html lang="en">
4
+ <body style={{ margin: 0, padding: 0 }}>{children}</body>
5
+ </html>
6
+ );
7
+ }
package/app/page.jsx ADDED
@@ -0,0 +1,321 @@
1
+ "use client";
2
+
3
+ import { useState, useEffect } from "react";
4
+
5
+ export default function HomePage() {
6
+ const [routeList, setRouteList] = useState([]);
7
+ const [port, setPort] = useState(4000);
8
+ const [loading, setLoading] = useState(true);
9
+ const [activeEndpoint, setActiveEndpoint] = useState(null);
10
+
11
+ useEffect(() => {
12
+ fetch("/api/info")
13
+ .then((res) => res.json())
14
+ .then((data) => {
15
+ setRouteList(data.routeList);
16
+ setPort(data.port);
17
+ setLoading(false);
18
+ })
19
+ .catch((err) => {
20
+ console.error("Failed to load API info:", err);
21
+ setLoading(false);
22
+ });
23
+ }, []);
24
+
25
+ if (loading) {
26
+ return (
27
+ <>
28
+ <div className="loading-container">Loading...</div>
29
+ <style jsx>{`
30
+ .loading-container {
31
+ display: flex;
32
+ justify-content: center;
33
+ align-items: center;
34
+ min-height: 100vh;
35
+ background: linear-gradient(to bottom, #1a1a2e 0%, #16213e 100%);
36
+ color: white;
37
+ font-size: 1.5rem;
38
+ }
39
+ `}</style>
40
+ </>
41
+ );
42
+ }
43
+
44
+ return (
45
+ <>
46
+ <div className="container">
47
+ <div className="header">
48
+ <div className="header-content">
49
+ <h1>🚀 db-json-cli API</h1>
50
+ <p>RESTful JSON API Documentation</p>
51
+ </div>
52
+ </div>
53
+
54
+ <div className="content">
55
+ <div className="info-box">
56
+ <h2>📖 API Information</h2>
57
+ <p>Welcome to the db-json-cli API. This API provides RESTful endpoints for managing your data.</p>
58
+ <div className="base-url">Base URL: http://localhost:{port}</div>
59
+ </div>
60
+
61
+ <div className="endpoints">
62
+ <h2>Available Endpoints</h2>
63
+
64
+ {routeList.map((r) => (
65
+ <div key={r.key}>
66
+ <div
67
+ className={`endpoint-item ${activeEndpoint === `${r.key}-get` ? "active" : ""}`}
68
+ onClick={() => setActiveEndpoint(activeEndpoint === `${r.key}-get` ? null : `${r.key}-get`)}
69
+ >
70
+ <div className="endpoint-header">
71
+ <span className="method-badge method-get">GET</span>
72
+ <span className="endpoint-path">/{r.key}</span>
73
+ <span className={`permission-badge permission-${r.permission}`}>
74
+ {r.permission === "public" ? "🔓" : "🔒"} {r.permission.toUpperCase()}
75
+ </span>
76
+ <span className="endpoint-count">
77
+ {r.count} {r.count === 1 ? "item" : "items"}
78
+ </span>
79
+ </div>
80
+ <div className="endpoint-description">
81
+ Retrieve all {r.key} or filter by ID range using ?from=1&to=10
82
+ </div>
83
+ {activeEndpoint === `${r.key}-get` && (
84
+ <div className="endpoint-actions">
85
+ <a
86
+ href={`/api/${r.key}`}
87
+ target="_blank"
88
+ rel="noopener noreferrer"
89
+ className="action-btn btn-primary"
90
+ onClick={(e) => e.stopPropagation()}
91
+ >
92
+ Try it out
93
+ </a>
94
+ </div>
95
+ )}
96
+ </div>
97
+
98
+ <div className="endpoint-item">
99
+ <div className="endpoint-header">
100
+ <span className="method-badge method-get">GET</span>
101
+ <span className="endpoint-path">/{r.key}/:id</span>
102
+ <span className={`permission-badge permission-${r.permission}`}>
103
+ {r.permission === "public" ? "🔓" : "🔒"} {r.permission.toUpperCase()}
104
+ </span>
105
+ </div>
106
+ <div className="endpoint-description">Retrieve a specific item by ID</div>
107
+ </div>
108
+
109
+ <div className="endpoint-item">
110
+ <div className="endpoint-header">
111
+ <span className="method-badge method-post">POST</span>
112
+ <span className="endpoint-path">/{r.key}</span>
113
+ <span className={`permission-badge permission-${r.permission}`}>
114
+ {r.permission === "public" ? "🔓" : "🔒"} {r.permission.toUpperCase()}
115
+ </span>
116
+ </div>
117
+ <div className="endpoint-description">Create a new item (ID will be auto-generated)</div>
118
+ </div>
119
+ </div>
120
+ ))}
121
+
122
+ <div className="endpoint-item">
123
+ <div className="endpoint-header">
124
+ <span className="method-badge method-post">POST</span>
125
+ <span className="endpoint-path">/register</span>
126
+ </div>
127
+ <div className="endpoint-description">Register a new user account</div>
128
+ </div>
129
+
130
+ <div className="endpoint-item">
131
+ <div className="endpoint-header">
132
+ <span className="method-badge method-post">POST</span>
133
+ <span className="endpoint-path">/login</span>
134
+ </div>
135
+ <div className="endpoint-description">Login and receive access tokens</div>
136
+ </div>
137
+ </div>
138
+ </div>
139
+
140
+ <div className="footer">
141
+ <p>Generated by db-json-cli • Made with ♥</p>
142
+ </div>
143
+ </div>
144
+
145
+ <style jsx>{`
146
+ * {
147
+ margin: 0;
148
+ padding: 0;
149
+ box-sizing: border-box;
150
+ }
151
+ .container {
152
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
153
+ background: linear-gradient(to bottom, #1a1a2e 0%, #16213e 100%);
154
+ color: #333;
155
+ min-height: 100vh;
156
+ }
157
+ .header {
158
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
159
+ padding: 3rem 2rem;
160
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
161
+ }
162
+ .header-content {
163
+ max-width: 1200px;
164
+ margin: 0 auto;
165
+ }
166
+ .header h1 {
167
+ color: white;
168
+ font-size: 2.5rem;
169
+ margin-bottom: 0.5rem;
170
+ font-weight: 700;
171
+ }
172
+ .header p {
173
+ color: rgba(255, 255, 255, 0.9);
174
+ font-size: 1.1rem;
175
+ }
176
+ .content {
177
+ max-width: 1200px;
178
+ margin: 0 auto;
179
+ padding: 2rem;
180
+ }
181
+ .info-box {
182
+ background: white;
183
+ border-radius: 12px;
184
+ padding: 1.5rem;
185
+ margin-bottom: 2rem;
186
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
187
+ }
188
+ .info-box h2 {
189
+ color: #667eea;
190
+ font-size: 1.3rem;
191
+ margin-bottom: 0.5rem;
192
+ }
193
+ .info-box p {
194
+ color: #666;
195
+ line-height: 1.6;
196
+ }
197
+ .base-url {
198
+ background: #f8f9fa;
199
+ padding: 0.5rem 1rem;
200
+ border-radius: 6px;
201
+ font-family: "Courier New", monospace;
202
+ color: #333;
203
+ display: inline-block;
204
+ margin-top: 0.5rem;
205
+ }
206
+ .endpoints {
207
+ background: white;
208
+ border-radius: 12px;
209
+ padding: 2rem;
210
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
211
+ }
212
+ .endpoints h2 {
213
+ color: #333;
214
+ font-size: 1.5rem;
215
+ margin-bottom: 1.5rem;
216
+ padding-bottom: 0.5rem;
217
+ border-bottom: 2px solid #667eea;
218
+ }
219
+ .endpoint-item {
220
+ background: #f8f9fa;
221
+ border: 1px solid #e9ecef;
222
+ border-radius: 8px;
223
+ padding: 1.5rem;
224
+ margin-bottom: 1rem;
225
+ transition: all 0.3s ease;
226
+ cursor: pointer;
227
+ }
228
+ .endpoint-item:hover,
229
+ .endpoint-item.active {
230
+ transform: translateY(-2px);
231
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
232
+ border-color: #667eea;
233
+ }
234
+ .endpoint-header {
235
+ display: flex;
236
+ align-items: center;
237
+ gap: 1rem;
238
+ margin-bottom: 1rem;
239
+ flex-wrap: wrap;
240
+ }
241
+ .method-badge {
242
+ padding: 0.3rem 0.8rem;
243
+ border-radius: 4px;
244
+ font-weight: 600;
245
+ font-size: 0.75rem;
246
+ text-transform: uppercase;
247
+ letter-spacing: 0.5px;
248
+ }
249
+ .method-get {
250
+ background: #e7f5ff;
251
+ color: #1971c2;
252
+ }
253
+ .method-post {
254
+ background: #d3f9d8;
255
+ color: #2f9e44;
256
+ }
257
+ .permission-badge {
258
+ padding: 0.3rem 0.8rem;
259
+ border-radius: 4px;
260
+ font-weight: 600;
261
+ font-size: 0.75rem;
262
+ text-transform: uppercase;
263
+ letter-spacing: 0.5px;
264
+ }
265
+ .permission-public {
266
+ background: #d3f9d8;
267
+ color: #2f9e44;
268
+ }
269
+ .permission-private {
270
+ background: #ffd43b;
271
+ color: #856404;
272
+ }
273
+ .endpoint-path {
274
+ font-family: "Courier New", monospace;
275
+ font-size: 1.1rem;
276
+ color: #333;
277
+ font-weight: 500;
278
+ }
279
+ .endpoint-count {
280
+ margin-left: auto;
281
+ background: #667eea;
282
+ color: white;
283
+ padding: 0.3rem 0.8rem;
284
+ border-radius: 20px;
285
+ font-size: 0.85rem;
286
+ font-weight: 600;
287
+ }
288
+ .endpoint-description {
289
+ color: #666;
290
+ line-height: 1.5;
291
+ }
292
+ .endpoint-actions {
293
+ margin-top: 1rem;
294
+ }
295
+ .action-btn {
296
+ padding: 0.5rem 1rem;
297
+ border-radius: 6px;
298
+ text-decoration: none;
299
+ font-size: 0.9rem;
300
+ font-weight: 500;
301
+ transition: all 0.2s;
302
+ display: inline-block;
303
+ }
304
+ .btn-primary {
305
+ background: #667eea;
306
+ color: white;
307
+ }
308
+ .btn-primary:hover {
309
+ background: #5568d3;
310
+ transform: translateY(-1px);
311
+ }
312
+ .footer {
313
+ text-align: center;
314
+ padding: 2rem;
315
+ color: rgba(255, 255, 255, 0.7);
316
+ font-size: 0.9rem;
317
+ }
318
+ `}</style>
319
+ </>
320
+ );
321
+ }
package/bin/cli.js ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execSync } from "child_process";
4
+ import yargs from "yargs";
5
+ import { hideBin } from "yargs/helpers";
6
+ import path from "path";
7
+ import { fileURLToPath } from "url";
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+
12
+ const argv = yargs(hideBin(process.argv))
13
+ .option("port", { alias: "p", type: "number", default: 4000 })
14
+ .option("db", { alias: "d", type: "string", default: "./db.json" })
15
+ .option("watch", { alias: "w", type: "boolean", default: false })
16
+ .help().argv;
17
+
18
+ // 패키지 내부의 프로젝트 루트 (db-json-cli 자체)
19
+ const packageRoot = path.join(__dirname, "..");
20
+
21
+ process.env.DB_PATH = path.resolve(argv.db);
22
+ process.env.PORT = argv.port.toString();
23
+
24
+ console.log(`✅ db-json-cli running on http://localhost:${argv.port}\n`);
25
+
26
+ try {
27
+ // packageRoot에서 Next.js 실행
28
+ execSync(`npx next start -p ${argv.port}`, {
29
+ stdio: "inherit",
30
+ cwd: packageRoot,
31
+ env: process.env,
32
+ shell: true,
33
+ });
34
+ } catch (err) {
35
+ console.error("Error:", err.message);
36
+ process.exit(1);
37
+ }
package/jsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": ".",
4
+ "paths": {
5
+ "@/*": ["./*"]
6
+ }
7
+ }
8
+ }
@@ -1,8 +1,8 @@
1
1
  import jwt from "jsonwebtoken";
2
2
  import bcrypt from "bcryptjs";
3
3
 
4
- const ACCESS_SECRET = "access-secret";
5
- const REFRESH_SECRET = "refresh-secret";
4
+ const ACCESS_SECRET = process.env.ACCESS_SECRET || "access-secret";
5
+ const REFRESH_SECRET = process.env.REFRESH_SECRET || "refresh-secret";
6
6
 
7
7
  export const hashPassword = async (password) => {
8
8
  const salt = await bcrypt.genSalt(10);
@@ -19,16 +19,18 @@ export const generateTokens = (payload) => {
19
19
  return { accessToken, refreshToken };
20
20
  };
21
21
 
22
- export const authMiddleware = async (req, res, next) => {
23
- const auth = req.headers["authorization"];
24
- if (!auth) return res.status(401).json({ message: "No token" });
25
-
26
- const token = auth.split(" ")[1];
22
+ export const verifyToken = (token) => {
27
23
  try {
28
- const decoded = jwt.verify(token, ACCESS_SECRET);
29
- req.user = decoded;
30
- next();
24
+ return jwt.verify(token, ACCESS_SECRET);
31
25
  } catch (e) {
32
- return res.status(401).json({ message: "Invalid token" });
26
+ return null;
33
27
  }
34
28
  };
29
+
30
+ export const authMiddleware = (req) => {
31
+ const auth = req.headers.get("authorization");
32
+ if (!auth) return null;
33
+
34
+ const token = auth.split(" ")[1];
35
+ return verifyToken(token);
36
+ };
package/lib/db.js ADDED
@@ -0,0 +1,47 @@
1
+ import fs from "fs-extra";
2
+
3
+ let dbCache = null;
4
+ let dbPath = process.env.DB_PATH || "./db.json";
5
+
6
+ export const getDB = async () => {
7
+ if (dbCache) return dbCache;
8
+
9
+ const defaultDB = {
10
+ users: [],
11
+ rules: { test1: "public", test2: "private", test3: "public" },
12
+ test1: [
13
+ { id: 1, message: "good" },
14
+ { id: 2, message: "good" },
15
+ { id: 3, message: "good" },
16
+ ],
17
+ test2: [
18
+ { id: 1, message: "good" },
19
+ { id: 2, message: "good" },
20
+ { id: 3, message: "good" },
21
+ ],
22
+ test3: [
23
+ { id: 1, message: "good" },
24
+ { id: 2, message: "good" },
25
+ { id: 3, message: "good" },
26
+ ],
27
+ };
28
+
29
+ if (fs.existsSync(dbPath)) {
30
+ dbCache = await fs.readJson(dbPath);
31
+ } else {
32
+ dbCache = defaultDB;
33
+ await fs.writeJson(dbPath, defaultDB, { spaces: 2 });
34
+ }
35
+
36
+ return dbCache;
37
+ };
38
+
39
+ export const saveDB = async (db) => {
40
+ dbCache = db;
41
+ await fs.writeJson(dbPath, db, { spaces: 2 });
42
+ };
43
+
44
+ export const refreshDB = async () => {
45
+ dbCache = null;
46
+ return await getDB();
47
+ };
package/next.config.js ADDED
@@ -0,0 +1,21 @@
1
+ /** @type {import('next').NextConfig} */
2
+ const nextConfig = {
3
+ reactStrictMode: true,
4
+ async headers() {
5
+ return [
6
+ {
7
+ source: "/(.*)",
8
+ headers: [
9
+ {
10
+ key: "Content-Security-Policy",
11
+ // 아예 모든 연결을 허용해서 테스트해보세요 (개발용)
12
+ value:
13
+ "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' http://localhost:4000;",
14
+ },
15
+ ],
16
+ },
17
+ ];
18
+ },
19
+ };
20
+
21
+ export default nextConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "db-json-cli",
3
- "version": "1.0.5",
3
+ "version": "2.0.1",
4
4
  "license": "MIT",
5
5
  "description": "Lightweight JSON-based backend server with JWT authentication and CLI support",
6
6
  "repository": {
@@ -17,24 +17,35 @@
17
17
  "jwt",
18
18
  "mock-server",
19
19
  "express",
20
- "api"
20
+ "api",
21
+ "db-json-cli"
21
22
  ],
23
+ "type": "module",
22
24
  "bin": {
23
- "db-json-cli": "./bin/db-json-cli.js"
25
+ "db-json-cli": "./bin/cli.js"
24
26
  },
25
- "type": "module",
27
+ "files": [
28
+ "bin/",
29
+ "app/",
30
+ "lib/",
31
+ ".next/",
32
+ "next.config.js",
33
+ "jsconfig.json",
34
+ "db.json"
35
+ ],
26
36
  "scripts": {
27
- "start": "node bin/db-json-cli.js"
37
+ "dev": "next dev",
38
+ "build": "next build",
39
+ "start": "next start",
40
+ "prepublishOnly": "npm run build"
28
41
  },
29
42
  "dependencies": {
43
+ "next": "^14.0.0",
44
+ "react": "^18.2.0",
45
+ "react-dom": "^18.2.0",
46
+ "fs-extra": "^11.2.0",
47
+ "jsonwebtoken": "^9.0.2",
30
48
  "bcryptjs": "^2.4.3",
31
- "body-parser": "^1.20.2",
32
- "chokidar": "^4.0.3",
33
- "cors": "^2.8.5",
34
- "ejs": "^3.1.10",
35
- "express": "^4.21.2",
36
- "fs-extra": "^11.1.1",
37
- "jsonwebtoken": "^9.0.0",
38
- "yargs": "^18.0.0"
49
+ "yargs": "^17.7.2"
39
50
  }
40
51
  }
@@ -1,30 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import yargs from "yargs";
4
- import { hideBin } from "yargs/helpers";
5
- import { startServer } from "../src/server.js";
6
-
7
- const argv = yargs(hideBin(process.argv))
8
- .option("port", {
9
- alias: "p",
10
- type: "number",
11
- default: 4000,
12
- description: "Port to run the server on",
13
- })
14
- .option("db", {
15
- alias: "d",
16
- type: "string",
17
- default: "./db.json",
18
- description: "Path to JSON database file",
19
- })
20
- .option("watch", {
21
- alias: "w",
22
- type: "boolean",
23
- default: false,
24
- description: "Watch DB file for changes",
25
- })
26
- .help().argv;
27
-
28
- if (argv.watch) process.env.WATCH = "true";
29
-
30
- startServer(argv.db, argv.port);