@taujs/server 0.5.3 → 0.5.5

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/index.js CHANGED
@@ -99,62 +99,19 @@ var require_picocolors = __commonJS({
99
99
 
100
100
  // src/CreateServer.ts
101
101
  var import_picocolors4 = __toESM(require_picocolors(), 1);
102
- import path5 from "path";
103
- import { performance as performance3 } from "perf_hooks";
104
- import Fastify from "fastify";
105
-
106
- // src/Setup.ts
102
+ import path6 from "path";
107
103
  import { performance } from "perf_hooks";
104
+ import Fastify from "fastify";
108
105
 
109
- // src/constants.ts
110
- var import_picocolors = __toESM(require_picocolors(), 1);
111
- var RENDERTYPE = {
112
- ssr: "ssr",
113
- streaming: "streaming"
114
- };
115
- var SSRTAG = {
116
- ssrHead: "<!--ssr-head-->",
117
- ssrHtml: "<!--ssr-html-->"
118
- };
119
- var TEMPLATE = {
120
- defaultEntryClient: "entry-client",
121
- defaultEntryServer: "entry-server",
122
- defaultHtmlTemplate: "index.html"
123
- };
124
- var DEV_CSP_DIRECTIVES = {
125
- "default-src": ["'self'"],
126
- "connect-src": ["'self'", "ws:", "http:"],
127
- "style-src": ["'self'", "'unsafe-inline'"],
128
- "img-src": ["'self'", "data:"]
129
- };
130
- var CONTENT = {
131
- TAG: "\u03C4js"
132
- };
133
- var DEBUG = {
134
- auth: { label: "auth", colour: import_picocolors.default.blue },
135
- csp: { label: "csp", colour: import_picocolors.default.yellow },
136
- errors: { label: "errors", colour: import_picocolors.default.red },
137
- routes: { label: "routes", colour: import_picocolors.default.cyan },
138
- security: { label: "security", colour: import_picocolors.default.yellow },
139
- trx: { label: "trx", colour: import_picocolors.default.magenta },
140
- vite: { label: "vite", colour: import_picocolors.default.yellow }
141
- };
142
- var REGEX = {
143
- BENIGN_NET_ERR: /\b(?:ECONNRESET|EPIPE|ECONNABORTED)\b|socket hang up|aborted|premature(?: close)?/i,
144
- SAFE_TRACE: /^[a-zA-Z0-9-_:.]{1,128}$/
145
- };
146
- var ENTRY_EXTENSIONS = [".ts", ".tsx"];
106
+ // src/core/telemetry/Telemetry.ts
107
+ var now = () => globalThis.performance?.now?.() ?? Date.now();
147
108
 
148
- // src/Setup.ts
109
+ // src/core/config/Setup.ts
149
110
  var extractBuildConfigs = (config) => {
150
- return config.apps.map(({ appId, entryPoint, plugins }) => ({
151
- appId,
152
- entryPoint,
153
- plugins
154
- }));
111
+ return config.apps.map(({ appId, entryPoint, plugins }) => ({ appId, entryPoint, plugins }));
155
112
  };
156
113
  var extractRoutes = (taujsConfig) => {
157
- const t0 = performance.now();
114
+ const t0 = now();
158
115
  const allRoutes = [];
159
116
  const apps = [];
160
117
  const warnings = [];
@@ -173,7 +130,7 @@ var extractRoutes = (taujsConfig) => {
173
130
  if (appIds.length > 1) warnings.push(`Route path "${path7}" is declared in multiple apps: ${appIds.join(", ")}`);
174
131
  }
175
132
  const sortedRoutes = allRoutes.sort((a, b) => computeScore(b.path) - computeScore(a.path));
176
- const durationMs = performance.now() - t0;
133
+ const durationMs = now() - t0;
177
134
  return {
178
135
  routes: sortedRoutes,
179
136
  apps,
@@ -183,7 +140,7 @@ var extractRoutes = (taujsConfig) => {
183
140
  };
184
141
  };
185
142
  var extractSecurity = (taujsConfig) => {
186
- const t0 = performance.now();
143
+ const t0 = now();
187
144
  const user = taujsConfig.security ?? {};
188
145
  const userCsp = user.csp;
189
146
  const hasExplicitCSP = !!userCsp;
@@ -204,7 +161,7 @@ var extractSecurity = (taujsConfig) => {
204
161
  hasReporting: !!normalisedCsp?.reporting?.endpoint,
205
162
  reportOnly: !!normalisedCsp?.reporting?.reportOnly
206
163
  };
207
- const durationMs = performance.now() - t0;
164
+ const durationMs = now() - t0;
208
165
  return {
209
166
  security,
210
167
  durationMs,
@@ -212,58 +169,11 @@ var extractSecurity = (taujsConfig) => {
212
169
  summary
213
170
  };
214
171
  };
215
- function printConfigSummary(logger, apps, configsCount, totalRoutes, durationMs, warnings) {
216
- logger.info({}, `${CONTENT.TAG} [config] Loaded ${configsCount} app(s), ${totalRoutes} route(s) in ${durationMs.toFixed(1)}ms`);
217
- apps.forEach((a) => logger.debug("routes", {}, `\u2022 ${a.appId}: ${a.routeCount} route(s)`));
218
- warnings.forEach((w) => logger.warn({}, `${CONTENT.TAG} [warn] ${w}`));
219
- }
220
- function printSecuritySummary(logger, routes, security, hasExplicitCSP, securityDurationMs) {
221
- const total = routes.length;
222
- const disabled = routes.filter((r) => r.attr?.middleware?.csp === false).length;
223
- const custom = routes.filter((r) => {
224
- const v = r.attr?.middleware?.csp;
225
- return v !== void 0 && v !== false;
226
- }).length;
227
- const enabled = total - disabled;
228
- const hasReporting = !!security.csp?.reporting?.endpoint;
229
- const mode = security.csp?.defaultMode ?? "merge";
230
- let status = "configured";
231
- let detail = "";
232
- if (hasExplicitCSP) {
233
- detail = `explicit, mode=${mode}`;
234
- if (hasReporting) detail += ", reporting";
235
- if (custom > 0) detail += `, ${custom} route override(s)`;
236
- } else {
237
- if (process.env.NODE_ENV === "production") {
238
- logger.warn({}, "(consider explicit config for production)");
239
- }
240
- }
241
- logger.info({}, `${CONTENT.TAG} [security] CSP ${status} (${enabled}/${total} routes) in ${securityDurationMs.toFixed(1)}ms`);
242
- }
243
- function printContractReport(logger, report) {
244
- for (const r of report.items) {
245
- const line = `${CONTENT.TAG} [security][${r.key}] ${r.message}`;
246
- if (r.status === "error") {
247
- logger.error({}, line);
248
- } else if (r.status === "warning") {
249
- logger.warn({}, line);
250
- } else if (r.status === "skipped") {
251
- logger.debug(r.key, {}, line);
252
- } else {
253
- logger.info({}, line);
254
- }
255
- }
256
- }
257
172
  var computeScore = (path7) => {
258
173
  return path7.split("/").filter(Boolean).reduce((score, segment) => score + (segment.startsWith(":") ? 1 : 10), 0);
259
174
  };
260
- function printVitePluginSummary(logger, appPlugins, merged) {
261
- const mergedNames = merged.map((p) => p?.name).filter((n) => typeof n === "string" && n.length > 0);
262
- const appsLine = appPlugins.length === 0 ? "no app plugins" : appPlugins.map((a) => `${a.appId}=[${a.plugins.join(", ") || "none"}]`).join(" ");
263
- logger.info(void 0, `${CONTENT.TAG} [vite] Plugins ${appsLine} merged=[${mergedNames.join(", ") || "none"}]`);
264
- }
265
175
 
266
- // src/logging/AppError.ts
176
+ // src/core/errors/AppError.ts
267
177
  var HTTP_STATUS = {
268
178
  infra: 500,
269
179
  upstream: 502,
@@ -387,6 +297,40 @@ function toReason(e) {
387
297
  return new Error(String(e));
388
298
  }
389
299
 
300
+ // src/constants.ts
301
+ var import_picocolors = __toESM(require_picocolors(), 1);
302
+ var SSRTAG = {
303
+ ssrHead: "<!--ssr-head-->",
304
+ ssrHtml: "<!--ssr-html-->"
305
+ };
306
+ var TEMPLATE = {
307
+ defaultEntryClient: "entry-client",
308
+ defaultEntryServer: "entry-server",
309
+ defaultHtmlTemplate: "index.html"
310
+ };
311
+ var ENTRY_EXTENSIONS = [".ts", ".tsx"];
312
+ var DEV_CSP_DIRECTIVES = {
313
+ "default-src": ["'self'"],
314
+ "connect-src": ["'self'", "ws:", "http:"],
315
+ "style-src": ["'self'", "'unsafe-inline'"],
316
+ "img-src": ["'self'", "data:"]
317
+ };
318
+ var CONTENT = {
319
+ TAG: "\u03C4js"
320
+ };
321
+ var DEBUG = {
322
+ auth: { label: "auth", colour: import_picocolors.default.blue },
323
+ csp: { label: "csp", colour: import_picocolors.default.yellow },
324
+ errors: { label: "errors", colour: import_picocolors.default.red },
325
+ routes: { label: "routes", colour: import_picocolors.default.cyan },
326
+ security: { label: "security", colour: import_picocolors.default.yellow },
327
+ trx: { label: "trx", colour: import_picocolors.default.magenta },
328
+ vite: { label: "vite", colour: import_picocolors.default.yellow }
329
+ };
330
+ var REGEX = {
331
+ BENIGN_NET_ERR: /\b(?:ECONNRESET|EPIPE|ECONNABORTED)\b|socket hang up|aborted|premature(?: close)?/i
332
+ };
333
+
390
334
  // src/logging/Logger.ts
391
335
  var import_picocolors2 = __toESM(require_picocolors(), 1);
392
336
 
@@ -451,8 +395,10 @@ function parseDebugInput(input) {
451
395
  return input;
452
396
  }
453
397
 
454
- // src/logging/Logger.ts
398
+ // src/core/logging/types.ts
455
399
  var DEBUG_CATEGORIES = ["auth", "routes", "errors", "vite", "network", "ssr"];
400
+
401
+ // src/logging/Logger.ts
456
402
  var Logger = class _Logger {
457
403
  constructor(config = {}) {
458
404
  this.config = config;
@@ -512,12 +458,12 @@ var Logger = class _Logger {
512
458
  return copy;
513
459
  }
514
460
  formatTimestamp() {
515
- const now = /* @__PURE__ */ new Date();
516
- if (process.env.NODE_ENV === "production") return now.toISOString();
517
- const hours = String(now.getHours()).padStart(2, "0");
518
- const minutes = String(now.getMinutes()).padStart(2, "0");
519
- const seconds = String(now.getSeconds()).padStart(2, "0");
520
- const millis = String(now.getMilliseconds()).padStart(3, "0");
461
+ const now2 = /* @__PURE__ */ new Date();
462
+ if (process.env.NODE_ENV === "production") return now2.toISOString();
463
+ const hours = String(now2.getHours()).padStart(2, "0");
464
+ const minutes = String(now2.getMinutes()).padStart(2, "0");
465
+ const seconds = String(now2.getSeconds()).padStart(2, "0");
466
+ const millis = String(now2.getMilliseconds()).padStart(3, "0");
521
467
  return `${hours}:${minutes}:${seconds}.${millis}`;
522
468
  }
523
469
  emit(level, message, meta, category) {
@@ -765,48 +711,79 @@ var verifyContracts = (app, routes, contracts, security) => {
765
711
  return { items };
766
712
  };
767
713
 
714
+ // src/Setup.ts
715
+ function printConfigSummary(logger, apps, configsCount, totalRoutes, durationMs, warnings) {
716
+ logger.info({}, `${CONTENT.TAG} [config] Loaded ${configsCount} app(s), ${totalRoutes} route(s) in ${durationMs.toFixed(1)}ms`);
717
+ apps.forEach((a) => logger.debug("routes", {}, `\u2022 ${a.appId}: ${a.routeCount} route(s)`));
718
+ warnings.forEach((w) => logger.warn({}, `${CONTENT.TAG} [warn] ${w}`));
719
+ }
720
+ function printSecuritySummary(logger, routes, security, hasExplicitCSP, securityDurationMs) {
721
+ const total = routes.length;
722
+ const disabled = routes.filter((r) => r.attr?.middleware?.csp === false).length;
723
+ const custom = routes.filter((r) => {
724
+ const v = r.attr?.middleware?.csp;
725
+ return v !== void 0 && v !== false;
726
+ }).length;
727
+ const enabled = total - disabled;
728
+ const hasReporting = !!security.csp?.reporting?.endpoint;
729
+ const mode = security.csp?.defaultMode ?? "merge";
730
+ let status = "configured";
731
+ let detail = "";
732
+ if (hasExplicitCSP) {
733
+ detail = `explicit, mode=${mode}`;
734
+ if (hasReporting) detail += ", reporting";
735
+ if (custom > 0) detail += `, ${custom} route override(s)`;
736
+ } else {
737
+ if (process.env.NODE_ENV === "production") {
738
+ logger.warn({}, "(consider explicit config for production)");
739
+ }
740
+ }
741
+ logger.info({}, `${CONTENT.TAG} [security] CSP ${status} (${enabled}/${total} routes) in ${securityDurationMs.toFixed(1)}ms`);
742
+ }
743
+ function printContractReport(logger, report) {
744
+ for (const r of report.items) {
745
+ const line = `${CONTENT.TAG} [security][${r.key}] ${r.message}`;
746
+ if (r.status === "error") {
747
+ logger.error({}, line);
748
+ } else if (r.status === "warning") {
749
+ logger.warn({}, line);
750
+ } else if (r.status === "skipped") {
751
+ logger.debug(r.key, {}, line);
752
+ } else {
753
+ logger.info({}, line);
754
+ }
755
+ }
756
+ }
757
+ function printVitePluginSummary(logger, appPlugins, merged) {
758
+ const mergedNames = merged.map((p) => p?.name).filter((n) => typeof n === "string" && n.length > 0);
759
+ const appsLine = appPlugins.length === 0 ? "no app plugins" : appPlugins.map((a) => `${a.appId}=[${a.plugins.join(", ") || "none"}]`).join(" ");
760
+ logger.info(void 0, `${CONTENT.TAG} [vite] Plugins ${appsLine} merged=[${mergedNames.join(", ") || "none"}]`);
761
+ }
762
+
768
763
  // src/SSRServer.ts
769
764
  import fp3 from "fastify-plugin";
770
765
 
771
- // src/logging/utils/index.ts
772
- var httpStatusFrom = (err, fallback = 500) => err instanceof AppError ? err.httpStatus : fallback;
773
- var toHttp = (err) => {
774
- const app = AppError.from(err);
775
- const status = httpStatusFrom(app);
776
- const errorMessage = app.safeMessage;
777
- return {
778
- status,
779
- body: {
780
- error: errorMessage,
781
- ...app.code && { code: app.code },
782
- statusText: statusText(status)
783
- }
784
- };
785
- };
786
- var statusText = (status) => {
787
- const map = {
788
- 400: "Bad Request",
789
- 401: "Unauthorized",
790
- 403: "Forbidden",
791
- 404: "Not Found",
792
- 405: "Method Not Allowed",
793
- 408: "Request Timeout",
794
- 422: "Unprocessable Entity",
795
- 429: "Too Many Requests",
796
- 499: "Client Closed Request",
797
- 500: "Internal Server Error",
798
- 502: "Bad Gateway",
799
- 503: "Service Unavailable",
800
- 504: "Gateway Timeout"
801
- };
802
- return map[status] ?? "Error";
766
+ // src/core/routes/DataRoutes.ts
767
+ import { match } from "path-to-regexp";
768
+
769
+ // src/core/logging/noop.ts
770
+ var noopLogger = {
771
+ debug: () => {
772
+ },
773
+ info: () => {
774
+ },
775
+ warn: () => {
776
+ },
777
+ error: () => {
778
+ },
779
+ child: () => noopLogger,
780
+ isDebugEnabled: () => false
803
781
  };
804
782
 
805
- // src/utils/DataRoutes.ts
806
- import { match } from "path-to-regexp";
783
+ // src/core/logging/resolve.ts
784
+ var resolveLogs = (logger) => logger ?? noopLogger;
807
785
 
808
- // src/utils/DataServices.ts
809
- import { performance as performance2 } from "perf_hooks";
786
+ // src/core/services/DataServices.ts
810
787
  function createCaller(registry, ctx) {
811
788
  return (serviceName, methodName, args) => callServiceMethod(registry, serviceName, methodName, args ?? {}, ctx);
812
789
  }
@@ -819,26 +796,27 @@ async function callServiceMethod(registry, serviceName, methodName, params, ctx)
819
796
  if (!service) throw AppError.notFound(`Unknown service: ${serviceName}`);
820
797
  const method = service[methodName];
821
798
  if (!method) throw AppError.notFound(`Unknown method: ${serviceName}.${methodName}`);
822
- const logger = ctx.logger?.child?.({
799
+ const baseLogger = resolveLogs(ctx.logger);
800
+ const logger = baseLogger.child({
823
801
  component: "service-call",
824
802
  service: serviceName,
825
803
  method: methodName,
826
804
  traceId: ctx.traceId
827
805
  });
828
- const t0 = performance2.now();
806
+ const t0 = now();
829
807
  try {
830
808
  const result = await method(params ?? {}, ctx);
831
809
  if (typeof result !== "object" || result === null) {
832
810
  throw AppError.internal(`Non-object result from ${serviceName}.${methodName}`);
833
811
  }
834
- logger?.debug?.({ ms: +(performance2.now() - t0).toFixed(1) }, "Service method ok");
812
+ logger.debug({ ms: +(now() - t0).toFixed(1) }, "Service method ok");
835
813
  return result;
836
814
  } catch (err) {
837
- logger?.error?.(
815
+ logger.error(
838
816
  {
839
817
  params,
840
818
  error: err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : String(err),
841
- ms: +(performance2.now() - t0).toFixed(1)
819
+ ms: +(now() - t0).toFixed(1)
842
820
  },
843
821
  "Service method failed"
844
822
  );
@@ -855,7 +833,7 @@ var isServiceDescriptor = (obj) => {
855
833
  return true;
856
834
  };
857
835
 
858
- // src/utils/DataRoutes.ts
836
+ // src/core/routes/DataRoutes.ts
859
837
  var safeDecode = (value) => {
860
838
  try {
861
839
  return decodeURIComponent(value);
@@ -953,43 +931,86 @@ var fetchInitialData = async (attr, params, serviceRegistry, ctx, callServiceMet
953
931
  }
954
932
  };
955
933
 
956
- // src/security/Auth.ts
957
- var createAuthHook = (routeMatchers, logger) => {
958
- return async function authHook(req, reply) {
959
- const url = new URL(req.url, `http://${req.headers.host}`).pathname;
960
- const match2 = matchRoute(url, routeMatchers);
961
- if (!match2) return;
962
- const { route } = match2;
963
- const authConfig = route.attr?.middleware?.auth;
964
- req.routeMeta = {
965
- path: route.path,
966
- appId: route.appId,
967
- attr: {
968
- middleware: {
969
- auth: route.attr?.middleware?.auth
970
- },
971
- render: route.attr?.render
972
- }
973
- };
974
- if (!authConfig) {
975
- logger.debug("auth", { method: req.method, url: req.url }, "(none)");
976
- return;
977
- }
978
- if (typeof req.server.authenticate !== "function") {
979
- logger.warn(
980
- {
981
- path: url,
982
- appId: route.appId
983
- },
984
- "Route requires auth but Fastify authenticate decorator is missing"
985
- );
986
- return reply.status(500).send("Server misconfiguration: auth decorator missing.");
987
- }
988
- try {
989
- logger.debug("auth", { method: req.method, url: req.url }, "Invoking authenticate(...)");
990
- await req.server.authenticate(req, reply);
991
- logger.debug("auth", { method: req.method, url: req.url }, "Authentication successful");
992
- } catch (err) {
934
+ // src/System.ts
935
+ import { dirname, join } from "path";
936
+ import "path";
937
+ import { fileURLToPath } from "url";
938
+ var isDevelopment = process.env.NODE_ENV === "development";
939
+ var __filename = fileURLToPath(import.meta.url);
940
+ var DIR_SUFFIX = isDevelopment ? ".." : "./";
941
+ var __dirname = join(dirname(__filename), DIR_SUFFIX);
942
+
943
+ // src/logging/utils/index.ts
944
+ var httpStatusFrom = (err, fallback = 500) => err instanceof AppError ? err.httpStatus : fallback;
945
+ var toHttp = (err) => {
946
+ const app = AppError.from(err);
947
+ const status = httpStatusFrom(app);
948
+ const errorMessage = app.safeMessage;
949
+ return {
950
+ status,
951
+ body: {
952
+ error: errorMessage,
953
+ ...app.code && { code: app.code },
954
+ statusText: statusText(status)
955
+ }
956
+ };
957
+ };
958
+ var statusText = (status) => {
959
+ const map = {
960
+ 400: "Bad Request",
961
+ 401: "Unauthorized",
962
+ 403: "Forbidden",
963
+ 404: "Not Found",
964
+ 405: "Method Not Allowed",
965
+ 408: "Request Timeout",
966
+ 422: "Unprocessable Entity",
967
+ 429: "Too Many Requests",
968
+ 499: "Client Closed Request",
969
+ 500: "Internal Server Error",
970
+ 502: "Bad Gateway",
971
+ 503: "Service Unavailable",
972
+ 504: "Gateway Timeout"
973
+ };
974
+ return map[status] ?? "Error";
975
+ };
976
+
977
+ // src/security/Auth.ts
978
+ var createAuthHook = (routeMatchers, logger) => {
979
+ return async function authHook(req, reply) {
980
+ const url = new URL(req.url, `http://${req.headers.host}`).pathname;
981
+ const match2 = matchRoute(url, routeMatchers);
982
+ if (!match2) return;
983
+ const { route } = match2;
984
+ const authConfig = route.attr?.middleware?.auth;
985
+ req.routeMeta = {
986
+ path: route.path,
987
+ appId: route.appId,
988
+ attr: {
989
+ middleware: {
990
+ auth: route.attr?.middleware?.auth
991
+ },
992
+ render: route.attr?.render
993
+ }
994
+ };
995
+ if (!authConfig) {
996
+ logger.debug("auth", { method: req.method, url: req.url }, "(none)");
997
+ return;
998
+ }
999
+ if (typeof req.server.authenticate !== "function") {
1000
+ logger.warn(
1001
+ {
1002
+ path: url,
1003
+ appId: route.appId
1004
+ },
1005
+ "Route requires auth but Fastify authenticate decorator is missing"
1006
+ );
1007
+ return reply.status(500).send("Server misconfiguration: auth decorator missing.");
1008
+ }
1009
+ try {
1010
+ logger.debug("auth", { method: req.method, url: req.url }, "Invoking authenticate(...)");
1011
+ await req.server.authenticate(req, reply);
1012
+ logger.debug("auth", { method: req.method, url: req.url }, "Authentication successful");
1013
+ } catch (err) {
993
1014
  logger.debug("auth", { method: req.method, url: req.url }, "Authentication failed");
994
1015
  return reply.send(err);
995
1016
  }
@@ -999,16 +1020,6 @@ var createAuthHook = (routeMatchers, logger) => {
999
1020
  // src/security/CSP.ts
1000
1021
  import fp from "fastify-plugin";
1001
1022
  import crypto from "crypto";
1002
-
1003
- // src/utils/System.ts
1004
- import { dirname, join } from "path";
1005
- import "path";
1006
- import { fileURLToPath } from "url";
1007
- var isDevelopment = process.env.NODE_ENV === "development";
1008
- var __filename = fileURLToPath(import.meta.url);
1009
- var __dirname = join(dirname(__filename), !isDevelopment ? "./" : "..");
1010
-
1011
- // src/security/CSP.ts
1012
1023
  var defaultGenerateCSP = (directives, nonce, req) => {
1013
1024
  const merged = { ...directives };
1014
1025
  merged["script-src"] = merged["script-src"] || ["'self'"];
@@ -1232,7 +1243,6 @@ var cspReportPlugin = fp2(
1232
1243
  );
1233
1244
 
1234
1245
  // src/utils/AssetManager.ts
1235
- import { existsSync } from "fs";
1236
1246
  import { readFile } from "fs/promises";
1237
1247
  import path2 from "path";
1238
1248
  import { pathToFileURL } from "url";
@@ -1344,14 +1354,6 @@ var rebuildTemplate = (parts, headContent, bodyContent) => {
1344
1354
  };
1345
1355
 
1346
1356
  // src/utils/AssetManager.ts
1347
- function resolveEntryFile(clientRoot, stem) {
1348
- for (const ext of ENTRY_EXTENSIONS) {
1349
- const filename = `${stem}${ext}`;
1350
- const absPath = path2.join(clientRoot, filename);
1351
- if (existsSync(absPath)) return filename;
1352
- }
1353
- throw new Error(`Entry file "${stem}" not found in ${clientRoot}. Tried: ${ENTRY_EXTENSIONS.map((e) => stem + e).join(", ")}`);
1354
- }
1355
1357
  var createMaps = () => ({
1356
1358
  bootstrapModules: /* @__PURE__ */ new Map(),
1357
1359
  cssLinks: /* @__PURE__ */ new Map(),
@@ -1364,108 +1366,104 @@ var createMaps = () => ({
1364
1366
  var processConfigs = (configs, baseClientRoot, templateDefaults) => {
1365
1367
  return configs.map((config) => {
1366
1368
  const clientRoot = path2.resolve(baseClientRoot, config.entryPoint);
1367
- const entryClient = config.entryClient || templateDefaults.defaultEntryClient;
1368
- const entryServer = config.entryServer || templateDefaults.defaultEntryServer;
1369
- const entryClientFile = resolveEntryFile(clientRoot, entryClient);
1370
- const entryServerFile = resolveEntryFile(clientRoot, entryServer);
1371
1369
  return {
1372
1370
  clientRoot,
1373
1371
  entryPoint: config.entryPoint,
1374
- entryClient,
1375
- entryServer,
1372
+ entryClient: config.entryClient || templateDefaults.defaultEntryClient,
1373
+ // stem
1374
+ entryServer: config.entryServer || templateDefaults.defaultEntryServer,
1375
+ // stem
1376
1376
  htmlTemplate: config.htmlTemplate || templateDefaults.defaultHtmlTemplate,
1377
1377
  appId: config.appId,
1378
- plugins: config.plugins ?? [],
1379
- entryClientFile,
1380
- entryServerFile
1378
+ plugins: config.plugins ?? []
1381
1379
  };
1382
1380
  });
1383
1381
  };
1382
+ var logAssetError = (logger, stage, err) => {
1383
+ if (err instanceof AppError) {
1384
+ logger.error(
1385
+ {
1386
+ error: {
1387
+ name: err.name,
1388
+ message: err.message,
1389
+ stack: err.stack,
1390
+ code: err.code
1391
+ },
1392
+ stage
1393
+ },
1394
+ "Asset load failed"
1395
+ );
1396
+ return;
1397
+ }
1398
+ logger.error(
1399
+ {
1400
+ error: err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : String(err),
1401
+ stage
1402
+ },
1403
+ "Asset load failed"
1404
+ );
1405
+ };
1406
+ var findManifestEntry = (manifest, stem) => {
1407
+ for (const ext of ENTRY_EXTENSIONS) {
1408
+ const entry = manifest[`${stem}${ext}`];
1409
+ if (entry?.file) return entry;
1410
+ }
1411
+ return null;
1412
+ };
1384
1413
  var loadAssets = async (processedConfigs, baseClientRoot, bootstrapModules, cssLinks, manifests, preloadLinks, renderModules, ssrManifests, templates, opts = {}) => {
1385
- const logger = opts.logger ?? createLogger({
1386
- debug: opts.debug,
1387
- includeContext: true
1388
- });
1414
+ const logger = resolveLogs(opts.logger);
1389
1415
  for (const config of processedConfigs) {
1390
- const { clientRoot, entryClient, entryServer, htmlTemplate, entryPoint, entryClientFile, entryServerFile } = config;
1416
+ const { clientRoot, entryServer, entryClient, htmlTemplate, entryPoint } = config;
1391
1417
  try {
1392
1418
  const templateHtmlPath = path2.join(clientRoot, htmlTemplate);
1393
- const templateHtml = await readFile(templateHtmlPath, "utf-8");
1394
- templates.set(clientRoot, templateHtml);
1419
+ templates.set(clientRoot, await readFile(templateHtmlPath, "utf-8"));
1395
1420
  const relativeBasePath = path2.relative(baseClientRoot, clientRoot).replace(/\\/g, "/");
1396
1421
  const adjustedRelativePath = relativeBasePath ? `/${relativeBasePath}` : "";
1397
- if (!isDevelopment) {
1398
- try {
1399
- const distRoot = path2.dirname(baseClientRoot);
1400
- const ssrRoot = path2.join(distRoot, "ssr");
1401
- const clientDistPath = path2.join(baseClientRoot, entryPoint);
1402
- const manifestPath = path2.join(clientDistPath, ".vite/manifest.json");
1403
- const manifestContent = await readFile(manifestPath, "utf-8");
1404
- const manifest = JSON.parse(manifestContent);
1405
- manifests.set(clientRoot, manifest);
1406
- const ssrDistPath = path2.join(ssrRoot, entryPoint);
1407
- const ssrManifestPath = path2.join(ssrDistPath, ".vite/ssr-manifest.json");
1408
- const ssrManifestContent = await readFile(ssrManifestPath, "utf-8");
1409
- const ssrManifest = JSON.parse(ssrManifestContent);
1410
- ssrManifests.set(clientRoot, ssrManifest);
1411
- const manifestEntry = manifest[entryClientFile];
1412
- if (!manifestEntry?.file) {
1413
- throw AppError.internal(`Entry client file not found in manifest for ${entryClientFile}`, {
1414
- details: {
1415
- clientRoot,
1416
- entryClientFile,
1417
- availableKeys: Object.keys(manifest)
1418
- }
1419
- });
1420
- }
1421
- const bootstrapModule = `/${adjustedRelativePath}/${manifestEntry.file}`.replace(/\/{2,}/g, "/");
1422
- bootstrapModules.set(clientRoot, bootstrapModule);
1423
- const preloadLink = renderPreloadLinks(ssrManifest, adjustedRelativePath);
1424
- preloadLinks.set(clientRoot, preloadLink);
1425
- const cssLink = getCssLinks(manifest, adjustedRelativePath);
1426
- cssLinks.set(clientRoot, cssLink);
1427
- const renderModulePath = path2.join(ssrDistPath, `${entryServer}.js`);
1428
- const moduleUrl = pathToFileURL(renderModulePath).href;
1429
- try {
1430
- const importedModule = await import(moduleUrl);
1431
- renderModules.set(clientRoot, importedModule);
1432
- } catch (err) {
1433
- throw AppError.internal(`Failed to load render module ${renderModulePath}`, {
1434
- cause: err,
1435
- details: { moduleUrl, clientRoot, entryServer, ssrDistPath }
1436
- });
1437
- }
1438
- } catch (err) {
1439
- if (err instanceof AppError) {
1440
- logger.error(
1441
- {
1442
- error: { name: err.name, message: err.message, stack: err.stack, code: err.code },
1443
- stage: "loadAssets:production"
1444
- },
1445
- "Asset load failed"
1446
- );
1447
- } else {
1448
- logger.error(
1449
- {
1450
- error: err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : String(err),
1451
- stage: "loadAssets:production"
1452
- },
1453
- "Asset load failed"
1454
- );
1422
+ if (isDevelopment) {
1423
+ const bootstrapModule2 = `/${adjustedRelativePath}/${entryClient}`.replace(/\/{2,}/g, "/");
1424
+ bootstrapModules.set(clientRoot, bootstrapModule2);
1425
+ continue;
1426
+ }
1427
+ const distRoot = path2.dirname(baseClientRoot);
1428
+ const ssrRoot = path2.join(distRoot, "ssr");
1429
+ const clientDistPath = path2.join(baseClientRoot, entryPoint);
1430
+ const manifestPath = path2.join(clientDistPath, ".vite/manifest.json");
1431
+ const manifest = JSON.parse(await readFile(manifestPath, "utf-8"));
1432
+ manifests.set(clientRoot, manifest);
1433
+ const ssrDistPath = path2.join(ssrRoot, entryPoint);
1434
+ const ssrManifestPath = path2.join(ssrDistPath, ".vite/ssr-manifest.json");
1435
+ const ssrManifest = JSON.parse(await readFile(ssrManifestPath, "utf-8"));
1436
+ ssrManifests.set(clientRoot, ssrManifest);
1437
+ const manifestEntry = findManifestEntry(manifest, entryClient);
1438
+ if (!manifestEntry?.file) {
1439
+ throw AppError.internal(`Entry "${entryClient}" not found in manifest`, {
1440
+ details: {
1441
+ tried: ENTRY_EXTENSIONS.map((e) => `${entryClient}${e}`),
1442
+ availableKeys: Object.keys(manifest),
1443
+ clientRoot,
1444
+ entryPoint,
1445
+ manifestPath
1455
1446
  }
1456
- }
1457
- } else {
1458
- const bootstrapModule = `/${adjustedRelativePath}/${entryClientFile}`.replace(/\/{2,}/g, "/");
1459
- bootstrapModules.set(clientRoot, bootstrapModule);
1447
+ });
1448
+ }
1449
+ const bootstrapModule = `/${adjustedRelativePath}/${manifestEntry.file}`.replace(/\/{2,}/g, "/");
1450
+ bootstrapModules.set(clientRoot, bootstrapModule);
1451
+ preloadLinks.set(clientRoot, renderPreloadLinks(ssrManifest, adjustedRelativePath));
1452
+ cssLinks.set(clientRoot, getCssLinks(manifest, adjustedRelativePath));
1453
+ const renderModulePath = path2.join(ssrDistPath, `${entryServer}.js`);
1454
+ const moduleUrl = pathToFileURL(renderModulePath).href;
1455
+ try {
1456
+ const importedModule = await import(moduleUrl);
1457
+ renderModules.set(clientRoot, importedModule);
1458
+ } catch (err) {
1459
+ throw AppError.internal(`Failed to load render module ${renderModulePath}`, {
1460
+ cause: err,
1461
+ details: { moduleUrl, clientRoot, entryServer, ssrDistPath }
1462
+ });
1460
1463
  }
1461
1464
  } catch (err) {
1462
- logger.error(
1463
- {
1464
- error: err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : String(err),
1465
- stage: "loadAssets:config"
1466
- },
1467
- "Failed to process config"
1468
- );
1465
+ logAssetError(logger, isDevelopment ? "loadAssets:development" : "loadAssets:production", err);
1466
+ if (!isDevelopment) throw err;
1469
1467
  }
1470
1468
  }
1471
1469
  };
@@ -1544,27 +1542,284 @@ var setupDevServer = async (app, baseClientRoot, alias, debug, devNet, plugins =
1544
1542
  protocol: "ws"
1545
1543
  }
1546
1544
  }
1547
- });
1548
- overrideCSSHMRConsoleError();
1549
- app.addHook("onRequest", async (request, reply) => {
1550
- await new Promise((resolve) => {
1551
- viteDevServer.middlewares(request.raw, reply.raw, () => {
1552
- if (!reply.sent) resolve();
1553
- });
1554
- });
1555
- });
1556
- return viteDevServer;
1557
- };
1558
-
1559
- // src/utils/HandleRender.ts
1560
- import path4 from "path";
1561
- import { PassThrough } from "stream";
1545
+ });
1546
+ overrideCSSHMRConsoleError();
1547
+ app.addHook("onRequest", async (request, reply) => {
1548
+ await new Promise((resolve) => {
1549
+ viteDevServer.middlewares(request.raw, reply.raw, () => {
1550
+ if (!reply.sent) resolve();
1551
+ });
1552
+ });
1553
+ });
1554
+ return viteDevServer;
1555
+ };
1556
+
1557
+ // src/utils/HandleRender.ts
1558
+ import path5 from "path";
1559
+ import { PassThrough } from "stream";
1560
+
1561
+ // src/core/constants.ts
1562
+ var RENDERTYPE = {
1563
+ ssr: "ssr",
1564
+ streaming: "streaming"
1565
+ };
1566
+ var REGEX2 = {
1567
+ SAFE_TRACE: /^[a-zA-Z0-9-_:.]{1,128}$/
1568
+ };
1569
+
1570
+ // src/Build.ts
1571
+ import { existsSync } from "fs";
1572
+ import * as fs from "fs";
1573
+ import path4 from "path";
1574
+ import { build } from "vite";
1575
+ function resolveInputs(isSSRBuild, mainExists, paths) {
1576
+ if (isSSRBuild) return { server: paths.server };
1577
+ if (mainExists) return { client: paths.client, main: paths.main };
1578
+ return { client: paths.client };
1579
+ }
1580
+ function resolveEntryFile(clientRoot, stem, exists = fs.existsSync) {
1581
+ for (const ext of ENTRY_EXTENSIONS) {
1582
+ const filename = `${stem}${ext}`;
1583
+ if (exists(path4.join(clientRoot, filename))) return filename;
1584
+ }
1585
+ throw new Error(`Entry file "${stem}" not found in ${clientRoot}. Tried: ${ENTRY_EXTENSIONS.map((e) => stem + e).join(", ")}`);
1586
+ }
1587
+ function getFrameworkInvariants(config) {
1588
+ return {
1589
+ root: config.root || "",
1590
+ base: config.base || "/",
1591
+ publicDir: config.publicDir === void 0 ? "public" : config.publicDir,
1592
+ build: {
1593
+ outDir: config.build?.outDir || "",
1594
+ manifest: config.build?.manifest ?? false,
1595
+ ssr: config.build?.ssr ?? void 0,
1596
+ // Preserve exact type
1597
+ ssrManifest: config.build?.ssrManifest ?? false,
1598
+ format: config.build?.format,
1599
+ target: config.build?.target,
1600
+ rollupOptions: {
1601
+ input: config.build?.rollupOptions?.input || {}
1602
+ }
1603
+ }
1604
+ };
1605
+ }
1606
+ var normalisePlugins = (p) => Array.isArray(p) ? p : p ? [p] : [];
1607
+ function mergeViteConfig(framework, userOverride, context) {
1608
+ if (!userOverride) return framework;
1609
+ const userConfig = typeof userOverride === "function" && context ? userOverride(context) : userOverride;
1610
+ const invariants = getFrameworkInvariants(framework);
1611
+ const merged = {
1612
+ ...framework,
1613
+ build: { ...framework.build ?? {} },
1614
+ css: { ...framework.css ?? {} },
1615
+ resolve: { ...framework.resolve ?? {} },
1616
+ plugins: [...framework.plugins ?? []],
1617
+ define: { ...framework.define ?? {} }
1618
+ };
1619
+ const ignoredKeys = [];
1620
+ if (userConfig.plugins) merged.plugins = [...normalisePlugins(merged.plugins), ...normalisePlugins(userConfig.plugins)];
1621
+ if (userConfig.define && typeof userConfig.define === "object") merged.define = { ...merged.define, ...userConfig.define };
1622
+ if (userConfig.css?.preprocessorOptions) {
1623
+ const fpp = merged.css?.preprocessorOptions ?? {};
1624
+ const upp = userConfig.css.preprocessorOptions;
1625
+ merged.css ??= {};
1626
+ merged.css.preprocessorOptions ??= {};
1627
+ merged.css.preprocessorOptions = Object.keys({ ...fpp, ...upp }).reduce((acc, engine) => {
1628
+ acc[engine] = {
1629
+ ...fpp[engine],
1630
+ ...upp[engine]
1631
+ };
1632
+ return acc;
1633
+ }, {});
1634
+ }
1635
+ if (userConfig.build) {
1636
+ const protectedBuildFields = ["outDir", "ssr", "ssrManifest", "format", "target"];
1637
+ for (const field of protectedBuildFields) {
1638
+ if (field in userConfig.build) ignoredKeys.push(`build.${field}`);
1639
+ }
1640
+ if ("sourcemap" in userConfig.build) merged.build.sourcemap = userConfig.build.sourcemap;
1641
+ if ("minify" in userConfig.build) merged.build.minify = userConfig.build.minify;
1642
+ if (userConfig.build.terserOptions) {
1643
+ merged.build.terserOptions = {
1644
+ ...merged.build.terserOptions,
1645
+ ...userConfig.build.terserOptions
1646
+ };
1647
+ }
1648
+ if (userConfig.build.rollupOptions) {
1649
+ const userRollup = userConfig.build.rollupOptions;
1650
+ const ro = merged.build.rollupOptions ??= {};
1651
+ if ("input" in userRollup) ignoredKeys.push("build.rollupOptions.input");
1652
+ if ("external" in userRollup) ro.external = userRollup.external;
1653
+ if (userRollup.output) {
1654
+ const uo = Array.isArray(userRollup.output) ? userRollup.output[0] : userRollup.output;
1655
+ ro.output = {
1656
+ ...Array.isArray(ro.output) ? ro.output[0] : ro.output,
1657
+ ...uo?.manualChunks ? { manualChunks: uo.manualChunks } : {}
1658
+ };
1659
+ }
1660
+ }
1661
+ }
1662
+ if (userConfig.resolve) {
1663
+ const { alias: _ignore, ...rest } = userConfig.resolve;
1664
+ if (_ignore) ignoredKeys.push("resolve.alias");
1665
+ merged.resolve = { ...merged.resolve, ...rest };
1666
+ }
1667
+ if (userConfig.server) ignoredKeys.push("server");
1668
+ if ("root" in userConfig) ignoredKeys.push("root");
1669
+ if ("base" in userConfig) ignoredKeys.push("base");
1670
+ if ("publicDir" in userConfig) ignoredKeys.push("publicDir");
1671
+ for (const key of ["esbuild", "logLevel", "envPrefix", "optimizeDeps", "ssr"]) {
1672
+ if (key in userConfig) merged[key] = userConfig[key];
1673
+ }
1674
+ merged.root = invariants.root;
1675
+ merged.base = invariants.base;
1676
+ merged.publicDir = invariants.publicDir;
1677
+ merged.build.outDir = invariants.build.outDir;
1678
+ merged.build.manifest = invariants.build.manifest;
1679
+ merged.build.ssr = invariants.build.ssr;
1680
+ merged.build.ssrManifest = invariants.build.ssrManifest;
1681
+ merged.build.format = invariants.build.format;
1682
+ merged.build.target = invariants.build.target;
1683
+ if (invariants.build.ssr === void 0) delete merged.build.ssr;
1684
+ if (invariants.build.format === void 0) delete merged.build.format;
1685
+ if (invariants.build.target === void 0) delete merged.build.target;
1686
+ (merged.build.rollupOptions ??= {}).input = invariants.build.rollupOptions.input;
1687
+ if (ignoredKeys.length > 0) {
1688
+ const prefix = context ? `[taujs:build:${context.entryPoint}]` : "[taujs:build]";
1689
+ console.warn(`${prefix} Ignored Vite config overrides: ${[...new Set(ignoredKeys)].join(", ")}`);
1690
+ }
1691
+ return merged;
1692
+ }
1693
+ function resolveAppFilter(argv, env) {
1694
+ const read = (keys) => {
1695
+ const end = argv.indexOf("--");
1696
+ const limit = end === -1 ? argv.length : end;
1697
+ for (let i = 0; i < limit; i++) {
1698
+ const arg = argv[i];
1699
+ if (!arg) continue;
1700
+ for (const key of keys) {
1701
+ if (arg === key) {
1702
+ const next = argv[i + 1];
1703
+ if (!next || next.startsWith("-")) return "";
1704
+ return next.trim();
1705
+ }
1706
+ const pref = `${key}=`;
1707
+ if (arg.startsWith(pref)) {
1708
+ const v = arg.slice(pref.length).trim();
1709
+ return v;
1710
+ }
1711
+ }
1712
+ }
1713
+ return void 0;
1714
+ };
1715
+ const envFilter = env.TAUJS_APP || env.TAUJS_APPS;
1716
+ const cliFilter = read(["--app", "--apps", "-a"]);
1717
+ const raw = (cliFilter ?? envFilter)?.trim() || void 0;
1718
+ if (!raw) return { selectedIds: null, raw: void 0 };
1719
+ const selectedIds = new Set(
1720
+ raw.split(",").map((s) => s.trim()).filter(Boolean)
1721
+ );
1722
+ return { selectedIds, raw };
1723
+ }
1724
+ async function taujsBuild({
1725
+ config,
1726
+ projectRoot,
1727
+ clientBaseDir,
1728
+ isSSRBuild = process.env.BUILD_MODE === "ssr",
1729
+ alias: userAlias,
1730
+ vite: userViteConfig
1731
+ }) {
1732
+ const deleteDist = async () => {
1733
+ const { rm } = await import("fs/promises");
1734
+ const distPath = path4.resolve(projectRoot, "dist");
1735
+ try {
1736
+ await rm(distPath, { recursive: true, force: true });
1737
+ console.log("Deleted the dist directory\n");
1738
+ } catch (err) {
1739
+ console.error("Error deleting dist directory:", err);
1740
+ }
1741
+ };
1742
+ const extractedConfigs = extractBuildConfigs(config);
1743
+ const processedConfigs = processConfigs(extractedConfigs, clientBaseDir, TEMPLATE);
1744
+ const { selectedIds, raw: appFilterRaw } = resolveAppFilter(process.argv.slice(2), process.env);
1745
+ const configsToBuild = selectedIds ? processedConfigs.filter(({ appId, entryPoint }) => selectedIds.has(appId) || selectedIds.has(entryPoint)) : processedConfigs;
1746
+ if (selectedIds && configsToBuild.length === 0) {
1747
+ console.error(
1748
+ `[taujs:build] No apps match filter "${appFilterRaw}". Known apps: ${processedConfigs.map((c) => `${c.appId}${c.entryPoint ? ` (entry: ${c.entryPoint})` : ""}`).join(", ")}`
1749
+ );
1750
+ process.exit(1);
1751
+ }
1752
+ if (!isSSRBuild) await deleteDist();
1753
+ for (const appConfig of configsToBuild) {
1754
+ const { appId, entryPoint, clientRoot, entryClient, entryServer, htmlTemplate, plugins = [] } = appConfig;
1755
+ const outDir = path4.resolve(projectRoot, isSSRBuild ? `dist/ssr/${entryPoint}` : `dist/client/${entryPoint}`);
1756
+ const root = entryPoint ? path4.resolve(clientBaseDir, entryPoint) : clientBaseDir;
1757
+ const defaultAlias = {
1758
+ "@client": root,
1759
+ "@server": path4.resolve(projectRoot, "src/server"),
1760
+ "@shared": path4.resolve(projectRoot, "src/shared")
1761
+ };
1762
+ const resolvedAlias = { ...defaultAlias, ...userAlias ?? {} };
1763
+ const entryClientFile = resolveEntryFile(clientRoot, entryClient);
1764
+ const entryServerFile = resolveEntryFile(clientRoot, entryServer);
1765
+ const server = path4.resolve(clientRoot, entryServerFile);
1766
+ const client = path4.resolve(clientRoot, entryClientFile);
1767
+ const main = path4.resolve(clientRoot, htmlTemplate);
1768
+ const inputs = resolveInputs(isSSRBuild, !isSSRBuild && existsSync(main), { server, client, main });
1769
+ const nodeVersion = process.versions.node.split(".")[0];
1770
+ const frameworkConfig = {
1771
+ base: entryPoint ? `/${entryPoint}/` : "/",
1772
+ build: {
1773
+ outDir,
1774
+ emptyOutDir: true,
1775
+ manifest: !isSSRBuild,
1776
+ rollupOptions: {
1777
+ input: inputs
1778
+ },
1779
+ ssr: isSSRBuild ? server : void 0,
1780
+ ssrManifest: isSSRBuild,
1781
+ ...isSSRBuild && {
1782
+ format: "esm",
1783
+ target: `node${nodeVersion}`,
1784
+ copyPublicDir: false
1785
+ }
1786
+ },
1787
+ css: {
1788
+ preprocessorOptions: {
1789
+ scss: { api: "modern-compiler" }
1790
+ }
1791
+ },
1792
+ plugins,
1793
+ publicDir: isSSRBuild ? false : "public",
1794
+ resolve: { alias: resolvedAlias },
1795
+ root
1796
+ };
1797
+ const buildContext = {
1798
+ appId,
1799
+ entryPoint,
1800
+ isSSRBuild,
1801
+ clientRoot
1802
+ };
1803
+ const finalConfig = mergeViteConfig(frameworkConfig, userViteConfig, buildContext);
1804
+ try {
1805
+ const mode = isSSRBuild ? "SSR" : "Client";
1806
+ console.log(`[taujs:build:${entryPoint}] Building \u2192 ${mode}`);
1807
+ await build(finalConfig);
1808
+ console.log(`[taujs:build:${entryPoint}] \u2713 Complete
1809
+ `);
1810
+ } catch (error) {
1811
+ console.error(`[taujs:build:${entryPoint}] \u2717 Failed
1812
+ `, error);
1813
+ process.exit(1);
1814
+ }
1815
+ }
1816
+ }
1562
1817
 
1563
1818
  // src/utils/Telemetry.ts
1564
1819
  import crypto2 from "crypto";
1565
1820
  function createRequestContext(req, reply, baseLogger) {
1566
1821
  const raw = typeof req.headers["x-trace-id"] === "string" ? req.headers["x-trace-id"] : "";
1567
- const traceId = raw && REGEX.SAFE_TRACE.test(raw) ? raw : typeof req.id === "string" ? req.id : crypto2.randomUUID();
1822
+ const traceId = raw && REGEX2.SAFE_TRACE.test(raw) ? raw : typeof req.id === "string" ? req.id : crypto2.randomUUID();
1568
1823
  reply.header("x-trace-id", traceId);
1569
1824
  const anyLogger = baseLogger;
1570
1825
  const child = anyLogger.child;
@@ -1615,7 +1870,7 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
1615
1870
  }
1616
1871
  });
1617
1872
  }
1618
- const { clientRoot, entryServerFile } = config;
1873
+ const { clientRoot, entryServer } = config;
1619
1874
  let template = ensureNonNull(maps.templates.get(clientRoot), `Template not found for clientRoot: ${clientRoot}`);
1620
1875
  const bootstrapModule = maps.bootstrapModules.get(clientRoot);
1621
1876
  const cssLink = maps.cssLinks.get(clientRoot);
@@ -1627,7 +1882,8 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
1627
1882
  try {
1628
1883
  template = template.replace(/<script type="module" src="\/@vite\/client"><\/script>/g, "");
1629
1884
  template = template.replace(/<style type="text\/css">[\s\S]*?<\/style>/g, "");
1630
- const entryServerPath = path4.join(clientRoot, entryServerFile);
1885
+ const entryServerFile = resolveEntryFile(clientRoot, entryServer);
1886
+ const entryServerPath = path5.join(clientRoot, entryServerFile);
1631
1887
  const executedModule = await viteDevServer.ssrLoadModule(entryServerPath);
1632
1888
  renderModule = executedModule;
1633
1889
  const styles = await collectStyle(viteDevServer, [entryServerPath]);
@@ -1635,7 +1891,7 @@ var handleRender = async (req, reply, routeMatchers, processedConfigs, serviceRe
1635
1891
  template = template?.replace("</head>", `<style type="text/css"${styleNonce}>${styles}</style></head>`);
1636
1892
  template = await viteDevServer.transformIndexHtml(url, template);
1637
1893
  } catch (error) {
1638
- throw AppError.internal("Failed to load dev assets", { cause: error, details: { clientRoot, entryServerFile, url } });
1894
+ throw AppError.internal("Failed to load dev assets", { cause: error, details: { clientRoot, entryServer, url } });
1639
1895
  }
1640
1896
  } else {
1641
1897
  renderModule = maps.renderModules.get(clientRoot);
@@ -1904,30 +2160,6 @@ var handleNotFound = async (req, reply, processedConfigs, maps, opts = {}) => {
1904
2160
  }
1905
2161
  };
1906
2162
 
1907
- // src/utils/ResolveRouteData.ts
1908
- async function resolveRouteData(url, opts) {
1909
- const { req, reply, routeMatchers, serviceRegistry, logger } = opts;
1910
- const match2 = matchRoute(url, routeMatchers);
1911
- if (!match2) {
1912
- throw AppError.notFound("route_not_found", {
1913
- details: { url }
1914
- });
1915
- }
1916
- const { route, params } = match2;
1917
- const attr = route.attr;
1918
- if (!attr?.data) {
1919
- throw AppError.notFound("no_data_handler", {
1920
- details: {
1921
- url,
1922
- path: route.path,
1923
- appId: route.appId
1924
- }
1925
- });
1926
- }
1927
- const ctx = createRequestContext(req, reply, logger);
1928
- return fetchInitialData(attr, params, serviceRegistry, ctx);
1929
- }
1930
-
1931
2163
  // src/utils/StaticAssets.ts
1932
2164
  function normaliseStaticAssets(reg) {
1933
2165
  if (!reg) return [];
@@ -2000,10 +2232,7 @@ var SSRServer = fp3(
2000
2232
  maps.renderModules,
2001
2233
  maps.ssrManifests,
2002
2234
  maps.templates,
2003
- {
2004
- debug: opts.debug,
2005
- logger
2006
- }
2235
+ { logger }
2007
2236
  );
2008
2237
  if (!isDevelopment && !opts.staticAssets) {
2009
2238
  const fastifyStatic = await import("@fastify/static");
@@ -2040,23 +2269,6 @@ var SSRServer = fp3(
2040
2269
  viteDevServer = await setupDevServer(app, clientRoot, alias, opts.debug, opts.devNet, plugins);
2041
2270
  }
2042
2271
  app.addHook("onRequest", createAuthHook(routeMatchers, logger));
2043
- app.get("/__taujs/route", async (req, reply) => {
2044
- const query = req.query;
2045
- const url = typeof query.url === "string" ? query.url : "";
2046
- if (!url) {
2047
- throw AppError.badRequest("url query param required", {
2048
- details: { query }
2049
- });
2050
- }
2051
- const data = await resolveRouteData(url, {
2052
- req,
2053
- reply,
2054
- routeMatchers,
2055
- serviceRegistry,
2056
- logger
2057
- });
2058
- return reply.status(200).send({ data });
2059
- });
2060
2272
  app.get("/*", async (req, reply) => {
2061
2273
  await handleRender(req, reply, routeMatchers, processedConfigs, serviceRegistry, maps, {
2062
2274
  debug: opts.debug,
@@ -2111,13 +2323,13 @@ var SSRServer = fp3(
2111
2323
 
2112
2324
  // src/CreateServer.ts
2113
2325
  var resolveClientRoot = (userClientRoot) => {
2114
- if (userClientRoot) return path5.isAbsolute(userClientRoot) ? userClientRoot : path5.resolve(process.cwd(), userClientRoot);
2326
+ if (userClientRoot) return path6.isAbsolute(userClientRoot) ? userClientRoot : path6.resolve(process.cwd(), userClientRoot);
2115
2327
  const cwd = process.cwd();
2116
- if (process.env.NODE_ENV === "production") return path5.resolve(cwd, "dist/client");
2117
- return path5.resolve(cwd, "src/client");
2328
+ if (process.env.NODE_ENV === "production") return path6.resolve(cwd, "dist/client");
2329
+ return path6.resolve(cwd, "src/client");
2118
2330
  };
2119
2331
  var createServer = async (opts) => {
2120
- const t0 = performance3.now();
2332
+ const t0 = performance.now();
2121
2333
  const clientRoot = resolveClientRoot(opts.clientRoot);
2122
2334
  const app = opts.fastify ?? Fastify({ logger: false });
2123
2335
  const fastifyLogger = app.log && app.log.level && app.log.level !== "silent" ? app.log : void 0;
@@ -2178,7 +2390,7 @@ var createServer = async (opts) => {
2178
2390
  "Failed to register SSRServer"
2179
2391
  );
2180
2392
  }
2181
- const t1 = performance3.now();
2393
+ const t1 = performance.now();
2182
2394
  console.log(`
2183
2395
  ${import_picocolors4.default.bgGreen(import_picocolors4.default.black(` ${CONTENT.TAG} `))} configured in ${(t1 - t0).toFixed(0)}ms
2184
2396
  `);
@@ -2186,264 +2398,11 @@ ${import_picocolors4.default.bgGreen(import_picocolors4.default.black(` ${CONTEN
2186
2398
  return { app, net };
2187
2399
  };
2188
2400
 
2189
- // src/Build.ts
2190
- import { existsSync as existsSync2 } from "fs";
2191
- import path6 from "path";
2192
- import { build } from "vite";
2193
- function resolveInputs(isSSRBuild, mainExists, paths) {
2194
- if (isSSRBuild) return { server: paths.server };
2195
- if (mainExists) return { client: paths.client, main: paths.main };
2196
- return { client: paths.client };
2197
- }
2198
- function getFrameworkInvariants(config) {
2199
- return {
2200
- root: config.root || "",
2201
- base: config.base || "/",
2202
- publicDir: config.publicDir === void 0 ? "public" : config.publicDir,
2203
- build: {
2204
- outDir: config.build?.outDir || "",
2205
- manifest: config.build?.manifest ?? false,
2206
- ssr: config.build?.ssr ?? void 0,
2207
- // Preserve exact type
2208
- ssrManifest: config.build?.ssrManifest ?? false,
2209
- format: config.build?.format,
2210
- target: config.build?.target,
2211
- rollupOptions: {
2212
- input: config.build?.rollupOptions?.input || {}
2213
- }
2214
- }
2215
- };
2216
- }
2217
- function mergeViteConfig(framework, userOverride, context) {
2218
- if (!userOverride) return framework;
2219
- const userConfig = typeof userOverride === "function" && context ? userOverride(context) : userOverride;
2220
- const invariants = getFrameworkInvariants(framework);
2221
- const merged = {
2222
- ...framework,
2223
- build: { ...framework.build ?? {} },
2224
- css: { ...framework.css ?? {} },
2225
- resolve: { ...framework.resolve ?? {} },
2226
- plugins: [...framework.plugins ?? []],
2227
- define: { ...framework.define ?? {} }
2228
- };
2229
- const ignoredKeys = [];
2230
- if (userConfig.plugins) {
2231
- const frameworkPlugins = merged.plugins;
2232
- merged.plugins = [...frameworkPlugins, ...userConfig.plugins];
2233
- }
2234
- if (userConfig.define && typeof userConfig.define === "object") {
2235
- merged.define = {
2236
- ...merged.define,
2237
- ...userConfig.define
2238
- };
2239
- }
2240
- if (userConfig.css?.preprocessorOptions && typeof userConfig.css.preprocessorOptions === "object") {
2241
- const fpp = merged.css.preprocessorOptions ?? {};
2242
- const upp = userConfig.css.preprocessorOptions;
2243
- merged.css.preprocessorOptions = Object.keys({ ...fpp, ...upp }).reduce((acc, engine) => {
2244
- const fppEngine = fpp[engine];
2245
- const uppEngine = upp[engine];
2246
- acc[engine] = { ...fppEngine ?? {}, ...uppEngine ?? {} };
2247
- return acc;
2248
- }, {});
2249
- }
2250
- if (userConfig.build) {
2251
- const protectedBuildFields = ["outDir", "ssr", "ssrManifest", "format", "target"];
2252
- for (const field of protectedBuildFields) {
2253
- if (field in userConfig.build) {
2254
- ignoredKeys.push(`build.${field}`);
2255
- }
2256
- }
2257
- if ("sourcemap" in userConfig.build) merged.build.sourcemap = userConfig.build.sourcemap;
2258
- if ("minify" in userConfig.build) merged.build.minify = userConfig.build.minify;
2259
- if (userConfig.build.terserOptions && typeof userConfig.build.terserOptions === "object") {
2260
- merged.build.terserOptions = {
2261
- ...merged.build.terserOptions ?? {},
2262
- ...userConfig.build.terserOptions
2263
- };
2264
- }
2265
- if (userConfig.build.rollupOptions) {
2266
- if (!merged.build.rollupOptions) {
2267
- merged.build.rollupOptions = {};
2268
- }
2269
- const userRollup = userConfig.build.rollupOptions;
2270
- if ("input" in userRollup) ignoredKeys.push("build.rollupOptions.input");
2271
- if ("external" in userRollup) merged.build.rollupOptions.external = userRollup.external;
2272
- if (userRollup.output) {
2273
- const mro = merged.build.rollupOptions ??= {};
2274
- const uo = Array.isArray(userRollup.output) ? userRollup.output[0] : userRollup.output;
2275
- const baseOut = Array.isArray(mro.output) ? mro.output[0] ?? {} : mro.output ?? {};
2276
- mro.output = { ...baseOut, ...uo?.manualChunks ? { manualChunks: uo.manualChunks } : {} };
2277
- }
2278
- }
2279
- }
2280
- if (userConfig.resolve) {
2281
- const userResolve = userConfig.resolve;
2282
- const { alias: _ignore, ...resolveRest } = userResolve;
2283
- if (_ignore) ignoredKeys.push("resolve.alias");
2284
- merged.resolve = {
2285
- ...merged.resolve,
2286
- ...resolveRest
2287
- };
2288
- }
2289
- if (userConfig.server) ignoredKeys.push("server (ignored in build; dev-only)");
2290
- if ("root" in userConfig) ignoredKeys.push("root");
2291
- if ("base" in userConfig) ignoredKeys.push("base");
2292
- if ("publicDir" in userConfig) ignoredKeys.push("publicDir");
2293
- const safeTopLevelKeys = /* @__PURE__ */ new Set([
2294
- "esbuild",
2295
- "logLevel",
2296
- "envPrefix",
2297
- "optimizeDeps",
2298
- "ssr"
2299
- // NOTE: NOT 'server' (build-time irrelevant; dev-server only)
2300
- ]);
2301
- for (const [key, value] of Object.entries(userConfig)) {
2302
- if (safeTopLevelKeys.has(key)) merged[key] = value;
2303
- }
2304
- merged.root = invariants.root;
2305
- merged.base = invariants.base;
2306
- merged.publicDir = invariants.publicDir;
2307
- merged.build.outDir = invariants.build.outDir;
2308
- merged.build.manifest = invariants.build.manifest;
2309
- if (invariants.build.ssr !== void 0) merged.build.ssr = invariants.build.ssr;
2310
- merged.build.ssrManifest = invariants.build.ssrManifest;
2311
- if (invariants.build.format) merged.build.format = invariants.build.format;
2312
- if (invariants.build.target) merged.build.target = invariants.build.target;
2313
- if (!merged.build.rollupOptions) merged.build.rollupOptions = {};
2314
- merged.build.rollupOptions.input = invariants.build.rollupOptions.input;
2315
- if (ignoredKeys.length > 0) {
2316
- const uniqueKeys = [...new Set(ignoredKeys)];
2317
- const prefix = context ? `[taujs:build:${context.entryPoint}]` : "[taujs:build]";
2318
- console.warn(`${prefix} Ignored Vite config overrides: ${uniqueKeys.join(", ")}`);
2319
- }
2320
- return merged;
2321
- }
2322
- function resolveAppFilter(argv, env) {
2323
- const read = (keys) => {
2324
- const end = argv.indexOf("--");
2325
- const limit = end === -1 ? argv.length : end;
2326
- for (let i = 0; i < limit; i++) {
2327
- const arg = argv[i];
2328
- if (!arg) continue;
2329
- for (const key of keys) {
2330
- if (arg === key) {
2331
- const next = argv[i + 1];
2332
- if (!next || next.startsWith("-")) return "";
2333
- return next.trim();
2334
- }
2335
- const pref = `${key}=`;
2336
- if (arg.startsWith(pref)) {
2337
- const v = arg.slice(pref.length).trim();
2338
- return v;
2339
- }
2340
- }
2341
- }
2342
- return void 0;
2343
- };
2344
- const envFilter = env.TAUJS_APP || env.TAUJS_APPS;
2345
- const cliFilter = read(["--app", "--apps", "-a"]);
2346
- const raw = (cliFilter ?? envFilter)?.trim() || void 0;
2347
- if (!raw) return { selectedIds: null, raw: void 0 };
2348
- const selectedIds = new Set(
2349
- raw.split(",").map((s) => s.trim()).filter(Boolean)
2350
- );
2351
- return { selectedIds, raw };
2352
- }
2353
- async function taujsBuild({
2354
- config,
2355
- projectRoot,
2356
- clientBaseDir,
2357
- isSSRBuild = process.env.BUILD_MODE === "ssr",
2358
- alias: userAlias,
2359
- vite: userViteConfig
2360
- }) {
2361
- const deleteDist = async () => {
2362
- const { rm } = await import("fs/promises");
2363
- const distPath = path6.resolve(projectRoot, "dist");
2364
- try {
2365
- await rm(distPath, { recursive: true, force: true });
2366
- console.log("Deleted the dist directory\n");
2367
- } catch (err) {
2368
- console.error("Error deleting dist directory:", err);
2369
- }
2370
- };
2371
- const extractedConfigs = extractBuildConfigs(config);
2372
- const processedConfigs = processConfigs(extractedConfigs, clientBaseDir, TEMPLATE);
2373
- const { selectedIds, raw: appFilterRaw } = resolveAppFilter(process.argv.slice(2), process.env);
2374
- const configsToBuild = selectedIds ? processedConfigs.filter(({ appId, entryPoint }) => selectedIds.has(appId) || selectedIds.has(entryPoint)) : processedConfigs;
2375
- if (selectedIds && configsToBuild.length === 0) {
2376
- console.error(
2377
- `[taujs:build] No apps match filter "${appFilterRaw}". Known apps: ${processedConfigs.map((c) => `${c.appId}${c.entryPoint ? ` (entry: ${c.entryPoint})` : ""}`).join(", ")}`
2378
- );
2379
- process.exit(1);
2380
- }
2381
- if (!isSSRBuild) await deleteDist();
2382
- for (const appConfig of configsToBuild) {
2383
- const { appId, entryPoint, clientRoot, entryClientFile, entryServerFile, htmlTemplate, plugins = [] } = appConfig;
2384
- const outDir = path6.resolve(projectRoot, isSSRBuild ? `dist/ssr/${entryPoint}` : `dist/client/${entryPoint}`);
2385
- const root = entryPoint ? path6.resolve(clientBaseDir, entryPoint) : clientBaseDir;
2386
- const defaultAlias = {
2387
- "@client": root,
2388
- "@server": path6.resolve(projectRoot, "src/server"),
2389
- "@shared": path6.resolve(projectRoot, "src/shared")
2390
- };
2391
- const resolvedAlias = { ...defaultAlias, ...userAlias ?? {} };
2392
- const server = path6.resolve(clientRoot, entryServerFile);
2393
- const client = path6.resolve(clientRoot, entryClientFile);
2394
- const main = path6.resolve(clientRoot, htmlTemplate);
2395
- const inputs = resolveInputs(isSSRBuild, !isSSRBuild && existsSync2(main), { server, client, main });
2396
- const nodeVersion = process.versions.node.split(".")[0];
2397
- const frameworkConfig = {
2398
- base: entryPoint ? `/${entryPoint}/` : "/",
2399
- build: {
2400
- outDir,
2401
- emptyOutDir: true,
2402
- manifest: !isSSRBuild,
2403
- rollupOptions: {
2404
- input: inputs
2405
- },
2406
- ssr: isSSRBuild ? server : void 0,
2407
- ssrManifest: isSSRBuild,
2408
- ...isSSRBuild && {
2409
- format: "esm",
2410
- target: `node${nodeVersion}`,
2411
- copyPublicDir: false
2412
- }
2413
- },
2414
- css: {
2415
- preprocessorOptions: {
2416
- scss: { api: "modern-compiler" }
2417
- }
2418
- },
2419
- plugins,
2420
- publicDir: isSSRBuild ? false : "public",
2421
- resolve: { alias: resolvedAlias },
2422
- root
2423
- };
2424
- const buildContext = {
2425
- appId,
2426
- entryPoint,
2427
- isSSRBuild,
2428
- clientRoot
2429
- };
2430
- const finalConfig = mergeViteConfig(frameworkConfig, userViteConfig, buildContext);
2431
- try {
2432
- const mode = isSSRBuild ? "SSR" : "Client";
2433
- console.log(`[taujs:build:${entryPoint}] Building \u2192 ${mode}`);
2434
- await build(finalConfig);
2435
- console.log(`[taujs:build:${entryPoint}] \u2713 Complete
2436
- `);
2437
- } catch (error) {
2438
- console.error(`[taujs:build:${entryPoint}] \u2717 Failed
2439
- `, error);
2440
- process.exit(1);
2441
- }
2442
- }
2443
- }
2444
-
2445
2401
  // src/logging/Adapters.ts
2446
- var cleanMeta = (m) => m && Object.keys(m).length === 0 ? void 0 : m;
2402
+ var cleanMeta = (meta) => {
2403
+ if (meta && typeof meta === "object" && !Array.isArray(meta)) return Object.keys(meta).length ? meta : void 0;
2404
+ return void 0;
2405
+ };
2447
2406
  function messageMetaAdapter(sink) {
2448
2407
  return {
2449
2408
  debug: (meta, message) => sink.debug?.(message, cleanMeta(meta)),