@jay-framework/stack-server-runtime 0.7.0 → 0.9.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.
- package/dist/index.d.ts +121 -4
- package/dist/index.js +76 -11
- package/package.json +9 -9
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnyJayStackComponentDefinition, PageProps, AnySlowlyRenderResult, UrlParams, JayStackComponentDefinition, AnyFastRenderResult } from '@jay-framework/fullstack-component';
|
|
1
|
+
import { AnyJayStackComponentDefinition, PageProps, AnySlowlyRenderResult, UrlParams, JayStackComponentDefinition, AnyFastRenderResult, 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';
|
|
@@ -21,11 +21,128 @@ declare class DevSlowlyChangingPhase implements SlowlyChangingPhase {
|
|
|
21
21
|
constructor(dontCacheSlowly: boolean);
|
|
22
22
|
runSlowlyForPage(pageParams: UrlParams, pageProps: PageProps, parts: Array<DevServerPagePart>): Promise<AnySlowlyRenderResult>;
|
|
23
23
|
}
|
|
24
|
-
declare function runLoadParams<
|
|
25
|
-
declare function runSlowlyChangingRender<
|
|
24
|
+
declare function runLoadParams<Refs extends object, SlowVS extends object, FastVS extends object, InteractiveVS extends object, Services extends Array<any>, Contexts extends Array<any>, PropsT extends object, Params extends UrlParams, CompCore extends JayComponentCore<PropsT, InteractiveVS>>(compDefinition: JayStackComponentDefinition<Refs, SlowVS, FastVS, InteractiveVS, Services, Contexts, PropsT, Params, CompCore>, services: Services): Promise<void>;
|
|
25
|
+
declare function runSlowlyChangingRender<Refs extends object, SlowVS extends object, FastVS extends object, InteractiveVS extends object, Services extends Array<any>, Contexts extends Array<any>, PropsT extends object, Params extends UrlParams, CompCore extends JayComponentCore<PropsT, InteractiveVS>>(compDefinition: JayStackComponentDefinition<Refs, SlowVS, FastVS, InteractiveVS, Services, Contexts, PropsT, Params, CompCore>): void;
|
|
26
26
|
|
|
27
27
|
declare function renderFastChangingData(pageParams: object, pageProps: PageProps, carryForward: object, parts: Array<DevServerPagePart>): Promise<AnyFastRenderResult>;
|
|
28
28
|
|
|
29
29
|
declare function generateClientScript(defaultViewState: object, fastCarryForward: object, parts: DevServerPagePart[], jayHtmlPath: string): string;
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Service registry for Jay Stack server-side dependency injection.
|
|
33
|
+
*
|
|
34
|
+
* Services are global singletons (not hierarchical like client contexts) that provide
|
|
35
|
+
* infrastructure capabilities like database connections, API clients, etc.
|
|
36
|
+
*
|
|
37
|
+
* Note: ServiceMarker and createJayService are defined in @jay-framework/fullstack-component
|
|
38
|
+
* to avoid circular dependencies. This module contains only the runtime implementation.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Registers a service instance with the given marker.
|
|
43
|
+
* Typically called within an `onInit()` callback.
|
|
44
|
+
*
|
|
45
|
+
* @param marker - The service marker created with `createJayService()`
|
|
46
|
+
* @param service - The service instance to register
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* onInit(async () => {
|
|
51
|
+
* const db = await createDatabase();
|
|
52
|
+
* registerService(DATABASE_SERVICE, db);
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
declare function registerService<ServiceType>(marker: ServiceMarker<ServiceType>, service: ServiceType): void;
|
|
57
|
+
/**
|
|
58
|
+
* Retrieves a registered service by its marker.
|
|
59
|
+
* Throws an error if the service is not found.
|
|
60
|
+
*
|
|
61
|
+
* @param marker - The service marker
|
|
62
|
+
* @returns The registered service instance
|
|
63
|
+
* @throws Error if service is not registered
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* onShutdown(async () => {
|
|
68
|
+
* const db = getService(DATABASE_SERVICE);
|
|
69
|
+
* await db?.close();
|
|
70
|
+
* });
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
declare function getService<ServiceType>(marker: ServiceMarker<ServiceType>): ServiceType;
|
|
74
|
+
/**
|
|
75
|
+
* Checks if a service is registered.
|
|
76
|
+
*
|
|
77
|
+
* @param marker - The service marker
|
|
78
|
+
* @returns true if the service is registered
|
|
79
|
+
*/
|
|
80
|
+
declare function hasService<ServiceType>(marker: ServiceMarker<ServiceType>): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Clears all registered services.
|
|
83
|
+
* Internal API used by dev-server during hot reload.
|
|
84
|
+
*/
|
|
85
|
+
declare function clearServiceRegistry(): void;
|
|
86
|
+
/**
|
|
87
|
+
* Resolves an array of service markers to their registered instances.
|
|
88
|
+
* Used by the runtime to inject services into render functions.
|
|
89
|
+
*
|
|
90
|
+
* @param serviceMarkers - Array of service markers to resolve
|
|
91
|
+
* @returns Array of resolved service instances
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const services = resolveServices([DATABASE_SERVICE, INVENTORY_SERVICE]);
|
|
96
|
+
* // Returns: [databaseInstance, inventoryInstance]
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
declare function resolveServices(serviceMarkers: any[]): Array<any>;
|
|
100
|
+
type InitCallback = () => void | Promise<void>;
|
|
101
|
+
type ShutdownCallback = () => void | Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Registers a callback to be executed during service initialization.
|
|
104
|
+
* Multiple callbacks can be registered and will be executed in order.
|
|
105
|
+
*
|
|
106
|
+
* @param callback - Async or sync function to initialize services
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* onInit(async () => {
|
|
111
|
+
* const db = await connectToDatabase(process.env.DATABASE_URL);
|
|
112
|
+
* registerService(DATABASE_SERVICE, db);
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
declare function onInit(callback: InitCallback): void;
|
|
117
|
+
/**
|
|
118
|
+
* Registers a callback to be executed during service shutdown.
|
|
119
|
+
* Multiple callbacks can be registered. They execute in reverse order (LIFO).
|
|
120
|
+
*
|
|
121
|
+
* @param callback - Async or sync function to clean up services
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* onShutdown(async () => {
|
|
126
|
+
* const db = getService(DATABASE_SERVICE);
|
|
127
|
+
* await db?.close();
|
|
128
|
+
* });
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
declare function onShutdown(callback: ShutdownCallback): void;
|
|
132
|
+
/**
|
|
133
|
+
* Executes all registered init callbacks in order.
|
|
134
|
+
* Internal API called by dev-server on startup.
|
|
135
|
+
*/
|
|
136
|
+
declare function runInitCallbacks(): Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Executes all registered shutdown callbacks in reverse order (LIFO).
|
|
139
|
+
* Internal API called by dev-server on shutdown/reload.
|
|
140
|
+
*/
|
|
141
|
+
declare function runShutdownCallbacks(): Promise<void>;
|
|
142
|
+
/**
|
|
143
|
+
* Clears all registered lifecycle callbacks.
|
|
144
|
+
* Internal API used by dev-server during hot reload.
|
|
145
|
+
*/
|
|
146
|
+
declare function clearLifecycleCallbacks(): void;
|
|
147
|
+
|
|
148
|
+
export { DevSlowlyChangingPhase, type SlowlyChangingPhase, clearLifecycleCallbacks, clearServiceRegistry, generateClientScript, getService, hasService, loadPageParts, onInit, onShutdown, registerService, renderFastChangingData, resolveServices, runInitCallbacks, runLoadParams, runShutdownCallbacks, runSlowlyChangingRender };
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,53 @@ import fs from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { parseJayFile } from "@jay-framework/compiler-jay-html";
|
|
5
5
|
import { createRequire } from "module";
|
|
6
|
+
const serviceRegistry = /* @__PURE__ */ new Map();
|
|
7
|
+
function registerService(marker, service) {
|
|
8
|
+
serviceRegistry.set(marker, service);
|
|
9
|
+
}
|
|
10
|
+
function getService(marker) {
|
|
11
|
+
const service = serviceRegistry.get(marker);
|
|
12
|
+
if (service === void 0) {
|
|
13
|
+
const symbolKey = marker;
|
|
14
|
+
const serviceName = symbolKey.description || "Unknown service";
|
|
15
|
+
throw new Error(
|
|
16
|
+
`Service '${serviceName}' not found. Did you register it in jay.init.ts?
|
|
17
|
+
Make sure to call: registerService(${serviceName.toUpperCase()}_SERVICE, ...)`
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
return service;
|
|
21
|
+
}
|
|
22
|
+
function hasService(marker) {
|
|
23
|
+
return serviceRegistry.has(marker);
|
|
24
|
+
}
|
|
25
|
+
function clearServiceRegistry() {
|
|
26
|
+
serviceRegistry.clear();
|
|
27
|
+
}
|
|
28
|
+
function resolveServices(serviceMarkers) {
|
|
29
|
+
return serviceMarkers.map((marker) => getService(marker));
|
|
30
|
+
}
|
|
31
|
+
const initCallbacks = [];
|
|
32
|
+
const shutdownCallbacks = [];
|
|
33
|
+
function onInit(callback) {
|
|
34
|
+
initCallbacks.push(callback);
|
|
35
|
+
}
|
|
36
|
+
function onShutdown(callback) {
|
|
37
|
+
shutdownCallbacks.push(callback);
|
|
38
|
+
}
|
|
39
|
+
async function runInitCallbacks() {
|
|
40
|
+
for (const callback of initCallbacks) {
|
|
41
|
+
await callback();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function runShutdownCallbacks() {
|
|
45
|
+
for (let i = shutdownCallbacks.length - 1; i >= 0; i--) {
|
|
46
|
+
await shutdownCallbacks[i]();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function clearLifecycleCallbacks() {
|
|
50
|
+
initCallbacks.length = 0;
|
|
51
|
+
shutdownCallbacks.length = 0;
|
|
52
|
+
}
|
|
6
53
|
function isLeftSideParamsSubsetOfRightSideParams(left, right) {
|
|
7
54
|
return Object.keys(left).reduce((prev, curr) => prev && left[curr] === right[curr], true);
|
|
8
55
|
}
|
|
@@ -21,7 +68,8 @@ class DevSlowlyChangingPhase {
|
|
|
21
68
|
for (const part of parts) {
|
|
22
69
|
const { compDefinition } = part;
|
|
23
70
|
if (compDefinition.loadParams) {
|
|
24
|
-
const
|
|
71
|
+
const services = resolveServices(compDefinition.services);
|
|
72
|
+
const compParams = compDefinition.loadParams(services);
|
|
25
73
|
if (!await findMatchingParams(pageParams, compParams))
|
|
26
74
|
return notFound();
|
|
27
75
|
}
|
|
@@ -31,9 +79,10 @@ class DevSlowlyChangingPhase {
|
|
|
31
79
|
for (const part of parts) {
|
|
32
80
|
const { compDefinition, key } = part;
|
|
33
81
|
if (compDefinition.slowlyRender) {
|
|
82
|
+
const services = resolveServices(compDefinition.services);
|
|
34
83
|
const slowlyRenderedPart = await compDefinition.slowlyRender(
|
|
35
84
|
{ ...pageProps, ...pageParams },
|
|
36
|
-
|
|
85
|
+
...services
|
|
37
86
|
);
|
|
38
87
|
if (slowlyRenderedPart.kind === "PartialRender") {
|
|
39
88
|
if (!key) {
|
|
@@ -50,8 +99,8 @@ class DevSlowlyChangingPhase {
|
|
|
50
99
|
return partialRender(slowlyViewState, carryForward);
|
|
51
100
|
}
|
|
52
101
|
}
|
|
53
|
-
async function runLoadParams(compDefinition,
|
|
54
|
-
compDefinition.loadParams(
|
|
102
|
+
async function runLoadParams(compDefinition, services) {
|
|
103
|
+
compDefinition.loadParams(services);
|
|
55
104
|
}
|
|
56
105
|
function runSlowlyChangingRender(compDefinition) {
|
|
57
106
|
}
|
|
@@ -62,9 +111,11 @@ async function renderFastChangingData(pageParams, pageProps, carryForward, parts
|
|
|
62
111
|
const { compDefinition, key } = part;
|
|
63
112
|
if (compDefinition.fastRender) {
|
|
64
113
|
const partSlowlyCarryForward = key ? carryForward[key] : carryForward;
|
|
114
|
+
const services = resolveServices(compDefinition.services);
|
|
65
115
|
const fastRenderedPart = await compDefinition.fastRender(
|
|
66
116
|
{ ...pageProps, ...pageParams },
|
|
67
|
-
|
|
117
|
+
partSlowlyCarryForward,
|
|
118
|
+
...services
|
|
68
119
|
);
|
|
69
120
|
if (fastRenderedPart.kind === "PartialRender") {
|
|
70
121
|
if (!key) {
|
|
@@ -114,12 +165,12 @@ const require2 = createRequire(import.meta.url);
|
|
|
114
165
|
async function loadPageParts(vite, route, pagesBase, jayRollupConfig) {
|
|
115
166
|
const exists = await fs.access(route.compPath, fs.constants.F_OK).then(() => true).catch(() => false);
|
|
116
167
|
const parts = [];
|
|
117
|
-
const pageCode = path.resolve(pagesBase, "./page.ts");
|
|
118
168
|
if (exists) {
|
|
119
|
-
const pageComponent = (await vite.ssrLoadModule(route.compPath)).page;
|
|
169
|
+
const pageComponent = (await vite.ssrLoadModule(route.compPath + "?jay-server")).page;
|
|
120
170
|
parts.push({
|
|
121
171
|
compDefinition: pageComponent,
|
|
122
|
-
|
|
172
|
+
// Client import uses client-only code (server code stripped)
|
|
173
|
+
clientImport: `import {page} from '${route.compPath}?jay-client'`,
|
|
123
174
|
clientPart: `{comp: page.comp, contextMarkers: []}`
|
|
124
175
|
});
|
|
125
176
|
}
|
|
@@ -141,14 +192,18 @@ async function loadPageParts(vite, route, pagesBase, jayRollupConfig) {
|
|
|
141
192
|
for await (const headlessImport of jayHtml.headlessImports) {
|
|
142
193
|
const module2 = headlessImport.codeLink.module;
|
|
143
194
|
const name = headlessImport.codeLink.names[0].name;
|
|
144
|
-
const
|
|
145
|
-
const
|
|
195
|
+
const isLocalModule = module2[0] === "." || module2[0] === "/";
|
|
196
|
+
const modulePath = isLocalModule ? path.resolve(dirName, module2) : require2.resolve(module2, { paths: require2.resolve.paths(dirName) });
|
|
197
|
+
const serverModulePath = isLocalModule ? modulePath + "?jay-server" : modulePath;
|
|
198
|
+
const compDefinition = (await vite.ssrLoadModule(serverModulePath))[name];
|
|
146
199
|
const moduleImport = module2.startsWith("./") ? path.resolve(pagesBase, module2) : module2;
|
|
200
|
+
const isNpmPackage = !module2.startsWith("./") && !module2.startsWith("../");
|
|
201
|
+
const clientModuleImport = isNpmPackage ? `${moduleImport}/client` : `${moduleImport}?jay-client`;
|
|
147
202
|
const key = headlessImport.key;
|
|
148
203
|
const part = {
|
|
149
204
|
key,
|
|
150
205
|
compDefinition,
|
|
151
|
-
clientImport: `import {${name}} from '${
|
|
206
|
+
clientImport: `import {${name}} from '${clientModuleImport}'`,
|
|
152
207
|
clientPart: `{comp: ${name}.comp, contextMarkers: [], key: '${headlessImport.key}'}`
|
|
153
208
|
};
|
|
154
209
|
parts.push(part);
|
|
@@ -158,9 +213,19 @@ async function loadPageParts(vite, route, pagesBase, jayRollupConfig) {
|
|
|
158
213
|
}
|
|
159
214
|
export {
|
|
160
215
|
DevSlowlyChangingPhase,
|
|
216
|
+
clearLifecycleCallbacks,
|
|
217
|
+
clearServiceRegistry,
|
|
161
218
|
generateClientScript,
|
|
219
|
+
getService,
|
|
220
|
+
hasService,
|
|
162
221
|
loadPageParts,
|
|
222
|
+
onInit,
|
|
223
|
+
onShutdown,
|
|
224
|
+
registerService,
|
|
163
225
|
renderFastChangingData,
|
|
226
|
+
resolveServices,
|
|
227
|
+
runInitCallbacks,
|
|
164
228
|
runLoadParams,
|
|
229
|
+
runShutdownCallbacks,
|
|
165
230
|
runSlowlyChangingRender
|
|
166
231
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/stack-server-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.mts",
|
|
@@ -26,16 +26,16 @@
|
|
|
26
26
|
"test:watch": "vitest"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@jay-framework/compiler-jay-html": "^0.
|
|
30
|
-
"@jay-framework/component": "^0.
|
|
31
|
-
"@jay-framework/fullstack-component": "^0.
|
|
32
|
-
"@jay-framework/runtime": "^0.
|
|
33
|
-
"@jay-framework/stack-route-scanner": "^0.
|
|
29
|
+
"@jay-framework/compiler-jay-html": "^0.9.0",
|
|
30
|
+
"@jay-framework/component": "^0.9.0",
|
|
31
|
+
"@jay-framework/fullstack-component": "^0.9.0",
|
|
32
|
+
"@jay-framework/runtime": "^0.9.0",
|
|
33
|
+
"@jay-framework/stack-route-scanner": "^0.9.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@jay-framework/dev-environment": "^0.
|
|
37
|
-
"@jay-framework/jay-cli": "^0.
|
|
38
|
-
"@jay-framework/stack-client-runtime": "^0.
|
|
36
|
+
"@jay-framework/dev-environment": "^0.9.0",
|
|
37
|
+
"@jay-framework/jay-cli": "^0.9.0",
|
|
38
|
+
"@jay-framework/stack-client-runtime": "^0.9.0",
|
|
39
39
|
"@types/express": "^5.0.2",
|
|
40
40
|
"@types/node": "^22.15.21",
|
|
41
41
|
"nodemon": "^3.0.3",
|