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 +357 -73
- 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,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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
475
|
+
traceId,
|
|
194
476
|
triggerName,
|
|
195
477
|
triggerType: trigger.kind,
|
|
196
478
|
actor,
|
|
197
|
-
logger
|
|
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
|
-
|
|
508
|
+
session.end("Success");
|
|
230
509
|
return result;
|
|
231
510
|
} catch (error) {
|
|
232
|
-
|
|
233
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
819
|
+
this.logger.info("MCP Server started");
|
|
537
820
|
}
|
|
538
821
|
async stop() {
|
|
539
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
913
|
+
this.logger.info("Scheduler started");
|
|
633
914
|
}
|
|
634
915
|
stop() {
|
|
635
916
|
this.baker.stopAll();
|
|
636
|
-
|
|
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:
|
|
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
|
-
|
|
966
|
+
this.logger.info("Scheduling action", { actionName, runAt, input });
|
|
684
967
|
} else if (when instanceof Date) {
|
|
685
|
-
|
|
968
|
+
this.logger.info("Scheduling action", { actionName, runAt: when, input });
|
|
686
969
|
} else if (typeof when === "string") {
|
|
687
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1074
|
+
logger.info("Types regenerated");
|
|
791
1075
|
} catch (error) {
|
|
792
|
-
|
|
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
|
|
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 };
|