@samanhappy/mcphub 0.9.5 → 0.9.7
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/dist/config/DaoConfigService.js +210 -0
- package/dist/config/DaoConfigService.js.map +1 -0
- package/dist/config/configManager.js +123 -0
- package/dist/config/configManager.js.map +1 -0
- package/dist/config/migrationUtils.js +206 -0
- package/dist/config/migrationUtils.js.map +1 -0
- package/dist/controllers/logController.js +1 -1
- package/dist/controllers/logController.js.map +1 -1
- package/dist/controllers/marketController.js +1 -1
- package/dist/controllers/marketController.js.map +1 -1
- package/dist/controllers/openApiController.js +158 -7
- package/dist/controllers/openApiController.js.map +1 -1
- package/dist/controllers/promptController.js +1 -1
- package/dist/controllers/serverController.js +8 -9
- package/dist/controllers/serverController.js.map +1 -1
- package/dist/dao/DaoFactory.js +102 -0
- package/dist/dao/DaoFactory.js.map +1 -0
- package/dist/dao/GroupDao.js +156 -0
- package/dist/dao/GroupDao.js.map +1 -0
- package/dist/dao/ServerDao.js +117 -0
- package/dist/dao/ServerDao.js.map +1 -0
- package/dist/dao/SystemConfigDao.js +55 -0
- package/dist/dao/SystemConfigDao.js.map +1 -0
- package/dist/dao/UserConfigDao.js +72 -0
- package/dist/dao/UserConfigDao.js.map +1 -0
- package/dist/dao/UserDao.js +107 -0
- package/dist/dao/UserDao.js.map +1 -0
- package/dist/dao/base/BaseDao.js +49 -0
- package/dist/dao/base/BaseDao.js.map +1 -0
- package/dist/dao/base/JsonFileBaseDao.js +84 -0
- package/dist/dao/base/JsonFileBaseDao.js.map +1 -0
- package/dist/dao/examples.js +172 -0
- package/dist/dao/examples.js.map +1 -0
- package/dist/dao/index.js +11 -0
- package/dist/dao/index.js.map +1 -0
- package/dist/routes/index.js +4 -1
- package/dist/routes/index.js.map +1 -1
- package/dist/scripts/dao-demo.js +226 -0
- package/dist/scripts/dao-demo.js.map +1 -0
- package/dist/services/mcpService.js +49 -71
- package/dist/services/mcpService.js.map +1 -1
- package/dist/services/openApiGeneratorService.js +44 -8
- package/dist/services/openApiGeneratorService.js.map +1 -1
- package/dist/services/sseService.js.map +1 -1
- package/dist/services/vectorSearchService.js +1 -1
- package/dist/services/vectorSearchService.js.map +1 -1
- package/frontend/dist/assets/index-ISu9ai3k.js +212 -0
- package/frontend/dist/assets/index-ISu9ai3k.js.map +1 -0
- package/frontend/dist/index.html +1 -1
- package/package.json +3 -1
- package/frontend/dist/assets/index-dsw9o-29.js +0 -212
- package/frontend/dist/assets/index-dsw9o-29.js.map +0 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { JsonFileBaseDao } from './base/JsonFileBaseDao.js';
|
|
2
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
3
|
+
/**
|
|
4
|
+
* JSON file-based Group DAO implementation
|
|
5
|
+
*/
|
|
6
|
+
export class GroupDaoImpl extends JsonFileBaseDao {
|
|
7
|
+
async getAll() {
|
|
8
|
+
const settings = await this.loadSettings();
|
|
9
|
+
return settings.groups || [];
|
|
10
|
+
}
|
|
11
|
+
async saveAll(groups) {
|
|
12
|
+
const settings = await this.loadSettings();
|
|
13
|
+
settings.groups = groups;
|
|
14
|
+
await this.saveSettings(settings);
|
|
15
|
+
}
|
|
16
|
+
getEntityId(group) {
|
|
17
|
+
return group.id;
|
|
18
|
+
}
|
|
19
|
+
createEntity(data) {
|
|
20
|
+
return {
|
|
21
|
+
id: uuidv4(),
|
|
22
|
+
owner: 'admin', // Default owner
|
|
23
|
+
...data,
|
|
24
|
+
servers: data.servers || [],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
updateEntity(existing, updates) {
|
|
28
|
+
return {
|
|
29
|
+
...existing,
|
|
30
|
+
...updates,
|
|
31
|
+
id: existing.id, // ID should not be updated
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
async findAll() {
|
|
35
|
+
return this.getAll();
|
|
36
|
+
}
|
|
37
|
+
async findById(id) {
|
|
38
|
+
const groups = await this.getAll();
|
|
39
|
+
return groups.find((group) => group.id === id) || null;
|
|
40
|
+
}
|
|
41
|
+
async create(data) {
|
|
42
|
+
const groups = await this.getAll();
|
|
43
|
+
// Check if group name already exists
|
|
44
|
+
if (groups.find((group) => group.name === data.name)) {
|
|
45
|
+
throw new Error(`Group with name ${data.name} already exists`);
|
|
46
|
+
}
|
|
47
|
+
const newGroup = this.createEntity(data);
|
|
48
|
+
groups.push(newGroup);
|
|
49
|
+
await this.saveAll(groups);
|
|
50
|
+
return newGroup;
|
|
51
|
+
}
|
|
52
|
+
async update(id, updates) {
|
|
53
|
+
const groups = await this.getAll();
|
|
54
|
+
const index = groups.findIndex((group) => group.id === id);
|
|
55
|
+
if (index === -1) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
// Check if name update would cause conflict
|
|
59
|
+
if (updates.name && updates.name !== groups[index].name) {
|
|
60
|
+
const existingGroup = groups.find((group) => group.name === updates.name && group.id !== id);
|
|
61
|
+
if (existingGroup) {
|
|
62
|
+
throw new Error(`Group with name ${updates.name} already exists`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Don't allow ID changes
|
|
66
|
+
const { id: _, ...allowedUpdates } = updates;
|
|
67
|
+
const updatedGroup = this.updateEntity(groups[index], allowedUpdates);
|
|
68
|
+
groups[index] = updatedGroup;
|
|
69
|
+
await this.saveAll(groups);
|
|
70
|
+
return updatedGroup;
|
|
71
|
+
}
|
|
72
|
+
async delete(id) {
|
|
73
|
+
const groups = await this.getAll();
|
|
74
|
+
const index = groups.findIndex((group) => group.id === id);
|
|
75
|
+
if (index === -1) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
groups.splice(index, 1);
|
|
79
|
+
await this.saveAll(groups);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
async exists(id) {
|
|
83
|
+
const group = await this.findById(id);
|
|
84
|
+
return group !== null;
|
|
85
|
+
}
|
|
86
|
+
async count() {
|
|
87
|
+
const groups = await this.getAll();
|
|
88
|
+
return groups.length;
|
|
89
|
+
}
|
|
90
|
+
async findByOwner(owner) {
|
|
91
|
+
const groups = await this.getAll();
|
|
92
|
+
return groups.filter((group) => group.owner === owner);
|
|
93
|
+
}
|
|
94
|
+
async findByServer(serverName) {
|
|
95
|
+
const groups = await this.getAll();
|
|
96
|
+
return groups.filter((group) => {
|
|
97
|
+
if (Array.isArray(group.servers)) {
|
|
98
|
+
return group.servers.some((server) => {
|
|
99
|
+
if (typeof server === 'string') {
|
|
100
|
+
return server === serverName;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
return server.name === serverName;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
async addServerToGroup(groupId, serverName) {
|
|
111
|
+
const group = await this.findById(groupId);
|
|
112
|
+
if (!group) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
// Check if server already exists in group
|
|
116
|
+
const serverExists = group.servers.some((server) => {
|
|
117
|
+
if (typeof server === 'string') {
|
|
118
|
+
return server === serverName;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
return server.name === serverName;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
if (serverExists) {
|
|
125
|
+
return true; // Already exists, consider it success
|
|
126
|
+
}
|
|
127
|
+
const updatedServers = [...group.servers, serverName];
|
|
128
|
+
const result = await this.update(groupId, { servers: updatedServers });
|
|
129
|
+
return result !== null;
|
|
130
|
+
}
|
|
131
|
+
async removeServerFromGroup(groupId, serverName) {
|
|
132
|
+
const group = await this.findById(groupId);
|
|
133
|
+
if (!group) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
const updatedServers = group.servers.filter((server) => {
|
|
137
|
+
if (typeof server === 'string') {
|
|
138
|
+
return server !== serverName;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
return server.name !== serverName;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
const result = await this.update(groupId, { servers: updatedServers });
|
|
145
|
+
return result !== null;
|
|
146
|
+
}
|
|
147
|
+
async updateServers(groupId, servers) {
|
|
148
|
+
const result = await this.update(groupId, { servers });
|
|
149
|
+
return result !== null;
|
|
150
|
+
}
|
|
151
|
+
async findByName(name) {
|
|
152
|
+
const groups = await this.getAll();
|
|
153
|
+
return groups.find((group) => group.name === name) || null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=GroupDao.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GroupDao.js","sourceRoot":"","sources":["../../src/dao/GroupDao.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { JsonFileBaseDao } from './base/JsonFileBaseDao.js';
|
|
2
|
+
/**
|
|
3
|
+
* JSON file-based Server DAO implementation
|
|
4
|
+
*/
|
|
5
|
+
export class ServerDaoImpl extends JsonFileBaseDao {
|
|
6
|
+
async getAll() {
|
|
7
|
+
const settings = await this.loadSettings();
|
|
8
|
+
const servers = [];
|
|
9
|
+
for (const [name, config] of Object.entries(settings.mcpServers || {})) {
|
|
10
|
+
servers.push({
|
|
11
|
+
name,
|
|
12
|
+
...config,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
return servers;
|
|
16
|
+
}
|
|
17
|
+
async saveAll(servers) {
|
|
18
|
+
const settings = await this.loadSettings();
|
|
19
|
+
settings.mcpServers = {};
|
|
20
|
+
for (const server of servers) {
|
|
21
|
+
const { name, ...config } = server;
|
|
22
|
+
settings.mcpServers[name] = config;
|
|
23
|
+
}
|
|
24
|
+
await this.saveSettings(settings);
|
|
25
|
+
}
|
|
26
|
+
getEntityId(server) {
|
|
27
|
+
return server.name;
|
|
28
|
+
}
|
|
29
|
+
createEntity(_data) {
|
|
30
|
+
throw new Error('Server name must be provided');
|
|
31
|
+
}
|
|
32
|
+
updateEntity(existing, updates) {
|
|
33
|
+
return {
|
|
34
|
+
...existing,
|
|
35
|
+
...updates,
|
|
36
|
+
name: existing.name, // Name should not be updated
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async findAll() {
|
|
40
|
+
return this.getAll();
|
|
41
|
+
}
|
|
42
|
+
async findById(name) {
|
|
43
|
+
const servers = await this.getAll();
|
|
44
|
+
return servers.find((server) => server.name === name) || null;
|
|
45
|
+
}
|
|
46
|
+
async create(data) {
|
|
47
|
+
const servers = await this.getAll();
|
|
48
|
+
// Check if server already exists
|
|
49
|
+
if (servers.find((server) => server.name === data.name)) {
|
|
50
|
+
throw new Error(`Server ${data.name} already exists`);
|
|
51
|
+
}
|
|
52
|
+
const newServer = {
|
|
53
|
+
enabled: true, // Default to enabled
|
|
54
|
+
owner: 'admin', // Default owner
|
|
55
|
+
...data,
|
|
56
|
+
};
|
|
57
|
+
servers.push(newServer);
|
|
58
|
+
await this.saveAll(servers);
|
|
59
|
+
return newServer;
|
|
60
|
+
}
|
|
61
|
+
async update(name, updates) {
|
|
62
|
+
const servers = await this.getAll();
|
|
63
|
+
const index = servers.findIndex((server) => server.name === name);
|
|
64
|
+
if (index === -1) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
// Don't allow name changes
|
|
68
|
+
const { name: _, ...allowedUpdates } = updates;
|
|
69
|
+
const updatedServer = this.updateEntity(servers[index], allowedUpdates);
|
|
70
|
+
servers[index] = updatedServer;
|
|
71
|
+
await this.saveAll(servers);
|
|
72
|
+
return updatedServer;
|
|
73
|
+
}
|
|
74
|
+
async delete(name) {
|
|
75
|
+
const servers = await this.getAll();
|
|
76
|
+
const index = servers.findIndex((server) => server.name === name);
|
|
77
|
+
if (index === -1) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
servers.splice(index, 1);
|
|
81
|
+
await this.saveAll(servers);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
async exists(name) {
|
|
85
|
+
const server = await this.findById(name);
|
|
86
|
+
return server !== null;
|
|
87
|
+
}
|
|
88
|
+
async count() {
|
|
89
|
+
const servers = await this.getAll();
|
|
90
|
+
return servers.length;
|
|
91
|
+
}
|
|
92
|
+
async findByOwner(owner) {
|
|
93
|
+
const servers = await this.getAll();
|
|
94
|
+
return servers.filter((server) => server.owner === owner);
|
|
95
|
+
}
|
|
96
|
+
async findEnabled() {
|
|
97
|
+
const servers = await this.getAll();
|
|
98
|
+
return servers.filter((server) => server.enabled !== false);
|
|
99
|
+
}
|
|
100
|
+
async findByType(type) {
|
|
101
|
+
const servers = await this.getAll();
|
|
102
|
+
return servers.filter((server) => server.type === type);
|
|
103
|
+
}
|
|
104
|
+
async setEnabled(name, enabled) {
|
|
105
|
+
const result = await this.update(name, { enabled });
|
|
106
|
+
return result !== null;
|
|
107
|
+
}
|
|
108
|
+
async updateTools(name, tools) {
|
|
109
|
+
const result = await this.update(name, { tools });
|
|
110
|
+
return result !== null;
|
|
111
|
+
}
|
|
112
|
+
async updatePrompts(name, prompts) {
|
|
113
|
+
const result = await this.update(name, { prompts });
|
|
114
|
+
return result !== null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=ServerDao.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ServerDao.js","sourceRoot":"","sources":["../../src/dao/ServerDao.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { JsonFileBaseDao } from './base/JsonFileBaseDao.js';
|
|
2
|
+
/**
|
|
3
|
+
* JSON file-based System Configuration DAO implementation
|
|
4
|
+
*/
|
|
5
|
+
export class SystemConfigDaoImpl extends JsonFileBaseDao {
|
|
6
|
+
async get() {
|
|
7
|
+
const settings = await this.loadSettings();
|
|
8
|
+
return settings.systemConfig || {};
|
|
9
|
+
}
|
|
10
|
+
async update(config) {
|
|
11
|
+
const settings = await this.loadSettings();
|
|
12
|
+
const currentConfig = settings.systemConfig || {};
|
|
13
|
+
// Deep merge configuration
|
|
14
|
+
const updatedConfig = this.deepMerge(currentConfig, config);
|
|
15
|
+
settings.systemConfig = updatedConfig;
|
|
16
|
+
await this.saveSettings(settings);
|
|
17
|
+
return updatedConfig;
|
|
18
|
+
}
|
|
19
|
+
async reset() {
|
|
20
|
+
const settings = await this.loadSettings();
|
|
21
|
+
const defaultConfig = {};
|
|
22
|
+
settings.systemConfig = defaultConfig;
|
|
23
|
+
await this.saveSettings(settings);
|
|
24
|
+
return defaultConfig;
|
|
25
|
+
}
|
|
26
|
+
async getSection(section) {
|
|
27
|
+
const config = await this.get();
|
|
28
|
+
return config[section];
|
|
29
|
+
}
|
|
30
|
+
async updateSection(section, value) {
|
|
31
|
+
try {
|
|
32
|
+
await this.update({ [section]: value });
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Deep merge two objects
|
|
41
|
+
*/
|
|
42
|
+
deepMerge(target, source) {
|
|
43
|
+
const result = { ...target };
|
|
44
|
+
for (const key in source) {
|
|
45
|
+
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
|
46
|
+
result[key] = this.deepMerge(target[key] || {}, source[key]);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
result[key] = source[key];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=SystemConfigDao.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SystemConfigDao.js","sourceRoot":"","sources":["../../src/dao/SystemConfigDao.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAgC5D;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,eAAe;IACtD,KAAK,CAAC,GAAG;QACP,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC3C,OAAO,QAAQ,CAAC,YAAY,IAAI,EAAE,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAA6B;QACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC3C,MAAM,aAAa,GAAG,QAAQ,CAAC,YAAY,IAAI,EAAE,CAAC;QAElD,2BAA2B;QAC3B,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QAC5D,QAAQ,CAAC,YAAY,GAAG,aAAa,CAAC;QAEtC,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAClC,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC3C,MAAM,aAAa,GAAiB,EAAE,CAAC;QAEvC,QAAQ,CAAC,YAAY,GAAG,aAAa,CAAC;QACtC,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAElC,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,UAAU,CAA+B,OAAU;QACvD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,OAAU,EACV,KAAsB;QAEtB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAA2B,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACK,SAAS,CAAC,MAAW,EAAE,MAAW;QACxC,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;QAE7B,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBAClF,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/D,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { JsonFileBaseDao } from './base/JsonFileBaseDao.js';
|
|
2
|
+
/**
|
|
3
|
+
* JSON file-based User Configuration DAO implementation
|
|
4
|
+
*/
|
|
5
|
+
export class UserConfigDaoImpl extends JsonFileBaseDao {
|
|
6
|
+
async get(username) {
|
|
7
|
+
const settings = await this.loadSettings();
|
|
8
|
+
return settings.userConfigs?.[username];
|
|
9
|
+
}
|
|
10
|
+
async getAll() {
|
|
11
|
+
const settings = await this.loadSettings();
|
|
12
|
+
return settings.userConfigs || {};
|
|
13
|
+
}
|
|
14
|
+
async update(username, config) {
|
|
15
|
+
const settings = await this.loadSettings();
|
|
16
|
+
if (!settings.userConfigs) {
|
|
17
|
+
settings.userConfigs = {};
|
|
18
|
+
}
|
|
19
|
+
const currentConfig = settings.userConfigs[username] || {};
|
|
20
|
+
// Deep merge configuration
|
|
21
|
+
const updatedConfig = this.deepMerge(currentConfig, config);
|
|
22
|
+
settings.userConfigs[username] = updatedConfig;
|
|
23
|
+
await this.saveSettings(settings);
|
|
24
|
+
return updatedConfig;
|
|
25
|
+
}
|
|
26
|
+
async delete(username) {
|
|
27
|
+
const settings = await this.loadSettings();
|
|
28
|
+
if (!settings.userConfigs || !settings.userConfigs[username]) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
delete settings.userConfigs[username];
|
|
32
|
+
await this.saveSettings(settings);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
async exists(username) {
|
|
36
|
+
const config = await this.get(username);
|
|
37
|
+
return config !== undefined;
|
|
38
|
+
}
|
|
39
|
+
async reset(username) {
|
|
40
|
+
const defaultConfig = {};
|
|
41
|
+
return this.update(username, defaultConfig);
|
|
42
|
+
}
|
|
43
|
+
async getSection(username, section) {
|
|
44
|
+
const config = await this.get(username);
|
|
45
|
+
return config?.[section];
|
|
46
|
+
}
|
|
47
|
+
async updateSection(username, section, value) {
|
|
48
|
+
try {
|
|
49
|
+
await this.update(username, { [section]: value });
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Deep merge two objects
|
|
58
|
+
*/
|
|
59
|
+
deepMerge(target, source) {
|
|
60
|
+
const result = { ...target };
|
|
61
|
+
for (const key in source) {
|
|
62
|
+
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
|
63
|
+
result[key] = this.deepMerge(target[key] || {}, source[key]);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
result[key] = source[key];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=UserConfigDao.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserConfigDao.js","sourceRoot":"","sources":["../../src/dao/UserConfigDao.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { JsonFileBaseDao } from './base/JsonFileBaseDao.js';
|
|
2
|
+
import bcrypt from 'bcryptjs';
|
|
3
|
+
/**
|
|
4
|
+
* JSON file-based User DAO implementation
|
|
5
|
+
*/
|
|
6
|
+
export class UserDaoImpl extends JsonFileBaseDao {
|
|
7
|
+
async getAll() {
|
|
8
|
+
const settings = await this.loadSettings();
|
|
9
|
+
return settings.users || [];
|
|
10
|
+
}
|
|
11
|
+
async saveAll(users) {
|
|
12
|
+
const settings = await this.loadSettings();
|
|
13
|
+
settings.users = users;
|
|
14
|
+
await this.saveSettings(settings);
|
|
15
|
+
}
|
|
16
|
+
getEntityId(user) {
|
|
17
|
+
return user.username;
|
|
18
|
+
}
|
|
19
|
+
createEntity(_data) {
|
|
20
|
+
// This method should not be called directly for users
|
|
21
|
+
throw new Error('Use createWithHashedPassword instead');
|
|
22
|
+
}
|
|
23
|
+
updateEntity(existing, updates) {
|
|
24
|
+
return {
|
|
25
|
+
...existing,
|
|
26
|
+
...updates,
|
|
27
|
+
username: existing.username, // Username should not be updated
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async findAll() {
|
|
31
|
+
return this.getAll();
|
|
32
|
+
}
|
|
33
|
+
async findById(username) {
|
|
34
|
+
return this.findByUsername(username);
|
|
35
|
+
}
|
|
36
|
+
async findByUsername(username) {
|
|
37
|
+
const users = await this.getAll();
|
|
38
|
+
return users.find((user) => user.username === username) || null;
|
|
39
|
+
}
|
|
40
|
+
async create(_data) {
|
|
41
|
+
throw new Error('Use createWithHashedPassword instead');
|
|
42
|
+
}
|
|
43
|
+
async createWithHashedPassword(username, password, isAdmin = false) {
|
|
44
|
+
const users = await this.getAll();
|
|
45
|
+
// Check if user already exists
|
|
46
|
+
if (users.find((user) => user.username === username)) {
|
|
47
|
+
throw new Error(`User ${username} already exists`);
|
|
48
|
+
}
|
|
49
|
+
const hashedPassword = await bcrypt.hash(password, 10);
|
|
50
|
+
const newUser = {
|
|
51
|
+
username,
|
|
52
|
+
password: hashedPassword,
|
|
53
|
+
isAdmin,
|
|
54
|
+
};
|
|
55
|
+
users.push(newUser);
|
|
56
|
+
await this.saveAll(users);
|
|
57
|
+
return newUser;
|
|
58
|
+
}
|
|
59
|
+
async update(username, updates) {
|
|
60
|
+
const users = await this.getAll();
|
|
61
|
+
const index = users.findIndex((user) => user.username === username);
|
|
62
|
+
if (index === -1) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
// Don't allow username changes
|
|
66
|
+
const { username: _, ...allowedUpdates } = updates;
|
|
67
|
+
const updatedUser = this.updateEntity(users[index], allowedUpdates);
|
|
68
|
+
users[index] = updatedUser;
|
|
69
|
+
await this.saveAll(users);
|
|
70
|
+
return updatedUser;
|
|
71
|
+
}
|
|
72
|
+
async updatePassword(username, newPassword) {
|
|
73
|
+
const hashedPassword = await bcrypt.hash(newPassword, 10);
|
|
74
|
+
const result = await this.update(username, { password: hashedPassword });
|
|
75
|
+
return result !== null;
|
|
76
|
+
}
|
|
77
|
+
async delete(username) {
|
|
78
|
+
const users = await this.getAll();
|
|
79
|
+
const index = users.findIndex((user) => user.username === username);
|
|
80
|
+
if (index === -1) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
users.splice(index, 1);
|
|
84
|
+
await this.saveAll(users);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
async exists(username) {
|
|
88
|
+
const user = await this.findByUsername(username);
|
|
89
|
+
return user !== null;
|
|
90
|
+
}
|
|
91
|
+
async count() {
|
|
92
|
+
const users = await this.getAll();
|
|
93
|
+
return users.length;
|
|
94
|
+
}
|
|
95
|
+
async validateCredentials(username, password) {
|
|
96
|
+
const user = await this.findByUsername(username);
|
|
97
|
+
if (!user) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return bcrypt.compare(password, user.password);
|
|
101
|
+
}
|
|
102
|
+
async findAdmins() {
|
|
103
|
+
const users = await this.getAll();
|
|
104
|
+
return users.filter((user) => user.isAdmin === true);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=UserDao.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserDao.js","sourceRoot":"","sources":["../../src/dao/UserDao.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base DAO implementation with common functionality
|
|
3
|
+
*/
|
|
4
|
+
export class BaseDaoImpl {
|
|
5
|
+
async findAll() {
|
|
6
|
+
return this.getAll();
|
|
7
|
+
}
|
|
8
|
+
async findById(id) {
|
|
9
|
+
const entities = await this.getAll();
|
|
10
|
+
return entities.find((entity) => this.getEntityId(entity) === id) || null;
|
|
11
|
+
}
|
|
12
|
+
async create(data) {
|
|
13
|
+
const entities = await this.getAll();
|
|
14
|
+
const newEntity = this.createEntity(data);
|
|
15
|
+
entities.push(newEntity);
|
|
16
|
+
await this.saveAll(entities);
|
|
17
|
+
return newEntity;
|
|
18
|
+
}
|
|
19
|
+
async update(id, updates) {
|
|
20
|
+
const entities = await this.getAll();
|
|
21
|
+
const index = entities.findIndex((entity) => this.getEntityId(entity) === id);
|
|
22
|
+
if (index === -1) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const updatedEntity = this.updateEntity(entities[index], updates);
|
|
26
|
+
entities[index] = updatedEntity;
|
|
27
|
+
await this.saveAll(entities);
|
|
28
|
+
return updatedEntity;
|
|
29
|
+
}
|
|
30
|
+
async delete(id) {
|
|
31
|
+
const entities = await this.getAll();
|
|
32
|
+
const index = entities.findIndex((entity) => this.getEntityId(entity) === id);
|
|
33
|
+
if (index === -1) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
entities.splice(index, 1);
|
|
37
|
+
await this.saveAll(entities);
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
async exists(id) {
|
|
41
|
+
const entity = await this.findById(id);
|
|
42
|
+
return entity !== null;
|
|
43
|
+
}
|
|
44
|
+
async count() {
|
|
45
|
+
const entities = await this.getAll();
|
|
46
|
+
return entities.length;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=BaseDao.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseDao.js","sourceRoot":"","sources":["../../../src/dao/base/BaseDao.ts"],"names":[],"mappings":"AAwCA;;GAEG;AACH,MAAM,OAAgB,WAAW;IAO/B,KAAK,CAAC,OAAO;QACX,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,EAAK;QAClB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAmB;QAC9B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAE1C,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzB,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAE7B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAK,EAAE,OAAmB;QACrC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAE9E,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QAClE,QAAQ,CAAC,KAAK,CAAC,GAAG,aAAa,CAAC;QAEhC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAK;QAChB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAE9E,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC1B,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAK;QAChB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACvC,OAAO,MAAM,KAAK,IAAI,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACrC,OAAO,QAAQ,CAAC,MAAM,CAAC;IACzB,CAAC;CACF"}
|