@jay-framework/stack-server-runtime 0.15.2 → 0.15.4

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
@@ -539,6 +539,15 @@ interface PluginClientInitInfo {
539
539
  */
540
540
  declare function preparePluginClientInits(plugins: PluginWithInit[]): PluginClientInitInfo[];
541
541
 
542
+ /**
543
+ * Generate JS code to reconstruct Promise.resolve()/Promise.reject() for async ViewState properties.
544
+ * JSON.stringify drops Promise objects, so this emits assignments that recreate them from tracked outcomes.
545
+ */
546
+ declare function generatePromiseReconstruction(outcomes: Array<{
547
+ id: string;
548
+ status: 'resolved' | 'rejected';
549
+ value: any;
550
+ }>): string;
542
551
  /**
543
552
  * Information needed to generate client init script for the project.
544
553
  */
@@ -583,7 +592,21 @@ declare function buildScriptFragments(parts: DevServerPagePart[], clientInitData
583
592
  * @param mode - 'client' appends to DOM; 'hydrate' skips appendChild (DOM already present)
584
593
  */
585
594
  declare function buildAutomationWrap(options: GenerateClientScriptOptions, mode: 'client' | 'hydrate'): string;
586
- declare function generateClientScript(defaultViewState: object, fastCarryForward: object, parts: DevServerPagePart[], jayHtmlPath: string, trackByMap?: TrackByMap, clientInitData?: Record<string, Record<string, any>>, projectInit?: ProjectClientInitInfo, pluginInits?: PluginClientInitInfo[], options?: GenerateClientScriptOptions): string;
595
+ /**
596
+ * Resolve all top-level Promise values in a ViewState object.
597
+ * Returns the ViewState with Promises replaced by their resolved values,
598
+ * plus a list of outcomes for reconstructing Promise.resolve()/Promise.reject()
599
+ * in the client script.
600
+ */
601
+ declare function resolveViewStatePromises(viewState: object): Promise<{
602
+ resolved: object;
603
+ outcomes: Array<{
604
+ id: string;
605
+ status: 'resolved' | 'rejected';
606
+ value: any;
607
+ }>;
608
+ }>;
609
+ declare function generateClientScript(defaultViewState: object, fastCarryForward: object, parts: DevServerPagePart[], jayHtmlPath: string, trackByMap?: TrackByMap, clientInitData?: Record<string, Record<string, any>>, projectInit?: ProjectClientInitInfo, pluginInits?: PluginClientInitInfo[], options?: GenerateClientScriptOptions): Promise<string>;
587
610
 
588
611
  /**
589
612
  * Invalidate the cached server element module for a jay-html file.
@@ -896,7 +919,6 @@ interface PluginsIndexEntry {
896
919
  actions?: ActionIndexEntry[];
897
920
  }
898
921
  interface PluginsIndex {
899
- jay_stack_version: string;
900
922
  plugins: PluginsIndexEntry[];
901
923
  }
902
924
  interface MaterializeContractsOptions {
@@ -1128,4 +1150,4 @@ declare function executePluginReferences(plugin: PluginWithReferences, options:
1128
1150
  verbose?: boolean;
1129
1151
  }): Promise<PluginReferencesResult>;
1130
1152
 
1131
- export { type ActionDiscoveryOptions, type ActionDiscoveryResult, type ActionErrorResponse, type ActionExecutionResult, type ActionIndexEntry, type ActionMetadata, ActionRegistry, type ActionSchema, type DevServerPagePart, DevSlowlyChangingPhase, type GenerateClientScriptOptions, type HeadlessInstanceComponent, type InstancePhaseData, type InstanceSlowRenderResult, type LoadedPageParts, type MaterializeContractsOptions, type MaterializeResult, type PluginActionDiscoveryOptions, type PluginClientInitInfo, type PluginContractEntry, type PluginInitDiscoveryOptions, type PluginReferencesContext, type PluginReferencesHandler, type PluginReferencesResult, type PluginScanOptions, type PluginSetupContext, type PluginSetupHandler, type PluginSetupResult, type PluginWithInit, type PluginWithReferences, type PluginWithSetup, type PluginsIndex, type PluginsIndexEntry, type ProjectClientInitInfo, type RegisteredAction, type ScannedPlugin, type ScriptFragments, SlowRenderCache, type SlowRenderCacheEntry, type SlowlyChangingPhase, type ViteSSRLoader, actionRegistry, buildAutomationWrap, buildScriptFragments, clearActionRegistry, clearClientInitData, clearLifecycleCallbacks, clearServerElementCache, clearServiceRegistry, discoverAllPluginActions, discoverAndRegisterActions, discoverPluginActions, discoverPluginsWithInit, discoverPluginsWithReferences, discoverPluginsWithSetup, executeAction, executePluginReferences, executePluginServerInits, executePluginSetup, generateClientScript, generateSSRPageHtml, getActionCacheHeaders, getClientInitData, getClientInitDataForKey, getRegisteredAction, getRegisteredActionNames, getService, getServiceRegistry, hasAction, hasService, invalidateServerElementCache, listContracts, loadActionMetadata, loadPageParts, materializeContracts, onInit, onShutdown, parseActionMetadata, preparePluginClientInits, registerAction, registerService, renderFastChangingData, resolveActionMetadataPath, resolveServices, runInitCallbacks, runLoadParams, runShutdownCallbacks, runSlowlyChangingRender, scanPlugins, setClientInitData, slowRenderInstances, sortPluginsByDependencies, validateForEachInstances };
1153
+ export { type ActionDiscoveryOptions, type ActionDiscoveryResult, type ActionErrorResponse, type ActionExecutionResult, type ActionIndexEntry, type ActionMetadata, ActionRegistry, type ActionSchema, type DevServerPagePart, DevSlowlyChangingPhase, type GenerateClientScriptOptions, type HeadlessInstanceComponent, type InstancePhaseData, type InstanceSlowRenderResult, type LoadedPageParts, type MaterializeContractsOptions, type MaterializeResult, type PluginActionDiscoveryOptions, type PluginClientInitInfo, type PluginContractEntry, type PluginInitDiscoveryOptions, type PluginReferencesContext, type PluginReferencesHandler, type PluginReferencesResult, type PluginScanOptions, type PluginSetupContext, type PluginSetupHandler, type PluginSetupResult, type PluginWithInit, type PluginWithReferences, type PluginWithSetup, type PluginsIndex, type PluginsIndexEntry, type ProjectClientInitInfo, type RegisteredAction, type ScannedPlugin, type ScriptFragments, SlowRenderCache, type SlowRenderCacheEntry, type SlowlyChangingPhase, type ViteSSRLoader, actionRegistry, buildAutomationWrap, buildScriptFragments, clearActionRegistry, clearClientInitData, clearLifecycleCallbacks, clearServerElementCache, clearServiceRegistry, discoverAllPluginActions, discoverAndRegisterActions, discoverPluginActions, discoverPluginsWithInit, discoverPluginsWithReferences, discoverPluginsWithSetup, executeAction, executePluginReferences, executePluginServerInits, executePluginSetup, generateClientScript, generatePromiseReconstruction, generateSSRPageHtml, getActionCacheHeaders, getClientInitData, getClientInitDataForKey, getRegisteredAction, getRegisteredActionNames, getService, getServiceRegistry, hasAction, hasService, invalidateServerElementCache, listContracts, loadActionMetadata, loadPageParts, materializeContracts, onInit, onShutdown, parseActionMetadata, preparePluginClientInits, registerAction, registerService, renderFastChangingData, resolveActionMetadataPath, resolveServices, resolveViewStatePromises, runInitCallbacks, runLoadParams, runShutdownCallbacks, runSlowlyChangingRender, scanPlugins, setClientInitData, slowRenderInstances, sortPluginsByDependencies, validateForEachInstances };
package/dist/index.js CHANGED
@@ -483,6 +483,18 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
483
483
  }
484
484
  return Promise.resolve(phaseOutput(fastViewState, fastCarryForward));
485
485
  }
486
+ function generatePromiseReconstruction(outcomes) {
487
+ if (outcomes.length === 0)
488
+ return "";
489
+ return outcomes.map((outcome) => {
490
+ if (outcome.status === "resolved") {
491
+ return ` viewState[${JSON.stringify(outcome.id)}] = Promise.resolve(${JSON.stringify(outcome.value)});`;
492
+ } else {
493
+ const errMsg = outcome.value?.message ?? "Unknown error";
494
+ return ` viewState[${JSON.stringify(outcome.id)}] = Promise.reject(new Error(${JSON.stringify(errMsg)}));`;
495
+ }
496
+ }).join("\n") + "\n";
497
+ }
486
498
  function buildScriptFragments(parts, clientInitData2, projectInit, pluginInits, options) {
487
499
  const { enableAutomation = true, slowViewState } = options;
488
500
  const hasSlowViewState = slowViewState && Object.keys(slowViewState).length > 0;
@@ -558,7 +570,34 @@ function buildAutomationWrap(options, mode) {
558
570
  window.__jay.automation = wrapped.automation;
559
571
  window.dispatchEvent(new Event('jay:automation-ready'));${appendLine}`;
560
572
  }
561
- function generateClientScript(defaultViewState, fastCarryForward, parts, jayHtmlPath, trackByMap = {}, clientInitData2 = {}, projectInit, pluginInits = [], options = {}) {
573
+ async function resolveViewStatePromises(viewState) {
574
+ const entries = Object.entries(viewState);
575
+ const hasPromises = entries.some(([, v]) => v instanceof Promise);
576
+ if (!hasPromises)
577
+ return { resolved: viewState, outcomes: [] };
578
+ const result = { ...viewState };
579
+ const outcomes = [];
580
+ for (const [key, value] of entries) {
581
+ if (value instanceof Promise) {
582
+ try {
583
+ const val = await value;
584
+ result[key] = val;
585
+ outcomes.push({ id: key, status: "resolved", value: val });
586
+ } catch (err) {
587
+ delete result[key];
588
+ outcomes.push({
589
+ id: key,
590
+ status: "rejected",
591
+ value: { message: err?.message ?? String(err) }
592
+ });
593
+ }
594
+ }
595
+ }
596
+ return { resolved: result, outcomes };
597
+ }
598
+ async function generateClientScript(defaultViewState, fastCarryForward, parts, jayHtmlPath, trackByMap = {}, clientInitData2 = {}, projectInit, pluginInits = [], options = {}) {
599
+ const { resolved, outcomes } = await resolveViewStatePromises(defaultViewState);
600
+ defaultViewState = resolved;
562
601
  const {
563
602
  partImports,
564
603
  compositeParts,
@@ -586,7 +625,7 @@ function generateClientScript(defaultViewState, fastCarryForward, parts, jayHtml
586
625
  import { render } from '${jayHtmlPath}';
587
626
  ${partImports}${slowViewStateDecl}
588
627
  const viewState = ${JSON.stringify(defaultViewState)};
589
- const fastCarryForward = ${JSON.stringify(fastCarryForward)};
628
+ ${generatePromiseReconstruction(outcomes)} const fastCarryForward = ${JSON.stringify(fastCarryForward)};
590
629
  const trackByMap = ${JSON.stringify(trackByMap)};
591
630
  ${clientInitExecution}
592
631
  const target = document.getElementById('target');
@@ -598,6 +637,10 @@ ${automationWrap}
598
637
  </body>
599
638
  </html>`;
600
639
  }
640
+ function asyncSwapScript(id, html) {
641
+ const escapedHtml = html.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
642
+ return `<script>(function(){var t=document.querySelector('[jay-async="${id}:pending"]');if(t){var d=document.createElement('div');d.innerHTML='${escapedHtml}';t.replaceWith(d.firstChild);}window.__jay&&window.__jay.hydrateAsync&&window.__jay.hydrateAsync('${id}');})()<\/script>`;
643
+ }
601
644
  const serverModuleCache = /* @__PURE__ */ new Map();
602
645
  function invalidateServerElementCache(jayHtmlPath) {
603
646
  if (serverModuleCache.delete(jayHtmlPath)) {
@@ -625,6 +668,7 @@ async function generateSSRPageHtml(vite, jayHtmlContent, jayHtmlFilename, jayHtm
625
668
  }
626
669
  const htmlChunks = [];
627
670
  const asyncPromises = [];
671
+ const asyncOutcomes = [];
628
672
  const ctx = {
629
673
  write: (chunk) => {
630
674
  htmlChunks.push(chunk);
@@ -632,14 +676,20 @@ async function generateSSRPageHtml(vite, jayHtmlContent, jayHtmlFilename, jayHtm
632
676
  onAsync: (promise, id, templates) => {
633
677
  const asyncPromise = promise.then(
634
678
  (val) => {
679
+ asyncOutcomes.push({ id, status: "resolved", value: val });
635
680
  if (templates.resolved) {
636
- return templates.resolved(val);
681
+ return asyncSwapScript(id, templates.resolved(val));
637
682
  }
638
683
  return "";
639
684
  },
640
685
  (err) => {
686
+ asyncOutcomes.push({
687
+ id,
688
+ status: "rejected",
689
+ value: { message: err?.message ?? String(err) }
690
+ });
641
691
  if (templates.rejected) {
642
- return templates.rejected(err);
692
+ return asyncSwapScript(id, templates.rejected(err));
643
693
  }
644
694
  return "";
645
695
  }
@@ -660,7 +710,8 @@ async function generateSSRPageHtml(vite, jayHtmlContent, jayHtmlFilename, jayHtm
660
710
  clientInitData2,
661
711
  projectInit,
662
712
  pluginInits,
663
- options
713
+ options,
714
+ asyncOutcomes
664
715
  );
665
716
  const headLinksHtml = cached.headLinks.map((link) => {
666
717
  const attrs = Object.entries(link.attributes).map(([k, v]) => ` ${k}="${v}"`).join("");
@@ -722,6 +773,10 @@ async function compileAndLoadServerElement(vite, jayHtmlContent, jayHtmlFilename
722
773
  const serverElementFilename = jayHtmlFilename.replace(".jay-html", ".server-element.ts");
723
774
  const serverElementPath = path__default.join(serverElementDir, serverElementFilename);
724
775
  await fs$2.writeFile(serverElementPath, adjustedCode, "utf-8");
776
+ const existingModule = vite.moduleGraph.getModuleById(serverElementPath);
777
+ if (existingModule) {
778
+ vite.moduleGraph.invalidateModule(existingModule);
779
+ }
725
780
  const serverModule = await vite.ssrLoadModule(serverElementPath);
726
781
  return {
727
782
  renderToStream: serverModule.renderToStream,
@@ -729,7 +784,7 @@ async function compileAndLoadServerElement(vite, jayHtmlContent, jayHtmlFilename
729
784
  css: parsedJayFile.css
730
785
  };
731
786
  }
732
- function generateHydrationScript(defaultViewState, fastCarryForward, parts, jayHtmlPath, trackByMap = {}, clientInitData2 = {}, projectInit, pluginInits = [], options = {}) {
787
+ function generateHydrationScript(defaultViewState, fastCarryForward, parts, jayHtmlPath, trackByMap = {}, clientInitData2 = {}, projectInit, pluginInits = [], options = {}, asyncOutcomes = []) {
733
788
  const {
734
789
  partImports,
735
790
  compositeParts,
@@ -749,7 +804,7 @@ function generateHydrationScript(defaultViewState, fastCarryForward, parts, jayH
749
804
  import { hydrate } from '${hydrateImportPath}';
750
805
  ${partImports}${slowViewStateDecl}
751
806
  const viewState = ${JSON.stringify(defaultViewState)};
752
- const fastCarryForward = ${JSON.stringify(fastCarryForward)};
807
+ ${generatePromiseReconstruction(asyncOutcomes)} const fastCarryForward = ${JSON.stringify(fastCarryForward)};
753
808
  const trackByMap = ${JSON.stringify(trackByMap)};
754
809
 
755
810
  const target = document.getElementById('target');
@@ -2042,15 +2097,6 @@ function resolveActionFilePath(actionPath, packageName, pluginPath, isLocal, pro
2042
2097
  function toKebabCase(str) {
2043
2098
  return str.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
2044
2099
  }
2045
- function getJayStackVersion() {
2046
- try {
2047
- const packageJsonPath = path.join(__dirname, "..", "package.json");
2048
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
2049
- return packageJson.version || "0.0.0";
2050
- } catch {
2051
- return "0.0.0";
2052
- }
2053
- }
2054
2100
  async function materializeContracts(options, services = /* @__PURE__ */ new Map()) {
2055
2101
  const {
2056
2102
  projectRoot,
@@ -2183,7 +2229,6 @@ async function materializeContracts(options, services = /* @__PURE__ */ new Map(
2183
2229
  }
2184
2230
  }
2185
2231
  const pluginsIndex = {
2186
- jay_stack_version: getJayStackVersion(),
2187
2232
  plugins: Array.from(pluginsIndexMap.entries()).map(([name, data]) => ({
2188
2233
  name,
2189
2234
  path: data.path,
@@ -2251,7 +2296,6 @@ async function listContracts(options) {
2251
2296
  }
2252
2297
  }
2253
2298
  return {
2254
- jay_stack_version: getJayStackVersion(),
2255
2299
  plugins: Array.from(pluginsMap.entries()).map(([name, data]) => ({
2256
2300
  name,
2257
2301
  path: data.path,
@@ -2409,6 +2453,7 @@ export {
2409
2453
  executePluginServerInits,
2410
2454
  executePluginSetup,
2411
2455
  generateClientScript,
2456
+ generatePromiseReconstruction,
2412
2457
  generateSSRPageHtml,
2413
2458
  getActionCacheHeaders,
2414
2459
  getClientInitData,
@@ -2433,6 +2478,7 @@ export {
2433
2478
  renderFastChangingData,
2434
2479
  resolveActionMetadataPath,
2435
2480
  resolveServices,
2481
+ resolveViewStatePromises,
2436
2482
  runInitCallbacks,
2437
2483
  runLoadParams,
2438
2484
  runShutdownCallbacks,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/stack-server-runtime",
3
- "version": "0.15.2",
3
+ "version": "0.15.4",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.mts",
@@ -26,21 +26,21 @@
26
26
  "test:watch": "vitest"
27
27
  },
28
28
  "dependencies": {
29
- "@jay-framework/compiler-jay-html": "^0.15.2",
30
- "@jay-framework/compiler-shared": "^0.15.2",
31
- "@jay-framework/component": "^0.15.2",
32
- "@jay-framework/fullstack-component": "^0.15.2",
33
- "@jay-framework/logger": "^0.15.2",
34
- "@jay-framework/runtime": "^0.15.2",
35
- "@jay-framework/ssr-runtime": "^0.15.2",
36
- "@jay-framework/stack-route-scanner": "^0.15.2",
37
- "@jay-framework/view-state-merge": "^0.15.2",
29
+ "@jay-framework/compiler-jay-html": "^0.15.4",
30
+ "@jay-framework/compiler-shared": "^0.15.4",
31
+ "@jay-framework/component": "^0.15.4",
32
+ "@jay-framework/fullstack-component": "^0.15.4",
33
+ "@jay-framework/logger": "^0.15.4",
34
+ "@jay-framework/runtime": "^0.15.4",
35
+ "@jay-framework/ssr-runtime": "^0.15.4",
36
+ "@jay-framework/stack-route-scanner": "^0.15.4",
37
+ "@jay-framework/view-state-merge": "^0.15.4",
38
38
  "yaml": "^2.3.4"
39
39
  },
40
40
  "devDependencies": {
41
- "@jay-framework/dev-environment": "^0.15.2",
42
- "@jay-framework/jay-cli": "^0.15.2",
43
- "@jay-framework/stack-client-runtime": "^0.15.2",
41
+ "@jay-framework/dev-environment": "^0.15.4",
42
+ "@jay-framework/jay-cli": "^0.15.4",
43
+ "@jay-framework/stack-client-runtime": "^0.15.4",
44
44
  "@types/express": "^5.0.2",
45
45
  "@types/node": "^22.15.21",
46
46
  "nodemon": "^3.0.3",