@intranefr/superbackend 1.7.7 → 1.7.9
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/.beads/.br_history/issues.20260314_212352_900045509.jsonl +0 -0
- package/.beads/.br_history/issues.20260314_212352_900045509.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_087140743.jsonl +1 -0
- package/.beads/.br_history/issues.20260314_212353_087140743.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_285881504.jsonl +2 -0
- package/.beads/.br_history/issues.20260314_212353_285881504.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_473915419.jsonl +3 -0
- package/.beads/.br_history/issues.20260314_212353_473915419.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_659476307.jsonl +4 -0
- package/.beads/.br_history/issues.20260314_212353_659476307.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_869998925.jsonl +5 -0
- package/.beads/.br_history/issues.20260314_212353_869998925.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212354_054785029.jsonl +6 -0
- package/.beads/.br_history/issues.20260314_212354_054785029.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_175893691.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_175893691.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_338509797.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_338509797.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_515443192.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_515443192.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_676417592.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_676417592.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_839182422.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_839182422.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213337_004349113.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213337_004349113.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213337_179824080.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213337_179824080.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213701_705075332.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213701_705075332.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213706_783128702.jsonl +8 -0
- package/.beads/.br_history/issues.20260314_213706_783128702.jsonl.meta.json +1 -0
- package/.beads/config.yaml +4 -0
- package/.beads/issues.jsonl +8 -0
- package/.beads/metadata.json +4 -0
- package/.env.example +8 -0
- package/autochangelog/.env.example +36 -0
- package/autochangelog/README.md +412 -0
- package/autochangelog/config/database.js +27 -0
- package/autochangelog/package.json +47 -0
- package/autochangelog/public/landing.html +581 -0
- package/autochangelog/server.js +104 -0
- package/autochangelog/src/app.js +181 -0
- package/autochangelog/src/config/database.js +26 -0
- package/autochangelog/src/controllers/auth.js +488 -0
- package/autochangelog/src/controllers/changelog.js +682 -0
- package/autochangelog/src/controllers/project.js +580 -0
- package/autochangelog/src/controllers/repository.js +780 -0
- package/autochangelog/src/middleware/auth.js +386 -0
- package/autochangelog/src/models/Changelog.js +443 -0
- package/autochangelog/src/models/Project.js +226 -0
- package/autochangelog/src/models/Repository.js +366 -0
- package/autochangelog/src/models/User.js +223 -0
- package/autochangelog/src/routes/auth.routes.js +32 -0
- package/autochangelog/src/routes/changelog.routes.js +42 -0
- package/autochangelog/src/routes/github-auth.routes.js +102 -0
- package/autochangelog/src/routes/project.routes.js +50 -0
- package/autochangelog/src/routes/repository.routes.js +54 -0
- package/autochangelog/src/services/changelog.js +722 -0
- package/autochangelog/src/services/github.js +243 -0
- package/autochangelog/utils/logger.js +77 -0
- package/autochangelog/views/404.ejs +18 -0
- package/autochangelog/views/dashboard.ejs +596 -0
- package/autochangelog/views/index.ejs +231 -0
- package/autochangelog/views/layouts/main.ejs +44 -0
- package/autochangelog/views/login.ejs +104 -0
- package/autochangelog/views/partials/footer.ejs +20 -0
- package/autochangelog/views/partials/navbar.ejs +51 -0
- package/autochangelog/views/register.ejs +109 -0
- package/autochangelog-cli/README.md +266 -0
- package/autochangelog-cli/bin/autochangelog +120 -0
- package/autochangelog-cli/package.json +46 -0
- package/autochangelog-cli/src/cli/commands/auth.js +291 -0
- package/autochangelog-cli/src/cli/commands/changelog.js +619 -0
- package/autochangelog-cli/src/cli/commands/project.js +427 -0
- package/autochangelog-cli/src/cli/commands/repo.js +557 -0
- package/autochangelog-cli/src/cli/commands/stats.js +706 -0
- package/autochangelog-cli/src/cli/utils/config.js +277 -0
- package/autochangelog-cli/src/cli/utils/errors.js +307 -0
- package/autochangelog-cli/src/cli/utils/logger.js +75 -0
- package/autochangelog-cli/src/cli/utils/output.js +357 -0
- package/package.json +8 -3
- package/plugins/supercli/README.md +108 -0
- package/plugins/supercli/plugin.json +123 -0
- package/server.js +1 -1
- package/src/cli/api.js +380 -0
- package/src/cli/direct/agent-utils.js +61 -0
- package/src/cli/direct/cli-utils.js +112 -0
- package/src/cli/direct/data-seeding.js +307 -0
- package/src/cli/direct/db-admin.js +84 -0
- package/src/cli/direct/db-advanced.js +372 -0
- package/src/cli/direct/db-utils.js +558 -0
- package/src/cli/direct/help.js +195 -0
- package/src/cli/direct/migration.js +107 -0
- package/src/cli/direct/rbac-advanced.js +132 -0
- package/src/cli/direct/resources-additional.js +400 -0
- package/src/cli/direct/resources-cms-advanced.js +173 -0
- package/src/cli/direct/resources-cms.js +247 -0
- package/src/cli/direct/resources-core.js +253 -0
- package/src/cli/direct/resources-execution.js +367 -0
- package/src/cli/direct/resources-health.js +152 -0
- package/src/cli/direct/resources-integrations.js +182 -0
- package/src/cli/direct/resources-logs.js +204 -0
- package/src/cli/direct/resources-org-rbac.js +187 -0
- package/src/cli/direct/resources-system.js +236 -0
- package/src/cli/direct.js +556 -0
- package/src/controllers/admin.controller.js +4 -0
- package/src/controllers/auth.controller.js +148 -1
- package/src/controllers/waitingList.controller.js +130 -1
- package/src/models/RbacRole.js +1 -1
- package/src/models/User.js +39 -5
- package/src/routes/auth.routes.js +6 -0
- package/src/routes/waitingList.routes.js +12 -2
- package/src/routes/waitingListAdmin.routes.js +3 -0
- package/src/services/email.service.js +1 -0
- package/src/services/github.service.js +255 -0
- package/src/services/rateLimiter.service.js +29 -1
- package/src/services/waitingListJson.service.js +32 -3
- package/views/admin-waiting-list.ejs +386 -3
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Data seeding and import/export utilities
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const mongoose = require('mongoose');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const seedUsers = {
|
|
12
|
+
async execute(options) {
|
|
13
|
+
const User = mongoose.model('User');
|
|
14
|
+
const count = parseInt(options.value) || 10;
|
|
15
|
+
const role = options.description || 'user';
|
|
16
|
+
|
|
17
|
+
const users = [];
|
|
18
|
+
for (let i = 0; i < count; i++) {
|
|
19
|
+
users.push({
|
|
20
|
+
email: `testuser${i}@example.com`,
|
|
21
|
+
password: 'password123',
|
|
22
|
+
role,
|
|
23
|
+
name: `Test User ${i}`,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await User.insertMany(users);
|
|
28
|
+
return { seeded: count, role, message: `${count} users created with password "password123"` };
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const seedSettings = {
|
|
33
|
+
async execute(options) {
|
|
34
|
+
const GlobalSetting = mongoose.model('GlobalSetting');
|
|
35
|
+
|
|
36
|
+
const settings = [
|
|
37
|
+
{ key: 'SITE_NAME', value: 'My Site', description: 'Site name' },
|
|
38
|
+
{ key: 'SITE_DESCRIPTION', value: 'A sample site', description: 'Site description' },
|
|
39
|
+
{ key: 'CONTACT_EMAIL', value: 'contact@example.com', description: 'Contact email' },
|
|
40
|
+
{ key: 'MAX_UPLOAD_SIZE', value: 10485760, description: 'Max upload size in bytes' },
|
|
41
|
+
{ key: 'ALLOWED_DOMAINS', value: ['localhost', 'example.com'], description: 'Allowed domains' },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
let created = 0;
|
|
45
|
+
for (const setting of settings) {
|
|
46
|
+
const existing = await GlobalSetting.findOne({ key: setting.key });
|
|
47
|
+
if (!existing) {
|
|
48
|
+
await GlobalSetting.create(setting);
|
|
49
|
+
created++;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { seeded: created, total: settings.length, message: `${created} settings created` };
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const seedAgents = {
|
|
58
|
+
async execute(options) {
|
|
59
|
+
const Agent = mongoose.model('Agent');
|
|
60
|
+
|
|
61
|
+
const agents = [
|
|
62
|
+
{ name: 'General Assistant', model: 'gpt-4o-mini', systemPrompt: 'You are a helpful assistant.', tools: [] },
|
|
63
|
+
{ name: 'Code Helper', model: 'gpt-4o', systemPrompt: 'You are a coding assistant. Help users write and debug code.', tools: [] },
|
|
64
|
+
{ name: 'Content Writer', model: 'gpt-4o-mini', systemPrompt: 'You are a content writing assistant. Help create engaging content.', tools: [] },
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
let created = 0;
|
|
68
|
+
for (const agent of agents) {
|
|
69
|
+
const existing = await Agent.findOne({ name: agent.name });
|
|
70
|
+
if (!existing) {
|
|
71
|
+
await Agent.create(agent);
|
|
72
|
+
created++;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return { seeded: created, total: agents.length };
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const clearAllData = {
|
|
81
|
+
async execute(options, context) {
|
|
82
|
+
const db = context.db;
|
|
83
|
+
const confirm = options.yes;
|
|
84
|
+
|
|
85
|
+
if (!confirm) {
|
|
86
|
+
throw new Error('Use --yes to confirm clearing all data. This is IRREVERSIBLE!');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const collections = await db.listCollections().toArray();
|
|
90
|
+
let deletedCount = 0;
|
|
91
|
+
|
|
92
|
+
for (const coll of collections) {
|
|
93
|
+
const result = await db.collection(coll.name).deleteMany({});
|
|
94
|
+
deletedCount += result.deletedCount;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { deletedCount, collectionsCleared: collections.length };
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const importJson = {
|
|
102
|
+
async execute(options, context) {
|
|
103
|
+
const db = context.db;
|
|
104
|
+
const collectionName = options.key;
|
|
105
|
+
const inputFile = options.value;
|
|
106
|
+
|
|
107
|
+
if (!collectionName) throw new Error('--key (collection name) is required');
|
|
108
|
+
if (!inputFile) throw new Error('--value (input file path) is required');
|
|
109
|
+
|
|
110
|
+
const filePath = path.isAbsolute(inputFile) ? inputFile : path.resolve(process.cwd(), inputFile);
|
|
111
|
+
|
|
112
|
+
if (!fs.existsSync(filePath)) {
|
|
113
|
+
throw new Error(`File not found: ${filePath}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
117
|
+
const documents = JSON.parse(content);
|
|
118
|
+
|
|
119
|
+
if (!Array.isArray(documents)) {
|
|
120
|
+
throw new Error('JSON file must contain an array of documents');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const collection = db.collection(collectionName);
|
|
124
|
+
|
|
125
|
+
// Remove _id fields to avoid conflicts
|
|
126
|
+
const cleanDocs = documents.map(doc => {
|
|
127
|
+
const { _id, ...rest } = doc;
|
|
128
|
+
return rest;
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const result = await collection.insertMany(cleanDocs);
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
collection: collectionName,
|
|
135
|
+
importedCount: result.insertedCount,
|
|
136
|
+
sourceFile: inputFile,
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const exportJson = {
|
|
142
|
+
async execute(options, context) {
|
|
143
|
+
const db = context.db;
|
|
144
|
+
const collectionName = options.key;
|
|
145
|
+
const outputFile = options.value || `${collectionName}-export.json`;
|
|
146
|
+
const query = options.description ? JSON.parse(options.description) : {};
|
|
147
|
+
|
|
148
|
+
if (!collectionName) throw new Error('--key (collection name) is required');
|
|
149
|
+
|
|
150
|
+
const collection = db.collection(collectionName);
|
|
151
|
+
const documents = await collection.find(query).toArray();
|
|
152
|
+
|
|
153
|
+
fs.writeFileSync(outputFile, JSON.stringify(documents, null, 2));
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
collection: collectionName,
|
|
157
|
+
exportedCount: documents.length,
|
|
158
|
+
outputFile,
|
|
159
|
+
query,
|
|
160
|
+
};
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const exportAllCollections = {
|
|
165
|
+
async execute(options, context) {
|
|
166
|
+
const db = context.db;
|
|
167
|
+
const outputDir = options.value || './db-export';
|
|
168
|
+
|
|
169
|
+
if (!fs.existsSync(outputDir)) {
|
|
170
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const collections = await db.listCollections().toArray();
|
|
174
|
+
const exported = [];
|
|
175
|
+
|
|
176
|
+
for (const coll of collections) {
|
|
177
|
+
const documents = await db.collection(coll.name).find().toArray();
|
|
178
|
+
const outputFile = path.join(outputDir, `${coll.name}.json`);
|
|
179
|
+
fs.writeFileSync(outputFile, JSON.stringify(documents, null, 2));
|
|
180
|
+
exported.push({ name: coll.name, count: documents.length, file: outputFile });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
outputDir,
|
|
185
|
+
exportedCollections: exported,
|
|
186
|
+
totalCollections: collections.length,
|
|
187
|
+
};
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const countByField = {
|
|
192
|
+
async execute(options, context) {
|
|
193
|
+
const db = context.db;
|
|
194
|
+
const collectionName = options.key;
|
|
195
|
+
const fieldName = options.value;
|
|
196
|
+
|
|
197
|
+
if (!collectionName) throw new Error('--key (collection name) is required');
|
|
198
|
+
if (!fieldName) throw new Error('--value (field name) is required');
|
|
199
|
+
|
|
200
|
+
const collection = db.collection(collectionName);
|
|
201
|
+
const result = await collection.aggregate([
|
|
202
|
+
{ $group: { _id: `$${fieldName}`, count: { $sum: 1 } } },
|
|
203
|
+
{ $sort: { count: -1 } },
|
|
204
|
+
]).toArray();
|
|
205
|
+
|
|
206
|
+
return { collection: collectionName, fieldName, distribution: result };
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const findOrphanedDocuments = {
|
|
211
|
+
async execute(options, context) {
|
|
212
|
+
const db = context.db;
|
|
213
|
+
const collectionName = options.key;
|
|
214
|
+
const refField = options.value;
|
|
215
|
+
const refCollection = options.description;
|
|
216
|
+
|
|
217
|
+
if (!collectionName) throw new Error('--key (collection name) is required');
|
|
218
|
+
if (!refField) throw new Error('--value (reference field) is required');
|
|
219
|
+
if (!refCollection) throw new Error('--description (referenced collection) is required');
|
|
220
|
+
|
|
221
|
+
const collection = db.collection(collectionName);
|
|
222
|
+
const refCollectionObj = db.collection(refCollection);
|
|
223
|
+
|
|
224
|
+
const docs = await collection.find({ [refField]: { $exists: true, $ne: null } }).toArray();
|
|
225
|
+
const orphaned = [];
|
|
226
|
+
|
|
227
|
+
for (const doc of docs) {
|
|
228
|
+
const refId = doc[refField];
|
|
229
|
+
const exists = await refCollectionObj.findOne({ _id: refId });
|
|
230
|
+
if (!exists) {
|
|
231
|
+
orphaned.push({ _id: doc._id, [refField]: refId });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
collection: collectionName,
|
|
237
|
+
refField,
|
|
238
|
+
refCollection,
|
|
239
|
+
orphanedCount: orphaned.length,
|
|
240
|
+
orphaned: orphaned.slice(0, 50),
|
|
241
|
+
};
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
const deleteOrphanedDocuments = {
|
|
246
|
+
async execute(options, context) {
|
|
247
|
+
const db = context.db;
|
|
248
|
+
const collectionName = options.key;
|
|
249
|
+
const refField = options.value;
|
|
250
|
+
const refCollection = options.description;
|
|
251
|
+
|
|
252
|
+
if (!collectionName) throw new Error('--key (collection name) is required');
|
|
253
|
+
if (!refField) throw new Error('--value (reference field) is required');
|
|
254
|
+
if (!refCollection) throw new Error('--description (referenced collection) is required');
|
|
255
|
+
|
|
256
|
+
const collection = db.collection(collectionName);
|
|
257
|
+
const refCollectionObj = db.collection(refCollection);
|
|
258
|
+
|
|
259
|
+
const docs = await collection.find({ [refField]: { $exists: true, $ne: null } }).toArray();
|
|
260
|
+
let deletedCount = 0;
|
|
261
|
+
|
|
262
|
+
for (const doc of docs) {
|
|
263
|
+
const refId = doc[refField];
|
|
264
|
+
const exists = await refCollectionObj.findOne({ _id: refId });
|
|
265
|
+
if (!exists) {
|
|
266
|
+
await collection.deleteOne({ _id: doc._id });
|
|
267
|
+
deletedCount++;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return { collection: collectionName, refField, deletedCount };
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
const generateTestData = {
|
|
276
|
+
async execute(options, context) {
|
|
277
|
+
const db = context.db;
|
|
278
|
+
const collectionName = options.key;
|
|
279
|
+
const count = parseInt(options.value) || 100;
|
|
280
|
+
|
|
281
|
+
if (!collectionName) throw new Error('--key (collection name) is required');
|
|
282
|
+
|
|
283
|
+
const collection = db.collection(collectionName);
|
|
284
|
+
const documents = [];
|
|
285
|
+
|
|
286
|
+
for (let i = 0; i < count; i++) {
|
|
287
|
+
documents.push({
|
|
288
|
+
name: `Test Item ${i}`,
|
|
289
|
+
value: Math.random() * 1000,
|
|
290
|
+
status: ['active', 'inactive', 'pending'][Math.floor(Math.random() * 3)],
|
|
291
|
+
createdAt: new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000),
|
|
292
|
+
updatedAt: new Date(),
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const result = await collection.insertMany(documents);
|
|
297
|
+
|
|
298
|
+
return { collection: collectionName, insertedCount: result.insertedCount, count };
|
|
299
|
+
},
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
module.exports = {
|
|
303
|
+
seedUsers, seedSettings, seedAgents, clearAllData,
|
|
304
|
+
importJson, exportJson, exportAllCollections,
|
|
305
|
+
countByField, findOrphanedDocuments, deleteOrphanedDocuments,
|
|
306
|
+
generateTestData,
|
|
307
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Database administration: db-info, db-users, slow-queries, profiling
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const mongoose = require("mongoose");
|
|
8
|
+
|
|
9
|
+
const dbInfo = {
|
|
10
|
+
async execute(options, context) {
|
|
11
|
+
if (options.command && options.command !== "execute") return;
|
|
12
|
+
const db = context.db;
|
|
13
|
+
const info = await db.admin().serverInfo();
|
|
14
|
+
const stats = await db.admin().serverStatus();
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
version: info.version,
|
|
18
|
+
gitVersion: info.gitVersion,
|
|
19
|
+
uptime: stats.uptime,
|
|
20
|
+
uptimeMillis: stats.uptimeMillis,
|
|
21
|
+
localTime: stats.localTime,
|
|
22
|
+
connections: {
|
|
23
|
+
current: stats.connections.current,
|
|
24
|
+
available: stats.connections.available,
|
|
25
|
+
},
|
|
26
|
+
memory: stats.mem,
|
|
27
|
+
assertions: stats.assertions,
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const dbUsers = {
|
|
33
|
+
async execute(options, context) {
|
|
34
|
+
if (options.command && options.command !== "execute") return;
|
|
35
|
+
const db = context.db;
|
|
36
|
+
const users = await db.admin().command({ usersInfo: 1 });
|
|
37
|
+
return { users: users.users || [] };
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const slowQueries = {
|
|
42
|
+
async execute(options, context) {
|
|
43
|
+
if (options.command && options.command !== "execute") return;
|
|
44
|
+
const db = context.db;
|
|
45
|
+
const profileMs = parseInt(options.value) || 100;
|
|
46
|
+
|
|
47
|
+
const result = await db
|
|
48
|
+
.collection("system.profile")
|
|
49
|
+
.find({ millis: { $gt: profileMs } })
|
|
50
|
+
.sort({ ts: -1 })
|
|
51
|
+
.limit(50)
|
|
52
|
+
.toArray();
|
|
53
|
+
return {
|
|
54
|
+
profileMs,
|
|
55
|
+
slowQueries: result.length,
|
|
56
|
+
samples: result.slice(0, 10),
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const enableProfiling = {
|
|
62
|
+
async execute(options, context) {
|
|
63
|
+
const db = context.db;
|
|
64
|
+
const level = parseInt(options.value) || 1;
|
|
65
|
+
await db.setProfilingLevel(level);
|
|
66
|
+
return { level, message: `Profiling enabled at level ${level}` };
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const disableProfiling = {
|
|
71
|
+
async execute(options, context) {
|
|
72
|
+
const db = context.db;
|
|
73
|
+
await db.setProfilingLevel(0);
|
|
74
|
+
return { level: 0, message: "Profiling disabled" };
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
module.exports = {
|
|
79
|
+
dbInfo,
|
|
80
|
+
dbUsers,
|
|
81
|
+
slowQueries,
|
|
82
|
+
enableProfiling,
|
|
83
|
+
disableProfiling,
|
|
84
|
+
};
|