@memo-code/memo 0.8.5 → 0.8.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.
Files changed (97) hide show
  1. package/dist/web/server/main.cjs +145359 -0
  2. package/package.json +2 -1
  3. package/dist/web/server/app.controller.d.ts +0 -6
  4. package/dist/web/server/app.controller.js +0 -33
  5. package/dist/web/server/app.module.d.ts +0 -4
  6. package/dist/web/server/app.module.js +0 -61
  7. package/dist/web/server/auth/access-token.guard.d.ts +0 -9
  8. package/dist/web/server/auth/access-token.guard.js +0 -53
  9. package/dist/web/server/auth/auth.controller.d.ts +0 -18
  10. package/dist/web/server/auth/auth.controller.js +0 -75
  11. package/dist/web/server/auth/auth.module.d.ts +0 -2
  12. package/dist/web/server/auth/auth.module.js +0 -24
  13. package/dist/web/server/auth/auth.service.d.ts +0 -15
  14. package/dist/web/server/auth/auth.service.js +0 -146
  15. package/dist/web/server/auth/auth.types.d.ts +0 -26
  16. package/dist/web/server/auth/auth.types.js +0 -2
  17. package/dist/web/server/auth/public.decorator.d.ts +0 -2
  18. package/dist/web/server/auth/public.decorator.js +0 -7
  19. package/dist/web/server/chat/chat.controller.d.ts +0 -30
  20. package/dist/web/server/chat/chat.controller.js +0 -150
  21. package/dist/web/server/chat/chat.module.d.ts +0 -2
  22. package/dist/web/server/chat/chat.module.js +0 -26
  23. package/dist/web/server/chat/chat.service.d.ts +0 -61
  24. package/dist/web/server/chat/chat.service.js +0 -847
  25. package/dist/web/server/chat/chat.types.d.ts +0 -38
  26. package/dist/web/server/chat/chat.types.js +0 -2
  27. package/dist/web/server/common/constants.d.ts +0 -1
  28. package/dist/web/server/common/constants.js +0 -4
  29. package/dist/web/server/common/filters/api-error.filter.d.ts +0 -7
  30. package/dist/web/server/common/filters/api-error.filter.js +0 -95
  31. package/dist/web/server/common/interceptors/api-response.interceptor.d.ts +0 -15
  32. package/dist/web/server/common/interceptors/api-response.interceptor.js +0 -51
  33. package/dist/web/server/common/middleware/request-logging.middleware.d.ts +0 -7
  34. package/dist/web/server/common/middleware/request-logging.middleware.js +0 -42
  35. package/dist/web/server/config/memo-config.service.d.ts +0 -7
  36. package/dist/web/server/config/memo-config.service.js +0 -106
  37. package/dist/web/server/config/memo-config.types.d.ts +0 -6
  38. package/dist/web/server/config/memo-config.types.js +0 -2
  39. package/dist/web/server/config/server-config.module.d.ts +0 -2
  40. package/dist/web/server/config/server-config.module.js +0 -22
  41. package/dist/web/server/config/server-config.service.d.ts +0 -14
  42. package/dist/web/server/config/server-config.service.js +0 -326
  43. package/dist/web/server/config/server-config.service.test.d.ts +0 -1
  44. package/dist/web/server/config/server-config.service.test.js +0 -193
  45. package/dist/web/server/config/server-config.types.d.ts +0 -27
  46. package/dist/web/server/config/server-config.types.js +0 -2
  47. package/dist/web/server/main.d.ts +0 -1
  48. package/dist/web/server/main.js +0 -19
  49. package/dist/web/server/mcp/mcp.controller.d.ts +0 -38
  50. package/dist/web/server/mcp/mcp.controller.js +0 -126
  51. package/dist/web/server/mcp/mcp.module.d.ts +0 -2
  52. package/dist/web/server/mcp/mcp.module.js +0 -22
  53. package/dist/web/server/mcp/mcp.service.d.ts +0 -25
  54. package/dist/web/server/mcp/mcp.service.js +0 -56
  55. package/dist/web/server/server.d.ts +0 -18
  56. package/dist/web/server/server.js +0 -142
  57. package/dist/web/server/sessions/sessions.controller.d.ts +0 -8
  58. package/dist/web/server/sessions/sessions.controller.js +0 -59
  59. package/dist/web/server/sessions/sessions.module.d.ts +0 -2
  60. package/dist/web/server/sessions/sessions.module.js +0 -24
  61. package/dist/web/server/sessions/sessions.service.d.ts +0 -22
  62. package/dist/web/server/sessions/sessions.service.js +0 -217
  63. package/dist/web/server/sessions/sessions.types.d.ts +0 -18
  64. package/dist/web/server/sessions/sessions.types.js +0 -2
  65. package/dist/web/server/skills/skills.controller.d.ts +0 -31
  66. package/dist/web/server/skills/skills.controller.js +0 -86
  67. package/dist/web/server/skills/skills.module.d.ts +0 -2
  68. package/dist/web/server/skills/skills.module.js +0 -24
  69. package/dist/web/server/skills/skills.service.d.ts +0 -38
  70. package/dist/web/server/skills/skills.service.js +0 -97
  71. package/dist/web/server/stream/stream.module.d.ts +0 -2
  72. package/dist/web/server/stream/stream.module.js +0 -20
  73. package/dist/web/server/stream/stream.service.d.ts +0 -26
  74. package/dist/web/server/stream/stream.service.js +0 -166
  75. package/dist/web/server/tsconfig.build.tsbuildinfo +0 -1
  76. package/dist/web/server/workspaces/workspaces.module.d.ts +0 -2
  77. package/dist/web/server/workspaces/workspaces.module.js +0 -20
  78. package/dist/web/server/workspaces/workspaces.service.d.ts +0 -38
  79. package/dist/web/server/workspaces/workspaces.service.js +0 -378
  80. package/dist/web/server/workspaces/workspaces.types.d.ts +0 -1
  81. package/dist/web/server/workspaces/workspaces.types.js +0 -2
  82. package/dist/web/server/workspaces/workspaces.utils.d.ts +0 -1
  83. package/dist/web/server/workspaces/workspaces.utils.js +0 -9
  84. package/dist/web/server/ws/rpc-router.service.d.ts +0 -20
  85. package/dist/web/server/ws/rpc-router.service.js +0 -275
  86. package/dist/web/server/ws/session-runtime-registry.service.d.ts +0 -37
  87. package/dist/web/server/ws/session-runtime-registry.service.js +0 -118
  88. package/dist/web/server/ws/ws-event-bus.service.d.ts +0 -5
  89. package/dist/web/server/ws/ws-event-bus.service.js +0 -27
  90. package/dist/web/server/ws/ws-gateway.module.d.ts +0 -2
  91. package/dist/web/server/ws/ws-gateway.module.js +0 -42
  92. package/dist/web/server/ws/ws-gateway.service.d.ts +0 -42
  93. package/dist/web/server/ws/ws-gateway.service.js +0 -473
  94. package/dist/web/server/ws/ws.errors.d.ts +0 -8
  95. package/dist/web/server/ws/ws.errors.js +0 -16
  96. package/dist/web/server/ws/ws.types.d.ts +0 -34
  97. package/dist/web/server/ws/ws.types.js +0 -2
