legonode 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -0
- package/dist/cli/cli.d.ts +3 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +44 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/commands/build.d.ts +8 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +101 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +13 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +285 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/start.d.ts +10 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +108 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/pluginHooks.d.ts +5 -0
- package/dist/cli/pluginHooks.d.ts.map +1 -0
- package/dist/cli/pluginHooks.js +11 -0
- package/dist/cli/pluginHooks.js.map +1 -0
- package/dist/src/body/parseBody.d.ts +11 -0
- package/dist/src/body/parseBody.d.ts.map +1 -0
- package/dist/src/body/parseBody.js +113 -0
- package/dist/src/body/parseBody.js.map +1 -0
- package/dist/src/config/loadConfig.d.ts +71 -0
- package/dist/src/config/loadConfig.d.ts.map +1 -0
- package/dist/src/config/loadConfig.js +69 -0
- package/dist/src/config/loadConfig.js.map +1 -0
- package/dist/src/core/context.d.ts +139 -0
- package/dist/src/core/context.d.ts.map +1 -0
- package/dist/src/core/context.js +293 -0
- package/dist/src/core/context.js.map +1 -0
- package/dist/src/core/lifecycle.d.ts +3 -0
- package/dist/src/core/lifecycle.d.ts.map +1 -0
- package/dist/src/core/lifecycle.js +14 -0
- package/dist/src/core/lifecycle.js.map +1 -0
- package/dist/src/core/runtime.d.ts +28 -0
- package/dist/src/core/runtime.d.ts.map +1 -0
- package/dist/src/core/runtime.js +104 -0
- package/dist/src/core/runtime.js.map +1 -0
- package/dist/src/cors/cors.d.ts +5 -0
- package/dist/src/cors/cors.d.ts.map +1 -0
- package/dist/src/cors/cors.js +75 -0
- package/dist/src/cors/cors.js.map +1 -0
- package/dist/src/events/eventBus.d.ts +19 -0
- package/dist/src/events/eventBus.d.ts.map +1 -0
- package/dist/src/events/eventBus.js +29 -0
- package/dist/src/events/eventBus.js.map +1 -0
- package/dist/src/events/eventExecutor.d.ts +5 -0
- package/dist/src/events/eventExecutor.d.ts.map +1 -0
- package/dist/src/events/eventExecutor.js +84 -0
- package/dist/src/events/eventExecutor.js.map +1 -0
- package/dist/src/index.d.ts +23 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +13 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/json/fastStringify.d.ts +7 -0
- package/dist/src/json/fastStringify.d.ts.map +1 -0
- package/dist/src/json/fastStringify.js +73 -0
- package/dist/src/json/fastStringify.js.map +1 -0
- package/dist/src/loader/fileScanner.d.ts +18 -0
- package/dist/src/loader/fileScanner.d.ts.map +1 -0
- package/dist/src/loader/fileScanner.js +133 -0
- package/dist/src/loader/fileScanner.js.map +1 -0
- package/dist/src/loader/moduleCache.d.ts +3 -0
- package/dist/src/loader/moduleCache.d.ts.map +1 -0
- package/dist/src/loader/moduleCache.js +19 -0
- package/dist/src/loader/moduleCache.js.map +1 -0
- package/dist/src/loader/moduleLoader.d.ts +2 -0
- package/dist/src/loader/moduleLoader.d.ts.map +1 -0
- package/dist/src/loader/moduleLoader.js +4 -0
- package/dist/src/loader/moduleLoader.js.map +1 -0
- package/dist/src/logger/requestLogger.d.ts +20 -0
- package/dist/src/logger/requestLogger.d.ts.map +1 -0
- package/dist/src/logger/requestLogger.js +63 -0
- package/dist/src/logger/requestLogger.js.map +1 -0
- package/dist/src/middleware/middlewareLoader.d.ts +3 -0
- package/dist/src/middleware/middlewareLoader.d.ts.map +1 -0
- package/dist/src/middleware/middlewareLoader.js +28 -0
- package/dist/src/middleware/middlewareLoader.js.map +1 -0
- package/dist/src/middleware/middlewareResolver.d.ts +13 -0
- package/dist/src/middleware/middlewareResolver.d.ts.map +1 -0
- package/dist/src/middleware/middlewareResolver.js +72 -0
- package/dist/src/middleware/middlewareResolver.js.map +1 -0
- package/dist/src/middleware/middlewareRunner.d.ts +10 -0
- package/dist/src/middleware/middlewareRunner.d.ts.map +1 -0
- package/dist/src/middleware/middlewareRunner.js +27 -0
- package/dist/src/middleware/middlewareRunner.js.map +1 -0
- package/dist/src/middleware/middlewareTable.d.ts +6 -0
- package/dist/src/middleware/middlewareTable.d.ts.map +1 -0
- package/dist/src/middleware/middlewareTable.js +44 -0
- package/dist/src/middleware/middlewareTable.js.map +1 -0
- package/dist/src/pipeline/compose.d.ts +10 -0
- package/dist/src/pipeline/compose.d.ts.map +1 -0
- package/dist/src/pipeline/compose.js +35 -0
- package/dist/src/pipeline/compose.js.map +1 -0
- package/dist/src/pipeline/pipelineCache.d.ts +16 -0
- package/dist/src/pipeline/pipelineCache.d.ts.map +1 -0
- package/dist/src/pipeline/pipelineCache.js +73 -0
- package/dist/src/pipeline/pipelineCache.js.map +1 -0
- package/dist/src/plugin/pluginAPI.d.ts +63 -0
- package/dist/src/plugin/pluginAPI.d.ts.map +1 -0
- package/dist/src/plugin/pluginAPI.js +2 -0
- package/dist/src/plugin/pluginAPI.js.map +1 -0
- package/dist/src/plugin/pluginManager.d.ts +6 -0
- package/dist/src/plugin/pluginManager.d.ts.map +1 -0
- package/dist/src/plugin/pluginManager.js +16 -0
- package/dist/src/plugin/pluginManager.js.map +1 -0
- package/dist/src/router/matcher.d.ts +10 -0
- package/dist/src/router/matcher.d.ts.map +1 -0
- package/dist/src/router/matcher.js +69 -0
- package/dist/src/router/matcher.js.map +1 -0
- package/dist/src/router/radixTree.d.ts +24 -0
- package/dist/src/router/radixTree.d.ts.map +1 -0
- package/dist/src/router/radixTree.js +208 -0
- package/dist/src/router/radixTree.js.map +1 -0
- package/dist/src/router/routeLoader.d.ts +22 -0
- package/dist/src/router/routeLoader.d.ts.map +1 -0
- package/dist/src/router/routeLoader.js +94 -0
- package/dist/src/router/routeLoader.js.map +1 -0
- package/dist/src/router/routeTable.d.ts +25 -0
- package/dist/src/router/routeTable.d.ts.map +1 -0
- package/dist/src/router/routeTable.js +133 -0
- package/dist/src/router/routeTable.js.map +1 -0
- package/dist/src/router/router.d.ts +18 -0
- package/dist/src/router/router.d.ts.map +1 -0
- package/dist/src/router/router.js +158 -0
- package/dist/src/router/router.js.map +1 -0
- package/dist/src/schedules/parseSchedule.d.ts +15 -0
- package/dist/src/schedules/parseSchedule.d.ts.map +1 -0
- package/dist/src/schedules/parseSchedule.js +111 -0
- package/dist/src/schedules/parseSchedule.js.map +1 -0
- package/dist/src/schedules/runScheduler.d.ts +14 -0
- package/dist/src/schedules/runScheduler.d.ts.map +1 -0
- package/dist/src/schedules/runScheduler.js +58 -0
- package/dist/src/schedules/runScheduler.js.map +1 -0
- package/dist/src/schedules/scheduleLoader.d.ts +14 -0
- package/dist/src/schedules/scheduleLoader.d.ts.map +1 -0
- package/dist/src/schedules/scheduleLoader.js +122 -0
- package/dist/src/schedules/scheduleLoader.js.map +1 -0
- package/dist/src/schedules/types.d.ts +37 -0
- package/dist/src/schedules/types.d.ts.map +1 -0
- package/dist/src/schedules/types.js +2 -0
- package/dist/src/schedules/types.js.map +1 -0
- package/dist/src/server/errorHandler.d.ts +4 -0
- package/dist/src/server/errorHandler.d.ts.map +1 -0
- package/dist/src/server/errorHandler.js +10 -0
- package/dist/src/server/errorHandler.js.map +1 -0
- package/dist/src/server/requestHandler.d.ts +35 -0
- package/dist/src/server/requestHandler.d.ts.map +1 -0
- package/dist/src/server/requestHandler.js +439 -0
- package/dist/src/server/requestHandler.js.map +1 -0
- package/dist/src/server/server.d.ts +20 -0
- package/dist/src/server/server.d.ts.map +1 -0
- package/dist/src/server/server.js +74 -0
- package/dist/src/server/server.js.map +1 -0
- package/dist/src/tasks/scheduler.d.ts +10 -0
- package/dist/src/tasks/scheduler.d.ts.map +1 -0
- package/dist/src/tasks/scheduler.js +10 -0
- package/dist/src/tasks/scheduler.js.map +1 -0
- package/dist/src/tasks/taskRunner.d.ts +3 -0
- package/dist/src/tasks/taskRunner.d.ts.map +1 -0
- package/dist/src/tasks/taskRunner.js +4 -0
- package/dist/src/tasks/taskRunner.js.map +1 -0
- package/dist/src/trace/traceEngine.d.ts +45 -0
- package/dist/src/trace/traceEngine.d.ts.map +1 -0
- package/dist/src/trace/traceEngine.js +63 -0
- package/dist/src/trace/traceEngine.js.map +1 -0
- package/dist/src/trace/traceStore.d.ts +10 -0
- package/dist/src/trace/traceStore.d.ts.map +1 -0
- package/dist/src/trace/traceStore.js +10 -0
- package/dist/src/trace/traceStore.js.map +1 -0
- package/dist/src/utils/logger.d.ts +6 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +21 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/path.d.ts +2 -0
- package/dist/src/utils/path.d.ts.map +1 -0
- package/dist/src/utils/path.js +4 -0
- package/dist/src/utils/path.js.map +1 -0
- package/dist/src/validation/routeSchema.d.ts +77 -0
- package/dist/src/validation/routeSchema.d.ts.map +1 -0
- package/dist/src/validation/routeSchema.js +134 -0
- package/dist/src/validation/routeSchema.js.map +1 -0
- package/dist/src/validation/validateApp.d.ts +20 -0
- package/dist/src/validation/validateApp.d.ts.map +1 -0
- package/dist/src/validation/validateApp.js +23 -0
- package/dist/src/validation/validateApp.js.map +1 -0
- package/dist/src/validation/validateBody.d.ts +7 -0
- package/dist/src/validation/validateBody.d.ts.map +1 -0
- package/dist/src/validation/validateBody.js +8 -0
- package/dist/src/validation/validateBody.js.map +1 -0
- package/package.json +31 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taskRunner.js","sourceRoot":"","sources":["../../../src/tasks/taskRunner.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAmB;IAC/C,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Data passed when a request span starts. Log as [datetime][traceId] method pathname. */
|
|
2
|
+
export type TraceStartData = {
|
|
3
|
+
traceId: string;
|
|
4
|
+
method: string;
|
|
5
|
+
pathname: string;
|
|
6
|
+
startTime: string;
|
|
7
|
+
};
|
|
8
|
+
/** Data recorded for one request span. Passed to the tracer callback on span end. */
|
|
9
|
+
export type TraceData = {
|
|
10
|
+
/** Unique id for this request. One per request; use to correlate logs and tracer output. */
|
|
11
|
+
traceId: string;
|
|
12
|
+
/** HTTP method (e.g. GET, POST). */
|
|
13
|
+
method: string;
|
|
14
|
+
/** Request pathname. */
|
|
15
|
+
pathname: string;
|
|
16
|
+
/** Resolved route id (e.g. /api/users) or undefined if no route matched. */
|
|
17
|
+
routeId?: string;
|
|
18
|
+
/** Response status code. */
|
|
19
|
+
statusCode?: number;
|
|
20
|
+
/** Response body size in bytes (when sent via ctx.res or return). */
|
|
21
|
+
responseSize?: number;
|
|
22
|
+
/** Span duration in milliseconds. */
|
|
23
|
+
durationMs: number;
|
|
24
|
+
/** Start time (ISO string). */
|
|
25
|
+
startTime: string;
|
|
26
|
+
/** End time (ISO string). */
|
|
27
|
+
endTime: string;
|
|
28
|
+
/** Optional error message when handler threw. */
|
|
29
|
+
error?: string;
|
|
30
|
+
/** Custom annotations (set internally by framework from request lifecycle). */
|
|
31
|
+
annotations: Record<string, unknown>;
|
|
32
|
+
};
|
|
33
|
+
export type TracerFn = (data: TraceData) => void;
|
|
34
|
+
export type TraceStartFn = (data: TraceStartData) => void;
|
|
35
|
+
export type TraceSpan = {
|
|
36
|
+
/** Unique id for this request. One per request; use in logs and response headers. */
|
|
37
|
+
readonly traceId: string;
|
|
38
|
+
start: (meta?: Record<string, unknown>) => void;
|
|
39
|
+
annotate: (key: string, value: unknown) => void;
|
|
40
|
+
end: () => void;
|
|
41
|
+
};
|
|
42
|
+
/** Shared no-op span when tracing is disabled; avoids per-request allocation and UUID. */
|
|
43
|
+
export declare const NOOP_TRACE: TraceSpan;
|
|
44
|
+
export declare function createTraceSpan(tracer?: TracerFn, traceStart?: TraceStartFn): TraceSpan;
|
|
45
|
+
//# sourceMappingURL=traceEngine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceEngine.d.ts","sourceRoot":"","sources":["../../../src/trace/traceEngine.ts"],"names":[],"mappings":"AAEA,0FAA0F;AAC1F,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qFAAqF;AACrF,MAAM,MAAM,SAAS,GAAG;IACtB,4FAA4F;IAC5F,OAAO,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;AACjD,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;AAE1D,MAAM,MAAM,SAAS,GAAG;IACtB,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAChD,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,UAAU,EAAE,SAOxB,CAAC;AAEF,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,YAAY,GAAG,SAAS,CAyDvF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
/** Shared no-op span when tracing is disabled; avoids per-request allocation and UUID. */
|
|
3
|
+
export const NOOP_TRACE = {
|
|
4
|
+
get traceId() {
|
|
5
|
+
return "";
|
|
6
|
+
},
|
|
7
|
+
start: () => { },
|
|
8
|
+
annotate: () => { },
|
|
9
|
+
end: () => { }
|
|
10
|
+
};
|
|
11
|
+
export function createTraceSpan(tracer, traceStart) {
|
|
12
|
+
if (tracer === undefined && traceStart === undefined)
|
|
13
|
+
return NOOP_TRACE;
|
|
14
|
+
const traceId = randomUUID();
|
|
15
|
+
let startTime = null;
|
|
16
|
+
const annotations = {};
|
|
17
|
+
let initialMeta = {};
|
|
18
|
+
return {
|
|
19
|
+
get traceId() {
|
|
20
|
+
return traceId;
|
|
21
|
+
},
|
|
22
|
+
start(meta) {
|
|
23
|
+
startTime = Date.now();
|
|
24
|
+
initialMeta = meta ?? {};
|
|
25
|
+
const method = meta?.method ?? "GET";
|
|
26
|
+
const pathname = meta?.pathname ?? "";
|
|
27
|
+
traceStart?.({
|
|
28
|
+
traceId,
|
|
29
|
+
method,
|
|
30
|
+
pathname,
|
|
31
|
+
startTime: new Date(startTime).toISOString(),
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
annotate(key, value) {
|
|
35
|
+
annotations[key] = value;
|
|
36
|
+
},
|
|
37
|
+
end() {
|
|
38
|
+
const endTime = Date.now();
|
|
39
|
+
const start = startTime ?? endTime;
|
|
40
|
+
const durationMs = endTime - start;
|
|
41
|
+
const routeId = annotations.routeId;
|
|
42
|
+
const statusCode = annotations.statusCode;
|
|
43
|
+
const error = annotations.error;
|
|
44
|
+
const responseSize = annotations.responseSize;
|
|
45
|
+
const data = {
|
|
46
|
+
traceId,
|
|
47
|
+
...initialMeta,
|
|
48
|
+
method: initialMeta.method ?? "GET",
|
|
49
|
+
pathname: initialMeta.pathname ?? "",
|
|
50
|
+
durationMs,
|
|
51
|
+
startTime: new Date(start).toISOString(),
|
|
52
|
+
endTime: new Date(endTime).toISOString(),
|
|
53
|
+
annotations: { ...annotations },
|
|
54
|
+
...(routeId !== undefined && routeId !== null && { routeId }),
|
|
55
|
+
...(statusCode !== undefined && statusCode !== null && { statusCode }),
|
|
56
|
+
...(responseSize !== undefined && responseSize !== null && { responseSize }),
|
|
57
|
+
...(error !== undefined && error !== null && { error }),
|
|
58
|
+
};
|
|
59
|
+
tracer?.(data);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=traceEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceEngine.js","sourceRoot":"","sources":["../../../src/trace/traceEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA+CzC,0FAA0F;AAC1F,MAAM,CAAC,MAAM,UAAU,GAAc;IACnC,IAAI,OAAO;QACT,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;IACf,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC;IAClB,GAAG,EAAE,GAAG,EAAE,GAAE,CAAC;CACd,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,MAAiB,EAAE,UAAyB;IAC1E,IAAI,MAAM,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC;IACxE,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,MAAM,WAAW,GAA4B,EAAE,CAAC;IAChD,IAAI,WAAW,GAA4B,EAAE,CAAC;IAE9C,OAAO;QACL,IAAI,OAAO;YACT,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,KAAK,CAAC,IAA8B;YAClC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC;YACzB,MAAM,MAAM,GAAI,IAAI,EAAE,MAAiB,IAAI,KAAK,CAAC;YACjD,MAAM,QAAQ,GAAI,IAAI,EAAE,QAAmB,IAAI,EAAE,CAAC;YAClD,UAAU,EAAE,CAAC;gBACX,OAAO;gBACP,MAAM;gBACN,QAAQ;gBACR,SAAS,EAAE,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;aAC7C,CAAC,CAAC;QACL,CAAC;QAED,QAAQ,CAAC,GAAW,EAAE,KAAc;YAClC,WAAW,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC3B,CAAC;QAED,GAAG;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,SAAS,IAAI,OAAO,CAAC;YACnC,MAAM,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;YAEnC,MAAM,OAAO,GAAG,WAAW,CAAC,OAA6B,CAAC;YAC1D,MAAM,UAAU,GAAG,WAAW,CAAC,UAAgC,CAAC;YAChE,MAAM,KAAK,GAAG,WAAW,CAAC,KAA2B,CAAC;YACtD,MAAM,YAAY,GAAG,WAAW,CAAC,YAAkC,CAAC;YAEpE,MAAM,IAAI,GAAc;gBACtB,OAAO;gBACP,GAAG,WAAW;gBACd,MAAM,EAAG,WAAW,CAAC,MAAiB,IAAI,KAAK;gBAC/C,QAAQ,EAAG,WAAW,CAAC,QAAmB,IAAI,EAAE;gBAChD,UAAU;gBACV,SAAS,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE;gBACxC,OAAO,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE;gBACxC,WAAW,EAAE,EAAE,GAAG,WAAW,EAAE;gBAC/B,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC;gBAC7D,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,UAAU,KAAK,IAAI,IAAI,EAAE,UAAU,EAAE,CAAC;gBACtE,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,YAAY,KAAK,IAAI,IAAI,EAAE,YAAY,EAAE,CAAC;gBAC5E,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;aACxD,CAAC;YAEF,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type TraceRecord = {
|
|
2
|
+
route?: string;
|
|
3
|
+
totalMs?: number;
|
|
4
|
+
};
|
|
5
|
+
export type TraceStore = {
|
|
6
|
+
add: (record: TraceRecord) => void;
|
|
7
|
+
list: () => TraceRecord[];
|
|
8
|
+
};
|
|
9
|
+
export declare function createInMemoryTraceStore(): TraceStore;
|
|
10
|
+
//# sourceMappingURL=traceStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceStore.d.ts","sourceRoot":"","sources":["../../../src/trace/traceStore.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IACnC,IAAI,EAAE,MAAM,WAAW,EAAE,CAAC;CAC3B,CAAC;AAEF,wBAAgB,wBAAwB,IAAI,UAAU,CAQrD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceStore.js","sourceRoot":"","sources":["../../../src/trace/traceStore.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,wBAAwB;IACtC,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,OAAO;QACL,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE;YACd,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QACD,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE;KAC5B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/utils/logger.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,SAAS;oBACJ,OAAO,EAAE;oBACT,OAAO,EAAE;qBACR,OAAO,EAAE;CAC3B,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { inspect } from "node:util";
|
|
2
|
+
function formatArg(arg) {
|
|
3
|
+
if (typeof arg === "string")
|
|
4
|
+
return arg;
|
|
5
|
+
return inspect(arg, {
|
|
6
|
+
colors: true,
|
|
7
|
+
depth: 8,
|
|
8
|
+
compact: false,
|
|
9
|
+
breakLength: 100,
|
|
10
|
+
sorted: true,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function formatArgs(args) {
|
|
14
|
+
return args.map((arg) => formatArg(arg)).join(" ");
|
|
15
|
+
}
|
|
16
|
+
export const appLogger = {
|
|
17
|
+
info: (...args) => console.log(formatArgs(args)),
|
|
18
|
+
warn: (...args) => console.warn(formatArgs(args)),
|
|
19
|
+
error: (...args) => console.error(formatArgs(args)),
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,SAAS,SAAS,CAAC,GAAY;IAC7B,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,CAAC;QACR,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,GAAG;QAChB,MAAM,EAAE,IAAI;KACb,CAAC,CAAC;AACL,CAAC;AAED,SAAS,UAAU,CAAC,IAAe;IACjC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC3D,IAAI,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC5D,KAAK,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;CAC/D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/utils/path.ts"],"names":[],"mappings":"AAAA,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,UAElD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.js","sourceRoot":"","sources":["../../../src/utils/path.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Simple type descriptor. Add "?" for optional: "string?", "number?", "boolean?" */
|
|
3
|
+
export type SimpleType = "string" | "number" | "boolean" | "object" | "array";
|
|
4
|
+
/** Shape for body, params, or query: field name -> simple type string or nested object. */
|
|
5
|
+
export interface SimpleSchemaShape {
|
|
6
|
+
[key: string]: SimpleType | string | SimpleSchemaShape;
|
|
7
|
+
}
|
|
8
|
+
/** Per-key schema: either a simple shape (converted to Zod) or a Zod schema. */
|
|
9
|
+
export type SchemaPart = SimpleSchemaShape | z.ZodTypeAny;
|
|
10
|
+
/** Route schema: validate body (only for methods that send body), params, query. */
|
|
11
|
+
export type RouteSchema = {
|
|
12
|
+
body?: SchemaPart;
|
|
13
|
+
params?: SchemaPart;
|
|
14
|
+
query?: SchemaPart;
|
|
15
|
+
};
|
|
16
|
+
/** Per-method overrides. Merged on top of SCHEMA for the current method. */
|
|
17
|
+
export type MethodSchemaMap = Partial<Record<string, RouteSchema>>;
|
|
18
|
+
/** Response body schema per status code. Enforced before sending so only allowed shapes are sent. */
|
|
19
|
+
export type ResponseSchemaMap = Partial<Record<number, SchemaPart>>;
|
|
20
|
+
/** Infer TypeScript type from a simple shape (e.g. { id: "string", name: "string" } -> { id: string; name: string }). */
|
|
21
|
+
export type InferSimpleShape<T> = T extends Record<string, SimpleType | string | SimpleSchemaShape> ? {
|
|
22
|
+
[K in keyof T]: InferSimpleValue<T[K]>;
|
|
23
|
+
} : never;
|
|
24
|
+
/** Map simple type strings to TS types. Supports "string?", "number?", etc. */
|
|
25
|
+
export type InferSimpleValue<V> = V extends "string" ? string : V extends "number" ? number : V extends "boolean" ? boolean : V extends "object" ? object : V extends "array" ? unknown[] : V extends "string?" ? string | undefined : V extends "number?" ? number | undefined : V extends "boolean?" ? boolean | undefined : V extends "object?" ? object | undefined : V extends "array?" ? unknown[] | undefined : V extends SimpleSchemaShape ? InferSimpleShape<V> : unknown;
|
|
26
|
+
/** Infer response body types from a response schema map (Zod or simple shapes) for use with Context<T>. */
|
|
27
|
+
export type InferResponseBodies<S extends ResponseSchemaMap> = {
|
|
28
|
+
[K in keyof S]: S[K] extends z.ZodTypeAny ? z.infer<S[K]> : S[K] extends SimpleSchemaShape ? InferSimpleShape<S[K]> : unknown;
|
|
29
|
+
};
|
|
30
|
+
/** Merge local route response schema with default (config) schema. Local overrides default for same status. */
|
|
31
|
+
export type MergedResponseBodies<Local extends ResponseSchemaMap, Default extends ResponseSchemaMap = Record<number, never>> = Omit<InferResponseBodies<Default>, keyof Local> & InferResponseBodies<Local>;
|
|
32
|
+
export type ResponseValidationResult = {
|
|
33
|
+
ok: true;
|
|
34
|
+
} | {
|
|
35
|
+
ok: false;
|
|
36
|
+
details: unknown;
|
|
37
|
+
};
|
|
38
|
+
/** Validate response body against a schema (e.g. from config.responses[200] or GET_RESPONSE_SCHEMA[201]). */
|
|
39
|
+
export declare function validateResponseBody(schema: SchemaPart, data: unknown): ResponseValidationResult;
|
|
40
|
+
/** Merge method overrides onto base. Method schema wins for each key (body, params, query). */
|
|
41
|
+
export declare function mergeRouteSchema(base: RouteSchema | undefined, methodOverride: RouteSchema | undefined): RouteSchema;
|
|
42
|
+
export type ValidationResult = {
|
|
43
|
+
ok: true;
|
|
44
|
+
body?: unknown;
|
|
45
|
+
params?: Record<string, string | string[]>;
|
|
46
|
+
query?: Record<string, string>;
|
|
47
|
+
} | {
|
|
48
|
+
ok: false;
|
|
49
|
+
status: number;
|
|
50
|
+
json: {
|
|
51
|
+
error: string;
|
|
52
|
+
details?: unknown;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
/** Thrown when route validation fails; request handler sends status + json. */
|
|
56
|
+
export declare class ValidationError extends Error {
|
|
57
|
+
readonly status: number;
|
|
58
|
+
readonly json: {
|
|
59
|
+
error: string;
|
|
60
|
+
details?: unknown;
|
|
61
|
+
};
|
|
62
|
+
constructor(status: number, json: {
|
|
63
|
+
error: string;
|
|
64
|
+
details?: unknown;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Validate ctx against the merged route schema.
|
|
69
|
+
* Body is only validated when method is POST, PUT, or PATCH.
|
|
70
|
+
*/
|
|
71
|
+
export declare function validateRoute(schema: RouteSchema, method: string, ctx: {
|
|
72
|
+
body: unknown;
|
|
73
|
+
params: Record<string, string | string[]>;
|
|
74
|
+
query: Record<string, string>;
|
|
75
|
+
}): ValidationResult;
|
|
76
|
+
export { z };
|
|
77
|
+
//# sourceMappingURL=routeSchema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routeSchema.d.ts","sourceRoot":"","sources":["../../../src/validation/routeSchema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Validate response body against a schema (e.g. from config.responses[200] or GET_RESPONSE_SCHEMA[201]). */
|
|
3
|
+
export function validateResponseBody(schema, data) {
|
|
4
|
+
const zodSchema = toZodSchema(schema);
|
|
5
|
+
const parsed = zodSchema.safeParse(data);
|
|
6
|
+
if (parsed.success)
|
|
7
|
+
return { ok: true };
|
|
8
|
+
return { ok: false, details: parsed.error.flatten() };
|
|
9
|
+
}
|
|
10
|
+
const BODY_METHODS = new Set(["POST", "PUT", "PATCH"]);
|
|
11
|
+
function isZodType(v) {
|
|
12
|
+
return v != null && typeof v === "object" && "safeParse" in v && typeof v.safeParse === "function";
|
|
13
|
+
}
|
|
14
|
+
function parseSimpleType(s) {
|
|
15
|
+
const optional = s.endsWith("?");
|
|
16
|
+
const type = (optional ? s.slice(0, -1) : s);
|
|
17
|
+
return { type, optional };
|
|
18
|
+
}
|
|
19
|
+
function simpleToZod(value) {
|
|
20
|
+
if (typeof value === "string") {
|
|
21
|
+
const { type, optional } = parseSimpleType(value);
|
|
22
|
+
let schema;
|
|
23
|
+
switch (type) {
|
|
24
|
+
case "string":
|
|
25
|
+
schema = z.string();
|
|
26
|
+
break;
|
|
27
|
+
case "number":
|
|
28
|
+
schema = z.coerce.number();
|
|
29
|
+
break;
|
|
30
|
+
case "boolean":
|
|
31
|
+
schema = z.coerce.boolean();
|
|
32
|
+
break;
|
|
33
|
+
case "object":
|
|
34
|
+
schema = z.record(z.unknown());
|
|
35
|
+
break;
|
|
36
|
+
case "array":
|
|
37
|
+
schema = z.array(z.unknown());
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
schema = z.unknown();
|
|
41
|
+
}
|
|
42
|
+
return optional ? schema.optional() : schema;
|
|
43
|
+
}
|
|
44
|
+
if (typeof value === "object" && value !== null && !isZodType(value)) {
|
|
45
|
+
const shape = {};
|
|
46
|
+
for (const [k, v] of Object.entries(value)) {
|
|
47
|
+
shape[k] = simpleToZod(v);
|
|
48
|
+
}
|
|
49
|
+
return z.object(shape);
|
|
50
|
+
}
|
|
51
|
+
return z.unknown();
|
|
52
|
+
}
|
|
53
|
+
function toZodSchema(part) {
|
|
54
|
+
if (isZodType(part))
|
|
55
|
+
return part;
|
|
56
|
+
return simpleToZod(part);
|
|
57
|
+
}
|
|
58
|
+
/** Merge method overrides onto base. Method schema wins for each key (body, params, query). */
|
|
59
|
+
export function mergeRouteSchema(base, methodOverride) {
|
|
60
|
+
if (!methodOverride)
|
|
61
|
+
return base ?? {};
|
|
62
|
+
if (!base)
|
|
63
|
+
return methodOverride;
|
|
64
|
+
const body = methodOverride.body ?? base.body;
|
|
65
|
+
const params = methodOverride.params ?? base.params;
|
|
66
|
+
const query = methodOverride.query ?? base.query;
|
|
67
|
+
const out = {};
|
|
68
|
+
if (body !== undefined)
|
|
69
|
+
out.body = body;
|
|
70
|
+
if (params !== undefined)
|
|
71
|
+
out.params = params;
|
|
72
|
+
if (query !== undefined)
|
|
73
|
+
out.query = query;
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
/** Thrown when route validation fails; request handler sends status + json. */
|
|
77
|
+
export class ValidationError extends Error {
|
|
78
|
+
status;
|
|
79
|
+
json;
|
|
80
|
+
constructor(status, json) {
|
|
81
|
+
super("Validation failed");
|
|
82
|
+
this.status = status;
|
|
83
|
+
this.json = json;
|
|
84
|
+
this.name = "ValidationError";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Validate ctx against the merged route schema.
|
|
89
|
+
* Body is only validated when method is POST, PUT, or PATCH.
|
|
90
|
+
*/
|
|
91
|
+
export function validateRoute(schema, method, ctx) {
|
|
92
|
+
const validateBody = BODY_METHODS.has(method);
|
|
93
|
+
const result = { ok: true };
|
|
94
|
+
const queryObj = ctx.query;
|
|
95
|
+
if (schema.body && validateBody) {
|
|
96
|
+
const bodySchema = toZodSchema(schema.body);
|
|
97
|
+
const parsed = bodySchema.safeParse(ctx.body);
|
|
98
|
+
if (!parsed.success) {
|
|
99
|
+
return {
|
|
100
|
+
ok: false,
|
|
101
|
+
status: 400,
|
|
102
|
+
json: { error: "Validation failed", details: parsed.error.flatten() }
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
result.body = parsed.data;
|
|
106
|
+
}
|
|
107
|
+
if (schema.params) {
|
|
108
|
+
const paramsSchema = toZodSchema(schema.params);
|
|
109
|
+
const parsed = paramsSchema.safeParse(ctx.params);
|
|
110
|
+
if (!parsed.success) {
|
|
111
|
+
return {
|
|
112
|
+
ok: false,
|
|
113
|
+
status: 400,
|
|
114
|
+
json: { error: "Invalid params", details: parsed.error.flatten() }
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
result.params = parsed.data;
|
|
118
|
+
}
|
|
119
|
+
if (schema.query) {
|
|
120
|
+
const querySchema = toZodSchema(schema.query);
|
|
121
|
+
const parsed = querySchema.safeParse(queryObj);
|
|
122
|
+
if (!parsed.success) {
|
|
123
|
+
return {
|
|
124
|
+
ok: false,
|
|
125
|
+
status: 400,
|
|
126
|
+
json: { error: "Invalid query", details: parsed.error.flatten() }
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
result.query = parsed.data;
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
export { z };
|
|
134
|
+
//# sourceMappingURL=routeSchema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routeSchema.js","sourceRoot":"","sources":["../../../src/validation/routeSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2ExB,6GAA6G;AAC7G,MAAM,UAAU,oBAAoB,CAAC,MAAkB,EAAE,IAAa;IACpE,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACxC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AAEvD,SAAS,SAAS,CAAC,CAAU;IAC3B,OAAO,CAAC,IAAI,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,WAAW,IAAI,CAAC,IAAI,OAAQ,CAAkB,CAAC,SAAS,KAAK,UAAU,CAAC;AACvH,CAAC;AAED,SAAS,eAAe,CAAC,CAAS;IAChC,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAe,CAAC;IAC3D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,WAAW,CAAC,KAA8C;IACjE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,MAAoB,CAAC;QACzB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,QAAQ;gBACX,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;gBACpB,MAAM;YACR,KAAK,QAAQ;gBACX,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC3B,MAAM;YACR,KAAK,SAAS;gBACZ,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC5B,MAAM;YACR,KAAK,QAAQ;gBACX,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC/B,MAAM;YACR,KAAK,OAAO;gBACV,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC9B,MAAM;YACR;gBACE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;QACzB,CAAC;QACD,OAAO,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/C,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACrE,MAAM,KAAK,GAAiC,EAAE,CAAC;QAC/C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3C,KAAK,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAA4C,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC;AACrB,CAAC;AAED,SAAS,WAAW,CAAC,IAAgB;IACnC,IAAI,SAAS,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO,WAAW,CAAC,IAAyB,CAAC,CAAC;AAChD,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,gBAAgB,CAAC,IAA6B,EAAE,cAAuC;IACrG,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,IAAI,EAAE,CAAC;IACvC,IAAI,CAAC,IAAI;QAAE,OAAO,cAAc,CAAC;IACjC,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC;IAC9C,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;IACpD,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC;IACjD,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,IAAI,IAAI,KAAK,SAAS;QAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;IACxC,IAAI,MAAM,KAAK,SAAS;QAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC;IAC9C,IAAI,KAAK,KAAK,SAAS;QAAE,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;IAC3C,OAAO,GAAG,CAAC;AACb,CAAC;AAMD,+EAA+E;AAC/E,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAEtB;IACA;IAFlB,YACkB,MAAc,EACd,IAA0C;QAE1D,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAHX,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAsC;QAG1D,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAmB,EACnB,MAAc,EACd,GAAgG;IAEhG,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAqB,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC;IAE3B,IAAI,MAAM,CAAC,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE;aACtE,CAAC;QACJ,CAAC;QACA,MAA6B,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACpD,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE;aACnE,CAAC;QACJ,CAAC;QACA,MAAyD,CAAC,MAAM,GAAG,MAAM,CAAC,IAAyC,CAAC;IACvH,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE;aAClE,CAAC;QACJ,CAAC;QACA,MAA6C,CAAC,KAAK,GAAG,MAAM,CAAC,IAA8B,CAAC;IAC/F,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,OAAO,EAAE,CAAC,EAAE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type ValidateAppOptions = {
|
|
2
|
+
/**
|
|
3
|
+
* When true (e.g. during build), validation steps are logged.
|
|
4
|
+
* When false (e.g. during dev), validations run with no logs.
|
|
5
|
+
*/
|
|
6
|
+
isBuild?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* When true (default), validate entire app tree.
|
|
9
|
+
* When false, scan only appDir (that directory only, no nested checking).
|
|
10
|
+
*/
|
|
11
|
+
isRecursive?: boolean;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Run all app validations for the given app directory.
|
|
15
|
+
* - Routes: duplicate handler per path+method (and more in future).
|
|
16
|
+
* When isBuild is true, logs each validation step; otherwise runs silently.
|
|
17
|
+
* Throws on first validation failure.
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateApp(appDir: string, options?: ValidateAppOptions): Promise<boolean>;
|
|
20
|
+
//# sourceMappingURL=validateApp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateApp.d.ts","sourceRoot":"","sources":["../../../src/validation/validateApp.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,OAAO,CAAC,CAclB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { validateRouteConflictsAsync } from "../router/routeTable.js";
|
|
2
|
+
import { appLogger } from "../utils/logger.js";
|
|
3
|
+
/**
|
|
4
|
+
* Run all app validations for the given app directory.
|
|
5
|
+
* - Routes: duplicate handler per path+method (and more in future).
|
|
6
|
+
* When isBuild is true, logs each validation step; otherwise runs silently.
|
|
7
|
+
* Throws on first validation failure.
|
|
8
|
+
*/
|
|
9
|
+
export async function validateApp(appDir, options) {
|
|
10
|
+
try {
|
|
11
|
+
const { isBuild = false, isRecursive = true } = options ?? {};
|
|
12
|
+
if (isBuild) {
|
|
13
|
+
appLogger.info(" validating routes...");
|
|
14
|
+
}
|
|
15
|
+
await validateRouteConflictsAsync(appDir, { isRecursive });
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
appLogger.error("[legonode] validation failed", error.message);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=validateApp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateApp.js","sourceRoot":"","sources":["../../../src/validation/validateApp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAe/C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,OAA4B;IAE5B,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,GAAG,KAAK,EAAE,WAAW,GAAG,IAAI,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;QAE9D,IAAI,OAAO,EAAE,CAAC;YACZ,SAAS,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QAC3C,CAAC;QACD,MAAM,2BAA2B,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;QAE3D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,SAAS,CAAC,KAAK,CAAC,8BAA8B,EAAG,KAAe,CAAC,OAAO,CAAC,CAAC;QAC1E,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LegonodeContext } from "../core/context.js";
|
|
2
|
+
/**
|
|
3
|
+
* Validate ctx.body with a parse function (e.g. Zod schema's .parse).
|
|
4
|
+
* Returns the parsed value on success; throws on failure (error handler can send 400).
|
|
5
|
+
*/
|
|
6
|
+
export declare function validateBody<T>(ctx: LegonodeContext, parse: (body: unknown) => T): T;
|
|
7
|
+
//# sourceMappingURL=validateBody.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateBody.d.ts","sourceRoot":"","sources":["../../../src/validation/validateBody.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAEpF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate ctx.body with a parse function (e.g. Zod schema's .parse).
|
|
3
|
+
* Returns the parsed value on success; throws on failure (error handler can send 400).
|
|
4
|
+
*/
|
|
5
|
+
export function validateBody(ctx, parse) {
|
|
6
|
+
return parse(ctx.body);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=validateBody.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateBody.js","sourceRoot":"","sources":["../../../src/validation/validateBody.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAI,GAAoB,EAAE,KAA2B;IAC/E,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "legonode",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"dependencies": {
|
|
5
|
+
"commander": "^12.0.0",
|
|
6
|
+
"fast-json-stringify": "^5.0.0",
|
|
7
|
+
"pino": "^9.0.0",
|
|
8
|
+
"pino-pretty": "^11.0.0",
|
|
9
|
+
"tsx": "^4.19.0",
|
|
10
|
+
"zod": "^3.23.0"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/src/index.d.ts",
|
|
15
|
+
"default": "./dist/src/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"legonode": "dist/cli/cli.js"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "rm -rf dist && tsc -p tsconfig.json",
|
|
26
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"type": "module",
|
|
30
|
+
"types": "./dist/src/index.d.ts"
|
|
31
|
+
}
|