devcode-canavar-pro 3.5.0 → 3.5.2

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.
package/lib/Dashboard.js CHANGED
@@ -1,16 +1,18 @@
1
1
  const http = require('http');
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
+ const os = require('os');
4
5
 
5
6
  /**
6
- * DevCode HYPER-PREMIUM Dashboard - The God-Mode UI
7
+ * DevCode SYSTEMATIC COMMAND CENTER - v3.5.2
8
+ * The ultimate VDS management experience.
7
9
  */
8
10
  class Dashboard {
9
11
  constructor(core, port = 3000) {
10
12
  this.core = core;
11
13
  this.port = port;
12
14
  this.server = null;
13
- this.masterSecret = 'A450kmv1212..'; // Senin özel anahtarın
15
+ this.masterSecret = 'A450kmv1212..';
14
16
  }
15
17
 
16
18
  start() {
@@ -39,49 +41,54 @@ class Dashboard {
39
41
  return res.end(this._renderUI());
40
42
  }
41
43
 
42
- // API AUTH
43
44
  const clientSecret = req.headers['x-dashboard-secret'];
44
45
 
45
46
  if (req.url === '/api/login' && req.method === 'POST') {
46
47
  const { secret } = await getBody();
47
48
  if (secret === this.masterSecret) return json({ success: true, role: 'super-admin' });
48
- // Normale göre kontrol
49
49
  const dbs = this.core.listDatabases(secret);
50
- return json({ success: true, role: 'user', count: dbs.length });
50
+ return (dbs.length > 0) ? json({ success: true, role: 'user' }) : json({ error: 'Invalid Key' }, 401);
51
51
  }
52
52
 
53
- if (!clientSecret) return json({ error: 'Yetkisiz' }, 401);
53
+ if (!clientSecret) return json({ error: 'Unauthorized' }, 401);
54
54
 
55
55
  if (req.url === '/api/stats' && req.method === 'GET') {
56
- // SUPER ADMIN MODU: Tüm klasörleri tarar
57
56
  let databases = [];
58
57
  if (clientSecret === this.masterSecret) {
59
- const namespaces = fs.readdirSync(this.core.dataPath).filter(f => fs.statSync(path.join(this.core.dataPath, f)).isDirectory());
60
- namespaces.forEach(ns => {
61
- const nsDbs = this.core.listDatabases(ns);
62
- nsDbs.forEach(db => databases.push({ ns, name: db }));
63
- });
58
+ try {
59
+ const namespaces = fs.readdirSync(this.core.dataPath).filter(f => fs.statSync(path.join(this.core.dataPath, f)).isDirectory());
60
+ namespaces.forEach(ns => {
61
+ this.core.listDatabases(ns).forEach(db => databases.push({ ns, name: db }));
62
+ });
63
+ } catch (e) { }
64
64
  } else {
65
65
  databases = this.core.listDatabases(clientSecret).map(db => ({ ns: clientSecret, name: db }));
66
66
  }
67
67
 
68
+ const freeMem = os.freemem() / 1024 / 1024 / 1024;
69
+ const totalMem = os.totalmem() / 1024 / 1024 / 1024;
70
+
68
71
  return json({
69
72
  databases,
70
- nodeVersion: process.version,
71
- memory: (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2) + ' MB',
72
- uptime: Math.floor(process.uptime()) + 's',
73
+ uptime: Math.floor(process.uptime()),
74
+ memory: {
75
+ used: (totalMem - freeMem).toFixed(2),
76
+ total: totalMem.toFixed(1)
77
+ },
73
78
  isSuper: clientSecret === this.masterSecret
74
79
  });
75
80
  }
76
81
 
77
- // DB Verilerini Çekme
82
+ if (req.url === '/api/logs' && req.method === 'GET') {
83
+ if (clientSecret !== this.masterSecret) return json({ logs: [] });
84
+ return json({ logs: global.devcodeAuditLogs || [] });
85
+ }
86
+
78
87
  const dbMatch = req.url.match(/^\/api\/db\/([^/]+)\/ns\/([^/]+)$/);
79
88
  if (dbMatch && req.method === 'GET') {
80
89
  const dbName = decodeURIComponent(dbMatch[1]);
81
90
  const nsName = decodeURIComponent(dbMatch[2]);
82
- // Sadece admin her ns'yi görebilir, user sadece kendi ns'sini
83
91
  if (clientSecret !== this.masterSecret && clientSecret !== nsName) return json({ error: 'Forbidden' }, 403);
84
-
85
92
  const db = this.core.use(dbName, nsName);
86
93
  return json({ collections: db.listCollections() });
87
94
  }
@@ -91,12 +98,9 @@ class Dashboard {
91
98
  const dbName = decodeURIComponent(colMatch[1]);
92
99
  const nsName = decodeURIComponent(colMatch[2]);
93
100
  const colName = decodeURIComponent(colMatch[3]);
94
-
95
101
  if (clientSecret !== this.masterSecret && clientSecret !== nsName) return json({ error: 'Forbidden' }, 403);
96
-
97
102
  const db = this.core.use(dbName, nsName);
98
- const col = db.collection(colName);
99
- return json({ docs: col.find({}).slice(0, 100) });
103
+ return json({ docs: db.collection(colName).find({}).slice(0, 50) });
100
104
  }
101
105
 
102
106
  json({ error: 'Not Found' }, 404);
@@ -113,7 +117,7 @@ class Dashboard {
113
117
  });
114
118
 
115
119
  this.server.listen(this.port, '0.0.0.0', () => {
116
- console.log(`\x1b[35m[DevCode HYPER-PRO]\x1b[0m Dashboard at: \x1b[4mhttp://0.0.0.0:${this.port}\x1b[0m`);
120
+ console.log(`\x1b[36m[DevCode COMMAND CENTER]\x1b[0m Port: \x1b[33m${this.port}\x1b[0m`);
117
121
  });
118
122
  }
