@jay-framework/stack-server-runtime 0.6.10 → 0.8.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 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<StaticViewState extends object, ViewState extends object, Refs extends object, ServerContexts extends Array<any>, ClientContexts extends Array<any>, PropsT extends object, Params extends UrlParams, CompCore extends JayComponentCore<PropsT, ViewState>>(compDefinition: JayStackComponentDefinition<StaticViewState, ViewState, Refs, ServerContexts, ClientContexts, PropsT, Params, CompCore>, serverContexts: ServerContexts): Promise<void>;
25
- declare function runSlowlyChangingRender<StaticViewState extends object, ViewState extends object, Refs extends object, ServerContexts extends Array<any>, ClientContexts extends Array<any>, PropsT extends object, Params extends UrlParams, CompCore extends JayComponentCore<PropsT, ViewState>>(compDefinition: JayStackComponentDefinition<StaticViewState, ViewState, Refs, ServerContexts, ClientContexts, PropsT, Params, CompCore>): void;
24
+ declare function runLoadParams<StaticViewState extends object, ViewState extends object, Refs extends object, Services extends Array<any>, Contexts extends Array<any>, PropsT extends object, Params extends UrlParams, CompCore extends JayComponentCore<PropsT, ViewState>>(compDefinition: JayStackComponentDefinition<StaticViewState, ViewState, Refs, Services, Contexts, PropsT, Params, CompCore>, services: Services): Promise<void>;
25
+ declare function runSlowlyChangingRender<StaticViewState extends object, ViewState extends object, Refs extends object, Services extends Array<any>, Contexts extends Array<any>, PropsT extends object, Params extends UrlParams, CompCore extends JayComponentCore<PropsT, ViewState>>(compDefinition: JayStackComponentDefinition<StaticViewState, ViewState, Refs, 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
- export { DevSlowlyChangingPhase, type SlowlyChangingPhase, generateClientScript, loadPageParts, renderFastChangingData, runLoadParams, runSlowlyChangingRender };
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 compParams = compDefinition.loadParams([]);
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, serverContexts) {
54
- compDefinition.loadParams(serverContexts);
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
- ...[partSlowlyCarryForward]
117
+ partSlowlyCarryForward,
118
+ ...services
68
119
  );
69
120
  if (fastRenderedPart.kind === "PartialRender") {
70
121
  if (!key) {
@@ -114,12 +165,11 @@ 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
169
  const pageComponent = (await vite.ssrLoadModule(route.compPath)).page;
120
170
  parts.push({
121
171
  compDefinition: pageComponent,
122
- clientImport: `import {page} from '${pageCode}'`,
172
+ clientImport: `import {page} from '${route.compPath}'`,
123
173
  clientPart: `{comp: page.comp, contextMarkers: []}`
124
174
  });
125
175
  }
@@ -158,9 +208,19 @@ async function loadPageParts(vite, route, pagesBase, jayRollupConfig) {
158
208
  }
159
209
  export {
160
210
  DevSlowlyChangingPhase,
211
+ clearLifecycleCallbacks,
212
+ clearServiceRegistry,
161
213
  generateClientScript,
214
+ getService,
215
+ hasService,
162
216
  loadPageParts,
217
+ onInit,
218
+ onShutdown,
219
+ registerService,
163
220
  renderFastChangingData,
221
+ resolveServices,
222
+ runInitCallbacks,
164
223
  runLoadParams,
224
+ runShutdownCallbacks,
165
225
  runSlowlyChangingRender
166
226
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/stack-server-runtime",
3
- "version": "0.6.10",
3
+ "version": "0.8.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.6.10",
30
- "@jay-framework/component": "^0.6.10",
31
- "@jay-framework/fullstack-component": "^0.6.10",
32
- "@jay-framework/runtime": "^0.6.10",
33
- "@jay-framework/stack-route-scanner": "^0.6.10"
29
+ "@jay-framework/compiler-jay-html": "^0.8.0",
30
+ "@jay-framework/component": "^0.8.0",
31
+ "@jay-framework/fullstack-component": "^0.8.0",
32
+ "@jay-framework/runtime": "^0.8.0",
33
+ "@jay-framework/stack-route-scanner": "^0.8.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@jay-framework/dev-environment": "^0.6.10",
37
- "@jay-framework/jay-cli": "^0.6.10",
38
- "@jay-framework/stack-client-runtime": "^0.6.10",
36
+ "@jay-framework/dev-environment": "^0.8.0",
37
+ "@jay-framework/jay-cli": "^0.8.0",
38
+ "@jay-framework/stack-client-runtime": "^0.8.0",
39
39
  "@types/express": "^5.0.2",
40
40
  "@types/node": "^22.15.21",
41
41
  "nodemon": "^3.0.3",