@cloud-copilot/log 0.1.0

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 ADDED
@@ -0,0 +1,214 @@
1
+ # Log
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/@cloud-copilot/log.svg?logo=nodedotjs)](https://www.npmjs.com/package/@cloud-copilot/log) [![MIT](https://img.shields.io/github/license/cloud-copilot/log)](LICENSE.txt) [![GuardDog](https://github.com/cloud-copilot/log/actions/workflows/guarddog.yml/badge.svg)](https://github.com/cloud-copilot/log/actions/workflows/guarddog.yml) [![Known Vulnerabilities](https://snyk.io/test/github/cloud-copilot/log/badge.svg?targetFile=package.json&style=flat-square)](https://snyk.io/test/github/cloud-copilot/log?targetFile=package.json)
4
+
5
+ A lightweight logger to output JSON structured logs for Typescript.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @cloud-copilot/log
11
+ ```
12
+
13
+ ## Basic Usage
14
+
15
+ ```typescript
16
+ import { StandardLogger } from '@cloud-copilot/log'
17
+
18
+ // Create a logger with default log level (warn)
19
+ const logger = new StandardLogger()
20
+
21
+ // Or specify an initial log level
22
+ const logger = new StandardLogger('info')
23
+
24
+ // Log messages at different levels
25
+ logger.error('Something went wrong')
26
+ logger.warn('This is a warning')
27
+ logger.info('Information message')
28
+ logger.debug('Debug information')
29
+ logger.trace('Trace information')
30
+ ```
31
+
32
+ ## Log Levels
33
+
34
+ The logger supports five log levels in order of priority:
35
+
36
+ - `error` (0) - Highest priority
37
+ - `warn` (1)
38
+ - `info` (2)
39
+ - `debug` (3)
40
+ - `trace` (4) - Lowest priority
41
+
42
+ Only messages at or above the current log level will be output. For example, if the log level is set to `info`, then `error`, `warn`, and `info` messages will be logged, but `debug` and `trace` will be filtered out.
43
+
44
+ ```typescript
45
+ const logger = new StandardLogger('info')
46
+
47
+ logger.error('This will be logged') // ✓
48
+ logger.warn('This will be logged') // ✓
49
+ logger.info('This will be logged') // ✓
50
+ logger.debug('This will be filtered') // ✗
51
+ logger.trace('This will be filtered') // ✗
52
+ ```
53
+
54
+ ## Changing Log Level
55
+
56
+ ```typescript
57
+ const logger = new StandardLogger('error')
58
+
59
+ // Change the log level at runtime
60
+ logger.setLogLevel('debug')
61
+
62
+ // Invalid log levels throw an error
63
+ logger.setLogLevel('invalid') // throws Error: Invalid log level: invalid
64
+ ```
65
+
66
+ ## Structured Logging
67
+
68
+ The logger automatically creates structured JSON output with timestamps:
69
+
70
+ ```typescript
71
+ const logger = new StandardLogger('info')
72
+
73
+ logger.info('User logged in')
74
+ // Output: {"timestamp":"2023-10-01T12:00:00.000Z","level":"info","message":"User logged in"}
75
+ ```
76
+
77
+ ## Object Merging
78
+
79
+ Objects passed as arguments are merged into the log entry:
80
+
81
+ ```typescript
82
+ logger.info('User action', {
83
+ userId: 123,
84
+ action: 'login',
85
+ ip: '192.168.1.1'
86
+ })
87
+ // Output: {"timestamp":"2023-10-01T12:00:00.000Z","level":"info","message":"User action","userId":123,"action":"login","ip":"192.168.1.1"}
88
+ ```
89
+
90
+ ## Error Handling
91
+
92
+ Error objects are specially handled and added to an `errors` array:
93
+
94
+ ```typescript
95
+ const error = new Error('Database connection failed')
96
+
97
+ logger.error('Operation failed', error, { userId: 123 })
98
+ // Output: {
99
+ // "timestamp": "2023-10-01T12:00:00.000Z",
100
+ // "level": "error",
101
+ // "message": "Operation failed",
102
+ // "userId": 123,
103
+ // "errors": [{
104
+ // "name": "Error",
105
+ // "message": "Database connection failed",
106
+ // "stack": "Error: Database connection failed\n at ..."
107
+ // }]
108
+ // }
109
+ ```
110
+
111
+ ## Mixed Arguments
112
+
113
+ The logger handles mixed argument types intelligently:
114
+
115
+ ```typescript
116
+ logger.warn(
117
+ 'Processing user', // string message
118
+ { userId: 123 }, // object (merged)
119
+ 'with status', // string message
120
+ { status: 'active' }, // object (merged)
121
+ new Error('Minor issue') // error (in errors array)
122
+ )
123
+ // Output: {
124
+ // "timestamp": "2023-10-01T12:00:00.000Z",
125
+ // "level": "warn",
126
+ // "message": "Processing user with status",
127
+ // "userId": 123,
128
+ // "status": "active",
129
+ // "errors": [{"name": "Error", "message": "Minor issue", "stack": "..."}]
130
+ // }
131
+ ```
132
+
133
+ ## Advanced Examples
134
+
135
+ ### Application Logging
136
+
137
+ ```typescript
138
+ import { StandardLogger } from '@cloud-copilot/log'
139
+
140
+ class UserService {
141
+ private logger = new StandardLogger('info')
142
+
143
+ async createUser(userData: any) {
144
+ this.logger.info('Creating user', {
145
+ operation: 'createUser',
146
+ email: userData.email
147
+ })
148
+
149
+ try {
150
+ // ... user creation logic
151
+ this.logger.info('User created successfully', {
152
+ userId: newUser.id,
153
+ email: newUser.email
154
+ })
155
+ } catch (error) {
156
+ this.logger.error('Failed to create user', error, {
157
+ email: userData.email
158
+ })
159
+ throw error
160
+ }
161
+ }
162
+ }
163
+ ```
164
+
165
+ ### Environment-based Log Levels
166
+
167
+ ```typescript
168
+ const logLevel = process.env.LOG_LEVEL || 'warn'
169
+ const logger = new StandardLogger(logLevel as LogLevel)
170
+
171
+ // In production: LOG_LEVEL=error (only errors)
172
+ // In development: LOG_LEVEL=debug (detailed logging)
173
+ ```
174
+
175
+ ### Validating Log Levels
176
+
177
+ Use the `isLogLevel` utility function to validate log level strings:
178
+
179
+ ```typescript
180
+ import { isLogLevel } from '@cloud-copilot/log'
181
+
182
+ // Validate user input
183
+ const userInput = 'debug'
184
+ if (isLogLevel(userInput)) {
185
+ const logger = new StandardLogger(userInput)
186
+ } else {
187
+ console.error('Invalid log level provided')
188
+ }
189
+
190
+ // Safe environment variable parsing
191
+ const envLogLevel = process.env.LOG_LEVEL
192
+ const logLevel = isLogLevel(envLogLevel) ? envLogLevel : 'warn'
193
+ const logger = new StandardLogger(logLevel)
194
+
195
+ // Type guard in functions
196
+ function createLoggerFromConfig(config: { logLevel?: string }) {
197
+ if (config.logLevel && isLogLevel(config.logLevel)) {
198
+ return new StandardLogger(config.logLevel)
199
+ }
200
+ return new StandardLogger() // defaults to 'warn'
201
+ }
202
+ ```
203
+
204
+ ## TypeScript Support
205
+
206
+ Full TypeScript support with proper type definitions:
207
+
208
+ ```typescript
209
+ import { StandardLogger, LogLevel, LogLevels, isLogLevel } from '@cloud-copilot/log'
210
+
211
+ const logger: StandardLogger = new StandardLogger()
212
+ const level: LogLevel = 'info'
213
+ const isValid: boolean = isLogLevel('debug') // true
214
+ ```
@@ -0,0 +1,2 @@
1
+ export { isLogLevel, StandardLogger, type LogLevel } from './log';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAA"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StandardLogger = exports.isLogLevel = void 0;
4
+ var log_1 = require("./log");
5
+ Object.defineProperty(exports, "isLogLevel", { enumerable: true, get: function () { return log_1.isLogLevel; } });
6
+ Object.defineProperty(exports, "StandardLogger", { enumerable: true, get: function () { return log_1.StandardLogger; } });
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,6BAAiE;AAAxD,iGAAA,UAAU,OAAA;AAAE,qGAAA,cAAc,OAAA"}
@@ -0,0 +1,28 @@
1
+ export declare const LogLevels: readonly ["error", "warn", "info", "debug", "trace"];
2
+ export type LogLevel = (typeof LogLevels)[number];
3
+ /**
4
+ * Determine if a string is a valid log level.
5
+ *
6
+ * @param level the log level string to check
7
+ * @returns true if the string is a valid log level, false otherwise
8
+ */
9
+ export declare function isLogLevel(level: string | LogLevel): level is LogLevel;
10
+ interface Logger {
11
+ error: (...args: unknown[]) => void;
12
+ warn: (...args: unknown[]) => void;
13
+ info: (...args: unknown[]) => void;
14
+ debug: (...args: unknown[]) => void;
15
+ trace: (...args: unknown[]) => void;
16
+ }
17
+ export declare class StandardLogger implements Logger {
18
+ private logLevel;
19
+ constructor(initialLogLevel?: LogLevel);
20
+ setLogLevel(level: LogLevel): void;
21
+ error(...args: unknown[]): void;
22
+ warn(...args: unknown[]): void;
23
+ info(...args: unknown[]): void;
24
+ debug(...args: unknown[]): void;
25
+ trace(...args: unknown[]): void;
26
+ }
27
+ export {};
28
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/log.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,sDAAuD,CAAA;AAE7E,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAA;AAUjD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,IAAI,QAAQ,CAEtE;AAED,UAAU,MAAM;IACd,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACnC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACnC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;CACpC;AAED,qBAAa,cAAe,YAAW,MAAM;IAC3C,OAAO,CAAC,QAAQ,CAAU;gBAEd,eAAe,CAAC,EAAE,QAAQ;IAQtC,WAAW,CAAC,KAAK,EAAE,QAAQ;IAO3B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAGxB,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAGvB,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAGvB,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAGxB,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;CAGzB"}
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StandardLogger = exports.LogLevels = void 0;
4
+ exports.isLogLevel = isLogLevel;
5
+ exports.LogLevels = ['error', 'warn', 'info', 'debug', 'trace'];
6
+ const LEVELS = {
7
+ error: 0,
8
+ warn: 1,
9
+ info: 2,
10
+ debug: 3,
11
+ trace: 4
12
+ };
13
+ /**
14
+ * Determine if a string is a valid log level.
15
+ *
16
+ * @param level the log level string to check
17
+ * @returns true if the string is a valid log level, false otherwise
18
+ */
19
+ function isLogLevel(level) {
20
+ return level !== undefined && LEVELS.hasOwnProperty(level);
21
+ }
22
+ class StandardLogger {
23
+ logLevel;
24
+ constructor(initialLogLevel) {
25
+ if (initialLogLevel && isLogLevel(initialLogLevel)) {
26
+ this.logLevel = initialLogLevel;
27
+ }
28
+ else {
29
+ this.logLevel = 'warn';
30
+ }
31
+ }
32
+ setLogLevel(level) {
33
+ if (!isLogLevel(level)) {
34
+ throw new Error(`Invalid log level: ${level}`);
35
+ }
36
+ this.logLevel = level;
37
+ }
38
+ error(...args) {
39
+ logAt(this.logLevel, 'error', args);
40
+ }
41
+ warn(...args) {
42
+ logAt(this.logLevel, 'warn', args);
43
+ }
44
+ info(...args) {
45
+ logAt(this.logLevel, 'info', args);
46
+ }
47
+ debug(...args) {
48
+ logAt(this.logLevel, 'debug', args);
49
+ }
50
+ trace(...args) {
51
+ logAt(this.logLevel, 'trace', args);
52
+ }
53
+ }
54
+ exports.StandardLogger = StandardLogger;
55
+ // helper to serialize non-object args into a single string
56
+ function serializeArgs(args) {
57
+ return args
58
+ .map((a) => typeof a === 'string'
59
+ ? a
60
+ : a instanceof Error
61
+ ? a.stack || a.message
62
+ : a === undefined
63
+ ? 'undefined'
64
+ : JSON.stringify(a))
65
+ .join(' ');
66
+ }
67
+ function isError(obj) {
68
+ return (obj instanceof Error ||
69
+ (typeof obj === 'object' && obj !== null && 'message' in obj && 'name' in obj));
70
+ }
71
+ // core log function: level check → prefix → JSON output
72
+ function logAt(currentLevel, level, args) {
73
+ if (LEVELS[level] > LEVELS[currentLevel])
74
+ return;
75
+ // Base log entry
76
+ const entry = {
77
+ timestamp: new Date().toISOString(),
78
+ level
79
+ };
80
+ // Separate object args and message args
81
+ const objectArgs = args.filter((a) => typeof a === 'object' && a !== null && !isError(a));
82
+ const messageArgs = args.filter((a) => typeof a !== 'object' || a === null);
83
+ const errorArgs = args.filter(isError);
84
+ // Merge all object arguments into the entry
85
+ for (const obj of objectArgs) {
86
+ Object.assign(entry, obj);
87
+ }
88
+ const msg = serializeArgs(messageArgs);
89
+ if (msg) {
90
+ entry.message = msg;
91
+ }
92
+ if (errorArgs.length > 0) {
93
+ entry.errors = errorArgs.map((e) => ({
94
+ name: e.name,
95
+ message: e.message,
96
+ stack: e.stack
97
+ }));
98
+ }
99
+ const line = JSON.stringify(entry);
100
+ switch (level) {
101
+ case 'error':
102
+ return console.error(line);
103
+ case 'warn':
104
+ return console.warn(line);
105
+ case 'info':
106
+ return console.info(line);
107
+ default:
108
+ return console.log(line);
109
+ }
110
+ }
111
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/log.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,2 @@
1
+ export { isLogLevel, StandardLogger, type LogLevel } from './log';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAA"}
@@ -0,0 +1,2 @@
1
+ export { isLogLevel, StandardLogger } from './log';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAiB,MAAM,OAAO,CAAA"}
@@ -0,0 +1,28 @@
1
+ export declare const LogLevels: readonly ["error", "warn", "info", "debug", "trace"];
2
+ export type LogLevel = (typeof LogLevels)[number];
3
+ /**
4
+ * Determine if a string is a valid log level.
5
+ *
6
+ * @param level the log level string to check
7
+ * @returns true if the string is a valid log level, false otherwise
8
+ */
9
+ export declare function isLogLevel(level: string | LogLevel): level is LogLevel;
10
+ interface Logger {
11
+ error: (...args: unknown[]) => void;
12
+ warn: (...args: unknown[]) => void;
13
+ info: (...args: unknown[]) => void;
14
+ debug: (...args: unknown[]) => void;
15
+ trace: (...args: unknown[]) => void;
16
+ }
17
+ export declare class StandardLogger implements Logger {
18
+ private logLevel;
19
+ constructor(initialLogLevel?: LogLevel);
20
+ setLogLevel(level: LogLevel): void;
21
+ error(...args: unknown[]): void;
22
+ warn(...args: unknown[]): void;
23
+ info(...args: unknown[]): void;
24
+ debug(...args: unknown[]): void;
25
+ trace(...args: unknown[]): void;
26
+ }
27
+ export {};
28
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/log.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,sDAAuD,CAAA;AAE7E,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAA;AAUjD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,IAAI,QAAQ,CAEtE;AAED,UAAU,MAAM;IACd,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACnC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACnC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;CACpC;AAED,qBAAa,cAAe,YAAW,MAAM;IAC3C,OAAO,CAAC,QAAQ,CAAU;gBAEd,eAAe,CAAC,EAAE,QAAQ;IAQtC,WAAW,CAAC,KAAK,EAAE,QAAQ;IAO3B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAGxB,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAGvB,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAGvB,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAGxB,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;CAGzB"}
@@ -0,0 +1,105 @@
1
+ export const LogLevels = ['error', 'warn', 'info', 'debug', 'trace'];
2
+ const LEVELS = {
3
+ error: 0,
4
+ warn: 1,
5
+ info: 2,
6
+ debug: 3,
7
+ trace: 4
8
+ };
9
+ /**
10
+ * Determine if a string is a valid log level.
11
+ *
12
+ * @param level the log level string to check
13
+ * @returns true if the string is a valid log level, false otherwise
14
+ */
15
+ export function isLogLevel(level) {
16
+ return level !== undefined && LEVELS.hasOwnProperty(level);
17
+ }
18
+ export class StandardLogger {
19
+ constructor(initialLogLevel) {
20
+ if (initialLogLevel && isLogLevel(initialLogLevel)) {
21
+ this.logLevel = initialLogLevel;
22
+ }
23
+ else {
24
+ this.logLevel = 'warn';
25
+ }
26
+ }
27
+ setLogLevel(level) {
28
+ if (!isLogLevel(level)) {
29
+ throw new Error(`Invalid log level: ${level}`);
30
+ }
31
+ this.logLevel = level;
32
+ }
33
+ error(...args) {
34
+ logAt(this.logLevel, 'error', args);
35
+ }
36
+ warn(...args) {
37
+ logAt(this.logLevel, 'warn', args);
38
+ }
39
+ info(...args) {
40
+ logAt(this.logLevel, 'info', args);
41
+ }
42
+ debug(...args) {
43
+ logAt(this.logLevel, 'debug', args);
44
+ }
45
+ trace(...args) {
46
+ logAt(this.logLevel, 'trace', args);
47
+ }
48
+ }
49
+ // helper to serialize non-object args into a single string
50
+ function serializeArgs(args) {
51
+ return args
52
+ .map((a) => typeof a === 'string'
53
+ ? a
54
+ : a instanceof Error
55
+ ? a.stack || a.message
56
+ : a === undefined
57
+ ? 'undefined'
58
+ : JSON.stringify(a))
59
+ .join(' ');
60
+ }
61
+ function isError(obj) {
62
+ return (obj instanceof Error ||
63
+ (typeof obj === 'object' && obj !== null && 'message' in obj && 'name' in obj));
64
+ }
65
+ // core log function: level check → prefix → JSON output
66
+ function logAt(currentLevel, level, args) {
67
+ if (LEVELS[level] > LEVELS[currentLevel])
68
+ return;
69
+ // Base log entry
70
+ const entry = {
71
+ timestamp: new Date().toISOString(),
72
+ level
73
+ };
74
+ // Separate object args and message args
75
+ const objectArgs = args.filter((a) => typeof a === 'object' && a !== null && !isError(a));
76
+ const messageArgs = args.filter((a) => typeof a !== 'object' || a === null);
77
+ const errorArgs = args.filter(isError);
78
+ // Merge all object arguments into the entry
79
+ for (const obj of objectArgs) {
80
+ Object.assign(entry, obj);
81
+ }
82
+ const msg = serializeArgs(messageArgs);
83
+ if (msg) {
84
+ entry.message = msg;
85
+ }
86
+ if (errorArgs.length > 0) {
87
+ entry.errors = errorArgs.map((e) => ({
88
+ name: e.name,
89
+ message: e.message,
90
+ stack: e.stack
91
+ }));
92
+ }
93
+ const line = JSON.stringify(entry);
94
+ switch (level) {
95
+ case 'error':
96
+ return console.error(line);
97
+ case 'warn':
98
+ return console.warn(line);
99
+ case 'info':
100
+ return console.info(line);
101
+ default:
102
+ return console.log(line);
103
+ }
104
+ }
105
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/log.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
package/package.json ADDED
@@ -0,0 +1,108 @@
1
+ {
2
+ "name": "@cloud-copilot/log",
3
+ "version": "0.1.0",
4
+ "description": "A lightweight JSON logger",
5
+ "keywords": [
6
+ "typescript",
7
+ "logging"
8
+ ],
9
+ "homepage": "https://github.com/cloud-copilot/log#readme",
10
+ "bugs": {
11
+ "url": "https://github.com/cloud-copilot/log/issues"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/cloud-copilot/log.git"
16
+ },
17
+ "exports": {
18
+ ".": {
19
+ "import": "./dist/esm/index.js",
20
+ "require": "./dist/cjs/index.js"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist/**/*"
25
+ ],
26
+ "types": "dist/cjs/index.d.ts",
27
+ "license": "MIT",
28
+ "author": "David Kerber <dave@cloudcopilot.io>",
29
+ "main": "dist/esm/index.js",
30
+ "scripts": {
31
+ "build": "npx tsc -p tsconfig.cjs.json && npx tsc -p tsconfig.esm.json && ./postbuild.sh",
32
+ "clean": "rm -rf dist",
33
+ "test": "npx vitest --run --coverage",
34
+ "release": "npm install && npm run clean && npm run build && npm test && npm run format-check && npm publish",
35
+ "format": "npx prettier --write src/",
36
+ "format-check": "npx prettier --check src/"
37
+ },
38
+ "devDependencies": {
39
+ "@cloud-copilot/prettier-config": "^0.1.0",
40
+ "@semantic-release/changelog": "^6.0.3",
41
+ "@semantic-release/commit-analyzer": "^13.0.1",
42
+ "@semantic-release/git": "^10.0.1",
43
+ "@semantic-release/github": "^11.0.1",
44
+ "@semantic-release/npm": "^12.0.1",
45
+ "@semantic-release/release-notes-generator": "^14.0.3",
46
+ "@types/node": "^22.5.0",
47
+ "@vitest/coverage-v8": "^3.0.7",
48
+ "semantic-release": "^24.2.1",
49
+ "typescript": "^5.7.2",
50
+ "vitest": "^3.0.7"
51
+ },
52
+ "prettier": "@cloud-copilot/prettier-config",
53
+ "release": {
54
+ "branches": [
55
+ "main"
56
+ ],
57
+ "plugins": [
58
+ [
59
+ "@semantic-release/commit-analyzer",
60
+ {
61
+ "releaseRules": [
62
+ {
63
+ "type": "feat",
64
+ "release": "patch"
65
+ },
66
+ {
67
+ "type": "fix",
68
+ "release": "patch"
69
+ },
70
+ {
71
+ "breaking": true,
72
+ "release": "patch"
73
+ },
74
+ {
75
+ "type": "*",
76
+ "release": "patch"
77
+ }
78
+ ]
79
+ }
80
+ ],
81
+ "@semantic-release/release-notes-generator",
82
+ "@semantic-release/changelog",
83
+ [
84
+ "@semantic-release/npm",
85
+ {
86
+ "npmPublish": true
87
+ }
88
+ ],
89
+ [
90
+ "@semantic-release/git",
91
+ {
92
+ "assets": [
93
+ "package.json",
94
+ "package-lock.json",
95
+ "CHANGELOG.md"
96
+ ],
97
+ "message": "chore(release): ${nextRelease.version} [skip ci]"
98
+ }
99
+ ],
100
+ [
101
+ "@semantic-release/github",
102
+ {
103
+ "assets": []
104
+ }
105
+ ]
106
+ ]
107
+ }
108
+ }