@jay-framework/stack-server-build 0.24.2 → 0.24.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -124,6 +124,8 @@ interface ScriptFragments {
124
124
  * Build the shared script fragments used by both client and hydration scripts.
125
125
  */
126
126
  declare function buildScriptFragments(parts: DevServerPagePart[], clientInitData: Record<string, Record<string, any>>, projectInit: ProjectClientInitInfo | undefined, pluginInits: PluginClientInitInfo[], options: GenerateClientScriptOptions): ScriptFragments;
127
+ /** Dev-only: subscribe to jay:page-reload and reload when route prefix matches. */
128
+ declare function buildPageReloadHmrScript(): string;
127
129
  /**
128
130
  * Generate the automation wrapping code.
129
131
  * @param mode - 'client' appends to DOM; 'hydrate' skips appendChild (DOM already present)
@@ -172,17 +174,23 @@ headTags?: HeadTag[],
172
174
  /** Script tags with jay-script="allow" (DL#149) */
173
175
  scripts?: JayHtmlScript[]): Promise<string>;
174
176
  /**
175
- * Generate a frozen page — pure SSR HTML with no client scripts (DL#127).
177
+ * Generate a frozen page — pure SSR HTML (DL#127).
176
178
  *
177
179
  * Uses the same server element module as generateSSRPageHtml, but:
178
180
  * - No hydration script
179
- * - No Vite client
180
181
  * - No component runtime
181
182
  * - Just rendered HTML + CSS
182
183
  *
184
+ * Script policy:
185
+ * - Production / `format=fragment`: no client scripts
186
+ * - Dev full-page (`injectDevHmr: true`): minimal reload listener only — no hydration,
187
+ * automation, or freeze capture. Caller must run the result through `transformIndexHtml`.
188
+ *
183
189
  * @param format - 'page' for full HTML document, 'fragment' for body-only (shadow DOM)
184
190
  */
185
- declare function generateFrozenPageHtml(vite: ViteDevServer, jayHtmlContent: string, jayHtmlFilename: string, jayHtmlDir: string, viewState: object, buildFolder: string, projectRoot: string, routeDir: string, tsConfigFilePath?: string, sourceDir?: string, format?: 'page' | 'fragment', freezeName?: string): Promise<string>;
191
+ declare function generateFrozenPageHtml(vite: ViteDevServer, jayHtmlContent: string, jayHtmlFilename: string, jayHtmlDir: string, viewState: object, buildFolder: string, projectRoot: string, routeDir: string, tsConfigFilePath?: string, sourceDir?: string, format?: 'page' | 'fragment', freezeName?: string, options?: {
192
+ injectDevHmr?: boolean;
193
+ }): Promise<string>;
186
194
 
