@taujs/server 0.4.1 → 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-LCDjtT9m.d.ts → Config-CEhfq8Mm.d.ts} +65 -29
- package/dist/Config.d.ts +1 -1
- package/dist/Config.js +180 -10
- package/dist/index.d.ts +85 -5
- package/dist/index.js +585 -326
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -189,8 +189,8 @@ var require_plugin = __commonJS({
|
|
|
189
189
|
|
|
190
190
|
// src/CreateServer.ts
|
|
191
191
|
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
192
|
-
import
|
|
193
|
-
import { performance as
|
|
192
|
+
import path7 from "path";
|
|
193
|
+
import { performance as performance3 } from "perf_hooks";
|
|
194
194
|
import fastifyStatic from "@fastify/static";
|
|
195
195
|
import Fastify from "fastify";
|
|
196
196
|
|
|
@@ -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,13 +344,133 @@ 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
|
-
// 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);
|
|
@@ -489,9 +609,11 @@ var Logger = class _Logger {
|
|
|
489
609
|
if (!this.shouldEmit(level)) return;
|
|
490
610
|
const timestamp = this.formatTimestamp();
|
|
491
611
|
const wantCtx = this.config.includeContext === void 0 ? false : typeof this.config.includeContext === "function" ? this.config.includeContext(level) : this.config.includeContext;
|
|
492
|
-
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;
|
|
493
615
|
const consoleFallback = level === "error" ? console.error : level === "warn" ? console.warn : console.log;
|
|
494
|
-
const
|
|
616
|
+
const hasCustom = !!boundSink;
|
|
495
617
|
const merged = meta ?? {};
|
|
496
618
|
const withCtx = wantCtx && Object.keys(this.context).length > 0 ? { context: this.context, ...merged } : merged;
|
|
497
619
|
const finalMeta = this.shouldIncludeStack(level) ? withCtx : this.stripStacks(withCtx);
|
|
@@ -512,16 +634,20 @@ var Logger = class _Logger {
|
|
|
512
634
|
return plainTag;
|
|
513
635
|
}
|
|
514
636
|
})();
|
|
515
|
-
const tagForOutput =
|
|
637
|
+
const tagForOutput = hasCustom ? plainTag : coloredTag;
|
|
516
638
|
const formatted = `${timestamp} ${tagForOutput} ${message}`;
|
|
517
|
-
if (this.config.singleLine && hasMeta && !
|
|
639
|
+
if (this.config.singleLine && hasMeta && !hasCustom) {
|
|
518
640
|
const metaStr = JSON.stringify(finalMeta).replace(/\n/g, "\\n");
|
|
519
641
|
consoleFallback(`${formatted} ${metaStr}`);
|
|
520
642
|
return;
|
|
521
643
|
}
|
|
522
|
-
if (
|
|
644
|
+
if (hasCustom) {
|
|
523
645
|
const obj = hasMeta ? finalMeta : {};
|
|
524
|
-
|
|
646
|
+
try {
|
|
647
|
+
const result = boundSink(obj, formatted);
|
|
648
|
+
} catch (err) {
|
|
649
|
+
hasMeta ? consoleFallback(formatted, finalMeta) : consoleFallback(formatted);
|
|
650
|
+
}
|
|
525
651
|
} else {
|
|
526
652
|
hasMeta ? consoleFallback(formatted, finalMeta) : consoleFallback(formatted);
|
|
527
653
|
}
|
|
@@ -554,7 +680,54 @@ function createLogger(opts) {
|
|
|
554
680
|
return logger;
|
|
555
681
|
}
|
|
556
682
|
|
|
683
|
+
// src/network/CLI.ts
|
|
684
|
+
function readFlag(argv, keys, bareValue) {
|
|
685
|
+
const end = argv.indexOf("--");
|
|
686
|
+
const limit = end === -1 ? argv.length : end;
|
|
687
|
+
for (let i = 0; i < limit; i++) {
|
|
688
|
+
const arg = argv[i];
|
|
689
|
+
for (const key of keys) {
|
|
690
|
+
if (arg === key) {
|
|
691
|
+
const next = argv[i + 1];
|
|
692
|
+
if (!next || next.startsWith("-")) return bareValue;
|
|
693
|
+
return next.trim();
|
|
694
|
+
}
|
|
695
|
+
const pref = `${key}=`;
|
|
696
|
+
if (arg && arg.startsWith(pref)) {
|
|
697
|
+
const v = arg.slice(pref.length).trim();
|
|
698
|
+
return v || bareValue;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return void 0;
|
|
703
|
+
}
|
|
704
|
+
function resolveNet(input) {
|
|
705
|
+
const env = process.env;
|
|
706
|
+
const argv = process.argv;
|
|
707
|
+
let host = "localhost";
|
|
708
|
+
let port = 5173;
|
|
709
|
+
let hmrPort = 5174;
|
|
710
|
+
if (input?.host) host = input.host;
|
|
711
|
+
if (Number.isFinite(input?.port)) port = Number(input.port);
|
|
712
|
+
if (Number.isFinite(input?.hmrPort)) hmrPort = Number(input.hmrPort);
|
|
713
|
+
if (env.HOST?.trim()) host = env.HOST.trim();
|
|
714
|
+
else if (env.FASTIFY_ADDRESS?.trim()) host = env.FASTIFY_ADDRESS.trim();
|
|
715
|
+
if (env.PORT) port = Number(env.PORT) || port;
|
|
716
|
+
if (env.FASTIFY_PORT) port = Number(env.FASTIFY_PORT) || port;
|
|
717
|
+
if (env.HMR_PORT) hmrPort = Number(env.HMR_PORT) || hmrPort;
|
|
718
|
+
const cliHost = readFlag(argv, ["--host", "--hostname", "-H"], "0.0.0.0");
|
|
719
|
+
const cliPort = readFlag(argv, ["--port", "-p"]);
|
|
720
|
+
const cliHMR = readFlag(argv, ["--hmr-port"]);
|
|
721
|
+
if (cliHost) host = cliHost;
|
|
722
|
+
if (cliPort) port = Number(cliPort) || port;
|
|
723
|
+
if (cliHMR) hmrPort = Number(cliHMR) || hmrPort;
|
|
724
|
+
if (host === "true" || host === "") host = "0.0.0.0";
|
|
725
|
+
return { host, port, hmrPort };
|
|
726
|
+
}
|
|
727
|
+
|
|
557
728
|
// src/network/Network.ts
|
|
729
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
730
|
+
import { networkInterfaces } from "os";
|
|
558
731
|
var isPrivateIPv4 = (addr) => {
|
|
559
732
|
if (!/^\d+\.\d+\.\d+\.\d+$/.test(addr)) return false;
|
|
560
733
|
const [a, b, _c, _d] = addr.split(".").map(Number);
|
|
@@ -606,51 +779,6 @@ var bannerPlugin = async (fastify, options) => {
|
|
|
606
779
|
});
|
|
607
780
|
};
|
|
608
781
|
|
|
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
782
|
// src/security/VerifyMiddleware.ts
|
|
655
783
|
var isAuthRequired = (route) => Boolean(route.attr?.middleware?.auth);
|
|
656
784
|
var hasAuthenticate = (app) => typeof app.authenticate === "function";
|
|
@@ -717,130 +845,7 @@ var verifyContracts = (app, routes, contracts, security) => {
|
|
|
717
845
|
|
|
718
846
|
// src/SSRServer.ts
|
|
719
847
|
var import_fastify_plugin3 = __toESM(require_plugin(), 1);
|
|
720
|
-
|
|
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
|
-
}
|
|
848
|
+
import path6 from "path";
|
|
844
849
|
|
|
845
850
|
// src/logging/utils/index.ts
|
|
846
851
|
var httpStatusFrom = (err, fallback = 500) => err instanceof AppError ? err.httpStatus : fallback;
|
|
@@ -880,39 +885,53 @@ var statusText = (status) => {
|
|
|
880
885
|
import { match } from "path-to-regexp";
|
|
881
886
|
|
|
882
887
|
// src/utils/DataServices.ts
|
|
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
|
+
}
|
|
883
895
|
async function callServiceMethod(registry, serviceName, methodName, params, ctx) {
|
|
884
896
|
if (ctx.signal?.aborted) throw AppError.timeout("Request canceled");
|
|
885
897
|
const service = registry[serviceName];
|
|
886
898
|
if (!service) throw AppError.notFound(`Unknown service: ${serviceName}`);
|
|
887
|
-
const
|
|
888
|
-
if (!
|
|
889
|
-
const logger = ctx.logger?.child({
|
|
899
|
+
const method = service[methodName];
|
|
900
|
+
if (!method) throw AppError.notFound(`Unknown method: ${serviceName}.${methodName}`);
|
|
901
|
+
const logger = ctx.logger?.child?.({
|
|
890
902
|
component: "service-call",
|
|
891
903
|
service: serviceName,
|
|
892
904
|
method: methodName,
|
|
893
905
|
traceId: ctx.traceId
|
|
894
906
|
});
|
|
907
|
+
const t0 = performance2.now();
|
|
895
908
|
try {
|
|
896
|
-
const
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
909
|
+
const result = await method(params ?? {}, ctx);
|
|
910
|
+
if (typeof result !== "object" || result === null) {
|
|
911
|
+
throw AppError.internal(`Non-object result from ${serviceName}.${methodName}`);
|
|
912
|
+
}
|
|
913
|
+
logger?.debug?.({ ms: +(performance2.now() - t0).toFixed(1) }, "Service method ok");
|
|
914
|
+
return result;
|
|
901
915
|
} catch (err) {
|
|
902
|
-
logger?.error(
|
|
916
|
+
logger?.error?.(
|
|
903
917
|
{
|
|
904
918
|
params,
|
|
905
|
-
error: err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : String(err)
|
|
919
|
+
error: err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : String(err),
|
|
920
|
+
ms: +(performance2.now() - t0).toFixed(1)
|
|
906
921
|
},
|
|
907
922
|
"Service method failed"
|
|
908
923
|
);
|
|
909
|
-
throw err;
|
|
924
|
+
throw err instanceof AppError ? err : err instanceof Error ? AppError.internal(err.message, { cause: err }) : AppError.internal("Unknown error", { details: { err } });
|
|
910
925
|
}
|
|
911
926
|
}
|
|
912
927
|
var isServiceDescriptor = (obj) => {
|
|
913
|
-
if (typeof obj !== "object" ||
|
|
914
|
-
const
|
|
915
|
-
|
|
928
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) return false;
|
|
929
|
+
const o = obj;
|
|
930
|
+
if (typeof o.serviceName !== "string" || typeof o.serviceMethod !== "string") return false;
|
|
931
|
+
if ("args" in o) {
|
|
932
|
+
if (o.args === null || typeof o.args !== "object" || Array.isArray(o.args)) return false;
|
|
933
|
+
}
|
|
934
|
+
return true;
|
|
916
935
|
};
|
|
917
936
|
|
|
918
937
|
// src/utils/DataRoutes.ts
|
|
@@ -923,15 +942,15 @@ var safeDecode = (value) => {
|
|
|
923
942
|
return value;
|
|
924
943
|
}
|
|
925
944
|
};
|
|
926
|
-
var cleanPath = (
|
|
927
|
-
if (!
|
|
928
|
-
const basePart =
|
|
945
|
+
var cleanPath = (path9) => {
|
|
946
|
+
if (!path9) return "/";
|
|
947
|
+
const basePart = path9.split("?")[0];
|
|
929
948
|
const base = basePart ? basePart.split("#")[0] : "/";
|
|
930
949
|
return base || "/";
|
|
931
950
|
};
|
|
932
|
-
var calculateSpecificity = (
|
|
951
|
+
var calculateSpecificity = (path9) => {
|
|
933
952
|
let score = 0;
|
|
934
|
-
const segments =
|
|
953
|
+
const segments = path9.split("/").filter(Boolean);
|
|
935
954
|
for (const segment of segments) {
|
|
936
955
|
if (segment.startsWith(":")) {
|
|
937
956
|
score += 1;
|
|
@@ -956,9 +975,9 @@ var createRouteMatchers = (routes) => {
|
|
|
956
975
|
});
|
|
957
976
|
};
|
|
958
977
|
var matchRoute = (url, routeMatchers) => {
|
|
959
|
-
const
|
|
978
|
+
const path9 = cleanPath(url);
|
|
960
979
|
for (const { route, matcher, keys } of routeMatchers) {
|
|
961
|
-
const match2 = matcher(
|
|
980
|
+
const match2 = matcher(path9);
|
|
962
981
|
if (match2) {
|
|
963
982
|
return {
|
|
964
983
|
route,
|
|
@@ -972,14 +991,16 @@ var matchRoute = (url, routeMatchers) => {
|
|
|
972
991
|
var fetchInitialData = async (attr, params, serviceRegistry, ctx, callServiceMethodImpl = callServiceMethod) => {
|
|
973
992
|
const dataHandler = attr?.data;
|
|
974
993
|
if (!dataHandler || typeof dataHandler !== "function") return {};
|
|
994
|
+
const ctxForData = {
|
|
995
|
+
...ctx,
|
|
996
|
+
headers: ctx.headers ?? {}
|
|
997
|
+
};
|
|
998
|
+
ensureServiceCaller(serviceRegistry, ctxForData);
|
|
975
999
|
try {
|
|
976
|
-
const result = await dataHandler(params,
|
|
977
|
-
...ctx,
|
|
978
|
-
headers: ctx.headers ?? {}
|
|
979
|
-
});
|
|
1000
|
+
const result = await dataHandler(params, ctxForData);
|
|
980
1001
|
if (isServiceDescriptor(result)) {
|
|
981
1002
|
const { serviceName, serviceMethod, args } = result;
|
|
982
|
-
return callServiceMethodImpl(serviceRegistry, serviceName, serviceMethod, args ?? {},
|
|
1003
|
+
return callServiceMethodImpl(serviceRegistry, serviceName, serviceMethod, args ?? {}, ctxForData);
|
|
983
1004
|
}
|
|
984
1005
|
if (isPlainObject(result)) return result;
|
|
985
1006
|
throw AppError.badRequest("attr.data must return a plain object or a ServiceDescriptor");
|
|
@@ -1019,6 +1040,16 @@ var createAuthHook = (routeMatchers, logger) => {
|
|
|
1019
1040
|
if (!match2) return;
|
|
1020
1041
|
const { route } = match2;
|
|
1021
1042
|
const authConfig = route.attr?.middleware?.auth;
|
|
1043
|
+
req.routeMeta = {
|
|
1044
|
+
path: route.path,
|
|
1045
|
+
appId: route.appId,
|
|
1046
|
+
attr: {
|
|
1047
|
+
middleware: {
|
|
1048
|
+
auth: route.attr?.middleware?.auth
|
|
1049
|
+
},
|
|
1050
|
+
render: route.attr?.render
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1022
1053
|
if (!authConfig) {
|
|
1023
1054
|
logger.debug("auth", { method: req.method, url: req.url }, "(none)");
|
|
1024
1055
|
return;
|
|
@@ -1086,9 +1117,9 @@ var mergeDirectives = (base, override) => {
|
|
|
1086
1117
|
}
|
|
1087
1118
|
return merged;
|
|
1088
1119
|
};
|
|
1089
|
-
var findMatchingRoute = (routeMatchers,
|
|
1120
|
+
var findMatchingRoute = (routeMatchers, path9) => {
|
|
1090
1121
|
if (!routeMatchers) return null;
|
|
1091
|
-
const match2 = matchRoute(
|
|
1122
|
+
const match2 = matchRoute(path9, routeMatchers);
|
|
1092
1123
|
return match2 ? { route: match2.route, params: match2.params } : null;
|
|
1093
1124
|
};
|
|
1094
1125
|
var cspPlugin = (0, import_fastify_plugin.default)(
|
|
@@ -1103,42 +1134,27 @@ var cspPlugin = (0, import_fastify_plugin.default)(
|
|
|
1103
1134
|
fastify.addHook("onRequest", (req, reply, done) => {
|
|
1104
1135
|
const nonce = generateNonce();
|
|
1105
1136
|
req.cspNonce = nonce;
|
|
1137
|
+
const headerNameFor = (routeCSP2) => routeCSP2 && typeof routeCSP2 === "object" && routeCSP2.reportOnly || opts.reporting?.reportOnly ? "Content-Security-Policy-Report-Only" : "Content-Security-Policy";
|
|
1138
|
+
let routeCSP;
|
|
1106
1139
|
try {
|
|
1107
1140
|
const routeMatch = findMatchingRoute(matchers, req.url);
|
|
1108
|
-
|
|
1141
|
+
routeCSP = routeMatch?.route.attr?.middleware?.csp;
|
|
1109
1142
|
if (routeCSP === false) {
|
|
1110
1143
|
done();
|
|
1111
1144
|
return;
|
|
1112
1145
|
}
|
|
1113
1146
|
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);
|
|
1147
|
+
if (routeCSP && typeof routeCSP === "object" && !routeCSP.disabled) {
|
|
1148
|
+
const routeDirectives = typeof routeCSP.directives === "function" ? routeCSP.directives({
|
|
1149
|
+
url: req.url,
|
|
1150
|
+
params: routeMatch?.params || {},
|
|
1151
|
+
headers: req.headers,
|
|
1152
|
+
req
|
|
1153
|
+
}) : routeCSP.directives ?? {};
|
|
1154
|
+
finalDirectives = routeCSP.mode === "replace" ? routeDirectives : mergeDirectives(globalDirectives, routeDirectives);
|
|
1140
1155
|
}
|
|
1141
|
-
|
|
1156
|
+
const cspHeader = routeCSP?.generateCSP ? routeCSP.generateCSP(finalDirectives, nonce, req) : generateCSP(finalDirectives, nonce, req);
|
|
1157
|
+
reply.header(headerNameFor(routeCSP), cspHeader);
|
|
1142
1158
|
} catch (error) {
|
|
1143
1159
|
logger.error(
|
|
1144
1160
|
{
|
|
@@ -1148,7 +1164,7 @@ var cspPlugin = (0, import_fastify_plugin.default)(
|
|
|
1148
1164
|
"CSP plugin error"
|
|
1149
1165
|
);
|
|
1150
1166
|
const fallbackHeader = generateCSP(globalDirectives, nonce, req);
|
|
1151
|
-
reply.header(
|
|
1167
|
+
reply.header(headerNameFor(routeCSP), fallbackHeader);
|
|
1152
1168
|
}
|
|
1153
1169
|
done();
|
|
1154
1170
|
});
|
|
@@ -1433,8 +1449,9 @@ var loadAssets = async (processedConfigs, baseClientRoot, bootstrapModules, cssL
|
|
|
1433
1449
|
debug: opts.debug,
|
|
1434
1450
|
includeContext: true
|
|
1435
1451
|
});
|
|
1452
|
+
const projectRoot = opts.projectRoot ?? path2.resolve(process.cwd());
|
|
1436
1453
|
for (const config of processedConfigs) {
|
|
1437
|
-
const { clientRoot, entryClient, entryServer, htmlTemplate } = config;
|
|
1454
|
+
const { clientRoot, entryClient, entryServer, htmlTemplate, entryPoint } = config;
|
|
1438
1455
|
try {
|
|
1439
1456
|
const templateHtmlPath = path2.join(clientRoot, htmlTemplate);
|
|
1440
1457
|
const templateHtml = await readFile(templateHtmlPath, "utf-8");
|
|
@@ -1443,11 +1460,13 @@ var loadAssets = async (processedConfigs, baseClientRoot, bootstrapModules, cssL
|
|
|
1443
1460
|
const adjustedRelativePath = relativeBasePath ? `/${relativeBasePath}` : "";
|
|
1444
1461
|
if (!isDevelopment) {
|
|
1445
1462
|
try {
|
|
1446
|
-
const
|
|
1463
|
+
const clientDistPath = path2.resolve(projectRoot, "client", entryPoint);
|
|
1464
|
+
const manifestPath = path2.join(clientDistPath, ".vite/manifest.json");
|
|
1447
1465
|
const manifestContent = await readFile(manifestPath, "utf-8");
|
|
1448
1466
|
const manifest = JSON.parse(manifestContent);
|
|
1449
1467
|
manifests.set(clientRoot, manifest);
|
|
1450
|
-
const
|
|
1468
|
+
const ssrDistPath = path2.resolve(projectRoot, "ssr", entryPoint);
|
|
1469
|
+
const ssrManifestPath = path2.join(ssrDistPath, ".vite/ssr-manifest.json");
|
|
1451
1470
|
const ssrManifestContent = await readFile(ssrManifestPath, "utf-8");
|
|
1452
1471
|
const ssrManifest = JSON.parse(ssrManifestContent);
|
|
1453
1472
|
ssrManifests.set(clientRoot, ssrManifest);
|
|
@@ -1467,7 +1486,7 @@ var loadAssets = async (processedConfigs, baseClientRoot, bootstrapModules, cssL
|
|
|
1467
1486
|
preloadLinks.set(clientRoot, preloadLink);
|
|
1468
1487
|
const cssLink = getCssLinks(manifest, adjustedRelativePath);
|
|
1469
1488
|
cssLinks.set(clientRoot, cssLink);
|
|
1470
|
-
const renderModulePath = path2.join(
|
|
1489
|
+
const renderModulePath = path2.join(ssrDistPath, `${entryServer}.js`);
|
|
1471
1490
|
const moduleUrl = pathToFileURL(renderModulePath).href;
|
|
1472
1491
|
try {
|
|
1473
1492
|
const importedModule = await import(moduleUrl);
|
|
@@ -1475,7 +1494,7 @@ var loadAssets = async (processedConfigs, baseClientRoot, bootstrapModules, cssL
|
|
|
1475
1494
|
} catch (err) {
|
|
1476
1495
|
throw AppError.internal(`Failed to load render module ${renderModulePath}`, {
|
|
1477
1496
|
cause: err,
|
|
1478
|
-
details: { moduleUrl, clientRoot, entryServer }
|
|
1497
|
+
details: { moduleUrl, clientRoot, entryServer, ssrDistPath }
|
|
1479
1498
|
});
|
|
1480
1499
|
}
|
|
1481
1500
|
} catch (err) {
|
|
@@ -1686,10 +1705,15 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1686
1705
|
if (renderType === RENDERTYPE.ssr) {
|
|
1687
1706
|
const { renderSSR } = renderModule;
|
|
1688
1707
|
if (!renderSSR) {
|
|
1689
|
-
throw AppError.internal(
|
|
1690
|
-
|
|
1691
|
-
|
|
1708
|
+
throw AppError.internal(
|
|
1709
|
+
"ssr",
|
|
1710
|
+
{
|
|
1711
|
+
details: { clientRoot, availableFunctions: Object.keys(renderModule) }
|
|
1712
|
+
},
|
|
1713
|
+
"renderSSR function not found in module"
|
|
1714
|
+
);
|
|
1692
1715
|
}
|
|
1716
|
+
logger.debug?.("ssr", {}, "ssr requested");
|
|
1693
1717
|
const ac = new AbortController();
|
|
1694
1718
|
const onAborted = () => ac.abort("client_aborted");
|
|
1695
1719
|
req.raw.on("aborted", onAborted);
|
|
@@ -1698,7 +1722,7 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1698
1722
|
});
|
|
1699
1723
|
reply.raw.on("finish", () => req.raw.off("aborted", onAborted));
|
|
1700
1724
|
if (ac.signal.aborted) {
|
|
1701
|
-
logger.warn("SSR skipped; already aborted"
|
|
1725
|
+
logger.warn({ url: req.url }, "SSR skipped; already aborted");
|
|
1702
1726
|
return;
|
|
1703
1727
|
}
|
|
1704
1728
|
const initialDataResolved = await initialDataInput();
|
|
@@ -1708,14 +1732,31 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1708
1732
|
const res = await renderSSR(initialDataResolved, req.url, attr?.meta, ac.signal, { logger: reqLogger });
|
|
1709
1733
|
headContent = res.headContent;
|
|
1710
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
|
+
}
|
|
1711
1740
|
} catch (err) {
|
|
1712
1741
|
const msg = String(err?.message ?? err ?? "");
|
|
1713
1742
|
const benign = REGEX.BENIGN_NET_ERR.test(msg);
|
|
1714
1743
|
if (ac.signal.aborted || benign) {
|
|
1715
|
-
logger.warn(
|
|
1744
|
+
logger.warn(
|
|
1745
|
+
{
|
|
1746
|
+
url: req.url,
|
|
1747
|
+
reason: msg
|
|
1748
|
+
},
|
|
1749
|
+
"SSR aborted mid-render (benign)"
|
|
1750
|
+
);
|
|
1716
1751
|
return;
|
|
1717
1752
|
}
|
|
1718
|
-
logger.error(
|
|
1753
|
+
logger.error(
|
|
1754
|
+
{
|
|
1755
|
+
url: req.url,
|
|
1756
|
+
error: normaliseError(err)
|
|
1757
|
+
},
|
|
1758
|
+
"SSR render failed"
|
|
1759
|
+
);
|
|
1719
1760
|
throw err;
|
|
1720
1761
|
}
|
|
1721
1762
|
let aggregateHeadContent = headContent;
|
|
@@ -1727,13 +1768,14 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1727
1768
|
const bootstrapScriptTag = shouldHydrate && bootstrapModule ? `<script${nonceAttr} type="module" src="${bootstrapModule}" defer></script>` : "";
|
|
1728
1769
|
const safeAppHtml = appHtml.trim();
|
|
1729
1770
|
const fullHtml = rebuildTemplate(templateParts, aggregateHeadContent, `${safeAppHtml}${initialDataScript}${bootstrapScriptTag}`);
|
|
1771
|
+
logger.debug?.("ssr", {}, "ssr template rebuilt and sending response");
|
|
1730
1772
|
try {
|
|
1731
1773
|
return reply.status(200).header("Content-Type", "text/html").send(fullHtml);
|
|
1732
1774
|
} catch (err) {
|
|
1733
1775
|
const msg = String(err?.message ?? err ?? "");
|
|
1734
1776
|
const benign = REGEX.BENIGN_NET_ERR.test(msg);
|
|
1735
|
-
if (!benign) logger.error(
|
|
1736
|
-
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)");
|
|
1737
1779
|
return;
|
|
1738
1780
|
}
|
|
1739
1781
|
} else {
|
|
@@ -1743,30 +1785,44 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1743
1785
|
details: { clientRoot, availableFunctions: Object.keys(renderModule) }
|
|
1744
1786
|
});
|
|
1745
1787
|
}
|
|
1788
|
+
const headers2 = reply.getHeaders();
|
|
1789
|
+
headers2["Content-Type"] = "text/html; charset=utf-8";
|
|
1746
1790
|
const cspHeader = reply.getHeader("Content-Security-Policy");
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
});
|
|
1791
|
+
if (cspHeader) headers2["Content-Security-Policy"] = cspHeader;
|
|
1792
|
+
reply.raw.writeHead(200, headers2);
|
|
1793
|
+
const abortedState = { aborted: false };
|
|
1751
1794
|
const ac = new AbortController();
|
|
1752
|
-
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
|
+
};
|
|
1753
1802
|
req.raw.on("aborted", onAborted);
|
|
1754
1803
|
reply.raw.on("close", () => {
|
|
1755
|
-
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);
|
|
1756
1814
|
});
|
|
1757
|
-
reply.raw.on("finish", () => req.raw.off("aborted", onAborted));
|
|
1758
1815
|
const shouldHydrate = attr?.hydrate !== false;
|
|
1759
|
-
const abortedState = { aborted: false };
|
|
1760
1816
|
const isBenignSocketAbort = (e) => {
|
|
1761
1817
|
const msg = String(e?.message ?? e ?? "");
|
|
1762
1818
|
return REGEX.BENIGN_NET_ERR.test(msg);
|
|
1763
1819
|
};
|
|
1764
1820
|
const writable = new PassThrough();
|
|
1765
1821
|
writable.on("error", (err) => {
|
|
1766
|
-
if (!isBenignSocketAbort(err)) logger.error(
|
|
1822
|
+
if (!isBenignSocketAbort(err)) logger.error({ error: err }, "PassThrough error:");
|
|
1767
1823
|
});
|
|
1768
1824
|
reply.raw.on("error", (err) => {
|
|
1769
|
-
if (!isBenignSocketAbort(err)) logger.error("HTTP socket error:"
|
|
1825
|
+
if (!isBenignSocketAbort(err)) logger.error({ error: err }, "HTTP socket error:");
|
|
1770
1826
|
});
|
|
1771
1827
|
writable.pipe(reply.raw, { end: false });
|
|
1772
1828
|
let finalData = void 0;
|
|
@@ -1786,30 +1842,33 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
|
|
|
1786
1842
|
},
|
|
1787
1843
|
onError: (err) => {
|
|
1788
1844
|
if (abortedState.aborted || isBenignSocketAbort(err)) {
|
|
1789
|
-
logger.warn("Client disconnected before stream finished");
|
|
1845
|
+
logger.warn({}, "Client disconnected before stream finished");
|
|
1790
1846
|
try {
|
|
1791
1847
|
if (!reply.raw.writableEnded && !reply.raw.destroyed) reply.raw.destroy();
|
|
1792
1848
|
} catch (e) {
|
|
1793
|
-
logger.debug?.("
|
|
1849
|
+
logger.debug?.("ssr", { error: normaliseError(e) }, "stream teardown: destroy() failed");
|
|
1794
1850
|
}
|
|
1795
1851
|
return;
|
|
1796
1852
|
}
|
|
1797
1853
|
abortedState.aborted = true;
|
|
1798
|
-
logger.error(
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1854
|
+
logger.error(
|
|
1855
|
+
{
|
|
1856
|
+
error: normaliseError(err),
|
|
1857
|
+
clientRoot,
|
|
1858
|
+
url: req.url
|
|
1859
|
+
},
|
|
1860
|
+
"Critical rendering error during stream"
|
|
1861
|
+
);
|
|
1803
1862
|
try {
|
|
1804
1863
|
ac?.abort?.();
|
|
1805
1864
|
} catch (e) {
|
|
1806
|
-
logger.debug?.("
|
|
1865
|
+
logger.debug?.("ssr", { error: normaliseError(e) }, "stream teardown: abort() failed");
|
|
1807
1866
|
}
|
|
1808
1867
|
const reason = toReason(err);
|
|
1809
1868
|
try {
|
|
1810
1869
|
if (!reply.raw.writableEnded && !reply.raw.destroyed) reply.raw.destroy(reason);
|
|
1811
1870
|
} catch (e) {
|
|
1812
|
-
logger.debug?.("
|
|
1871
|
+
logger.debug?.("ssr", { error: normaliseError(e) }, "stream teardown: destroy() failed");
|
|
1813
1872
|
}
|
|
1814
1873
|
}
|
|
1815
1874
|
},
|
|
@@ -1896,8 +1955,33 @@ var handleNotFound = async (req, reply, processedConfigs, maps, opts = {}) => {
|
|
|
1896
1955
|
}
|
|
1897
1956
|
};
|
|
1898
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
|
+
|
|
1899
1982
|
// src/utils/StaticAssets.ts
|
|
1900
|
-
|
|
1983
|
+
import path5 from "path";
|
|
1984
|
+
function normaliseStaticAssets(reg) {
|
|
1901
1985
|
if (!reg) return [];
|
|
1902
1986
|
return Array.isArray(reg) ? reg : [reg];
|
|
1903
1987
|
}
|
|
@@ -1905,11 +1989,14 @@ function prefixWeight(prefix) {
|
|
|
1905
1989
|
if (typeof prefix !== "string" || prefix === "/" || prefix.length === 0) return 0;
|
|
1906
1990
|
return prefix.split("/").filter(Boolean).length;
|
|
1907
1991
|
}
|
|
1908
|
-
async function registerStaticAssets(app, baseClientRoot, reg, defaults) {
|
|
1909
|
-
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 }) => ({
|
|
1910
1997
|
plugin,
|
|
1911
1998
|
options: {
|
|
1912
|
-
root:
|
|
1999
|
+
root: staticRoot,
|
|
1913
2000
|
prefix: "/",
|
|
1914
2001
|
index: false,
|
|
1915
2002
|
wildcard: false,
|
|
@@ -1938,6 +2025,7 @@ var SSRServer = (0, import_fastify_plugin3.default)(
|
|
|
1938
2025
|
const processedConfigs = processConfigs(configs, baseClientRoot, TEMPLATE);
|
|
1939
2026
|
const routeMatchers = createRouteMatchers(routes);
|
|
1940
2027
|
let viteDevServer;
|
|
2028
|
+
const projectRoot = path6.resolve(baseClientRoot, "..");
|
|
1941
2029
|
await loadAssets(
|
|
1942
2030
|
processedConfigs,
|
|
1943
2031
|
baseClientRoot,
|
|
@@ -1950,10 +2038,11 @@ var SSRServer = (0, import_fastify_plugin3.default)(
|
|
|
1950
2038
|
maps.templates,
|
|
1951
2039
|
{
|
|
1952
2040
|
debug: opts.debug,
|
|
1953
|
-
logger
|
|
2041
|
+
logger,
|
|
2042
|
+
projectRoot
|
|
1954
2043
|
}
|
|
1955
2044
|
);
|
|
1956
|
-
if (opts.staticAssets) await registerStaticAssets(app, baseClientRoot, opts.staticAssets);
|
|
2045
|
+
if (opts.staticAssets) await registerStaticAssets(app, baseClientRoot, opts.staticAssets, void 0, projectRoot);
|
|
1957
2046
|
if (security?.csp?.reporting) {
|
|
1958
2047
|
app.register(cspReportPlugin, {
|
|
1959
2048
|
path: security.csp.reporting.endpoint,
|
|
@@ -1970,6 +2059,23 @@ var SSRServer = (0, import_fastify_plugin3.default)(
|
|
|
1970
2059
|
});
|
|
1971
2060
|
if (isDevelopment) viteDevServer = await setupDevServer(app, baseClientRoot, alias, opts.debug, opts.devNet);
|
|
1972
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
|
+
});
|
|
1973
2079
|
app.get("/*", async (req, reply) => {
|
|
1974
2080
|
await handleRender(req, reply, routeMatchers, processedConfigs, serviceRegistry, maps, {
|
|
1975
2081
|
debug: opts.debug,
|
|
@@ -2024,20 +2130,21 @@ var SSRServer = (0, import_fastify_plugin3.default)(
|
|
|
2024
2130
|
|
|
2025
2131
|
// src/CreateServer.ts
|
|
2026
2132
|
var createServer = async (opts) => {
|
|
2027
|
-
const t0 =
|
|
2028
|
-
const clientRoot = opts.clientRoot ??
|
|
2133
|
+
const t0 = performance3.now();
|
|
2134
|
+
const clientRoot = opts.clientRoot ?? path7.resolve(process.cwd(), "client");
|
|
2029
2135
|
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
|
-
});
|
|
2136
|
+
const fastifyLogger = app.log && app.log.level && app.log.level !== "silent" ? app.log : void 0;
|
|
2035
2137
|
const logger = createLogger({
|
|
2036
2138
|
debug: opts.debug,
|
|
2037
|
-
custom: opts.logger,
|
|
2139
|
+
custom: opts.logger ?? fastifyLogger,
|
|
2038
2140
|
minLevel: process.env.NODE_ENV === "production" ? "info" : "debug",
|
|
2039
2141
|
includeContext: true
|
|
2040
2142
|
});
|
|
2143
|
+
const net = resolveNet(opts.config.server);
|
|
2144
|
+
await app.register(bannerPlugin, {
|
|
2145
|
+
debug: opts.debug,
|
|
2146
|
+
hmr: { host: net.host, port: net.hmrPort }
|
|
2147
|
+
});
|
|
2041
2148
|
const configs = extractBuildConfigs(opts.config);
|
|
2042
2149
|
const { routes, apps, totalRoutes, durationMs, warnings } = extractRoutes(opts.config);
|
|
2043
2150
|
const { security, durationMs: securityDuration, hasExplicitCSP } = extractSecurity(opts.config);
|
|
@@ -2084,7 +2191,7 @@ var createServer = async (opts) => {
|
|
|
2084
2191
|
"Failed to register SSRServer"
|
|
2085
2192
|
);
|
|
2086
2193
|
}
|
|
2087
|
-
const t1 =
|
|
2194
|
+
const t1 = performance3.now();
|
|
2088
2195
|
console.log(`
|
|
2089
2196
|
${import_picocolors4.default.bgGreen(import_picocolors4.default.black(` ${CONTENT.TAG} `))} configured in ${(t1 - t0).toFixed(0)}ms
|
|
2090
2197
|
`);
|
|
@@ -2093,18 +2200,149 @@ ${import_picocolors4.default.bgGreen(import_picocolors4.default.black(` ${CONTEN
|
|
|
2093
2200
|
};
|
|
2094
2201
|
|
|
2095
2202
|
// src/Build.ts
|
|
2096
|
-
import
|
|
2203
|
+
import { existsSync } from "fs";
|
|
2204
|
+
import path8 from "path";
|
|
2097
2205
|
import { build } from "vite";
|
|
2098
|
-
|
|
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
|
+
}
|
|
2099
2335
|
async function taujsBuild({
|
|
2100
2336
|
config,
|
|
2101
2337
|
projectRoot,
|
|
2102
2338
|
clientBaseDir,
|
|
2103
|
-
isSSRBuild = process.env.BUILD_MODE === "ssr"
|
|
2339
|
+
isSSRBuild = process.env.BUILD_MODE === "ssr",
|
|
2340
|
+
alias: userAlias,
|
|
2341
|
+
vite: userViteConfig
|
|
2104
2342
|
}) {
|
|
2105
2343
|
const deleteDist = async () => {
|
|
2106
2344
|
const { rm } = await import("fs/promises");
|
|
2107
|
-
const distPath =
|
|
2345
|
+
const distPath = path8.resolve(projectRoot, "dist");
|
|
2108
2346
|
try {
|
|
2109
2347
|
await rm(distPath, { recursive: true, force: true });
|
|
2110
2348
|
console.log("Deleted the dist directory\n");
|
|
@@ -2115,26 +2353,36 @@ async function taujsBuild({
|
|
|
2115
2353
|
const extractedConfigs = extractBuildConfigs(config);
|
|
2116
2354
|
const processedConfigs = processConfigs(extractedConfigs, clientBaseDir, TEMPLATE);
|
|
2117
2355
|
if (!isSSRBuild) await deleteDist();
|
|
2118
|
-
for (const
|
|
2119
|
-
const { appId, entryPoint, clientRoot, entryClient, entryServer, htmlTemplate, plugins = [] } =
|
|
2120
|
-
const outDir =
|
|
2121
|
-
const root = entryPoint ?
|
|
2122
|
-
const
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
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 = {
|
|
2126
2372
|
base: entryPoint ? `/${entryPoint}/` : "/",
|
|
2127
2373
|
build: {
|
|
2128
2374
|
outDir,
|
|
2375
|
+
emptyOutDir: true,
|
|
2129
2376
|
manifest: !isSSRBuild,
|
|
2130
2377
|
rollupOptions: {
|
|
2131
|
-
input:
|
|
2378
|
+
input: inputs
|
|
2132
2379
|
},
|
|
2133
2380
|
ssr: isSSRBuild ? server : void 0,
|
|
2134
2381
|
ssrManifest: isSSRBuild,
|
|
2135
2382
|
...isSSRBuild && {
|
|
2136
2383
|
format: "esm",
|
|
2137
|
-
target: `node${
|
|
2384
|
+
target: `node${nodeVersion}`,
|
|
2385
|
+
copyPublicDir: false
|
|
2138
2386
|
}
|
|
2139
2387
|
},
|
|
2140
2388
|
css: {
|
|
@@ -2142,39 +2390,50 @@ async function taujsBuild({
|
|
|
2142
2390
|
scss: { api: "modern-compiler" }
|
|
2143
2391
|
}
|
|
2144
2392
|
},
|
|
2145
|
-
plugins
|
|
2146
|
-
publicDir: "public",
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
"/api": {
|
|
2158
|
-
target: "http://localhost:3000",
|
|
2159
|
-
changeOrigin: true,
|
|
2160
|
-
rewrite: (path7) => path7.replace(/^\/api/, "")
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
}
|
|
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
|
|
2164
2405
|
};
|
|
2406
|
+
const finalConfig = mergeViteConfig(frameworkConfig, userViteConfig, buildContext);
|
|
2165
2407
|
try {
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
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
|
|
2169
2412
|
`);
|
|
2170
2413
|
} catch (error) {
|
|
2171
|
-
console.error(`
|
|
2414
|
+
console.error(`[taujs:build:${entryPoint}] \u2717 Failed
|
|
2172
2415
|
`, error);
|
|
2173
2416
|
process.exit(1);
|
|
2174
2417
|
}
|
|
2175
2418
|
}
|
|
2176
2419
|
}
|
|
2420
|
+
|
|
2421
|
+
// src/logging/Adapters.ts
|
|
2422
|
+
var cleanMeta = (m) => m && Object.keys(m).length === 0 ? void 0 : m;
|
|
2423
|
+
function messageMetaAdapter(sink) {
|
|
2424
|
+
return {
|
|
2425
|
+
debug: (meta, message) => sink.debug?.(message, cleanMeta(meta)),
|
|
2426
|
+
info: (meta, message) => sink.info?.(message, cleanMeta(meta)),
|
|
2427
|
+
warn: (meta, message) => sink.warn?.(message, cleanMeta(meta)),
|
|
2428
|
+
error: (meta, message) => sink.error?.(message, cleanMeta(meta)),
|
|
2429
|
+
child: (ctx) => messageMetaAdapter(sink.child?.(ctx) ?? sink)
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
2432
|
+
function winstonAdapter(winston) {
|
|
2433
|
+
return messageMetaAdapter(winston);
|
|
2434
|
+
}
|
|
2177
2435
|
export {
|
|
2178
2436
|
createServer,
|
|
2179
|
-
taujsBuild
|
|
2437
|
+
taujsBuild,
|
|
2438
|
+
winstonAdapter
|
|
2180
2439
|
};
|