@enactprotocol/shared 1.2.13 → 2.0.1

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 (207) hide show
  1. package/README.md +44 -0
  2. package/dist/config.d.ts +164 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +386 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/constants.d.ts +15 -5
  7. package/dist/constants.d.ts.map +1 -0
  8. package/dist/constants.js +24 -8
  9. package/dist/constants.js.map +1 -0
  10. package/dist/execution/command.d.ts +102 -0
  11. package/dist/execution/command.d.ts.map +1 -0
  12. package/dist/execution/command.js +262 -0
  13. package/dist/execution/command.js.map +1 -0
  14. package/dist/execution/index.d.ts +12 -0
  15. package/dist/execution/index.d.ts.map +1 -0
  16. package/dist/execution/index.js +17 -0
  17. package/dist/execution/index.js.map +1 -0
  18. package/dist/execution/runtime.d.ts +82 -0
  19. package/dist/execution/runtime.d.ts.map +1 -0
  20. package/dist/execution/runtime.js +273 -0
  21. package/dist/execution/runtime.js.map +1 -0
  22. package/dist/execution/types.d.ts +306 -0
  23. package/dist/execution/types.d.ts.map +1 -0
  24. package/dist/execution/types.js +14 -0
  25. package/dist/execution/types.js.map +1 -0
  26. package/dist/execution/validation.d.ts +43 -0
  27. package/dist/execution/validation.d.ts.map +1 -0
  28. package/dist/execution/validation.js +430 -0
  29. package/dist/execution/validation.js.map +1 -0
  30. package/dist/index.d.ts +21 -21
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +49 -25
  33. package/dist/index.js.map +1 -0
  34. package/dist/manifest/index.d.ts +7 -0
  35. package/dist/manifest/index.d.ts.map +1 -0
  36. package/dist/manifest/index.js +10 -0
  37. package/dist/manifest/index.js.map +1 -0
  38. package/dist/manifest/loader.d.ts +76 -0
  39. package/dist/manifest/loader.d.ts.map +1 -0
  40. package/dist/manifest/loader.js +146 -0
  41. package/dist/manifest/loader.js.map +1 -0
  42. package/dist/manifest/parser.d.ts +64 -0
  43. package/dist/manifest/parser.d.ts.map +1 -0
  44. package/dist/manifest/parser.js +135 -0
  45. package/dist/manifest/parser.js.map +1 -0
  46. package/dist/manifest/validator.d.ts +95 -0
  47. package/dist/manifest/validator.d.ts.map +1 -0
  48. package/dist/manifest/validator.js +258 -0
  49. package/dist/manifest/validator.js.map +1 -0
  50. package/dist/paths.d.ts +57 -0
  51. package/dist/paths.d.ts.map +1 -0
  52. package/dist/paths.js +93 -0
  53. package/dist/paths.js.map +1 -0
  54. package/dist/registry.d.ts +73 -0
  55. package/dist/registry.d.ts.map +1 -0
  56. package/dist/registry.js +147 -0
  57. package/dist/registry.js.map +1 -0
  58. package/dist/resolver.d.ts +89 -0
  59. package/dist/resolver.d.ts.map +1 -0
  60. package/dist/resolver.js +282 -0
  61. package/dist/resolver.js.map +1 -0
  62. package/dist/types/index.d.ts +6 -0
  63. package/dist/types/index.d.ts.map +1 -0
  64. package/dist/types/index.js +5 -0
  65. package/dist/types/index.js.map +1 -0
  66. package/dist/types/manifest.d.ts +201 -0
  67. package/dist/types/manifest.d.ts.map +1 -0
  68. package/dist/types/manifest.js +13 -0
  69. package/dist/types/manifest.js.map +1 -0
  70. package/dist/types.d.ts +5 -132
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +5 -3
  73. package/dist/types.js.map +1 -0
  74. package/dist/utils/fs.d.ts +105 -0
  75. package/dist/utils/fs.d.ts.map +1 -0
  76. package/dist/utils/fs.js +233 -0
  77. package/dist/utils/fs.js.map +1 -0
  78. package/dist/utils/logger.d.ts +102 -25
  79. package/dist/utils/logger.d.ts.map +1 -0
  80. package/dist/utils/logger.js +214 -57
  81. package/dist/utils/logger.js.map +1 -0
  82. package/dist/utils/version.d.ts +60 -2
  83. package/dist/utils/version.d.ts.map +1 -0
  84. package/dist/utils/version.js +255 -31
  85. package/dist/utils/version.js.map +1 -0
  86. package/package.json +16 -58
  87. package/src/config.ts +510 -0
  88. package/src/constants.ts +36 -0
  89. package/src/execution/command.ts +314 -0
  90. package/src/execution/index.ts +73 -0
  91. package/src/execution/runtime.ts +308 -0
  92. package/src/execution/types.ts +379 -0
  93. package/src/execution/validation.ts +508 -0
  94. package/src/index.ts +238 -30
  95. package/src/manifest/index.ts +36 -0
  96. package/src/manifest/loader.ts +187 -0
  97. package/src/manifest/parser.ts +173 -0
  98. package/src/manifest/validator.ts +309 -0
  99. package/src/paths.ts +108 -0
  100. package/src/registry.ts +219 -0
  101. package/src/resolver.ts +345 -0
  102. package/src/types/index.ts +30 -0
  103. package/src/types/manifest.ts +255 -0
  104. package/src/types.ts +5 -188
  105. package/src/utils/fs.ts +281 -0
  106. package/src/utils/logger.ts +270 -59
  107. package/src/utils/version.ts +304 -36
  108. package/tests/config.test.ts +515 -0
  109. package/tests/execution/command.test.ts +317 -0
  110. package/tests/execution/validation.test.ts +384 -0
  111. package/tests/fixtures/invalid-tool.yaml +4 -0
  112. package/tests/fixtures/valid-tool.md +62 -0
  113. package/tests/fixtures/valid-tool.yaml +40 -0
  114. package/tests/index.test.ts +8 -0
  115. package/tests/manifest/loader.test.ts +291 -0
  116. package/tests/manifest/parser.test.ts +345 -0
  117. package/tests/manifest/validator.test.ts +394 -0
  118. package/tests/manifest-types.test.ts +358 -0
  119. package/tests/paths.test.ts +153 -0
  120. package/tests/registry.test.ts +231 -0
  121. package/tests/resolver.test.ts +272 -0
  122. package/tests/utils/fs.test.ts +388 -0
  123. package/tests/utils/logger.test.ts +480 -0
  124. package/tests/utils/version.test.ts +390 -0
  125. package/tsconfig.json +12 -0
  126. package/dist/LocalToolResolver.d.ts +0 -84
  127. package/dist/LocalToolResolver.js +0 -353
  128. package/dist/api/enact-api.d.ts +0 -130
  129. package/dist/api/enact-api.js +0 -428
  130. package/dist/api/index.d.ts +0 -2
  131. package/dist/api/index.js +0 -2
  132. package/dist/api/types.d.ts +0 -103
  133. package/dist/api/types.js +0 -1
  134. package/dist/core/DaggerExecutionProvider.d.ts +0 -169
  135. package/dist/core/DaggerExecutionProvider.js +0 -1029
  136. package/dist/core/DirectExecutionProvider.d.ts +0 -23
  137. package/dist/core/DirectExecutionProvider.js +0 -406
  138. package/dist/core/EnactCore.d.ts +0 -162
  139. package/dist/core/EnactCore.js +0 -597
  140. package/dist/core/NativeExecutionProvider.d.ts +0 -9
  141. package/dist/core/NativeExecutionProvider.js +0 -16
  142. package/dist/core/index.d.ts +0 -3
  143. package/dist/core/index.js +0 -3
  144. package/dist/exec/index.d.ts +0 -3
  145. package/dist/exec/index.js +0 -3
  146. package/dist/exec/logger.d.ts +0 -11
  147. package/dist/exec/logger.js +0 -57
  148. package/dist/exec/validate.d.ts +0 -5
  149. package/dist/exec/validate.js +0 -167
  150. package/dist/lib/enact-direct.d.ts +0 -150
  151. package/dist/lib/enact-direct.js +0 -159
  152. package/dist/lib/index.d.ts +0 -1
  153. package/dist/lib/index.js +0 -1
  154. package/dist/security/index.d.ts +0 -3
  155. package/dist/security/index.js +0 -3
  156. package/dist/security/security.d.ts +0 -23
  157. package/dist/security/security.js +0 -137
  158. package/dist/security/sign.d.ts +0 -103
  159. package/dist/security/sign.js +0 -666
  160. package/dist/security/verification-enforcer.d.ts +0 -53
  161. package/dist/security/verification-enforcer.js +0 -204
  162. package/dist/services/McpCoreService.d.ts +0 -98
  163. package/dist/services/McpCoreService.js +0 -124
  164. package/dist/services/index.d.ts +0 -1
  165. package/dist/services/index.js +0 -1
  166. package/dist/utils/config.d.ts +0 -111
  167. package/dist/utils/config.js +0 -342
  168. package/dist/utils/env-loader.d.ts +0 -54
  169. package/dist/utils/env-loader.js +0 -270
  170. package/dist/utils/help.d.ts +0 -36
  171. package/dist/utils/help.js +0 -248
  172. package/dist/utils/index.d.ts +0 -7
  173. package/dist/utils/index.js +0 -7
  174. package/dist/utils/silent-monitor.d.ts +0 -67
  175. package/dist/utils/silent-monitor.js +0 -242
  176. package/dist/utils/timeout.d.ts +0 -5
  177. package/dist/utils/timeout.js +0 -23
  178. package/dist/web/env-manager-server.d.ts +0 -29
  179. package/dist/web/env-manager-server.js +0 -367
  180. package/dist/web/index.d.ts +0 -1
  181. package/dist/web/index.js +0 -1
  182. package/src/LocalToolResolver.ts +0 -424
  183. package/src/api/enact-api.ts +0 -604
  184. package/src/api/index.ts +0 -2
  185. package/src/api/types.ts +0 -114
  186. package/src/core/DaggerExecutionProvider.ts +0 -1357
  187. package/src/core/DirectExecutionProvider.ts +0 -484
  188. package/src/core/EnactCore.ts +0 -847
  189. package/src/core/index.ts +0 -3
  190. package/src/exec/index.ts +0 -3
  191. package/src/exec/logger.ts +0 -63
  192. package/src/exec/validate.ts +0 -238
  193. package/src/lib/enact-direct.ts +0 -254
  194. package/src/lib/index.ts +0 -1
  195. package/src/services/McpCoreService.ts +0 -201
  196. package/src/services/index.ts +0 -1
  197. package/src/utils/config.ts +0 -438
  198. package/src/utils/env-loader.ts +0 -370
  199. package/src/utils/help.ts +0 -257
  200. package/src/utils/index.ts +0 -7
  201. package/src/utils/silent-monitor.ts +0 -328
  202. package/src/utils/timeout.ts +0 -26
  203. package/src/web/env-manager-server.ts +0 -465
  204. package/src/web/index.ts +0 -1
  205. package/src/web/static/app.js +0 -663
  206. package/src/web/static/index.html +0 -117
  207. package/src/web/static/style.css +0 -291
