@jay-framework/dev-server 0.11.0 → 0.12.0

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +49 -2
  2. package/dist/index.js +379 -99
  3. package/package.json +14 -13
package/dist/index.d.ts CHANGED
@@ -2,8 +2,10 @@ import { ViteDevServer, Connect } from 'vite';
2
2
  import { JayRoute } from '@jay-framework/stack-route-scanner';
3
3
  import { RequestHandler } from 'express-serve-static-core';
4
4
  import { JayRollupConfig } from '@jay-framework/rollup-plugin';
5
+ import { LogLevel } from '@jay-framework/logger';
5
6
  import { ProjectClientInitInfo, PluginWithInit, ActionRegistry } from '@jay-framework/stack-server-runtime';
6
7
  import { RequestHandler as RequestHandler$1 } from 'express';
8
+ import { JayRollupConfig as JayRollupConfig$1 } from '@jay-framework/compiler-jay-stack';
7
9
 
8
10
  interface DevServerOptions {
9
11
  publicBaseUrlPath?: string;
@@ -23,6 +25,11 @@ interface DevServerOptions {
23
25
  * The automation API is available at `window.__jay.automation` and via `AUTOMATION_CONTEXT`.
24
26
  */
25
27
  disableAutomation?: boolean;
28
+ /**
29
+ * Log level for dev server output.
30
+ * Controls both Jay logging and Vite logging.
31
+ */
32
+ logLevel?: LogLevel;
26
33
  }
27
34
 
28
35
  /**
@@ -100,7 +107,7 @@ interface DevServer {
100
107
  routes: DevServerRoute[];
101
108
  lifecycleManager: ServiceLifecycleManager;
102
109
  }
103
- declare function mkDevServer(options: DevServerOptions): Promise<DevServer>;
110
+ declare function mkDevServer(rawOptions: DevServerOptions): Promise<DevServer>;
104
111
 
105
112
  /**
106
113
  * Action Router for Jay Stack dev server.
@@ -151,4 +158,44 @@ declare function createActionRouter(options?: ActionRouterOptions): RequestHandl
151
158
  */
152
159
  declare function actionBodyParser(): RequestHandler$1;
153
160
 
154
- export { ACTION_ENDPOINT_BASE, type ActionRouterOptions, type DevServer, type DevServerOptions, type DevServerRoute, actionBodyParser, createActionRouter, mkDevServer };
161
+ /**
162
+ * Vite Factory
163
+ *
164
+ * Single source of truth for creating Vite servers.
165
+ * Used by both the dev-server and CLI commands.
166
+ */
167
+
168
+ interface CreateViteServerOptions {
169
+ /** Project root directory */
170
+ projectRoot: string;
171
+ /** Root directory for pages (defaults to projectRoot) */
172
+ pagesRoot?: string;
173
+ /** Base URL path for public assets */
174
+ base?: string;
175
+ /** Jay Stack compiler config (optional, will use defaults if not provided) */
176
+ jayRollupConfig?: JayRollupConfig$1;
177
+ /** Log level (defaults to 'info' for dev-server, 'warn' for CLI) */
178
+ logLevel?: 'info' | 'warn' | 'error' | 'silent';
179
+ /** Whether to clear screen on rebuild */
180
+ clearScreen?: boolean;
181
+ }
182
+ /**
183
+ * Creates a Vite server configured for Jay Stack.
184
+ *
185
+ * This is the single source of truth for Vite configuration.
186
+ * Both dev-server and CLI use this function.
187
+ */
188
+ declare function createViteServer(options: CreateViteServerOptions): Promise<ViteDevServer>;
189
+ /**
190
+ * Creates a minimal Vite server for CLI usage.
191
+ *
192
+ * This is a convenience wrapper around createViteServer with CLI-appropriate defaults.
193
+ * Disables dependency optimization and ignores the build/ folder to avoid errors
194
+ * from stale build artifacts (e.g., build/client-scripts/ referencing build/slow-render-cache/).
195
+ */
196
+ declare function createViteForCli(options: {
197
+ projectRoot: string;
198
+ tsConfigFilePath?: string;
199
+ }): Promise<ViteDevServer>;
200
+
201
+ export { ACTION_ENDPOINT_BASE, type ActionRouterOptions, type CreateViteServerOptions, type DevServer, type DevServerOptions, type DevServerRoute, actionBodyParser, createActionRouter, createViteForCli, createViteServer, mkDevServer };
package/dist/index.js CHANGED
@@ -5,16 +5,17 @@ var __publicField = (obj, key, value) => {
5
5
  return value;
6
6
  };
7
7
  import { createServer } from "vite";
8
- import { scanRoutes, routeToExpressRoute } from "@jay-framework/stack-route-scanner";
9
- import { discoverPluginsWithInit, sortPluginsByDependencies, executePluginServerInits, runInitCallbacks, actionRegistry, discoverAndRegisterActions, discoverAllPluginActions, runShutdownCallbacks, clearLifecycleCallbacks, clearServiceRegistry, clearClientInitData, DevSlowlyChangingPhase, SlowRenderCache, preparePluginClientInits, loadPageParts, renderFastChangingData, generateClientScript, getClientInitData } from "@jay-framework/stack-server-runtime";
10
8
  import { jayRuntime } from "@jay-framework/vite-plugin";
11
9
  import { createRequire } from "module";
12
10
  import "@jay-framework/compiler-shared";
13
11
  import * as path from "node:path";
14
12
  import path__default from "node:path";
15
- import { parseContract, slowRenderTransform } from "@jay-framework/compiler-jay-html";
13
+ import { discoverHeadlessInstances, parseContract, slowRenderTransform, JAY_IMPORT_RESOLVER, resolveHeadlessInstances } from "@jay-framework/compiler-jay-html";
14
+ import { getLogger, getDevLogger } from "@jay-framework/logger";
16
15
  import { createRequire as createRequire$1 } from "node:module";
17
16
  import * as fs from "node:fs";
17
+ import { scanRoutes, routeToExpressRoute } from "@jay-framework/stack-route-scanner";
18
+ import { discoverPluginsWithInit, sortPluginsByDependencies, executePluginServerInits, runInitCallbacks, actionRegistry, discoverAndRegisterActions, discoverAllPluginActions, runShutdownCallbacks, clearLifecycleCallbacks, clearServiceRegistry, clearClientInitData, DevSlowlyChangingPhase, SlowRenderCache, preparePluginClientInits, getServiceRegistry, materializeContracts, loadPageParts, renderFastChangingData, slowRenderInstances, generateClientScript, getClientInitData, resolveServices } from "@jay-framework/stack-server-runtime";
18
19
  import fs$1 from "node:fs/promises";
19
20
  import { pathToFileURL } from "node:url";
20
21
  const s$1 = createRequire(import.meta.url), e$1 = s$1("typescript"), c$1 = new Proxy(e$1, {
@@ -1021,7 +1022,7 @@ function createImportChainTracker(options = {}) {
1021
1022
  importChain.clear();
1022
1023
  detectedServerModules.clear();
1023
1024
  if (verbose) {
1024
- console.log("[import-chain-tracker] Build started, tracking imports...");
1025
+ getLogger().info("[import-chain-tracker] Build started, tracking imports...");
1025
1026
  }
1026
1027
  },
1027
1028
  resolveId(source, importer, options2) {
@@ -1033,7 +1034,7 @@ function createImportChainTracker(options = {}) {
1033
1034
  }
1034
1035
  if (importer) {
1035
1036
  if (verbose) {
1036
- console.log(
1037
+ getLogger().info(
1037
1038
  `[import-chain-tracker] ${shortenPath(importer)} imports ${source}`
1038
1039
  );
1039
1040
  }
@@ -1050,14 +1051,14 @@ function createImportChainTracker(options = {}) {
1050
1051
  if (isServerOnlyModule(id)) {
1051
1052
  detectedServerModules.add(id);
1052
1053
  const chain = buildImportChain(id);
1053
- console.error(
1054
+ getLogger().error(
1054
1055
  `
1055
1056
  [import-chain-tracker] ⚠️ Server-only module detected in client build!`
1056
1057
  );
1057
- console.error(`Module: ${shortenPath(id)}`);
1058
- console.error(`Import chain:`);
1059
- console.error(formatChain(chain));
1060
- console.error("");
1058
+ getLogger().error(`Module: ${shortenPath(id)}`);
1059
+ getLogger().error(`Import chain:`);
1060
+ getLogger().error(formatChain(chain));
1061
+ getLogger().error("");
1061
1062
  }
1062
1063
  const importRegex = /import\s+(?:(?:\{[^}]*\}|[^{}\s,]+)\s+from\s+)?['"]([^'"]+)['"]/g;
1063
1064
  let match;
@@ -1067,16 +1068,18 @@ function createImportChainTracker(options = {}) {
1067
1068
  if (isServerOnlyModule(importedModule)) {
1068
1069
  if (!detectedServerModules.has(importedModule)) {
1069
1070
  detectedServerModules.add(importedModule);
1070
- console.error(
1071
+ getLogger().error(
1071
1072
  `
1072
1073
  [import-chain-tracker] ⚠️ Server-only import detected in client build!`
1073
1074
  );
1074
- console.error(`Module "${importedModule}" imported by: ${shortenPath(id)}`);
1075
+ getLogger().error(
1076
+ `Module "${importedModule}" imported by: ${shortenPath(id)}`
1077
+ );
1075
1078
  const chain = buildImportChain(id);
1076
1079
  chain.push(importedModule);
1077
- console.error(`Import chain:`);
1078
- console.error(formatChain(chain));
1079
- console.error("");
1080
+ getLogger().error(`Import chain:`);
1081
+ getLogger().error(formatChain(chain));
1082
+ getLogger().error("");
1080
1083
  }
1081
1084
  }
1082
1085
  }
@@ -1084,21 +1087,21 @@ function createImportChainTracker(options = {}) {
1084
1087
  },
1085
1088
  buildEnd() {
1086
1089
  if (detectedServerModules.size > 0) {
1087
- console.warn(
1090
+ getLogger().warn(
1088
1091
  `
1089
1092
  [import-chain-tracker] ⚠️ ${detectedServerModules.size} server-only module(s) detected during transform:`
1090
1093
  );
1091
1094
  for (const mod of detectedServerModules) {
1092
- console.warn(` - ${mod}`);
1095
+ getLogger().warn(` - ${mod}`);
1093
1096
  }
1094
- console.warn(
1097
+ getLogger().warn(
1095
1098
  "\nNote: These may be stripped by the code-split transform if only used in .withServer()."
1096
1099
  );
1097
- console.warn(
1100
+ getLogger().warn(
1098
1101
  'If build fails with "not exported" errors, check the import chains above.\n'
1099
1102
  );
1100
1103
  } else if (verbose) {
1101
- console.log(
1104
+ getLogger().info(
1102
1105
  "[import-chain-tracker] ✅ No server-only modules detected in client build"
1103
1106
  );
1104
1107
  }
@@ -1165,7 +1168,7 @@ function transformImports(options) {
1165
1168
  hasChanges = true;
1166
1169
  const newSource = `${packageName}/client`;
1167
1170
  if (verbose) {
1168
- console.log(
1171
+ getLogger().info(
1169
1172
  `[plugin-client-import] Rewriting import ${source} -> ${newSource} (in ${path.basename(filePath)})`
1170
1173
  );
1171
1174
  }
@@ -1182,7 +1185,7 @@ function transformImports(options) {
1182
1185
  hasChanges = true;
1183
1186
  const newSource = `${packageName}/client`;
1184
1187
  if (verbose) {
1185
- console.log(
1188
+ getLogger().info(
1186
1189
  `[plugin-client-import] Rewriting export ${source} -> ${newSource} (in ${path.basename(filePath)})`
1187
1190
  );
1188
1191
  }
@@ -1258,7 +1261,7 @@ function jayStackCompiler(options = {}) {
1258
1261
  try {
1259
1262
  return transformJayStackBuilder(code, id, environment);
1260
1263
  } catch (error) {
1261
- console.error(`[jay-stack:code-split] Error transforming ${id}:`, error);
1264
+ getLogger().error(`[jay-stack:code-split] Error transforming ${id}: ${error}`);
1262
1265
  return null;
1263
1266
  }
1264
1267
  }
@@ -1318,12 +1321,14 @@ function jayStackCompiler(options = {}) {
1318
1321
  try {
1319
1322
  code = await fs.promises.readFile(actualPath, "utf-8");
1320
1323
  } catch (err) {
1321
- console.error(`[action-transform] Could not read ${actualPath}:`, err);
1324
+ getLogger().error(
1325
+ `[action-transform] Could not read ${actualPath}: ${err}`
1326
+ );
1322
1327
  return null;
1323
1328
  }
1324
1329
  const actions = extractActionsFromSource(code, actualPath);
1325
1330
  if (actions.length === 0) {
1326
- console.warn(`[action-transform] No actions found in ${actualPath}`);
1331
+ getLogger().warn(`[action-transform] No actions found in ${actualPath}`);
1327
1332
  return null;
1328
1333
  }
1329
1334
  const lines = [
@@ -1350,6 +1355,69 @@ function jayStackCompiler(options = {}) {
1350
1355
  );
1351
1356
  return plugins;
1352
1357
  }
1358
+ async function createViteServer(options) {
1359
+ const {
1360
+ projectRoot,
1361
+ pagesRoot = projectRoot,
1362
+ base,
1363
+ jayRollupConfig = { tsConfigFilePath: path__default.join(projectRoot, "tsconfig.json") },
1364
+ logLevel = "info",
1365
+ clearScreen = true
1366
+ } = options;
1367
+ const vite = await createServer({
1368
+ // Don't start HTTP server - we use middleware mode
1369
+ server: { middlewareMode: true },
1370
+ // Use Jay Stack compiler for .jay-html and other custom transforms
1371
+ plugins: [...jayStackCompiler(jayRollupConfig)],
1372
+ // Custom app type (no default middleware)
1373
+ appType: "custom",
1374
+ // Base URL path
1375
+ base,
1376
+ // Root directory for module resolution
1377
+ root: pagesRoot,
1378
+ // SSR configuration
1379
+ ssr: {
1380
+ // Mark jay-framework packages as external so Vite uses Node's require
1381
+ // This ensures all packages share the same module instances (Symbol identity)
1382
+ external: ["@jay-framework/stack-server-runtime", "@jay-framework/fullstack-component"]
1383
+ },
1384
+ // Disable automatic entry point discovery for pre-bundling —
1385
+ // we run in middleware mode with no HTML files, so Vite can't auto-detect entries
1386
+ optimizeDeps: {
1387
+ entries: []
1388
+ },
1389
+ // Logging
1390
+ logLevel,
1391
+ clearScreen
1392
+ });
1393
+ return vite;
1394
+ }
1395
+ async function createViteForCli(options) {
1396
+ const { projectRoot, tsConfigFilePath = path__default.join(projectRoot, "tsconfig.json") } = options;
1397
+ const vite = await createServer({
1398
+ server: {
1399
+ middlewareMode: true,
1400
+ watch: {
1401
+ ignored: ["**/build/**"]
1402
+ }
1403
+ },
1404
+ plugins: [
1405
+ ...jayStackCompiler({ tsConfigFilePath })
1406
+ ],
1407
+ appType: "custom",
1408
+ root: projectRoot,
1409
+ ssr: {
1410
+ external: ["@jay-framework/stack-server-runtime", "@jay-framework/fullstack-component"]
1411
+ },
1412
+ // Disable dependency optimization — CLI only uses SSR, no browser bundles
1413
+ optimizeDeps: {
1414
+ entries: []
1415
+ },
1416
+ logLevel: "warn",
1417
+ clearScreen: false
1418
+ });
1419
+ return vite;
1420
+ }
1353
1421
  class ServiceLifecycleManager {
1354
1422
  constructor(projectRoot, sourceBase = "src") {
1355
1423
  /** Path to project's lib/init.ts (makeJayInit pattern) */
@@ -1388,8 +1456,9 @@ class ServiceLifecycleManager {
1388
1456
  * 4. Auto-discovering and registering actions
1389
1457
  */
1390
1458
  async initialize() {
1459
+ const log = getLogger();
1391
1460
  if (this.isInitialized) {
1392
- console.warn("[Services] Already initialized, skipping...");
1461
+ log.warn("[Services] Already initialized, skipping...");
1393
1462
  return;
1394
1463
  }
1395
1464
  this.projectInitFilePath = this.findProjectInitFile();
@@ -1399,18 +1468,18 @@ class ServiceLifecycleManager {
1399
1468
  });
1400
1469
  this.pluginsWithInit = sortPluginsByDependencies(discoveredPlugins);
1401
1470
  if (this.pluginsWithInit.length > 0) {
1402
- console.log(
1471
+ log.info(
1403
1472
  `[Services] Found ${this.pluginsWithInit.length} plugin(s) with init: ${this.pluginsWithInit.map((p) => p.name).join(", ")}`
1404
1473
  );
1405
1474
  }
1406
1475
  await executePluginServerInits(this.pluginsWithInit, this.viteServer ?? void 0, true);
1407
1476
  if (this.projectInitFilePath) {
1408
- console.log("[DevServer] Loading project init: src/init.ts");
1477
+ log.info("[DevServer] Loading project init: src/init.ts");
1409
1478
  try {
1410
1479
  if (this.viteServer) {
1411
1480
  const module = await this.viteServer.ssrLoadModule(this.projectInitFilePath);
1412
1481
  if (module.init?._serverInit) {
1413
- console.log("[DevServer] Running server init: project");
1482
+ log.info("[DevServer] Running server init: project");
1414
1483
  const { setClientInitData } = await import("@jay-framework/stack-server-runtime");
1415
1484
  const clientData = await module.init._serverInit();
1416
1485
  if (clientData !== void 0 && clientData !== null) {
@@ -1422,14 +1491,14 @@ class ServiceLifecycleManager {
1422
1491
  await import(fileUrl);
1423
1492
  }
1424
1493
  } catch (error) {
1425
- console.error("[Services] Failed to load project init:", error);
1494
+ log.error(`[Services] Failed to load project init: ${error}`);
1426
1495
  throw error;
1427
1496
  }
1428
1497
  } else {
1429
- console.log("[Services] No init.ts found, skipping project initialization");
1498
+ log.info("[Services] No init.ts found, skipping project initialization");
1430
1499
  }
1431
1500
  await runInitCallbacks();
1432
- console.log("[Services] Initialization complete");
1501
+ log.info("[Services] Initialization complete");
1433
1502
  await this.discoverActions();
1434
1503
  this.isInitialized = true;
1435
1504
  }
@@ -1437,6 +1506,7 @@ class ServiceLifecycleManager {
1437
1506
  * Auto-discovers and registers actions from project and plugins.
1438
1507
  */
1439
1508
  async discoverActions() {
1509
+ const log = getLogger();
1440
1510
  let totalActions = 0;
1441
1511
  try {
1442
1512
  const result = await discoverAndRegisterActions({
@@ -1448,7 +1518,7 @@ class ServiceLifecycleManager {
1448
1518
  });
1449
1519
  totalActions += result.actionCount;
1450
1520
  } catch (error) {
1451
- console.error("[Actions] Failed to auto-discover project actions:", error);
1521
+ log.error(`[Actions] Failed to auto-discover project actions: ${error}`);
1452
1522
  }
1453
1523
  try {
1454
1524
  const pluginActions = await discoverAllPluginActions({
@@ -1459,20 +1529,21 @@ class ServiceLifecycleManager {
1459
1529
  });
1460
1530
  totalActions += pluginActions.length;
1461
1531
  } catch (error) {
1462
- console.error("[Actions] Failed to auto-discover plugin actions:", error);
1532
+ log.error(`[Actions] Failed to auto-discover plugin actions: ${error}`);
1463
1533
  }
1464
1534
  if (totalActions > 0) {
1465
- console.log(`[Actions] Auto-registered ${totalActions} action(s) total`);
1535
+ log.info(`[Actions] Auto-registered ${totalActions} action(s) total`);
1466
1536
  }
1467
1537
  }
1468
1538
  /**
1469
1539
  * Shuts down services gracefully with timeout
1470
1540
  */
1471
1541
  async shutdown(timeoutMs = 5e3) {
1542
+ const log = getLogger();
1472
1543
  if (!this.isInitialized) {
1473
1544
  return;
1474
1545
  }
1475
- console.log("[Services] Shutting down...");
1546
+ log.info("[Services] Shutting down...");
1476
1547
  try {
1477
1548
  await Promise.race([
1478
1549
  runShutdownCallbacks(),
@@ -1480,12 +1551,12 @@ class ServiceLifecycleManager {
1480
1551
  (_, reject) => setTimeout(() => reject(new Error("Shutdown timeout")), timeoutMs)
1481
1552
  )
1482
1553
  ]);
1483
- console.log("[Services] Shutdown complete");
1554
+ log.info("[Services] Shutdown complete");
1484
1555
  } catch (error) {
1485
1556
  if (error.message === "Shutdown timeout") {
1486
- console.warn("[Services] Shutdown timed out after", timeoutMs, "ms");
1557
+ log.warn(`[Services] Shutdown timed out after ${timeoutMs}ms`);
1487
1558
  } else {
1488
- console.error("[Services] Shutdown error:", error);
1559
+ log.error(`[Services] Shutdown error: ${error}`);
1489
1560
  }
1490
1561
  } finally {
1491
1562
  this.isInitialized = false;
@@ -1495,7 +1566,8 @@ class ServiceLifecycleManager {
1495
1566
  * Hot reload: shutdown, clear caches, re-import, and re-initialize
1496
1567
  */
1497
1568
  async reload() {
1498
- console.log("[Services] Reloading services...");
1569
+ const log = getLogger();
1570
+ log.info("[Services] Reloading services...");
1499
1571
  await this.shutdown();
1500
1572
  clearLifecycleCallbacks();
1501
1573
  clearServiceRegistry();
@@ -1511,7 +1583,7 @@ class ServiceLifecycleManager {
1511
1583
  }
1512
1584
  this.isInitialized = false;
1513
1585
  await this.initialize();
1514
- console.log("[Services] Reload complete");
1586
+ log.info("[Services] Reload complete");
1515
1587
  }
1516
1588
  /**
1517
1589
  * Returns the path to the init file if found.
@@ -1813,6 +1885,7 @@ function filterPluginsForPage(allPluginClientInits, allPluginsWithInit, usedPack
1813
1885
  function mkRoute(route, vite, slowlyPhase, options, slowRenderCache, projectInit, allPluginsWithInit = [], allPluginClientInits = []) {
1814
1886
  const routePath = routeToExpressRoute(route);
1815
1887
  const handler = async (req, res) => {
1888
+ const timing = getDevLogger()?.startRequest(req.method, req.path);
1816
1889
  try {
1817
1890
  const url = req.originalUrl.replace(options.publicBaseUrlPath, "");
1818
1891
  const pageParams = { ...route.inferredParams, ...req.params };
@@ -1826,7 +1899,7 @@ function mkRoute(route, vite, slowlyPhase, options, slowRenderCache, projectInit
1826
1899
  try {
1827
1900
  await fs$1.access(cachedEntry.preRenderedPath);
1828
1901
  } catch {
1829
- console.log(
1902
+ getLogger().info(
1830
1903
  `[SlowRender] Cached file missing, rebuilding: ${cachedEntry.preRenderedPath}`
1831
1904
  );
1832
1905
  await slowRenderCache.invalidate(route.jayHtmlPath);
@@ -1845,7 +1918,8 @@ function mkRoute(route, vite, slowlyPhase, options, slowRenderCache, projectInit
1845
1918
  allPluginsWithInit,
1846
1919
  projectInit,
1847
1920
  res,
1848
- url
1921
+ url,
1922
+ timing
1849
1923
  );
1850
1924
  } else if (useSlowRenderCache) {
1851
1925
  await handlePreRenderRequest(
@@ -1860,7 +1934,8 @@ function mkRoute(route, vite, slowlyPhase, options, slowRenderCache, projectInit
1860
1934
  allPluginsWithInit,
1861
1935
  projectInit,
1862
1936
  res,
1863
- url
1937
+ url,
1938
+ timing
1864
1939
  );
1865
1940
  } else {
1866
1941
  await handleDirectRequest(
@@ -1874,18 +1949,21 @@ function mkRoute(route, vite, slowlyPhase, options, slowRenderCache, projectInit
1874
1949
  allPluginsWithInit,
1875
1950
  projectInit,
1876
1951
  res,
1877
- url
1952
+ url,
1953
+ timing
1878
1954
  );
1879
1955
  }
1880
1956
  } catch (e2) {
1881
1957
  vite?.ssrFixStacktrace(e2);
1882
- console.log(e2.stack);
1958
+ getLogger().error(e2.stack);
1883
1959
  res.status(500).end(e2.stack);
1960
+ timing?.end();
1884
1961
  }
1885
1962
  };
1886
1963
  return { path: routePath, handler, fsRoute: route };
1887
1964
  }
1888
- async function handleCachedRequest(vite, route, options, cachedEntry, pageParams, pageProps, allPluginClientInits, allPluginsWithInit, projectInit, res, url) {
1965
+ async function handleCachedRequest(vite, route, options, cachedEntry, pageParams, pageProps, allPluginClientInits, allPluginsWithInit, projectInit, res, url, timing) {
1966
+ const loadStart = Date.now();
1889
1967
  const pagePartsResult = await loadPageParts(
1890
1968
  vite,
1891
1969
  route,
@@ -1894,9 +1972,11 @@ async function handleCachedRequest(vite, route, options, cachedEntry, pageParams
1894
1972
  options.jayRollupConfig,
1895
1973
  { preRenderedPath: cachedEntry.preRenderedPath }
1896
1974
  );
1975
+ timing?.recordViteSsr(Date.now() - loadStart);
1897
1976
  if (!pagePartsResult.val) {
1898
- console.log(pagePartsResult.validations.join("\n"));
1977
+ getLogger().info(pagePartsResult.validations.join("\n"));
1899
1978
  res.status(500).end(pagePartsResult.validations.join("\n"));
1979
+ timing?.end();
1900
1980
  return;
1901
1981
  }
1902
1982
  const { parts: pageParts, clientTrackByMap, usedPackages } = pagePartsResult.val;
@@ -1905,32 +1985,56 @@ async function handleCachedRequest(vite, route, options, cachedEntry, pageParams
1905
1985
  allPluginsWithInit,
1906
1986
  usedPackages
1907
1987
  );
1988
+ const fastStart = Date.now();
1908
1989
  const renderedFast = await renderFastChangingData(
1909
1990
  pageParams,
1910
1991
  pageProps,
1911
1992
  cachedEntry.carryForward,
1912
1993
  pageParts
1913
1994
  );
1995
+ timing?.recordFastRender(Date.now() - fastStart);
1914
1996
  if (renderedFast.kind !== "PhaseOutput") {
1915
1997
  handleOtherResponseCodes(res, renderedFast);
1998
+ timing?.end();
1916
1999
  return;
1917
2000
  }
2001
+ let fastViewState = renderedFast.rendered;
2002
+ let fastCarryForward = renderedFast.carryForward;
2003
+ const instancePhaseData = cachedEntry.carryForward?.__instances;
2004
+ if (instancePhaseData && pagePartsResult.val.headlessInstanceComponents.length > 0) {
2005
+ const instanceFastResult = await renderFastChangingDataForInstances(
2006
+ instancePhaseData,
2007
+ pagePartsResult.val.headlessInstanceComponents
2008
+ );
2009
+ if (instanceFastResult) {
2010
+ fastViewState = {
2011
+ ...fastViewState,
2012
+ __headlessInstances: instanceFastResult.viewStates
2013
+ };
2014
+ fastCarryForward = {
2015
+ ...fastCarryForward,
2016
+ __headlessInstances: instanceFastResult.carryForwards
2017
+ };
2018
+ }
2019
+ }
1918
2020
  await sendResponse(
1919
2021
  vite,
1920
2022
  res,
1921
2023
  url,
1922
2024
  cachedEntry.preRenderedPath,
1923
2025
  pageParts,
1924
- renderedFast.rendered,
1925
- renderedFast.carryForward,
2026
+ fastViewState,
2027
+ fastCarryForward,
1926
2028
  clientTrackByMap,
1927
2029
  projectInit,
1928
2030
  pluginsForPage,
1929
2031
  options,
1930
- cachedEntry.slowViewState
2032
+ cachedEntry.slowViewState,
2033
+ timing
1931
2034
  );
1932
2035
  }
1933
- async function handlePreRenderRequest(vite, route, options, slowlyPhase, slowRenderCache, pageParams, pageProps, allPluginClientInits, allPluginsWithInit, projectInit, res, url) {
2036
+ async function handlePreRenderRequest(vite, route, options, slowlyPhase, slowRenderCache, pageParams, pageProps, allPluginClientInits, allPluginsWithInit, projectInit, res, url, timing) {
2037
+ const loadStart = Date.now();
1934
2038
  const initialPartsResult = await loadPageParts(
1935
2039
  vite,
1936
2040
  route,
@@ -1938,35 +2042,48 @@ async function handlePreRenderRequest(vite, route, options, slowlyPhase, slowRen
1938
2042
  options.projectRootFolder,
1939
2043
  options.jayRollupConfig
1940
2044
  );
2045
+ timing?.recordViteSsr(Date.now() - loadStart);
1941
2046
  if (!initialPartsResult.val) {
1942
- console.log(initialPartsResult.validations.join("\n"));
2047
+ getLogger().info(initialPartsResult.validations.join("\n"));
1943
2048
  res.status(500).end(initialPartsResult.validations.join("\n"));
2049
+ timing?.end();
1944
2050
  return;
1945
2051
  }
2052
+ const slowStart = Date.now();
1946
2053
  const renderedSlowly = await slowlyPhase.runSlowlyForPage(
1947
2054
  pageParams,
1948
2055
  pageProps,
1949
2056
  initialPartsResult.val.parts
1950
2057
  );
1951
2058
  if (renderedSlowly.kind !== "PhaseOutput") {
2059
+ timing?.recordSlowRender(Date.now() - slowStart);
1952
2060
  if (renderedSlowly.kind === "ClientError") {
1953
2061
  handleOtherResponseCodes(res, renderedSlowly);
1954
2062
  }
2063
+ timing?.end();
1955
2064
  return;
1956
2065
  }
1957
- const preRenderedContent = await preRenderJayHtml(route, renderedSlowly.rendered);
1958
- if (!preRenderedContent) {
2066
+ const preRenderResult = await preRenderJayHtml(
2067
+ route,
2068
+ renderedSlowly.rendered,
2069
+ initialPartsResult.val.headlessContracts,
2070
+ initialPartsResult.val.headlessInstanceComponents
2071
+ );
2072
+ timing?.recordSlowRender(Date.now() - slowStart);
2073
+ if (!preRenderResult) {
1959
2074
  res.status(500).end("Failed to pre-render jay-html");
2075
+ timing?.end();
1960
2076
  return;
1961
2077
  }
2078
+ const carryForward = preRenderResult.instancePhaseData ? { ...renderedSlowly.carryForward, __instances: preRenderResult.instancePhaseData } : renderedSlowly.carryForward;
1962
2079
  const preRenderedPath = await slowRenderCache.set(
1963
2080
  route.jayHtmlPath,
1964
2081
  pageParams,
1965
- preRenderedContent,
2082
+ preRenderResult.preRenderedJayHtml,
1966
2083
  renderedSlowly.rendered,
1967
- renderedSlowly.carryForward
2084
+ carryForward
1968
2085
  );
1969
- console.log(`[SlowRender] Cached pre-rendered jay-html at ${preRenderedPath}`);
2086
+ getLogger().info(`[SlowRender] Cached pre-rendered jay-html at ${preRenderedPath}`);
1970
2087
  const pagePartsResult = await loadPageParts(
1971
2088
  vite,
1972
2089
  route,
@@ -1976,8 +2093,9 @@ async function handlePreRenderRequest(vite, route, options, slowlyPhase, slowRen
1976
2093
  { preRenderedPath }
1977
2094
  );
1978
2095
  if (!pagePartsResult.val) {
1979
- console.log(pagePartsResult.validations.join("\n"));
2096
+ getLogger().info(pagePartsResult.validations.join("\n"));
1980
2097
  res.status(500).end(pagePartsResult.validations.join("\n"));
2098
+ timing?.end();
1981
2099
  return;
1982
2100
  }
1983
2101
  const { parts: pageParts, clientTrackByMap, usedPackages } = pagePartsResult.val;
@@ -1986,32 +2104,56 @@ async function handlePreRenderRequest(vite, route, options, slowlyPhase, slowRen
1986
2104
  allPluginsWithInit,
1987
2105
  usedPackages
1988
2106
  );
2107
+ const fastStart = Date.now();
1989
2108
  const renderedFast = await renderFastChangingData(
1990
2109
  pageParams,
1991
2110
  pageProps,
1992
- renderedSlowly.carryForward,
2111
+ carryForward,
1993
2112
  pageParts
1994
2113
  );
2114
+ timing?.recordFastRender(Date.now() - fastStart);
1995
2115
  if (renderedFast.kind !== "PhaseOutput") {
1996
2116
  handleOtherResponseCodes(res, renderedFast);
2117
+ timing?.end();
1997
2118
  return;
1998
2119
  }
2120
+ let fastViewState = renderedFast.rendered;
2121
+ let fastCarryForward = renderedFast.carryForward;
2122
+ const instancePhaseData = carryForward?.__instances;
2123
+ if (instancePhaseData && pagePartsResult.val.headlessInstanceComponents.length > 0) {
2124
+ const instanceFastResult = await renderFastChangingDataForInstances(
2125
+ instancePhaseData,
2126
+ pagePartsResult.val.headlessInstanceComponents
2127
+ );
2128
+ if (instanceFastResult) {
2129
+ fastViewState = {
2130
+ ...fastViewState,
2131
+ __headlessInstances: instanceFastResult.viewStates
2132
+ };
2133
+ fastCarryForward = {
2134
+ ...fastCarryForward,
2135
+ __headlessInstances: instanceFastResult.carryForwards
2136
+ };
2137
+ }
2138
+ }
1999
2139
  await sendResponse(
2000
2140
  vite,
2001
2141
  res,
2002
2142
  url,
2003
2143
  preRenderedPath,
2004
2144
  pageParts,
2005
- renderedFast.rendered,
2006
- renderedFast.carryForward,
2145
+ fastViewState,
2146
+ fastCarryForward,
2007
2147
  clientTrackByMap,
2008
2148
  projectInit,
2009
2149
  pluginsForPage,
2010
2150
  options,
2011
- renderedSlowly.rendered
2151
+ renderedSlowly.rendered,
2152
+ timing
2012
2153
  );
2013
2154
  }
2014
- async function handleDirectRequest(vite, route, options, slowlyPhase, pageParams, pageProps, allPluginClientInits, allPluginsWithInit, projectInit, res, url) {
2155
+ async function handleDirectRequest(vite, route, options, slowlyPhase, pageParams, pageProps, allPluginClientInits, allPluginsWithInit, projectInit, res, url, timing) {
2156
+ const loadStart = Date.now();
2015
2157
  const pagePartsResult = await loadPageParts(
2016
2158
  vite,
2017
2159
  route,
@@ -2019,9 +2161,11 @@ async function handleDirectRequest(vite, route, options, slowlyPhase, pageParams
2019
2161
  options.projectRootFolder,
2020
2162
  options.jayRollupConfig
2021
2163
  );
2164
+ timing?.recordViteSsr(Date.now() - loadStart);
2022
2165
  if (!pagePartsResult.val) {
2023
- console.log(pagePartsResult.validations.join("\n"));
2166
+ getLogger().info(pagePartsResult.validations.join("\n"));
2024
2167
  res.status(500).end(pagePartsResult.validations.join("\n"));
2168
+ timing?.end();
2025
2169
  return;
2026
2170
  }
2027
2171
  const {
@@ -2035,21 +2179,59 @@ async function handleDirectRequest(vite, route, options, slowlyPhase, pageParams
2035
2179
  allPluginsWithInit,
2036
2180
  usedPackages
2037
2181
  );
2182
+ const slowStart = Date.now();
2038
2183
  const renderedSlowly = await slowlyPhase.runSlowlyForPage(pageParams, pageProps, pageParts);
2039
2184
  if (renderedSlowly.kind !== "PhaseOutput") {
2185
+ timing?.recordSlowRender(Date.now() - slowStart);
2040
2186
  if (renderedSlowly.kind === "ClientError") {
2041
2187
  handleOtherResponseCodes(res, renderedSlowly);
2042
2188
  }
2189
+ timing?.end();
2043
2190
  return;
2044
2191
  }
2192
+ let instanceViewStates;
2193
+ let instancePhaseDataForFast;
2194
+ const headlessInstanceComponents = pagePartsResult.val.headlessInstanceComponents ?? [];
2195
+ if (headlessInstanceComponents.length > 0) {
2196
+ const jayHtmlContent = await fs$1.readFile(route.jayHtmlPath, "utf-8");
2197
+ const discoveryResult = discoverHeadlessInstances(jayHtmlContent);
2198
+ if (discoveryResult.instances.length > 0) {
2199
+ const slowResult = await slowRenderInstances(
2200
+ discoveryResult.instances,
2201
+ headlessInstanceComponents
2202
+ );
2203
+ if (slowResult) {
2204
+ instanceViewStates = { ...slowResult.slowViewStates };
2205
+ instancePhaseDataForFast = slowResult.instancePhaseData;
2206
+ }
2207
+ }
2208
+ }
2209
+ timing?.recordSlowRender(Date.now() - slowStart);
2210
+ const fastStart = Date.now();
2045
2211
  const renderedFast = await renderFastChangingData(
2046
2212
  pageParams,
2047
2213
  pageProps,
2048
2214
  renderedSlowly.carryForward,
2049
2215
  pageParts
2050
2216
  );
2217
+ if (instancePhaseDataForFast && instanceViewStates) {
2218
+ const instanceFastResult = await renderFastChangingDataForInstances(
2219
+ instancePhaseDataForFast,
2220
+ headlessInstanceComponents
2221
+ );
2222
+ if (instanceFastResult) {
2223
+ for (const [coordKey, fastVS] of Object.entries(instanceFastResult.viewStates)) {
2224
+ instanceViewStates[coordKey] = {
2225
+ ...instanceViewStates[coordKey] || {},
2226
+ ...fastVS
2227
+ };
2228
+ }
2229
+ }
2230
+ }
2231
+ timing?.recordFastRender(Date.now() - fastStart);
2051
2232
  if (renderedFast.kind !== "PhaseOutput") {
2052
2233
  handleOtherResponseCodes(res, renderedFast);
2234
+ timing?.end();
2053
2235
  return;
2054
2236
  }
2055
2237
  let viewState;
@@ -2062,6 +2244,12 @@ async function handleDirectRequest(vite, route, options, slowlyPhase, pageParams
2062
2244
  } else {
2063
2245
  viewState = { ...renderedSlowly.rendered, ...renderedFast.rendered };
2064
2246
  }
2247
+ if (instanceViewStates && Object.keys(instanceViewStates).length > 0) {
2248
+ viewState = {
2249
+ ...viewState,
2250
+ __headlessInstances: instanceViewStates
2251
+ };
2252
+ }
2065
2253
  await sendResponse(
2066
2254
  vite,
2067
2255
  res,
@@ -2073,10 +2261,12 @@ async function handleDirectRequest(vite, route, options, slowlyPhase, pageParams
2073
2261
  clientTrackByMap,
2074
2262
  projectInit,
2075
2263
  pluginsForPage,
2076
- options
2264
+ options,
2265
+ void 0,
2266
+ timing
2077
2267
  );
2078
2268
  }
2079
- async function sendResponse(vite, res, url, jayHtmlPath, pageParts, viewState, carryForward, clientTrackByMap, projectInit, pluginsForPage, options, slowViewState) {
2269
+ async function sendResponse(vite, res, url, jayHtmlPath, pageParts, viewState, carryForward, clientTrackByMap, projectInit, pluginsForPage, options, slowViewState, timing) {
2080
2270
  const pageHtml = generateClientScript(
2081
2271
  viewState,
2082
2272
  carryForward,
@@ -2091,10 +2281,19 @@ async function sendResponse(vite, res, url, jayHtmlPath, pageParts, viewState, c
2091
2281
  slowViewState
2092
2282
  }
2093
2283
  );
2284
+ if (options.buildFolder) {
2285
+ const pageName = !url || url === "/" ? "index" : url.replace(/^\//, "").replace(/\//g, "-");
2286
+ const clientScriptDir = path__default.join(options.buildFolder, "client-scripts");
2287
+ await fs$1.mkdir(clientScriptDir, { recursive: true });
2288
+ await fs$1.writeFile(path__default.join(clientScriptDir, `${pageName}.html`), pageHtml, "utf-8");
2289
+ }
2290
+ const viteStart = Date.now();
2094
2291
  const compiledPageHtml = await vite.transformIndexHtml(!!url ? url : "/", pageHtml);
2292
+ timing?.recordViteClient(Date.now() - viteStart);
2095
2293
  res.status(200).set({ "Content-Type": "text/html" }).send(compiledPageHtml);
2294
+ timing?.end();
2096
2295
  }
2097
- async function preRenderJayHtml(route, slowViewState) {
2296
+ async function preRenderJayHtml(route, slowViewState, headlessContracts, headlessInstanceComponents) {
2098
2297
  const jayHtmlContent = await fs$1.readFile(route.jayHtmlPath, "utf-8");
2099
2298
  const contractPath = route.jayHtmlPath.replace(".jay-html", ".jay-contract");
2100
2299
  let contract;
@@ -2104,15 +2303,14 @@ async function preRenderJayHtml(route, slowViewState) {
2104
2303
  if (parseResult.val) {
2105
2304
  contract = parseResult.val;
2106
2305
  } else if (parseResult.validations.length > 0) {
2107
- console.error(
2108
- `[SlowRender] Contract parse error for ${contractPath}:`,
2109
- parseResult.validations
2306
+ getLogger().error(
2307
+ `[SlowRender] Contract parse error for ${contractPath}: ${parseResult.validations.join(", ")}`
2110
2308
  );
2111
2309
  return void 0;
2112
2310
  }
2113
2311
  } catch (error) {
2114
2312
  if (error.code !== "ENOENT") {
2115
- console.error(`[SlowRender] Error reading contract ${contractPath}:`, error);
2313
+ getLogger().error(`[SlowRender] Error reading contract ${contractPath}: ${error}`);
2116
2314
  return void 0;
2117
2315
  }
2118
2316
  }
@@ -2120,20 +2318,99 @@ async function preRenderJayHtml(route, slowViewState) {
2120
2318
  jayHtmlContent,
2121
2319
  slowViewState,
2122
2320
  contract,
2123
- sourceDir: path__default.dirname(route.jayHtmlPath)
2321
+ headlessContracts,
2322
+ sourceDir: path__default.dirname(route.jayHtmlPath),
2323
+ importResolver: JAY_IMPORT_RESOLVER
2124
2324
  });
2125
- if (result.val) {
2126
- return result.val.preRenderedJayHtml;
2325
+ if (!result.val) {
2326
+ if (result.validations.length > 0) {
2327
+ getLogger().error(
2328
+ `[SlowRender] Transform failed for ${route.jayHtmlPath}: ${result.validations.join(", ")}`
2329
+ );
2330
+ }
2331
+ return void 0;
2332
+ }
2333
+ let preRenderedJayHtml = result.val.preRenderedJayHtml;
2334
+ let instancePhaseData;
2335
+ if (headlessInstanceComponents.length > 0) {
2336
+ const discoveryResult = discoverHeadlessInstances(preRenderedJayHtml);
2337
+ preRenderedJayHtml = discoveryResult.preRenderedJayHtml;
2338
+ if (discoveryResult.instances.length > 0) {
2339
+ const slowResult = await slowRenderInstances(
2340
+ discoveryResult.instances,
2341
+ headlessInstanceComponents
2342
+ );
2343
+ if (slowResult) {
2344
+ instancePhaseData = slowResult.instancePhaseData;
2345
+ const pass2Result = resolveHeadlessInstances(
2346
+ preRenderedJayHtml,
2347
+ slowResult.resolvedData,
2348
+ JAY_IMPORT_RESOLVER
2349
+ );
2350
+ if (pass2Result.val) {
2351
+ preRenderedJayHtml = pass2Result.val;
2352
+ }
2353
+ if (pass2Result.validations.length > 0) {
2354
+ getLogger().error(
2355
+ `[SlowRender] Instance resolution warnings for ${route.jayHtmlPath}: ${pass2Result.validations.join(", ")}`
2356
+ );
2357
+ }
2358
+ }
2359
+ }
2127
2360
  }
2128
- if (result.validations.length > 0) {
2129
- console.error(
2130
- `[SlowRender] Transform failed for ${route.jayHtmlPath}:`,
2131
- result.validations
2361
+ return { preRenderedJayHtml, instancePhaseData };
2362
+ }
2363
+ async function renderFastChangingDataForInstances(instancePhaseData, headlessInstanceComponents) {
2364
+ const componentByContractName = /* @__PURE__ */ new Map();
2365
+ for (const comp of headlessInstanceComponents) {
2366
+ componentByContractName.set(comp.contractName, comp);
2367
+ }
2368
+ const viewStates = {};
2369
+ const carryForwards = {};
2370
+ let hasResults = false;
2371
+ for (const instance of instancePhaseData.discovered) {
2372
+ const coordKey = instance.coordinate.join("/");
2373
+ const comp = componentByContractName.get(instance.contractName);
2374
+ if (!comp || !comp.compDefinition.fastRender) {
2375
+ continue;
2376
+ }
2377
+ const instanceCarryForward = instancePhaseData.carryForwards[coordKey] || {};
2378
+ const services = resolveServices(comp.compDefinition.services);
2379
+ const fastResult = await comp.compDefinition.fastRender(
2380
+ instance.props,
2381
+ instanceCarryForward,
2382
+ ...services
2132
2383
  );
2384
+ if (fastResult.kind === "PhaseOutput") {
2385
+ viewStates[coordKey] = fastResult.rendered;
2386
+ carryForwards[coordKey] = fastResult.carryForward;
2387
+ hasResults = true;
2388
+ }
2389
+ }
2390
+ return hasResults ? { viewStates, carryForwards } : void 0;
2391
+ }
2392
+ async function materializeDynamicContracts(projectRootFolder, buildFolder, viteServer) {
2393
+ try {
2394
+ const services = getServiceRegistry();
2395
+ const result = await materializeContracts(
2396
+ {
2397
+ projectRoot: projectRootFolder,
2398
+ outputDir: path__default.join(buildFolder, "materialized-contracts"),
2399
+ verbose: false,
2400
+ viteServer
2401
+ },
2402
+ services
2403
+ );
2404
+ const dynamicCount = result.dynamicCount;
2405
+ if (dynamicCount > 0) {
2406
+ getLogger().info(`[Contracts] Materialized ${dynamicCount} dynamic contract(s)`);
2407
+ }
2408
+ } catch (error) {
2409
+ getLogger().warn(`[Contracts] Failed to materialize dynamic contracts: ${error.message}`);
2133
2410
  }
2134
- return void 0;
2135
2411
  }
2136
- async function mkDevServer(options) {
2412
+ async function mkDevServer(rawOptions) {
2413
+ const options = defaults(rawOptions);
2137
2414
  const {
2138
2415
  publicBaseUrlPath,
2139
2416
  pagesRootFolder,
@@ -2141,23 +2418,20 @@ async function mkDevServer(options) {
2141
2418
  buildFolder,
2142
2419
  jayRollupConfig,
2143
2420
  dontCacheSlowly
2144
- } = defaults(options);
2421
+ } = options;
2422
+ const viteLogLevel = options.logLevel === "silent" ? "silent" : options.logLevel === "verbose" ? "info" : "warn";
2145
2423
  const lifecycleManager = new ServiceLifecycleManager(projectRootFolder);
2146
2424
  setupGracefulShutdown(lifecycleManager);
2147
- const vite = await createServer({
2148
- server: { middlewareMode: true },
2149
- plugins: [...jayStackCompiler(jayRollupConfig)],
2150
- appType: "custom",
2425
+ const vite = await createViteServer({
2426
+ projectRoot: projectRootFolder,
2427
+ pagesRoot: pagesRootFolder,
2151
2428
  base: publicBaseUrlPath,
2152
- root: pagesRootFolder,
2153
- ssr: {
2154
- // Mark stack-server-runtime as external so Vite uses Node's require
2155
- // This ensures lib/init.ts and dev-server share the same module instance
2156
- external: ["@jay-framework/stack-server-runtime"]
2157
- }
2429
+ jayRollupConfig,
2430
+ logLevel: viteLogLevel
2158
2431
  });
2159
2432
  lifecycleManager.setViteServer(vite);
2160
2433
  await lifecycleManager.initialize();
2434
+ await materializeDynamicContracts(projectRootFolder, buildFolder, vite);
2161
2435
  setupServiceHotReload(vite, lifecycleManager);
2162
2436
  setupActionRouter(vite);
2163
2437
  const routes = await initRoutes(pagesRootFolder);
@@ -2189,7 +2463,7 @@ async function mkDevServer(options) {
2189
2463
  }
2190
2464
  function setupGracefulShutdown(lifecycleManager) {
2191
2465
  const shutdown = async (signal) => {
2192
- console.log(`
2466
+ getLogger().important(`
2193
2467
  ${signal} received, shutting down gracefully...`);
2194
2468
  await lifecycleManager.shutdown();
2195
2469
  process.exit(0);
@@ -2205,7 +2479,7 @@ function setupServiceHotReload(vite, lifecycleManager) {
2205
2479
  vite.watcher.add(initFilePath);
2206
2480
  vite.watcher.on("change", async (changedPath) => {
2207
2481
  if (changedPath === initFilePath) {
2208
- console.log("[Services] lib/init.ts changed, reloading services...");
2482
+ getLogger().info("[Services] lib/init.ts changed, reloading services...");
2209
2483
  try {
2210
2484
  await lifecycleManager.reload();
2211
2485
  vite.ws.send({
@@ -2213,7 +2487,7 @@ function setupServiceHotReload(vite, lifecycleManager) {
2213
2487
  path: "*"
2214
2488
  });
2215
2489
  } catch (error) {
2216
- console.error("[Services] Failed to reload services:", error);
2490
+ getLogger().error(`[Services] Failed to reload services: ${error}`);
2217
2491
  }
2218
2492
  }
2219
2493
  });
@@ -2221,7 +2495,7 @@ function setupServiceHotReload(vite, lifecycleManager) {
2221
2495
  function setupActionRouter(vite) {
2222
2496
  vite.middlewares.use(actionBodyParser());
2223
2497
  vite.middlewares.use(ACTION_ENDPOINT_BASE, createActionRouter());
2224
- console.log(`[Actions] Action router mounted at ${ACTION_ENDPOINT_BASE}`);
2498
+ getLogger().info(`[Actions] Action router mounted at ${ACTION_ENDPOINT_BASE}`);
2225
2499
  }
2226
2500
  function setupSlowRenderCacheInvalidation(vite, cache, pagesRootFolder) {
2227
2501
  vite.watcher.on("change", (changedPath) => {
@@ -2230,7 +2504,7 @@ function setupSlowRenderCacheInvalidation(vite, cache, pagesRootFolder) {
2230
2504
  }
2231
2505
  if (changedPath.endsWith(".jay-html")) {
2232
2506
  cache.invalidate(changedPath).then(() => {
2233
- console.log(`[SlowRender] Cache invalidated for ${changedPath}`);
2507
+ getLogger().info(`[SlowRender] Cache invalidated for ${changedPath}`);
2234
2508
  });
2235
2509
  return;
2236
2510
  }
@@ -2238,14 +2512,18 @@ function setupSlowRenderCacheInvalidation(vite, cache, pagesRootFolder) {
2238
2512
  const dir = path__default.dirname(changedPath);
2239
2513
  const jayHtmlPath = path__default.join(dir, "page.jay-html");
2240
2514
  cache.invalidate(jayHtmlPath).then(() => {
2241
- console.log(`[SlowRender] Cache invalidated for ${jayHtmlPath} (page.ts changed)`);
2515
+ getLogger().info(
2516
+ `[SlowRender] Cache invalidated for ${jayHtmlPath} (page.ts changed)`
2517
+ );
2242
2518
  });
2243
2519
  return;
2244
2520
  }
2245
2521
  if (changedPath.endsWith(".jay-contract")) {
2246
2522
  const jayHtmlPath = changedPath.replace(".jay-contract", ".jay-html");
2247
2523
  cache.invalidate(jayHtmlPath).then(() => {
2248
- console.log(`[SlowRender] Cache invalidated for ${jayHtmlPath} (contract changed)`);
2524
+ getLogger().info(
2525
+ `[SlowRender] Cache invalidated for ${jayHtmlPath} (contract changed)`
2526
+ );
2249
2527
  });
2250
2528
  return;
2251
2529
  }
@@ -2255,5 +2533,7 @@ export {
2255
2533
  ACTION_ENDPOINT_BASE,
2256
2534
  actionBodyParser,
2257
2535
  createActionRouter,
2536
+ createViteForCli,
2537
+ createViteServer,
2258
2538
  mkDevServer
2259
2539
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/dev-server",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",
@@ -22,21 +22,22 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@jay-framework/compiler-jay-stack": "^0.11.0",
26
- "@jay-framework/compiler-shared": "^0.11.0",
27
- "@jay-framework/component": "^0.11.0",
28
- "@jay-framework/fullstack-component": "^0.11.0",
29
- "@jay-framework/runtime": "^0.11.0",
30
- "@jay-framework/stack-client-runtime": "^0.11.0",
31
- "@jay-framework/stack-route-scanner": "^0.11.0",
32
- "@jay-framework/stack-server-runtime": "^0.11.0",
33
- "@jay-framework/view-state-merge": "^0.11.0",
25
+ "@jay-framework/compiler-jay-stack": "^0.12.0",
26
+ "@jay-framework/compiler-shared": "^0.12.0",
27
+ "@jay-framework/component": "^0.12.0",
28
+ "@jay-framework/fullstack-component": "^0.12.0",
29
+ "@jay-framework/logger": "^0.12.0",
30
+ "@jay-framework/runtime": "^0.12.0",
31
+ "@jay-framework/stack-client-runtime": "^0.12.0",
32
+ "@jay-framework/stack-route-scanner": "^0.12.0",
33
+ "@jay-framework/stack-server-runtime": "^0.12.0",
34
+ "@jay-framework/view-state-merge": "^0.12.0",
34
35
  "vite": "^5.0.11"
35
36
  },
36
37
  "devDependencies": {
37
- "@jay-framework/dev-environment": "^0.11.0",
38
- "@jay-framework/jay-cli": "^0.11.0",
39
- "@jay-framework/stack-client-runtime": "^0.11.0",
38
+ "@jay-framework/dev-environment": "^0.12.0",
39
+ "@jay-framework/jay-cli": "^0.12.0",
40
+ "@jay-framework/stack-client-runtime": "^0.12.0",
40
41
  "@types/express": "^5.0.2",
41
42
  "@types/node": "^22.15.21",
42
43
  "nodemon": "^3.0.3",