gravity-run 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -3,9 +3,80 @@ import {
3
3
  BadRequestError,
4
4
  ForbiddenError,
5
5
  UnauthorizedError,
6
- globalLogger,
6
+ __commonJS,
7
+ __toESM,
7
8
  loadConfig
8
- } from "../shared/chunk-b636e30q.js";
9
+ } from "../shared/chunk-s3hrp89d.js";
10
+
11
+ // node_modules/picocolors/picocolors.js
12
+ var require_picocolors = __commonJS((exports, module) => {
13
+ var p = process || {};
14
+ var argv = p.argv || [];
15
+ var env = p.env || {};
16
+ var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
17
+ var formatter = (open, close, replace = open) => (input) => {
18
+ let string = "" + input, index = string.indexOf(close, open.length);
19
+ return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
20
+ };
21
+ var replaceClose = (string, close, replace, index) => {
22
+ let result = "", cursor = 0;
23
+ do {
24
+ result += string.substring(cursor, index) + replace;
25
+ cursor = index + close.length;
26
+ index = string.indexOf(close, cursor);
27
+ } while (~index);
28
+ return result + string.substring(cursor);
29
+ };
30
+ var createColors = (enabled = isColorSupported) => {
31
+ let f = enabled ? formatter : () => String;
32
+ return {
33
+ isColorSupported: enabled,
34
+ reset: f("\x1B[0m", "\x1B[0m"),
35
+ bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
36
+ dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
37
+ italic: f("\x1B[3m", "\x1B[23m"),
38
+ underline: f("\x1B[4m", "\x1B[24m"),
39
+ inverse: f("\x1B[7m", "\x1B[27m"),
40
+ hidden: f("\x1B[8m", "\x1B[28m"),
41
+ strikethrough: f("\x1B[9m", "\x1B[29m"),
42
+ black: f("\x1B[30m", "\x1B[39m"),
43
+ red: f("\x1B[31m", "\x1B[39m"),
44
+ green: f("\x1B[32m", "\x1B[39m"),
45
+ yellow: f("\x1B[33m", "\x1B[39m"),
46
+ blue: f("\x1B[34m", "\x1B[39m"),
47
+ magenta: f("\x1B[35m", "\x1B[39m"),
48
+ cyan: f("\x1B[36m", "\x1B[39m"),
49
+ white: f("\x1B[37m", "\x1B[39m"),
50
+ gray: f("\x1B[90m", "\x1B[39m"),
51
+ bgBlack: f("\x1B[40m", "\x1B[49m"),
52
+ bgRed: f("\x1B[41m", "\x1B[49m"),
53
+ bgGreen: f("\x1B[42m", "\x1B[49m"),
54
+ bgYellow: f("\x1B[43m", "\x1B[49m"),
55
+ bgBlue: f("\x1B[44m", "\x1B[49m"),
56
+ bgMagenta: f("\x1B[45m", "\x1B[49m"),
57
+ bgCyan: f("\x1B[46m", "\x1B[49m"),
58
+ bgWhite: f("\x1B[47m", "\x1B[49m"),
59
+ blackBright: f("\x1B[90m", "\x1B[39m"),
60
+ redBright: f("\x1B[91m", "\x1B[39m"),
61
+ greenBright: f("\x1B[92m", "\x1B[39m"),
62
+ yellowBright: f("\x1B[93m", "\x1B[39m"),
63
+ blueBright: f("\x1B[94m", "\x1B[39m"),
64
+ magentaBright: f("\x1B[95m", "\x1B[39m"),
65
+ cyanBright: f("\x1B[96m", "\x1B[39m"),
66
+ whiteBright: f("\x1B[97m", "\x1B[39m"),
67
+ bgBlackBright: f("\x1B[100m", "\x1B[49m"),
68
+ bgRedBright: f("\x1B[101m", "\x1B[49m"),
69
+ bgGreenBright: f("\x1B[102m", "\x1B[49m"),
70
+ bgYellowBright: f("\x1B[103m", "\x1B[49m"),
71
+ bgBlueBright: f("\x1B[104m", "\x1B[49m"),
72
+ bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
73
+ bgCyanBright: f("\x1B[106m", "\x1B[49m"),
74
+ bgWhiteBright: f("\x1B[107m", "\x1B[49m")
75
+ };
76
+ };
77
+ module.exports = createColors();
78
+ module.exports.createColors = createColors;
79
+ });
9
80
 
10
81
  // src/cli/index.ts
11
82
  import { Command as Command5 } from "commander";
@@ -152,17 +223,219 @@ function schemaToTypeString(schema) {
152
223
  return "any";
153
224
  }
154
225
 