187
195
  /**
188
196
  * Action metadata loaded from .jay-action files.
@@ -661,4 +669,4 @@ declare class SlowRenderCache {
661
669
  private scanAndDeleteCacheFiles;
662
670
  }
663
671
 
664
- export { type ActionDiscoveryOptions, type ActionDiscoveryResult, type ActionIndexEntry, type ActionMetadata, type ActionSchema, type CommandFlag, type CommandIndexEntry, type CommandMetadata, type ContextIndexEntry, type DevServerPagePart, type DiscoveredCommand, type GenerateClientScriptOptions, type HeadlessInstanceComponent, type LoadPagePartsOptions, type LoadedPageParts, type MaterializeContractsOptions, type MaterializeResult, type PluginActionDiscoveryOptions, type PluginContractEntry, type PluginWithAgentKit, type PluginWithSetup, type PluginsIndex, type PluginsIndexEntry, type ProjectClientInitInfo, type RouteIndexEntry, type ScriptFragments, type ServiceIndexEntry, SetupNeedsAnswerError, SlowRenderCache, type SlowRenderCacheEntry, type ViteSSRLoader, buildAutomationWrap, buildScriptFragments, clearServerElementCache, commandSchemaToFlags, discoverAllPluginActions, discoverAndRegisterActions, discoverPluginActions, discoverPluginCommands, discoverPluginsWithAgentKit, discoverPluginsWithSetup, executePluginAgentKit, executePluginCommand, executePluginSetup, generateClientScript, generateFrozenPageHtml, generatePromiseReconstruction, generateSSRPageHtml, headMetaToHeadTags, invalidateServerElementCache, listContracts, loadActionMetadata, loadPageParts, materializeContracts, parseActionMetadata, parseInputFromFlags, resolveActionMetadataPath, resolveViewStatePromises };
672
+ export { type ActionDiscoveryOptions, type ActionDiscoveryResult, type ActionIndexEntry, type ActionMetadata, type ActionSchema, type CommandFlag, type CommandIndexEntry, type CommandMetadata, type ContextIndexEntry, type DevServerPagePart, type DiscoveredCommand, type GenerateClientScriptOptions, type HeadlessInstanceComponent, type LoadPagePartsOptions, type LoadedPageParts, type MaterializeContractsOptions, type MaterializeResult, type PluginActionDiscoveryOptions, type PluginContractEntry, type PluginWithAgentKit, type PluginWithSetup, type PluginsIndex, type PluginsIndexEntry, type ProjectClientInitInfo, type RouteIndexEntry, type ScriptFragments, type ServiceIndexEntry, SetupNeedsAnswerError, SlowRenderCache, type SlowRenderCacheEntry, type ViteSSRLoader, buildAutomationWrap, buildPageReloadHmrScript, buildScriptFragments, clearServerElementCache, commandSchemaToFlags, discoverAllPluginActions, discoverAndRegisterActions, discoverPluginActions, discoverPluginCommands, discoverPluginsWithAgentKit, discoverPluginsWithSetup, executePluginAgentKit, executePluginCommand, executePluginSetup, generateClientScript, generateFrozenPageHtml, generatePromiseReconstruction, generateSSRPageHtml, headMetaToHeadTags, invalidateServerElementCache, listContracts, loadActionMetadata, loadPageParts, materializeContracts, parseActionMetadata, parseInputFromFlags, resolveActionMetadataPath, resolveViewStatePromises };
package/dist/index.js CHANGED
@@ -315,7 +315,7 @@ function normalizeActionEntry(entry) {
315
315
  if (typeof entry === "string") {
316
316
  return { name: entry };
317
317
  }
318
- return { name: entry.name, action: entry.action };
318
+ return { name: entry.name, action: entry.action, devOnly: entry.devOnly };
319
319
  }
320
320
  function loadPluginManifest(pluginDir) {
321
321
  const pluginYamlPath = path$1.join(pluginDir, "plugin.yaml");
@@ -397,6 +397,18 @@ ${clientParts.map((part) => " " + part.clientPart).join(",\n")}
397
397
  slowViewStateDecl
398
398
  };
399
399
  }
400
+ function buildPageReloadHmrScript() {
401
+ return `
402
+ if (import.meta.hot) {
403
+ import.meta.hot.on('jay:page-reload', (data) => {
404
+ const prefix = data.routePrefix;
405
+ const pathname = window.location.pathname;
406
+ if (pathname === prefix || pathname.startsWith(prefix + '/')) {
407
+ window.location.reload();
408
+ }
409
+ });
410
+ }`;
411
+ }
400
412
  function buildFreezeScript(routePattern) {
401
413
  const routePatternLiteral = routePattern ? `'${routePattern}'` : "undefined";
402
414
  return `
@@ -472,15 +484,7 @@ function buildFreezeScript(routePattern) {
472
484
  }
473
485
 
474
486
  // Targeted page reload: only reload if this page matches the changed route prefix
475
- if (import.meta.hot) {
476
- import.meta.hot.on('jay:page-reload', (data) => {
477
- const prefix = data.routePrefix;
478
- const pathname = window.location.pathname;
479
- if (pathname === prefix || pathname.startsWith(prefix + '/')) {
480
- window.location.reload();
481
- }
482
- });
483
- }`;
487
+ ${buildPageReloadHmrScript()}`;
484
488
  }
485
489
  function buildAutomationWrap(options, mode) {
486
490
  const { enableAutomation = true, slowViewState } = options;
@@ -719,7 +723,7 @@ ${titleTag}${headExtras ? headExtras + "\n" : ""} </head>
719
723
  </body>
720
724
  </html>`;
721
725
  }
722
- async function generateFrozenPageHtml(vite, jayHtmlContent, jayHtmlFilename, jayHtmlDir, viewState, buildFolder, projectRoot, routeDir, tsConfigFilePath, sourceDir, format = "page", freezeName) {
726
+ async function generateFrozenPageHtml(vite, jayHtmlContent, jayHtmlFilename, jayHtmlDir, viewState, buildFolder, projectRoot, routeDir, tsConfigFilePath, sourceDir, format = "page", freezeName, options) {
723
727
  const jayHtmlPath = path__default.join(jayHtmlDir, jayHtmlFilename);
724
728
  let cached = serverModuleCache.get(jayHtmlPath);
725
729
  if (!cached) {
@@ -765,6 +769,9 @@ ${ssrHtml}`;
765
769
  const cssLink = cached.cssHref ? ` <link rel="stylesheet" href="${cached.cssHref}" />` : "";
766
770
  const headExtras = [cssLink, frozenHeadTagsHtml].filter((_) => _).join("\n");
767
771
  const label = freezeName ? ` — ${freezeName}` : "";
772
+ const devHmrScript = options?.injectDevHmr === true ? `
773
+ <script type="module">${buildPageReloadHmrScript()}
774
+ <\/script>` : "";
768
775
  return `<!doctype html>
769
776
  <html lang="en">
770
777
  <head>
@@ -788,7 +795,7 @@ ${headExtras ? headExtras + "\n" : ""} <style>
788
795
  </style>
789
796
  </head>
790
797
  <body>
791
- <div id="target">${ssrHtml}</div>
798
+ <div id="target">${ssrHtml}</div>${devHmrScript}
792
799
  </body>
793
800
  </html>`;
794
801
  }
@@ -1169,9 +1176,18 @@ async function registerNpmPluginActions(packageName, pluginConfig, pluginDir, re
1169
1176
  } else {
1170
1177
  pluginModule = await import(packageName);
1171
1178
  }
1179
+ let toolsModule;
1180
+ const loadToolsModule = async () => {
1181
+ if (!toolsModule) {
1182
+ const toolsEntry = `${packageName}/tools`;
1183
+ toolsModule = viteServer ? await viteServer.ssrLoadModule(toolsEntry) : await import(toolsEntry);
1184
+ }
1185
+ return toolsModule;
1186
+ };
1172
1187
  for (const entry of pluginConfig.actions) {
1173
- const { name: actionName, action: actionPath } = normalizeActionEntry(entry);
1174
- const actionExport = pluginModule[actionName];
1188
+ const { name: actionName, action: actionPath, devOnly } = normalizeActionEntry(entry);
1189
+ const sourceModule = devOnly ? await loadToolsModule() : pluginModule;
1190
+ const actionExport = sourceModule[actionName];
1175
1191
  if (actionExport && isJayAction(actionExport)) {
1176
1192
  registry.register(actionExport);
1177
1193
  const registeredName = actionExport.actionName;
@@ -1243,6 +1259,13 @@ async function discoverPluginActions(pluginPath, projectRoot, registry = actionR
1243
1259
  return [];
1244
1260
  }
1245
1261
  }
1262
+ const resolveLocalToolsModulePath = () => {
1263
+ for (const candidate of ["tools.ts", "tools.js"]) {
1264
+ const candidatePath = path.join(pluginPath, candidate);
1265
+ if (fs.existsSync(candidatePath)) return candidatePath;
1266
+ }
1267
+ return null;
1268
+ };
1246
1269
  try {
1247
1270
  let pluginModule;
1248
1271
  if (viteServer) {
@@ -1250,9 +1273,23 @@ async function discoverPluginActions(pluginPath, projectRoot, registry = actionR
1250
1273
  } else {
1251
1274
  pluginModule = await import(modulePath);
1252
1275
  }
1276
+ let toolsModule;
1277
+ const loadToolsModule = async () => {
1278
+ if (toolsModule) return toolsModule;
1279
+ const toolsPath = resolveLocalToolsModulePath();
1280
+ if (!toolsPath) {
1281
+ getLogger().warn(
1282
+ `[Actions] Plugin "${pluginName}" declares a devOnly action but has no tools.ts/tools.js module`
1283
+ );
1284
+ return void 0;
1285
+ }
1286
+ toolsModule = viteServer ? await viteServer.ssrLoadModule(toolsPath) : await import(toolsPath);
1287
+ return toolsModule;
1288
+ };
1253
1289
  for (const entry of pluginConfig.actions) {
1254
- const { name: actionName, action: actionPath } = normalizeActionEntry(entry);
1255
- const actionExport = pluginModule[actionName];
1290
+ const { name: actionName, action: actionPath, devOnly } = normalizeActionEntry(entry);
1291
+ const sourceModule = devOnly ? await loadToolsModule() : pluginModule;
1292
+ const actionExport = sourceModule?.[actionName];
1256
1293
  if (actionExport && isJayAction(actionExport)) {
1257
1294
  registry.register(actionExport);
1258
1295
  const registeredName = actionExport.actionName;
@@ -1878,10 +1915,11 @@ async function loadCommandHandler(command, viteServer) {
1878
1915
  module = await import(modulePath);
1879
1916
  }
1880
1917
  } else {
1918
+ const toolsEntry = `${command.packageName}/tools`;
1881
1919
  if (viteServer) {
1882
- module = await viteServer.ssrLoadModule(command.packageName);
1920
+ module = await viteServer.ssrLoadModule(toolsEntry);
1883
1921
  } else {
1884
- module = await import(command.packageName);
1922
+ module = await import(toolsEntry);
1885
1923
  }
1886
1924
  }
1887
1925
  for (const [, exported] of Object.entries(module)) {
@@ -2015,14 +2053,15 @@ async function loadHandler(plugin, handlerName, viteServer) {
2015
2053
  `Handler "${handlerName}" not found in "${plugin.pluginPath}". Available exports: ${Object.keys(module).join(", ")}`
2016
2054
  );
2017
2055
  } else {
2056
+ const toolsEntry = `${plugin.packageName}/tools`;
2018
2057
  if (viteServer) {
2019
- module = await viteServer.ssrLoadModule(plugin.packageName);
2058
+ module = await viteServer.ssrLoadModule(toolsEntry);
2020
2059
  } else {
2021
- module = await import(plugin.packageName);
2060
+ module = await import(toolsEntry);
2022
2061
  }
2023
2062
  if (typeof module[handlerName] !== "function") {
2024
2063
  throw new Error(
2025
- `Handler "${handlerName}" not found as export in "${plugin.packageName}". Available exports: ${Object.keys(module).join(", ")}`
2064
+ `Handler "${handlerName}" not found as export in "${toolsEntry}". Available exports: ${Object.keys(module).join(", ")}`
2026
2065
  );
2027
2066
  }
2028
2067
  return module[handlerName];
@@ -2264,6 +2303,7 @@ export {
2264
2303
  SetupNeedsAnswerError,
2265
2304
  SlowRenderCache,
2266
2305
  buildAutomationWrap,
2306
+ buildPageReloadHmrScript,
2267
2307
  buildScriptFragments,
2268
2308
  clearServerElementCache,
2269
2309
  commandSchemaToFlags,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/stack-server-build",
3
- "version": "0.24.2",
3
+ "version": "0.24.3",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.mts",
@@ -24,21 +24,21 @@
24
24
  "test:watch": "vitest"
25
25
  },
26
26
  "dependencies": {
27
- "@jay-framework/compiler-jay-html": "^0.24.2",
28
- "@jay-framework/compiler-shared": "^0.24.2",
29
- "@jay-framework/component": "^0.24.2",
30
- "@jay-framework/fullstack-component": "^0.24.2",
31
- "@jay-framework/logger": "^0.24.2",
32
- "@jay-framework/runtime": "^0.24.2",
33
- "@jay-framework/ssr-runtime": "^0.24.2",
34
- "@jay-framework/stack-route-scanner": "^0.24.2",
35
- "@jay-framework/stack-server-runtime": "^0.24.2",
36
- "@jay-framework/view-state-merge": "^0.24.2",
27
+ "@jay-framework/compiler-jay-html": "^0.24.3",
28
+ "@jay-framework/compiler-shared": "^0.24.3",
29
+ "@jay-framework/component": "^0.24.3",
30
+ "@jay-framework/fullstack-component": "^0.24.3",
31
+ "@jay-framework/logger": "^0.24.3",
32
+ "@jay-framework/runtime": "^0.24.3",
33
+ "@jay-framework/ssr-runtime": "^0.24.3",
34
+ "@jay-framework/stack-route-scanner": "^0.24.3",
35
+ "@jay-framework/stack-server-runtime": "^0.24.3",
36
+ "@jay-framework/view-state-merge": "^0.24.3",
37
37
  "yaml": "^2.3.4"
38
38
  },
39
39
  "devDependencies": {
40
- "@jay-framework/dev-environment": "^0.24.2",
41
- "@jay-framework/rollup-plugin": "^0.24.2",
40
+ "@jay-framework/dev-environment": "^0.24.3",
41
+ "@jay-framework/rollup-plugin": "^0.24.3",
42
42
  "@types/node": "^22.15.21",
43
43
  "rimraf": "^5.0.5",
44
44
  "tsup": "^8.0.1",