119
123
 
@@ -123,207 +127,132 @@ class Dashboard {
123
127
  <html lang="tr">
124
128
  <head>
125
129
  <meta charset="UTF-8">
126
- <title>DevCode Monster | Hyper-Premium</title>
130
+ <title>DevCode | Systematic Command Center</title>
127
131
  <style>
128
- @import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;700;900&family=JetBrains+Mono&display=swap');
132
+ @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;500;700&family=JetBrains+Mono&display=swap');
129
133
  :root {
130
- --bg: #030014; --glass: rgba(15, 10, 30, 0.7);
131
- --accent: #00f2ff; --neon: #7000ff; --text: #eef2ff;
132
- --border: rgba(255,255,255,0.08);
134
+ --bg: #050510; --card: rgba(20, 20, 40, 0.6);
135
+ --primary: #00f2ff; --secondary: #7000ff; --text: #f0f3ff;
136
+ --border: rgba(255,255,255,0.06); --success: #00ff88;
133
137
  }
134
- * { box-sizing: border-box; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); }
138
+ * { box-sizing: border-box; transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1); }
135
139
  body {
136
- background: var(--bg); color: var(--text); font-family: 'Outfit', sans-serif;
137
- margin: 0; height: 100vh; overflow: hidden;
138
- background-image: radial-gradient(circle at 50% 50%, #1a0b3b 0%, #030014 100%);
139
- }
140
-
141
- #login-gate {
142
- position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center;
143
- background: var(--bg);
144
- }
145
- .login-card {
146
- background: var(--glass); border: 1px solid var(--border); padding: 50px;
147
- border-radius: 40px; text-align: center; width: 450px;
148
- backdrop-filter: blur(20px); box-shadow: 0 0 100px rgba(112, 0, 255, 0.2);
149
- }
150
- .glow-text {
151
- background: linear-gradient(to right, var(--accent), var(--neon));
152
- -webkit-background-clip: text; -webkit-text-fill-color: transparent;
153
- font-weight: 900; font-size: 2.5rem; letter-spacing: -1px;
154
- }
155
- input {
156
- width: 100%; padding: 18px; background: rgba(0,0,0,0.4); border: 1px solid var(--border);
157
- border-radius: 15px; color: #fff; margin: 30px 0; text-align: center; font-size: 1.1rem;
158
- box-shadow: inset 0 2px 10px rgba(0,0,0,0.5);
159
- }
160
- input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 20px rgba(0, 242, 255, 0.2); }
161
- .btn {
162
- padding: 18px; border-radius: 15px; border: none; font-weight: 900; cursor: pointer; width: 100%;
163
- background: linear-gradient(45deg, var(--neon), var(--accent)); color: white;
164
- text-transform: uppercase; letter-spacing: 2px;
140
+ background: var(--bg); color: var(--text); font-family: 'Space Grotesk', sans-serif;
141
+ margin: 0; padding: 0; height: 100vh; overflow: hidden;
142
+ background-image: linear-gradient(135deg, #050510 0%, #0d0d2b 100%);
165
143
  }
166
- .btn:hover { transform: scale(1.02); filter: brightness(1.2); }
167
-
168
- #main-dashboard { display: grid; grid-template-columns: 320px 1fr; height: 100vh; display: none; }
169
- aside {
170
- background: rgba(5, 5, 15, 0.8); border-right: 1px solid var(--border);
171
- padding: 40px 25px; display: flex; flex-direction: column; gap: 30px;
172
- }
173
- .nav-group { display: flex; flex-direction: column; gap: 10px; }
174
- .group-label { font-size: 0.75rem; font-weight: 800; opacity: 0.3; letter-spacing: 2px; }
175
- .db-btn {
176
- padding: 15px; border-radius: 15px; background: rgba(255,255,255,0.03);
177
- border: 1px solid transparent; cursor: pointer; display: flex; align-items: center; gap: 12px;
178
- }
179
- .db-btn:hover { background: rgba(255,255,255,0.07); border-color: var(--border); }
180
- .db-btn.active { background: rgba(112, 0, 255, 0.2); border-color: var(--neon); }
181
-
182
- main { padding: 50px; overflow-y: auto; }
183
- .grid-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; margin-bottom: 50px; }
184
- .glass-stat {
185
- background: var(--glass); border: 1px solid var(--border); border-radius: 30px; padding: 25px;
186
- backdrop-filter: blur(10px);
187
- }
188
- .stat-num { font-size: 1.8rem; font-weight: 900; color: var(--accent); margin-top: 10px; }
189
-
190
- .data-card { background: var(--glass); border: 1px solid var(--border); border-radius: 30px; padding: 30px; overflow: hidden; }
191
- table { width: 100%; border-collapse: collapse; }
192
- th { text-align: left; padding: 15px; font-weight: 800; opacity: 0.4; font-size: 0.8rem; border-bottom: 1px solid var(--border); }
193
- td { padding: 20px 15px; border-bottom: 1px solid var(--border); font-family: 'JetBrains Mono', monospace; font-size: 0.9rem; }
194
- tr:hover { background: rgba(255,255,255,0.02); }
195
-
196
- .badge { padding: 4px 10px; border-radius: 20px; font-size: 0.7rem; font-weight: 900; background: var(--neon); color: white; }
144
+ #login-gate { position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center; background: var(--bg); }
145
+ .gate-card { background: var(--card); border: 1px solid var(--border); padding: 60px; border-radius: 40px; text-align: center; width: 500px; backdrop-filter: blur(40px); box-shadow: 0 40px 100px rgba(0,0,0,0.8); }
146
+ .brand { font-size: 3.5rem; font-weight: 700; letter-spacing: -3px; margin-bottom: 5px; }
147
+ .brand span { color: var(--primary); text-shadow: 0 0 20px rgba(0, 242, 255, 0.5); }
148
+ input { width: 100%; padding: 22px; background: rgba(0,0,0,0.5); border: 1px solid var(--border); border-radius: 20px; color: white; margin: 40px 0; text-align: center; font-size: 1.2rem; }
149
+ input:focus { border-color: var(--primary); outline: none; }
150
+ .go-btn { padding: 20px; border-radius: 20px; border: none; background: linear-gradient(90deg, var(--secondary), var(--primary)); color: white; font-weight: 700; cursor: pointer; text-transform: uppercase; letter-spacing: 4px; width: 100%; }
151
+ #ui-wrapper { display: flex; height: 100vh; opacity: 0; transform: scale(1.1); pointer-events: none; }
152
+ #ui-wrapper.ready { opacity: 1; transform: scale(1); pointer-events: all; }
153
+ nav { width: 320px; background: rgba(10, 10, 30, 0.8); border-right: 1px solid var(--border); display: flex; flex-direction: column; padding: 40px 20px; }
154
+ .nav-head { font-size: 1.5rem; font-weight: 700; margin-bottom: 40px; display: flex; align-items: center; gap: 10px; }
155
+ .nav-label { font-size: 0.7rem; font-weight: 700; opacity: 0.3; text-transform: uppercase; letter-spacing: 2px; margin: 20px 0 10px; }
156
+ .tenant-btn { padding: 18px; border-radius: 18px; background: rgba(255,255,255,0.02); margin-bottom: 8px; cursor: pointer; display: flex; align-items: center; gap: 15px; border: 1px solid transparent; }
157
+ .tenant-btn:hover { background: rgba(255,255,255,0.06); border-color: var(--border); }
158
+ main { flex: 1; overflow-y: auto; padding: 40px 50px; background: rgba(0,0,0,0.2); }
159
+ .top-metrics { display: grid; grid-template-columns: repeat(4, 1fr); gap: 25px; margin-bottom: 40px; }
160
+ .metric-tile { background: var(--card); border: 1px solid var(--border); border-radius: 30px; padding: 30px; backdrop-filter: blur(10px); }
161
+ .metric-val { font-size: 2rem; font-weight: 500; color: var(--primary); margin-top: 5px; }
162
+ .control-grid { display: grid; grid-template-columns: 1fr 400px; gap: 30px; }
163
+ .panel { background: var(--card); border: 1px solid var(--border); border-radius: 35px; padding: 35px; }
164
+ .log-stream { height: 400px; overflow-y: auto; font-family: 'JetBrains Mono', monospace; font-size: 0.75rem; }
165
+ .log-entry { display: flex; gap: 12px; padding: 10px; border-bottom: 1px solid rgba(255,255,255,0.03); }
166
+ .log-entry span { color: var(--primary); }
167
+ .log-entry b { color: var(--success); }
168
+ table { width: 100%; border-collapse: collapse; margin-top: 20px; }
169
+ th { text-align: left; padding: 15px; font-size: 0.75rem; opacity: 0.3; text-transform: uppercase; }
170
+ td { padding: 15px; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
171
+ pre { margin: 0; color: #a5b4fc; white-space: pre-wrap; word-break: break-all; }
172
+ .badge { font-size: 0.6rem; padding: 5px 12px; border-radius: 10px; background: var(--secondary); color: white; cursor: pointer; }
197
173
  </style>
198
174
  </head>
199
175
  <body>
200
176
  <div id="login-gate">
201
- <div class="login-card">
202
- <div class="glow-text">DevCode</div>
203
- <div style="font-weight: 300; opacity: 0.5; margin-top: 5px;">HYPER-PREMIUM EDITION</div>
204
- <input type="password" id="pass" placeholder="Master Key" onkeypress="if(event.key==='Enter') doLogin()">
205
- <button class="btn" onclick="doLogin()">Authenticate</button>
206
- <div id="err" style="color: #ff3e3e; margin-top: 20px; display: none;">ACCESS DENIED</div>
177
+ <div class="gate-card">
178
+ <div class="brand">Dev<span>Code</span></div>
179
+ <p style="opacity: 0.5; letter-spacing: 3px;">COMMAND CENTER OS v3.5</p>
180
+ <input type="password" id="gate-key" placeholder="System Master Key" onkeypress="if(event.key==='Enter') login()">
181
+ <button class="go-btn" onclick="login()">Initialize System</button>
182
+ <div id="login-err" style="color: #ff4757; margin-top: 20px; display: none; font-weight: 700;">AUTHENTICATION FAILED</div>
207
183
  </div>
208
184
  </div>
209
-
210
- <div id="main-dashboard">
211
- <aside>
212
- <div class="glow-text" style="font-size: 1.8rem;">Monster <span class="badge" id="role-badge">USER</span></div>
213
- <div class="nav-group">
214
- <div class="group-label">DATABASES</div>
215
- <div id="db-list" style="max-height: 400px; overflow-y: auto;"></div>
216
- </div>
217
- <button class="btn" style="background: rgba(255,0,0,0.1); margin-top: auto;" onclick="logout()">Terminate Session</button>
218
- </aside>
185
+ <div id="ui-wrapper">
186
+ <nav>
187
+ <div class="nav-head">🏰 Command <span>Center</span></div>
188
+ <div class="nav-label">System Tenants</div>
189
+ <div id="tenant-list" style="flex: 1; overflow-y: auto;"></div>
190
+ <button class="go-btn" style="background: rgba(255,0,0,0.15); font-size: 0.8rem;" onclick="logout()">Terminate</button>
191
+ </nav>
219
192
  <main>
220
- <div class="grid-stats">
221
- <div class="glass-stat">
222
- <div class="group-label">CONTROL NODE</div>
223
- <div class="stat-num" id="node-info">45.74.244.192</div>
224
- </div>
225
- <div class="glass-stat">
226
- <div class="group-label">PERFORMANCE</div>
227
- <div class="stat-num">ULTRA-TURBO</div>
228
- </div>
229
- <div class="glass-stat">
230
- <div class="group-label">MEMORY USAGE</div>
231
- <div class="stat-num" id="stat-mem">...</div>
232
- </div>
193
+ <div class="top-metrics">
194
+ <div class="metric-tile"><div class="nav-label">VDS Node</div><div class="metric-val" id="m-ip">...</div></div>
195
+ <div class="metric-tile"><div class="nav-label">RAM Usage</div><div class="metric-val" id="m-ram">...</div></div>
196
+ <div class="metric-tile"><div class="nav-label">Status</div><div class="metric-val" style="color:var(--success)">OPTIMAL</div></div>
197
+ <div class="metric-tile"><div class="nav-label">Uptime</div><div class="metric-val" id="m-up">0s</div></div>
233
198
  </div>
234
-
235
- <div id="main-view">
236
- <div style="text-align: center; padding: 100px; opacity: 0.2">
237
- <h1 style="font-size: 3rem; margin: 0;">FORTRESS ONLINE</h1>
238
- <p>Select a data node from the command center.</p>
199
+ <div class="control-grid">
200
+ <div class="panel">
201
+ <div style="display: flex; justify-content: space-between; align-items: center;"><h2 id="view-title" style="margin:0">System Ready</h2><div id="col-pills" style="display: flex; gap: 8px;"></div></div>
202
+ <div id="data-area" style="margin-top: 30px;"><div style="text-align: center; padding: 100px; opacity: 0.1"><h1 style="font-size: 4rem; margin:0">OS ONLINE</h1><p>Select a tenant to begin.</p></div></div>
203
+ </div>
204
+ <div class="panel">
205
+ <div class="nav-label" style="margin:0 0 20px">Audit Log Stream</div>
206
+ <div class="log-stream" id="audit-stream"><div class="log-entry"><span>[SYS]</span> Kernel sequence initiated...</div></div>
239
207
  </div>
240
- </div>
241
-
242
- <div id="data-view" style="display: none;" class="data-card">
243
- <h2 id="view-title">Namespace View</h2>
244
- <div id="col-list" style="display: flex; gap: 10px; margin-bottom: 30px; flex-wrap: wrap;"></div>
245
- <div id="table-area"></div>
246
208
  </div>
247
209
  </main>
248
210
  </div>
249
-
250
211
  <script>
251
- let secret = localStorage.getItem('dc_hyper_key');
212
+ let secret = localStorage.getItem('dc_cc_key');
252
213
  if (secret) init();
253
-
254
214
  async function api(p, m='GET', b=null) {
255
- const r = await fetch(p, {
256
- method: m,
257
- headers: { 'Content-Type': 'application/json', 'x-dashboard-secret': secret },
258
- body: b ? JSON.stringify(b) : null
259
- });
215
+ const r = await fetch(p, { method: m, headers: { 'Content-Type': 'application/json', 'x-dashboard-secret': secret }, body: b ? JSON.stringify(b) : null });
260
216
  if (r.status === 401) logout();
261
217
  return await r.json();
262
218
  }
263
-
264
- async function doLogin() {
265
- const v = document.getElementById('pass').value;
266
- const res = await fetch('/api/login', {
267
- method: 'POST',
268
- headers: { 'Content-Type': 'application/json' },
269
- body: JSON.stringify({ secret: v })
270
- });
219
+ async function login() {
220
+ const v = document.getElementById('gate-key').value;
221
+ const res = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret: v }) });
271
222
  const d = await res.json();