226
+ // src/logger/action-logger.ts
227
+ var import_picocolors2 = __toESM(require_picocolors(), 1);
228
+
229
+ // src/logger/symbols.ts
230
+ var import_picocolors = __toESM(require_picocolors(), 1);
231
+ import isUnicodeSupported from "is-unicode-supported";
232
+ var unicode = isUnicodeSupported();
233
+ var u = (c, fallback) => unicode ? c : fallback;
234
+ var S_BAR_START = u("┌", "T");
235
+ var S_BAR = u("│", "|");
236
+ var S_BAR_END = u("└", "-");
237
+ var S_STEP_SUBMIT = u("◇", "o");
238
+ var S_RADIO_ACTIVE = u("●", ">");
239
+ var S_SUCCESS = u("✔", "√");
240
+ var S_ERROR = u("✖", "x");
241
+ var S_WARN = u("▲", "!");
242
+ var S_INFO = u("●", "•");
243
+ var bar = () => import_picocolors.default.gray(S_BAR);
244
+ var barStart = (text) => `${import_picocolors.default.gray(S_BAR_START)} ${text}`;
245
+ var barEnd = (text) => `${import_picocolors.default.gray(S_BAR_END)} ${text}`;
246
+ var stepInfo = (label, detail) => `${import_picocolors.default.green(S_STEP_SUBMIT)} ${label}${detail ? `: ${detail}` : ""}`;
247
+ var stepActive = (label, detail) => `${import_picocolors.default.cyan(S_RADIO_ACTIVE)} ${label}${detail ? `: ${detail}` : ""}`;
248
+ var stepSuccess = (label, detail) => `${import_picocolors.default.green(S_SUCCESS)} ${label}${detail ? `: ${detail}` : ""}`;
249
+ var stepError = (label, detail) => `${import_picocolors.default.red(S_ERROR)} ${label}${detail ? `: ${detail}` : ""}`;
250
+ var stepWarn = (label, detail) => `${import_picocolors.default.yellow(S_WARN)} ${label}${detail ? `: ${detail}` : ""}`;
251
+
252
+ // src/logger/action-logger.ts
253
+ class LoggerSession {
254
+ output;
255
+ startTime;
256
+ constructor(title, output = process.stdout) {
257
+ this.output = output;
258
+ this.startTime = Date.now();
259
+ this.write(barStart(title));
260
+ }
261
+ write(line) {
262
+ this.output.write(`${line}
263
+ `);
264
+ }
265
+ info(label, detail) {
266
+ this.write(stepInfo(label, detail));
267
+ return this;
268
+ }
269
+ step(label, detail) {
270
+ this.write(stepActive(label, detail));
271
+ return this;
272
+ }
273
+ success(label, detail) {
274
+ this.write(stepSuccess(label, detail));
275
+ return this;
276
+ }
277
+ warn(label, detail) {
278
+ this.write(stepWarn(label, detail));
279
+ return this;
280
+ }
281
+ error(label, detail) {
282
+ this.write(stepError(label, detail));
283
+ return this;
284
+ }
285
+ bar() {
286
+ this.write(bar());
287
+ return this;
288
+ }
289
+ end(message) {
290
+ const elapsed = Date.now() - this.startTime;
291
+ const msg = message ?? "Done";
292
+ this.write(bar());
293
+ this.write(barEnd(import_picocolors2.default.green(`${msg}`) + import_picocolors2.default.gray(` (${elapsed}ms)`)));
294
+ this.write("");
295
+ }
296
+ fail(message) {
297
+ const elapsed = Date.now() - this.startTime;
298
+ const msg = message ?? "Failed";
299
+ this.write(bar());
300
+ this.write(barEnd(import_picocolors2.default.red(`${msg}`) + import_picocolors2.default.gray(` (${elapsed}ms)`)));
301
+ this.write("");
302
+ }
303
+ }
304
+ // src/logger/pretty-print.ts
305
+ var import_picocolors3 = __toESM(require_picocolors(), 1);
306
+ var stepTag = (step) => step ? import_picocolors3.default.bold(import_picocolors3.default.cyan(step)) : "";
307
+ var timestampTag = (timestamp) => import_picocolors3.default.gray(timestamp);
308
+ var traceIdTag = (traceId) => traceId ? import_picocolors3.default.gray(traceId) : "";
309
+ var levelTags = {
310
+ error: import_picocolors3.default.red("[ERROR]"),
311
+ info: import_picocolors3.default.blue("[INFO]"),
312
+ warn: import_picocolors3.default.yellow("[WARN]"),
313
+ debug: import_picocolors3.default.gray("[DEBUG]")
314
+ };
315
+ var numericTag = (value) => import_picocolors3.default.green(value);
316
+ var stringTag = (value) => import_picocolors3.default.cyan(value);
317
+ var booleanTag = (value) => import_picocolors3.default.blue(value);
318
+ var arrayBrackets = ["[", "]"].map((s) => import_picocolors3.default.gray(s));
319
+ var objectBrackets = ["{", "}"].map((s) => import_picocolors3.default.gray(s));
320
+ var prettyPrintObject = (obj, depth = 0, parentIsLast = false, prefix = "") => {
321
+ const tab = prefix + (depth === 0 ? "" : parentIsLast ? "│ " : "│ ");
322
+ if (depth > 2)
323
+ return `${tab} └ ${import_picocolors3.default.gray("[...]")}`;
324
+ const entries = Object.entries(obj);
325
+ return entries.map(([key, value], index) => {
326
+ const isLast = index === entries.length - 1;
327
+ const isObject = typeof value === "object" && value !== null;
328
+ const branch = isLast ? "└" : "├";
329
+ if (isObject) {
330
+ const subObject = prettyPrintObject(value, depth + 1, isLast, tab);
331
+ const [start, end] = Array.isArray(value) ? arrayBrackets : objectBrackets;
332
+ return `${tab}${branch} ${key}: ${start}
333
+ ${subObject}
334
+ ${tab}${isLast ? " " : "│"} ${end}`;
335
+ }
336
+ let printedValue = value;
337
+ if (typeof value === "number")
338
+ printedValue = numericTag(String(value));
339
+ else if (typeof value === "boolean")
340
+ printedValue = booleanTag(String(value));
341
+ else if (typeof value === "string")
342
+ printedValue = stringTag(value);
343
+ return `${tab}${branch} ${key}: ${printedValue}`;
344
+ }).join(`
345
+ `);
346
+ };
347
+ var prettyPrint = (json, excludeDetails = false) => {
348
+ const { time, traceId, msg, flows, level, step, ...details } = json;
349
+ const levelTag = levelTags[level?.toLowerCase?.()] ?? levelTags.info;
350
+ const timestamp = timestampTag(`[${new Date(time).toLocaleTimeString()}]`);
351
+ const objectHasKeys = Object.keys(details).length > 0;
352
+ process.stdout.write(`${timestamp} ${traceIdTag(traceId)} ${levelTag} ${stepTag(step)} ${msg}
353
+ `);
354
+ if (objectHasKeys && !excludeDetails) {
355
+ process.stdout.write(`${prettyPrintObject(details)}
356
+ `);
357
+ }
358
+ };
359
+
360
+ // src/logger/logger.ts
361
+ var LEVELS = {
362
+ DEBUG: 10,
363
+ INFO: 20,
364
+ WARNING: 30,
365
+ ERROR: 40,
366
+ CRITICAL: 50
367
+ };
368
+ var levelMap = {
369
+ debug: LEVELS.DEBUG,
370
+ info: LEVELS.INFO,
371
+ warn: LEVELS.WARNING,
372
+ warning: LEVELS.WARNING,
373
+ error: LEVELS.ERROR,
374
+ critical: LEVELS.CRITICAL
375
+ };
376
+
377
+ class Logger {
378
+ options;
379
+ meta;
380
+ coreListeners;
381
+ listeners = [];
382
+ minLevel;
383
+ constructor(options = {}, meta = {}, coreListeners = []) {
384
+ this.options = options;
385
+ this.meta = meta;
386
+ this.coreListeners = coreListeners;
387
+ this.minLevel = options.level ? levelMap[options.level] ?? LEVELS.INFO : LEVELS.INFO;
388
+ }
389
+ child(meta) {
390
+ return new Logger(this.options, { ...this.meta, ...meta }, this.coreListeners);
391
+ }
392
+ session(title) {
393
+ return new LoggerSession(title);
394
+ }
395
+ shouldLog(messageLevel) {
396
+ return messageLevel >= this.minLevel;
397
+ }
398
+ _log(level, msg, args) {
399
+ const time = Date.now();
400
+ const meta = { ...this.meta, ...args ?? {} };
401
+ const isVerbose = this.options.verbose ?? false;
402
+ prettyPrint({ level, time, msg, ...meta }, !isVerbose);
403
+ this.coreListeners.forEach((listener) => {
404
+ listener(level, msg, meta);
405
+ });
406
+ this.listeners.forEach((listener) => {
407
+ listener(level, msg, meta);
408
+ });
409
+ }
410
+ info(message, args) {
411
+ if (this.shouldLog(LEVELS.INFO))
412
+ this._log("INFO", message, args);
413
+ }
414
+ error(message, args) {
415
+ if (this.shouldLog(LEVELS.ERROR))
416
+ this._log("ERROR", message, args);
417
+ }
418
+ debug(message, args) {
419
+ if (this.shouldLog(LEVELS.DEBUG))
420
+ this._log("DEBUG", message, args);
421
+ }
422
+ warn(message, args) {
423
+ if (this.shouldLog(LEVELS.WARNING))
424
+ this._log("WARNING", message, args);
425
+ }
426
+ addListener(listener) {
427
+ this.listeners.push(listener);
428
+ }
429
+ }
155
430
  // src/runtime/loader.ts
