@taujs/server 0.4.2 → 0.4.3
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-BuUuMjmO.d.ts → Config-CEhfq8Mm.d.ts} +41 -39
- package/dist/Config.d.ts +1 -1
- package/dist/Config.js +164 -1
- package/dist/index.d.ts +76 -5
- package/dist/index.js +343 -103
- package/package.json +1 -1
|
@@ -6,7 +6,6 @@ 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';
|
|
10
9
|
interface BaseLogger {
|
|
11
10
|
debug?(meta?: Record<string, unknown>, message?: string): void;
|
|
12
11
|
info?(meta?: Record<string, unknown>, message?: string): void;
|
|
@@ -23,41 +22,8 @@ interface Logs extends BaseLogger {
|
|
|
23
22
|
child(context: Record<string, unknown>): Logs;
|
|
24
23
|
isDebugEnabled(category: DebugCategory): boolean;
|
|
25
24
|
}
|
|
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;
|
|
60
25
|
|
|
26
|
+
type RegistryCaller<R extends ServiceRegistry = ServiceRegistry> = (serviceName: keyof R & string, methodName: string, args?: JsonObject) => Promise<JsonObject>;
|
|
61
27
|
type JsonPrimitive = string | number | boolean | null;
|
|
62
28
|
type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
63
29
|
[k: string]: JsonValue;
|
|
@@ -77,7 +43,9 @@ type ServiceContext = {
|
|
|
77
43
|
id: string;
|
|
78
44
|
roles: string[];
|
|
79
45
|
} | null;
|
|
46
|
+
call?: (service: string, method: string, args?: JsonObject) => Promise<JsonObject>;
|
|
80
47
|
};
|
|
48
|
+
declare function withDeadline(signal: AbortSignal | undefined, ms?: number): AbortSignal | undefined;
|
|
81
49
|
type ServiceMethod<P, R extends JsonObject = JsonObject> = (params: P, ctx: ServiceContext) => Promise<R>;
|
|
82
50
|
type ServiceDefinition = Readonly<Record<string, ServiceMethod<any, JsonObject>>>;
|
|
83
51
|
type ServiceRegistry = Readonly<Record<string, ServiceDefinition>>;
|
|
@@ -94,6 +62,7 @@ declare function defineService<T extends Record<string, ServiceMethod<any, JsonO
|
|
|
94
62
|
handler: ServiceMethod<infer P, infer R_1>;
|
|
95
63
|
} ? ServiceMethod<P, R_1> : never; };
|
|
96
64
|
declare const defineServiceRegistry: <R extends ServiceRegistry>(registry: R) => R;
|
|
65
|
+
declare function callServiceMethod(registry: ServiceRegistry, serviceName: string, methodName: string, params: JsonObject | undefined, ctx: ServiceContext): Promise<JsonObject>;
|
|
97
66
|
|
|
98
67
|
type RequestContext<L extends Logs = Logs> = {
|
|
99
68
|
traceId: string;
|
|
@@ -122,7 +91,11 @@ type BaseMiddleware = {
|
|
|
122
91
|
csp?: RouteCSPConfig | false;
|
|
123
92
|
};
|
|
124
93
|
type DataResult = Record<string, unknown> | ServiceDescriptor;
|
|
125
|
-
type
|
|
94
|
+
type RequestServiceContext<L extends Logs = Logs> = RequestContext<L> & {
|
|
95
|
+
call: RegistryCaller<ServiceRegistry>;
|
|
96
|
+
headers?: Record<string, string>;
|
|
97
|
+
};
|
|
98
|
+
type DataHandler<Params extends PathToRegExpParams, L extends Logs = Logs> = (params: Params, ctx: RequestServiceContext<L> & {
|
|
126
99
|
[key: string]: unknown;
|
|
127
100
|
}) => Promise<DataResult>;
|
|
128
101
|
type PathToRegExpParams = Partial<Record<string, string | string[]>>;
|
|
@@ -163,6 +136,35 @@ type CSPViolationReport = {
|
|
|
163
136
|
disposition?: 'enforce' | 'report';
|
|
164
137
|
};
|
|
165
138
|
|
|
139
|
+
type ErrorKind = 'infra' | 'upstream' | 'domain' | 'validation' | 'auth' | 'canceled' | 'timeout';
|
|
140
|
+
declare class AppError extends Error {
|
|
141
|
+
readonly kind: ErrorKind;
|
|
142
|
+
readonly httpStatus: number;
|
|
143
|
+
readonly details?: unknown;
|
|
144
|
+
readonly safeMessage: string;
|
|
145
|
+
readonly code?: string;
|
|
146
|
+
constructor(message: string, kind: ErrorKind, options?: {
|
|
147
|
+
httpStatus?: number;
|
|
148
|
+
details?: unknown;
|
|
149
|
+
cause?: unknown;
|
|
150
|
+
safeMessage?: string;
|
|
151
|
+
code?: string;
|
|
152
|
+
});
|
|
153
|
+
private getSafeMessage;
|
|
154
|
+
private serialiseValue;
|
|
155
|
+
toJSON(): any;
|
|
156
|
+
static notFound(message: string, details?: unknown, code?: string): AppError;
|
|
157
|
+
static forbidden(message: string, details?: unknown, code?: string): AppError;
|
|
158
|
+
static badRequest(message: string, details?: unknown, code?: string): AppError;
|
|
159
|
+
static unprocessable(message: string, details?: unknown, code?: string): AppError;
|
|
160
|
+
static timeout(message: string, details?: unknown, code?: string): AppError;
|
|
161
|
+
static canceled(message: string, details?: unknown, code?: string): AppError;
|
|
162
|
+
static internal(message: string, cause?: unknown, details?: unknown, code?: string): AppError;
|
|
163
|
+
static upstream(message: string, cause?: unknown, details?: unknown, code?: string): AppError;
|
|
164
|
+
static serviceUnavailable(message: string, cause?: unknown, details?: unknown, code?: string): AppError;
|
|
165
|
+
static from(err: unknown, fallback?: string): AppError;
|
|
166
|
+
}
|
|
167
|
+
|
|
166
168
|
/**
|
|
167
169
|
* τjs [ taujs ] Orchestration System
|
|
168
170
|
* (c) 2024-present Aoede Ltd
|
|
@@ -195,15 +197,15 @@ type AppConfig = {
|
|
|
195
197
|
routes?: AppRoute[];
|
|
196
198
|
};
|
|
197
199
|
type TaujsConfig = {
|
|
200
|
+
apps: AppConfig[];
|
|
201
|
+
security?: SecurityConfig;
|
|
198
202
|
server?: {
|
|
199
203
|
host?: string;
|
|
200
204
|
port?: number;
|
|
201
205
|
hmrPort?: number;
|
|
202
206
|
};
|
|
203
|
-
security?: SecurityConfig;
|
|
204
|
-
apps: AppConfig[];
|
|
205
207
|
};
|
|
206
208
|
|
|
207
209
|
declare function defineConfig<T extends TaujsConfig>(config: T): T;
|
|
208
210
|
|
|
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,
|
|
211
|
+
export { type AppConfig as A, type BaseLogger as B, type DebugConfig as D, type InitialRouteParams as I, type RegistryCaller as R, type ServiceRegistry as S, type TaujsConfig as T, type SecurityConfig as a, type AppRoute as b, callServiceMethod as c, defineConfig as d, defineService as e, defineServiceRegistry as f, type ServiceContext as g, AppError as h, withDeadline as w };
|
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, g as ServiceContext, T as TaujsConfig, d as defineConfig,
|
|
3
|
+
export { A as AppConfig, h as AppError, b as AppRoute, R as RegistryCaller, a as SecurityConfig, g as ServiceContext, T as TaujsConfig, c as callServiceMethod, d as defineConfig, e as defineService, f as defineServiceRegistry, w as withDeadline } from './Config-CEhfq8Mm.js';
|
package/dist/Config.js
CHANGED
|
@@ -1,9 +1,137 @@
|
|
|
1
1
|
// src/utils/DataServices.ts
|
|
2
2
|
import { performance } from "perf_hooks";
|
|
3
|
+
|
|
4
|
+
// src/logging/AppError.ts
|
|
5
|
+
var HTTP_STATUS = {
|
|
6
|
+
infra: 500,
|
|
7
|
+
upstream: 502,
|
|
8
|
+
domain: 404,
|
|
9
|
+
validation: 400,
|
|
10
|
+
auth: 403,
|
|
11
|
+
canceled: 499,
|
|
12
|
+
// Client Closed Request (nginx convention)
|
|
13
|
+
timeout: 504
|
|
14
|
+
};
|
|
15
|
+
var AppError = class _AppError extends Error {
|
|
16
|
+
kind;
|
|
17
|
+
httpStatus;
|
|
18
|
+
details;
|
|
19
|
+
safeMessage;
|
|
20
|
+
code;
|
|
21
|
+
constructor(message, kind, options = {}) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = "AppError";
|
|
24
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
25
|
+
if (options.cause !== void 0) {
|
|
26
|
+
Object.defineProperty(this, "cause", {
|
|
27
|
+
value: options.cause,
|
|
28
|
+
enumerable: false,
|
|
29
|
+
writable: false,
|
|
30
|
+
configurable: true
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
this.kind = kind;
|
|
34
|
+
this.httpStatus = options.httpStatus ?? HTTP_STATUS[kind];
|
|
35
|
+
this.details = options.details;
|
|
36
|
+
this.safeMessage = options.safeMessage ?? this.getSafeMessage(kind, message);
|
|
37
|
+
this.code = options.code;
|
|
38
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
|
|
39
|
+
}
|
|
40
|
+
getSafeMessage(kind, message) {
|
|
41
|
+
return kind === "domain" || kind === "validation" || kind === "auth" ? message : "Internal Server Error";
|
|
42
|
+
}
|
|
43
|
+
serialiseValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
44
|
+
if (value === null || value === void 0) return value;
|
|
45
|
+
if (typeof value !== "object") return value;
|
|
46
|
+
if (seen.has(value)) return "[circular]";
|
|
47
|
+
seen.add(value);
|
|
48
|
+
if (value instanceof Error) {
|
|
49
|
+
return {
|
|
50
|
+
name: value.name,
|
|
51
|
+
message: value.message,
|
|
52
|
+
stack: value.stack,
|
|
53
|
+
...value instanceof _AppError && {
|
|
54
|
+
kind: value.kind,
|
|
55
|
+
httpStatus: value.httpStatus,
|
|
56
|
+
code: value.code
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (Array.isArray(value)) return value.map((item) => this.serialiseValue(item, seen));
|
|
61
|
+
const result = {};
|
|
62
|
+
for (const [key, val] of Object.entries(value)) {
|
|
63
|
+
result[key] = this.serialiseValue(val, seen);
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
toJSON() {
|
|
68
|
+
return {
|
|
69
|
+
name: this.name,
|
|
70
|
+
kind: this.kind,
|
|
71
|
+
message: this.message,
|
|
72
|
+
safeMessage: this.safeMessage,
|
|
73
|
+
httpStatus: this.httpStatus,
|
|
74
|
+
...this.code && { code: this.code },
|
|
75
|
+
details: this.serialiseValue(this.details),
|
|
76
|
+
stack: this.stack,
|
|
77
|
+
...this.cause && {
|
|
78
|
+
cause: this.serialiseValue(this.cause)
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
static notFound(message, details, code) {
|
|
83
|
+
return new _AppError(message, "domain", { httpStatus: 404, details, code });
|
|
84
|
+
}
|
|
85
|
+
static forbidden(message, details, code) {
|
|
86
|
+
return new _AppError(message, "auth", { httpStatus: 403, details, code });
|
|
87
|
+
}
|
|
88
|
+
static badRequest(message, details, code) {
|
|
89
|
+
return new _AppError(message, "validation", { httpStatus: 400, details, code });
|
|
90
|
+
}
|
|
91
|
+
static unprocessable(message, details, code) {
|
|
92
|
+
return new _AppError(message, "validation", { httpStatus: 422, details, code });
|
|
93
|
+
}
|
|
94
|
+
static timeout(message, details, code) {
|
|
95
|
+
return new _AppError(message, "timeout", { details, code });
|
|
96
|
+
}
|
|
97
|
+
static canceled(message, details, code) {
|
|
98
|
+
return new _AppError(message, "canceled", { details, code });
|
|
99
|
+
}
|
|
100
|
+
static internal(message, cause, details, code) {
|
|
101
|
+
return new _AppError(message, "infra", { cause, details, code });
|
|
102
|
+
}
|
|
103
|
+
static upstream(message, cause, details, code) {
|
|
104
|
+
return new _AppError(message, "upstream", { cause, details, code });
|
|
105
|
+
}
|
|
106
|
+
static serviceUnavailable(message, cause, details, code) {
|
|
107
|
+
return new _AppError(message, "infra", { httpStatus: 503, cause, details, code });
|
|
108
|
+
}
|
|
109
|
+
static from(err, fallback = "Internal error") {
|
|
110
|
+
return err instanceof _AppError ? err : _AppError.internal(err?.message ?? fallback, err);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// src/utils/DataServices.ts
|
|
3
115
|
var runSchema = (schema, input) => {
|
|
4
116
|
if (!schema) return input;
|
|
5
117
|
return typeof schema.parse === "function" ? schema.parse(input) : schema(input);
|
|
6
118
|
};
|
|
119
|
+
function withDeadline(signal, ms) {
|
|
120
|
+
if (!ms) return signal;
|
|
121
|
+
const ctrl = new AbortController();
|
|
122
|
+
const onAbort = () => ctrl.abort(signal?.reason ?? new Error("Aborted"));
|
|
123
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
124
|
+
const t = setTimeout(() => ctrl.abort(new Error("DeadlineExceeded")), ms);
|
|
125
|
+
ctrl.signal.addEventListener(
|
|
126
|
+
"abort",
|
|
127
|
+
() => {
|
|
128
|
+
clearTimeout(t);
|
|
129
|
+
signal?.removeEventListener("abort", onAbort);
|
|
130
|
+
},
|
|
131
|
+
{ once: true }
|
|
132
|
+
);
|
|
133
|
+
return ctrl.signal;
|
|
134
|
+
}
|
|
7
135
|
function defineService(spec) {
|
|
8
136
|
const out = {};
|
|
9
137
|
for (const [name, v] of Object.entries(spec)) {
|
|
@@ -21,6 +149,38 @@ function defineService(spec) {
|
|
|
21
149
|
return Object.freeze(out);
|
|
22
150
|
}
|
|
23
151
|
var defineServiceRegistry = (registry) => Object.freeze(Object.fromEntries(Object.entries(registry).map(([k, v]) => [k, Object.freeze(v)])));
|
|
152
|
+
async function callServiceMethod(registry, serviceName, methodName, params, ctx) {
|
|
153
|
+
if (ctx.signal?.aborted) throw AppError.timeout("Request canceled");
|
|
154
|
+
const service = registry[serviceName];
|
|
155
|
+
if (!service) throw AppError.notFound(`Unknown service: ${serviceName}`);
|
|
156
|
+
const method = service[methodName];
|
|
157
|
+
if (!method) throw AppError.notFound(`Unknown method: ${serviceName}.${methodName}`);
|
|
158
|
+
const logger = ctx.logger?.child?.({
|
|
159
|
+
component: "service-call",
|
|
160
|
+
service: serviceName,
|
|
161
|
+
method: methodName,
|
|
162
|
+
traceId: ctx.traceId
|
|
163
|
+
});
|
|
164
|
+
const t0 = performance.now();
|
|
165
|
+
try {
|
|
166
|
+
const result = await method(params ?? {}, ctx);
|
|
167
|
+
if (typeof result !== "object" || result === null) {
|
|
168
|
+
throw AppError.internal(`Non-object result from ${serviceName}.${methodName}`);
|
|
169
|
+
}
|
|
170
|
+
logger?.debug?.({ ms: +(performance.now() - t0).toFixed(1) }, "Service method ok");
|
|
171
|
+
return result;
|
|
172
|
+
} catch (err) {
|
|
173
|
+
logger?.error?.(
|
|
174
|
+
{
|
|
175
|
+
params,
|
|
176
|
+
error: err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : String(err),
|
|
177
|
+
ms: +(performance.now() - t0).toFixed(1)
|
|
178
|
+
},
|
|
179
|
+
"Service method failed"
|
|
180
|
+
);
|
|
181
|
+
throw err instanceof AppError ? err : err instanceof Error ? AppError.internal(err.message, { cause: err }) : AppError.internal("Unknown error", { details: { err } });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
24
184
|
|
|
25
185
|
// src/Config.ts
|
|
26
186
|
function defineConfig(config) {
|
|
@@ -28,7 +188,10 @@ function defineConfig(config) {
|
|
|
28
188
|
return config;
|
|
29
189
|
}
|
|
30
190
|
export {
|
|
191
|
+
AppError,
|
|
192
|
+
callServiceMethod,
|
|
31
193
|
defineConfig,
|
|
32
194
|
defineService,
|
|
33
|
-
defineServiceRegistry
|
|
195
|
+
defineServiceRegistry,
|
|
196
|
+
withDeadline
|
|
34
197
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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
|
|
4
|
-
import 'vite';
|
|
2
|
+
import { T as TaujsConfig, S as ServiceRegistry, D as DebugConfig, B as BaseLogger, A as AppConfig } from './Config-CEhfq8Mm.js';
|
|
3
|
+
export { I as InitialRouteParams } from './Config-CEhfq8Mm.js';
|
|
4
|
+
import { InlineConfig } from 'vite';
|
|
5
5
|
|
|
6
6
|
type StaticMountEntry = {
|
|
7
7
|
plugin: FastifyPluginCallback<any> | FastifyPluginAsync<any>;
|
|
@@ -42,13 +42,84 @@ declare const createServer: (opts: CreateServerOptions) => Promise<CreateServerR
|
|
|
42
42
|
* including CSR, SSR, streaming, and middleware composition.
|
|
43
43
|
*/
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
type ViteBuildContext = {
|
|
46
|
+
appId: string;
|
|
47
|
+
entryPoint: string;
|
|
48
|
+
isSSRBuild: boolean;
|
|
49
|
+
clientRoot: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* User-supplied vite config override.
|
|
53
|
+
* Can be a static config object or a function that receives build context.
|
|
54
|
+
*
|
|
55
|
+
* **Plugin order**: Framework applies plugins in this sequence:
|
|
56
|
+
* 1. `appConfig.plugins` (from taujs.config.ts)
|
|
57
|
+
* 2. `nodePolyfills({ include: ['stream'] })` (client builds only)
|
|
58
|
+
* 3. `userViteConfig.plugins` (from this option)
|
|
59
|
+
*
|
|
60
|
+
* If you need plugins before nodePolyfills, add them to `appConfig.plugins` instead.
|
|
61
|
+
*
|
|
62
|
+
* **Allowed customisations:**
|
|
63
|
+
* - `plugins`: Appended to framework plugin list
|
|
64
|
+
* - `define`: Shallow-merged with framework defines
|
|
65
|
+
* - `css.preprocessorOptions`: Deep-merged by preprocessor engine (scss, less, etc.)
|
|
66
|
+
* - `build.sourcemap`, `minify`, `terserOptions`: Direct overrides
|
|
67
|
+
* - `build.rollupOptions.external`: Direct override
|
|
68
|
+
* - `build.rollupOptions.output.manualChunks`: Merged into output config
|
|
69
|
+
* - `resolve.*` (except `alias`): Merged with framework resolve config
|
|
70
|
+
* - `esbuild`, `logLevel`, `optimizeDeps`: Direct overrides
|
|
71
|
+
*
|
|
72
|
+
* **Protected fields (cannot override):**
|
|
73
|
+
* - `root`, `base`, `publicDir`: Framework-controlled per-app paths
|
|
74
|
+
* - `build.outDir`: Framework manages `dist/client` vs `dist/ssr` separation
|
|
75
|
+
* - `build.ssr`, `ssrManifest`, `format`, `target`: Framework-controlled for SSR integrity
|
|
76
|
+
* - `build.rollupOptions.input`: Framework manages entry points
|
|
77
|
+
* - `resolve.alias`: Use top-level `alias` option in taujsBuild() instead
|
|
78
|
+
* - `server.*`: Ignored in builds (dev-mode only; configure in DevServer.ts)
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* // Static config
|
|
83
|
+
* vite: {
|
|
84
|
+
* plugins: [visualizer()],
|
|
85
|
+
* build: { sourcemap: 'inline' }
|
|
86
|
+
* }
|
|
87
|
+
*
|
|
88
|
+
* // Function-based (conditional per app/mode)
|
|
89
|
+
* vite: ({ isSSRBuild, entryPoint }) => ({
|
|
90
|
+
* plugins: isSSRBuild ? [] : [visualizer()],
|
|
91
|
+
* logLevel: entryPoint === 'admin' ? 'info' : 'warn'
|
|
92
|
+
* })
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
type ViteConfigOverride = Partial<InlineConfig> | ((ctx: ViteBuildContext) => Partial<InlineConfig>);
|
|
96
|
+
declare function taujsBuild({ config, projectRoot, clientBaseDir, isSSRBuild, alias: userAlias, vite: userViteConfig, }: {
|
|
46
97
|
config: {
|
|
47
98
|
apps: AppConfig[];
|
|
48
99
|
};
|
|
49
100
|
projectRoot: string;
|
|
50
101
|
clientBaseDir: string;
|
|
51
102
|
isSSRBuild?: boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Top-level alias overrides. Use this instead of `vite.resolve.alias`.
|
|
105
|
+
* User aliases are merged with framework defaults; user values win on conflicts.
|
|
106
|
+
*
|
|
107
|
+
* Framework provides:
|
|
108
|
+
* - `@client`: Resolves to current app's root
|
|
109
|
+
* - `@server`: Resolves to `src/server`
|
|
110
|
+
* - `@shared`: Resolves to `src/shared`
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* alias: {
|
|
115
|
+
* '@utils': './src/utils',
|
|
116
|
+
* '@server': './custom-server', // overrides framework default
|
|
117
|
+
* }
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
alias?: Record<string, string>;
|
|
121
|
+
/** User-supplied Vite config overrides (plugins, tuning, etc.) */
|
|
122
|
+
vite?: ViteConfigOverride;
|
|
52
123
|
}): Promise<void>;
|
|
53
124
|
|
|
54
125
|
interface MessageMetaLogger {
|
|
@@ -60,4 +131,4 @@ interface MessageMetaLogger {
|
|
|
60
131
|
}
|
|
61
132
|
declare function winstonAdapter(winston: MessageMetaLogger): BaseLogger;
|
|
62
133
|
|
|
63
|
-
export { createServer, taujsBuild, winstonAdapter };
|
|
134
|
+
export { BaseLogger, createServer, taujsBuild, winstonAdapter };
|
package/dist/index.js
CHANGED
|
@@ -189,7 +189,7 @@ var require_plugin = __commonJS({
|
|
|
189
189
|
|
|
190
190
|
// src/CreateServer.ts
|
|
191
191
|
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
192
|
-
import
|
|
192
|
+
import path7 from "path";
|
|
193
193
|
import { performance as performance3 } from "perf_hooks";
|
|
194
194
|
import fastifyStatic from "@fastify/static";
|
|
195
195
|
import Fastify from "fastify";
|
|
@@ -259,8 +259,8 @@ var extractRoutes = (taujsConfig) => {
|
|
|
259
259
|
apps.push({ appId: app.appId, routeCount: appRoutes.length });
|
|
260
260
|
allRoutes.push(...appRoutes);
|
|
261
261
|
}
|
|
262
|
-
for (const [
|
|
263
|
-
if (appIds.length > 1) warnings.push(`Route path "${
|
|
262
|
+
for (const [path9, appIds] of pathTracker.entries()) {
|
|
263
|
+
if (appIds.length > 1) warnings.push(`Route path "${path9}" is declared in multiple apps: ${appIds.join(", ")}`);
|
|
264
264
|
}
|
|
265
265
|
const sortedRoutes = allRoutes.sort((a, b) => computeScore(b.path) - computeScore(a.path));
|
|
266
266
|
const durationMs = performance.now() - t0;
|
|
@@ -344,8 +344,8 @@ function printContractReport(logger, report) {
|
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
|
-
var computeScore = (
|
|
348
|
-
return
|
|
347
|
+
var computeScore = (path9) => {
|
|
348
|
+
return path9.split("/").filter(Boolean).reduce((score, segment) => score + (segment.startsWith(":") ? 1 : 10), 0);
|
|
349
349
|
};
|
|
350
350
|
|
|
351
351
|
// src/logging/AppError.ts
|
|
@@ -609,9 +609,11 @@ var Logger = class _Logger {
|
|
|
609
609
|
if (!this.shouldEmit(level)) return;
|
|
610
610
|
const timestamp = this.formatTimestamp();
|
|
611
611
|
const wantCtx = this.config.includeContext === void 0 ? false : typeof this.config.includeContext === "function" ? this.config.includeContext(level) : this.config.includeContext;
|
|
612
|
-
const
|
|
612
|
+
const owner = this.config.custom;
|
|
613
|
+
const rawSink = owner && typeof owner[level] === "function" ? owner[level] : void 0;
|
|
614
|
+
const boundSink = rawSink ? rawSink.bind(owner) : void 0;
|
|
613
615
|
const consoleFallback = level === "error" ? console.error : level === "warn" ? console.warn : console.log;
|
|
614
|
-
const
|
|
616
|
+
const hasCustom = !!boundSink;
|
|
615
617
|
const merged = meta ?? {};
|
|
616
618
|
const withCtx = wantCtx && Object.keys(this.context).length > 0 ? { context: this.context, ...merged } : merged;
|
|
617
619
|
const finalMeta = this.shouldIncludeStack(level) ? withCtx : this.stripStacks(withCtx);
|
|
@@ -632,16 +634,20 @@ var Logger = class _Logger {
|
|
|
632
634
|
return plainTag;
|
|
633
635
|
}
|
|
634
636
|
})();
|
|
635
|
-
const tagForOutput =
|
|
637
|
+
const tagForOutput = hasCustom ? plainTag : coloredTag;
|
|
636
638
|
const formatted = `${timestamp} ${tagForOutput} ${message}`;
|
|
637
|
-
if (this.config.singleLine && hasMeta && !
|
|
639
|
+
if (this.config.singleLine && hasMeta && !hasCustom) {
|
|
638
640
|
const metaStr = JSON.stringify(finalMeta).replace(/\n/g, "\\n");
|
|
639
641
|
consoleFallback(`${formatted} ${metaStr}`);
|
|
640
642
|
return;
|
|
641
643
|
}
|
|
642
|
-
if (
|
|
644
|
+
if (hasCustom) {
|
|
643
645
|
const obj = hasMeta ? finalMeta : {};
|
|
644
|
-
|
|
646
|
+
try {
|
|
647
|
+
const result = boundSink(obj, formatted);
|
|
648
|
+
} catch (err) {
|
|
649
|
+
hasMeta ? consoleFallback(formatted, finalMeta) : consoleFallback(formatted);
|
|
650
|
+
}
|
|
645
651
|
} else {
|
|
646
652
|
hasMeta ? consoleFallback(formatted, finalMeta) : consoleFallback(formatted);
|
|
647
653
|
}
|
|
@@ -839,6 +845,7 @@ var verifyContracts = (app, routes, contracts, security) => {
|
|
|
839
845
|
|
|
840
846
|
// src/SSRServer.ts
|
|
841
847
|
var import_fastify_plugin3 = __toESM(require_plugin(), 1);
|
|
848
|
+
import path6 from "path";
|
|
842
849
|
|
|
843
850
|
// src/logging/utils/index.ts
|
|
844
851
|
var httpStatusFrom = (err, fallback = 500) => err instanceof AppError ? err.httpStatus : fallback;
|
|
@@ -879,6 +886,12 @@ import { match } from "path-to-regexp";
|
|
|
879
886
|
|
|
880
887
|
// src/utils/DataServices.ts
|
|
881
888
|
import { performance as performance2 } from "perf_hooks";
|
|
889
|
+
function createCaller(registry, ctx) {
|
|
890
|
+
return (serviceName, methodName, args) => callServiceMethod(registry, serviceName, methodName, args ?? {}, ctx);
|
|
891
|
+
}
|
|
892
|
+
function ensureServiceCaller(registry, ctx) {
|
|
893
|
+
if (!ctx.call) ctx.call = createCaller(registry, ctx);
|
|
894
|
+
}
|
|
882
895
|
async function callServiceMethod(registry, serviceName, methodName, params, ctx) {
|
|
883
896
|
if (ctx.signal?.aborted) throw AppError.timeout("Request canceled");
|
|
884
897
|
const service = registry[serviceName];
|
|
@@ -929,15 +942,15 @@ var safeDecode = (value) => {
|
|
|
929
942
|
return value;
|
|
930
943
|
}
|
|
931
944
|
};
|
|
932
|
-
var cleanPath = (
|
|
933
|
-
if (!
|
|
934
|
-
const basePart =
|
|
945
|
+
var cleanPath = (path9) => {
|
|
946
|
+
if (!path9) return "/";
|
|
947
|
+
const basePart = path9.split("?")[0];
|
|
935
948
|
const base = basePart ? basePart.split("#")[0] : "/";
|
|
936
949
|
return base || "/";
|
|
937
950
|
};
|
|
938
|
-
var calculateSpecificity = (
|
|
951
|
+
var calculateSpecificity = (path9) => {
|
|
939
952
|
let score = 0;
|
|
940
|
-
const segments =
|
|
953
|
+
const segments = path9.split("/").filter(Boolean);
|
|
941
954
|
for (const segment of segments) {
|
|
942
955
|
if (segment.startsWith(":")) {
|
|
943
956
|
score += 1;
|
|
@@ -962,9 +975,9 @@ var createRouteMatchers = (routes) => {
|
|
|
962
975
|
});
|
|
963
976
|
};
|
|
964
977
|
var matchRoute = (url, routeMatchers) => {
|
|
965
|
-
const
|
|
978
|
+
const path9 = cleanPath(url);
|
|
966
979
|
for (const { route, matcher, keys } of routeMatchers) {
|
|
967
|
-
const match2 = matcher(
|
|
980
|
+
const match2 = matcher(path9);
|
|
968
981
|
if (match2) {
|
|
969
982
|
return {
|
|
970
983
|
route,
|
|
@@ -978,14 +991,16 @@ var matchRoute = (url, routeMatchers) => {
|
|
|
978
991
|
var fetchInitialData = async (attr, params, serviceRegistry, ctx, callServiceMethodImpl = callServiceMethod) => {
|
|
979
992
|
const dataHandler = attr?.data;
|
|
980
993
|
if (!dataHandler || typeof dataHandler !== "function") return {};
|
|
994
|
+
const ctxForData = {
|
|
995
|
+
...ctx,
|
|
996
|
+
headers: ctx.headers ?? {}
|
|
997
|
+
};
|
|
998
|
+
ensureServiceCaller(serviceRegistry, ctxForData);
|
|
981
999
|
try {
|
|
982
|
-
const result = await dataHandler(params,
|
|
983
|
-
...ctx,
|
|
984
|
-
headers: ctx.headers ?? {}
|
|
985
|
-
});
|
|
1000
|
+
const result = await dataHandler(params, ctxForData);
|
|
986
1001
|
if (isServiceDescriptor(result)) {
|
|
987
1002
|
const { serviceName, serviceMethod, args } = result;
|
|
988
|
-
return callServiceMethodImpl(serviceRegistry, serviceName, serviceMethod, args ?? {},
|
|
1003
|
+
return callServiceMethodImpl(serviceRegistry, serviceName, serviceMethod, args ?? {}, ctxForData);
|
|
989
1004
|
}
|
|
990
1005
|
if (isPlainObject(result)) return result;
|
|
991
1006
|
throw AppError.badRequest("attr.data must return a plain object or a ServiceDescriptor");
|
|
@@ -1102,9 +1117,9 @@ var mergeDirectives = (base, override) => {
|
|
|
1102
1117
|
}
|
|
1103
1118
|
return merged;
|
|
1104
1119
|
};
|
|
1105
|
-
var findMatchingRoute = (routeMatchers,
|
|
1120
|
+
var findMatchingRoute = (routeMatchers, path9) => {
|
|
1106
1121
|
if (!routeMatchers) return null;
|
|
1107
|
-
const match2 = matchRoute(
|
|
1122
|
+
const match2 = matchRoute(path9, routeMatchers);
|
|
1108
1123
|
return match2 ? { route: match2.route, params: match2.params } : null;
|
|
1109
1124
|
};
|
|
1110
1125
|
var cspPlugin = (0, import_fastify_plugin.default)(
|
|
@@ -1434,8 +1449,9 @@ var loadAssets = async (processedConfigs, baseClientRoot, bootstrapModules, cssL
|
|
|
1434
1449
|
debug: opts.debug,
|
|
1435
1450
|
includeContext: true
|
|
1436
1451
|
});
|
|
1452
|
+
const projectRoot = opts.projectRoot ?? path2.resolve(process.cwd());
|
|
1437
1453
|
for (const config of processedConfigs) {
|
|
1438
|
-
const { clientRoot, entryClient, entryServer, htmlTemplate } = config;
|
|
1454
|
+
const { clientRoot, entryClient, entryServer, htmlTemplate, entryPoint } = config;
|
|
1439
1455
|
try {
|
|
1440
1456
|
const templateHtmlPath = path2.join(clientRoot, htmlTemplate);
|
|
1441
1457
|
const templateHtml = await readFile(templateHtmlPath, "utf-8");
|
|
@@ -1444,11 +1460,13 @@ var loadAssets = async (processedConfigs, baseClientRoot, bootstrapModules, cssL
|
|
|
1444
1460
|
const adjustedRelativePath = relativeBasePath ? `/${relativeBasePath}` : "";
|
|
1445
1461
|
if (!isDevelopment) {
|
|
1446
1462
|
try {
|
|
1447
|
-
const
|
|
1463
|
+
const clientDistPath = path2.resolve(projectRoot, "client", entryPoint);
|
|
1464
|
+
const manifestPath = path2.join(clientDistPath, ".vite/manifest.json");
|
|
1448
1465
|
const manifestContent = await readFile(manifestPath, "utf-8");
|
|
1449
1466
|
const manifest = JSON.parse(manifestContent);
|
|
1450
1467
|
manifests.set(clientRoot, manifest);
|
|
1451
|
-
const
|
|
1468
|
+
const ssrDistPath = path2.resolve(projectRoot, "ssr", entryPoint);
|
|
1469
|
+
const ssrManifestPath = path2.join(ssrDistPath, ".vite/ssr-manifest.json");
|
|
1452
1470
|
const ssrManifestContent = await readFile(ssrManifestPath, "utf-8");
|
|
1453
1471
|
const ssrManifest = JSON.parse(ssrManifestContent);
|
|
1454
1472
|
ssrManifests.set(clientRoot, ssrManifest);
|
|
@@ -1468,7 +1486,7 @@ var loadAssets = async (processedConfigs, baseClientRoot, bootstrapModules, cssL
|
|
|
1468
1486
|
preloadLinks.set(clientRoot, preloadLink);
|
|
1469
1487
|
const cssLink = getCssLinks(manifest, adjustedRelativePath);
|
|
1470
1488
|
cssLinks.set(clientRoot, cssLink);
|
|
1471
|
-
const renderModulePath = path2.join(
|
|
1489
|
+
const renderModulePath = path2.join(ssrDistPath, `${entryServer}.js`);
|
|
1472
1490
|
const moduleUrl = pathToFileURL(renderModulePath).href;
|
|
1473
1491
|
try {
|
|
1474
1492
|
const importedModule = await import(moduleUrl);
|
|
@@ -1476,7 +1494,7 @@ var loadAssets = async (processedConfigs, baseClientRoot, bootstrapModules, cssL
|
|
|
1476
1494
|
} catch (err) {
|
|
1477
1495
|
throw AppError.internal(`Failed to load render module ${renderModulePath}`, {
|
|
1478
1496
|
cause: err,
|
|
1479
|
-
details: { moduleUrl, clientRoot, entryServer }
|
|
1497
|
+
details: { moduleUrl, clientRoot, entryServer, ssrDistPath }
|
|
1480
1498
|
});
|
|
1481
1499
|
}
|
|
1482
1500
|
} catch (err) {
|
|
@@ -1687,10 +1705,15 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1687
1705
|
if (renderType === RENDERTYPE.ssr) {
|
|
1688
1706
|
const { renderSSR } = renderModule;
|
|
1689
1707
|
if (!renderSSR) {
|
|
1690
|
-
throw AppError.internal(
|
|
1691
|
-
|
|
1692
|
-
|
|
1708
|
+
throw AppError.internal(
|
|
1709
|
+
"ssr",
|
|
1710
|
+
{
|
|
1711
|
+
details: { clientRoot, availableFunctions: Object.keys(renderModule) }
|
|
1712
|
+
},
|
|
1713
|
+
"renderSSR function not found in module"
|
|
1714
|
+
);
|
|
1693
1715
|
}
|
|
1716
|
+
logger.debug?.("ssr", {}, "ssr requested");
|
|
1694
1717
|
const ac = new AbortController();
|
|
1695
1718
|
const onAborted = () => ac.abort("client_aborted");
|
|
1696
1719
|
req.raw.on("aborted", onAborted);
|
|
@@ -1699,7 +1722,7 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1699
1722
|
});
|
|
1700
1723
|
reply.raw.on("finish", () => req.raw.off("aborted", onAborted));
|
|
1701
1724
|
if (ac.signal.aborted) {
|
|
1702
|
-
logger.warn("SSR skipped; already aborted"
|
|
1725
|
+
logger.warn({ url: req.url }, "SSR skipped; already aborted");
|
|
1703
1726
|
return;
|
|
1704
1727
|
}
|
|
1705
1728
|
const initialDataResolved = await initialDataInput();
|
|
@@ -1709,14 +1732,31 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1709
1732
|
const res = await renderSSR(initialDataResolved, req.url, attr?.meta, ac.signal, { logger: reqLogger });
|
|
1710
1733
|
headContent = res.headContent;
|
|
1711
1734
|
appHtml = res.appHtml;
|
|
1735
|
+
logger.debug?.("ssr", {}, "ssr data resolved");
|
|
1736
|
+
if (ac.signal.aborted) {
|
|
1737
|
+
logger.warn({}, "SSR completed but client disconnected");
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1712
1740
|
} catch (err) {
|
|
1713
1741
|
const msg = String(err?.message ?? err ?? "");
|
|
1714
1742
|
const benign = REGEX.BENIGN_NET_ERR.test(msg);
|
|
1715
1743
|
if (ac.signal.aborted || benign) {
|
|
1716
|
-
logger.warn(
|
|
1744
|
+
logger.warn(
|
|
1745
|
+
{
|
|
1746
|
+
url: req.url,
|
|
1747
|
+
reason: msg
|
|
1748
|
+
},
|
|
1749
|
+
"SSR aborted mid-render (benign)"
|
|
1750
|
+
);
|
|
1717
1751
|
return;
|
|
1718
1752
|
}
|
|
1719
|
-
logger.error(
|
|
1753
|
+
logger.error(
|
|
1754
|
+
{
|
|
1755
|
+
url: req.url,
|
|
1756
|
+
error: normaliseError(err)
|
|
1757
|
+
},
|
|
1758
|
+
"SSR render failed"
|
|
1759
|
+
);
|
|
1720
1760
|
throw err;
|
|
1721
1761
|
}
|
|
1722
1762
|
let aggregateHeadContent = headContent;
|
|
@@ -1728,13 +1768,14 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1728
1768
|
const bootstrapScriptTag = shouldHydrate && bootstrapModule ? `<script${nonceAttr} type="module" src="${bootstrapModule}" defer></script>` : "";
|
|
1729
1769
|
const safeAppHtml = appHtml.trim();
|
|
1730
1770
|
const fullHtml = rebuildTemplate(templateParts, aggregateHeadContent, `${safeAppHtml}${initialDataScript}${bootstrapScriptTag}`);
|
|
1771
|
+
logger.debug?.("ssr", {}, "ssr template rebuilt and sending response");
|
|
1731
1772
|
try {
|
|
1732
1773
|
return reply.status(200).header("Content-Type", "text/html").send(fullHtml);
|
|
1733
1774
|
} catch (err) {
|
|
1734
1775
|
const msg = String(err?.message ?? err ?? "");
|
|
1735
1776
|
const benign = REGEX.BENIGN_NET_ERR.test(msg);
|
|
1736
|
-
if (!benign) logger.error(
|
|
1737
|
-
else logger.warn(
|
|
1777
|
+
if (!benign) logger.error({ url: req.url, error: normaliseError(err) }, "SSR send failed");
|
|
1778
|
+
else logger.warn({ url: req.url, reason: msg }, "SSR send aborted (benign)");
|
|
1738
1779
|
return;
|
|
1739
1780
|
}
|
|
1740
1781
|
} else {
|
|
@@ -1744,30 +1785,44 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1744
1785
|
details: { clientRoot, availableFunctions: Object.keys(renderModule) }
|
|
1745
1786
|
});
|
|
1746
1787
|
}
|
|
1788
|
+
const headers2 = reply.getHeaders();
|
|
1789
|
+
headers2["Content-Type"] = "text/html; charset=utf-8";
|
|
1747
1790
|
const cspHeader = reply.getHeader("Content-Security-Policy");
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
});
|
|
1791
|
+
if (cspHeader) headers2["Content-Security-Policy"] = cspHeader;
|
|
1792
|
+
reply.raw.writeHead(200, headers2);
|
|
1793
|
+
const abortedState = { aborted: false };
|
|
1752
1794
|
const ac = new AbortController();
|
|
1753
|
-
const onAborted = () =>
|
|
1795
|
+
const onAborted = () => {
|
|
1796
|
+
if (!abortedState.aborted) {
|
|
1797
|
+
logger.warn({}, "Client disconnected before stream finished");
|
|
1798
|
+
abortedState.aborted = true;
|
|
1799
|
+
}
|
|
1800
|
+
ac.abort();
|
|
1801
|
+
};
|
|
1754
1802
|
req.raw.on("aborted", onAborted);
|
|
1755
1803
|
reply.raw.on("close", () => {
|
|
1756
|
-
if (!reply.raw.writableEnded)
|
|
1804
|
+
if (!reply.raw.writableEnded) {
|
|
1805
|
+
if (!abortedState.aborted) {
|
|
1806
|
+
logger.warn({}, "Client disconnected before stream finished");
|
|
1807
|
+
abortedState.aborted = true;
|
|
1808
|
+
}
|
|
1809
|
+
ac.abort();
|
|
1810
|
+
}
|
|
1811
|
+
});
|
|
1812
|
+
reply.raw.on("finish", () => {
|
|
1813
|
+
req.raw.off("aborted", onAborted);
|
|
1757
1814
|
});
|
|
1758
|
-
reply.raw.on("finish", () => req.raw.off("aborted", onAborted));
|
|
1759
1815
|
const shouldHydrate = attr?.hydrate !== false;
|
|
1760
|
-
const abortedState = { aborted: false };
|
|
1761
1816
|
const isBenignSocketAbort = (e) => {
|
|
1762
1817
|
const msg = String(e?.message ?? e ?? "");
|
|
1763
1818
|
return REGEX.BENIGN_NET_ERR.test(msg);
|
|
1764
1819
|
};
|
|
1765
1820
|
const writable = new PassThrough();
|
|
1766
1821
|
writable.on("error", (err) => {
|
|
1767
|
-
if (!isBenignSocketAbort(err)) logger.error(
|
|
1822
|
+
if (!isBenignSocketAbort(err)) logger.error({ error: err }, "PassThrough error:");
|
|
1768
1823
|
});
|
|
1769
1824
|
reply.raw.on("error", (err) => {
|
|
1770
|
-
if (!isBenignSocketAbort(err)) logger.error("HTTP socket error:"
|
|
1825
|
+
if (!isBenignSocketAbort(err)) logger.error({ error: err }, "HTTP socket error:");
|
|
1771
1826
|
});
|
|
1772
1827
|
writable.pipe(reply.raw, { end: false });
|
|
1773
1828
|
let finalData = void 0;
|
|
@@ -1787,30 +1842,33 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1787
1842
|
},
|
|
1788
1843
|
onError: (err) => {
|
|
1789
1844
|
if (abortedState.aborted || isBenignSocketAbort(err)) {
|
|
1790
|
-
logger.warn("Client disconnected before stream finished");
|
|
1845
|
+
logger.warn({}, "Client disconnected before stream finished");
|
|
1791
1846
|
try {
|
|
1792
1847
|
if (!reply.raw.writableEnded && !reply.raw.destroyed) reply.raw.destroy();
|
|
1793
1848
|
} catch (e) {
|
|
1794
|
-
logger.debug?.("
|
|
1849
|
+
logger.debug?.("ssr", { error: normaliseError(e) }, "stream teardown: destroy() failed");
|
|
1795
1850
|
}
|
|
1796
1851
|
return;
|
|
1797
1852
|
}
|
|
1798
1853
|
abortedState.aborted = true;
|
|
1799
|
-
logger.error(
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1854
|
+
logger.error(
|
|
1855
|
+
{
|
|
1856
|
+
error: normaliseError(err),
|
|
1857
|
+
clientRoot,
|
|
1858
|
+
url: req.url
|
|
1859
|
+
},
|
|
1860
|
+
"Critical rendering error during stream"
|
|
1861
|
+
);
|
|
1804
1862
|
try {
|
|
1805
1863
|
ac?.abort?.();
|
|
1806
1864
|
} catch (e) {
|
|
1807
|
-
logger.debug?.("
|
|
1865
|
+
logger.debug?.("ssr", { error: normaliseError(e) }, "stream teardown: abort() failed");
|
|
1808
1866
|
}
|
|
1809
1867
|
const reason = toReason(err);
|
|
1810
1868
|
try {
|
|
1811
1869
|
if (!reply.raw.writableEnded && !reply.raw.destroyed) reply.raw.destroy(reason);
|
|
1812
1870
|
} catch (e) {
|
|
1813
|
-
logger.debug?.("
|
|
1871
|
+
logger.debug?.("ssr", { error: normaliseError(e) }, "stream teardown: destroy() failed");
|
|
1814
1872
|
}
|
|
1815
1873
|
}
|
|
1816
1874
|
},
|
|
@@ -1897,8 +1955,33 @@ var handleNotFound = async (req, reply, processedConfigs, maps, opts = {}) => {
|
|
|
1897
1955
|
}
|
|
1898
1956
|
};
|
|
1899
1957
|
|
|
1958
|
+
// src/utils/ResolveRouteData.ts
|
|
1959
|
+
async function resolveRouteData(url, opts) {
|
|
1960
|
+
const { req, reply, routeMatchers, serviceRegistry, logger } = opts;
|
|
1961
|
+
const match2 = matchRoute(url, routeMatchers);
|
|
1962
|
+
if (!match2) {
|
|
1963
|
+
throw AppError.notFound("route_not_found", {
|
|
1964
|
+
details: { url }
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
const { route, params } = match2;
|
|
1968
|
+
const attr = route.attr;
|
|
1969
|
+
if (!attr?.data) {
|
|
1970
|
+
throw AppError.notFound("no_data_handler", {
|
|
1971
|
+
details: {
|
|
1972
|
+
url,
|
|
1973
|
+
path: route.path,
|
|
1974
|
+
appId: route.appId
|
|
1975
|
+
}
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
const ctx = createRequestContext(req, reply, logger);
|
|
1979
|
+
return fetchInitialData(attr, params, serviceRegistry, ctx);
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1900
1982
|
// src/utils/StaticAssets.ts
|
|
1901
|
-
|
|
1983
|
+
import path5 from "path";
|
|
1984
|
+
function normaliseStaticAssets(reg) {
|
|
1902
1985
|
if (!reg) return [];
|
|
1903
1986
|
return Array.isArray(reg) ? reg : [reg];
|
|
1904
1987
|
}
|
|
@@ -1906,11 +1989,14 @@ function prefixWeight(prefix) {
|
|
|
1906
1989
|
if (typeof prefix !== "string" || prefix === "/" || prefix.length === 0) return 0;
|
|
1907
1990
|
return prefix.split("/").filter(Boolean).length;
|
|
1908
1991
|
}
|
|
1909
|
-
async function registerStaticAssets(app, baseClientRoot, reg, defaults) {
|
|
1910
|
-
const
|
|
1992
|
+
async function registerStaticAssets(app, baseClientRoot, reg, defaults, projectRoot) {
|
|
1993
|
+
const isDevelopment2 = process.env.NODE_ENV === "development";
|
|
1994
|
+
const effectiveProjectRoot = projectRoot ?? path5.resolve(process.cwd());
|
|
1995
|
+
const staticRoot = isDevelopment2 ? baseClientRoot : path5.resolve(effectiveProjectRoot, "client");
|
|
1996
|
+
const entries = normaliseStaticAssets(reg).map(({ plugin, options }) => ({
|
|
1911
1997
|
plugin,
|
|
1912
1998
|
options: {
|
|
1913
|
-
root:
|
|
1999
|
+
root: staticRoot,
|
|
1914
2000
|
prefix: "/",
|
|
1915
2001
|
index: false,
|
|
1916
2002
|
wildcard: false,
|
|
@@ -1939,6 +2025,7 @@ var SSRServer = (0, import_fastify_plugin3.default)(
|
|
|
1939
2025
|
const processedConfigs = processConfigs(configs, baseClientRoot, TEMPLATE);
|
|
1940
2026
|
const routeMatchers = createRouteMatchers(routes);
|
|
1941
2027
|
let viteDevServer;
|
|
2028
|
+
const projectRoot = path6.resolve(baseClientRoot, "..");
|
|
1942
2029
|
await loadAssets(
|
|
1943
2030
|
processedConfigs,
|
|
1944
2031
|
baseClientRoot,
|
|
@@ -1951,10 +2038,11 @@ var SSRServer = (0, import_fastify_plugin3.default)(
|
|
|
1951
2038
|
maps.templates,
|
|
1952
2039
|
{
|
|
1953
2040
|
debug: opts.debug,
|
|
1954
|
-
logger
|
|
2041
|
+
logger,
|
|
2042
|
+
projectRoot
|
|
1955
2043
|
}
|
|
1956
2044
|
);
|
|
1957
|
-
if (opts.staticAssets) await registerStaticAssets(app, baseClientRoot, opts.staticAssets);
|
|
2045
|
+
if (opts.staticAssets) await registerStaticAssets(app, baseClientRoot, opts.staticAssets, void 0, projectRoot);
|
|
1958
2046
|
if (security?.csp?.reporting) {
|
|
1959
2047
|
app.register(cspReportPlugin, {
|
|
1960
2048
|
path: security.csp.reporting.endpoint,
|
|
@@ -1971,6 +2059,23 @@ var SSRServer = (0, import_fastify_plugin3.default)(
|
|
|
1971
2059
|
});
|
|
1972
2060
|
if (isDevelopment) viteDevServer = await setupDevServer(app, baseClientRoot, alias, opts.debug, opts.devNet);
|
|
1973
2061
|
app.addHook("onRequest", createAuthHook(routeMatchers, logger));
|
|
2062
|
+
app.get("/__taujs/data", async (req, reply) => {
|
|
2063
|
+
const query = req.query;
|
|
2064
|
+
const url = typeof query.url === "string" ? query.url : "";
|
|
2065
|
+
if (!url) {
|
|
2066
|
+
throw AppError.badRequest("url query param required", {
|
|
2067
|
+
details: { query }
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
2070
|
+
const data = await resolveRouteData(url, {
|
|
2071
|
+
req,
|
|
2072
|
+
reply,
|
|
2073
|
+
routeMatchers,
|
|
2074
|
+
serviceRegistry,
|
|
2075
|
+
logger
|
|
2076
|
+
});
|
|
2077
|
+
return reply.status(200).send({ data });
|
|
2078
|
+
});
|
|
1974
2079
|
app.get("/*", async (req, reply) => {
|
|
1975
2080
|
await handleRender(req, reply, routeMatchers, processedConfigs, serviceRegistry, maps, {
|
|
1976
2081
|
debug: opts.debug,
|
|
@@ -2026,9 +2131,9 @@ var SSRServer = (0, import_fastify_plugin3.default)(
|
|
|
2026
2131
|
// src/CreateServer.ts
|
|
2027
2132
|
var createServer = async (opts) => {
|
|
2028
2133
|
const t0 = performance3.now();
|
|
2029
|
-
const clientRoot = opts.clientRoot ??
|
|
2134
|
+
const clientRoot = opts.clientRoot ?? path7.resolve(process.cwd(), "client");
|
|
2030
2135
|
const app = opts.fastify ?? Fastify({ logger: false });
|
|
2031
|
-
const fastifyLogger = app.log && app.log.level !== "silent" ? app.log : void 0;
|
|
2136
|
+
const fastifyLogger = app.log && app.log.level && app.log.level !== "silent" ? app.log : void 0;
|
|
2032
2137
|
const logger = createLogger({
|
|
2033
2138
|
debug: opts.debug,
|
|
2034
2139
|
custom: opts.logger ?? fastifyLogger,
|
|
@@ -2095,18 +2200,149 @@ ${import_picocolors4.default.bgGreen(import_picocolors4.default.black(` ${CONTEN
|
|
|
2095
2200
|
};
|
|
2096
2201
|
|
|
2097
2202
|
// src/Build.ts
|
|
2098
|
-
import
|
|
2203
|
+
import { existsSync } from "fs";
|
|
2204
|
+
import path8 from "path";
|
|
2099
2205
|
import { build } from "vite";
|
|
2100
|
-
|
|
2206
|
+
function resolveInputs(isSSRBuild, mainExists, paths) {
|
|
2207
|
+
if (isSSRBuild) return { server: paths.server };
|
|
2208
|
+
if (mainExists) return { client: paths.client, main: paths.main };
|
|
2209
|
+
return { client: paths.client };
|
|
2210
|
+
}
|
|
2211
|
+
function getFrameworkInvariants(config) {
|
|
2212
|
+
return {
|
|
2213
|
+
root: config.root || "",
|
|
2214
|
+
base: config.base || "/",
|
|
2215
|
+
publicDir: config.publicDir === void 0 ? "public" : config.publicDir,
|
|
2216
|
+
build: {
|
|
2217
|
+
outDir: config.build?.outDir || "",
|
|
2218
|
+
manifest: config.build?.manifest ?? false,
|
|
2219
|
+
ssr: config.build?.ssr ?? void 0,
|
|
2220
|
+
// Preserve exact type
|
|
2221
|
+
ssrManifest: config.build?.ssrManifest ?? false,
|
|
2222
|
+
format: config.build?.format,
|
|
2223
|
+
target: config.build?.target,
|
|
2224
|
+
rollupOptions: {
|
|
2225
|
+
input: config.build?.rollupOptions?.input || {}
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
};
|
|
2229
|
+
}
|
|
2230
|
+
function mergeViteConfig(framework, userOverride, context) {
|
|
2231
|
+
if (!userOverride) return framework;
|
|
2232
|
+
const userConfig = typeof userOverride === "function" && context ? userOverride(context) : userOverride;
|
|
2233
|
+
const invariants = getFrameworkInvariants(framework);
|
|
2234
|
+
const merged = {
|
|
2235
|
+
...framework,
|
|
2236
|
+
build: { ...framework.build ?? {} },
|
|
2237
|
+
css: { ...framework.css ?? {} },
|
|
2238
|
+
resolve: { ...framework.resolve ?? {} },
|
|
2239
|
+
plugins: [...framework.plugins ?? []],
|
|
2240
|
+
define: { ...framework.define ?? {} }
|
|
2241
|
+
};
|
|
2242
|
+
const ignoredKeys = [];
|
|
2243
|
+
if (userConfig.plugins) {
|
|
2244
|
+
const frameworkPlugins = merged.plugins;
|
|
2245
|
+
merged.plugins = [...frameworkPlugins, ...userConfig.plugins];
|
|
2246
|
+
}
|
|
2247
|
+
if (userConfig.define && typeof userConfig.define === "object") {
|
|
2248
|
+
merged.define = {
|
|
2249
|
+
...merged.define,
|
|
2250
|
+
...userConfig.define
|
|
2251
|
+
};
|
|
2252
|
+
}
|
|
2253
|
+
if (userConfig.css?.preprocessorOptions && typeof userConfig.css.preprocessorOptions === "object") {
|
|
2254
|
+
const fpp = merged.css.preprocessorOptions ?? {};
|
|
2255
|
+
const upp = userConfig.css.preprocessorOptions;
|
|
2256
|
+
merged.css.preprocessorOptions = Object.keys({ ...fpp, ...upp }).reduce((acc, engine) => {
|
|
2257
|
+
const fppEngine = fpp[engine];
|
|
2258
|
+
const uppEngine = upp[engine];
|
|
2259
|
+
acc[engine] = { ...fppEngine ?? {}, ...uppEngine ?? {} };
|
|
2260
|
+
return acc;
|
|
2261
|
+
}, {});
|
|
2262
|
+
}
|
|
2263
|
+
if (userConfig.build) {
|
|
2264
|
+
const protectedBuildFields = ["outDir", "ssr", "ssrManifest", "format", "target"];
|
|
2265
|
+
for (const field of protectedBuildFields) {
|
|
2266
|
+
if (field in userConfig.build) {
|
|
2267
|
+
ignoredKeys.push(`build.${field}`);
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
if ("sourcemap" in userConfig.build) merged.build.sourcemap = userConfig.build.sourcemap;
|
|
2271
|
+
if ("minify" in userConfig.build) merged.build.minify = userConfig.build.minify;
|
|
2272
|
+
if (userConfig.build.terserOptions && typeof userConfig.build.terserOptions === "object") {
|
|
2273
|
+
merged.build.terserOptions = {
|
|
2274
|
+
...merged.build.terserOptions ?? {},
|
|
2275
|
+
...userConfig.build.terserOptions
|
|
2276
|
+
};
|
|
2277
|
+
}
|
|
2278
|
+
if (userConfig.build.rollupOptions) {
|
|
2279
|
+
if (!merged.build.rollupOptions) {
|
|
2280
|
+
merged.build.rollupOptions = {};
|
|
2281
|
+
}
|
|
2282
|
+
const userRollup = userConfig.build.rollupOptions;
|
|
2283
|
+
if ("input" in userRollup) ignoredKeys.push("build.rollupOptions.input");
|
|
2284
|
+
if ("external" in userRollup) merged.build.rollupOptions.external = userRollup.external;
|
|
2285
|
+
if (userRollup.output) {
|
|
2286
|
+
const mro = merged.build.rollupOptions ??= {};
|
|
2287
|
+
const uo = Array.isArray(userRollup.output) ? userRollup.output[0] : userRollup.output;
|
|
2288
|
+
const baseOut = Array.isArray(mro.output) ? mro.output[0] ?? {} : mro.output ?? {};
|
|
2289
|
+
mro.output = { ...baseOut, ...uo?.manualChunks ? { manualChunks: uo.manualChunks } : {} };
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
if (userConfig.resolve) {
|
|
2294
|
+
const userResolve = userConfig.resolve;
|
|
2295
|
+
const { alias: _ignore, ...resolveRest } = userResolve;
|
|
2296
|
+
if (_ignore) ignoredKeys.push("resolve.alias");
|
|
2297
|
+
merged.resolve = {
|
|
2298
|
+
...merged.resolve,
|
|
2299
|
+
...resolveRest
|
|
2300
|
+
};
|
|
2301
|
+
}
|
|
2302
|
+
if (userConfig.server) ignoredKeys.push("server (ignored in build; dev-only)");
|
|
2303
|
+
if ("root" in userConfig) ignoredKeys.push("root");
|
|
2304
|
+
if ("base" in userConfig) ignoredKeys.push("base");
|
|
2305
|
+
if ("publicDir" in userConfig) ignoredKeys.push("publicDir");
|
|
2306
|
+
const safeTopLevelKeys = /* @__PURE__ */ new Set([
|
|
2307
|
+
"esbuild",
|
|
2308
|
+
"logLevel",
|
|
2309
|
+
"envPrefix",
|
|
2310
|
+
"optimizeDeps",
|
|
2311
|
+
"ssr"
|
|
2312
|
+
// NOTE: NOT 'server' (build-time irrelevant; dev-server only)
|
|
2313
|
+
]);
|
|
2314
|
+
for (const [key, value] of Object.entries(userConfig)) {
|
|
2315
|
+
if (safeTopLevelKeys.has(key)) merged[key] = value;
|
|
2316
|
+
}
|
|
2317
|
+
merged.root = invariants.root;
|
|
2318
|
+
merged.base = invariants.base;
|
|
2319
|
+
merged.publicDir = invariants.publicDir;
|
|
2320
|
+
merged.build.outDir = invariants.build.outDir;
|
|
2321
|
+
merged.build.manifest = invariants.build.manifest;
|
|
2322
|
+
if (invariants.build.ssr !== void 0) merged.build.ssr = invariants.build.ssr;
|
|
2323
|
+
merged.build.ssrManifest = invariants.build.ssrManifest;
|
|
2324
|
+
if (invariants.build.format) merged.build.format = invariants.build.format;
|
|
2325
|
+
if (invariants.build.target) merged.build.target = invariants.build.target;
|
|
2326
|
+
if (!merged.build.rollupOptions) merged.build.rollupOptions = {};
|
|
2327
|
+
merged.build.rollupOptions.input = invariants.build.rollupOptions.input;
|
|
2328
|
+
if (ignoredKeys.length > 0) {
|
|
2329
|
+
const uniqueKeys = [...new Set(ignoredKeys)];
|
|
2330
|
+
const prefix = context ? `[taujs:build:${context.entryPoint}]` : "[taujs:build]";
|
|
2331
|
+
console.warn(`${prefix} Ignored Vite config overrides: ${uniqueKeys.join(", ")}`);
|
|
2332
|
+
}
|
|
2333
|
+
return merged;
|
|
2334
|
+
}
|
|
2101
2335
|
async function taujsBuild({
|
|
2102
2336
|
config,
|
|
2103
2337
|
projectRoot,
|
|
2104
2338
|
clientBaseDir,
|
|
2105
|
-
isSSRBuild = process.env.BUILD_MODE === "ssr"
|
|
2339
|
+
isSSRBuild = process.env.BUILD_MODE === "ssr",
|
|
2340
|
+
alias: userAlias,
|
|
2341
|
+
vite: userViteConfig
|
|
2106
2342
|
}) {
|
|
2107
2343
|
const deleteDist = async () => {
|
|
2108
2344
|
const { rm } = await import("fs/promises");
|
|
2109
|
-
const distPath =
|
|
2345
|
+
const distPath = path8.resolve(projectRoot, "dist");
|
|
2110
2346
|
try {
|
|
2111
2347
|
await rm(distPath, { recursive: true, force: true });
|
|
2112
2348
|
console.log("Deleted the dist directory\n");
|
|
@@ -2117,26 +2353,36 @@ async function taujsBuild({
|
|
|
2117
2353
|
const extractedConfigs = extractBuildConfigs(config);
|
|
2118
2354
|
const processedConfigs = processConfigs(extractedConfigs, clientBaseDir, TEMPLATE);
|
|
2119
2355
|
if (!isSSRBuild) await deleteDist();
|
|
2120
|
-
for (const
|
|
2121
|
-
const { appId, entryPoint, clientRoot, entryClient, entryServer, htmlTemplate, plugins = [] } =
|
|
2122
|
-
const outDir =
|
|
2123
|
-
const root = entryPoint ?
|
|
2124
|
-
const
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2356
|
+
for (const appConfig of processedConfigs) {
|
|
2357
|
+
const { appId, entryPoint, clientRoot, entryClient, entryServer, htmlTemplate, plugins = [] } = appConfig;
|
|
2358
|
+
const outDir = path8.resolve(projectRoot, isSSRBuild ? `dist/ssr/${entryPoint}` : `dist/client/${entryPoint}`);
|
|
2359
|
+
const root = entryPoint ? path8.resolve(clientBaseDir, entryPoint) : clientBaseDir;
|
|
2360
|
+
const defaultAlias = {
|
|
2361
|
+
"@client": root,
|
|
2362
|
+
"@server": path8.resolve(projectRoot, "src/server"),
|
|
2363
|
+
"@shared": path8.resolve(projectRoot, "src/shared")
|
|
2364
|
+
};
|
|
2365
|
+
const resolvedAlias = { ...defaultAlias, ...userAlias ?? {} };
|
|
2366
|
+
const server = path8.resolve(clientRoot, `${entryServer}.tsx`);
|
|
2367
|
+
const client = path8.resolve(clientRoot, `${entryClient}.tsx`);
|
|
2368
|
+
const main = path8.resolve(clientRoot, htmlTemplate);
|
|
2369
|
+
const inputs = resolveInputs(isSSRBuild, !isSSRBuild && existsSync(main), { server, client, main });
|
|
2370
|
+
const nodeVersion = process.versions.node.split(".")[0];
|
|
2371
|
+
const frameworkConfig = {
|
|
2128
2372
|
base: entryPoint ? `/${entryPoint}/` : "/",
|
|
2129
2373
|
build: {
|
|
2130
2374
|
outDir,
|
|
2375
|
+
emptyOutDir: true,
|
|
2131
2376
|
manifest: !isSSRBuild,
|
|
2132
2377
|
rollupOptions: {
|
|
2133
|
-
input:
|
|
2378
|
+
input: inputs
|
|
2134
2379
|
},
|
|
2135
2380
|
ssr: isSSRBuild ? server : void 0,
|
|
2136
2381
|
ssrManifest: isSSRBuild,
|
|
2137
2382
|
...isSSRBuild && {
|
|
2138
2383
|
format: "esm",
|
|
2139
|
-
target: `node${
|
|
2384
|
+
target: `node${nodeVersion}`,
|
|
2385
|
+
copyPublicDir: false
|
|
2140
2386
|
}
|
|
2141
2387
|
},
|
|
2142
2388
|
css: {
|
|
@@ -2144,33 +2390,28 @@ async function taujsBuild({
|
|
|
2144
2390
|
scss: { api: "modern-compiler" }
|
|
2145
2391
|
}
|
|
2146
2392
|
},
|
|
2147
|
-
plugins
|
|
2148
|
-
publicDir: "public",
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
"/api": {
|
|
2160
|
-
target: "http://localhost:3000",
|
|
2161
|
-
changeOrigin: true,
|
|
2162
|
-
rewrite: (path7) => path7.replace(/^\/api/, "")
|
|
2163
|
-
}
|
|
2164
|
-
}
|
|
2165
|
-
}
|
|
2393
|
+
plugins,
|
|
2394
|
+
publicDir: isSSRBuild ? false : "public",
|
|
2395
|
+
// single shared public
|
|
2396
|
+
// publicDir: isSSRBuild ? false : path.join(root, 'public'), // per-app. no public dir for SSR builds
|
|
2397
|
+
resolve: { alias: resolvedAlias },
|
|
2398
|
+
root
|
|
2399
|
+
};
|
|
2400
|
+
const buildContext = {
|
|
2401
|
+
appId,
|
|
2402
|
+
entryPoint,
|
|
2403
|
+
isSSRBuild,
|
|
2404
|
+
clientRoot
|
|
2166
2405
|
};
|
|
2406
|
+
const finalConfig = mergeViteConfig(frameworkConfig, userViteConfig, buildContext);
|
|
2167
2407
|
try {
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2408
|
+
const mode = isSSRBuild ? "SSR" : "Client";
|
|
2409
|
+
console.log(`[taujs:build:${entryPoint}] Building \u2192 ${mode}`);
|
|
2410
|
+
await build(finalConfig);
|
|
2411
|
+
console.log(`[taujs:build:${entryPoint}] \u2713 Complete
|
|
2171
2412
|
`);
|
|
2172
2413
|
} catch (error) {
|
|
2173
|
-
console.error(`
|
|
2414
|
+
console.error(`[taujs:build:${entryPoint}] \u2717 Failed
|
|
2174
2415
|
`, error);
|
|
2175
2416
|
process.exit(1);
|
|
2176
2417
|
}
|
|
@@ -2192,7 +2433,6 @@ function winstonAdapter(winston) {
|
|
|
2192
2433
|
return messageMetaAdapter(winston);
|
|
2193
2434
|
}
|
|
2194
2435
|
export {
|
|
2195
|
-
createLogger,
|
|
2196
2436
|
createServer,
|
|
2197
2437
|
taujsBuild,
|
|
2198
2438
|
winstonAdapter
|