@prmichaelsen/remember-mcp 0.2.3 → 0.2.5
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/README.md +42 -13
- package/dist/server-factory.js +32 -13
- package/dist/server.js +26 -57
- package/dist/utils/logger.d.ts +4 -4
- package/package.json +2 -1
- package/src/server-factory.spec.ts +4 -2
- package/src/server-factory.ts +13 -5
- package/src/server.ts +0 -62
- package/src/utils/logger.ts +25 -8
package/README.md
CHANGED
|
@@ -4,17 +4,49 @@ Multi-tenant memory system MCP server with vector search, relationships, and tru
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- 10 MCP tools for memory and relationship management
|
|
8
8
|
- Multi-tenant with per-user isolation
|
|
9
|
-
- Vector search with Weaviate
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
9
|
+
- Vector search with Weaviate (semantic + keyword hybrid search)
|
|
10
|
+
- Knowledge graph with relationship tracking
|
|
11
|
+
- RAG queries with natural language
|
|
12
|
+
- 45 content types (notes, events, people, recipes, etc.)
|
|
13
|
+
- Trust-based access control (planned for M7)
|
|
14
14
|
|
|
15
15
|
## Quick Start
|
|
16
16
|
|
|
17
|
-
###
|
|
17
|
+
### Option 1: Use with Claude Desktop (Recommended)
|
|
18
|
+
|
|
19
|
+
Add to your Claude Desktop MCP configuration:
|
|
20
|
+
|
|
21
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
22
|
+
**Linux**: `~/.config/Claude/claude_desktop_config.json`
|
|
23
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"remember": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["-y", "@prmichaelsen/remember-mcp"],
|
|
31
|
+
"env": {
|
|
32
|
+
"WEAVIATE_REST_URL": "https://your-instance.weaviate.cloud",
|
|
33
|
+
"WEAVIATE_API_KEY": "your-weaviate-api-key",
|
|
34
|
+
"OPENAI_EMBEDDINGS_API_KEY": "sk-...",
|
|
35
|
+
"FIREBASE_ADMIN_SERVICE_ACCOUNT_KEY": "{\"type\":\"service_account\",\"project_id\":\"your-project\",\"private_key\":\"-----BEGIN PRIVATE KEY-----\\nYOUR_KEY\\n-----END PRIVATE KEY-----\\n\",\"client_email\":\"firebase-adminsdk@your-project.iam.gserviceaccount.com\"}",
|
|
36
|
+
"FIREBASE_PROJECT_ID": "your-project-id"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Important**:
|
|
44
|
+
- Use `\\n` (double backslash) for newlines in private_key
|
|
45
|
+
- Escape all quotes with `\"`
|
|
46
|
+
- Get Weaviate Cloud at https://console.weaviate.cloud
|
|
47
|
+
- Get Firebase service account from Firebase Console → Project Settings → Service Accounts
|
|
48
|
+
|
|
49
|
+
### Option 2: Standalone (stdio transport)
|
|
18
50
|
|
|
19
51
|
```bash
|
|
20
52
|
# Install dependencies
|
|
@@ -32,10 +64,10 @@ npm run build
|
|
|
32
64
|
npm start
|
|
33
65
|
```
|
|
34
66
|
|
|
35
|
-
### With mcp-auth (multi-tenant production)
|
|
67
|
+
### Option 3: With mcp-auth (multi-tenant production)
|
|
36
68
|
|
|
37
69
|
```typescript
|
|
38
|
-
import { wrapServer, JWTAuthProvider
|
|
70
|
+
import { wrapServer, JWTAuthProvider } from '@prmichaelsen/mcp-auth';
|
|
39
71
|
import { createServer } from '@prmichaelsen/remember-mcp/factory';
|
|
40
72
|
|
|
41
73
|
const wrapped = wrapServer({
|
|
@@ -43,10 +75,7 @@ const wrapped = wrapServer({
|
|
|
43
75
|
authProvider: new JWTAuthProvider({
|
|
44
76
|
jwtSecret: process.env.JWT_SECRET
|
|
45
77
|
}),
|
|
46
|
-
tokenResolver
|
|
47
|
-
tenantManagerUrl: process.env.TENANT_MANAGER_URL,
|
|
48
|
-
serviceToken: process.env.SERVICE_TOKEN
|
|
49
|
-
}),
|
|
78
|
+
// tokenResolver not needed - remember-mcp is self-managed
|
|
50
79
|
resourceType: 'remember',
|
|
51
80
|
transport: { type: 'sse', port: 3000 }
|
|
52
81
|
});
|
package/dist/server-factory.js
CHANGED
|
@@ -630,24 +630,40 @@ function shouldLog(level) {
|
|
|
630
630
|
return LOG_LEVELS[level] >= currentLevel;
|
|
631
631
|
}
|
|
632
632
|
var logger = {
|
|
633
|
-
debug: (message,
|
|
633
|
+
debug: (message, data) => {
|
|
634
634
|
if (shouldLog("debug")) {
|
|
635
|
-
|
|
635
|
+
if (data) {
|
|
636
|
+
console.debug(JSON.stringify({ level: "DEBUG", message, ...data }));
|
|
637
|
+
} else {
|
|
638
|
+
console.debug(`[DEBUG] ${message}`);
|
|
639
|
+
}
|
|
636
640
|
}
|
|
637
641
|
},
|
|
638
|
-
info: (message,
|
|
642
|
+
info: (message, data) => {
|
|
639
643
|
if (shouldLog("info")) {
|
|
640
|
-
|
|
644
|
+
if (data) {
|
|
645
|
+
console.info(JSON.stringify({ level: "INFO", message, ...data }));
|
|
646
|
+
} else {
|
|
647
|
+
console.info(`[INFO] ${message}`);
|
|
648
|
+
}
|
|
641
649
|
}
|
|
642
650
|
},
|
|
643
|
-
warn: (message,
|
|
651
|
+
warn: (message, data) => {
|
|
644
652
|
if (shouldLog("warn")) {
|
|
645
|
-
|
|
653
|
+
if (data) {
|
|
654
|
+
console.warn(JSON.stringify({ level: "WARN", message, ...data }));
|
|
655
|
+
} else {
|
|
656
|
+
console.warn(`[WARN] ${message}`);
|
|
657
|
+
}
|
|
646
658
|
}
|
|
647
659
|
},
|
|
648
|
-
error: (message,
|
|
660
|
+
error: (message, data) => {
|
|
649
661
|
if (shouldLog("error")) {
|
|
650
|
-
|
|
662
|
+
if (data) {
|
|
663
|
+
console.error(JSON.stringify({ level: "ERROR", message, ...data }));
|
|
664
|
+
} else {
|
|
665
|
+
console.error(`[ERROR] ${message}`);
|
|
666
|
+
}
|
|
651
667
|
}
|
|
652
668
|
}
|
|
653
669
|
};
|
|
@@ -2700,8 +2716,14 @@ async function ensureDatabasesInitialized() {
|
|
|
2700
2716
|
databasesInitialized = true;
|
|
2701
2717
|
logger.info("Databases initialized successfully");
|
|
2702
2718
|
} catch (error) {
|
|
2703
|
-
|
|
2704
|
-
|
|
2719
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2720
|
+
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
2721
|
+
logger.error("Database initialization failed", {
|
|
2722
|
+
error: errorMessage,
|
|
2723
|
+
stack: errorStack,
|
|
2724
|
+
type: error instanceof Error ? error.constructor.name : "Unknown"
|
|
2725
|
+
});
|
|
2726
|
+
throw new Error(`Database initialization failed: ${errorMessage}`);
|
|
2705
2727
|
} finally {
|
|
2706
2728
|
initializationPromise = null;
|
|
2707
2729
|
}
|
|
@@ -2709,9 +2731,6 @@ async function ensureDatabasesInitialized() {
|
|
|
2709
2731
|
return initializationPromise;
|
|
2710
2732
|
}
|
|
2711
2733
|
function createServer(accessToken, userId, options = {}) {
|
|
2712
|
-
if (!accessToken) {
|
|
2713
|
-
throw new Error("accessToken is required");
|
|
2714
|
-
}
|
|
2715
2734
|
if (!userId) {
|
|
2716
2735
|
throw new Error("userId is required");
|
|
2717
2736
|
}
|
package/dist/server.js
CHANGED
|
@@ -308,7 +308,7 @@ var require_main = __commonJS({
|
|
|
308
308
|
return { parsed: parsedAll };
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
|
-
function
|
|
311
|
+
function config3(options) {
|
|
312
312
|
if (_dotenvKey(options).length === 0) {
|
|
313
313
|
return DotenvModule.configDotenv(options);
|
|
314
314
|
}
|
|
@@ -375,7 +375,7 @@ var require_main = __commonJS({
|
|
|
375
375
|
configDotenv,
|
|
376
376
|
_configVault,
|
|
377
377
|
_parseVault,
|
|
378
|
-
config:
|
|
378
|
+
config: config3,
|
|
379
379
|
decrypt,
|
|
380
380
|
parse,
|
|
381
381
|
populate
|
|
@@ -564,24 +564,40 @@ function shouldLog(level) {
|
|
|
564
564
|
return LOG_LEVELS[level] >= currentLevel;
|
|
565
565
|
}
|
|
566
566
|
var logger = {
|
|
567
|
-
debug: (message,
|
|
567
|
+
debug: (message, data) => {
|
|
568
568
|
if (shouldLog("debug")) {
|
|
569
|
-
|
|
569
|
+
if (data) {
|
|
570
|
+
console.debug(JSON.stringify({ level: "DEBUG", message, ...data }));
|
|
571
|
+
} else {
|
|
572
|
+
console.debug(`[DEBUG] ${message}`);
|
|
573
|
+
}
|
|
570
574
|
}
|
|
571
575
|
},
|
|
572
|
-
info: (message,
|
|
576
|
+
info: (message, data) => {
|
|
573
577
|
if (shouldLog("info")) {
|
|
574
|
-
|
|
578
|
+
if (data) {
|
|
579
|
+
console.info(JSON.stringify({ level: "INFO", message, ...data }));
|
|
580
|
+
} else {
|
|
581
|
+
console.info(`[INFO] ${message}`);
|
|
582
|
+
}
|
|
575
583
|
}
|
|
576
584
|
},
|
|
577
|
-
warn: (message,
|
|
585
|
+
warn: (message, data) => {
|
|
578
586
|
if (shouldLog("warn")) {
|
|
579
|
-
|
|
587
|
+
if (data) {
|
|
588
|
+
console.warn(JSON.stringify({ level: "WARN", message, ...data }));
|
|
589
|
+
} else {
|
|
590
|
+
console.warn(`[WARN] ${message}`);
|
|
591
|
+
}
|
|
580
592
|
}
|
|
581
593
|
},
|
|
582
|
-
error: (message,
|
|
594
|
+
error: (message, data) => {
|
|
583
595
|
if (shouldLog("error")) {
|
|
584
|
-
|
|
596
|
+
if (data) {
|
|
597
|
+
console.error(JSON.stringify({ level: "ERROR", message, ...data }));
|
|
598
|
+
} else {
|
|
599
|
+
console.error(`[ERROR] ${message}`);
|
|
600
|
+
}
|
|
585
601
|
}
|
|
586
602
|
}
|
|
587
603
|
};
|
|
@@ -2643,14 +2659,6 @@ function registerHandlers(server) {
|
|
|
2643
2659
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
2644
2660
|
return {
|
|
2645
2661
|
tools: [
|
|
2646
|
-
{
|
|
2647
|
-
name: "health_check",
|
|
2648
|
-
description: "Check server health and database connections",
|
|
2649
|
-
inputSchema: {
|
|
2650
|
-
type: "object",
|
|
2651
|
-
properties: {}
|
|
2652
|
-
}
|
|
2653
|
-
},
|
|
2654
2662
|
// Memory tools
|
|
2655
2663
|
createMemoryTool,
|
|
2656
2664
|
searchMemoryTool,
|
|
@@ -2672,9 +2680,6 @@ function registerHandlers(server) {
|
|
|
2672
2680
|
let result;
|
|
2673
2681
|
const userId = args.user_id || "default_user";
|
|
2674
2682
|
switch (name) {
|
|
2675
|
-
case "health_check":
|
|
2676
|
-
result = await handleHealthCheck();
|
|
2677
|
-
break;
|
|
2678
2683
|
case "remember_create_memory":
|
|
2679
2684
|
result = await handleCreateMemory(args, userId);
|
|
2680
2685
|
break;
|
|
@@ -2731,42 +2736,6 @@ function registerHandlers(server) {
|
|
|
2731
2736
|
}
|
|
2732
2737
|
});
|
|
2733
2738
|
}
|
|
2734
|
-
async function handleHealthCheck() {
|
|
2735
|
-
const health = {
|
|
2736
|
-
status: "healthy",
|
|
2737
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2738
|
-
server: {
|
|
2739
|
-
name: "remember-mcp",
|
|
2740
|
-
version: "0.1.0"
|
|
2741
|
-
},
|
|
2742
|
-
databases: {
|
|
2743
|
-
weaviate: {
|
|
2744
|
-
connected: false,
|
|
2745
|
-
url: config.weaviate.url
|
|
2746
|
-
},
|
|
2747
|
-
firestore: {
|
|
2748
|
-
connected: false,
|
|
2749
|
-
projectId: config.firebase.projectId
|
|
2750
|
-
}
|
|
2751
|
-
}
|
|
2752
|
-
};
|
|
2753
|
-
try {
|
|
2754
|
-
const weaviateClient = getWeaviateClient();
|
|
2755
|
-
health.databases.weaviate.connected = await weaviateClient.isReady();
|
|
2756
|
-
} catch (error) {
|
|
2757
|
-
logger.error("Weaviate health check failed:", error);
|
|
2758
|
-
health.databases.weaviate.connected = false;
|
|
2759
|
-
}
|
|
2760
|
-
try {
|
|
2761
|
-
health.databases.firestore.connected = await testFirestoreConnection();
|
|
2762
|
-
} catch (error) {
|
|
2763
|
-
logger.error("Firestore health check failed:", error);
|
|
2764
|
-
health.databases.firestore.connected = false;
|
|
2765
|
-
}
|
|
2766
|
-
const allHealthy = health.databases.weaviate.connected && health.databases.firestore.connected;
|
|
2767
|
-
health.status = allHealthy ? "healthy" : "degraded";
|
|
2768
|
-
return JSON.stringify(health, null, 2);
|
|
2769
|
-
}
|
|
2770
2739
|
async function main() {
|
|
2771
2740
|
try {
|
|
2772
2741
|
logger.info("Starting remember-mcp server...");
|
package/dist/utils/logger.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const logger: {
|
|
2
|
-
debug: (message: string,
|
|
3
|
-
info: (message: string,
|
|
4
|
-
warn: (message: string,
|
|
5
|
-
error: (message: string,
|
|
2
|
+
debug: (message: string, data?: any) => void;
|
|
3
|
+
info: (message: string, data?: any) => void;
|
|
4
|
+
warn: (message: string, data?: any) => void;
|
|
5
|
+
error: (message: string, data?: any) => void;
|
|
6
6
|
};
|
|
7
7
|
//# sourceMappingURL=logger.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prmichaelsen/remember-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Multi-tenant memory system MCP server with vector search and relationships",
|
|
5
5
|
"main": "dist/server.js",
|
|
6
6
|
"type": "module",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
51
51
|
"@prmichaelsen/firebase-admin-sdk-v8": "^2.2.0",
|
|
52
|
+
"@prmichaelsen/mcp-auth": "^7.0.4",
|
|
52
53
|
"dotenv": "^16.4.5",
|
|
53
54
|
"weaviate-client": "^3.2.0"
|
|
54
55
|
},
|
|
@@ -9,8 +9,10 @@ describe('Server Factory', () => {
|
|
|
9
9
|
expect(server).toHaveProperty('setRequestHandler');
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
it('should
|
|
13
|
-
|
|
12
|
+
it('should allow empty accessToken (not used by remember-mcp)', () => {
|
|
13
|
+
// accessToken is not used by remember-mcp (self-managed data)
|
|
14
|
+
// Should not throw even with empty string
|
|
15
|
+
expect(() => createServer('', 'user123')).not.toThrow();
|
|
14
16
|
});
|
|
15
17
|
|
|
16
18
|
it('should require userId', () => {
|
package/src/server-factory.ts
CHANGED
|
@@ -59,8 +59,17 @@ async function ensureDatabasesInitialized(): Promise<void> {
|
|
|
59
59
|
databasesInitialized = true;
|
|
60
60
|
logger.info('Databases initialized successfully');
|
|
61
61
|
} catch (error) {
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
// Format error as single-line JSON for better cloud logging
|
|
63
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
64
|
+
const errorStack = error instanceof Error ? error.stack : undefined;
|
|
65
|
+
|
|
66
|
+
logger.error('Database initialization failed', {
|
|
67
|
+
error: errorMessage,
|
|
68
|
+
stack: errorStack,
|
|
69
|
+
type: error instanceof Error ? error.constructor.name : 'Unknown'
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
throw new Error(`Database initialization failed: ${errorMessage}`);
|
|
64
73
|
} finally {
|
|
65
74
|
initializationPromise = null;
|
|
66
75
|
}
|
|
@@ -105,9 +114,8 @@ export function createServer(
|
|
|
105
114
|
userId: string,
|
|
106
115
|
options: ServerOptions = {}
|
|
107
116
|
): Server {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
117
|
+
// Note: accessToken is not used by remember-mcp (self-managed data)
|
|
118
|
+
// but required by mcp-auth contract. Can be any value including empty string.
|
|
111
119
|
|
|
112
120
|
if (!userId) {
|
|
113
121
|
throw new Error('userId is required');
|
package/src/server.ts
CHANGED
|
@@ -79,14 +79,6 @@ function registerHandlers(server: Server): void {
|
|
|
79
79
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
80
80
|
return {
|
|
81
81
|
tools: [
|
|
82
|
-
{
|
|
83
|
-
name: 'health_check',
|
|
84
|
-
description: 'Check server health and database connections',
|
|
85
|
-
inputSchema: {
|
|
86
|
-
type: 'object',
|
|
87
|
-
properties: {},
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
82
|
// Memory tools
|
|
91
83
|
createMemoryTool,
|
|
92
84
|
searchMemoryTool,
|
|
@@ -115,10 +107,6 @@ function registerHandlers(server: Server): void {
|
|
|
115
107
|
const userId = (args as any).user_id || 'default_user';
|
|
116
108
|
|
|
117
109
|
switch (name) {
|
|
118
|
-
case 'health_check':
|
|
119
|
-
result = await handleHealthCheck();
|
|
120
|
-
break;
|
|
121
|
-
|
|
122
110
|
case 'remember_create_memory':
|
|
123
111
|
result = await handleCreateMemory(args as any, userId);
|
|
124
112
|
break;
|
|
@@ -188,56 +176,6 @@ function registerHandlers(server: Server): void {
|
|
|
188
176
|
});
|
|
189
177
|
}
|
|
190
178
|
|
|
191
|
-
/**
|
|
192
|
-
* Health check handler
|
|
193
|
-
*/
|
|
194
|
-
async function handleHealthCheck(): Promise<string> {
|
|
195
|
-
const health = {
|
|
196
|
-
status: 'healthy',
|
|
197
|
-
timestamp: new Date().toISOString(),
|
|
198
|
-
server: {
|
|
199
|
-
name: 'remember-mcp',
|
|
200
|
-
version: '0.1.0',
|
|
201
|
-
},
|
|
202
|
-
databases: {
|
|
203
|
-
weaviate: {
|
|
204
|
-
connected: false,
|
|
205
|
-
url: config.weaviate.url,
|
|
206
|
-
},
|
|
207
|
-
firestore: {
|
|
208
|
-
connected: false,
|
|
209
|
-
projectId: config.firebase.projectId,
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
try {
|
|
215
|
-
// Test Weaviate connection
|
|
216
|
-
const weaviateClient = getWeaviateClient();
|
|
217
|
-
health.databases.weaviate.connected = await weaviateClient.isReady();
|
|
218
|
-
} catch (error) {
|
|
219
|
-
logger.error('Weaviate health check failed:', error);
|
|
220
|
-
health.databases.weaviate.connected = false;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
try {
|
|
224
|
-
// Test Firestore connection
|
|
225
|
-
health.databases.firestore.connected = await testFirestoreConnection();
|
|
226
|
-
} catch (error) {
|
|
227
|
-
logger.error('Firestore health check failed:', error);
|
|
228
|
-
health.databases.firestore.connected = false;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Overall status
|
|
232
|
-
const allHealthy =
|
|
233
|
-
health.databases.weaviate.connected &&
|
|
234
|
-
health.databases.firestore.connected;
|
|
235
|
-
|
|
236
|
-
health.status = allHealthy ? 'healthy' : 'degraded';
|
|
237
|
-
|
|
238
|
-
return JSON.stringify(health, null, 2);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
179
|
/**
|
|
242
180
|
* Main server startup
|
|
243
181
|
*/
|
package/src/utils/logger.ts
CHANGED
|
@@ -16,27 +16,44 @@ function shouldLog(level: LogLevel): boolean {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export const logger = {
|
|
19
|
-
debug: (message: string,
|
|
19
|
+
debug: (message: string, data?: any) => {
|
|
20
20
|
if (shouldLog('debug')) {
|
|
21
|
-
|
|
21
|
+
if (data) {
|
|
22
|
+
console.debug(JSON.stringify({ level: 'DEBUG', message, ...data }));
|
|
23
|
+
} else {
|
|
24
|
+
console.debug(`[DEBUG] ${message}`);
|
|
25
|
+
}
|
|
22
26
|
}
|
|
23
27
|
},
|
|
24
28
|
|
|
25
|
-
info: (message: string,
|
|
29
|
+
info: (message: string, data?: any) => {
|
|
26
30
|
if (shouldLog('info')) {
|
|
27
|
-
|
|
31
|
+
if (data) {
|
|
32
|
+
console.info(JSON.stringify({ level: 'INFO', message, ...data }));
|
|
33
|
+
} else {
|
|
34
|
+
console.info(`[INFO] ${message}`);
|
|
35
|
+
}
|
|
28
36
|
}
|
|
29
37
|
},
|
|
30
38
|
|
|
31
|
-
warn: (message: string,
|
|
39
|
+
warn: (message: string, data?: any) => {
|
|
32
40
|
if (shouldLog('warn')) {
|
|
33
|
-
|
|
41
|
+
if (data) {
|
|
42
|
+
console.warn(JSON.stringify({ level: 'WARN', message, ...data }));
|
|
43
|
+
} else {
|
|
44
|
+
console.warn(`[WARN] ${message}`);
|
|
45
|
+
}
|
|
34
46
|
}
|
|
35
47
|
},
|
|
36
48
|
|
|
37
|
-
error: (message: string,
|
|
49
|
+
error: (message: string, data?: any) => {
|
|
38
50
|
if (shouldLog('error')) {
|
|
39
|
-
|
|
51
|
+
if (data) {
|
|
52
|
+
// Structured logging for cloud environments
|
|
53
|
+
console.error(JSON.stringify({ level: 'ERROR', message, ...data }));
|
|
54
|
+
} else {
|
|
55
|
+
console.error(`[ERROR] ${message}`);
|
|
56
|
+
}
|
|
40
57
|
}
|
|
41
58
|
},
|
|
42
59
|
};
|