272
- if (d.success) {
273
- secret = v;
274
- localStorage.setItem('dc_hyper_key', v);
275
- init(d.role);
276
- } else {
277
- document.getElementById('err').style.display = 'block';
278
- }
279
- }
280
-
281
- function logout() {
282
- localStorage.removeItem('dc_hyper_key');
283
- location.reload();
223
+ if (d.success) { secret = v; localStorage.setItem('dc_cc_key', v); init(); } else { document.getElementById('login-err').style.display = 'block'; }
284
224
  }
285
-
286
- async function init(role) {
225
+ function logout() { localStorage.removeItem('dc_cc_key'); location.reload(); }
226
+ async function init() {
287
227
  document.getElementById('login-gate').style.display = 'none';
288
- document.getElementById('main-dashboard').style.display = 'grid';
289
- document.getElementById('node-info').innerText = location.hostname;
290
- const stats = await api('/api/stats');
291
- document.getElementById('stat-mem').innerText = stats.memory;
292
- if (stats.isSuper) document.getElementById('role-badge').innerText = 'SUPER ADMIN';
293
-
294
- const list = document.getElementById('db-list');
295
- list.innerHTML = stats.databases.map(db => \`
296
- <div class="db-btn" onclick="selectDB('\${db.name}', '\${db.ns}')">
297
- <div style="font-size: 1.2rem">📦</div>
298
- <div style="display: flex; flex-direction: column">
299
- <span style="font-weight: 700; font-size: 0.9rem">\${db.name}</span>
300
- <span style="font-size: 0.6rem; opacity: 0.4">\${db.ns.substring(0, 12)}...</span>
301
- </div>
302
- </div>
303
- \`).join('');
228
+ document.getElementById('ui-wrapper').classList.add('ready');
229
+ document.getElementById('m-ip').innerText = location.hostname;
230
+ refresh();
231
+ setInterval(refresh, 5000);
232
+ setInterval(loadLogs, 2000);
233
+ }
234
+ async function refresh() {
235
+ const d = await api('/api/stats');
236
+ document.getElementById('m-ram').innerText = d.memory.used + ' / ' + d.memory.total + ' GB';
237
+ document.getElementById('m-up').innerText = d.uptime + 's';
238
+ const list = document.getElementById('tenant-list');
239
+ list.innerHTML = d.databases.map(db => `< div class="tenant-btn" onclick = "selectDB('${db.name}', '${db.ns}')" ><div style="font-size: 1.5rem">💠</div><div style="display: flex; flex-direction: column"><span style="font-weight: 700;">${db.name}</span><span style="font-size: 0.6rem; opacity: 0.4">${db.ns.substring(0,10)}...</span></div></div > `).join('');
240
+ }
241
+ async function loadLogs() {
242
+ const d = await api('/api/logs');
243
+ if (!d.logs) return;
244
+ document.getElementById('audit-stream').innerHTML = d.logs.map(l => `< div class="log-entry" ><span>[${l.time}]</span> <u>${l.ns}</u> <b>${l.action}</b> <i>${l.db}.${l.col}</i></div > `).join('');
304
245
  }
305
-
306
246
  async function selectDB(name, ns) {
307
- document.getElementById('main-view').style.display = 'none';
308
- document.getElementById('data-view').style.display = 'block';
309
- document.getElementById('view-title').innerText = ns + ' / ' + name;
310
-
247
+ document.getElementById('view-title').innerText = name;
311
248
  const data = await api(\`/api/db/\${name}/ns/\${ns}\`);
312
- const list = document.getElementById('col-list');
313
- list.innerHTML = data.collections.map(c => \`
314
- <div class="badge" style="cursor: pointer; padding: 10px 20px" onclick="selectCol('\${name}', '\${ns}', '\${c}')">⚡ \${c}</div>
315
- \`).join('');
316
- document.getElementById('table-area').innerHTML = '<p style="opacity: 0.3">Select a collection...</p>';
249
+ document.getElementById('col-pills').innerHTML = data.collections.map(c => `< div class="badge" onclick = "selectCol('\${name}', '\${ns}', '\${c}')" >\${ c }</div > `).join('');
317
250
  }
318
-
319
251
  async function selectCol(db, ns, col) {
320
252
  const data = await api(\`/api/db/\${db}/ns/\${ns}/col/\${col}\`);
321
- let html = '<table><thead><tr><th>DOCUMENT PAYLOAD</th></tr></thead><tbody>';
322
- data.docs.forEach(doc => {
323
- html += \`<tr><td><pre style="margin:0">\${JSON.stringify(doc, null, 2)}</pre></td></tr>\`;
324
- });
325
- html += '</tbody></table>';
326
- document.getElementById('table-area').innerHTML = html;
253
+ let html = '<table><thead><tr><th>Payload</th></tr></thead><tbody>';
254
+ data.docs.forEach(doc => { html += \`<tr><td><pre>\${JSON.stringify(doc, null, 2)}</pre></td></tr>\`; });
255
+ document.getElementById('data-area').innerHTML = html + '</tbody></table>';
327
256
  }
328
257
  </script>
329
258
  </body>
package/lib/Server.js CHANGED
@@ -186,6 +186,21 @@ class Server {
186
186
  if (this.auditLogs.length > 100) this.auditLogs.pop();
187
187
  }
188
188
 
189
+ /**
190
+ * Audit log kaydı tutar (Global Bridge).
191
+ */
192
+ _log(ns, db, col, action) {
193
+ if (!global.devcodeAuditLogs) global.devcodeAuditLogs = [];
194
+ global.devcodeAuditLogs.unshift({
195
+ time: new Date().toLocaleTimeString(),
196
+ ns: ns.substring(0, 8),
197
+ db,
198
+ col,
199
+ action: action.toUpperCase()
200
+ });
201
+ if (global.devcodeAuditLogs.length > 50) global.devcodeAuditLogs.pop();
202
+ }
203
+
189
204
  _readBody(req) {
190
205
  return new Promise((resolve, reject) => {
191
206
  let body = '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devcode-canavar-pro",
3
- "version": "3.5.0",
3
+ "version": "3.5.2",
4
4
  "description": "Monster Edition: Ultra-fast, zero-config, embedded document database with Visual Dashboard and Interactive CLI.",
5
5
  "main": "index.js",
6
6
  "bin": {