@coherent.js/runtime 1.0.0-beta.2

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.
@@ -0,0 +1,330 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/runtimes/node.js
21
+ var node_exports = {};
22
+ __export(node_exports, {
23
+ NodeRuntime: () => NodeRuntime,
24
+ createNodeRuntime: () => createNodeRuntime,
25
+ default: () => node_default
26
+ });
27
+ module.exports = __toCommonJS(node_exports);
28
+ var import_core = require("@coherent.js/core");
29
+ var import_http = require("http");
30
+ var NodeRuntime = class {
31
+ constructor(options = {}) {
32
+ this.options = {
33
+ port: 3e3,
34
+ host: "localhost",
35
+ caching: true,
36
+ framework: null,
37
+ // 'express', 'fastify', 'koa', or null for standalone
38
+ headers: {
39
+ "Content-Type": "text/html; charset=utf-8",
40
+ "Cache-Control": "public, max-age=3600",
41
+ ...options.headers
42
+ },
43
+ ...options
44
+ };
45
+ this.componentRegistry = /* @__PURE__ */ new Map();
46
+ this.routeRegistry = /* @__PURE__ */ new Map();
47
+ this.middleware = [];
48
+ this.cache = /* @__PURE__ */ new Map();
49
+ this.renderCount = 0;
50
+ this.server = null;
51
+ if (this.options.caching) {
52
+ this.initializeCacheCleanup();
53
+ }
54
+ }
55
+ initializeCacheCleanup() {
56
+ setInterval(() => {
57
+ if (this.cache.size > 1e3) {
58
+ const entries = Array.from(this.cache.entries());
59
+ const toDelete = entries.slice(0, entries.length - 500);
60
+ toDelete.forEach(([key]) => this.cache.delete(key));
61
+ }
62
+ }, 3e5);
63
+ }
64
+ // Component management
65
+ registerComponent(name, component) {
66
+ this.componentRegistry.set(name, component);
67
+ return component;
68
+ }
69
+ getComponent(name) {
70
+ return this.componentRegistry.get(name);
71
+ }
72
+ // Route management
73
+ addRoute(pattern, handler) {
74
+ this.routeRegistry.set(pattern, handler);
75
+ }
76
+ matchRoute(pathname) {
77
+ for (const [pattern, handler] of this.routeRegistry.entries()) {
78
+ const match = this.matchPattern(pattern, pathname);
79
+ if (match) {
80
+ return { handler, params: match.params };
81
+ }
82
+ }
83
+ return null;
84
+ }
85
+ matchPattern(pattern, pathname) {
86
+ const patternParts = pattern.split("/").filter(Boolean);
87
+ const pathParts = pathname.split("/").filter(Boolean);
88
+ if (patternParts.length !== pathParts.length) {
89
+ return null;
90
+ }
91
+ const params = {};
92
+ for (let i = 0; i < patternParts.length; i++) {
93
+ const patternPart = patternParts[i];
94
+ const pathPart = pathParts[i];
95
+ if (patternPart.startsWith(":")) {
96
+ params[patternPart.slice(1)] = pathPart;
97
+ } else if (patternPart !== pathPart) {
98
+ return null;
99
+ }
100
+ }
101
+ return { params };
102
+ }
103
+ // Rendering
104
+ async renderComponent(component, props = {}, options = {}) {
105
+ try {
106
+ const resolvedComponent = typeof component === "string" ? this.getComponent(component) : component;
107
+ if (!resolvedComponent) {
108
+ throw new Error(`Component not found: ${component}`);
109
+ }
110
+ const cacheKey = this.generateCacheKey(resolvedComponent, props);
111
+ if (this.options.caching && this.cache.has(cacheKey)) {
112
+ const cached = this.cache.get(cacheKey);
113
+ if (Date.now() - cached.timestamp < (options.cacheMaxAge || 3e5)) {
114
+ return cached.html;
115
+ }
116
+ this.cache.delete(cacheKey);
117
+ }
118
+ const vdom = resolvedComponent(props);
119
+ const html = (0, import_core.render)(vdom);
120
+ if (this.options.caching && options.cacheable !== false) {
121
+ this.cache.set(cacheKey, {
122
+ html,
123
+ timestamp: Date.now()
124
+ });
125
+ }
126
+ this.renderCount++;
127
+ return html;
128
+ } catch (error) {
129
+ console.error("Node render error:", error);
130
+ throw error;
131
+ }
132
+ }
133
+ generateCacheKey(component, props) {
134
+ const componentName = component.name || "anonymous";
135
+ const propsHash = this.hashObject(props);
136
+ return `${componentName}-${propsHash}`;
137
+ }
138
+ hashObject(obj) {
139
+ const str = JSON.stringify(obj, Object.keys(obj).sort());
140
+ let hash = 0;
141
+ for (let i = 0; i < str.length; i++) {
142
+ const char = str.charCodeAt(i);
143
+ hash = (hash << 5) - hash + char;
144
+ hash = hash & hash;
145
+ }
146
+ return hash.toString(36);
147
+ }
148
+ // HTTP Request handling (for standalone mode)
149
+ async handleRequest(req, res) {
150
+ try {
151
+ const url = new URL(req.url, `http://${req.headers.host}`);
152
+ const pathname = url.pathname;
153
+ const context = {
154
+ req,
155
+ res,
156
+ url,
157
+ pathname,
158
+ params: {},
159
+ query: Object.fromEntries(url.searchParams),
160
+ method: req.method,
161
+ headers: req.headers,
162
+ runtime: this,
163
+ state: {}
164
+ };
165
+ let middlewareIndex = 0;
166
+ const next = async () => {
167
+ if (middlewareIndex < this.middleware.length) {
168
+ const middleware = this.middleware[middlewareIndex++];
169
+ return await middleware(context, next);
170
+ }
171
+ };
172
+ if (this.middleware.length > 0) {
173
+ await next();
174
+ }
175
+ if (res.headersSent) {
176
+ return;
177
+ }
178
+ const match = this.matchRoute(pathname);
179
+ if (!match) {
180
+ res.writeHead(404, { "Content-Type": "text/html" });
181
+ res.end("<h1>404 Not Found</h1>");
182
+ return;
183
+ }
184
+ context.params = match.params;
185
+ const result = await match.handler(context);
186
+ if (res.headersSent) {
187
+ return;
188
+ }
189
+ if (typeof result === "string") {
190
+ res.writeHead(200, this.options.headers);
191
+ res.end(result);
192
+ return;
193
+ }
194
+ if (result && typeof result === "object") {
195
+ if (result.component) {
196
+ const html = await this.renderComponent(
197
+ result.component,
198
+ result.props || {},
199
+ result.options || {}
200
+ );
201
+ res.writeHead(result.status || 200, {
202
+ ...this.options.headers,
203
+ ...result.headers
204
+ });
205
+ res.end(html);
206
+ return;
207
+ }
208
+ if (result.json !== void 0) {
209
+ res.writeHead(result.status || 200, {
210
+ "Content-Type": "application/json",
211
+ ...result.headers
212
+ });
213
+ res.end(JSON.stringify(result.json));
214
+ return;
215
+ }
216
+ if (result.redirect) {
217
+ res.writeHead(result.status || 302, {
218
+ "Location": result.redirect
219
+ });
220
+ res.end();
221
+ return;
222
+ }
223
+ res.writeHead(200, { "Content-Type": "application/json" });
224
+ res.end(JSON.stringify(result));
225
+ return;
226
+ }
227
+ res.writeHead(200, this.options.headers);
228
+ res.end(String(result));
229
+ } catch (error) {
230
+ console.error("Request handling error:", error);
231
+ if (!res.headersSent) {
232
+ res.writeHead(500, { "Content-Type": "application/json" });
233
+ res.end(JSON.stringify({ error: error.message }));
234
+ }
235
+ }
236
+ }
237
+ // Create app factory
238
+ createApp() {
239
+ const app = {
240
+ // Component registration
241
+ component: (name, component) => this.registerComponent(name, component),
242
+ // Routing
243
+ get: (pattern, handler) => this.addRoute(pattern, handler),
244
+ post: (pattern, handler) => this.addRoute(pattern, handler),
245
+ put: (pattern, handler) => this.addRoute(pattern, handler),
246
+ delete: (pattern, handler) => this.addRoute(pattern, handler),
247
+ route: (pattern, handler) => this.addRoute(pattern, handler),
248
+ // Middleware support
249
+ use: (middleware) => {
250
+ if (typeof middleware !== "function") {
251
+ throw new Error("Middleware must be a function");
252
+ }
253
+ this.middleware.push(middleware);
254
+ return app;
255
+ },
256
+ // Server control
257
+ listen: (port, callback) => {
258
+ const serverPort = port || this.options.port;
259
+ this.server = (0, import_http.createServer)((req, res) => this.handleRequest(req, res));
260
+ this.server.listen(serverPort, this.options.host, () => {
261
+ console.log(`Coherent.js Node runtime listening on http://${this.options.host}:${serverPort}`);
262
+ if (callback) callback();
263
+ });
264
+ return this.server;
265
+ },
266
+ close: (callback) => {
267
+ if (this.server) {
268
+ this.server.close(callback);
269
+ }
270
+ },
271
+ // Utilities
272
+ render: (component, props, options) => this.renderComponent(component, props, options),
273
+ getRuntime: () => this,
274
+ getStats: () => ({
275
+ renderCount: this.renderCount,
276
+ cacheSize: this.cache.size,
277
+ componentCount: this.componentRegistry.size,
278
+ routeCount: this.routeRegistry.size,
279
+ middlewareCount: this.middleware.length
280
+ })
281
+ };
282
+ return app;
283
+ }
284
+ // Framework integration helpers
285
+ expressMiddleware() {
286
+ return async (req, res, next) => {
287
+ req.coherent = {
288
+ render: async (component, props, options) => {
289
+ const html = await this.renderComponent(component, props, options);
290
+ res.send(html);
291
+ },
292
+ runtime: this
293
+ };
294
+ next();
295
+ };
296
+ }
297
+ fastifyPlugin() {
298
+ return async (fastify) => {
299
+ fastify.decorate("coherent", {
300
+ render: async (component, props, renderOptions) => {
301
+ return await this.renderComponent(component, props, renderOptions);
302
+ },
303
+ runtime: this
304
+ });
305
+ };
306
+ }
307
+ koaMiddleware() {
308
+ return async (ctx, next) => {
309
+ ctx.coherent = {
310
+ render: async (component, props, options) => {
311
+ const html = await this.renderComponent(component, props, options);
312
+ ctx.type = "html";
313
+ ctx.body = html;
314
+ },
315
+ runtime: this
316
+ };
317
+ await next();
318
+ };
319
+ }
320
+ };
321
+ function createNodeRuntime(options = {}) {
322
+ return new NodeRuntime(options);
323
+ }
324
+ var node_default = NodeRuntime;
325
+ // Annotate the CommonJS export names for ESM import in node:
326
+ 0 && (module.exports = {
327
+ NodeRuntime,
328
+ createNodeRuntime
329
+ });
330
+ //# sourceMappingURL=coherent-node.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/runtimes/node.js"],
4
+ "sourcesContent": ["/**\n * Node.js Runtime - For Node.js with framework integrations\n * Provides server-side rendering with Express, Fastify, Koa support\n */\n\nimport { render } from '@coherent.js/core';\nimport { createServer } from 'http';\n\nexport class NodeRuntime {\n constructor(options = {}) {\n this.options = {\n port: 3000,\n host: 'localhost',\n caching: true,\n framework: null, // 'express', 'fastify', 'koa', or null for standalone\n headers: {\n 'Content-Type': 'text/html; charset=utf-8',\n 'Cache-Control': 'public, max-age=3600',\n ...options.headers\n },\n ...options\n };\n \n this.componentRegistry = new Map();\n this.routeRegistry = new Map();\n this.middleware = [];\n this.cache = new Map();\n this.renderCount = 0;\n this.server = null;\n \n // Initialize cache cleanup if caching is enabled\n if (this.options.caching) {\n this.initializeCacheCleanup();\n }\n }\n\n initializeCacheCleanup() {\n // Simple LRU-style cleanup\n setInterval(() => {\n if (this.cache.size > 1000) {\n const entries = Array.from(this.cache.entries());\n const toDelete = entries.slice(0, entries.length - 500);\n toDelete.forEach(([key]) => this.cache.delete(key));\n }\n }, 300000); // Every 5 minutes\n }\n\n // Component management\n registerComponent(name, component) {\n this.componentRegistry.set(name, component);\n return component;\n }\n\n getComponent(name) {\n return this.componentRegistry.get(name);\n }\n\n // Route management\n addRoute(pattern, handler) {\n this.routeRegistry.set(pattern, handler);\n }\n\n matchRoute(pathname) {\n for (const [pattern, handler] of this.routeRegistry.entries()) {\n const match = this.matchPattern(pattern, pathname);\n if (match) {\n return { handler, params: match.params };\n }\n }\n return null;\n }\n\n matchPattern(pattern, pathname) {\n const patternParts = pattern.split('/').filter(Boolean);\n const pathParts = pathname.split('/').filter(Boolean);\n\n if (patternParts.length !== pathParts.length) {\n return null;\n }\n\n const params = {};\n \n for (let i = 0; i < patternParts.length; i++) {\n const patternPart = patternParts[i];\n const pathPart = pathParts[i];\n\n if (patternPart.startsWith(':')) {\n params[patternPart.slice(1)] = pathPart;\n } else if (patternPart !== pathPart) {\n return null;\n }\n }\n\n return { params };\n }\n\n // Rendering\n async renderComponent(component, props = {}, options = {}) {\n \n try {\n // Resolve component\n const resolvedComponent = typeof component === 'string' \n ? this.getComponent(component) \n : component;\n\n if (!resolvedComponent) {\n throw new Error(`Component not found: ${component}`);\n }\n\n // Check cache\n const cacheKey = this.generateCacheKey(resolvedComponent, props);\n if (this.options.caching && this.cache.has(cacheKey)) {\n const cached = this.cache.get(cacheKey);\n if (Date.now() - cached.timestamp < (options.cacheMaxAge || 300000)) {\n return cached.html;\n }\n this.cache.delete(cacheKey);\n }\n\n // Render component\n const vdom = resolvedComponent(props);\n const html = render(vdom);\n\n // Cache result\n if (this.options.caching && options.cacheable !== false) {\n this.cache.set(cacheKey, {\n html,\n timestamp: Date.now()\n });\n }\n\n this.renderCount++;\n \n return html;\n } catch (error) {\n console.error('Node render error:', error);\n throw error;\n }\n }\n\n generateCacheKey(component, props) {\n const componentName = component.name || 'anonymous';\n const propsHash = this.hashObject(props);\n return `${componentName}-${propsHash}`;\n }\n\n hashObject(obj) {\n const str = JSON.stringify(obj, Object.keys(obj).sort());\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash;\n }\n return hash.toString(36);\n }\n\n // HTTP Request handling (for standalone mode)\n async handleRequest(req, res) {\n try {\n const url = new URL(req.url, `http://${req.headers.host}`);\n const pathname = url.pathname;\n \n // Create context\n const context = {\n req,\n res,\n url,\n pathname,\n params: {},\n query: Object.fromEntries(url.searchParams),\n method: req.method,\n headers: req.headers,\n runtime: this,\n state: {}\n };\n\n // Execute middleware chain\n let middlewareIndex = 0;\n const next = async () => {\n if (middlewareIndex < this.middleware.length) {\n const middleware = this.middleware[middlewareIndex++];\n return await middleware(context, next);\n }\n };\n\n // Run middleware\n if (this.middleware.length > 0) {\n await next();\n }\n\n // Check if middleware already sent a response\n if (res.headersSent) {\n return;\n }\n \n // Find matching route\n const match = this.matchRoute(pathname);\n \n if (!match) {\n res.writeHead(404, { 'Content-Type': 'text/html' });\n res.end('<h1>404 Not Found</h1>');\n return;\n }\n\n // Add route params to context\n context.params = match.params;\n\n // Execute route handler\n const result = await match.handler(context);\n \n // Handle different response types\n if (res.headersSent) {\n return; // Handler already sent response\n }\n\n if (typeof result === 'string') {\n res.writeHead(200, this.options.headers);\n res.end(result);\n return;\n }\n\n if (result && typeof result === 'object') {\n if (result.component) {\n const html = await this.renderComponent(\n result.component, \n result.props || {}, \n result.options || {}\n );\n res.writeHead(result.status || 200, {\n ...this.options.headers,\n ...result.headers\n });\n res.end(html);\n return;\n }\n\n if (result.json !== undefined) {\n res.writeHead(result.status || 200, {\n 'Content-Type': 'application/json',\n ...result.headers\n });\n res.end(JSON.stringify(result.json));\n return;\n }\n\n if (result.redirect) {\n res.writeHead(result.status || 302, {\n 'Location': result.redirect\n });\n res.end();\n return;\n }\n\n // Default: send as JSON\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(result));\n return;\n }\n\n // Fallback\n res.writeHead(200, this.options.headers);\n res.end(String(result));\n\n } catch (error) {\n console.error('Request handling error:', error);\n \n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: error.message }));\n }\n }\n }\n\n // Create app factory\n createApp() {\n const app = {\n // Component registration\n component: (name, component) => this.registerComponent(name, component),\n \n // Routing\n get: (pattern, handler) => this.addRoute(pattern, handler),\n post: (pattern, handler) => this.addRoute(pattern, handler),\n put: (pattern, handler) => this.addRoute(pattern, handler),\n delete: (pattern, handler) => this.addRoute(pattern, handler),\n route: (pattern, handler) => this.addRoute(pattern, handler),\n \n // Middleware support\n use: (middleware) => {\n if (typeof middleware !== 'function') {\n throw new Error('Middleware must be a function');\n }\n this.middleware.push(middleware);\n return app;\n },\n \n // Server control\n listen: (port, callback) => {\n const serverPort = port || this.options.port;\n this.server = createServer((req, res) => this.handleRequest(req, res));\n \n this.server.listen(serverPort, this.options.host, () => {\n console.log(`Coherent.js Node runtime listening on http://${this.options.host}:${serverPort}`);\n if (callback) callback();\n });\n \n return this.server;\n },\n \n close: (callback) => {\n if (this.server) {\n this.server.close(callback);\n }\n },\n \n // Utilities\n render: (component, props, options) => this.renderComponent(component, props, options),\n getRuntime: () => this,\n getStats: () => ({\n renderCount: this.renderCount,\n cacheSize: this.cache.size,\n componentCount: this.componentRegistry.size,\n routeCount: this.routeRegistry.size,\n middlewareCount: this.middleware.length\n })\n };\n\n return app;\n }\n\n // Framework integration helpers\n expressMiddleware() {\n return async (req, res, next) => {\n req.coherent = {\n render: async (component, props, options) => {\n const html = await this.renderComponent(component, props, options);\n res.send(html);\n },\n runtime: this\n };\n next();\n };\n }\n\n fastifyPlugin() {\n return async (fastify) => {\n fastify.decorate('coherent', {\n render: async (component, props, renderOptions) => {\n return await this.renderComponent(component, props, renderOptions);\n },\n runtime: this\n });\n };\n }\n\n koaMiddleware() {\n return async (ctx, next) => {\n ctx.coherent = {\n render: async (component, props, options) => {\n const html = await this.renderComponent(component, props, options);\n ctx.type = 'html';\n ctx.body = html;\n },\n runtime: this\n };\n await next();\n };\n }\n}\n\n/**\n * Create a Node.js runtime instance\n */\nexport function createNodeRuntime(options = {}) {\n return new NodeRuntime(options);\n}\n\nexport default NodeRuntime;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,kBAAuB;AACvB,kBAA6B;AAEtB,IAAM,cAAN,MAAkB;AAAA,EACvB,YAAY,UAAU,CAAC,GAAG;AACxB,SAAK,UAAU;AAAA,MACb,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,WAAW;AAAA;AAAA,MACX,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,iBAAiB;AAAA,QACjB,GAAG,QAAQ;AAAA,MACb;AAAA,MACA,GAAG;AAAA,IACL;AAEA,SAAK,oBAAoB,oBAAI,IAAI;AACjC,SAAK,gBAAgB,oBAAI,IAAI;AAC7B,SAAK,aAAa,CAAC;AACnB,SAAK,QAAQ,oBAAI,IAAI;AACrB,SAAK,cAAc;AACnB,SAAK,SAAS;AAGd,QAAI,KAAK,QAAQ,SAAS;AACxB,WAAK,uBAAuB;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,yBAAyB;AAEvB,gBAAY,MAAM;AAChB,UAAI,KAAK,MAAM,OAAO,KAAM;AAC1B,cAAM,UAAU,MAAM,KAAK,KAAK,MAAM,QAAQ,CAAC;AAC/C,cAAM,WAAW,QAAQ,MAAM,GAAG,QAAQ,SAAS,GAAG;AACtD,iBAAS,QAAQ,CAAC,CAAC,GAAG,MAAM,KAAK,MAAM,OAAO,GAAG,CAAC;AAAA,MACpD;AAAA,IACF,GAAG,GAAM;AAAA,EACX;AAAA;AAAA,EAGA,kBAAkB,MAAM,WAAW;AACjC,SAAK,kBAAkB,IAAI,MAAM,SAAS;AAC1C,WAAO;AAAA,EACT;AAAA,EAEA,aAAa,MAAM;AACjB,WAAO,KAAK,kBAAkB,IAAI,IAAI;AAAA,EACxC;AAAA;AAAA,EAGA,SAAS,SAAS,SAAS;AACzB,SAAK,cAAc,IAAI,SAAS,OAAO;AAAA,EACzC;AAAA,EAEA,WAAW,UAAU;AACnB,eAAW,CAAC,SAAS,OAAO,KAAK,KAAK,cAAc,QAAQ,GAAG;AAC7D,YAAM,QAAQ,KAAK,aAAa,SAAS,QAAQ;AACjD,UAAI,OAAO;AACT,eAAO,EAAE,SAAS,QAAQ,MAAM,OAAO;AAAA,MACzC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,aAAa,SAAS,UAAU;AAC9B,UAAM,eAAe,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AACtD,UAAM,YAAY,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AAEpD,QAAI,aAAa,WAAW,UAAU,QAAQ;AAC5C,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,CAAC;AAEhB,aAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,YAAM,cAAc,aAAa,CAAC;AAClC,YAAM,WAAW,UAAU,CAAC;AAE5B,UAAI,YAAY,WAAW,GAAG,GAAG;AAC/B,eAAO,YAAY,MAAM,CAAC,CAAC,IAAI;AAAA,MACjC,WAAW,gBAAgB,UAAU;AACnC,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO,EAAE,OAAO;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,gBAAgB,WAAW,QAAQ,CAAC,GAAG,UAAU,CAAC,GAAG;AAEzD,QAAI;AAEF,YAAM,oBAAoB,OAAO,cAAc,WAC3C,KAAK,aAAa,SAAS,IAC3B;AAEJ,UAAI,CAAC,mBAAmB;AACtB,cAAM,IAAI,MAAM,wBAAwB,SAAS,EAAE;AAAA,MACrD;AAGA,YAAM,WAAW,KAAK,iBAAiB,mBAAmB,KAAK;AAC/D,UAAI,KAAK,QAAQ,WAAW,KAAK,MAAM,IAAI,QAAQ,GAAG;AACpD,cAAM,SAAS,KAAK,MAAM,IAAI,QAAQ;AACtC,YAAI,KAAK,IAAI,IAAI,OAAO,aAAa,QAAQ,eAAe,MAAS;AACnE,iBAAO,OAAO;AAAA,QAChB;AACA,aAAK,MAAM,OAAO,QAAQ;AAAA,MAC5B;AAGA,YAAM,OAAO,kBAAkB,KAAK;AACpC,YAAM,WAAO,oBAAO,IAAI;AAGxB,UAAI,KAAK,QAAQ,WAAW,QAAQ,cAAc,OAAO;AACvD,aAAK,MAAM,IAAI,UAAU;AAAA,UACvB;AAAA,UACA,WAAW,KAAK,IAAI;AAAA,QACtB,CAAC;AAAA,MACH;AAEA,WAAK;AAEL,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ,MAAM,sBAAsB,KAAK;AACzC,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,iBAAiB,WAAW,OAAO;AACjC,UAAM,gBAAgB,UAAU,QAAQ;AACxC,UAAM,YAAY,KAAK,WAAW,KAAK;AACvC,WAAO,GAAG,aAAa,IAAI,SAAS;AAAA,EACtC;AAAA,EAEA,WAAW,KAAK;AACd,UAAM,MAAM,KAAK,UAAU,KAAK,OAAO,KAAK,GAAG,EAAE,KAAK,CAAC;AACvD,QAAI,OAAO;AACX,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,YAAM,OAAO,IAAI,WAAW,CAAC;AAC7B,cAAS,QAAQ,KAAK,OAAQ;AAC9B,aAAO,OAAO;AAAA,IAChB;AACA,WAAO,KAAK,SAAS,EAAE;AAAA,EACzB;AAAA;AAAA,EAGA,MAAM,cAAc,KAAK,KAAK;AAC5B,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,IAAI,KAAK,UAAU,IAAI,QAAQ,IAAI,EAAE;AACzD,YAAM,WAAW,IAAI;AAGrB,YAAM,UAAU;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,CAAC;AAAA,QACT,OAAO,OAAO,YAAY,IAAI,YAAY;AAAA,QAC1C,QAAQ,IAAI;AAAA,QACZ,SAAS,IAAI;AAAA,QACb,SAAS;AAAA,QACT,OAAO,CAAC;AAAA,MACV;AAGA,UAAI,kBAAkB;AACtB,YAAM,OAAO,YAAY;AACvB,YAAI,kBAAkB,KAAK,WAAW,QAAQ;AAC5C,gBAAM,aAAa,KAAK,WAAW,iBAAiB;AACpD,iBAAO,MAAM,WAAW,SAAS,IAAI;AAAA,QACvC;AAAA,MACF;AAGA,UAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,cAAM,KAAK;AAAA,MACb;AAGA,UAAI,IAAI,aAAa;AACnB;AAAA,MACF;AAGA,YAAM,QAAQ,KAAK,WAAW,QAAQ;AAEtC,UAAI,CAAC,OAAO;AACV,YAAI,UAAU,KAAK,EAAE,gBAAgB,YAAY,CAAC;AAClD,YAAI,IAAI,wBAAwB;AAChC;AAAA,MACF;AAGA,cAAQ,SAAS,MAAM;AAGvB,YAAM,SAAS,MAAM,MAAM,QAAQ,OAAO;AAG1C,UAAI,IAAI,aAAa;AACnB;AAAA,MACF;AAEA,UAAI,OAAO,WAAW,UAAU;AAC9B,YAAI,UAAU,KAAK,KAAK,QAAQ,OAAO;AACvC,YAAI,IAAI,MAAM;AACd;AAAA,MACF;AAEA,UAAI,UAAU,OAAO,WAAW,UAAU;AACxC,YAAI,OAAO,WAAW;AACpB,gBAAM,OAAO,MAAM,KAAK;AAAA,YACtB,OAAO;AAAA,YACP,OAAO,SAAS,CAAC;AAAA,YACjB,OAAO,WAAW,CAAC;AAAA,UACrB;AACA,cAAI,UAAU,OAAO,UAAU,KAAK;AAAA,YAClC,GAAG,KAAK,QAAQ;AAAA,YAChB,GAAG,OAAO;AAAA,UACZ,CAAC;AACD,cAAI,IAAI,IAAI;AACZ;AAAA,QACF;AAEA,YAAI,OAAO,SAAS,QAAW;AAC7B,cAAI,UAAU,OAAO,UAAU,KAAK;AAAA,YAClC,gBAAgB;AAAA,YAChB,GAAG,OAAO;AAAA,UACZ,CAAC;AACD,cAAI,IAAI,KAAK,UAAU,OAAO,IAAI,CAAC;AACnC;AAAA,QACF;AAEA,YAAI,OAAO,UAAU;AACnB,cAAI,UAAU,OAAO,UAAU,KAAK;AAAA,YAClC,YAAY,OAAO;AAAA,UACrB,CAAC;AACD,cAAI,IAAI;AACR;AAAA,QACF;AAGA,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI,IAAI,KAAK,UAAU,MAAM,CAAC;AAC9B;AAAA,MACF;AAGA,UAAI,UAAU,KAAK,KAAK,QAAQ,OAAO;AACvC,UAAI,IAAI,OAAO,MAAM,CAAC;AAAA,IAExB,SAAS,OAAO;AACd,cAAQ,MAAM,2BAA2B,KAAK;AAE9C,UAAI,CAAC,IAAI,aAAa;AACpB,YAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,YAAI,IAAI,KAAK,UAAU,EAAE,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,YAAY;AACV,UAAM,MAAM;AAAA;AAAA,MAEV,WAAW,CAAC,MAAM,cAAc,KAAK,kBAAkB,MAAM,SAAS;AAAA;AAAA,MAGtE,KAAK,CAAC,SAAS,YAAY,KAAK,SAAS,SAAS,OAAO;AAAA,MACzD,MAAM,CAAC,SAAS,YAAY,KAAK,SAAS,SAAS,OAAO;AAAA,MAC1D,KAAK,CAAC,SAAS,YAAY,KAAK,SAAS,SAAS,OAAO;AAAA,MACzD,QAAQ,CAAC,SAAS,YAAY,KAAK,SAAS,SAAS,OAAO;AAAA,MAC5D,OAAO,CAAC,SAAS,YAAY,KAAK,SAAS,SAAS,OAAO;AAAA;AAAA,MAG3D,KAAK,CAAC,eAAe;AACnB,YAAI,OAAO,eAAe,YAAY;AACpC,gBAAM,IAAI,MAAM,+BAA+B;AAAA,QACjD;AACA,aAAK,WAAW,KAAK,UAAU;AAC/B,eAAO;AAAA,MACT;AAAA;AAAA,MAGA,QAAQ,CAAC,MAAM,aAAa;AAC1B,cAAM,aAAa,QAAQ,KAAK,QAAQ;AACxC,aAAK,aAAS,0BAAa,CAAC,KAAK,QAAQ,KAAK,cAAc,KAAK,GAAG,CAAC;AAErE,aAAK,OAAO,OAAO,YAAY,KAAK,QAAQ,MAAM,MAAM;AACtD,kBAAQ,IAAI,gDAAgD,KAAK,QAAQ,IAAI,IAAI,UAAU,EAAE;AAC7F,cAAI,SAAU,UAAS;AAAA,QACzB,CAAC;AAED,eAAO,KAAK;AAAA,MACd;AAAA,MAEA,OAAO,CAAC,aAAa;AACnB,YAAI,KAAK,QAAQ;AACf,eAAK,OAAO,MAAM,QAAQ;AAAA,QAC5B;AAAA,MACF;AAAA;AAAA,MAGA,QAAQ,CAAC,WAAW,OAAO,YAAY,KAAK,gBAAgB,WAAW,OAAO,OAAO;AAAA,MACrF,YAAY,MAAM;AAAA,MAClB,UAAU,OAAO;AAAA,QACf,aAAa,KAAK;AAAA,QAClB,WAAW,KAAK,MAAM;AAAA,QACtB,gBAAgB,KAAK,kBAAkB;AAAA,QACvC,YAAY,KAAK,cAAc;AAAA,QAC/B,iBAAiB,KAAK,WAAW;AAAA,MACnC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,oBAAoB;AAClB,WAAO,OAAO,KAAK,KAAK,SAAS;AAC/B,UAAI,WAAW;AAAA,QACb,QAAQ,OAAO,WAAW,OAAO,YAAY;AAC3C,gBAAM,OAAO,MAAM,KAAK,gBAAgB,WAAW,OAAO,OAAO;AACjE,cAAI,KAAK,IAAI;AAAA,QACf;AAAA,QACA,SAAS;AAAA,MACX;AACA,WAAK;AAAA,IACP;AAAA,EACF;AAAA,EAEA,gBAAgB;AACd,WAAO,OAAO,YAAY;AACxB,cAAQ,SAAS,YAAY;AAAA,QAC3B,QAAQ,OAAO,WAAW,OAAO,kBAAkB;AACjD,iBAAO,MAAM,KAAK,gBAAgB,WAAW,OAAO,aAAa;AAAA,QACnE;AAAA,QACA,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,gBAAgB;AACd,WAAO,OAAO,KAAK,SAAS;AAC1B,UAAI,WAAW;AAAA,QACb,QAAQ,OAAO,WAAW,OAAO,YAAY;AAC3C,gBAAM,OAAO,MAAM,KAAK,gBAAgB,WAAW,OAAO,OAAO;AACjE,cAAI,OAAO;AACX,cAAI,OAAO;AAAA,QACb;AAAA,QACA,SAAS;AAAA,MACX;AACA,YAAM,KAAK;AAAA,IACb;AAAA,EACF;AACF;AAKO,SAAS,kBAAkB,UAAU,CAAC,GAAG;AAC9C,SAAO,IAAI,YAAY,OAAO;AAChC;AAEA,IAAO,eAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,304 @@
1
+ // src/runtimes/node.js
2
+ import { render } from "@coherent.js/core";
3
+ import { createServer } from "http";
4
+ var NodeRuntime = class {
5
+ constructor(options = {}) {
6
+ this.options = {
7
+ port: 3e3,
8
+ host: "localhost",
9
+ caching: true,
10
+ framework: null,
11
+ // 'express', 'fastify', 'koa', or null for standalone
12
+ headers: {
13
+ "Content-Type": "text/html; charset=utf-8",
14
+ "Cache-Control": "public, max-age=3600",
15
+ ...options.headers
16
+ },
17
+ ...options
18
+ };
19
+ this.componentRegistry = /* @__PURE__ */ new Map();
20
+ this.routeRegistry = /* @__PURE__ */ new Map();
21
+ this.middleware = [];
22
+ this.cache = /* @__PURE__ */ new Map();
23
+ this.renderCount = 0;
24
+ this.server = null;
25
+ if (this.options.caching) {
26
+ this.initializeCacheCleanup();
27
+ }
28
+ }
29
+ initializeCacheCleanup() {
30
+ setInterval(() => {
31
+ if (this.cache.size > 1e3) {
32
+ const entries = Array.from(this.cache.entries());
33
+ const toDelete = entries.slice(0, entries.length - 500);
34
+ toDelete.forEach(([key]) => this.cache.delete(key));
35
+ }
36
+ }, 3e5);
37
+ }
38
+ // Component management
39
+ registerComponent(name, component) {
40
+ this.componentRegistry.set(name, component);
41
+ return component;
42
+ }
43
+ getComponent(name) {
44
+ return this.componentRegistry.get(name);
45
+ }
46
+ // Route management
47
+ addRoute(pattern, handler) {
48
+ this.routeRegistry.set(pattern, handler);
49
+ }
50
+ matchRoute(pathname) {
51
+ for (const [pattern, handler] of this.routeRegistry.entries()) {
52
+ const match = this.matchPattern(pattern, pathname);
53
+ if (match) {
54
+ return { handler, params: match.params };
55
+ }
56
+ }
57
+ return null;
58
+ }
59
+ matchPattern(pattern, pathname) {
60
+ const patternParts = pattern.split("/").filter(Boolean);
61
+ const pathParts = pathname.split("/").filter(Boolean);
62
+ if (patternParts.length !== pathParts.length) {
63
+ return null;
64
+ }
65
+ const params = {};
66
+ for (let i = 0; i < patternParts.length; i++) {
67
+ const patternPart = patternParts[i];
68
+ const pathPart = pathParts[i];
69
+ if (patternPart.startsWith(":")) {
70
+ params[patternPart.slice(1)] = pathPart;
71
+ } else if (patternPart !== pathPart) {
72
+ return null;
73
+ }
74
+ }
75
+ return { params };
76
+ }
77
+ // Rendering
78
+ async renderComponent(component, props = {}, options = {}) {
79
+ try {
80
+ const resolvedComponent = typeof component === "string" ? this.getComponent(component) : component;
81
+ if (!resolvedComponent) {
82
+ throw new Error(`Component not found: ${component}`);
83
+ }
84
+ const cacheKey = this.generateCacheKey(resolvedComponent, props);
85
+ if (this.options.caching && this.cache.has(cacheKey)) {
86
+ const cached = this.cache.get(cacheKey);
87
+ if (Date.now() - cached.timestamp < (options.cacheMaxAge || 3e5)) {
88
+ return cached.html;
89
+ }
90
+ this.cache.delete(cacheKey);
91
+ }
92
+ const vdom = resolvedComponent(props);
93
+ const html = render(vdom);
94
+ if (this.options.caching && options.cacheable !== false) {
95
+ this.cache.set(cacheKey, {
96
+ html,
97
+ timestamp: Date.now()
98
+ });
99
+ }
100
+ this.renderCount++;
101
+ return html;
102
+ } catch (error) {
103
+ console.error("Node render error:", error);
104
+ throw error;
105
+ }
106
+ }
107
+ generateCacheKey(component, props) {
108
+ const componentName = component.name || "anonymous";
109
+ const propsHash = this.hashObject(props);
110
+ return `${componentName}-${propsHash}`;
111
+ }
112
+ hashObject(obj) {
113
+ const str = JSON.stringify(obj, Object.keys(obj).sort());
114
+ let hash = 0;
115
+ for (let i = 0; i < str.length; i++) {
116
+ const char = str.charCodeAt(i);
117
+ hash = (hash << 5) - hash + char;
118
+ hash = hash & hash;
119
+ }
120
+ return hash.toString(36);
121
+ }
122
+ // HTTP Request handling (for standalone mode)
123
+ async handleRequest(req, res) {
124
+ try {
125
+ const url = new URL(req.url, `http://${req.headers.host}`);
126
+ const pathname = url.pathname;
127
+ const context = {
128
+ req,
129
+ res,
130
+ url,
131
+ pathname,
132
+ params: {},
133
+ query: Object.fromEntries(url.searchParams),
134
+ method: req.method,
135
+ headers: req.headers,
136
+ runtime: this,
137
+ state: {}
138
+ };
139
+ let middlewareIndex = 0;
140
+ const next = async () => {
141
+ if (middlewareIndex < this.middleware.length) {
142
+ const middleware = this.middleware[middlewareIndex++];
143
+ return await middleware(context, next);
144
+ }
145
+ };
146
+ if (this.middleware.length > 0) {
147
+ await next();
148
+ }
149
+ if (res.headersSent) {
150
+ return;
151
+ }
152
+ const match = this.matchRoute(pathname);
153
+ if (!match) {
154
+ res.writeHead(404, { "Content-Type": "text/html" });
155
+ res.end("<h1>404 Not Found</h1>");
156
+ return;
157
+ }
158
+ context.params = match.params;
159
+ const result = await match.handler(context);
160
+ if (res.headersSent) {
161
+ return;
162
+ }
163
+ if (typeof result === "string") {
164
+ res.writeHead(200, this.options.headers);
165
+ res.end(result);
166
+ return;
167
+ }
168
+ if (result && typeof result === "object") {
169
+ if (result.component) {
170
+ const html = await this.renderComponent(
171
+ result.component,
172
+ result.props || {},
173
+ result.options || {}
174
+ );
175
+ res.writeHead(result.status || 200, {
176
+ ...this.options.headers,
177
+ ...result.headers
178
+ });
179
+ res.end(html);
180
+ return;
181
+ }
182
+ if (result.json !== void 0) {
183
+ res.writeHead(result.status || 200, {
184
+ "Content-Type": "application/json",
185
+ ...result.headers
186
+ });
187
+ res.end(JSON.stringify(result.json));
188
+ return;
189
+ }
190
+ if (result.redirect) {
191
+ res.writeHead(result.status || 302, {
192
+ "Location": result.redirect
193
+ });
194
+ res.end();
195
+ return;
196
+ }
197
+ res.writeHead(200, { "Content-Type": "application/json" });
198
+ res.end(JSON.stringify(result));
199
+ return;
200
+ }
201
+ res.writeHead(200, this.options.headers);
202
+ res.end(String(result));
203
+ } catch (error) {
204
+ console.error("Request handling error:", error);
205
+ if (!res.headersSent) {
206
+ res.writeHead(500, { "Content-Type": "application/json" });
207
+ res.end(JSON.stringify({ error: error.message }));
208
+ }
209
+ }
210
+ }
211
+ // Create app factory
212
+ createApp() {
213
+ const app = {
214
+ // Component registration
215
+ component: (name, component) => this.registerComponent(name, component),
216
+ // Routing
217
+ get: (pattern, handler) => this.addRoute(pattern, handler),
218
+ post: (pattern, handler) => this.addRoute(pattern, handler),
219
+ put: (pattern, handler) => this.addRoute(pattern, handler),
220
+ delete: (pattern, handler) => this.addRoute(pattern, handler),
221
+ route: (pattern, handler) => this.addRoute(pattern, handler),
222
+ // Middleware support
223
+ use: (middleware) => {
224
+ if (typeof middleware !== "function") {
225
+ throw new Error("Middleware must be a function");
226
+ }
227
+ this.middleware.push(middleware);
228
+ return app;
229
+ },
230
+ // Server control
231
+ listen: (port, callback) => {
232
+ const serverPort = port || this.options.port;
233
+ this.server = createServer((req, res) => this.handleRequest(req, res));
234
+ this.server.listen(serverPort, this.options.host, () => {
235
+ console.log(`Coherent.js Node runtime listening on http://${this.options.host}:${serverPort}`);
236
+ if (callback) callback();
237
+ });
238
+ return this.server;
239
+ },
240
+ close: (callback) => {
241
+ if (this.server) {
242
+ this.server.close(callback);
243
+ }
244
+ },
245
+ // Utilities
246
+ render: (component, props, options) => this.renderComponent(component, props, options),
247
+ getRuntime: () => this,
248
+ getStats: () => ({
249
+ renderCount: this.renderCount,
250
+ cacheSize: this.cache.size,
251
+ componentCount: this.componentRegistry.size,
252
+ routeCount: this.routeRegistry.size,
253
+ middlewareCount: this.middleware.length
254
+ })
255
+ };
256
+ return app;
257
+ }
258
+ // Framework integration helpers
259
+ expressMiddleware() {
260
+ return async (req, res, next) => {
261
+ req.coherent = {
262
+ render: async (component, props, options) => {
263
+ const html = await this.renderComponent(component, props, options);
264
+ res.send(html);
265
+ },
266
+ runtime: this
267
+ };
268
+ next();
269
+ };
270
+ }
271
+ fastifyPlugin() {
272
+ return async (fastify) => {
273
+ fastify.decorate("coherent", {
274
+ render: async (component, props, renderOptions) => {
275
+ return await this.renderComponent(component, props, renderOptions);
276
+ },
277
+ runtime: this
278
+ });
279
+ };
280
+ }
281
+ koaMiddleware() {
282
+ return async (ctx, next) => {
283
+ ctx.coherent = {
284
+ render: async (component, props, options) => {
285
+ const html = await this.renderComponent(component, props, options);
286
+ ctx.type = "html";
287
+ ctx.body = html;
288
+ },
289
+ runtime: this
290
+ };
291
+ await next();
292
+ };
293
+ }
294
+ };
295
+ function createNodeRuntime(options = {}) {
296
+ return new NodeRuntime(options);
297
+ }
298
+ var node_default = NodeRuntime;
299
+ export {
300
+ NodeRuntime,
301
+ createNodeRuntime,
302
+ node_default as default
303
+ };
304
+ //# sourceMappingURL=coherent-node.js.map