156
- import { pathToFileURL } from "node:url";
157
- import { glob } from "glob";
158
- async function loadActions(dir) {
159
- const files = glob.sync(`**/*.ts`, {
160
- cwd: dir,
161
- ignore: `**/*.spec.ts`
162
- });
431
+ async function loadActions(dir, logger = new Logger) {
432
+ const glob = new Bun.Glob(`${dir}/**/*.ts`);
433
+ const files = glob.scanSync();
434
+ logger.debug("Loading actions from", { files });
163
435
  const actions = [];
164
436
  for (const file of files) {
165
- const module = await import(pathToFileURL(file).href);
437
+ const module = await import(Bun.pathToFileURL(file).href);
438
+ logger.debug("Loading action", { file });
166
439
  for (const exported of Object.values(module)) {
167
440
  if (isAction(exported)) {
168
441
  actions.push(exported);
@@ -183,34 +456,34 @@ class ActionExecutor {
183
456
  this.baseContext = baseContext;
184
457
  }
185
458
  async execute(action, triggerName, sourceData) {
459
+ const traceId = Bun.randomUUIDv7();
186
460
  const config = action.config;
461
+ const baseLogger = this.baseContext.logger ?? new Logger;
462
+ const logger = baseLogger.child({
463
+ action: config.name,
464
+ traceId,
465
+ trigger: triggerName
466
+ });
187
467
  const trigger = config.triggers?.find((t) => t.name === triggerName);
188
468
  if (!trigger) {
189
469
  throw new BadRequestError(`Trigger '${triggerName}' not found for action '${config.name}'`);
190
470
  }
191
471
  const actor = await this.resolveActor(trigger, sourceData);
472
+ const session = logger.session(`Basalt Action: ${config.name}`);
473
+ session.bar().info("Trigger", `${trigger.kind} (${triggerName})`).info("Identity", `${actor.id ?? "anonymous"} (${actor.type})`).bar();
192
474
  const ctx = {
193
- requestId: this.baseContext.requestId || `req-${Date.now()}-${Math.random().toString(36).slice(2)}`,
475
+ traceId,
194
476
  triggerName,
195
477
  triggerType: trigger.kind,
196
478
  actor,
197
- logger: this.baseContext.logger || globalLogger,
479
+ logger,
198
480
  db: this.baseContext.db,
199
481
  storage: this.baseContext.storage,
200
- enqueue: this.baseContext.enqueue || this.createEnqueueFn(),
201
- schedule: this.baseContext.schedule || this.createScheduleFn(),
482
+ enqueue: this.baseContext.enqueue || this.createEnqueueFn(logger),
483
+ schedule: this.baseContext.schedule || this.createScheduleFn(logger),
202
484
  org: this.baseContext.org,
203
485
  ...this.baseContext
204
486
  };
205
- const logger = ctx.logger.child({
206
- action: config.name,
207
- requestId: ctx.requestId,
208
- trigger: triggerName
209
- });
210
- logger.info("Action execution started", {
211
- actor: actor.type,
212
- triggerType: trigger.kind
213
- });
214
487
  try {
215
488
  let input = sourceData;
216
489
  if (trigger.map) {
@@ -222,17 +495,21 @@ class ActionExecutor {
222
495
  }
223
496
  await this.checkRateLimit(ctx, config);
224
497
  if (config.access) {
498
+ session.step("Access", "checking...");
225
499
  await this.checkAccess(ctx, config.access);
500
+ session.success("Access", "passed");
501
+ }
502
+ if (config.guard) {
503
+ session.step("Guard", "checking...");
504
+ await this.checkGuard(ctx, input, config);
505
+ session.success("Guard", "passed");
226
506
  }
227
- await this.checkGuard(ctx, input, config);
228
507
  const result = await action(input, ctx);
229
- logger.info("Action execution completed");
508
+ session.end("Success");
230
509
  return result;
231
510
  } catch (error) {
232
- logger.error("Action execution failed", {
233
- error: error.message,
234
- stack: error.stack
235
- });
511
+ session.error("Error", error.message);
512
+ session.fail("Failed");
236
513
  throw error;
237
514
  }
238
515
  }
@@ -316,17 +593,17 @@ class ActionExecutor {
316
593
  }
317
594
  }
318
595
  }
319
- createEnqueueFn() {
596
+ createEnqueueFn(logger) {
320
597
  return async (eventType, data) => {
321
- globalLogger.warn("enqueue called but no event bus configured", {
598
+ logger.warn("enqueue called but no event bus configured", {
322
599
  eventType,
323
600
  data
324
601
  });
325
602
  };
326
603
  }
327
- createScheduleFn() {
604
+ createScheduleFn(logger) {
328
605
  return async (actionName, input, runAt) => {
329
- globalLogger.warn("schedule called but no scheduler configured", {
606
+ logger.warn("schedule called but no scheduler configured", {
330
607
  actionName,
331
608
  runAt,
332
609
  input
@@ -339,8 +616,10 @@ class ActionExecutor {
339
616
  class EventBus {
340
617
  subscriptions = [];
341
618
  executor;
619
+ logger;
342
620
  constructor(baseContext) {
343
621
  this.executor = new ActionExecutor(baseContext);
622
+ this.logger = baseContext.logger;
344
623
  }
345
624
  subscribe(pattern, action, triggerName) {
346
625
  this.subscriptions.push({ pattern, action, triggerName });
@@ -348,14 +627,14 @@ class EventBus {
348
627
  async publish(event) {
349
628
  const matching = this.subscriptions.filter((sub) => this.matchPattern(sub.pattern, event.type));
350
629
  if (matching.length === 0) {
351
- globalLogger.debug("No subscribers for event", { eventType: event.type });
630
+ this.logger.debug("No subscribers for event", { eventType: event.type });
352
631
  return;
353
632
  }
354
633
  const results = await Promise.allSettled(matching.map(async (sub) => {
355
634
  try {
356
635
  return await this.executor.execute(sub.action, sub.triggerName, event);
357
636
  } catch (error) {
358
- globalLogger.error("Event handler failed", {
637
+ this.logger.error("Event handler failed", {
359
638
  event: event.type,
360
639
  action: sub.action.config.name,
361
640
  error: error.message
@@ -365,7 +644,7 @@ class EventBus {
365
644
  }));
366
645
  const failed = results.filter((r) => r.status === "rejected").length;
367
646
  const succeeded = results.filter((r) => r.status === "fulfilled").length;
368
- globalLogger.info("Event published", {
647
+ this.logger.info("Event published", {
369
648
  event: event.type,
370
649
  handlers: matching.length,
371
650
  succeeded,
@@ -381,10 +660,12 @@ class EventBus {
381
660
  // src/runtime/http.ts
382
661
  class HttpServer {
383
662
  config;
663
+ logger;
384
664
  server;
385
665
  router;
386
- constructor(config, router) {
666
+ constructor(config, router, logger = new Logger) {
387
667
  this.config = config;
668
+ this.logger = logger;
388
669
  this.router = router;
389
670
  }
390
671
  async start() {
@@ -412,10 +693,10 @@ class HttpServer {
412
693
  body = await req.json();
413
694
  } else if (contentType.includes("application/x-www-form-urlencoded")) {
414
695
  const formData = await req.formData();
415
- body = Object.fromEntries(formData);
696
+ body = Object.fromEntries(formData.entries());
416
697
  } else if (contentType.includes("multipart/form-data")) {
417
698
  const formData = await req.formData();
418
- body = Object.fromEntries(formData);
699
+ body = Object.fromEntries(formData.entries());
419
700
  } else {
420
701
  body = await req.text();
421
702
  }
@@ -446,7 +727,7 @@ class HttpServer {
446
727
  }
447
728
  });
448
729
  } catch (error) {
449
- globalLogger.error("HTTP request failed", {
730
+ this.logger.error("HTTP request failed", {
450
731
  error: error.message,
451
732
  stack: error.stack
452
733
  });
@@ -474,8 +755,8 @@ class HttpServer {
474
755
  });
475
756
  }
476
757
  },
477
- error(error) {
478
- globalLogger.error("HTTP server error", {
758
+ error: (error) => {
759
+ this.logger.error("HTTP server error", {
479
760
  error: error.message,
480
761
  stack: error.stack
481
762
  });
@@ -487,14 +768,14 @@ class HttpServer {
487
768
  });
488
769
  }
489
770
  });
490
- globalLogger.info("HTTP server started", {
771
+ this.logger.info("HTTP server started", {
491
772
  url: `http://${host}:${port}`
492
773
  });
493
774
  }
494
775
  async stop() {
495
776
  if (this.server) {
496
777
  this.server.stop();
497
- globalLogger.info("HTTP server stopped");
778
+ this.logger.info("HTTP server stopped");
498
779
  }
499
780
  }
500
781
  getUrl() {
@@ -522,21 +803,23 @@ function getCorsHeaders(corsConfig) {
522
803
  // src/runtime/mcp-server.ts
523
804
  class McpServer {
524
805
  context;
525
- constructor(context) {
806
+ logger;
807
+ constructor(context, logger = new Logger) {
526
808
  this.context = context;
809
+ this.logger = logger;
527
810
  }
528
811
  register(action, trigger) {
529
- globalLogger.info("Registering MCP tool", {
812
+ this.logger.info("Registering MCP tool", {
530
813
  tool: trigger.tool,
531
814
  action: action.config.name,
532
815
  context: this.context
533
816
  });
534
817
  }
535
818
  async start() {
536
- globalLogger.info("MCP Server started");
819
+ this.logger.info("MCP Server started");
537
820
  }
538
821
  async stop() {
539
- globalLogger.info("MCP Server stopped");
822
+ this.logger.info("MCP Server stopped");
540
823
  }
541
824
  }
542
825
 
@@ -590,11 +873,7 @@ class Router {
590
873
  };
591
874
  }
592
875
  getRoutes() {
593
- return this.routes.map((r) => ({
594
- method: r.method,
595
- path: r.trigger.path,
596
- action: r.action.config.name
597
- }));
876
+ return this.routes;
598
877
  }
599
878
  }
600
879
 
@@ -603,8 +882,10 @@ import Baker from "cronbake";
603
882
  class Scheduler {
604
883
  baker = Baker.create();
605
884
  executor;
885
+ logger;
606
886
  constructor(baseContext) {
607
887
  this.executor = new ActionExecutor(baseContext);
888
+ this.logger = baseContext.logger;
608
889
  }
609
890
  schedule(action, trigger) {
610
891
  this.baker.add({
@@ -612,13 +893,13 @@ class Scheduler {
612
893
  cron: trigger.schedule,
613
894
  callback: async () => {
614
895
  try {
615
- globalLogger.info("Running scheduled action", {
896
+ this.logger.info("Running scheduled action", {
616
897
  action: action.config.name,
617
898
  schedule: trigger.schedule
618
899
  });
619
900
  await this.executor.execute(action, trigger.name, {});
620
901
  } catch (error) {
621
- globalLogger.error("Scheduled action failed", {
902
+ this.logger.error("Scheduled action failed", {
622
903
  action: action.config.name,
623
904
  error: error.message,
624
905
  stack: error.stack
@@ -629,11 +910,11 @@ class Scheduler {
629
910
  }
630
911
  start() {
631
912
  this.baker.bakeAll();
632
- globalLogger.info("Scheduler started");
913
+ this.logger.info("Scheduler started");
633
914
  }
634
915
  stop() {
635
916
  this.baker.stopAll();
636
- globalLogger.info("Stopped all cron jobs");
917
+ this.logger.info("Stopped all cron jobs");
637
918
  }
638
919
  }
639
920
 
@@ -645,21 +926,23 @@ class BasaltServer {
645
926
  scheduler;
646
927
  mcpServer;
647
928
  httpServer;
929
+ logger;
648
930
  actions = [];
649
931
  constructor(config) {
650
932
  this.config = config;
933
+ this.logger = new Logger(config.logger ?? {});
651
934
  const baseContext = this.buildBaseContext();
652
935
  this.router = new Router(baseContext);
653
936
  this.eventBus = new EventBus(baseContext);
654
937
  this.scheduler = new Scheduler(baseContext);
655
- this.httpServer = new HttpServer(this.config, this.router);
938
+ this.httpServer = new HttpServer(this.config, this.router, this.logger);
656
939
  if (this.config.mcp?.enabled) {
657
- this.mcpServer = new McpServer(baseContext);
940
+ this.mcpServer = new McpServer(baseContext, this.logger);
658
941
  }
659
942
  }
660
943
  buildBaseContext() {
661
944
  return {
662
- logger: globalLogger,
945
+ logger: this.logger,
663
946
  db: undefined,
664
947
  storage: undefined,
665
948
  enqueue: async (eventType, data) => {
@@ -680,11 +963,11 @@ class BasaltServer {
680
963
  const actionName = action.config.name;
681
964
  if (typeof when === "number") {
682
965
  const runAt = new Date(Date.now() + when * 1000);
683
- globalLogger.info("Scheduling action", { actionName, runAt, input });
966
+ this.logger.info("Scheduling action", { actionName, runAt, input });
684
967
  } else if (when instanceof Date) {
685
- globalLogger.info("Scheduling action", { actionName, runAt: when, input });
968
+ this.logger.info("Scheduling action", { actionName, runAt: when, input });
686
969
  } else if (typeof when === "string") {
687
- globalLogger.info("Scheduling recurring action", {
970
+ this.logger.info("Scheduling recurring action", {
688
971
  actionName,
689
972
  cron: when,
690
973
  input
@@ -692,7 +975,7 @@ class BasaltServer {
692
975
  }
693
976
  }
694
977
  async initialize() {
695
- this.actions = await loadActions(this.config.actionsDir || "./src/actions");
978
+ this.actions = await loadActions(this.config.actionsDir || "./src/actions", this.logger);
696
979
  for (const action of this.actions) {
697
980
  if (!action.config.triggers)
698
981
  continue;
@@ -701,7 +984,7 @@ class BasaltServer {
701
984
  case "api": {
702
985
  const apiTrigger = trigger;
703
986
  this.router.register(action, apiTrigger);
704
- globalLogger.info("Registered API route", {
987
+ this.logger.info("Registered API route", {
705
988
  method: apiTrigger.method,
706
989
  path: apiTrigger.path,
707
990
  action: action.config.name
@@ -711,7 +994,7 @@ class BasaltServer {
711
994
  case "cron": {
712
995
  const cronTrigger = trigger;
713
996
  this.scheduler.schedule(action, cronTrigger);
714
- globalLogger.info("Registered cron job", {
997
+ this.logger.info("Registered cron job", {
715
998
  schedule: cronTrigger.schedule,
716
999
  action: action.config.name
717
1000
  });
@@ -720,7 +1003,7 @@ class BasaltServer {
720
1003
  case "event": {
721
1004
  const eventTrigger = trigger;
722
1005
  this.eventBus.subscribe(eventTrigger.event, action, eventTrigger.name);
723
- globalLogger.info("Registered event handler", {
1006
+ this.logger.info("Registered event handler", {
724
1007
  event: eventTrigger.event,
725
1008
  action: action.config.name
726
1009
  });
@@ -729,7 +1012,7 @@ class BasaltServer {
729
1012
  case "agent": {
730
1013
  const agentTrigger = trigger;
731
1014
  this.mcpServer?.register(action, agentTrigger);
732
- globalLogger.info("Registered MCP tool", {
1015
+ this.logger.info("Registered MCP tool", {
733
1016
  tool: agentTrigger.tool,
734
1017
  action: action.config.name
735
1018
  });
@@ -738,7 +1021,7 @@ class BasaltServer {
738
1021
  }
739
1022
  }
740
1023
  }
741
- globalLogger.info("Basalt initialized", {
1024
+ this.logger.info("Basalt initialized", {
742
1025
  actions: this.actions.length,
743
1026
  routes: this.router.getRoutes().length
744
1027
  });
@@ -771,6 +1054,7 @@ class BasaltServer {
771
1054
 
772
1055
  // src/runtime/dev.ts
773
1056
  async function createDevServer(config) {
1057
+ const logger = new Logger(config.logger ?? {});
774
1058
  const server = new BasaltServer(config);
775
1059
  await server.initialize();
776
1060
  if (config.dev?.watch !== false) {
@@ -780,16 +1064,16 @@ async function createDevServer(config) {
780
1064
  return;
781
1065
  if (!/\.(ts|js)$/.test(filename))
782
1066
  return;
783
- globalLogger.info("Action file changed, regenerating...", {
1067
+ logger.info("Action file changed, regenerating...", {
784
1068
  filename,
785
1069
  eventType
786
1070
  });
787
1071
  try {
788
- const actions = await loadActions(actionsDir);
1072
+ const actions = await loadActions(actionsDir, logger);
789
1073
  await generateActionTypes(actions);
790
- globalLogger.info("Types regenerated");
1074
+ logger.info("Types regenerated");
791
1075
  } catch (error) {
792
- globalLogger.error("Failed to regenerate types", {
1076
+ logger.error("Failed to regenerate types", {
793
1077
  error: error.message
794
1078
  });
795
1079
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  type DatabaseConfig = {};
2
- type LoggerOptions = {};
2
+ type LogLevel = "debug" | "info" | "warn" | "error" | "critical";
3
+ type LoggerOptions = {
4
+ /** Minimum log level (default: 'info') */
5
+ level?: LogLevel;
6
+ /** Show verbose output with metadata details (default: false) */
7
+ verbose?: boolean;
8
+ };
3
9
  type StorageConfig = {};
4
10
  interface BasaltConfig {
5
11
  /**
@@ -76,6 +82,32 @@ declare function loadConfig(): Promise<BasaltConfig>;
76
82
  declare function defineConfig(config: BasaltConfig): BasaltConfig;
77
83
  import { TSchema as TSchema2 } from "typebox";
78
84
  import { Static, TSchema } from "typebox";
85
+ /**
86
+ * A structured logging session with clack-style box-drawing output.
87
+ * Created via `logger.session("title")`.
88
+ */
89
+ declare class LoggerSession {
90
+ private output;
91
+ private startTime;
92
+ constructor(title: string, output?: NodeJS.WritableStream);
93
+ private write;
94
+ /** Static info line: ◇ label: detail */
95
+ info(label: string, detail?: string): this;
96
+ /** In-progress step: ● label: detail */
97
+ step(label: string, detail?: string): this;
98
+ /** Completed step: ✔ label: detail */
99
+ success(label: string, detail?: string): this;
100
+ /** Warning step: ▲ label: detail */
101
+ warn(label: string, detail?: string): this;
102
+ /** Error step: ✖ label: detail */
103
+ error(label: string, detail?: string): this;
104
+ /** Empty separator bar: │ */
105
+ bar(): this;
106
+ /** Close the session with success: └ message (Xms) */
107
+ end(message?: string): void;
108
+ /** Close the session as error: └ message (Xms) */
109
+ fail(message?: string): void;
110
+ }
79
111
  declare const LEVELS: {
80
112
  readonly DEBUG: 10;
81
113
  readonly INFO: 20;
@@ -83,15 +115,20 @@ declare const LEVELS: {
83
115
  readonly ERROR: 40;
84
116
  readonly CRITICAL: 50;
85
117
  };
86
- type LogLevel = keyof typeof LEVELS;
87
- type LogListener = (level: LogLevel, msg: string, args?: unknown) => void;
118
+ type LogLevel2 = keyof typeof LEVELS;
119
+ type LogListener = (level: LogLevel2, msg: string, args?: unknown) => void;
88
120
  declare class Logger {
89
- readonly isVerbose: boolean;
121
+ private readonly options;
90
122
  private readonly meta;
91
123
  private readonly coreListeners;
92
124
  private readonly listeners;
93
- constructor(isVerbose?: boolean, meta?: Record<string, unknown>, coreListeners?: LogListener[]);
125
+ private readonly minLevel;
126
+ constructor(options?: LoggerOptions, meta?: Record<string, unknown>, coreListeners?: LogListener[]);
127
+ /** Create a child logger with additional metadata */
94
128
  child(meta: Record<string, unknown>): Logger;
129
+ /** Start a structured logging session with clack-style output */
130
+ session(title: string): LoggerSession;
131
+ private shouldLog;
95
132
  private _log;
96
133
  info(message: string, args?: unknown): void;
97
134
  error(message: string, args?: unknown): void;
@@ -128,7 +165,7 @@ interface ApiTrigger extends BaseTrigger<"api"> {
128
165
  interface ApiRequest {
129
166
  method: string;
130
167
  path: string;
131
- params: Record<string, string>;
168
+ params: Record<string, string | undefined>;
132
169
  query: Record<string, string>;
133
170
  body: unknown;
134
171
  headers: Record<string, string>;
@@ -256,7 +293,7 @@ type BaseActionContext = {
256
293
  logger: Logger;
257
294
  triggerName: string;
258
295
  triggerType: TriggerKind;
259
- requestId: string;
296
+ traceId: string;
260
297
  };
261
298
  type ExtendActionContext = {};
262
299
  type ActionContext = BaseActionContext & ExtendActionContext;
package/dist/index.js CHANGED
@@ -7,9 +7,8 @@ import {
7
7
  NotFoundError,
8
8
  UnauthorizedError,
9
9
  defineConfig,
10
- globalLogger,
11
10
  loadConfig
12
- } from "./shared/chunk-b636e30q.js";
11
+ } from "./shared/chunk-s3hrp89d.js";
13
12
  // src/core/action.ts
14
13
  import { Value } from "typebox/value";
15
14
  function resolveRateLimitRules(config, triggerType) {
@@ -85,8 +84,6 @@ async function checkGuard(ctx, input, config) {
85
84
  }
86
85
  function action(config, handler) {
87
86
  const wrapped = async (input, ctx) => {
88
- const logger = ctx.log ? ctx.log.child({ action: config.name, requestId: ctx.requestId }) : globalLogger.child({ action: config.name, requestId: ctx.requestId });
89
- logger.info("Action started", { input, trigger: ctx.triggerName });
90
87
  try {
91
88
  if (config.input && !Value.Check(config.input, input)) {
92
89
  const errors = [...Value.Errors(config.input, input)];
@@ -97,14 +94,8 @@ function action(config, handler) {
97
94
  await checkAccess(ctx, config.access);
98
95
  }
99
96
  await checkGuard(ctx, input, config);
100
- const result = await handler(input, ctx);
101
- logger.info("Action completed successfully");
102
- return result;
97
+ return await handler(input, ctx);
103
98
  } catch (error) {
104
- logger.error("Action failed", {
105
- error: error.message,
106
- stack: error.stack
107
- });
108
99
  throw error;
109
100
  }
110
101
  };
@@ -0,0 +1,79 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
19
+
20
+ // src/config/loader.ts
21
+ function loadConfig() {
22
+ return Promise.resolve({});
23
+ }
24
+
25
+ // src/config/index.ts
26
+ function defineConfig(config) {
27
+ return config;
28
+ }
29
+
30
+ // src/utils/errors.ts
31
+ class BasaltError extends Error {
32
+ code;
33
+ status;
34
+ constructor(message, code, status) {
35
+ super(message);
36
+ this.code = code;
37
+ this.status = status;
38
+ this.name = this.constructor.name;
39
+ Object.setPrototypeOf(this, new.target.prototype);
40
+ }
41
+ }
42
+
43
+ class NotFoundError extends BasaltError {
44
+ constructor(message = "Resource not found") {
45
+ super(message, "NOT_FOUND", 404);
46
+ }
47
+ }
48
+
49
+ class UnauthorizedError extends BasaltError {
50
+ constructor(message = "Unauthorized") {
51
+ super(message, "UNAUTHORIZED", 401);
52
+ }
53
+ }
54
+
55
+ class ForbiddenError extends BasaltError {
56
+ constructor(message = "Forbidden") {
57
+ super(message, "FORBIDDEN", 403);
58
+ }
59
+ }
60
+
61
+ class BadRequestError extends BasaltError {
62
+ constructor(message = "Bad Request") {
63
+ super(message, "BAD_REQUEST", 400);
64
+ }
65
+ }
66
+
67
+ class InternalServerError extends BasaltError {
68
+ constructor(message = "Internal Server Error") {
69
+ super(message, "INTERNAL_SERVER_ERROR", 500);
70
+ }
71
+ }
72
+
73
+ class NonRetriableError extends BasaltError {
74
+ constructor(message) {
75
+ super(message, "NON_RETRIABLE_ERROR", 500);
76
+ }
77
+ }
78
+
79
+ export { __toESM, __commonJS, loadConfig, defineConfig, BasaltError, NotFoundError, UnauthorizedError, ForbiddenError, BadRequestError, InternalServerError, NonRetriableError };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gravity-run",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "A framework for building scalable applications",
5
5
  "homepage": "https://github.com/alihussnainrb/gravity#readme",
6
6
  "bugs": {
@@ -80,6 +80,7 @@
80
80
  "cronbake": "^0.4.0",
81
81
  "glob": "^13.0.1",
82
82
  "inquirer": "^13.2.2",
83
+ "is-unicode-supported": "^2.1.0",
83
84
  "typebox": "^1.0.81"
84
85
  }
85
86
  }
@@ -1,274 +0,0 @@
1
- import { createRequire } from "node:module";
2
- var __create = Object.create;
3
- var __getProtoOf = Object.getPrototypeOf;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __toESM = (mod, isNodeMode, target) => {
8
- target = mod != null ? __create(__getProtoOf(mod)) : {};
9
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
- for (let key of __getOwnPropNames(mod))
11
- if (!__hasOwnProp.call(to, key))
12
- __defProp(to, key, {
13
- get: () => mod[key],
14
- enumerable: true
15
- });
16
- return to;
17
- };
18
- var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
19
-
20
- // node_modules/picocolors/picocolors.js
21
- var require_picocolors = __commonJS((exports, module) => {
22
- var p = process || {};
23
- var argv = p.argv || [];
24
- var env = p.env || {};
25
- var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
26
- var formatter = (open, close, replace = open) => (input) => {
27
- let string = "" + input, index = string.indexOf(close, open.length);
28
- return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
29
- };
30
- var replaceClose = (string, close, replace, index) => {
31
- let result = "", cursor = 0;
32
- do {
33
- result += string.substring(cursor, index) + replace;
34
- cursor = index + close.length;
35
- index = string.indexOf(close, cursor);
36
- } while (~index);
37
- return result + string.substring(cursor);
38
- };
39
- var createColors = (enabled = isColorSupported) => {
40
- let f = enabled ? formatter : () => String;
41
- return {
42
- isColorSupported: enabled,
43
- reset: f("\x1B[0m", "\x1B[0m"),
44
- bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
45
- dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
46
- italic: f("\x1B[3m", "\x1B[23m"),
47
- underline: f("\x1B[4m", "\x1B[24m"),
48
- inverse: f("\x1B[7m", "\x1B[27m"),
49
- hidden: f("\x1B[8m", "\x1B[28m"),
50
- strikethrough: f("\x1B[9m", "\x1B[29m"),
51
- black: f("\x1B[30m", "\x1B[39m"),
52
- red: f("\x1B[31m", "\x1B[39m"),
53
- green: f("\x1B[32m", "\x1B[39m"),
54
- yellow: f("\x1B[33m", "\x1B[39m"),
55
- blue: f("\x1B[34m", "\x1B[39m"),
56
- magenta: f("\x1B[35m", "\x1B[39m"),
57
- cyan: f("\x1B[36m", "\x1B[39m"),
58
- white: f("\x1B[37m", "\x1B[39m"),
59
- gray: f("\x1B[90m", "\x1B[39m"),
60
- bgBlack: f("\x1B[40m", "\x1B[49m"),
61
- bgRed: f("\x1B[41m", "\x1B[49m"),
62
- bgGreen: f("\x1B[42m", "\x1B[49m"),
63
- bgYellow: f("\x1B[43m", "\x1B[49m"),
64
- bgBlue: f("\x1B[44m", "\x1B[49m"),
65
- bgMagenta: f("\x1B[45m", "\x1B[49m"),
66
- bgCyan: f("\x1B[46m", "\x1B[49m"),
67
- bgWhite: f("\x1B[47m", "\x1B[49m"),
68
- blackBright: f("\x1B[90m", "\x1B[39m"),
69
- redBright: f("\x1B[91m", "\x1B[39m"),
70
- greenBright: f("\x1B[92m", "\x1B[39m"),
71
- yellowBright: f("\x1B[93m", "\x1B[39m"),
72
- blueBright: f("\x1B[94m", "\x1B[39m"),
73
- magentaBright: f("\x1B[95m", "\x1B[39m"),
74
- cyanBright: f("\x1B[96m", "\x1B[39m"),
75
- whiteBright: f("\x1B[97m", "\x1B[39m"),
76
- bgBlackBright: f("\x1B[100m", "\x1B[49m"),
77
- bgRedBright: f("\x1B[101m", "\x1B[49m"),
78
- bgGreenBright: f("\x1B[102m", "\x1B[49m"),
79
- bgYellowBright: f("\x1B[103m", "\x1B[49m"),
80
- bgBlueBright: f("\x1B[104m", "\x1B[49m"),
81
- bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
82
- bgCyanBright: f("\x1B[106m", "\x1B[49m"),
83
- bgWhiteBright: f("\x1B[107m", "\x1B[49m")
84
- };
85
- };
86
- module.exports = createColors();
87
- module.exports.createColors = createColors;
88
- });
89
-
90
- // src/config/loader.ts
91
- function loadConfig() {
92
- return Promise.resolve({});
93
- }
94
-
95
- // src/config/index.ts
96
- function defineConfig(config) {
97
- return config;
98
- }
99
-
100
- // src/utils/errors.ts
101
- class BasaltError extends Error {
102
- code;
103
- status;
104
- constructor(message, code, status) {
105
- super(message);
106
- this.code = code;
107
- this.status = status;
108
- this.name = this.constructor.name;
109
- Object.setPrototypeOf(this, new.target.prototype);
110
- }
111
- }
112
-
113
- class NotFoundError extends BasaltError {
114
- constructor(message = "Resource not found") {
115
- super(message, "NOT_FOUND", 404);
116
- }
117
- }
118
-
119
- class UnauthorizedError extends BasaltError {
120
- constructor(message = "Unauthorized") {
121
- super(message, "UNAUTHORIZED", 401);
122
- }
123
- }
124
-
125
- class ForbiddenError extends BasaltError {
126
- constructor(message = "Forbidden") {
127
- super(message, "FORBIDDEN", 403);
128
- }
129
- }
130
-
131
- class BadRequestError extends BasaltError {
132
- constructor(message = "Bad Request") {
133
- super(message, "BAD_REQUEST", 400);
134
- }
135
- }
136
-
137
- class InternalServerError extends BasaltError {
138
- constructor(message = "Internal Server Error") {
139
- super(message, "INTERNAL_SERVER_ERROR", 500);
140
- }
141
- }
142
-
143
- class NonRetriableError extends BasaltError {
144
- constructor(message) {
145
- super(message, "NON_RETRIABLE_ERROR", 500);
146
- }
147
- }
148
-
149
- // src/logger/pretty-print.ts
150
- var import_picocolors = __toESM(require_picocolors(), 1);
151
- var stepTag = (step) => step ? import_picocolors.default.bold(import_picocolors.default.cyan(step)) : "";
152
- var timestampTag = (timestamp) => import_picocolors.default.gray(timestamp);
153
- var traceIdTag = (traceId) => traceId ? import_picocolors.default.gray(traceId) : "";
154
- var levelTags = {
155
- error: import_picocolors.default.red("[ERROR]"),
156
- info: import_picocolors.default.blue("[INFO]"),
157
- warn: import_picocolors.default.yellow("[WARN]"),
158
- debug: import_picocolors.default.gray("[DEBUG]")
159
- };
160
- var numericTag = (value) => import_picocolors.default.green(value);
161
- var stringTag = (value) => import_picocolors.default.cyan(value);
162
- var booleanTag = (value) => import_picocolors.default.blue(value);
163
- var arrayBrackets = ["[", "]"].map((s) => import_picocolors.default.gray(s));
164
- var objectBrackets = ["{", "}"].map((s) => import_picocolors.default.gray(s));
165
- var prettyPrintObject = (obj, depth = 0, parentIsLast = false, prefix = "") => {
166
- const tab = prefix + (depth === 0 ? "" : parentIsLast ? "│ " : "│ ");
167
- if (depth > 2)
168
- return `${tab} └ ${import_picocolors.default.gray("[...]")}`;
169
- const entries = Object.entries(obj);
170
- return entries.map(([key, value], index) => {
171
- const isLast = index === entries.length - 1;
172
- const isObject = typeof value === "object" && value !== null;
173
- const branch = isLast ? "└" : "├";
174
- if (isObject) {
175
- const subObject = prettyPrintObject(value, depth + 1, isLast, tab);
176
- const [start, end] = Array.isArray(value) ? arrayBrackets : objectBrackets;
177
- return `${tab}${branch} ${key}: ${start}
178
- ${subObject}
179
- ${tab}${isLast ? " " : "│"} ${end}`;
180
- }
181
- let printedValue = value;
182
- if (typeof value === "number")
183
- printedValue = numericTag(String(value));
184
- else if (typeof value === "boolean")
185
- printedValue = booleanTag(String(value));
186
- else if (typeof value === "string")
187
- printedValue = stringTag(value);
188
- return `${tab}${branch} ${key}: ${printedValue}`;
189
- }).join(`
190
- `);
191
- };
192
- var prettyPrint = (json, excludeDetails = false) => {
193
- const { time, traceId, msg, flows, level, step, ...details } = json;
194
- const levelTag = levelTags[level] ?? levelTags.info;
195
- const timestamp = timestampTag(`[${new Date(time).toLocaleTimeString()}]`);
196
- const objectHasKeys = Object.keys(details).length > 0;
197
- process.stdout.write(`${timestamp} ${traceIdTag(traceId)} ${levelTag} ${stepTag(step)} ${msg}
198
- `);
199
- if (objectHasKeys && !excludeDetails) {
200
- process.stdout.write(`${prettyPrintObject(details)}
201
- `);
202
- }
203
- };
204
-
205
- // src/logger/logger.ts
206
- var LEVELS = {
207
- DEBUG: 10,
208
- INFO: 20,
209
- WARNING: 30,
210
- ERROR: 40,
211
- CRITICAL: 50
212
- };
213
- var levelMap = {
214
- debug: LEVELS.DEBUG,
215
- info: LEVELS.INFO,
216
- warn: LEVELS.WARNING,
217
- warning: LEVELS.WARNING,
218
- error: LEVELS.ERROR,
219
- critical: LEVELS.CRITICAL
220
- };
221
- var getLogLevel = () => {
222
- const level = process.env.LOG_LEVEL ?? "info";
223
- return levelMap[level] ?? LEVELS.INFO;
224
- };
225
- var shouldLog = (messageLevel) => {
226
- return messageLevel >= getLogLevel();
227
- };
228
-
229
- class Logger {
230
- isVerbose;
231
- meta;
232
- coreListeners;
233
- listeners = [];
234
- constructor(isVerbose = false, meta = {}, coreListeners = []) {
235
- this.isVerbose = isVerbose;
236
- this.meta = meta;
237
- this.coreListeners = coreListeners;
238
- }
239
- child(meta) {
240
- return new Logger(this.isVerbose, { ...this.meta, ...meta }, this.coreListeners);
241
- }
242
- _log(level, msg, args) {
243
- const time = Date.now();
244
- const meta = { ...this.meta, ...args ?? {} };
245
- prettyPrint({ level, time, msg, ...meta }, !this.isVerbose);
246
- this.coreListeners.forEach((listener) => {
247
- listener(level, msg, meta);
248
- });
249
- this.listeners.forEach((listener) => {
250
- listener(level, msg, meta);
251
- });
252
- }
253
- info(message, args) {
254
- if (shouldLog(LEVELS.INFO))
255
- this._log("INFO", message, args);
256
- }
257
- error(message, args) {
258
- if (shouldLog(LEVELS.ERROR))
259
- this._log("ERROR", message, args);
260
- }
261
- debug(message, args) {
262
- if (shouldLog(LEVELS.DEBUG))
263
- this._log("DEBUG", message, args);
264
- }
265
- warn(message, args) {
266
- if (shouldLog(LEVELS.WARNING))
267
- this._log("WARNING", message, args);
268
- }
269
- addListener(listener) {
270
- this.listeners.push(listener);
271
- }
272
- }
273
- var globalLogger = new Logger;
274
- export { loadConfig, defineConfig, globalLogger, BasaltError, NotFoundError, UnauthorizedError, ForbiddenError, BadRequestError, InternalServerError, NonRetriableError };