@taujs/server 0.4.1 → 0.4.2
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/{Config-LCDjtT9m.d.ts → Config-BuUuMjmO.d.ts} +61 -27
- package/dist/Config.d.ts +1 -1
- package/dist/Config.js +16 -9
- package/dist/index.d.ts +12 -3
- package/dist/index.js +244 -225
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ type DebugCategory = (typeof DEBUG_CATEGORIES)[number];
|
|
|
6
6
|
type DebugConfig = boolean | DebugCategory[] | ({
|
|
7
7
|
all?: boolean;
|
|
8
8
|
} & Partial<Record<DebugCategory, boolean>>);
|
|
9
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
9
10
|
interface BaseLogger {
|
|
10
11
|
debug?(meta?: Record<string, unknown>, message?: string): void;
|
|
11
12
|
info?(meta?: Record<string, unknown>, message?: string): void;
|
|
@@ -22,17 +23,51 @@ interface Logs extends BaseLogger {
|
|
|
22
23
|
child(context: Record<string, unknown>): Logs;
|
|
23
24
|
isDebugEnabled(category: DebugCategory): boolean;
|
|
24
25
|
}
|
|
26
|
+
declare class Logger implements Logs {
|
|
27
|
+
private config;
|
|
28
|
+
private debugEnabled;
|
|
29
|
+
private context;
|
|
30
|
+
constructor(config?: {
|
|
31
|
+
custom?: BaseLogger;
|
|
32
|
+
context?: Record<string, unknown>;
|
|
33
|
+
minLevel?: LogLevel;
|
|
34
|
+
includeStack?: boolean | ((level: LogLevel) => boolean);
|
|
35
|
+
includeContext?: boolean | ((level: LogLevel) => boolean);
|
|
36
|
+
singleLine?: boolean;
|
|
37
|
+
});
|
|
38
|
+
child(context: Record<string, unknown>): Logger;
|
|
39
|
+
configure(debug?: DebugConfig): void;
|
|
40
|
+
isDebugEnabled(category: DebugCategory): boolean;
|
|
41
|
+
private shouldEmit;
|
|
42
|
+
private shouldIncludeStack;
|
|
43
|
+
private stripStacks;
|
|
44
|
+
private formatTimestamp;
|
|
45
|
+
private emit;
|
|
46
|
+
info(meta?: unknown, message?: string): void;
|
|
47
|
+
warn(meta?: unknown, message?: string): void;
|
|
48
|
+
error(meta?: unknown, message?: string): void;
|
|
49
|
+
debug(category: DebugCategory, meta?: unknown, message?: string): void;
|
|
50
|
+
}
|
|
51
|
+
declare function createLogger(opts?: {
|
|
52
|
+
debug?: DebugConfig | string | boolean;
|
|
53
|
+
custom?: BaseLogger;
|
|
54
|
+
context?: Record<string, unknown>;
|
|
55
|
+
minLevel?: LogLevel;
|
|
56
|
+
includeStack?: boolean | ((level: LogLevel) => boolean);
|
|
57
|
+
includeContext?: boolean | ((level: LogLevel) => boolean);
|
|
58
|
+
singleLine?: boolean;
|
|
59
|
+
}): Logger;
|
|
25
60
|
|
|
26
|
-
type
|
|
27
|
-
type
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
61
|
+
type JsonPrimitive = string | number | boolean | null;
|
|
62
|
+
type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
63
|
+
[k: string]: JsonValue;
|
|
64
|
+
};
|
|
65
|
+
type JsonObject = {
|
|
66
|
+
[k: string]: JsonValue;
|
|
67
|
+
};
|
|
68
|
+
type NarrowSchema<T> = {
|
|
69
|
+
parse: (u: unknown) => T;
|
|
70
|
+
} | ((u: unknown) => T);
|
|
36
71
|
type ServiceContext = {
|
|
37
72
|
signal?: AbortSignal;
|
|
38
73
|
deadlineMs?: number;
|
|
@@ -43,18 +78,21 @@ type ServiceContext = {
|
|
|
43
78
|
roles: string[];
|
|
44
79
|
} | null;
|
|
45
80
|
};
|
|
46
|
-
type ServiceMethod<P, R extends
|
|
47
|
-
type
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
81
|
+
type ServiceMethod<P, R extends JsonObject = JsonObject> = (params: P, ctx: ServiceContext) => Promise<R>;
|
|
82
|
+
type ServiceDefinition = Readonly<Record<string, ServiceMethod<any, JsonObject>>>;
|
|
83
|
+
type ServiceRegistry = Readonly<Record<string, ServiceDefinition>>;
|
|
84
|
+
type ServiceDescriptor = {
|
|
85
|
+
serviceName: string;
|
|
86
|
+
serviceMethod: string;
|
|
87
|
+
args?: JsonObject;
|
|
53
88
|
};
|
|
54
|
-
|
|
55
|
-
|
|
89
|
+
declare function defineService<T extends Record<string, ServiceMethod<any, JsonObject> | {
|
|
90
|
+
handler: ServiceMethod<any, JsonObject>;
|
|
91
|
+
params?: NarrowSchema<any>;
|
|
92
|
+
result?: NarrowSchema<any>;
|
|
93
|
+
}>>(spec: T): { [K in keyof T]: T[K] extends ServiceMethod<infer P, infer R> ? ServiceMethod<P, R> : T[K] extends {
|
|
56
94
|
handler: ServiceMethod<infer P, infer R_1>;
|
|
57
|
-
} ?
|
|
95
|
+
} ? ServiceMethod<P, R_1> : never; };
|
|
58
96
|
declare const defineServiceRegistry: <R extends ServiceRegistry>(registry: R) => R;
|
|
59
97
|
|
|
60
98
|
type RequestContext<L extends Logs = Logs> = {
|
|
@@ -73,6 +111,7 @@ type RouteCSPConfig = {
|
|
|
73
111
|
req: FastifyRequest;
|
|
74
112
|
}) => CSPDirectives);
|
|
75
113
|
generateCSP?: (directives: CSPDirectives, nonce: string, req: FastifyRequest) => string;
|
|
114
|
+
reportOnly?: boolean;
|
|
76
115
|
};
|
|
77
116
|
type BaseMiddleware = {
|
|
78
117
|
auth?: {
|
|
@@ -82,12 +121,7 @@ type BaseMiddleware = {
|
|
|
82
121
|
};
|
|
83
122
|
csp?: RouteCSPConfig | false;
|
|
84
123
|
};
|
|
85
|
-
type
|
|
86
|
-
serviceName: string;
|
|
87
|
-
serviceMethod: string;
|
|
88
|
-
args?: Record<string, unknown>;
|
|
89
|
-
};
|
|
90
|
-
type DataResult = Record<string, unknown> | ServiceCall;
|
|
124
|
+
type DataResult = Record<string, unknown> | ServiceDescriptor;
|
|
91
125
|
type DataHandler<Params extends PathToRegExpParams, L extends Logs = Logs> = (params: Params, ctx: RequestContext<L> & {
|
|
92
126
|
[key: string]: unknown;
|
|
93
127
|
}) => Promise<DataResult>;
|
|
@@ -172,4 +206,4 @@ type TaujsConfig = {
|
|
|
172
206
|
|
|
173
207
|
declare function defineConfig<T extends TaujsConfig>(config: T): T;
|
|
174
208
|
|
|
175
|
-
export { type AppConfig as A, type BaseLogger as B, type DebugConfig as D, type InitialRouteParams as I, type ServiceRegistry as S, type TaujsConfig as T, type SecurityConfig as a, type AppRoute as b,
|
|
209
|
+
export { type AppConfig as A, type BaseLogger as B, type DebugConfig as D, type InitialRouteParams as I, type ServiceRegistry as S, type TaujsConfig as T, type SecurityConfig as a, type AppRoute as b, createLogger as c, defineConfig as d, defineServiceRegistry as e, defineService as f, type ServiceContext as g };
|
package/dist/Config.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'fastify';
|
|
2
2
|
import 'vite';
|
|
3
|
-
export { A as AppConfig, b as AppRoute, a as SecurityConfig, T as TaujsConfig, d as defineConfig,
|
|
3
|
+
export { A as AppConfig, b as AppRoute, a as SecurityConfig, g as ServiceContext, T as TaujsConfig, d as defineConfig, f as defineService, e as defineServiceRegistry } from './Config-BuUuMjmO.js';
|
package/dist/Config.js
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
// src/utils/DataServices.ts
|
|
2
|
-
|
|
2
|
+
import { performance } from "perf_hooks";
|
|
3
|
+
var runSchema = (schema, input) => {
|
|
4
|
+
if (!schema) return input;
|
|
5
|
+
return typeof schema.parse === "function" ? schema.parse(input) : schema(input);
|
|
6
|
+
};
|
|
7
|
+
function defineService(spec) {
|
|
3
8
|
const out = {};
|
|
4
|
-
for (const [
|
|
9
|
+
for (const [name, v] of Object.entries(spec)) {
|
|
5
10
|
if (typeof v === "function") {
|
|
6
|
-
out[
|
|
11
|
+
out[name] = v;
|
|
7
12
|
} else {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
const { handler, params: paramsSchema, result: resultSchema } = v;
|
|
14
|
+
out[name] = async (params, ctx) => {
|
|
15
|
+
const p = runSchema(paramsSchema, params);
|
|
16
|
+
const r = await handler(p, ctx);
|
|
17
|
+
return runSchema(resultSchema, r);
|
|
11
18
|
};
|
|
12
19
|
}
|
|
13
20
|
}
|
|
14
|
-
return out;
|
|
15
|
-
}
|
|
16
|
-
var defineServiceRegistry = (registry) => registry;
|
|
21
|
+
return Object.freeze(out);
|
|
22
|
+
}
|
|
23
|
+
var defineServiceRegistry = (registry) => Object.freeze(Object.fromEntries(Object.entries(registry).map(([k, v]) => [k, Object.freeze(v)])));
|
|
17
24
|
|
|
18
25
|
// src/Config.ts
|
|
19
26
|
function defineConfig(config) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FastifyPluginCallback, FastifyPluginAsync, FastifyInstance } from 'fastify';
|
|
2
|
-
import { T as TaujsConfig, S as ServiceRegistry, D as DebugConfig, B as BaseLogger, A as AppConfig } from './Config-
|
|
3
|
-
export { I as InitialRouteParams } from './Config-
|
|
2
|
+
import { T as TaujsConfig, S as ServiceRegistry, D as DebugConfig, B as BaseLogger, A as AppConfig } from './Config-BuUuMjmO.js';
|
|
3
|
+
export { I as InitialRouteParams, c as createLogger } from './Config-BuUuMjmO.js';
|
|
4
4
|
import 'vite';
|
|
5
5
|
|
|
6
6
|
type StaticMountEntry = {
|
|
@@ -51,4 +51,13 @@ declare function taujsBuild({ config, projectRoot, clientBaseDir, isSSRBuild, }:
|
|
|
51
51
|
isSSRBuild?: boolean;
|
|
52
52
|
}): Promise<void>;
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
interface MessageMetaLogger {
|
|
55
|
+
debug?: (message?: string, meta?: Record<string, unknown>) => unknown;
|
|
56
|
+
info?: (message?: string, meta?: Record<string, unknown>) => unknown;
|
|
57
|
+
warn?: (message?: string, meta?: Record<string, unknown>) => unknown;
|
|
58
|
+
error?: (message?: string, meta?: Record<string, unknown>) => unknown;
|
|
59
|
+
child?: (bindings: Record<string, unknown>) => MessageMetaLogger | undefined;
|
|
60
|
+
}
|
|
61
|
+
declare function winstonAdapter(winston: MessageMetaLogger): BaseLogger;
|
|
62
|
+
|
|
63
|
+
export { createServer, taujsBuild, winstonAdapter };
|
package/dist/index.js
CHANGED
|
@@ -190,7 +190,7 @@ var require_plugin = __commonJS({
|
|
|
190
190
|
// src/CreateServer.ts
|
|
191
191
|
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
192
192
|
import path5 from "path";
|
|
193
|
-
import { performance as
|
|
193
|
+
import { performance as performance3 } from "perf_hooks";
|
|
194
194
|
import fastifyStatic from "@fastify/static";
|
|
195
195
|
import Fastify from "fastify";
|
|
196
196
|
|
|
@@ -348,9 +348,129 @@ var computeScore = (path7) => {
|
|
|
348
348
|
return path7.split("/").filter(Boolean).reduce((score, segment) => score + (segment.startsWith(":") ? 1 : 10), 0);
|
|
349
349
|
};
|
|
350
350
|
|
|
351
|
-
// src/
|
|
352
|
-
var
|
|
353
|
-
|
|
351
|
+
// src/logging/AppError.ts
|
|
352
|
+
var HTTP_STATUS = {
|
|
353
|
+
infra: 500,
|
|
354
|
+
upstream: 502,
|
|
355
|
+
domain: 404,
|
|
356
|
+
validation: 400,
|
|
357
|
+
auth: 403,
|
|
358
|
+
canceled: 499,
|
|
359
|
+
// Client Closed Request (nginx convention)
|
|
360
|
+
timeout: 504
|
|
361
|
+
};
|
|
362
|
+
var AppError = class _AppError extends Error {
|
|
363
|
+
kind;
|
|
364
|
+
httpStatus;
|
|
365
|
+
details;
|
|
366
|
+
safeMessage;
|
|
367
|
+
code;
|
|
368
|
+
constructor(message, kind, options = {}) {
|
|
369
|
+
super(message);
|
|
370
|
+
this.name = "AppError";
|
|
371
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
372
|
+
if (options.cause !== void 0) {
|
|
373
|
+
Object.defineProperty(this, "cause", {
|
|
374
|
+
value: options.cause,
|
|
375
|
+
enumerable: false,
|
|
376
|
+
writable: false,
|
|
377
|
+
configurable: true
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
this.kind = kind;
|
|
381
|
+
this.httpStatus = options.httpStatus ?? HTTP_STATUS[kind];
|
|
382
|
+
this.details = options.details;
|
|
383
|
+
this.safeMessage = options.safeMessage ?? this.getSafeMessage(kind, message);
|
|
384
|
+
this.code = options.code;
|
|
385
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
|
|
386
|
+
}
|
|
387
|
+
getSafeMessage(kind, message) {
|
|
388
|
+
return kind === "domain" || kind === "validation" || kind === "auth" ? message : "Internal Server Error";
|
|
389
|
+
}
|
|
390
|
+
serialiseValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
391
|
+
if (value === null || value === void 0) return value;
|
|
392
|
+
if (typeof value !== "object") return value;
|
|
393
|
+
if (seen.has(value)) return "[circular]";
|
|
394
|
+
seen.add(value);
|
|
395
|
+
if (value instanceof Error) {
|
|
396
|
+
return {
|
|
397
|
+
name: value.name,
|
|
398
|
+
message: value.message,
|
|
399
|
+
stack: value.stack,
|
|
400
|
+
...value instanceof _AppError && {
|
|
401
|
+
kind: value.kind,
|
|
402
|
+
httpStatus: value.httpStatus,
|
|
403
|
+
code: value.code
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
if (Array.isArray(value)) return value.map((item) => this.serialiseValue(item, seen));
|
|
408
|
+
const result = {};
|
|
409
|
+
for (const [key, val] of Object.entries(value)) {
|
|
410
|
+
result[key] = this.serialiseValue(val, seen);
|
|
411
|
+
}
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
414
|
+
toJSON() {
|
|
415
|
+
return {
|
|
416
|
+
name: this.name,
|
|
417
|
+
kind: this.kind,
|
|
418
|
+
message: this.message,
|
|
419
|
+
safeMessage: this.safeMessage,
|
|
420
|
+
httpStatus: this.httpStatus,
|
|
421
|
+
...this.code && { code: this.code },
|
|
422
|
+
details: this.serialiseValue(this.details),
|
|
423
|
+
stack: this.stack,
|
|
424
|
+
...this.cause && {
|
|
425
|
+
cause: this.serialiseValue(this.cause)
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
static notFound(message, details, code) {
|
|
430
|
+
return new _AppError(message, "domain", { httpStatus: 404, details, code });
|
|
431
|
+
}
|
|
432
|
+
static forbidden(message, details, code) {
|
|
433
|
+
return new _AppError(message, "auth", { httpStatus: 403, details, code });
|
|
434
|
+
}
|
|
435
|
+
static badRequest(message, details, code) {
|
|
436
|
+
return new _AppError(message, "validation", { httpStatus: 400, details, code });
|
|
437
|
+
}
|
|
438
|
+
static unprocessable(message, details, code) {
|
|
439
|
+
return new _AppError(message, "validation", { httpStatus: 422, details, code });
|
|
440
|
+
}
|
|
441
|
+
static timeout(message, details, code) {
|
|
442
|
+
return new _AppError(message, "timeout", { details, code });
|
|
443
|
+
}
|
|
444
|
+
static canceled(message, details, code) {
|
|
445
|
+
return new _AppError(message, "canceled", { details, code });
|
|
446
|
+
}
|
|
447
|
+
static internal(message, cause, details, code) {
|
|
448
|
+
return new _AppError(message, "infra", { cause, details, code });
|
|
449
|
+
}
|
|
450
|
+
static upstream(message, cause, details, code) {
|
|
451
|
+
return new _AppError(message, "upstream", { cause, details, code });
|
|
452
|
+
}
|
|
453
|
+
static serviceUnavailable(message, cause, details, code) {
|
|
454
|
+
return new _AppError(message, "infra", { httpStatus: 503, cause, details, code });
|
|
455
|
+
}
|
|
456
|
+
static from(err, fallback = "Internal error") {
|
|
457
|
+
return err instanceof _AppError ? err : _AppError.internal(err?.message ?? fallback, err);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
function normaliseError(e) {
|
|
461
|
+
if (e instanceof Error) return { name: e.name, message: e.message, stack: e.stack };
|
|
462
|
+
const hasMessageProp = e != null && typeof e.message !== "undefined";
|
|
463
|
+
const msg = hasMessageProp ? String(e.message) : String(e);
|
|
464
|
+
return { name: "Error", message: msg };
|
|
465
|
+
}
|
|
466
|
+
function toReason(e) {
|
|
467
|
+
if (e instanceof Error) return e;
|
|
468
|
+
if (e === null) return new Error("null");
|
|
469
|
+
if (typeof e === "undefined") return new Error("Unknown render error");
|
|
470
|
+
const maybeMsg = e?.message;
|
|
471
|
+
if (typeof maybeMsg !== "undefined") return new Error(String(maybeMsg));
|
|
472
|
+
return new Error(String(e));
|
|
473
|
+
}
|
|
354
474
|
|
|
355
475
|
// src/logging/Logger.ts
|
|
356
476
|
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
@@ -554,7 +674,54 @@ function createLogger(opts) {
|
|
|
554
674
|
return logger;
|
|
555
675
|
}
|
|
556
676
|
|
|
677
|
+
// src/network/CLI.ts
|
|
678
|
+
function readFlag(argv, keys, bareValue) {
|
|
679
|
+
const end = argv.indexOf("--");
|
|
680
|
+
const limit = end === -1 ? argv.length : end;
|
|
681
|
+
for (let i = 0; i < limit; i++) {
|
|
682
|
+
const arg = argv[i];
|
|
683
|
+
for (const key of keys) {
|
|
684
|
+
if (arg === key) {
|
|
685
|
+
const next = argv[i + 1];
|
|
686
|
+
if (!next || next.startsWith("-")) return bareValue;
|
|
687
|
+
return next.trim();
|
|
688
|
+
}
|
|
689
|
+
const pref = `${key}=`;
|
|
690
|
+
if (arg && arg.startsWith(pref)) {
|
|
691
|
+
const v = arg.slice(pref.length).trim();
|
|
692
|
+
return v || bareValue;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return void 0;
|
|
697
|
+
}
|
|
698
|
+
function resolveNet(input) {
|
|
699
|
+
const env = process.env;
|
|
700
|
+
const argv = process.argv;
|
|
701
|
+
let host = "localhost";
|
|
702
|
+
let port = 5173;
|
|
703
|
+
let hmrPort = 5174;
|
|
704
|
+
if (input?.host) host = input.host;
|
|
705
|
+
if (Number.isFinite(input?.port)) port = Number(input.port);
|
|
706
|
+
if (Number.isFinite(input?.hmrPort)) hmrPort = Number(input.hmrPort);
|
|
707
|
+
if (env.HOST?.trim()) host = env.HOST.trim();
|
|
708
|
+
else if (env.FASTIFY_ADDRESS?.trim()) host = env.FASTIFY_ADDRESS.trim();
|
|
709
|
+
if (env.PORT) port = Number(env.PORT) || port;
|
|
710
|
+
if (env.FASTIFY_PORT) port = Number(env.FASTIFY_PORT) || port;
|
|
711
|
+
if (env.HMR_PORT) hmrPort = Number(env.HMR_PORT) || hmrPort;
|
|
712
|
+
const cliHost = readFlag(argv, ["--host", "--hostname", "-H"], "0.0.0.0");
|
|
713
|
+
const cliPort = readFlag(argv, ["--port", "-p"]);
|
|
714
|
+
const cliHMR = readFlag(argv, ["--hmr-port"]);
|
|
715
|
+
if (cliHost) host = cliHost;
|
|
716
|
+
if (cliPort) port = Number(cliPort) || port;
|
|
717
|
+
if (cliHMR) hmrPort = Number(cliHMR) || hmrPort;
|
|
718
|
+
if (host === "true" || host === "") host = "0.0.0.0";
|
|
719
|
+
return { host, port, hmrPort };
|
|
720
|
+
}
|
|
721
|
+
|
|
557
722
|
// src/network/Network.ts
|
|
723
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
724
|
+
import { networkInterfaces } from "os";
|
|
558
725
|
var isPrivateIPv4 = (addr) => {
|
|
559
726
|
if (!/^\d+\.\d+\.\d+\.\d+$/.test(addr)) return false;
|
|
560
727
|
const [a, b, _c, _d] = addr.split(".").map(Number);
|
|
@@ -606,51 +773,6 @@ var bannerPlugin = async (fastify, options) => {
|
|
|
606
773
|
});
|
|
607
774
|
};
|
|
608
775
|
|
|
609
|
-
// src/network/CLI.ts
|
|
610
|
-
function readFlag(argv, keys, bareValue) {
|
|
611
|
-
const end = argv.indexOf("--");
|
|
612
|
-
const limit = end === -1 ? argv.length : end;
|
|
613
|
-
for (let i = 0; i < limit; i++) {
|
|
614
|
-
const arg = argv[i];
|
|
615
|
-
for (const key of keys) {
|
|
616
|
-
if (arg === key) {
|
|
617
|
-
const next = argv[i + 1];
|
|
618
|
-
if (!next || next.startsWith("-")) return bareValue;
|
|
619
|
-
return next.trim();
|
|
620
|
-
}
|
|
621
|
-
const pref = `${key}=`;
|
|
622
|
-
if (arg && arg.startsWith(pref)) {
|
|
623
|
-
const v = arg.slice(pref.length).trim();
|
|
624
|
-
return v || bareValue;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
return void 0;
|
|
629
|
-
}
|
|
630
|
-
function resolveNet(input) {
|
|
631
|
-
const env = process.env;
|
|
632
|
-
const argv = process.argv;
|
|
633
|
-
let host = "localhost";
|
|
634
|
-
let port = 5173;
|
|
635
|
-
let hmrPort = 5174;
|
|
636
|
-
if (input?.host) host = input.host;
|
|
637
|
-
if (Number.isFinite(input?.port)) port = Number(input.port);
|
|
638
|
-
if (Number.isFinite(input?.hmrPort)) hmrPort = Number(input.hmrPort);
|
|
639
|
-
if (env.HOST?.trim()) host = env.HOST.trim();
|
|
640
|
-
else if (env.FASTIFY_ADDRESS?.trim()) host = env.FASTIFY_ADDRESS.trim();
|
|
641
|
-
if (env.PORT) port = Number(env.PORT) || port;
|
|
642
|
-
if (env.FASTIFY_PORT) port = Number(env.FASTIFY_PORT) || port;
|
|
643
|
-
if (env.HMR_PORT) hmrPort = Number(env.HMR_PORT) || hmrPort;
|
|
644
|
-
const cliHost = readFlag(argv, ["--host", "--hostname", "-H"], "0.0.0.0");
|
|
645
|
-
const cliPort = readFlag(argv, ["--port", "-p"]);
|
|
646
|
-
const cliHMR = readFlag(argv, ["--hmr-port"]);
|
|
647
|
-
if (cliHost) host = cliHost;
|
|
648
|
-
if (cliPort) port = Number(cliPort) || port;
|
|
649
|
-
if (cliHMR) hmrPort = Number(cliHMR) || hmrPort;
|
|
650
|
-
if (host === "true" || host === "") host = "0.0.0.0";
|
|
651
|
-
return { host, port, hmrPort };
|
|
652
|
-
}
|
|
653
|
-
|
|
654
776
|
// src/security/VerifyMiddleware.ts
|
|
655
777
|
var isAuthRequired = (route) => Boolean(route.attr?.middleware?.auth);
|
|
656
778
|
var hasAuthenticate = (app) => typeof app.authenticate === "function";
|
|
@@ -718,130 +840,6 @@ var verifyContracts = (app, routes, contracts, security) => {
|
|
|
718
840
|
// src/SSRServer.ts
|
|
719
841
|
var import_fastify_plugin3 = __toESM(require_plugin(), 1);
|
|
720
842
|
|
|
721
|
-
// src/logging/AppError.ts
|
|
722
|
-
var HTTP_STATUS = {
|
|
723
|
-
infra: 500,
|
|
724
|
-
upstream: 502,
|
|
725
|
-
domain: 404,
|
|
726
|
-
validation: 400,
|
|
727
|
-
auth: 403,
|
|
728
|
-
canceled: 499,
|
|
729
|
-
// Client Closed Request (nginx convention)
|
|
730
|
-
timeout: 504
|
|
731
|
-
};
|
|
732
|
-
var AppError = class _AppError extends Error {
|
|
733
|
-
kind;
|
|
734
|
-
httpStatus;
|
|
735
|
-
details;
|
|
736
|
-
safeMessage;
|
|
737
|
-
code;
|
|
738
|
-
constructor(message, kind, options = {}) {
|
|
739
|
-
super(message);
|
|
740
|
-
this.name = "AppError";
|
|
741
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
742
|
-
if (options.cause !== void 0) {
|
|
743
|
-
Object.defineProperty(this, "cause", {
|
|
744
|
-
value: options.cause,
|
|
745
|
-
enumerable: false,
|
|
746
|
-
writable: false,
|
|
747
|
-
configurable: true
|
|
748
|
-
});
|
|
749
|
-
}
|
|
750
|
-
this.kind = kind;
|
|
751
|
-
this.httpStatus = options.httpStatus ?? HTTP_STATUS[kind];
|
|
752
|
-
this.details = options.details;
|
|
753
|
-
this.safeMessage = options.safeMessage ?? this.getSafeMessage(kind, message);
|
|
754
|
-
this.code = options.code;
|
|
755
|
-
if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
|
|
756
|
-
}
|
|
757
|
-
getSafeMessage(kind, message) {
|
|
758
|
-
return kind === "domain" || kind === "validation" || kind === "auth" ? message : "Internal Server Error";
|
|
759
|
-
}
|
|
760
|
-
serialiseValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
761
|
-
if (value === null || value === void 0) return value;
|
|
762
|
-
if (typeof value !== "object") return value;
|
|
763
|
-
if (seen.has(value)) return "[circular]";
|
|
764
|
-
seen.add(value);
|
|
765
|
-
if (value instanceof Error) {
|
|
766
|
-
return {
|
|
767
|
-
name: value.name,
|
|
768
|
-
message: value.message,
|
|
769
|
-
stack: value.stack,
|
|
770
|
-
...value instanceof _AppError && {
|
|
771
|
-
kind: value.kind,
|
|
772
|
-
httpStatus: value.httpStatus,
|
|
773
|
-
code: value.code
|
|
774
|
-
}
|
|
775
|
-
};
|
|
776
|
-
}
|
|
777
|
-
if (Array.isArray(value)) return value.map((item) => this.serialiseValue(item, seen));
|
|
778
|
-
const result = {};
|
|
779
|
-
for (const [key, val] of Object.entries(value)) {
|
|
780
|
-
result[key] = this.serialiseValue(val, seen);
|
|
781
|
-
}
|
|
782
|
-
return result;
|
|
783
|
-
}
|
|
784
|
-
toJSON() {
|
|
785
|
-
return {
|
|
786
|
-
name: this.name,
|
|
787
|
-
kind: this.kind,
|
|
788
|
-
message: this.message,
|
|
789
|
-
safeMessage: this.safeMessage,
|
|
790
|
-
httpStatus: this.httpStatus,
|
|
791
|
-
...this.code && { code: this.code },
|
|
792
|
-
details: this.serialiseValue(this.details),
|
|
793
|
-
stack: this.stack,
|
|
794
|
-
...this.cause && {
|
|
795
|
-
cause: this.serialiseValue(this.cause)
|
|
796
|
-
}
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
static notFound(message, details, code) {
|
|
800
|
-
return new _AppError(message, "domain", { httpStatus: 404, details, code });
|
|
801
|
-
}
|
|
802
|
-
static forbidden(message, details, code) {
|
|
803
|
-
return new _AppError(message, "auth", { httpStatus: 403, details, code });
|
|
804
|
-
}
|
|
805
|
-
static badRequest(message, details, code) {
|
|
806
|
-
return new _AppError(message, "validation", { httpStatus: 400, details, code });
|
|
807
|
-
}
|
|
808
|
-
static unprocessable(message, details, code) {
|
|
809
|
-
return new _AppError(message, "validation", { httpStatus: 422, details, code });
|
|
810
|
-
}
|
|
811
|
-
static timeout(message, details, code) {
|
|
812
|
-
return new _AppError(message, "timeout", { details, code });
|
|
813
|
-
}
|
|
814
|
-
static canceled(message, details, code) {
|
|
815
|
-
return new _AppError(message, "canceled", { details, code });
|
|
816
|
-
}
|
|
817
|
-
static internal(message, cause, details, code) {
|
|
818
|
-
return new _AppError(message, "infra", { cause, details, code });
|
|
819
|
-
}
|
|
820
|
-
static upstream(message, cause, details, code) {
|
|
821
|
-
return new _AppError(message, "upstream", { cause, details, code });
|
|
822
|
-
}
|
|
823
|
-
static serviceUnavailable(message, cause, details, code) {
|
|
824
|
-
return new _AppError(message, "infra", { httpStatus: 503, cause, details, code });
|
|
825
|
-
}
|
|
826
|
-
static from(err, fallback = "Internal error") {
|
|
827
|
-
return err instanceof _AppError ? err : _AppError.internal(err?.message ?? fallback, err);
|
|
828
|
-
}
|
|
829
|
-
};
|
|
830
|
-
function normaliseError(e) {
|
|
831
|
-
if (e instanceof Error) return { name: e.name, message: e.message, stack: e.stack };
|
|
832
|
-
const hasMessageProp = e != null && typeof e.message !== "undefined";
|
|
833
|
-
const msg = hasMessageProp ? String(e.message) : String(e);
|
|
834
|
-
return { name: "Error", message: msg };
|
|
835
|
-
}
|
|
836
|
-
function toReason(e) {
|
|
837
|
-
if (e instanceof Error) return e;
|
|
838
|
-
if (e === null) return new Error("null");
|
|
839
|
-
if (typeof e === "undefined") return new Error("Unknown render error");
|
|
840
|
-
const maybeMsg = e?.message;
|
|
841
|
-
if (typeof maybeMsg !== "undefined") return new Error(String(maybeMsg));
|
|
842
|
-
return new Error(String(e));
|
|
843
|
-
}
|
|
844
|
-
|
|
845
843
|
// src/logging/utils/index.ts
|
|
846
844
|
var httpStatusFrom = (err, fallback = 500) => err instanceof AppError ? err.httpStatus : fallback;
|
|
847
845
|
var toHttp = (err) => {
|
|
@@ -880,39 +878,47 @@ var statusText = (status) => {
|
|
|
880
878
|
import { match } from "path-to-regexp";
|
|
881
879
|
|
|
882
880
|
// src/utils/DataServices.ts
|
|
881
|
+
import { performance as performance2 } from "perf_hooks";
|
|
883
882
|
async function callServiceMethod(registry, serviceName, methodName, params, ctx) {
|
|
884
883
|
if (ctx.signal?.aborted) throw AppError.timeout("Request canceled");
|
|
885
884
|
const service = registry[serviceName];
|
|
886
885
|
if (!service) throw AppError.notFound(`Unknown service: ${serviceName}`);
|
|
887
|
-
const
|
|
888
|
-
if (!
|
|
889
|
-
const logger = ctx.logger?.child({
|
|
886
|
+
const method = service[methodName];
|
|
887
|
+
if (!method) throw AppError.notFound(`Unknown method: ${serviceName}.${methodName}`);
|
|
888
|
+
const logger = ctx.logger?.child?.({
|
|
890
889
|
component: "service-call",
|
|
891
890
|
service: serviceName,
|
|
892
891
|
method: methodName,
|
|
893
892
|
traceId: ctx.traceId
|
|
894
893
|
});
|
|
894
|
+
const t0 = performance2.now();
|
|
895
895
|
try {
|
|
896
|
-
const
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
896
|
+
const result = await method(params ?? {}, ctx);
|
|
897
|
+
if (typeof result !== "object" || result === null) {
|
|
898
|
+
throw AppError.internal(`Non-object result from ${serviceName}.${methodName}`);
|
|
899
|
+
}
|
|
900
|
+
logger?.debug?.({ ms: +(performance2.now() - t0).toFixed(1) }, "Service method ok");
|
|
901
|
+
return result;
|
|
901
902
|
} catch (err) {
|
|
902
|
-
logger?.error(
|
|
903
|
+
logger?.error?.(
|
|
903
904
|
{
|
|
904
905
|
params,
|
|
905
|
-
error: err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : String(err)
|
|
906
|
+
error: err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : String(err),
|
|
907
|
+
ms: +(performance2.now() - t0).toFixed(1)
|
|
906
908
|
},
|
|
907
909
|
"Service method failed"
|
|
908
910
|
);
|
|
909
|
-
throw err;
|
|
911
|
+
throw err instanceof AppError ? err : err instanceof Error ? AppError.internal(err.message, { cause: err }) : AppError.internal("Unknown error", { details: { err } });
|
|
910
912
|
}
|
|
911
913
|
}
|
|
912
914
|
var isServiceDescriptor = (obj) => {
|
|
913
|
-
if (typeof obj !== "object" ||
|
|
914
|
-
const
|
|
915
|
-
|
|
915
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) return false;
|
|
916
|
+
const o = obj;
|
|
917
|
+
if (typeof o.serviceName !== "string" || typeof o.serviceMethod !== "string") return false;
|
|
918
|
+
if ("args" in o) {
|
|
919
|
+
if (o.args === null || typeof o.args !== "object" || Array.isArray(o.args)) return false;
|
|
920
|
+
}
|
|
921
|
+
return true;
|
|
916
922
|
};
|
|
917
923
|
|
|
918
924
|
// src/utils/DataRoutes.ts
|
|
@@ -1019,6 +1025,16 @@ var createAuthHook = (routeMatchers, logger) => {
|
|
|
1019
1025
|
if (!match2) return;
|
|
1020
1026
|
const { route } = match2;
|
|
1021
1027
|
const authConfig = route.attr?.middleware?.auth;
|
|
1028
|
+
req.routeMeta = {
|
|
1029
|
+
path: route.path,
|
|
1030
|
+
appId: route.appId,
|
|
1031
|
+
attr: {
|
|
1032
|
+
middleware: {
|
|
1033
|
+
auth: route.attr?.middleware?.auth
|
|
1034
|
+
},
|
|
1035
|
+
render: route.attr?.render
|
|
1036
|
+
}
|
|
1037
|
+
};
|
|
1022
1038
|
if (!authConfig) {
|
|
1023
1039
|
logger.debug("auth", { method: req.method, url: req.url }, "(none)");
|
|
1024
1040
|
return;
|
|
@@ -1103,42 +1119,27 @@ var cspPlugin = (0, import_fastify_plugin.default)(
|
|
|
1103
1119
|
fastify.addHook("onRequest", (req, reply, done) => {
|
|
1104
1120
|
const nonce = generateNonce();
|
|
1105
1121
|
req.cspNonce = nonce;
|
|
1122
|
+
const headerNameFor = (routeCSP2) => routeCSP2 && typeof routeCSP2 === "object" && routeCSP2.reportOnly || opts.reporting?.reportOnly ? "Content-Security-Policy-Report-Only" : "Content-Security-Policy";
|
|
1123
|
+
let routeCSP;
|
|
1106
1124
|
try {
|
|
1107
1125
|
const routeMatch = findMatchingRoute(matchers, req.url);
|
|
1108
|
-
|
|
1126
|
+
routeCSP = routeMatch?.route.attr?.middleware?.csp;
|
|
1109
1127
|
if (routeCSP === false) {
|
|
1110
1128
|
done();
|
|
1111
1129
|
return;
|
|
1112
1130
|
}
|
|
1113
1131
|
let finalDirectives = globalDirectives;
|
|
1114
|
-
if (routeCSP && typeof routeCSP === "object") {
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
headers: req.headers,
|
|
1123
|
-
req
|
|
1124
|
-
});
|
|
1125
|
-
} else {
|
|
1126
|
-
routeDirectives = routeCSP.directives || {};
|
|
1127
|
-
}
|
|
1128
|
-
if (routeCSP.mode === "replace") {
|
|
1129
|
-
finalDirectives = routeDirectives;
|
|
1130
|
-
} else {
|
|
1131
|
-
finalDirectives = mergeDirectives(globalDirectives, routeDirectives);
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
let cspHeader;
|
|
1136
|
-
if (routeCSP?.generateCSP) {
|
|
1137
|
-
cspHeader = routeCSP.generateCSP(finalDirectives, nonce, req);
|
|
1138
|
-
} else {
|
|
1139
|
-
cspHeader = generateCSP(finalDirectives, nonce, req);
|
|
1132
|
+
if (routeCSP && typeof routeCSP === "object" && !routeCSP.disabled) {
|
|
1133
|
+
const routeDirectives = typeof routeCSP.directives === "function" ? routeCSP.directives({
|
|
1134
|
+
url: req.url,
|
|
1135
|
+
params: routeMatch?.params || {},
|
|
1136
|
+
headers: req.headers,
|
|
1137
|
+
req
|
|
1138
|
+
}) : routeCSP.directives ?? {};
|
|
1139
|
+
finalDirectives = routeCSP.mode === "replace" ? routeDirectives : mergeDirectives(globalDirectives, routeDirectives);
|
|
1140
1140
|
}
|
|
1141
|
-
|
|
1141
|
+
const cspHeader = routeCSP?.generateCSP ? routeCSP.generateCSP(finalDirectives, nonce, req) : generateCSP(finalDirectives, nonce, req);
|
|
1142
|
+
reply.header(headerNameFor(routeCSP), cspHeader);
|
|
1142
1143
|
} catch (error) {
|
|
1143
1144
|
logger.error(
|
|
1144
1145
|
{
|
|
@@ -1148,7 +1149,7 @@ var cspPlugin = (0, import_fastify_plugin.default)(
|
|
|
1148
1149
|
"CSP plugin error"
|
|
1149
1150
|
);
|
|
1150
1151
|
const fallbackHeader = generateCSP(globalDirectives, nonce, req);
|
|
1151
|
-
reply.header(
|
|
1152
|
+
reply.header(headerNameFor(routeCSP), fallbackHeader);
|
|
1152
1153
|
}
|
|
1153
1154
|
done();
|
|
1154
1155
|
});
|
|
@@ -2024,20 +2025,21 @@ var SSRServer = (0, import_fastify_plugin3.default)(
|
|
|
2024
2025
|
|
|
2025
2026
|
// src/CreateServer.ts
|
|
2026
2027
|
var createServer = async (opts) => {
|
|
2027
|
-
const t0 =
|
|
2028
|
+
const t0 = performance3.now();
|
|
2028
2029
|
const clientRoot = opts.clientRoot ?? path5.resolve(process.cwd(), "client");
|
|
2029
2030
|
const app = opts.fastify ?? Fastify({ logger: false });
|
|
2030
|
-
const
|
|
2031
|
-
await app.register(bannerPlugin, {
|
|
2032
|
-
debug: opts.debug,
|
|
2033
|
-
hmr: { host: net.host, port: net.hmrPort }
|
|
2034
|
-
});
|
|
2031
|
+
const fastifyLogger = app.log && app.log.level !== "silent" ? app.log : void 0;
|
|
2035
2032
|
const logger = createLogger({
|
|
2036
2033
|
debug: opts.debug,
|
|
2037
|
-
custom: opts.logger,
|
|
2034
|
+
custom: opts.logger ?? fastifyLogger,
|
|
2038
2035
|
minLevel: process.env.NODE_ENV === "production" ? "info" : "debug",
|
|
2039
2036
|
includeContext: true
|
|
2040
2037
|
});
|
|
2038
|
+
const net = resolveNet(opts.config.server);
|
|
2039
|
+
await app.register(bannerPlugin, {
|
|
2040
|
+
debug: opts.debug,
|
|
2041
|
+
hmr: { host: net.host, port: net.hmrPort }
|
|
2042
|
+
});
|
|
2041
2043
|
const configs = extractBuildConfigs(opts.config);
|
|
2042
2044
|
const { routes, apps, totalRoutes, durationMs, warnings } = extractRoutes(opts.config);
|
|
2043
2045
|
const { security, durationMs: securityDuration, hasExplicitCSP } = extractSecurity(opts.config);
|
|
@@ -2084,7 +2086,7 @@ var createServer = async (opts) => {
|
|
|
2084
2086
|
"Failed to register SSRServer"
|
|
2085
2087
|
);
|
|
2086
2088
|
}
|
|
2087
|
-
const t1 =
|
|
2089
|
+
const t1 = performance3.now();
|
|
2088
2090
|
console.log(`
|
|
2089
2091
|
${import_picocolors4.default.bgGreen(import_picocolors4.default.black(` ${CONTENT.TAG} `))} configured in ${(t1 - t0).toFixed(0)}ms
|
|
2090
2092
|
`);
|
|
@@ -2174,7 +2176,24 @@ async function taujsBuild({
|
|
|
2174
2176
|
}
|
|
2175
2177
|
}
|
|
2176
2178
|
}
|
|
2179
|
+
|
|
2180
|
+
// src/logging/Adapters.ts
|
|
2181
|
+
var cleanMeta = (m) => m && Object.keys(m).length === 0 ? void 0 : m;
|
|
2182
|
+
function messageMetaAdapter(sink) {
|
|
2183
|
+
return {
|
|
2184
|
+
debug: (meta, message) => sink.debug?.(message, cleanMeta(meta)),
|
|
2185
|
+
info: (meta, message) => sink.info?.(message, cleanMeta(meta)),
|
|
2186
|
+
warn: (meta, message) => sink.warn?.(message, cleanMeta(meta)),
|
|
2187
|
+
error: (meta, message) => sink.error?.(message, cleanMeta(meta)),
|
|
2188
|
+
child: (ctx) => messageMetaAdapter(sink.child?.(ctx) ?? sink)
|
|
2189
|
+
};
|
|
2190
|
+
}
|
|
2191
|
+
function winstonAdapter(winston) {
|
|
2192
|
+
return messageMetaAdapter(winston);
|
|
2193
|
+
}
|
|
2177
2194
|
export {
|
|
2195
|
+
createLogger,
|
|
2178
2196
|
createServer,
|
|
2179
|
-
taujsBuild
|
|
2197
|
+
taujsBuild,
|
|
2198
|
+
winstonAdapter
|
|
2180
2199
|
};
|