@@ -1,326 +0,0 @@
1
- "use strict";
2
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
- return c > 3 && r && Object.defineProperty(target, key, r), r;
7
- };
8
- var ServerConfigService_1;
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.ServerConfigService = void 0;
11
- const node_crypto_1 = require("node:crypto");
12
- const promises_1 = require("node:fs/promises");
13
- const node_os_1 = require("node:os");
14
- const node_path_1 = require("node:path");
15
- const common_1 = require("@nestjs/common");
16
- const yaml_1 = require("yaml");
17
- const workspaces_utils_1 = require("../workspaces/workspaces.utils");
18
- const DEFAULT_ACCESS_TOKEN_TTL_SECONDS = 15 * 60;
19
- const DEFAULT_REFRESH_TOKEN_TTL_SECONDS = 30 * 24 * 60 * 60;
20
- const DEFAULT_ALLOWED_CORS_HOSTS = [
21
- 'localhost',
22
- '127.0.0.1',
23
- '::1',
24
- '*.ngrok-free.app',
25
- ];
26
- const DEFAULT_WORKSPACE_ROOT_PATH = '/';
27
- function expandHomePath(path) {
28
- if (!path.startsWith('~'))
29
- return path;
30
- return (0, node_path_1.join)((0, node_os_1.homedir)(), path.slice(1));
31
- }
32
- function resolveMemoHome() {
33
- const memoHome = process.env.MEMO_HOME;
34
- if (!memoHome)
35
- return (0, node_path_1.join)((0, node_os_1.homedir)(), '.memo');
36
- return expandHomePath(memoHome);
37
- }
38
- async function pathExists(path) {
39
- try {
40
- await (0, promises_1.access)(path);
41
- return true;
42
- }
43
- catch {
44
- return false;
45
- }
46
- }
47
- async function resolveServerConfigPath() {
48
- const explicitPath = process.env.MEMO_SERVER_CONFIG;
49
- if (explicitPath) {
50
- return expandHomePath(explicitPath);
51
- }
52
- const memoHome = resolveMemoHome();
53
- const yamlPath = (0, node_path_1.join)(memoHome, 'server.yaml');
54
- const jsonPath = (0, node_path_1.join)(memoHome, 'server.json');
55
- if (await pathExists(yamlPath))
56
- return yamlPath;
57
- if (await pathExists(jsonPath))
58
- return jsonPath;
59
- return yamlPath;
60
- }
61
- function randomSecret(bytes) {
62
- return (0, node_crypto_1.randomBytes)(bytes).toString('hex');
63
- }
64
- function randomPassword() {
65
- return (0, node_crypto_1.randomBytes)(12).toString('base64url');
66
- }
67
- function readString(value) {
68
- if (typeof value !== 'string')
69
- return null;
70
- const trimmed = value.trim();
71
- return trimmed.length > 0 ? trimmed : null;
72
- }
73
- function readAuthString(value) {
74
- if (typeof value === 'string') {
75
- return readString(value);
76
- }
77
- if (typeof value === 'number' ||
78
- typeof value === 'boolean' ||
79
- typeof value === 'bigint') {
80
- const normalized = String(value).trim();
81
- return normalized.length > 0 ? normalized : null;
82
- }
83
- return null;
84
- }
85
- function normalizePositiveInt(value, fallback) {
86
- if (typeof value === 'number' && Number.isInteger(value) && value > 0)
87
- return value;
88
- if (typeof value === 'string') {
89
- const parsed = Number.parseInt(value, 10);
90
- if (Number.isFinite(parsed) && parsed > 0)
91
- return parsed;
92
- }
93
- return fallback;
94
- }
95
- function normalizeAllowedHosts(input) {
96
- if (!Array.isArray(input))
97
- return [...DEFAULT_ALLOWED_CORS_HOSTS];
98
- const hosts = input
99
- .map((item) => (typeof item === 'string' ? item.trim() : ''))
100
- .filter((item) => item.length > 0);
101
- if (hosts.length === 0)
102
- return [...DEFAULT_ALLOWED_CORS_HOSTS];
103
- return Array.from(new Set(hosts));
104
- }
105
- function normalizeWorkspaceRootPath(value) {
106
- if (typeof value !== 'string' || !value.trim()) {
107
- return DEFAULT_WORKSPACE_ROOT_PATH;
108
- }
109
- return (0, workspaces_utils_1.normalizeWorkspacePath)(value);
110
- }
111
- function normalizeWorkspaceRecords(input) {
112
- if (!Array.isArray(input)) {
113
- return { items: [], changed: true };
114
- }
115
- const now = new Date().toISOString();
116
- const byId = new Map();
117
- let changed = false;
118
- for (const item of input) {
119
- if (!item || typeof item !== 'object' || Array.isArray(item)) {
120
- changed = true;
121
- continue;
122
- }
123
- const record = item;
124
- const rawCwd = readString(record.cwd);
125
- if (!rawCwd) {
126
- changed = true;
127
- continue;
128
- }
129
- const cwd = (0, workspaces_utils_1.normalizeWorkspacePath)(rawCwd);
130
- const id = readString(record.id) ?? (0, workspaces_utils_1.workspaceIdFromCwd)(cwd);
131
- const name = readString(record.name) ?? (0, workspaces_utils_1.defaultWorkspaceName)(cwd);
132
- const createdAt = readString(record.createdAt) ?? now;
133
- const lastUsedAt = readString(record.lastUsedAt) ?? createdAt;
134
- if (id !== record.id ||
135
- name !== record.name ||
136
- cwd !== record.cwd ||
137
- createdAt !== record.createdAt ||
138
- lastUsedAt !== record.lastUsedAt) {
139
- changed = true;
140
- }
141
- byId.set(id, {
142
- id,
143
- name,
144
- cwd,
145
- createdAt,
146
- lastUsedAt,
147
- });
148
- }
149
- const items = Array.from(byId.values()).sort((a, b) => a.cwd.localeCompare(b.cwd));
150
- if (items.length !== input.length) {
151
- changed = true;
152
- }
153
- return {
154
- items,
155
- changed,
156
- };
157
- }
158
- function parseConfigByExtension(raw, configPath) {
159
- if (!raw.trim())
160
- return {};
161
- const ext = (0, node_path_1.extname)(configPath).toLowerCase();
162
- if (ext === '.json') {
163
- try {
164
- return JSON.parse(raw);
165
- }
166
- catch (err) {
167
- throw new Error(`Failed to parse ${configPath}: ${err.message}. Please fix the JSON format.`);
168
- }
169
- }
170
- try {
171
- return (0, yaml_1.parse)(raw) ?? {};
172
- }
173
- catch (err) {
174
- throw new Error(`Failed to parse ${configPath}: ${err.message}. Please fix the YAML format.`);
175
- }
176
- }
177
- let ServerConfigService = ServerConfigService_1 = class ServerConfigService {
178
- logger = new common_1.Logger(ServerConfigService_1.name);
179
- configPath = null;
180
- config = null;
181
- async load() {
182
- if (this.config)
183
- return this.config;
184
- const { configPath, config, generated } = await this.readOrCreateConfig();
185
- this.configPath = configPath;
186
- this.config = config;
187
- if (generated) {
188
- this.logger.warn([
189
- `Created web-server auth config: ${configPath}`,
190
- `username="${config.auth.username}"`,
191
- `password="${config.auth.password}"`,
192
- 'Please change the password after first login.',
193
- ].join(' | '));
194
- }
195
- return config;
196
- }
197
- getConfigPath() {
198
- if (this.configPath)
199
- return this.configPath;
200
- const configured = process.env.MEMO_SERVER_CONFIG;
201
- if (configured)
202
- return expandHomePath(configured);
203
- return (0, node_path_1.join)(resolveMemoHome(), 'server.yaml');
204
- }
205
- getLoadedConfig() {
206
- if (!this.config) {
207
- throw new Error('Server config is not loaded yet. Call load() first.');
208
- }
209
- return this.config;
210
- }
211
- async updateConfig(mutator) {
212
- const current = await this.load();
213
- const next = mutator(current);
214
- const normalized = this.normalizeParsedConfig(next).config;
215
- const configPath = this.getConfigPath();
216
- await this.writeConfig(configPath, normalized);
217
- this.config = normalized;
218
- return normalized;
219
- }
220
- async readOrCreateConfig() {
221
- const configPath = await resolveServerConfigPath();
222
- try {
223
- await (0, promises_1.access)(configPath);
224
- }
225
- catch {
226
- const created = this.createDefaultConfig();
227
- await this.writeConfig(configPath, created);
228
- return { configPath, config: created, generated: true };
229
- }
230
- const raw = await (0, promises_1.readFile)(configPath, 'utf8');
231
- const parsed = parseConfigByExtension(raw, configPath);
232
- const normalized = this.normalizeParsedConfig(parsed);
233
- if (normalized.rewriteRequired) {
234
- await this.writeConfig(configPath, normalized.config);
235
- }
236
- return { configPath, config: normalized.config, generated: false };
237
- }
238
- createDefaultConfig() {
239
- return {
240
- auth: {
241
- username: 'memo',
242
- password: randomPassword(),
243
- accessTokenSecret: randomSecret(32),
244
- refreshTokenSecret: randomSecret(48),
245
- accessTokenTtlSeconds: DEFAULT_ACCESS_TOKEN_TTL_SECONDS,
246
- refreshTokenTtlSeconds: DEFAULT_REFRESH_TOKEN_TTL_SECONDS,
247
- },
248
- security: {
249
- corsAllowedHosts: [...DEFAULT_ALLOWED_CORS_HOSTS],
250
- },
251
- workspaces: [],
252
- workspaceBrowser: {
253
- rootPath: DEFAULT_WORKSPACE_ROOT_PATH,
254
- },
255
- };
256
- }
257
- normalizeParsedConfig(parsed) {
258
- let rewriteRequired = false;
259
- const username = readAuthString(parsed.auth?.username) ?? 'memo';
260
- if (!readAuthString(parsed.auth?.username))
261
- rewriteRequired = true;
262
- const password = readAuthString(parsed.auth?.password) ?? 'memo';
263
- if (!readAuthString(parsed.auth?.password))
264
- rewriteRequired = true;
265
- const accessTokenSecret = readAuthString(parsed.auth?.accessTokenSecret) ?? randomSecret(32);
266
- if (!readAuthString(parsed.auth?.accessTokenSecret))
267
- rewriteRequired = true;
268
- const refreshTokenSecret = readAuthString(parsed.auth?.refreshTokenSecret) ?? randomSecret(48);
269
- if (!readAuthString(parsed.auth?.refreshTokenSecret))
270
- rewriteRequired = true;
271
- const accessTokenTtlSeconds = normalizePositiveInt(parsed.auth?.accessTokenTtlSeconds, DEFAULT_ACCESS_TOKEN_TTL_SECONDS);
272
- if (accessTokenTtlSeconds !== parsed.auth?.accessTokenTtlSeconds)
273
- rewriteRequired = true;
274
- const refreshTokenTtlSeconds = normalizePositiveInt(parsed.auth?.refreshTokenTtlSeconds, DEFAULT_REFRESH_TOKEN_TTL_SECONDS);
275
- if (refreshTokenTtlSeconds !== parsed.auth?.refreshTokenTtlSeconds)
276
- rewriteRequired = true;
277
- const corsAllowedHosts = normalizeAllowedHosts(parsed.security?.corsAllowedHosts);
278
- if (!Array.isArray(parsed.security?.corsAllowedHosts) ||
279
- corsAllowedHosts.length !== parsed.security.corsAllowedHosts.length) {
280
- rewriteRequired = true;
281
- }
282
- const normalizedWorkspaces = normalizeWorkspaceRecords(parsed.workspaces);
283
- if (normalizedWorkspaces.changed) {
284
- rewriteRequired = true;
285
- }
286
- const workspaceRootPath = normalizeWorkspaceRootPath(parsed.workspaceBrowser?.rootPath);
287
- if (workspaceRootPath !== parsed.workspaceBrowser?.rootPath) {
288
- rewriteRequired = true;
289
- }
290
- return {
291
- config: {
292
- auth: {
293
- username,
294
- password,
295
- accessTokenSecret,
296
- refreshTokenSecret,
297
- accessTokenTtlSeconds,
298
- refreshTokenTtlSeconds,
299
- },
300
- security: {
301
- corsAllowedHosts,
302
- },
303
- workspaces: normalizedWorkspaces.items,
304
- workspaceBrowser: {
305
- rootPath: workspaceRootPath,
306
- },
307
- },
308
- rewriteRequired,
309
- };
310
- }
311
- async writeConfig(configPath, config) {
312
- await (0, promises_1.mkdir)((0, node_path_1.dirname)(configPath), { recursive: true });
313
- const ext = (0, node_path_1.extname)(configPath).toLowerCase();
314
- const content = ext === '.json'
315
- ? `${JSON.stringify(config, null, 2)}\n`
316
- : (0, yaml_1.stringify)(config);
317
- await (0, promises_1.writeFile)(configPath, content, {
318
- encoding: 'utf8',
319
- mode: 0o600,
320
- });
321
- }
322
- };
323
- exports.ServerConfigService = ServerConfigService;
324
- exports.ServerConfigService = ServerConfigService = ServerConfigService_1 = __decorate([
325
- (0, common_1.Injectable)()
326
- ], ServerConfigService);
@@ -1,193 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const node_assert_1 = __importDefault(require("node:assert"));
7
- const promises_1 = require("node:fs/promises");
8
- const node_os_1 = require("node:os");
9
- const node_path_1 = require("node:path");
10
- const yaml_1 = require("yaml");
11
- const vitest_1 = require("vitest");
12
- vitest_1.vi.mock('../workspaces/workspaces.utils', () => ({
13
- defaultWorkspaceName: (cwd) => cwd.split('/').filter(Boolean).at(-1) ?? 'workspace',
14
- normalizeWorkspacePath: (input) => input.replace(/\\/g, '/'),
15
- workspaceIdFromCwd: (cwd) => `workspace-${cwd.replace(/[^a-zA-Z0-9]/g, '_')}`,
16
- }));
17
- const server_config_service_1 = require("./server-config.service");
18
- function snapshotEnv() {
19
- return {
20
- memoHome: process.env.MEMO_HOME,
21
- serverConfig: process.env.MEMO_SERVER_CONFIG,
22
- };
23
- }
24
- function restoreEnv(snapshot) {
25
- if (snapshot.memoHome === undefined) {
26
- delete process.env.MEMO_HOME;
27
- }
28
- else {
29
- process.env.MEMO_HOME = snapshot.memoHome;
30
- }
31
- if (snapshot.serverConfig === undefined) {
32
- delete process.env.MEMO_SERVER_CONFIG;
33
- }
34
- else {
35
- process.env.MEMO_SERVER_CONFIG = snapshot.serverConfig;
36
- }
37
- }
38
- const tempRoots = [];
39
- (0, vitest_1.afterEach)(async () => {
40
- while (tempRoots.length > 0) {
41
- const item = tempRoots.pop();
42
- if (!item)
43
- continue;
44
- await (0, promises_1.rm)(item, { recursive: true, force: true });
45
- }
46
- });
47
- (0, vitest_1.describe)('ServerConfigService', () => {
48
- (0, vitest_1.test)('preserves configured password scalar when normalizing config', async () => {
49
- const envSnapshot = snapshotEnv();
50
- const memoHome = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'memo-web-server-config-'));
51
- tempRoots.push(memoHome);
52
- process.env.MEMO_HOME = memoHome;
53
- delete process.env.MEMO_SERVER_CONFIG;
54
- const configPath = (0, node_path_1.join)(memoHome, 'server.yaml');
55
- await (0, promises_1.writeFile)(configPath, [
56
- 'auth:',
57
- ' username: memo',
58
- ' password: 123456',
59
- 'security:',
60
- ' corsAllowedHosts:',
61
- ' - localhost',
62
- '',
63
- ].join('\n'), 'utf8');
64
- try {
65
- const first = await new server_config_service_1.ServerConfigService().load();
66
- node_assert_1.default.strictEqual(first.auth.password, '123456');
67
- const persisted = (0, yaml_1.parse)(await (0, promises_1.readFile)(configPath, 'utf8'));
68
- node_assert_1.default.strictEqual(typeof persisted.auth?.password, 'string', 'password should persist as string after normalization rewrite');
69
- node_assert_1.default.strictEqual(persisted.auth?.password, '123456');
70
- const second = await new server_config_service_1.ServerConfigService().load();
71
- node_assert_1.default.strictEqual(second.auth.password, '123456');
72
- }
73
- finally {
74
- restoreEnv(envSnapshot);
75
- }
76
- });
77
- (0, vitest_1.test)('creates default yaml config when missing', async () => {
78
- const envSnapshot = snapshotEnv();
79
- const memoHome = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'memo-web-server-default-'));
80
- tempRoots.push(memoHome);
81
- process.env.MEMO_HOME = memoHome;
82
- delete process.env.MEMO_SERVER_CONFIG;
83
- const service = new server_config_service_1.ServerConfigService();
84
- try {
85
- const loaded = await service.load();
86
- const configPath = (0, node_path_1.join)(memoHome, 'server.yaml');
87
- const persisted = (0, yaml_1.parse)(await (0, promises_1.readFile)(configPath, 'utf8'));
88
- node_assert_1.default.strictEqual(service.getConfigPath(), configPath);
89
- node_assert_1.default.strictEqual(loaded.auth.username, 'memo');
90
- node_assert_1.default.ok(loaded.auth.password.length > 0);
91
- node_assert_1.default.strictEqual(persisted.auth?.username, 'memo');
92
- node_assert_1.default.strictEqual(typeof persisted.auth?.password, 'string');
93
- }
94
- finally {
95
- restoreEnv(envSnapshot);
96
- }
97
- });
98
- (0, vitest_1.test)('loads explicit JSON config path and normalizes malformed fields', async () => {
99
- const envSnapshot = snapshotEnv();
100
- const memoHome = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'memo-web-server-json-'));
101
- tempRoots.push(memoHome);
102
- const configPath = (0, node_path_1.join)(memoHome, 'custom-server.json');
103
- process.env.MEMO_HOME = memoHome;
104
- process.env.MEMO_SERVER_CONFIG = configPath;
105
- await (0, promises_1.writeFile)(configPath, JSON.stringify({
106
- auth: {
107
- username: true,
108
- password: 12345,
109
- accessTokenSecret: '',
110
- refreshTokenSecret: '',
111
- accessTokenTtlSeconds: -1,
112
- refreshTokenTtlSeconds: 'abc',
113
- },
114
- security: {
115
- corsAllowedHosts: [],
116
- },
117
- workspaces: [
118
- { id: 'same', name: 'workspace-a', cwd: '/tmp/workspace-a' },
119
- { id: 'same', name: 'workspace-b', cwd: '/tmp/workspace-a' },
120
- { foo: 'invalid' },
121
- ],
122
- workspaceBrowser: {
123
- rootPath: '',
124
- },
125
- }, null, 2), 'utf8');
126
- const service = new server_config_service_1.ServerConfigService();
127
- try {
128
- const loaded = await service.load();
129
- node_assert_1.default.strictEqual(loaded.auth.username, 'true');
130
- node_assert_1.default.strictEqual(loaded.auth.password, '12345');
131
- node_assert_1.default.strictEqual(loaded.workspaces.length, 1);
132
- node_assert_1.default.strictEqual(loaded.workspaceBrowser.rootPath, '/');
133
- node_assert_1.default.ok(loaded.security.corsAllowedHosts.length > 0);
134
- const persisted = JSON.parse(await (0, promises_1.readFile)(configPath, 'utf8'));
135
- node_assert_1.default.strictEqual(Array.isArray(persisted.workspaces), true);
136
- node_assert_1.default.strictEqual(persisted.workspaces?.length, 1);
137
- node_assert_1.default.ok((persisted.auth?.accessTokenSecret?.length ?? 0) > 0);
138
- node_assert_1.default.ok((persisted.auth?.refreshTokenSecret?.length ?? 0) > 0);
139
- }
140
- finally {
141
- restoreEnv(envSnapshot);
142
- }
143
- });
144
- (0, vitest_1.test)('throws clear parsing error for invalid json config', async () => {
145
- const envSnapshot = snapshotEnv();
146
- const memoHome = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'memo-web-server-bad-json-'));
147
- tempRoots.push(memoHome);
148
- const configPath = (0, node_path_1.join)(memoHome, 'server.json');
149
- process.env.MEMO_HOME = memoHome;
150
- process.env.MEMO_SERVER_CONFIG = configPath;
151
- await (0, promises_1.writeFile)(configPath, '{"auth": ', 'utf8');
152
- try {
153
- await node_assert_1.default.rejects(() => new server_config_service_1.ServerConfigService().load(), /Failed to parse .*server\.json/);
154
- }
155
- finally {
156
- restoreEnv(envSnapshot);
157
- }
158
- });
159
- (0, vitest_1.test)('updateConfig persists normalized updates', async () => {
160
- const envSnapshot = snapshotEnv();
161
- const memoHome = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'memo-web-server-update-'));
162
- tempRoots.push(memoHome);
163
- process.env.MEMO_HOME = memoHome;
164
- delete process.env.MEMO_SERVER_CONFIG;
165
- const service = new server_config_service_1.ServerConfigService();
166
- try {
167
- await service.load();
168
- const updated = await service.updateConfig((config) => ({
169
- ...config,
170
- security: {
171
- corsAllowedHosts: ['example.com', 'localhost'],
172
- },
173
- workspaceBrowser: {
174
- rootPath: '/tmp/root',
175
- },
176
- }));
177
- node_assert_1.default.deepStrictEqual(updated.security.corsAllowedHosts, [
178
- 'example.com',
179
- 'localhost',
180
- ]);
181
- node_assert_1.default.strictEqual(updated.workspaceBrowser.rootPath, '/tmp/root');
182
- const persisted = (0, yaml_1.parse)(await (0, promises_1.readFile)((0, node_path_1.join)(memoHome, 'server.yaml'), 'utf8'));
183
- node_assert_1.default.deepStrictEqual(persisted.security?.corsAllowedHosts, [
184
- 'example.com',
185
- 'localhost',
186
- ]);
187
- node_assert_1.default.strictEqual(persisted.workspaceBrowser?.rootPath, '/tmp/root');
188
- }
189
- finally {
190
- restoreEnv(envSnapshot);
191
- }
192
- });
193
- });
@@ -1,27 +0,0 @@
1
- export type ServerAuthConfig = {
2
- username: string;
3
- password: string;
4
- accessTokenSecret: string;
5
- refreshTokenSecret: string;
6
- accessTokenTtlSeconds: number;
7
- refreshTokenTtlSeconds: number;
8
- };
9
- export type ServerSecurityConfig = {
10
- corsAllowedHosts: string[];
11
- };
12
- export type ServerWorkspaceRecord = {
13
- id: string;
14
- name: string;
15
- cwd: string;
16
- createdAt: string;
17
- lastUsedAt: string;
18
- };
19
- export type ServerWorkspaceBrowserConfig = {
20
- rootPath: string;
21
- };
22
- export type ServerRuntimeConfig = {
23
- auth: ServerAuthConfig;
24
- security: ServerSecurityConfig;
25
- workspaces: ServerWorkspaceRecord[];
26
- workspaceBrowser: ServerWorkspaceBrowserConfig;
27
- };
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1 +0,0 @@
1
- export {};
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const server_1 = require("./server");
4
- function parsePort(value) {
5
- if (!value)
6
- return undefined;
7
- const parsed = Number.parseInt(value, 10);
8
- if (Number.isInteger(parsed) && parsed > 0 && parsed <= 65535)
9
- return parsed;
10
- return undefined;
11
- }
12
- async function bootstrap() {
13
- await (0, server_1.startMemoWebServer)({
14
- host: process.env.MEMO_WEB_HOST ?? process.env.HOST,
15
- port: parsePort(process.env.MEMO_WEB_PORT ?? process.env.PORT),
16
- staticDir: process.env.MEMO_WEB_STATIC_DIR,
17
- });
18
- }
19
- void bootstrap();
@@ -1,38 +0,0 @@
1
- import { McpService } from './mcp.service';
2
- type UpsertMcpBody = {
3
- name?: unknown;
4
- config?: unknown;
5
- };
6
- type LoginBody = {
7
- scopes?: unknown;
8
- };
9
- type ActiveBody = {
10
- names?: unknown;
11
- };
12
- export declare class McpController {
13
- private readonly mcpService;
14
- constructor(mcpService: McpService);
15
- list(): Promise<{
16
- items: import("@memo-code/core", { with: { "resolution-mode": "import" } }).McpServerRecord[];
17
- }>;
18
- get(name: string): Promise<import("@memo-code/core", { with: { "resolution-mode": "import" } }).McpServerRecord>;
19
- create(body: UpsertMcpBody): Promise<{
20
- created: true;
21
- }>;
22
- update(name: string, body: UpsertMcpBody): Promise<{
23
- updated: true;
24
- }>;
25
- remove(name: string): Promise<{
26
- deleted: true;
27
- }>;
28
- login(name: string, body: LoginBody): Promise<{
29
- loggedIn: true;
30
- }>;
31
- logout(name: string): Promise<{
32
- loggedOut: true;
33
- }>;
34
- setActive(body: ActiveBody): Promise<{
35
- active: string[];
36
- }>;
37
- }
38
- export {};