gravity-run 0.0.6 → 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 +354 -68
- package/dist/index.d.ts +44 -7
- package/dist/index.js +2 -11
- package/dist/shared/chunk-s3hrp89d.js +79 -0
- package/package.json +2 -1
- package/dist/shared/chunk-b636e30q.js +0 -274
package/dist/cli/index.js
CHANGED
|
@@ -3,9 +3,80 @@ import {
|
|
|
3
3
|
BadRequestError,
|
|
4
4
|
ForbiddenError,
|
|
5
5
|
UnauthorizedError,
|
|
6
|
-
|
|
6
|
+
__commonJS,
|
|
7
|
+
__toESM,
|
|
7
8
|
loadConfig
|
|
8
|
-
} from "../shared/chunk-
|
|
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,15 +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
|
-
async function loadActions(dir) {
|
|
431
|
+
async function loadActions(dir, logger = new Logger) {
|
|
157
432
|
const glob = new Bun.Glob(`${dir}/**/*.ts`);
|
|
158
433
|
const files = glob.scanSync();
|
|
159
|
-
|
|
434
|
+
logger.debug("Loading actions from", { files });
|
|
160
435
|
const actions = [];
|
|
161
436
|
for (const file of files) {
|
|
162
437
|
const module = await import(Bun.pathToFileURL(file).href);
|
|
163
|
-
|
|
438
|
+
logger.debug("Loading action", { file });
|
|
164
439
|
for (const exported of Object.values(module)) {
|
|
165
440
|
if (isAction(exported)) {
|
|
166
441
|
actions.push(exported);
|
|
@@ -181,34 +456,34 @@ class ActionExecutor {
|
|
|
181
456
|
this.baseContext = baseContext;
|
|
182
457
|
}
|
|
183
458
|
async execute(action, triggerName, sourceData) {
|
|
459
|
+
const traceId = Bun.randomUUIDv7();
|
|
184
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
|
+
});
|
|
185
467
|
const trigger = config.triggers?.find((t) => t.name === triggerName);
|
|
186
468
|
if (!trigger) {
|
|
187
469
|
throw new BadRequestError(`Trigger '${triggerName}' not found for action '${config.name}'`);
|
|
188
470
|
}
|
|
189
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();
|
|
190
474
|
const ctx = {
|
|
191
|
-
|
|
475
|
+
traceId,
|
|
192
476
|
triggerName,
|
|
193
477
|
triggerType: trigger.kind,
|
|
194
478
|
actor,
|
|
195
|
-
logger
|
|
479
|
+
logger,
|
|
196
480
|
db: this.baseContext.db,
|
|
197
481
|
storage: this.baseContext.storage,
|
|
198
|
-
enqueue: this.baseContext.enqueue || this.createEnqueueFn(),
|
|
199
|
-
schedule: this.baseContext.schedule || this.createScheduleFn(),
|
|
482
|
+
enqueue: this.baseContext.enqueue || this.createEnqueueFn(logger),
|
|
483
|
+
schedule: this.baseContext.schedule || this.createScheduleFn(logger),
|
|
200
484
|
org: this.baseContext.org,
|
|
201
485
|
...this.baseContext
|
|
202
486
|
};
|
|
203
|
-
const logger = ctx.logger.child({
|
|
204
|
-
action: config.name,
|
|
205
|
-
requestId: ctx.requestId,
|
|
206
|
-
trigger: triggerName
|
|
207
|
-
});
|
|
208
|
-
logger.info("Action execution started", {
|
|
209
|
-
actor: actor.type,
|
|
210
|
-
triggerType: trigger.kind
|
|
211
|
-
});
|
|
212
487
|
try {
|
|
213
488
|
let input = sourceData;
|
|
214
489
|
if (trigger.map) {
|
|
@@ -220,17 +495,21 @@ class ActionExecutor {
|
|
|
220
495
|
}
|
|
221
496
|
await this.checkRateLimit(ctx, config);
|
|
222
497
|
if (config.access) {
|
|
498
|
+
session.step("Access", "checking...");
|
|
223
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");
|
|
224
506
|
}
|
|
225
|
-
await this.checkGuard(ctx, input, config);
|
|
226
507
|
const result = await action(input, ctx);
|
|
227
|
-
|
|
508
|
+
session.end("Success");
|
|
228
509
|
return result;
|
|
229
510
|
} catch (error) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
stack: error.stack
|
|
233
|
-
});
|
|
511
|
+
session.error("Error", error.message);
|
|
512
|
+
session.fail("Failed");
|
|
234
513
|
throw error;
|
|
235
514
|
}
|
|
236
515
|
}
|
|
@@ -314,17 +593,17 @@ class ActionExecutor {
|
|
|
314
593
|
}
|
|
315
594
|
}
|
|
316
595
|
}
|
|
317
|
-
createEnqueueFn() {
|
|
596
|
+
createEnqueueFn(logger) {
|
|
318
597
|
return async (eventType, data) => {
|
|
319
|
-
|
|
598
|
+
logger.warn("enqueue called but no event bus configured", {
|
|
320
599
|
eventType,
|
|
321
600
|
data
|
|
322
601
|
});
|
|
323
602
|
};
|
|
324
603
|
}
|
|
325
|
-
createScheduleFn() {
|
|
604
|
+
createScheduleFn(logger) {
|
|
326
605
|
return async (actionName, input, runAt) => {
|
|
327
|
-
|
|
606
|
+
logger.warn("schedule called but no scheduler configured", {
|
|
328
607
|
actionName,
|
|
329
608
|
runAt,
|
|
330
609
|
input
|
|
@@ -337,8 +616,10 @@ class ActionExecutor {
|
|
|
337
616
|
class EventBus {
|
|
338
617
|
subscriptions = [];
|
|
339
618
|
executor;
|
|
619
|
+
logger;
|
|
340
620
|
constructor(baseContext) {
|
|
341
621
|
this.executor = new ActionExecutor(baseContext);
|
|
622
|
+
this.logger = baseContext.logger;
|
|
342
623
|
}
|
|
343
624
|
subscribe(pattern, action, triggerName) {
|
|
344
625
|
this.subscriptions.push({ pattern, action, triggerName });
|
|
@@ -346,14 +627,14 @@ class EventBus {
|
|
|
346
627
|
async publish(event) {
|
|
347
628
|
const matching = this.subscriptions.filter((sub) => this.matchPattern(sub.pattern, event.type));
|
|
348
629
|
if (matching.length === 0) {
|
|
349
|
-
|
|
630
|
+
this.logger.debug("No subscribers for event", { eventType: event.type });
|
|
350
631
|
return;
|
|
351
632
|
}
|
|
352
633
|
const results = await Promise.allSettled(matching.map(async (sub) => {
|
|
353
634
|
try {
|
|
354
635
|
return await this.executor.execute(sub.action, sub.triggerName, event);
|
|
355
636
|
} catch (error) {
|
|
356
|
-
|
|
637
|
+
this.logger.error("Event handler failed", {
|
|
357
638
|
event: event.type,
|
|
358
639
|
action: sub.action.config.name,
|
|
359
640
|
error: error.message
|
|
@@ -363,7 +644,7 @@ class EventBus {
|
|
|
363
644
|
}));
|
|
364
645
|
const failed = results.filter((r) => r.status === "rejected").length;
|
|
365
646
|
const succeeded = results.filter((r) => r.status === "fulfilled").length;
|
|
366
|
-
|
|
647
|
+
this.logger.info("Event published", {
|
|
367
648
|
event: event.type,
|
|
368
649
|
handlers: matching.length,
|
|
369
650
|
succeeded,
|
|
@@ -379,10 +660,12 @@ class EventBus {
|
|
|
379
660
|
// src/runtime/http.ts
|
|
380
661
|
class HttpServer {
|
|
381
662
|
config;
|
|
663
|
+
logger;
|
|
382
664
|
server;
|
|
383
665
|
router;
|
|
384
|
-
constructor(config, router) {
|
|
666
|
+
constructor(config, router, logger = new Logger) {
|
|
385
667
|
this.config = config;
|
|
668
|
+
this.logger = logger;
|
|
386
669
|
this.router = router;
|
|
387
670
|
}
|
|
388
671
|
async start() {
|
|
@@ -410,10 +693,10 @@ class HttpServer {
|
|
|
410
693
|
body = await req.json();
|
|
411
694
|
} else if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
412
695
|
const formData = await req.formData();
|
|
413
|
-
body = Object.fromEntries(formData);
|
|
696
|
+
body = Object.fromEntries(formData.entries());
|
|
414
697
|
} else if (contentType.includes("multipart/form-data")) {
|
|
415
698
|
const formData = await req.formData();
|
|
416
|
-
body = Object.fromEntries(formData);
|
|
699
|
+
body = Object.fromEntries(formData.entries());
|
|
417
700
|
} else {
|
|
418
701
|
body = await req.text();
|
|
419
702
|
}
|
|
@@ -444,7 +727,7 @@ class HttpServer {
|
|
|
444
727
|
}
|
|
445
728
|
});
|
|
446
729
|
} catch (error) {
|
|
447
|
-
|
|
730
|
+
this.logger.error("HTTP request failed", {
|
|
448
731
|
error: error.message,
|
|
449
732
|
stack: error.stack
|
|
450
733
|
});
|
|
@@ -472,8 +755,8 @@ class HttpServer {
|
|
|
472
755
|
});
|
|
473
756
|
}
|
|
474
757
|
},
|
|
475
|
-
error(error) {
|
|
476
|
-
|
|
758
|
+
error: (error) => {
|
|
759
|
+
this.logger.error("HTTP server error", {
|
|
477
760
|
error: error.message,
|
|
478
761
|
stack: error.stack
|
|
479
762
|
});
|
|
@@ -485,14 +768,14 @@ class HttpServer {
|
|
|
485
768
|
});
|
|
486
769
|
}
|
|
487
770
|
});
|
|
488
|
-
|
|
771
|
+
this.logger.info("HTTP server started", {
|
|
489
772
|
url: `http://${host}:${port}`
|
|
490
773
|
});
|
|
491
774
|
}
|
|
492
775
|
async stop() {
|
|
493
776
|
if (this.server) {
|
|
494
777
|
this.server.stop();
|
|
495
|
-
|
|
778
|
+
this.logger.info("HTTP server stopped");
|
|
496
779
|
}
|
|
497
780
|
}
|
|
498
781
|
getUrl() {
|
|
@@ -520,21 +803,23 @@ function getCorsHeaders(corsConfig) {
|
|
|
520
803
|
// src/runtime/mcp-server.ts
|
|
521
804
|
class McpServer {
|
|
522
805
|
context;
|
|
523
|
-
|
|
806
|
+
logger;
|
|
807
|
+
constructor(context, logger = new Logger) {
|
|
524
808
|
this.context = context;
|
|
809
|
+
this.logger = logger;
|
|
525
810
|
}
|
|
526
811
|
register(action, trigger) {
|
|
527
|
-
|
|
812
|
+
this.logger.info("Registering MCP tool", {
|
|
528
813
|
tool: trigger.tool,
|
|
529
814
|
action: action.config.name,
|
|
530
815
|
context: this.context
|
|
531
816
|
});
|
|
532
817
|
}
|
|
533
818
|
async start() {
|
|
534
|
-
|
|
819
|
+
this.logger.info("MCP Server started");
|
|
535
820
|
}
|
|
536
821
|
async stop() {
|
|
537
|
-
|
|
822
|
+
this.logger.info("MCP Server stopped");
|
|
538
823
|
}
|
|
539
824
|
}
|
|
540
825
|
|
|
@@ -588,11 +873,7 @@ class Router {
|
|
|
588
873
|
};
|
|
589
874
|
}
|
|
590
875
|
getRoutes() {
|
|
591
|
-
return this.routes
|
|
592
|
-
method: r.method,
|
|
593
|
-
path: r.trigger.path,
|
|
594
|
-
action: r.action.config.name
|
|
595
|
-
}));
|
|
876
|
+
return this.routes;
|
|
596
877
|
}
|
|
597
878
|
}
|
|
598
879
|
|
|
@@ -601,8 +882,10 @@ import Baker from "cronbake";
|
|
|
601
882
|
class Scheduler {
|
|
602
883
|
baker = Baker.create();
|
|
603
884
|
executor;
|
|
885
|
+
logger;
|
|
604
886
|
constructor(baseContext) {
|
|
605
887
|
this.executor = new ActionExecutor(baseContext);
|
|
888
|
+
this.logger = baseContext.logger;
|
|
606
889
|
}
|
|
607
890
|
schedule(action, trigger) {
|
|
608
891
|
this.baker.add({
|
|
@@ -610,13 +893,13 @@ class Scheduler {
|
|
|
610
893
|
cron: trigger.schedule,
|
|
611
894
|
callback: async () => {
|
|
612
895
|
try {
|
|
613
|
-
|
|
896
|
+
this.logger.info("Running scheduled action", {
|
|
614
897
|
action: action.config.name,
|
|
615
898
|
schedule: trigger.schedule
|
|
616
899
|
});
|
|
617
900
|
await this.executor.execute(action, trigger.name, {});
|
|
618
901
|
} catch (error) {
|
|
619
|
-
|
|
902
|
+
this.logger.error("Scheduled action failed", {
|
|
620
903
|
action: action.config.name,
|
|
621
904
|
error: error.message,
|
|
622
905
|
stack: error.stack
|
|
@@ -627,11 +910,11 @@ class Scheduler {
|
|
|
627
910
|
}
|
|
628
911
|
start() {
|
|
629
912
|
this.baker.bakeAll();
|
|
630
|
-
|
|
913
|
+
this.logger.info("Scheduler started");
|
|
631
914
|
}
|
|
632
915
|
stop() {
|
|
633
916
|
this.baker.stopAll();
|
|
634
|
-
|
|
917
|
+
this.logger.info("Stopped all cron jobs");
|
|
635
918
|
}
|
|
636
919
|
}
|
|
637
920
|
|
|
@@ -643,21 +926,23 @@ class BasaltServer {
|
|
|
643
926
|
scheduler;
|
|
644
927
|
mcpServer;
|
|
645
928
|
httpServer;
|
|
929
|
+
logger;
|
|
646
930
|
actions = [];
|
|
647
931
|
constructor(config) {
|
|
648
932
|
this.config = config;
|
|
933
|
+
this.logger = new Logger(config.logger ?? {});
|
|
649
934
|
const baseContext = this.buildBaseContext();
|
|
650
935
|
this.router = new Router(baseContext);
|
|
651
936
|
this.eventBus = new EventBus(baseContext);
|
|
652
937
|
this.scheduler = new Scheduler(baseContext);
|
|
653
|
-
this.httpServer = new HttpServer(this.config, this.router);
|
|
938
|
+
this.httpServer = new HttpServer(this.config, this.router, this.logger);
|
|
654
939
|
if (this.config.mcp?.enabled) {
|
|
655
|
-
this.mcpServer = new McpServer(baseContext);
|
|
940
|
+
this.mcpServer = new McpServer(baseContext, this.logger);
|
|
656
941
|
}
|
|
657
942
|
}
|
|
658
943
|
buildBaseContext() {
|
|
659
944
|
return {
|
|
660
|
-
logger:
|
|
945
|
+
logger: this.logger,
|
|
661
946
|
db: undefined,
|
|
662
947
|
storage: undefined,
|
|
663
948
|
enqueue: async (eventType, data) => {
|
|
@@ -678,11 +963,11 @@ class BasaltServer {
|
|
|
678
963
|
const actionName = action.config.name;
|
|
679
964
|
if (typeof when === "number") {
|
|
680
965
|
const runAt = new Date(Date.now() + when * 1000);
|
|
681
|
-
|
|
966
|
+
this.logger.info("Scheduling action", { actionName, runAt, input });
|
|
682
967
|
} else if (when instanceof Date) {
|
|
683
|
-
|
|
968
|
+
this.logger.info("Scheduling action", { actionName, runAt: when, input });
|
|
684
969
|
} else if (typeof when === "string") {
|
|
685
|
-
|
|
970
|
+
this.logger.info("Scheduling recurring action", {
|
|
686
971
|
actionName,
|
|
687
972
|
cron: when,
|
|
688
973
|
input
|
|
@@ -690,7 +975,7 @@ class BasaltServer {
|
|
|
690
975
|
}
|
|
691
976
|
}
|
|
692
977
|
async initialize() {
|
|
693
|
-
this.actions = await loadActions(this.config.actionsDir || "./src/actions");
|
|
978
|
+
this.actions = await loadActions(this.config.actionsDir || "./src/actions", this.logger);
|
|
694
979
|
for (const action of this.actions) {
|
|
695
980
|
if (!action.config.triggers)
|
|
696
981
|
continue;
|
|
@@ -699,7 +984,7 @@ class BasaltServer {
|
|
|
699
984
|
case "api": {
|
|
700
985
|
const apiTrigger = trigger;
|
|
701
986
|
this.router.register(action, apiTrigger);
|
|
702
|
-
|
|
987
|
+
this.logger.info("Registered API route", {
|
|
703
988
|
method: apiTrigger.method,
|
|
704
989
|
path: apiTrigger.path,
|
|
705
990
|
action: action.config.name
|
|
@@ -709,7 +994,7 @@ class BasaltServer {
|
|
|
709
994
|
case "cron": {
|
|
710
995
|
const cronTrigger = trigger;
|
|
711
996
|
this.scheduler.schedule(action, cronTrigger);
|
|
712
|
-
|
|
997
|
+
this.logger.info("Registered cron job", {
|
|
713
998
|
schedule: cronTrigger.schedule,
|
|
714
999
|
action: action.config.name
|
|
715
1000
|
});
|
|
@@ -718,7 +1003,7 @@ class BasaltServer {
|
|
|
718
1003
|
case "event": {
|
|
719
1004
|
const eventTrigger = trigger;
|
|
720
1005
|
this.eventBus.subscribe(eventTrigger.event, action, eventTrigger.name);
|
|
721
|
-
|
|
1006
|
+
this.logger.info("Registered event handler", {
|
|
722
1007
|
event: eventTrigger.event,
|
|
723
1008
|
action: action.config.name
|
|
724
1009
|
});
|
|
@@ -727,7 +1012,7 @@ class BasaltServer {
|
|
|
727
1012
|
case "agent": {
|
|
728
1013
|
const agentTrigger = trigger;
|
|
729
1014
|
this.mcpServer?.register(action, agentTrigger);
|
|
730
|
-
|
|
1015
|
+
this.logger.info("Registered MCP tool", {
|
|
731
1016
|
tool: agentTrigger.tool,
|
|
732
1017
|
action: action.config.name
|
|
733
1018
|
});
|
|
@@ -736,7 +1021,7 @@ class BasaltServer {
|
|
|
736
1021
|
}
|
|
737
1022
|
}
|
|
738
1023
|
}
|
|
739
|
-
|
|
1024
|
+
this.logger.info("Basalt initialized", {
|
|
740
1025
|
actions: this.actions.length,
|
|
741
1026
|
routes: this.router.getRoutes().length
|
|
742
1027
|
});
|
|
@@ -769,6 +1054,7 @@ class BasaltServer {
|
|
|
769
1054
|
|
|
770
1055
|
// src/runtime/dev.ts
|
|
771
1056
|
async function createDevServer(config) {
|
|
1057
|
+
const logger = new Logger(config.logger ?? {});
|
|
772
1058
|
const server = new BasaltServer(config);
|
|
773
1059
|
await server.initialize();
|
|
774
1060
|
if (config.dev?.watch !== false) {
|
|
@@ -778,16 +1064,16 @@ async function createDevServer(config) {
|
|
|
778
1064
|
return;
|
|
779
1065
|
if (!/\.(ts|js)$/.test(filename))
|
|
780
1066
|
return;
|
|
781
|
-
|
|
1067
|
+
logger.info("Action file changed, regenerating...", {
|
|
782
1068
|
filename,
|
|
783
1069
|
eventType
|
|
784
1070
|
});
|
|
785
1071
|
try {
|
|
786
|
-
const actions = await loadActions(actionsDir);
|
|
1072
|
+
const actions = await loadActions(actionsDir, logger);
|
|
787
1073
|
await generateActionTypes(actions);
|
|
788
|
-
|
|
1074
|
+
logger.info("Types regenerated");
|
|
789
1075
|
} catch (error) {
|
|
790
|
-
|
|
1076
|
+
logger.error("Failed to regenerate types", {
|
|
791
1077
|
error: error.message
|
|
792
1078
|
});
|
|
793
1079
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
type DatabaseConfig = {};
|
|
2
|
-
type
|
|
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
|
|
87
|
-
type LogListener = (level:
|
|
118
|
+
type LogLevel2 = keyof typeof LEVELS;
|
|
119
|
+
type LogListener = (level: LogLevel2, msg: string, args?: unknown) => void;
|
|
88
120
|
declare class Logger {
|
|
89
|
-
readonly
|
|
121
|
+
private readonly options;
|
|
90
122
|
private readonly meta;
|
|
91
123
|
private readonly coreListeners;
|
|
92
124
|
private readonly listeners;
|
|
93
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
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.
|
|
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 };
|