@@ -0,0 +1,480 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Logger, configureLogger, createLogger, getLogger } from "../../src/utils/logger";
3
+
4
+ /** Helper to parse JSON from output array */
5
+ function parseOutput(output: string[], index: number): Record<string, unknown> {
6
+ const item = output[index];
7
+ if (item === undefined) {
8
+ throw new Error(`No output at index ${index}`);
9
+ }
10
+ return JSON.parse(item) as Record<string, unknown>;
11
+ }
12
+
13
+ /** Helper to get output at index */
14
+ function getOutput(output: string[], index: number): string {
15
+ const item = output[index];
16
+ if (item === undefined) {
17
+ throw new Error(`No output at index ${index}`);
18
+ }
19
+ return item;
20
+ }
21
+
22
+ describe("Logger", () => {
23
+ describe("constructor and options", () => {
24
+ test("creates logger with default options", () => {
25
+ const logger = new Logger();
26
+ expect(logger.getLevel()).toBe("info");
27
+ });
28
+
29
+ test("creates logger with custom level", () => {
30
+ const logger = new Logger({ level: "debug" });
31
+ expect(logger.getLevel()).toBe("debug");
32
+ });
33
+
34
+ test("creates logger with custom format", () => {
35
+ const output: string[] = [];
36
+ const logger = new Logger({
37
+ format: "json",
38
+ output: (text) => output.push(text),
39
+ });
40
+ logger.info("test");
41
+ expect(output.length).toBe(1);
42
+ const parsed = parseOutput(output, 0);
43
+ expect(parsed.level).toBe("info");
44
+ expect(parsed.message).toBe("test");
45
+ });
46
+
47
+ test("creates logger with prefix", () => {
48
+ const output: string[] = [];
49
+ const logger = new Logger({
50
+ prefix: "MyModule",
51
+ format: "json",
52
+ output: (text) => output.push(text),
53
+ });
54
+ logger.info("test");
55
+ const parsed = parseOutput(output, 0);
56
+ expect(parsed.message).toBe("[MyModule] test");
57
+ });
58
+ });
59
+
60
+ describe("level filtering", () => {
61
+ test("logs messages at or above current level", () => {
62
+ const output: string[] = [];
63
+ const logger = new Logger({
64
+ level: "warn",
65
+ format: "json",
66
+ output: (text) => output.push(text),
67
+ errorOutput: (text) => output.push(text),
68
+ });
69
+
70
+ logger.debug("debug msg");
71
+ logger.info("info msg");
72
+ logger.warn("warn msg");
73
+ logger.error("error msg");
74
+
75
+ expect(output.length).toBe(2); // only warn and error
76
+ expect(getOutput(output, 0)).toContain("warn msg");
77
+ expect(getOutput(output, 1)).toContain("error msg");
78
+ });
79
+
80
+ test("silent level suppresses all output", () => {
81
+ const output: string[] = [];
82
+ const logger = new Logger({
83
+ level: "silent",
84
+ output: (text) => output.push(text),
85
+ errorOutput: (text) => output.push(text),
86
+ });
87
+
88
+ logger.debug("debug");
89
+ logger.info("info");
90
+ logger.warn("warn");
91
+ logger.error("error");
92
+
93
+ expect(output.length).toBe(0);
94
+ });
95
+
96
+ test("debug level logs everything", () => {
97
+ const output: string[] = [];
98
+ const logger = new Logger({
99
+ level: "debug",
100
+ format: "json",
101
+ output: (text) => output.push(text),
102
+ errorOutput: (text) => output.push(text),
103
+ });
104
+
105
+ logger.debug("debug");
106
+ logger.info("info");
107
+ logger.warn("warn");
108
+ logger.error("error");
109
+
110
+ expect(output.length).toBe(4);
111
+ });
112
+
113
+ test("setLevel changes filtering", () => {
114
+ const output: string[] = [];
115
+ const logger = new Logger({
116
+ level: "info",
117
+ format: "json",
118
+ output: (text) => output.push(text),
119
+ errorOutput: (text) => output.push(text),
120
+ });
121
+
122
+ logger.debug("should not appear");
123
+ expect(output.length).toBe(0);
124
+
125
+ logger.setLevel("debug");
126
+ logger.debug("should appear");
127
+ expect(output.length).toBe(1);
128
+ });
129
+
130
+ test("shouldLog returns correct boolean", () => {
131
+ const logger = new Logger({ level: "warn" });
132
+ expect(logger.shouldLog("debug")).toBe(false);
133
+ expect(logger.shouldLog("info")).toBe(false);
134
+ expect(logger.shouldLog("warn")).toBe(true);
135
+ expect(logger.shouldLog("error")).toBe(true);
136
+ });
137
+ });
138
+
139
+ describe("output formats", () => {
140
+ test("JSON format outputs valid JSON", () => {
141
+ const output: string[] = [];
142
+ const logger = new Logger({
143
+ format: "json",
144
+ output: (text) => output.push(text),
145
+ });
146
+
147
+ logger.info("test message");
148
+
149
+ const parsed = parseOutput(output, 0);
150
+ expect(parsed.level).toBe("info");
151
+ expect(parsed.message).toBe("test message");
152
+ expect(parsed.timestamp).toBeDefined();
153
+ });
154
+
155
+ test("JSON format includes context", () => {
156
+ const output: string[] = [];
157
+ const logger = new Logger({
158
+ format: "json",
159
+ output: (text) => output.push(text),
160
+ });
161
+
162
+ logger.info("test", { userId: 123, action: "login" });
163
+
164
+ const parsed = parseOutput(output, 0);
165
+ expect(parsed.context).toEqual({ userId: 123, action: "login" });
166
+ });
167
+
168
+ test("JSON format omits empty context", () => {
169
+ const output: string[] = [];
170
+ const logger = new Logger({
171
+ format: "json",
172
+ output: (text) => output.push(text),
173
+ });
174
+
175
+ logger.info("test");
176
+
177
+ const parsed = parseOutput(output, 0);
178
+ expect(parsed.context).toBeUndefined();
179
+ });
180
+
181
+ test("console format includes timestamp and level", () => {
182
+ const output: string[] = [];
183
+ const logger = new Logger({
184
+ format: "console",
185
+ colors: false,
186
+ output: (text) => output.push(text),
187
+ });
188
+
189
+ logger.info("test message");
190
+
191
+ const out = getOutput(output, 0);
192
+ expect(out).toContain("INFO");
193
+ expect(out).toContain("test message");
194
+ // Should have ISO timestamp
195
+ expect(out).toMatch(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);
196
+ });
197
+
198
+ test("console format with colors includes ANSI codes", () => {
199
+ const output: string[] = [];
200
+ const logger = new Logger({
201
+ format: "console",
202
+ colors: true,
203
+ output: (text) => output.push(text),
204
+ });
205
+
206
+ logger.info("test");
207
+
208
+ // Should contain ANSI escape codes
209
+ expect(getOutput(output, 0)).toContain("\x1b[");
210
+ });
211
+
212
+ test("console format without colors has no ANSI codes", () => {
213
+ const output: string[] = [];
214
+ const logger = new Logger({
215
+ format: "console",
216
+ colors: false,
217
+ output: (text) => output.push(text),
218
+ });
219
+
220
+ logger.info("test");
221
+
222
+ expect(getOutput(output, 0)).not.toContain("\x1b[");
223
+ });
224
+
225
+ test("setFormat changes output format", () => {
226
+ const output: string[] = [];
227
+ const logger = new Logger({
228
+ format: "console",
229
+ colors: false,
230
+ output: (text) => output.push(text),
231
+ });
232
+
233
+ logger.info("console");
234
+ logger.setFormat("json");
235
+ logger.info("json");
236
+
237
+ // First message is console format (not valid JSON)
238
+ expect(() => JSON.parse(getOutput(output, 0))).toThrow();
239
+ // Second message is JSON
240
+ expect(parseOutput(output, 1).message).toBe("json");
241
+ });
242
+
243
+ test("setColors enables/disables colors", () => {
244
+ const output: string[] = [];
245
+ const logger = new Logger({
246
+ format: "console",
247
+ colors: true,
248
+ output: (text) => output.push(text),
249
+ });
250
+
251
+ logger.info("with colors");
252
+ logger.setColors(false);
253
+ logger.info("no colors");
254
+
255
+ expect(getOutput(output, 0)).toContain("\x1b[");
256
+ expect(getOutput(output, 1)).not.toContain("\x1b[");
257
+ });
258
+ });
259
+
260
+ describe("error output routing", () => {
261
+ test("warn and error use errorOutput", () => {
262
+ const stdout: string[] = [];
263
+ const stderr: string[] = [];
264
+ const logger = new Logger({
265
+ level: "debug",
266
+ format: "json",
267
+ output: (text) => stdout.push(text),
268
+ errorOutput: (text) => stderr.push(text),
269
+ });
270
+
271
+ logger.debug("debug");
272
+ logger.info("info");
273
+ logger.warn("warn");
274
+ logger.error("error");
275
+
276
+ expect(stdout.length).toBe(2); // debug, info
277
+ expect(stderr.length).toBe(2); // warn, error
278
+ });
279
+ });
280
+
281
+ describe("child loggers", () => {
282
+ test("child logger inherits settings", () => {
283
+ const output: string[] = [];
284
+ const parent = new Logger({
285
+ level: "debug",
286
+ format: "json",
287
+ output: (text) => output.push(text),
288
+ });
289
+
290
+ const child = parent.child("SubModule");
291
+ child.info("test");
292
+
293
+ const parsed = parseOutput(output, 0);
294
+ expect(parsed.message).toBe("[SubModule] test");
295
+ });
296
+
297
+ test("child logger chains prefixes", () => {
298
+ const output: string[] = [];
299
+ const parent = new Logger({
300
+ level: "debug",
301
+ format: "json",
302
+ prefix: "Parent",
303
+ output: (text) => output.push(text),
304
+ });
305
+
306
+ const child = parent.child("Child");
307
+ child.info("test");
308
+
309
+ const parsed = parseOutput(output, 0);
310
+ expect(parsed.message).toBe("[Parent:Child] test");
311
+ });
312
+
313
+ test("setPrefix changes prefix", () => {
314
+ const output: string[] = [];
315
+ const logger = new Logger({
316
+ format: "json",
317
+ output: (text) => output.push(text),
318
+ });
319
+
320
+ logger.info("no prefix");
321
+ logger.setPrefix("NewPrefix");
322
+ logger.info("with prefix");
323
+
324
+ const msg1 = parseOutput(output, 0).message;
325
+ const msg2 = parseOutput(output, 1).message;
326
+ expect(msg1).toBe("no prefix");
327
+ expect(msg2).toBe("[NewPrefix] with prefix");
328
+ });
329
+ });
330
+
331
+ describe("structured context", () => {
332
+ test("context is included in JSON output", () => {
333
+ const output: string[] = [];
334
+ const logger = new Logger({
335
+ format: "json",
336
+ output: (text) => output.push(text),
337
+ });
338
+
339
+ logger.info("user action", {
340
+ userId: "u123",
341
+ action: "login",
342
+ success: true,
343
+ duration: 150,
344
+ });
345
+
346
+ const parsed = parseOutput(output, 0);
347
+ expect(parsed.context).toEqual({
348
+ userId: "u123",
349
+ action: "login",
350
+ success: true,
351
+ duration: 150,
352
+ });
353
+ });
354
+
355
+ test("context is included in console output", () => {
356
+ const output: string[] = [];
357
+ const logger = new Logger({
358
+ format: "console",
359
+ colors: false,
360
+ output: (text) => output.push(text),
361
+ });
362
+
363
+ logger.info("test", { key: "value" });
364
+
365
+ expect(getOutput(output, 0)).toContain('{"key":"value"}');
366
+ });
367
+
368
+ test("nested context is supported", () => {
369
+ const output: string[] = [];
370
+ const logger = new Logger({
371
+ format: "json",
372
+ output: (text) => output.push(text),
373
+ });
374
+
375
+ logger.info("nested", {
376
+ user: { id: 1, name: "test" },
377
+ tags: ["a", "b"],
378
+ });
379
+
380
+ const parsed = parseOutput(output, 0);
381
+ const context = parsed.context as Record<string, unknown>;
382
+ expect(context.user).toEqual({ id: 1, name: "test" });
383
+ expect(context.tags).toEqual(["a", "b"]);
384
+ });
385
+ });
386
+
387
+ describe("convenience functions", () => {
388
+ test("createLogger creates new instance", () => {
389
+ const logger = createLogger({ level: "debug" });
390
+ expect(logger).toBeInstanceOf(Logger);
391
+ expect(logger.getLevel()).toBe("debug");
392
+ });
393
+
394
+ test("getLogger returns singleton", () => {
395
+ const logger1 = getLogger();
396
+ const logger2 = getLogger();
397
+ expect(logger1).toBe(logger2);
398
+ });
399
+
400
+ test("configureLogger updates singleton", () => {
401
+ configureLogger({ level: "error" });
402
+ const newLogger = getLogger();
403
+ expect(newLogger.getLevel()).toBe("error");
404
+ // Restore to info for other tests
405
+ configureLogger({ level: "info" });
406
+ });
407
+ });
408
+
409
+ describe("level-specific methods", () => {
410
+ test("debug method logs at debug level", () => {
411
+ const output: string[] = [];
412
+ const logger = new Logger({
413
+ level: "debug",
414
+ format: "json",
415
+ output: (text) => output.push(text),
416
+ });
417
+
418
+ logger.debug("debug message");
419
+ const parsed = parseOutput(output, 0);
420
+ expect(parsed.level).toBe("debug");
421
+ });
422
+
423
+ test("info method logs at info level", () => {
424
+ const output: string[] = [];
425
+ const logger = new Logger({
426
+ level: "debug",
427
+ format: "json",
428
+ output: (text) => output.push(text),
429
+ });
430
+
431
+ logger.info("info message");
432
+ const parsed = parseOutput(output, 0);
433
+ expect(parsed.level).toBe("info");
434
+ });
435
+
436
+ test("warn method logs at warn level", () => {
437
+ const output: string[] = [];
438
+ const logger = new Logger({
439
+ level: "debug",
440
+ format: "json",
441
+ errorOutput: (text) => output.push(text),
442
+ });
443
+
444
+ logger.warn("warn message");
445
+ const parsed = parseOutput(output, 0);
446
+ expect(parsed.level).toBe("warn");
447
+ });
448
+
449
+ test("error method logs at error level", () => {
450
+ const output: string[] = [];
451
+ const logger = new Logger({
452
+ level: "debug",
453
+ format: "json",
454
+ errorOutput: (text) => output.push(text),
455
+ });
456
+
457
+ logger.error("error message");
458
+ const parsed = parseOutput(output, 0);
459
+ expect(parsed.level).toBe("error");
460
+ });
461
+ });
462
+
463
+ describe("timestamp format", () => {
464
+ test("timestamp is ISO 8601 format", () => {
465
+ const output: string[] = [];
466
+ const logger = new Logger({
467
+ format: "json",
468
+ output: (text) => output.push(text),
469
+ });
470
+
471
+ logger.info("test");
472
+ const parsed = parseOutput(output, 0);
473
+
474
+ // Should be valid ISO 8601
475
+ const timestamp = parsed.timestamp as string;
476
+ const date = new Date(timestamp);
477
+ expect(date.toISOString()).toBe(timestamp);
478
+ });
479
+ });
480
+ });