@jay-framework/stack-server-runtime 0.15.5 → 0.15.6
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 +55 -3
- package/dist/index.js +282 -49
- package/package.json +13 -13
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnyJayStackComponentDefinition, PageProps, AnySlowlyRenderResult, UrlParams, JayStackComponentDefinition, AnyFastRenderResult, HttpMethod, CacheOptions, JayAction, JayActionDefinition, ServiceMarker } from '@jay-framework/fullstack-component';
|
|
1
|
+
import { AnyJayStackComponentDefinition, PageProps, AnySlowlyRenderResult, UrlParams, JayStackComponentDefinition, AnyFastRenderResult, HttpMethod, CacheOptions, JayAction, JayActionDefinition, HeadTag, ServiceMarker } from '@jay-framework/fullstack-component';
|
|
2
2
|
import { JayComponentCore } from '@jay-framework/component';
|
|
3
3
|
import { ViteDevServer } from 'vite';
|
|
4
4
|
import { JayRoute } from '@jay-framework/stack-route-scanner';
|
|
@@ -49,6 +49,10 @@ interface LoadedPageParts {
|
|
|
49
49
|
discoveredInstances: DiscoveredHeadlessInstance[];
|
|
50
50
|
/** Discovered forEach <jay:xxx> instances from the jay-html (DL#109) */
|
|
51
51
|
forEachInstances: ForEachHeadlessInstance[];
|
|
52
|
+
/** Absolute paths to linked CSS files (from <link rel="stylesheet">) for dev-server watching */
|
|
53
|
+
linkedCssFiles: string[];
|
|
54
|
+
/** Absolute paths to headfull FS component jay-html files for dev-server watching */
|
|
55
|
+
linkedComponentFiles: string[];
|
|
52
56
|
}
|
|
53
57
|
interface LoadPagePartsOptions {
|
|
54
58
|
/**
|
|
@@ -97,6 +101,8 @@ interface InstancePhaseData {
|
|
|
97
101
|
}>;
|
|
98
102
|
/** CarryForward per instance (keyed by coordinate path, e.g. "p1/product-card:0") */
|
|
99
103
|
carryForwards: Record<string, object>;
|
|
104
|
+
/** Slow ViewState per instance (keyed by coordinate path) */
|
|
105
|
+
slowViewStates?: Record<string, object>;
|
|
100
106
|
/** ForEach instances that need fast-phase per-item rendering */
|
|
101
107
|
forEachInstances?: ForEachHeadlessInstance[];
|
|
102
108
|
}
|
|
@@ -626,7 +632,11 @@ declare function clearServerElementCache(): void;
|
|
|
626
632
|
* 3. Build hydration script (uses ?jay-hydrate query for hydrate target)
|
|
627
633
|
* 4. Return full HTML page string
|
|
628
634
|
*/
|
|
629
|
-
declare function generateSSRPageHtml(vite: ViteDevServer, jayHtmlContent: string, jayHtmlFilename: string, jayHtmlDir: string, viewState: object, jayHtmlImportPath: string, parts: DevServerPagePart[], carryForward: object, trackByMap: TrackByMap, clientInitData: Record<string, Record<string, any>>, buildFolder: string, projectRoot: string, routeDir: string, tsConfigFilePath?: string, projectInit?: ProjectClientInitInfo, pluginInits?: PluginClientInitInfo[], options?: GenerateClientScriptOptions
|
|
635
|
+
declare function generateSSRPageHtml(vite: ViteDevServer, jayHtmlContent: string, jayHtmlFilename: string, jayHtmlDir: string, viewState: object, jayHtmlImportPath: string, parts: DevServerPagePart[], carryForward: object, trackByMap: TrackByMap, clientInitData: Record<string, Record<string, any>>, buildFolder: string, projectRoot: string, routeDir: string, tsConfigFilePath?: string, projectInit?: ProjectClientInitInfo, pluginInits?: PluginClientInitInfo[], options?: GenerateClientScriptOptions,
|
|
636
|
+
/** Source directory for headfull FS file resolution when jayHtmlDir is pre-rendered */
|
|
637
|
+
sourceDir?: string,
|
|
638
|
+
/** Head tags to inject into <head> during SSR (Design Log #127) */
|
|
639
|
+
headTags?: HeadTag[]): Promise<string>;
|
|
630
640
|
|
|
631
641
|
/**
|
|
632
642
|
* Service registry for Jay Stack server-side dependency injection.
|
|
@@ -906,10 +916,25 @@ interface ActionIndexEntry {
|
|
|
906
916
|
/** Contract entry within a plugin in plugins-index.yaml */
|
|
907
917
|
interface PluginContractEntry {
|
|
908
918
|
name: string;
|
|
919
|
+
description?: string;
|
|
909
920
|
type: 'static' | 'dynamic';
|
|
910
921
|
path: string;
|
|
911
922
|
metadata?: Record<string, unknown>;
|
|
912
923
|
}
|
|
924
|
+
/** Service entry in plugins-index.yaml (DL#125) */
|
|
925
|
+
interface ServiceIndexEntry {
|
|
926
|
+
name: string;
|
|
927
|
+
marker: string;
|
|
928
|
+
description?: string;
|
|
929
|
+
doc?: string;
|
|
930
|
+
}
|
|
931
|
+
/** Context entry in plugins-index.yaml (DL#125) */
|
|
932
|
+
interface ContextIndexEntry {
|
|
933
|
+
name: string;
|
|
934
|
+
marker: string;
|
|
935
|
+
description?: string;
|
|
936
|
+
doc?: string;
|
|
937
|
+
}
|
|
913
938
|
/** Entry for plugins-index.yaml (Design Log #85) */
|
|
914
939
|
interface PluginsIndexEntry {
|
|
915
940
|
name: string;
|
|
@@ -917,6 +942,10 @@ interface PluginsIndexEntry {
|
|
|
917
942
|
contracts: PluginContractEntry[];
|
|
918
943
|
/** Actions with .jay-action metadata (exposed to AI agents) */
|
|
919
944
|
actions?: ActionIndexEntry[];
|
|
945
|
+
/** Server-side services provided by this plugin (DL#125) */
|
|
946
|
+
services?: ServiceIndexEntry[];
|
|
947
|
+
/** Client-side contexts provided by this plugin (DL#125) */
|
|
948
|
+
contexts?: ContextIndexEntry[];
|
|
920
949
|
}
|
|
921
950
|
interface PluginsIndex {
|
|
922
951
|
plugins: PluginsIndexEntry[];
|
|
@@ -1150,4 +1179,27 @@ declare function executePluginReferences(plugin: PluginWithReferences, options:
|
|
|
1150
1179
|
verbose?: boolean;
|
|
1151
1180
|
}): Promise<PluginReferencesResult>;
|
|
1152
1181
|
|
|
1153
|
-
|
|
1182
|
+
/**
|
|
1183
|
+
* Head tag utilities for SSR head injection (Design Log #127).
|
|
1184
|
+
*
|
|
1185
|
+
* Components declare HeadTag[] via phaseOutput(). The SSR pipeline collects
|
|
1186
|
+
* tags from all sources, deduplicates with last-write-wins + collision warning,
|
|
1187
|
+
* and serializes to HTML for injection into <head>.
|
|
1188
|
+
*/
|
|
1189
|
+
|
|
1190
|
+
/**
|
|
1191
|
+
* Compute a unique identity key for deduplication.
|
|
1192
|
+
* Returns undefined for tags that should always be included (no dedup).
|
|
1193
|
+
*/
|
|
1194
|
+
declare function tagIdentityKey(tag: HeadTag): string | undefined;
|
|
1195
|
+
/**
|
|
1196
|
+
* Merge head tags from multiple sources with last-write-wins.
|
|
1197
|
+
* Warns on collision via logger.
|
|
1198
|
+
*/
|
|
1199
|
+
declare function mergeHeadTags(sources: HeadTag[][]): HeadTag[];
|
|
1200
|
+
/**
|
|
1201
|
+
* Serialize an array of HeadTag objects into an HTML string.
|
|
1202
|
+
*/
|
|
1203
|
+
declare function serializeHeadTags(tags: HeadTag[]): string;
|
|
1204
|
+
|
|
1205
|
+
export { type ActionDiscoveryOptions, type ActionDiscoveryResult, type ActionErrorResponse, type ActionExecutionResult, type ActionIndexEntry, type ActionMetadata, ActionRegistry, type ActionSchema, type ContextIndexEntry, 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, type ServiceIndexEntry, 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, mergeHeadTags, onInit, onShutdown, parseActionMetadata, preparePluginClientInits, registerAction, registerService, renderFastChangingData, resolveActionMetadataPath, resolveServices, resolveViewStatePromises, runInitCallbacks, runLoadParams, runShutdownCallbacks, runSlowlyChangingRender, scanPlugins, serializeHeadTags, setClientInitData, slowRenderInstances, sortPluginsByDependencies, tagIdentityKey, validateForEachInstances };
|
package/dist/index.js
CHANGED
|
@@ -11,12 +11,12 @@ import fs$1 from "fs";
|
|
|
11
11
|
import path$1 from "path";
|
|
12
12
|
import YAML from "yaml";
|
|
13
13
|
import { createRequire } from "module";
|
|
14
|
-
import { parseJayFile, JAY_IMPORT_RESOLVER, generateServerElementFile, discoverHeadlessInstances, parseAction } from "@jay-framework/compiler-jay-html";
|
|
14
|
+
import { parseJayFile, JAY_IMPORT_RESOLVER, generateServerElementFile, injectHeadfullFSTemplates, discoverHeadlessInstances, assignCoordinatesToJayHtml, parseAction } from "@jay-framework/compiler-jay-html";
|
|
15
|
+
import { getLogger } from "@jay-framework/logger";
|
|
15
16
|
import fs$2 from "node:fs/promises";
|
|
16
17
|
import * as path from "node:path";
|
|
17
18
|
import path__default from "node:path";
|
|
18
19
|
import crypto from "node:crypto";
|
|
19
|
-
import { getLogger } from "@jay-framework/logger";
|
|
20
20
|
import * as fs from "node:fs";
|
|
21
21
|
import { createRequire as createRequire$1 } from "node:module";
|
|
22
22
|
const serviceRegistry = /* @__PURE__ */ new Map();
|
|
@@ -87,6 +87,7 @@ class DevSlowlyChangingPhase {
|
|
|
87
87
|
async runSlowlyForPage(pageParams, pageProps, parts, discoveredInstances, headlessInstanceComponents, jayHtmlPath) {
|
|
88
88
|
let slowlyViewState = {};
|
|
89
89
|
let carryForward = {};
|
|
90
|
+
const slowHeadTagSources = [];
|
|
90
91
|
for (const part of parts) {
|
|
91
92
|
const { compDefinition, key, contractInfo } = part;
|
|
92
93
|
if (compDefinition.slowlyRender) {
|
|
@@ -111,6 +112,9 @@ class DevSlowlyChangingPhase {
|
|
|
111
112
|
slowlyViewState[key] = slowlyRenderedPart.rendered;
|
|
112
113
|
carryForward[key] = slowlyRenderedPart.carryForward;
|
|
113
114
|
}
|
|
115
|
+
if (slowlyRenderedPart.headTags) {
|
|
116
|
+
slowHeadTagSources.push(slowlyRenderedPart.headTags);
|
|
117
|
+
}
|
|
114
118
|
} else
|
|
115
119
|
return slowlyRenderedPart;
|
|
116
120
|
}
|
|
@@ -158,6 +162,9 @@ class DevSlowlyChangingPhase {
|
|
|
158
162
|
contract: comp.contract,
|
|
159
163
|
slowViewState: slowResult.rendered
|
|
160
164
|
});
|
|
165
|
+
if (slowResult.headTags) {
|
|
166
|
+
slowHeadTagSources.push(slowResult.headTags);
|
|
167
|
+
}
|
|
161
168
|
}
|
|
162
169
|
}
|
|
163
170
|
}
|
|
@@ -165,6 +172,9 @@ class DevSlowlyChangingPhase {
|
|
|
165
172
|
carryForward.__instanceSlowViewStates = instanceSlowViewStates;
|
|
166
173
|
carryForward.__instanceResolvedData = instanceResolvedData;
|
|
167
174
|
}
|
|
175
|
+
if (slowHeadTagSources.length > 0) {
|
|
176
|
+
carryForward.__slowHeadTags = slowHeadTagSources;
|
|
177
|
+
}
|
|
168
178
|
return phaseOutput(slowlyViewState, carryForward);
|
|
169
179
|
}
|
|
170
180
|
}
|
|
@@ -378,6 +388,7 @@ function resolveBinding(binding, item) {
|
|
|
378
388
|
async function renderFastChangingData(pageParams, pageProps, carryForward, parts, instancePhaseData, forEachInstances, headlessInstanceComponents, mergedSlowViewState, query = {}) {
|
|
379
389
|
let fastViewState = {};
|
|
380
390
|
let fastCarryForward = {};
|
|
391
|
+
const fastHeadTagSources = [];
|
|
381
392
|
for (const part of parts) {
|
|
382
393
|
const { compDefinition, key, contractInfo } = part;
|
|
383
394
|
if (compDefinition.fastRender) {
|
|
@@ -405,6 +416,9 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
|
|
|
405
416
|
fastViewState[key] = fastRenderedPart.rendered;
|
|
406
417
|
fastCarryForward[key] = fastRenderedPart.carryForward;
|
|
407
418
|
}
|
|
419
|
+
if (fastRenderedPart.headTags) {
|
|
420
|
+
fastHeadTagSources.push(fastRenderedPart.headTags);
|
|
421
|
+
}
|
|
408
422
|
} else
|
|
409
423
|
return fastRenderedPart;
|
|
410
424
|
}
|
|
@@ -419,18 +433,25 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
|
|
|
419
433
|
for (const instance of instancePhaseData.discovered) {
|
|
420
434
|
const coordKey = instance.coordinate.join("/");
|
|
421
435
|
const comp = componentByContractName.get(instance.contractName);
|
|
422
|
-
if (!comp
|
|
436
|
+
if (!comp)
|
|
423
437
|
continue;
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
438
|
+
const instanceSlowVS = instancePhaseData.slowViewStates?.[coordKey] ?? carryForward?.__instanceSlowViewStates?.[coordKey];
|
|
439
|
+
if (comp.compDefinition.fastRender) {
|
|
440
|
+
const services = resolveServices(comp.compDefinition.services);
|
|
441
|
+
const cf = instancePhaseData.carryForwards[coordKey];
|
|
442
|
+
const instanceProps = { ...instance.props, query };
|
|
443
|
+
const fastResult = comp.compDefinition.slowlyRender ? await comp.compDefinition.fastRender(instanceProps, cf, ...services) : await comp.compDefinition.fastRender(instanceProps, ...services);
|
|
444
|
+
if (fastResult.kind === "PhaseOutput") {
|
|
445
|
+
instanceViewStates[coordKey] = instanceSlowVS ? { ...instanceSlowVS, ...fastResult.rendered } : fastResult.rendered;
|
|
446
|
+
if (fastResult.carryForward) {
|
|
447
|
+
instanceCarryForwards[coordKey] = fastResult.carryForward;
|
|
448
|
+
}
|
|
449
|
+
if (fastResult.headTags) {
|
|
450
|
+
fastHeadTagSources.push(fastResult.headTags);
|
|
451
|
+
}
|
|
433
452
|
}
|
|
453
|
+
} else {
|
|
454
|
+
instanceViewStates[coordKey] = instanceSlowVS ?? {};
|
|
434
455
|
}
|
|
435
456
|
}
|
|
436
457
|
}
|
|
@@ -491,7 +512,11 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
|
|
|
491
512
|
if (Object.keys(instanceCarryForwards).length > 0) {
|
|
492
513
|
fastCarryForward.__headlessInstances = instanceCarryForwards;
|
|
493
514
|
}
|
|
494
|
-
|
|
515
|
+
const result = phaseOutput(fastViewState, fastCarryForward);
|
|
516
|
+
if (fastHeadTagSources.length > 0) {
|
|
517
|
+
result.headTags = fastHeadTagSources.flat();
|
|
518
|
+
}
|
|
519
|
+
return Promise.resolve(result);
|
|
495
520
|
}
|
|
496
521
|
function generatePromiseReconstruction(outcomes) {
|
|
497
522
|
if (outcomes.length === 0)
|
|
@@ -635,7 +660,8 @@ async function generateClientScript(defaultViewState, fastCarryForward, parts, j
|
|
|
635
660
|
import { render } from '${jayHtmlPath}';
|
|
636
661
|
${partImports}${slowViewStateDecl}
|
|
637
662
|
const viewState = ${JSON.stringify(defaultViewState)};
|
|
638
|
-
${generatePromiseReconstruction(outcomes)}
|
|
663
|
+
${generatePromiseReconstruction(outcomes)}
|
|
664
|
+
const fastCarryForward = ${JSON.stringify(fastCarryForward)};
|
|
639
665
|
const trackByMap = ${JSON.stringify(trackByMap)};
|
|
640
666
|
${clientInitExecution}
|
|
641
667
|
const target = document.getElementById('target');
|
|
@@ -651,6 +677,65 @@ function asyncSwapScript(id, html) {
|
|
|
651
677
|
const escapedHtml = html.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
652
678
|
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>`;
|
|
653
679
|
}
|
|
680
|
+
function tagIdentityKey(tag) {
|
|
681
|
+
const t = tag.tag.toLowerCase();
|
|
682
|
+
if (t === "title")
|
|
683
|
+
return "title";
|
|
684
|
+
if (t === "meta") {
|
|
685
|
+
if (tag.attrs?.name)
|
|
686
|
+
return `meta:name:${tag.attrs.name}`;
|
|
687
|
+
if (tag.attrs?.property)
|
|
688
|
+
return `meta:property:${tag.attrs.property}`;
|
|
689
|
+
if (tag.attrs?.charset !== void 0)
|
|
690
|
+
return "meta:charset";
|
|
691
|
+
return void 0;
|
|
692
|
+
}
|
|
693
|
+
if (t === "link") {
|
|
694
|
+
if (tag.attrs?.rel === "canonical")
|
|
695
|
+
return "link:canonical";
|
|
696
|
+
return void 0;
|
|
697
|
+
}
|
|
698
|
+
return void 0;
|
|
699
|
+
}
|
|
700
|
+
function mergeHeadTags(sources) {
|
|
701
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
702
|
+
const result = [];
|
|
703
|
+
for (let si = 0; si < sources.length; si++) {
|
|
704
|
+
for (const tag of sources[si]) {
|
|
705
|
+
const key = tagIdentityKey(tag);
|
|
706
|
+
if (key) {
|
|
707
|
+
const existing = byKey.get(key);
|
|
708
|
+
if (existing && existing.sourceIndex !== si) {
|
|
709
|
+
getLogger().warn(
|
|
710
|
+
`[head-tags] Collision on "${key}" — overwriting with tag from source ${si}`
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
byKey.set(key, { tag, sourceIndex: si });
|
|
714
|
+
} else {
|
|
715
|
+
result.push(tag);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return [...[...byKey.values()].map((v) => v.tag), ...result];
|
|
720
|
+
}
|
|
721
|
+
function escapeAttr(value) {
|
|
722
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
723
|
+
}
|
|
724
|
+
function escapeHtml(value) {
|
|
725
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
726
|
+
}
|
|
727
|
+
const VOID_ELEMENTS = /* @__PURE__ */ new Set(["meta", "link", "base", "br", "hr", "img", "input"]);
|
|
728
|
+
function serializeHeadTags(tags) {
|
|
729
|
+
return tags.map((tag) => {
|
|
730
|
+
const t = tag.tag.toLowerCase();
|
|
731
|
+
const attrs = tag.attrs ? Object.entries(tag.attrs).map(([k, v]) => ` ${k}="${escapeAttr(v)}"`).join("") : "";
|
|
732
|
+
if (VOID_ELEMENTS.has(t)) {
|
|
733
|
+
return ` <${t}${attrs} />`;
|
|
734
|
+
}
|
|
735
|
+
const children = tag.children ? escapeHtml(tag.children) : "";
|
|
736
|
+
return ` <${t}${attrs}>${children}</${t}>`;
|
|
737
|
+
}).join("\n");
|
|
738
|
+
}
|
|
654
739
|
const serverModuleCache = /* @__PURE__ */ new Map();
|
|
655
740
|
function invalidateServerElementCache(jayHtmlPath) {
|
|
656
741
|
if (serverModuleCache.delete(jayHtmlPath)) {
|
|
@@ -660,7 +745,7 @@ function invalidateServerElementCache(jayHtmlPath) {
|
|
|
660
745
|
function clearServerElementCache() {
|
|
661
746
|
serverModuleCache.clear();
|
|
662
747
|
}
|
|
663
|
-
async function generateSSRPageHtml(vite, jayHtmlContent, jayHtmlFilename, jayHtmlDir, viewState, jayHtmlImportPath, parts, carryForward, trackByMap = {}, clientInitData2 = {}, buildFolder, projectRoot, routeDir, tsConfigFilePath, projectInit, pluginInits = [], options = {}) {
|
|
748
|
+
async function generateSSRPageHtml(vite, jayHtmlContent, jayHtmlFilename, jayHtmlDir, viewState, jayHtmlImportPath, parts, carryForward, trackByMap = {}, clientInitData2 = {}, buildFolder, projectRoot, routeDir, tsConfigFilePath, projectInit, pluginInits = [], options = {}, sourceDir, headTags) {
|
|
664
749
|
const jayHtmlPath = path__default.join(jayHtmlDir, jayHtmlFilename);
|
|
665
750
|
let cached = serverModuleCache.get(jayHtmlPath);
|
|
666
751
|
if (!cached) {
|
|
@@ -672,7 +757,8 @@ async function generateSSRPageHtml(vite, jayHtmlContent, jayHtmlFilename, jayHtm
|
|
|
672
757
|
buildFolder,
|
|
673
758
|
projectRoot,
|
|
674
759
|
routeDir,
|
|
675
|
-
tsConfigFilePath
|
|
760
|
+
tsConfigFilePath,
|
|
761
|
+
sourceDir
|
|
676
762
|
);
|
|
677
763
|
serverModuleCache.set(jayHtmlPath, cached);
|
|
678
764
|
}
|
|
@@ -728,14 +814,16 @@ async function generateSSRPageHtml(vite, jayHtmlContent, jayHtmlFilename, jayHtm
|
|
|
728
814
|
return ` <link rel="${link.rel}" href="${link.href}"${attrs} />`;
|
|
729
815
|
}).join("\n");
|
|
730
816
|
const cssLink = cached.cssHref ? ` <link rel="stylesheet" href="${cached.cssHref}" />` : "";
|
|
731
|
-
const
|
|
817
|
+
const headTagsHtml = headTags && headTags.length > 0 ? serializeHeadTags(headTags) : "";
|
|
818
|
+
const hasCustomTitle = headTags?.some((t) => t.tag.toLowerCase() === "title");
|
|
819
|
+
const titleHtml = hasCustomTitle ? "" : " <title>Vite + TS</title>\n";
|
|
820
|
+
const headExtras = [headLinksHtml, cssLink, headTagsHtml].filter((_) => _).join("\n");
|
|
732
821
|
return `<!doctype html>
|
|
733
822
|
<html lang="en">
|
|
734
823
|
<head>
|
|
735
824
|
<meta charset="UTF-8" />
|
|
736
825
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
737
|
-
|
|
738
|
-
${headExtras ? headExtras + "\n" : ""} </head>
|
|
826
|
+
${titleHtml}${headExtras ? headExtras + "\n" : ""} </head>
|
|
739
827
|
<body>
|
|
740
828
|
<div id="target">${ssrHtml}</div>${asyncScripts}
|
|
741
829
|
${hydrationScript}
|
|
@@ -752,14 +840,15 @@ function rebaseRelativeImports(code, fromDir, toDir) {
|
|
|
752
840
|
return `from "${newRelPath}"`;
|
|
753
841
|
});
|
|
754
842
|
}
|
|
755
|
-
async function compileAndLoadServerElement(vite, jayHtmlContent, jayHtmlFilename, jayHtmlDir, buildFolder, projectRoot, routeDir, tsConfigFilePath) {
|
|
843
|
+
async function compileAndLoadServerElement(vite, jayHtmlContent, jayHtmlFilename, jayHtmlDir, buildFolder, projectRoot, routeDir, tsConfigFilePath, sourceDir) {
|
|
756
844
|
const jayFile = await parseJayFile(
|
|
757
845
|
jayHtmlContent,
|
|
758
846
|
jayHtmlFilename,
|
|
759
847
|
jayHtmlDir,
|
|
760
848
|
{ relativePath: tsConfigFilePath },
|
|
761
849
|
JAY_IMPORT_RESOLVER,
|
|
762
|
-
projectRoot
|
|
850
|
+
projectRoot,
|
|
851
|
+
sourceDir
|
|
763
852
|
);
|
|
764
853
|
const parsedJayFile = checkValidationErrors(jayFile);
|
|
765
854
|
const pageName = jayHtmlFilename.replace(".jay-html", "");
|
|
@@ -785,6 +874,8 @@ async function compileAndLoadServerElement(vite, jayHtmlContent, jayHtmlFilename
|
|
|
785
874
|
if (existingModule) {
|
|
786
875
|
vite.moduleGraph.invalidateModule(existingModule);
|
|
787
876
|
}
|
|
877
|
+
const jayHtmlPath = path__default.join(serverElementDir, jayHtmlFilename);
|
|
878
|
+
invalidateJayHtmlModules(vite, jayHtmlPath);
|
|
788
879
|
const serverModule = await vite.ssrLoadModule(serverElementPath);
|
|
789
880
|
let cssHref;
|
|
790
881
|
if (parsedJayFile.css) {
|
|
@@ -806,6 +897,34 @@ async function compileAndLoadServerElement(vite, jayHtmlContent, jayHtmlFilename
|
|
|
806
897
|
cssHref
|
|
807
898
|
};
|
|
808
899
|
}
|
|
900
|
+
function invalidateJayHtmlModules(vite, jayHtmlPath) {
|
|
901
|
+
let count = 0;
|
|
902
|
+
const byFile = vite.moduleGraph.getModulesByFile(jayHtmlPath);
|
|
903
|
+
if (byFile) {
|
|
904
|
+
for (const mod of byFile) {
|
|
905
|
+
vite.moduleGraph.invalidateModule(mod);
|
|
906
|
+
count++;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
const knownIds = [jayHtmlPath + ".ts", jayHtmlPath + JAY_QUERY_HYDRATE + ".ts"];
|
|
910
|
+
for (const id of knownIds) {
|
|
911
|
+
const mod = vite.moduleGraph.getModuleById(id);
|
|
912
|
+
if (mod) {
|
|
913
|
+
vite.moduleGraph.invalidateModule(mod);
|
|
914
|
+
count++;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
const idMap = vite.moduleGraph.idToModuleMap;
|
|
918
|
+
for (const [id, mod] of idMap) {
|
|
919
|
+
if (id.includes(jayHtmlPath)) {
|
|
920
|
+
vite.moduleGraph.invalidateModule(mod);
|
|
921
|
+
count++;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
if (count > 0) {
|
|
925
|
+
getLogger().info(`[SSR] Invalidated ${count} Vite module(s) for ${jayHtmlPath}`);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
809
928
|
function generateHydrationScript(defaultViewState, fastCarryForward, parts, jayHtmlPath, trackByMap = {}, clientInitData2 = {}, projectInit, pluginInits = [], options = {}, asyncOutcomes = []) {
|
|
810
929
|
const {
|
|
811
930
|
partImports,
|
|
@@ -907,7 +1026,29 @@ async function loadPageParts(vite, route, pagesBase, projectBase, jayRollupConfi
|
|
|
907
1026
|
contract: hi.contract,
|
|
908
1027
|
contractPath: hi.contractPath
|
|
909
1028
|
}));
|
|
910
|
-
const
|
|
1029
|
+
const jayHtmlForDiscovery = injectHeadfullFSTemplates(
|
|
1030
|
+
jayHtmlSource,
|
|
1031
|
+
dirName,
|
|
1032
|
+
JAY_IMPORT_RESOLVER
|
|
1033
|
+
);
|
|
1034
|
+
let discoveryResult;
|
|
1035
|
+
if (headlessInstanceComponents.length > 0) {
|
|
1036
|
+
const firstDiscovery = discoverHeadlessInstances(jayHtmlForDiscovery);
|
|
1037
|
+
const headlessContractNameSet = new Set(
|
|
1038
|
+
jayHtml.headlessImports.map((hi) => hi.contractName)
|
|
1039
|
+
);
|
|
1040
|
+
const jayHtmlWithCoords = assignCoordinatesToJayHtml(
|
|
1041
|
+
firstDiscovery.preRenderedJayHtml,
|
|
1042
|
+
headlessContractNameSet
|
|
1043
|
+
);
|
|
1044
|
+
discoveryResult = discoverHeadlessInstances(jayHtmlWithCoords);
|
|
1045
|
+
} else {
|
|
1046
|
+
discoveryResult = {
|
|
1047
|
+
instances: [],
|
|
1048
|
+
forEachInstances: [],
|
|
1049
|
+
preRenderedJayHtml: jayHtmlSource
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
911
1052
|
return {
|
|
912
1053
|
parts,
|
|
913
1054
|
serverTrackByMap: jayHtml.serverTrackByMap,
|
|
@@ -916,7 +1057,9 @@ async function loadPageParts(vite, route, pagesBase, projectBase, jayRollupConfi
|
|
|
916
1057
|
headlessContracts,
|
|
917
1058
|
headlessInstanceComponents,
|
|
918
1059
|
discoveredInstances: discoveryResult.instances,
|
|
919
|
-
forEachInstances: discoveryResult.forEachInstances
|
|
1060
|
+
forEachInstances: discoveryResult.forEachInstances,
|
|
1061
|
+
linkedCssFiles: jayHtml.linkedCssFiles ?? [],
|
|
1062
|
+
linkedComponentFiles: jayHtml.linkedComponentFiles ?? []
|
|
920
1063
|
};
|
|
921
1064
|
});
|
|
922
1065
|
}
|
|
@@ -931,31 +1074,32 @@ async function slowRenderInstances(discovered, headlessInstanceComponents) {
|
|
|
931
1074
|
const carryForwards = {};
|
|
932
1075
|
for (const instance of discovered) {
|
|
933
1076
|
const comp = componentByContractName.get(instance.contractName);
|
|
934
|
-
if (!comp
|
|
1077
|
+
if (!comp)
|
|
935
1078
|
continue;
|
|
936
|
-
}
|
|
937
1079
|
const contractProps = comp.contract?.props ?? [];
|
|
938
1080
|
const normalizedProps = {};
|
|
939
1081
|
for (const [key, value] of Object.entries(instance.props)) {
|
|
940
1082
|
const match = contractProps.find((p) => p.name.toLowerCase() === key.toLowerCase());
|
|
941
1083
|
normalizedProps[match ? match.name : key] = value;
|
|
942
1084
|
}
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
1085
|
+
discoveredForFast.push({
|
|
1086
|
+
contractName: instance.contractName,
|
|
1087
|
+
props: normalizedProps,
|
|
1088
|
+
coordinate: instance.coordinate
|
|
1089
|
+
});
|
|
1090
|
+
if (comp.compDefinition.slowlyRender) {
|
|
1091
|
+
const services = resolveServices(comp.compDefinition.services);
|
|
1092
|
+
const slowResult = await comp.compDefinition.slowlyRender(normalizedProps, ...services);
|
|
1093
|
+
if (slowResult.kind === "PhaseOutput") {
|
|
1094
|
+
const coordKey = instance.coordinate.join("/");
|
|
1095
|
+
resolvedData.push({
|
|
1096
|
+
coordinate: instance.coordinate,
|
|
1097
|
+
contract: comp.contract,
|
|
1098
|
+
slowViewState: slowResult.rendered
|
|
1099
|
+
});
|
|
1100
|
+
slowViewStates[coordKey] = slowResult.rendered;
|
|
1101
|
+
carryForwards[coordKey] = slowResult.carryForward;
|
|
1102
|
+
}
|
|
959
1103
|
}
|
|
960
1104
|
}
|
|
961
1105
|
if (discoveredForFast.length === 0) {
|
|
@@ -964,7 +1108,7 @@ async function slowRenderInstances(discovered, headlessInstanceComponents) {
|
|
|
964
1108
|
return {
|
|
965
1109
|
resolvedData,
|
|
966
1110
|
slowViewStates,
|
|
967
|
-
instancePhaseData: { discovered: discoveredForFast, carryForwards }
|
|
1111
|
+
instancePhaseData: { discovered: discoveredForFast, carryForwards, slowViewStates }
|
|
968
1112
|
};
|
|
969
1113
|
}
|
|
970
1114
|
function validateForEachInstances(forEachInstances, headlessInstanceComponents) {
|
|
@@ -2153,11 +2297,34 @@ async function materializeContracts(options, services = /* @__PURE__ */ new Map(
|
|
|
2153
2297
|
const { manifest } = plugin;
|
|
2154
2298
|
const pluginRelPath = path.relative(projectRoot, plugin.pluginPath);
|
|
2155
2299
|
if (!pluginsIndexMap.has(plugin.name)) {
|
|
2156
|
-
|
|
2300
|
+
const entry = {
|
|
2157
2301
|
path: "./" + pluginRelPath.replace(/\\/g, "/"),
|
|
2158
2302
|
contracts: [],
|
|
2159
2303
|
actions: []
|
|
2160
|
-
}
|
|
2304
|
+
};
|
|
2305
|
+
if (manifest.services?.length) {
|
|
2306
|
+
entry.services = manifest.services.map((s2) => {
|
|
2307
|
+
const docPath = s2.doc ? "./" + path.relative(projectRoot, path.resolve(plugin.pluginPath, s2.doc)) : void 0;
|
|
2308
|
+
return {
|
|
2309
|
+
name: s2.name,
|
|
2310
|
+
marker: s2.marker,
|
|
2311
|
+
...s2.description && { description: s2.description },
|
|
2312
|
+
...docPath && { doc: docPath }
|
|
2313
|
+
};
|
|
2314
|
+
});
|
|
2315
|
+
}
|
|
2316
|
+
if (manifest.contexts?.length) {
|
|
2317
|
+
entry.contexts = manifest.contexts.map((c) => {
|
|
2318
|
+
const docPath = c.doc ? "./" + path.relative(projectRoot, path.resolve(plugin.pluginPath, c.doc)) : void 0;
|
|
2319
|
+
return {
|
|
2320
|
+
name: c.name,
|
|
2321
|
+
marker: c.marker,
|
|
2322
|
+
...c.description && { description: c.description },
|
|
2323
|
+
...docPath && { doc: docPath }
|
|
2324
|
+
};
|
|
2325
|
+
});
|
|
2326
|
+
}
|
|
2327
|
+
pluginsIndexMap.set(plugin.name, entry);
|
|
2161
2328
|
}
|
|
2162
2329
|
if (!dynamicOnly && manifest.contracts) {
|
|
2163
2330
|
for (const contract of manifest.contracts) {
|
|
@@ -2167,8 +2334,20 @@ async function materializeContracts(options, services = /* @__PURE__ */ new Map(
|
|
|
2167
2334
|
projectRoot
|
|
2168
2335
|
);
|
|
2169
2336
|
const relativePath = path.relative(projectRoot, contractPath);
|
|
2337
|
+
let description = contract.description;
|
|
2338
|
+
if (!description) {
|
|
2339
|
+
try {
|
|
2340
|
+
const contractContent = fs.readFileSync(contractPath, "utf-8");
|
|
2341
|
+
const parsed = YAML.parse(contractContent);
|
|
2342
|
+
if (parsed?.description && typeof parsed.description === "string") {
|
|
2343
|
+
description = parsed.description;
|
|
2344
|
+
}
|
|
2345
|
+
} catch {
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2170
2348
|
pluginsIndexMap.get(plugin.name).contracts.push({
|
|
2171
2349
|
name: contract.name,
|
|
2350
|
+
...description && { description },
|
|
2172
2351
|
type: "static",
|
|
2173
2352
|
path: "./" + relativePath
|
|
2174
2353
|
});
|
|
@@ -2202,8 +2381,17 @@ async function materializeContracts(options, services = /* @__PURE__ */ new Map(
|
|
|
2202
2381
|
const filePath = path.join(pluginOutputDir, fileName);
|
|
2203
2382
|
fs.writeFileSync(filePath, generated.yaml, "utf-8");
|
|
2204
2383
|
const relativePath = path.relative(projectRoot, filePath);
|
|
2384
|
+
let dynDescription;
|
|
2385
|
+
try {
|
|
2386
|
+
const parsedYaml = YAML.parse(generated.yaml);
|
|
2387
|
+
if (parsedYaml?.description && typeof parsedYaml.description === "string") {
|
|
2388
|
+
dynDescription = parsedYaml.description;
|
|
2389
|
+
}
|
|
2390
|
+
} catch {
|
|
2391
|
+
}
|
|
2205
2392
|
const contractEntry = {
|
|
2206
2393
|
name: fullName,
|
|
2394
|
+
...dynDescription && { description: dynDescription },
|
|
2207
2395
|
type: "dynamic",
|
|
2208
2396
|
path: "./" + relativePath,
|
|
2209
2397
|
...generated.metadata && { metadata: generated.metadata }
|
|
@@ -2239,7 +2427,10 @@ async function materializeContracts(options, services = /* @__PURE__ */ new Map(
|
|
|
2239
2427
|
if (!metadata)
|
|
2240
2428
|
continue;
|
|
2241
2429
|
const actionRelPath = path.relative(projectRoot, metadataFilePath);
|
|
2242
|
-
pluginsIndexMap.get(plugin.name)
|
|
2430
|
+
const pluginEntry = pluginsIndexMap.get(plugin.name);
|
|
2431
|
+
if (!pluginEntry.actions)
|
|
2432
|
+
pluginEntry.actions = [];
|
|
2433
|
+
pluginEntry.actions.push({
|
|
2243
2434
|
name: metadata.name,
|
|
2244
2435
|
description: metadata.description,
|
|
2245
2436
|
path: "./" + actionRelPath.replace(/\\/g, "/")
|
|
@@ -2255,7 +2446,9 @@ async function materializeContracts(options, services = /* @__PURE__ */ new Map(
|
|
|
2255
2446
|
name,
|
|
2256
2447
|
path: data.path,
|
|
2257
2448
|
contracts: data.contracts,
|
|
2258
|
-
...data.actions.length > 0 && { actions: data.actions }
|
|
2449
|
+
...data.actions && data.actions.length > 0 && { actions: data.actions },
|
|
2450
|
+
...data.services?.length && { services: data.services },
|
|
2451
|
+
...data.contexts?.length && { contexts: data.contexts }
|
|
2259
2452
|
}))
|
|
2260
2453
|
};
|
|
2261
2454
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
@@ -2286,10 +2479,33 @@ async function listContracts(options) {
|
|
|
2286
2479
|
const { manifest } = plugin;
|
|
2287
2480
|
const pluginRelPath = path.relative(projectRoot, plugin.pluginPath);
|
|
2288
2481
|
if (!pluginsMap.has(plugin.name)) {
|
|
2289
|
-
|
|
2482
|
+
const entry = {
|
|
2290
2483
|
path: "./" + pluginRelPath.replace(/\\/g, "/"),
|
|
2291
2484
|
contracts: []
|
|
2292
|
-
}
|
|
2485
|
+
};
|
|
2486
|
+
if (manifest.services?.length) {
|
|
2487
|
+
entry.services = manifest.services.map((s2) => {
|
|
2488
|
+
const docPath = s2.doc ? "./" + path.relative(projectRoot, path.resolve(plugin.pluginPath, s2.doc)) : void 0;
|
|
2489
|
+
return {
|
|
2490
|
+
name: s2.name,
|
|
2491
|
+
marker: s2.marker,
|
|
2492
|
+
...s2.description && { description: s2.description },
|
|
2493
|
+
...docPath && { doc: docPath }
|
|
2494
|
+
};
|
|
2495
|
+
});
|
|
2496
|
+
}
|
|
2497
|
+
if (manifest.contexts?.length) {
|
|
2498
|
+
entry.contexts = manifest.contexts.map((c) => {
|
|
2499
|
+
const docPath = c.doc ? "./" + path.relative(projectRoot, path.resolve(plugin.pluginPath, c.doc)) : void 0;
|
|
2500
|
+
return {
|
|
2501
|
+
name: c.name,
|
|
2502
|
+
marker: c.marker,
|
|
2503
|
+
...c.description && { description: c.description },
|
|
2504
|
+
...docPath && { doc: docPath }
|
|
2505
|
+
};
|
|
2506
|
+
});
|
|
2507
|
+
}
|
|
2508
|
+
pluginsMap.set(plugin.name, entry);
|
|
2293
2509
|
}
|
|
2294
2510
|
if (!dynamicOnly && manifest.contracts) {
|
|
2295
2511
|
for (const contract of manifest.contracts) {
|
|
@@ -2299,8 +2515,20 @@ async function listContracts(options) {
|
|
|
2299
2515
|
projectRoot
|
|
2300
2516
|
);
|
|
2301
2517
|
const relativePath = path.relative(projectRoot, contractPath);
|
|
2518
|
+
let listDescription = contract.description;
|
|
2519
|
+
if (!listDescription) {
|
|
2520
|
+
try {
|
|
2521
|
+
const contractContent = fs.readFileSync(contractPath, "utf-8");
|
|
2522
|
+
const parsed = YAML.parse(contractContent);
|
|
2523
|
+
if (parsed?.description && typeof parsed.description === "string") {
|
|
2524
|
+
listDescription = parsed.description;
|
|
2525
|
+
}
|
|
2526
|
+
} catch {
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2302
2529
|
pluginsMap.get(plugin.name).contracts.push({
|
|
2303
2530
|
name: contract.name,
|
|
2531
|
+
...listDescription && { description: listDescription },
|
|
2304
2532
|
type: "static",
|
|
2305
2533
|
path: "./" + relativePath
|
|
2306
2534
|
});
|
|
@@ -2321,7 +2549,9 @@ async function listContracts(options) {
|
|
|
2321
2549
|
plugins: Array.from(pluginsMap.entries()).map(([name, data]) => ({
|
|
2322
2550
|
name,
|
|
2323
2551
|
path: data.path,
|
|
2324
|
-
contracts: data.contracts
|
|
2552
|
+
contracts: data.contracts,
|
|
2553
|
+
...data.services?.length && { services: data.services },
|
|
2554
|
+
...data.contexts?.length && { contexts: data.contexts }
|
|
2325
2555
|
}))
|
|
2326
2556
|
};
|
|
2327
2557
|
}
|
|
@@ -2491,6 +2721,7 @@ export {
|
|
|
2491
2721
|
loadActionMetadata,
|
|
2492
2722
|
loadPageParts,
|
|
2493
2723
|
materializeContracts,
|
|
2724
|
+
mergeHeadTags,
|
|
2494
2725
|
onInit,
|
|
2495
2726
|
onShutdown,
|
|
2496
2727
|
parseActionMetadata,
|
|
@@ -2506,8 +2737,10 @@ export {
|
|
|
2506
2737
|
runShutdownCallbacks,
|
|
2507
2738
|
runSlowlyChangingRender,
|
|
2508
2739
|
scanPlugins,
|
|
2740
|
+
serializeHeadTags,
|
|
2509
2741
|
setClientInitData,
|
|
2510
2742
|
slowRenderInstances,
|
|
2511
2743
|
sortPluginsByDependencies,
|
|
2744
|
+
tagIdentityKey,
|
|
2512
2745
|
validateForEachInstances
|
|
2513
2746
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/stack-server-runtime",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.6",
|
|
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.
|
|
30
|
-
"@jay-framework/compiler-shared": "^0.15.
|
|
31
|
-
"@jay-framework/component": "^0.15.
|
|
32
|
-
"@jay-framework/fullstack-component": "^0.15.
|
|
33
|
-
"@jay-framework/logger": "^0.15.
|
|
34
|
-
"@jay-framework/runtime": "^0.15.
|
|
35
|
-
"@jay-framework/ssr-runtime": "^0.15.
|
|
36
|
-
"@jay-framework/stack-route-scanner": "^0.15.
|
|
37
|
-
"@jay-framework/view-state-merge": "^0.15.
|
|
29
|
+
"@jay-framework/compiler-jay-html": "^0.15.6",
|
|
30
|
+
"@jay-framework/compiler-shared": "^0.15.6",
|
|
31
|
+
"@jay-framework/component": "^0.15.6",
|
|
32
|
+
"@jay-framework/fullstack-component": "^0.15.6",
|
|
33
|
+
"@jay-framework/logger": "^0.15.6",
|
|
34
|
+
"@jay-framework/runtime": "^0.15.6",
|
|
35
|
+
"@jay-framework/ssr-runtime": "^0.15.6",
|
|
36
|
+
"@jay-framework/stack-route-scanner": "^0.15.6",
|
|
37
|
+
"@jay-framework/view-state-merge": "^0.15.6",
|
|
38
38
|
"yaml": "^2.3.4"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@jay-framework/dev-environment": "^0.15.
|
|
42
|
-
"@jay-framework/jay-cli": "^0.15.
|
|
43
|
-
"@jay-framework/stack-client-runtime": "^0.15.
|
|
41
|
+
"@jay-framework/dev-environment": "^0.15.6",
|
|
42
|
+
"@jay-framework/jay-cli": "^0.15.6",
|
|
43
|
+
"@jay-framework/stack-client-runtime": "^0.15.6",
|
|
44
44
|
"@types/express": "^5.0.2",
|
|
45
45
|
"@types/node": "^22.15.21",
|
|
46
46
|
"nodemon": "^3.0.3",
|