@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.
- package/LICENSE +21 -0
- package/README.md +1119 -0
- package/dist/coherent-browser.cjs +304 -0
- package/dist/coherent-browser.cjs.map +7 -0
- package/dist/coherent-browser.js +279 -0
- package/dist/coherent-browser.js.map +7 -0
- package/dist/coherent-edge.cjs +458 -0
- package/dist/coherent-edge.cjs.map +7 -0
- package/dist/coherent-edge.js +430 -0
- package/dist/coherent-edge.js.map +7 -0
- package/dist/coherent-node.cjs +330 -0
- package/dist/coherent-node.cjs.map +7 -0
- package/dist/coherent-node.js +304 -0
- package/dist/coherent-node.js.map +7 -0
- package/dist/coherent-standalone.esm.js +279 -0
- package/dist/coherent-standalone.esm.js.map +7 -0
- package/dist/coherent-standalone.js +2 -0
- package/dist/coherent-standalone.js.map +7 -0
- package/dist/coherent-static.cjs +356 -0
- package/dist/coherent-static.cjs.map +7 -0
- package/dist/coherent-static.js +331 -0
- package/dist/coherent-static.js.map +7 -0
- package/dist/coherent-universal.cjs +3294 -0
- package/dist/coherent-universal.cjs.map +7 -0
- package/dist/coherent-universal.js +3254 -0
- package/dist/coherent-universal.js.map +7 -0
- package/dist/coherent-universal.min.js +2 -0
- package/dist/coherent-universal.min.js.map +7 -0
- package/package.json +92 -0
- package/types/browser.d.ts +2 -0
- package/types/edge.d.ts +2 -0
- package/types/index.d.ts +118 -0
- package/types/static.d.ts +2 -0
|
@@ -0,0 +1,3294 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
25
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
26
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
27
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
28
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
29
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
30
|
+
mod
|
|
31
|
+
));
|
|
32
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
33
|
+
|
|
34
|
+
// src/runtimes/browser.js
|
|
35
|
+
var browser_exports = {};
|
|
36
|
+
__export(browser_exports, {
|
|
37
|
+
BrowserRuntime: () => BrowserRuntime
|
|
38
|
+
});
|
|
39
|
+
var import_core, import_client, import_web_components, BrowserRuntime;
|
|
40
|
+
var init_browser = __esm({
|
|
41
|
+
"src/runtimes/browser.js"() {
|
|
42
|
+
"use strict";
|
|
43
|
+
import_core = require("@coherent.js/core");
|
|
44
|
+
import_client = require("@coherent.js/client");
|
|
45
|
+
import_web_components = require("@coherent.js/web-components");
|
|
46
|
+
BrowserRuntime = class _BrowserRuntime {
|
|
47
|
+
constructor(options = {}) {
|
|
48
|
+
this.options = {
|
|
49
|
+
autoHydrate: true,
|
|
50
|
+
enableWebComponents: true,
|
|
51
|
+
enablePerformanceMonitoring: true,
|
|
52
|
+
routingMode: "hash",
|
|
53
|
+
// 'hash', 'history', or 'memory'
|
|
54
|
+
...options
|
|
55
|
+
};
|
|
56
|
+
this.componentRegistry = /* @__PURE__ */ new Map();
|
|
57
|
+
this.routeRegistry = /* @__PURE__ */ new Map();
|
|
58
|
+
this.currentRoute = null;
|
|
59
|
+
this.isInitialized = false;
|
|
60
|
+
this.renderMetrics = [];
|
|
61
|
+
this.startTime = Date.now();
|
|
62
|
+
}
|
|
63
|
+
async initialize() {
|
|
64
|
+
if (this.isInitialized) return;
|
|
65
|
+
if (document.readyState === "loading") {
|
|
66
|
+
await new Promise((resolve) => {
|
|
67
|
+
document.addEventListener("DOMContentLoaded", resolve);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (this.options.enableWebComponents) {
|
|
71
|
+
await this.initializeWebComponents();
|
|
72
|
+
}
|
|
73
|
+
if (this.options.routingMode !== "none") {
|
|
74
|
+
this.initializeRouting();
|
|
75
|
+
}
|
|
76
|
+
if (this.options.autoHydrate) {
|
|
77
|
+
await this.autoHydrate();
|
|
78
|
+
}
|
|
79
|
+
if (this.options.enablePerformanceMonitoring) {
|
|
80
|
+
this.initializePerformanceMonitoring();
|
|
81
|
+
}
|
|
82
|
+
this.isInitialized = true;
|
|
83
|
+
}
|
|
84
|
+
async initializeWebComponents() {
|
|
85
|
+
try {
|
|
86
|
+
await (0, import_web_components.integrateWithWebComponents)(
|
|
87
|
+
Object.fromEntries(this.componentRegistry),
|
|
88
|
+
this.options.webComponents || {}
|
|
89
|
+
);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.warn("Failed to initialize Web Components:", error);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
initializeRouting() {
|
|
95
|
+
const handleRouteChange = () => {
|
|
96
|
+
const newRoute = this.getCurrentRoute();
|
|
97
|
+
if (newRoute !== this.currentRoute) {
|
|
98
|
+
this.handleRouteChange(this.currentRoute, newRoute);
|
|
99
|
+
this.currentRoute = newRoute;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
if (this.options.routingMode === "hash") {
|
|
103
|
+
window.addEventListener("hashchange", handleRouteChange);
|
|
104
|
+
} else if (this.options.routingMode === "history") {
|
|
105
|
+
window.addEventListener("popstate", handleRouteChange);
|
|
106
|
+
}
|
|
107
|
+
this.currentRoute = this.getCurrentRoute();
|
|
108
|
+
handleRouteChange();
|
|
109
|
+
}
|
|
110
|
+
getCurrentRoute() {
|
|
111
|
+
if (this.options.routingMode === "hash") {
|
|
112
|
+
return window.location.hash.slice(1) || "/";
|
|
113
|
+
} else if (this.options.routingMode === "history") {
|
|
114
|
+
return window.location.pathname;
|
|
115
|
+
}
|
|
116
|
+
return "/";
|
|
117
|
+
}
|
|
118
|
+
handleRouteChange(oldRoute, newRoute) {
|
|
119
|
+
const handler = this.routeRegistry.get(newRoute) || this.routeRegistry.get("*");
|
|
120
|
+
if (handler) {
|
|
121
|
+
try {
|
|
122
|
+
handler({ route: newRoute, oldRoute, params: this.parseRouteParams(newRoute) });
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error("Route handler error:", error);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
parseRouteParams(route) {
|
|
129
|
+
const params = {};
|
|
130
|
+
const parts = route.split("/").filter(Boolean);
|
|
131
|
+
parts.forEach((part, index) => {
|
|
132
|
+
if (part.startsWith(":")) {
|
|
133
|
+
const key = part.slice(1);
|
|
134
|
+
const value = parts[index];
|
|
135
|
+
if (value && !value.startsWith(":")) {
|
|
136
|
+
params[key] = value;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
return params;
|
|
141
|
+
}
|
|
142
|
+
initializePerformanceMonitoring() {
|
|
143
|
+
if (typeof window === "undefined" || typeof window.PerformanceObserver === "undefined") return;
|
|
144
|
+
const observer = new window.PerformanceObserver((list) => {
|
|
145
|
+
for (const entry of list.getEntries()) {
|
|
146
|
+
if (entry.name.includes("coherent")) {
|
|
147
|
+
this.renderMetrics.push({
|
|
148
|
+
name: entry.name,
|
|
149
|
+
duration: entry.duration,
|
|
150
|
+
startTime: entry.startTime,
|
|
151
|
+
timestamp: Date.now()
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
try {
|
|
157
|
+
observer.observe({ entryTypes: ["measure", "mark"] });
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.warn("Performance monitoring not available:", error);
|
|
160
|
+
}
|
|
161
|
+
setInterval(() => {
|
|
162
|
+
const cutoff = Date.now() - 3e5;
|
|
163
|
+
this.renderMetrics = this.renderMetrics.filter((m) => m.timestamp > cutoff);
|
|
164
|
+
}, 6e4);
|
|
165
|
+
}
|
|
166
|
+
// Component management
|
|
167
|
+
registerComponent(name, component, options = {}) {
|
|
168
|
+
const hydratableComponent = (0, import_client.makeHydratable)(component, {
|
|
169
|
+
componentName: name,
|
|
170
|
+
...options
|
|
171
|
+
});
|
|
172
|
+
this.componentRegistry.set(name, hydratableComponent);
|
|
173
|
+
if (this.options.enableWebComponents && this.isInitialized) {
|
|
174
|
+
try {
|
|
175
|
+
(0, import_web_components.defineCoherentElement)(name, hydratableComponent, options);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.warn(`Failed to register Web Component ${name}:`, error);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return hydratableComponent;
|
|
181
|
+
}
|
|
182
|
+
getComponent(name) {
|
|
183
|
+
return this.componentRegistry.get(name);
|
|
184
|
+
}
|
|
185
|
+
// Routing
|
|
186
|
+
addRoute(path, handler) {
|
|
187
|
+
this.routeRegistry.set(path, handler);
|
|
188
|
+
}
|
|
189
|
+
navigate(path) {
|
|
190
|
+
if (this.options.routingMode === "hash") {
|
|
191
|
+
window.location.hash = path;
|
|
192
|
+
} else if (this.options.routingMode === "history") {
|
|
193
|
+
window.history.pushState({}, "", path);
|
|
194
|
+
this.handleRouteChange(this.currentRoute, path);
|
|
195
|
+
this.currentRoute = path;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Rendering
|
|
199
|
+
async render(component, props = {}, target = null) {
|
|
200
|
+
const startMark = `coherent-render-start-${Date.now()}`;
|
|
201
|
+
const endMark = `coherent-render-end-${Date.now()}`;
|
|
202
|
+
try {
|
|
203
|
+
performance.mark(startMark);
|
|
204
|
+
const resolvedComponent = typeof component === "string" ? this.getComponent(component) : component;
|
|
205
|
+
if (!resolvedComponent) {
|
|
206
|
+
throw new Error(`Component not found: ${component}`);
|
|
207
|
+
}
|
|
208
|
+
const vdom = resolvedComponent(props);
|
|
209
|
+
const html = (0, import_core.render)(vdom);
|
|
210
|
+
let targetElement = target;
|
|
211
|
+
if (typeof target === "string") {
|
|
212
|
+
targetElement = document.querySelector(target);
|
|
213
|
+
}
|
|
214
|
+
if (!targetElement) {
|
|
215
|
+
targetElement = document.body;
|
|
216
|
+
}
|
|
217
|
+
targetElement.innerHTML = html;
|
|
218
|
+
const instance = await (0, import_client.hydrate)(targetElement.firstElementChild, resolvedComponent, props);
|
|
219
|
+
performance.mark(endMark);
|
|
220
|
+
performance.measure(`coherent-render-${resolvedComponent.name || "anonymous"}`, startMark, endMark);
|
|
221
|
+
return instance;
|
|
222
|
+
} catch (error) {
|
|
223
|
+
performance.mark(endMark);
|
|
224
|
+
console.error("Render error:", error);
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Create a complete app
|
|
229
|
+
async createApp(_options = {}) {
|
|
230
|
+
await this.initialize();
|
|
231
|
+
return {
|
|
232
|
+
// Component management
|
|
233
|
+
component: (name, component, opts) => this.registerComponent(name, component, opts),
|
|
234
|
+
// Routing
|
|
235
|
+
route: (path, handler) => this.addRoute(path, handler),
|
|
236
|
+
navigate: (path) => this.navigate(path),
|
|
237
|
+
// Rendering
|
|
238
|
+
render: (component, props, target) => this.render(component, props, target),
|
|
239
|
+
// State management
|
|
240
|
+
state: import_core.withState,
|
|
241
|
+
memo: import_core.memo,
|
|
242
|
+
// Hydration
|
|
243
|
+
hydrate: (element, component, props) => (0, import_client.hydrate)(element, component, props),
|
|
244
|
+
// Utilities
|
|
245
|
+
getRuntime: () => this,
|
|
246
|
+
getCurrentRoute: () => this.currentRoute,
|
|
247
|
+
getPerformanceMetrics: () => [...this.renderMetrics],
|
|
248
|
+
// Lifecycle
|
|
249
|
+
mount: async (component, target = "#app") => {
|
|
250
|
+
const app = await this.render(component, {}, target);
|
|
251
|
+
return app;
|
|
252
|
+
},
|
|
253
|
+
unmount: (target = "#app") => {
|
|
254
|
+
const element = typeof target === "string" ? document.querySelector(target) : target;
|
|
255
|
+
if (element) {
|
|
256
|
+
element.innerHTML = "";
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
// Auto-hydration
|
|
262
|
+
async autoHydrate() {
|
|
263
|
+
const componentMap = Object.fromEntries(this.componentRegistry);
|
|
264
|
+
await (0, import_client.autoHydrate)(componentMap);
|
|
265
|
+
}
|
|
266
|
+
// Static methods for quick setup
|
|
267
|
+
static async createQuickApp(components = {}, options = {}) {
|
|
268
|
+
const runtime = new _BrowserRuntime(options);
|
|
269
|
+
Object.entries(components).forEach(([name, component]) => {
|
|
270
|
+
runtime.registerComponent(name, component);
|
|
271
|
+
});
|
|
272
|
+
return await runtime.createApp(options);
|
|
273
|
+
}
|
|
274
|
+
static async renderToPage(component, props = {}, target = "#app") {
|
|
275
|
+
const runtime = new _BrowserRuntime({ autoHydrate: false });
|
|
276
|
+
await runtime.initialize();
|
|
277
|
+
return await runtime.render(component, props, target);
|
|
278
|
+
}
|
|
279
|
+
// Performance utilities
|
|
280
|
+
getPerformanceReport() {
|
|
281
|
+
const now = Date.now();
|
|
282
|
+
const uptime = now - this.startTime;
|
|
283
|
+
const recentMetrics = this.renderMetrics.filter((m) => m.timestamp >= now - 6e4);
|
|
284
|
+
const averageRenderTime = recentMetrics.length > 0 ? recentMetrics.reduce((sum, m) => sum + m.duration, 0) / recentMetrics.length : 0;
|
|
285
|
+
return {
|
|
286
|
+
uptime,
|
|
287
|
+
totalRenders: this.renderMetrics.length,
|
|
288
|
+
recentRenders: recentMetrics.length,
|
|
289
|
+
averageRenderTime: Math.round(averageRenderTime * 100) / 100,
|
|
290
|
+
registeredComponents: this.componentRegistry.size,
|
|
291
|
+
registeredRoutes: this.routeRegistry.size,
|
|
292
|
+
currentRoute: this.currentRoute,
|
|
293
|
+
memoryUsage: this.getMemoryUsage()
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
getMemoryUsage() {
|
|
297
|
+
if (typeof performance !== "undefined" && performance.memory) {
|
|
298
|
+
return {
|
|
299
|
+
used: Math.round(performance.memory.usedJSHeapSize / 1024 / 1024),
|
|
300
|
+
total: Math.round(performance.memory.totalJSHeapSize / 1024 / 1024),
|
|
301
|
+
limit: Math.round(performance.memory.jsHeapSizeLimit / 1024 / 1024)
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
// Development utilities
|
|
307
|
+
debug() {
|
|
308
|
+
return {
|
|
309
|
+
runtime: this,
|
|
310
|
+
components: Array.from(this.componentRegistry.keys()),
|
|
311
|
+
routes: Array.from(this.routeRegistry.keys()),
|
|
312
|
+
performance: this.getPerformanceReport(),
|
|
313
|
+
options: this.options
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// src/runtimes/edge.js
|
|
321
|
+
var edge_exports = {};
|
|
322
|
+
__export(edge_exports, {
|
|
323
|
+
EdgeRuntime: () => EdgeRuntime2,
|
|
324
|
+
createBunHandler: () => createBunHandler,
|
|
325
|
+
createCloudflareWorker: () => createCloudflareWorker,
|
|
326
|
+
createDenoHandler: () => createDenoHandler
|
|
327
|
+
});
|
|
328
|
+
function createCloudflareWorker(app) {
|
|
329
|
+
return {
|
|
330
|
+
async fetch(request, _env, _ctx) {
|
|
331
|
+
return await app.fetch(request);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function createDenoHandler(app) {
|
|
336
|
+
return async (request) => {
|
|
337
|
+
return await app.fetch(request);
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function createBunHandler(app) {
|
|
341
|
+
return {
|
|
342
|
+
async fetch(request) {
|
|
343
|
+
return await app.fetch(request);
|
|
344
|
+
},
|
|
345
|
+
port: 3e3
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
var import_core2, EdgeRuntime2;
|
|
349
|
+
var init_edge = __esm({
|
|
350
|
+
"src/runtimes/edge.js"() {
|
|
351
|
+
"use strict";
|
|
352
|
+
import_core2 = require("@coherent.js/core");
|
|
353
|
+
EdgeRuntime2 = class _EdgeRuntime {
|
|
354
|
+
constructor(options = {}) {
|
|
355
|
+
this.options = {
|
|
356
|
+
caching: true,
|
|
357
|
+
streaming: false,
|
|
358
|
+
headers: {
|
|
359
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
360
|
+
"Cache-Control": "public, max-age=3600",
|
|
361
|
+
...options.headers
|
|
362
|
+
},
|
|
363
|
+
...options
|
|
364
|
+
};
|
|
365
|
+
this.componentRegistry = /* @__PURE__ */ new Map();
|
|
366
|
+
this.routeRegistry = /* @__PURE__ */ new Map();
|
|
367
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
368
|
+
this.middleware = [];
|
|
369
|
+
this.renderCount = 0;
|
|
370
|
+
if (this.options.caching) {
|
|
371
|
+
this.initializeCacheCleanup();
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
initializeCacheCleanup() {
|
|
375
|
+
if (typeof setInterval !== "undefined") {
|
|
376
|
+
setInterval(() => {
|
|
377
|
+
if (this.cache.size > 1e3) {
|
|
378
|
+
const entries = Array.from(this.cache.entries());
|
|
379
|
+
const toDelete = entries.slice(0, entries.length - 500);
|
|
380
|
+
toDelete.forEach(([key]) => this.cache.delete(key));
|
|
381
|
+
}
|
|
382
|
+
}, 3e5);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
// Component management
|
|
386
|
+
registerComponent(name, component) {
|
|
387
|
+
this.componentRegistry.set(name, component);
|
|
388
|
+
return component;
|
|
389
|
+
}
|
|
390
|
+
getComponent(name) {
|
|
391
|
+
return this.componentRegistry.get(name);
|
|
392
|
+
}
|
|
393
|
+
// Route management
|
|
394
|
+
addRoute(pattern, handler) {
|
|
395
|
+
this.routeRegistry.set(pattern, handler);
|
|
396
|
+
}
|
|
397
|
+
matchRoute(pathname) {
|
|
398
|
+
for (const [pattern, handler] of this.routeRegistry) {
|
|
399
|
+
const match = this.matchPattern(pattern, pathname);
|
|
400
|
+
if (match) {
|
|
401
|
+
return { handler, params: match.params };
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
matchPattern(pattern, pathname) {
|
|
407
|
+
if (pattern === "*" || pattern === pathname) {
|
|
408
|
+
return { params: {} };
|
|
409
|
+
}
|
|
410
|
+
const patternParts = pattern.split("/").filter(Boolean);
|
|
411
|
+
const pathParts = pathname.split("/").filter(Boolean);
|
|
412
|
+
if (patternParts.length !== pathParts.length) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
const params = {};
|
|
416
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
417
|
+
const patternPart = patternParts[i];
|
|
418
|
+
const pathPart = pathParts[i];
|
|
419
|
+
if (patternPart.startsWith(":")) {
|
|
420
|
+
params[patternPart.slice(1)] = pathPart;
|
|
421
|
+
} else if (patternPart !== pathPart) {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return { params };
|
|
426
|
+
}
|
|
427
|
+
// Rendering
|
|
428
|
+
async renderComponent(component, props = {}, options = {}) {
|
|
429
|
+
const _startTime = Date.now();
|
|
430
|
+
try {
|
|
431
|
+
const resolvedComponent = typeof component === "string" ? this.getComponent(component) : component;
|
|
432
|
+
if (!resolvedComponent) {
|
|
433
|
+
throw new Error(`Component not found: ${component}`);
|
|
434
|
+
}
|
|
435
|
+
const cacheKey = this.generateCacheKey(resolvedComponent, props);
|
|
436
|
+
if (this.options.caching && this.cache.has(cacheKey)) {
|
|
437
|
+
const cached = this.cache.get(cacheKey);
|
|
438
|
+
if (Date.now() - cached.timestamp < (options.cacheMaxAge || 3e5)) {
|
|
439
|
+
return cached.html;
|
|
440
|
+
}
|
|
441
|
+
this.cache.delete(cacheKey);
|
|
442
|
+
}
|
|
443
|
+
const vdom = resolvedComponent(props);
|
|
444
|
+
const html = (0, import_core2.render)(vdom);
|
|
445
|
+
if (this.options.caching && options.cacheable !== false) {
|
|
446
|
+
this.cache.set(cacheKey, {
|
|
447
|
+
html,
|
|
448
|
+
timestamp: Date.now()
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
this.renderCount++;
|
|
452
|
+
return html;
|
|
453
|
+
} catch (error) {
|
|
454
|
+
console.error("Edge render error:", error);
|
|
455
|
+
throw error;
|
|
456
|
+
} finally {
|
|
457
|
+
if (typeof performance !== "undefined" && performance.mark) {
|
|
458
|
+
performance.mark(`coherent-edge-render-${Date.now()}`);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
generateCacheKey(component, props) {
|
|
463
|
+
const componentName = component.name || "anonymous";
|
|
464
|
+
const propsHash = this.hashObject(props);
|
|
465
|
+
return `${componentName}-${propsHash}`;
|
|
466
|
+
}
|
|
467
|
+
hashObject(obj) {
|
|
468
|
+
const str = JSON.stringify(obj, Object.keys(obj).sort());
|
|
469
|
+
let hash = 0;
|
|
470
|
+
for (let i = 0; i < str.length; i++) {
|
|
471
|
+
const char = str.charCodeAt(i);
|
|
472
|
+
hash = (hash << 5) - hash + char;
|
|
473
|
+
hash = hash & hash;
|
|
474
|
+
}
|
|
475
|
+
return hash.toString(36);
|
|
476
|
+
}
|
|
477
|
+
// HTTP Request handling
|
|
478
|
+
async handleRequest(request) {
|
|
479
|
+
try {
|
|
480
|
+
const url = new URL(request.url);
|
|
481
|
+
const pathname = url.pathname;
|
|
482
|
+
const context = {
|
|
483
|
+
request,
|
|
484
|
+
url,
|
|
485
|
+
pathname,
|
|
486
|
+
params: {},
|
|
487
|
+
searchParams: Object.fromEntries(url.searchParams),
|
|
488
|
+
method: request.method,
|
|
489
|
+
headers: Object.fromEntries(request.headers),
|
|
490
|
+
runtime: this,
|
|
491
|
+
state: {}
|
|
492
|
+
// Shared state for middleware
|
|
493
|
+
};
|
|
494
|
+
let middlewareIndex = 0;
|
|
495
|
+
const next = async () => {
|
|
496
|
+
if (middlewareIndex < this.middleware.length) {
|
|
497
|
+
const middleware = this.middleware[middlewareIndex++];
|
|
498
|
+
return await middleware(context, next);
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
if (this.middleware.length > 0) {
|
|
502
|
+
await next();
|
|
503
|
+
}
|
|
504
|
+
if (context.response) {
|
|
505
|
+
return context.response;
|
|
506
|
+
}
|
|
507
|
+
const match = this.matchRoute(pathname);
|
|
508
|
+
if (!match) {
|
|
509
|
+
return this.createErrorResponse(404, "Not Found");
|
|
510
|
+
}
|
|
511
|
+
context.params = match.params;
|
|
512
|
+
const result = await match.handler(context);
|
|
513
|
+
if (result instanceof Response) {
|
|
514
|
+
return result;
|
|
515
|
+
}
|
|
516
|
+
if (typeof result === "string") {
|
|
517
|
+
return this.createHtmlResponse(result);
|
|
518
|
+
}
|
|
519
|
+
if (result && typeof result === "object") {
|
|
520
|
+
if (result.component) {
|
|
521
|
+
const html = await this.renderComponent(
|
|
522
|
+
result.component,
|
|
523
|
+
result.props || {},
|
|
524
|
+
result.options || {}
|
|
525
|
+
);
|
|
526
|
+
return this.createHtmlResponse(html, result.status, result.headers);
|
|
527
|
+
}
|
|
528
|
+
if (result.json) {
|
|
529
|
+
return this.createJsonResponse(result.json, result.status, result.headers);
|
|
530
|
+
}
|
|
531
|
+
if (result.redirect) {
|
|
532
|
+
return Response.redirect(result.redirect, result.status || 302);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return this.createJsonResponse(result);
|
|
536
|
+
} catch (error) {
|
|
537
|
+
console.error("Request handling error:", error);
|
|
538
|
+
return this.createErrorResponse(500, "Internal Server Error");
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
createHtmlResponse(html, status = 200, customHeaders = {}) {
|
|
542
|
+
return new Response(html, {
|
|
543
|
+
status,
|
|
544
|
+
headers: {
|
|
545
|
+
...this.options.headers,
|
|
546
|
+
...customHeaders
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
createJsonResponse(data, status = 200, customHeaders = {}) {
|
|
551
|
+
return new Response(JSON.stringify(data), {
|
|
552
|
+
status,
|
|
553
|
+
headers: {
|
|
554
|
+
"Content-Type": "application/json",
|
|
555
|
+
...customHeaders
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
createErrorResponse(status, message) {
|
|
560
|
+
const errorHtml = `
|
|
561
|
+
<!DOCTYPE html>
|
|
562
|
+
<html>
|
|
563
|
+
<head>
|
|
564
|
+
<title>Error ${status}</title>
|
|
565
|
+
<style>
|
|
566
|
+
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
|
|
567
|
+
h1 { color: #e74c3c; }
|
|
568
|
+
</style>
|
|
569
|
+
</head>
|
|
570
|
+
<body>
|
|
571
|
+
<h1>Error ${status}</h1>
|
|
572
|
+
<p>${message}</p>
|
|
573
|
+
</body>
|
|
574
|
+
</html>
|
|
575
|
+
`;
|
|
576
|
+
return new Response(errorHtml, {
|
|
577
|
+
status,
|
|
578
|
+
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
// API Routes
|
|
582
|
+
async handleApiRequest(request, handler) {
|
|
583
|
+
try {
|
|
584
|
+
const url = new URL(request.url);
|
|
585
|
+
const context = {
|
|
586
|
+
request,
|
|
587
|
+
url,
|
|
588
|
+
method: request.method,
|
|
589
|
+
headers: Object.fromEntries(request.headers),
|
|
590
|
+
searchParams: Object.fromEntries(url.searchParams),
|
|
591
|
+
runtime: this
|
|
592
|
+
};
|
|
593
|
+
if (request.method === "POST" || request.method === "PUT") {
|
|
594
|
+
const contentType = request.headers.get("content-type") || "";
|
|
595
|
+
if (contentType.includes("application/json")) {
|
|
596
|
+
context.body = await request.json();
|
|
597
|
+
} else if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
598
|
+
const formData = await request.formData();
|
|
599
|
+
context.body = Object.fromEntries(formData);
|
|
600
|
+
} else {
|
|
601
|
+
context.body = await request.text();
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
const result = await handler(context);
|
|
605
|
+
if (result instanceof Response) {
|
|
606
|
+
return result;
|
|
607
|
+
}
|
|
608
|
+
return this.createJsonResponse(result);
|
|
609
|
+
} catch (error) {
|
|
610
|
+
console.error("API request error:", error);
|
|
611
|
+
return this.createJsonResponse({ error: error.message }, 500);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
// Streaming support (for environments that support it)
|
|
615
|
+
async renderStream(component, props = {}) {
|
|
616
|
+
if (!this.options.streaming) {
|
|
617
|
+
return await this.renderComponent(component, props);
|
|
618
|
+
}
|
|
619
|
+
const encoder = new TextEncoder();
|
|
620
|
+
let buffer = "";
|
|
621
|
+
const chunkSize = this.options.streamChunkSize || 1024;
|
|
622
|
+
const stream = new ReadableStream({
|
|
623
|
+
async start(controller) {
|
|
624
|
+
try {
|
|
625
|
+
const flush = () => {
|
|
626
|
+
if (buffer.length > 0) {
|
|
627
|
+
controller.enqueue(encoder.encode(buffer));
|
|
628
|
+
buffer = "";
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
const renderNode = async (node) => {
|
|
632
|
+
if (!node || typeof node !== "object") {
|
|
633
|
+
if (node !== null && node !== void 0) {
|
|
634
|
+
buffer += String(node);
|
|
635
|
+
if (buffer.length >= chunkSize) {
|
|
636
|
+
flush();
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
if (Array.isArray(node)) {
|
|
642
|
+
for (const child of node) {
|
|
643
|
+
await renderNode(child);
|
|
644
|
+
}
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
for (const [tag, content] of Object.entries(node)) {
|
|
648
|
+
if (typeof content === "object" && content !== null) {
|
|
649
|
+
buffer += `<${tag}`;
|
|
650
|
+
for (const [key, value] of Object.entries(content)) {
|
|
651
|
+
if (key !== "children" && key !== "text" && value !== void 0) {
|
|
652
|
+
buffer += ` ${key}="${String(value)}"`;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
buffer += ">";
|
|
656
|
+
if (buffer.length >= chunkSize) {
|
|
657
|
+
flush();
|
|
658
|
+
}
|
|
659
|
+
if (content.text) {
|
|
660
|
+
buffer += String(content.text);
|
|
661
|
+
if (buffer.length >= chunkSize) {
|
|
662
|
+
flush();
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
if (content.children) {
|
|
666
|
+
await renderNode(content.children);
|
|
667
|
+
}
|
|
668
|
+
buffer += `</${tag}>`;
|
|
669
|
+
if (buffer.length >= chunkSize) {
|
|
670
|
+
flush();
|
|
671
|
+
}
|
|
672
|
+
} else {
|
|
673
|
+
buffer += `<${tag}>${String(content)}</${tag}>`;
|
|
674
|
+
if (buffer.length >= chunkSize) {
|
|
675
|
+
flush();
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
await renderNode(component);
|
|
681
|
+
flush();
|
|
682
|
+
controller.close();
|
|
683
|
+
} catch (error) {
|
|
684
|
+
controller.error(error);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
return new Response(stream, {
|
|
689
|
+
headers: {
|
|
690
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
691
|
+
"Transfer-Encoding": "chunked"
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
// Create app factory
|
|
696
|
+
createApp() {
|
|
697
|
+
const app = {
|
|
698
|
+
// Component registration
|
|
699
|
+
component: (name, component, opts) => this.registerComponent(name, component, opts),
|
|
700
|
+
// Routing
|
|
701
|
+
get: (pattern, handler) => this.addRoute(pattern, handler),
|
|
702
|
+
post: (pattern, handler) => this.addRoute(pattern, handler),
|
|
703
|
+
put: (pattern, handler) => this.addRoute(pattern, handler),
|
|
704
|
+
delete: (pattern, handler) => this.addRoute(pattern, handler),
|
|
705
|
+
route: (pattern, handler) => this.addRoute(pattern, handler),
|
|
706
|
+
// API endpoints
|
|
707
|
+
api: (pattern, handler) => {
|
|
708
|
+
this.addRoute(pattern, (context) => this.handleApiRequest(context.request, handler));
|
|
709
|
+
},
|
|
710
|
+
// Static file serving (basic)
|
|
711
|
+
static: (pattern) => {
|
|
712
|
+
this.addRoute(pattern, async () => {
|
|
713
|
+
return this.createErrorResponse(404, "Static file serving not implemented");
|
|
714
|
+
});
|
|
715
|
+
},
|
|
716
|
+
// Middleware support
|
|
717
|
+
use: (middleware) => {
|
|
718
|
+
if (typeof middleware !== "function") {
|
|
719
|
+
throw new Error("Middleware must be a function");
|
|
720
|
+
}
|
|
721
|
+
this.middleware.push(middleware);
|
|
722
|
+
return app;
|
|
723
|
+
},
|
|
724
|
+
// Request handler
|
|
725
|
+
fetch: (request) => this.handleRequest(request),
|
|
726
|
+
// Utilities
|
|
727
|
+
render: (component, props, options) => this.renderComponent(component, props, options),
|
|
728
|
+
getRuntime: () => this,
|
|
729
|
+
getStats: () => ({
|
|
730
|
+
renderCount: this.renderCount,
|
|
731
|
+
cacheSize: this.cache.size,
|
|
732
|
+
componentCount: this.componentRegistry.size,
|
|
733
|
+
routeCount: this.routeRegistry.size
|
|
734
|
+
})
|
|
735
|
+
};
|
|
736
|
+
return app;
|
|
737
|
+
}
|
|
738
|
+
// Static factory methods
|
|
739
|
+
static createApp(options = {}) {
|
|
740
|
+
const runtime = new _EdgeRuntime(options);
|
|
741
|
+
return runtime.createApp(options);
|
|
742
|
+
}
|
|
743
|
+
static async handleRequest(request, components = {}, routes = {}) {
|
|
744
|
+
const runtime = new _EdgeRuntime();
|
|
745
|
+
Object.entries(components).forEach(([name, component]) => {
|
|
746
|
+
runtime.registerComponent(name, component);
|
|
747
|
+
});
|
|
748
|
+
Object.entries(routes).forEach(([pattern, handler]) => {
|
|
749
|
+
runtime.addRoute(pattern, handler);
|
|
750
|
+
});
|
|
751
|
+
return await runtime.handleRequest(request);
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
// src/runtimes/static.js
|
|
758
|
+
var static_exports = {};
|
|
759
|
+
__export(static_exports, {
|
|
760
|
+
StaticRuntime: () => StaticRuntime
|
|
761
|
+
});
|
|
762
|
+
var import_core3, StaticRuntime;
|
|
763
|
+
var init_static = __esm({
|
|
764
|
+
"src/runtimes/static.js"() {
|
|
765
|
+
"use strict";
|
|
766
|
+
import_core3 = require("@coherent.js/core");
|
|
767
|
+
StaticRuntime = class _StaticRuntime {
|
|
768
|
+
constructor(options = {}) {
|
|
769
|
+
this.options = {
|
|
770
|
+
outputDir: "dist",
|
|
771
|
+
baseUrl: "",
|
|
772
|
+
generateSitemap: true,
|
|
773
|
+
generateManifest: true,
|
|
774
|
+
minifyHtml: true,
|
|
775
|
+
inlineCSS: false,
|
|
776
|
+
...options
|
|
777
|
+
};
|
|
778
|
+
this.componentRegistry = /* @__PURE__ */ new Map();
|
|
779
|
+
this.pageRegistry = /* @__PURE__ */ new Map();
|
|
780
|
+
this.staticAssets = /* @__PURE__ */ new Map();
|
|
781
|
+
this.generatedPages = /* @__PURE__ */ new Map();
|
|
782
|
+
this.buildStats = {
|
|
783
|
+
startTime: Date.now(),
|
|
784
|
+
pagesGenerated: 0,
|
|
785
|
+
assetsProcessed: 0,
|
|
786
|
+
totalSize: 0,
|
|
787
|
+
errors: []
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
// Component management
|
|
791
|
+
registerComponent(name, component, options = {}) {
|
|
792
|
+
this.componentRegistry.set(name, {
|
|
793
|
+
component,
|
|
794
|
+
options
|
|
795
|
+
});
|
|
796
|
+
return component;
|
|
797
|
+
}
|
|
798
|
+
getComponent(name) {
|
|
799
|
+
const registration = this.componentRegistry.get(name);
|
|
800
|
+
return registration ? registration.component : null;
|
|
801
|
+
}
|
|
802
|
+
// Page registration
|
|
803
|
+
addPage(route, component, options = {}) {
|
|
804
|
+
this.pageRegistry.set(route, {
|
|
805
|
+
component: typeof component === "string" ? this.getComponent(component) : component,
|
|
806
|
+
options: {
|
|
807
|
+
title: options.title || "Page",
|
|
808
|
+
description: options.description || "",
|
|
809
|
+
keywords: options.keywords || "",
|
|
810
|
+
generatePath: options.generatePath || this.routeToPath(route),
|
|
811
|
+
props: options.props || {},
|
|
812
|
+
...options
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
routeToPath(route) {
|
|
817
|
+
if (route === "/") return "/index.html";
|
|
818
|
+
if (route.includes(":")) {
|
|
819
|
+
console.warn(`Dynamic route ${route} requires explicit generatePath`);
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
822
|
+
return route.endsWith("/") ? `${route}index.html` : `${route}.html`;
|
|
823
|
+
}
|
|
824
|
+
// Static asset management
|
|
825
|
+
addAsset(path, content, options = {}) {
|
|
826
|
+
this.staticAssets.set(path, {
|
|
827
|
+
content,
|
|
828
|
+
type: options.type || this.inferContentType(path),
|
|
829
|
+
minify: options.minify !== false,
|
|
830
|
+
...options
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
inferContentType(path) {
|
|
834
|
+
const ext = path.split(".").pop().toLowerCase();
|
|
835
|
+
const contentTypes = {
|
|
836
|
+
"html": "text/html",
|
|
837
|
+
"css": "text/css",
|
|
838
|
+
"js": "application/javascript",
|
|
839
|
+
"json": "application/json",
|
|
840
|
+
"png": "image/png",
|
|
841
|
+
"jpg": "image/jpeg",
|
|
842
|
+
"jpeg": "image/jpeg",
|
|
843
|
+
"gif": "image/gif",
|
|
844
|
+
"svg": "image/svg+xml",
|
|
845
|
+
"ico": "image/x-icon"
|
|
846
|
+
};
|
|
847
|
+
return contentTypes[ext] || "text/plain";
|
|
848
|
+
}
|
|
849
|
+
// HTML template generation
|
|
850
|
+
generateHtmlDocument(content, options = {}) {
|
|
851
|
+
const {
|
|
852
|
+
title = "Coherent.js App",
|
|
853
|
+
description = "",
|
|
854
|
+
keywords = "",
|
|
855
|
+
lang = "en",
|
|
856
|
+
charset = "utf-8",
|
|
857
|
+
viewport = "width=device-width, initial-scale=1",
|
|
858
|
+
favicon = "/favicon.ico",
|
|
859
|
+
styles = [],
|
|
860
|
+
scripts = [],
|
|
861
|
+
meta = [],
|
|
862
|
+
bodyClass = "",
|
|
863
|
+
hydrate: hydrate2 = false,
|
|
864
|
+
componentName = null,
|
|
865
|
+
componentProps = {}
|
|
866
|
+
} = options;
|
|
867
|
+
const metaTags = [
|
|
868
|
+
`<meta charset="${charset}">`,
|
|
869
|
+
`<meta name="viewport" content="${viewport}">`,
|
|
870
|
+
description && `<meta name="description" content="${description}">`,
|
|
871
|
+
keywords && `<meta name="keywords" content="${keywords}">`,
|
|
872
|
+
...meta.map((m) => typeof m === "string" ? m : `<meta ${Object.entries(m).map(([k, v]) => `${k}="${v}"`).join(" ")}>`)
|
|
873
|
+
].filter(Boolean).join("\n ");
|
|
874
|
+
const styleTags = styles.map(
|
|
875
|
+
(style) => typeof style === "string" ? style.startsWith("<") ? style : `<link rel="stylesheet" href="${style}">` : `<style>${style.content}</style>`
|
|
876
|
+
).join("\n ");
|
|
877
|
+
const scriptTags = [
|
|
878
|
+
...scripts.map(
|
|
879
|
+
(script) => typeof script === "string" ? script.startsWith("<") ? script : `<script src="${script}"></script>` : `<script>${script.content}</script>`
|
|
880
|
+
),
|
|
881
|
+
// Add hydration script if enabled
|
|
882
|
+
hydrate2 && this.generateHydrationScript(componentName, componentProps)
|
|
883
|
+
].filter(Boolean).join("\n ");
|
|
884
|
+
return `<!DOCTYPE html>
|
|
885
|
+
<html lang="${lang}">
|
|
886
|
+
<head>
|
|
887
|
+
${metaTags}
|
|
888
|
+
<title>${this.escapeHtml(title)}</title>
|
|
889
|
+
<link rel="icon" href="${favicon}">
|
|
890
|
+
${styleTags}
|
|
891
|
+
</head>
|
|
892
|
+
<body${bodyClass ? ` class="${bodyClass}"` : ""}>
|
|
893
|
+
${content}
|
|
894
|
+
${scriptTags}
|
|
895
|
+
</body>
|
|
896
|
+
</html>`;
|
|
897
|
+
}
|
|
898
|
+
generateHydrationScript(componentName) {
|
|
899
|
+
if (!componentName) return "";
|
|
900
|
+
return `
|
|
901
|
+
<script type="module">
|
|
902
|
+
import { autoHydrate } from '/coherent-client.js';
|
|
903
|
+
|
|
904
|
+
// Auto-hydrate on page load
|
|
905
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
906
|
+
autoHydrate({
|
|
907
|
+
'${componentName}': window.components?.['${componentName}']
|
|
908
|
+
});
|
|
909
|
+
});
|
|
910
|
+
</script>`;
|
|
911
|
+
}
|
|
912
|
+
escapeHtml(text) {
|
|
913
|
+
if (typeof text !== "string") return text;
|
|
914
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
915
|
+
}
|
|
916
|
+
// Build process
|
|
917
|
+
async build() {
|
|
918
|
+
this.buildStats.startTime = Date.now();
|
|
919
|
+
console.log("\u{1F3D7}\uFE0F Starting static site generation...");
|
|
920
|
+
try {
|
|
921
|
+
await this.generatePages();
|
|
922
|
+
await this.processAssets();
|
|
923
|
+
if (this.options.generateSitemap) {
|
|
924
|
+
await this.generateSitemap();
|
|
925
|
+
}
|
|
926
|
+
if (this.options.generateManifest) {
|
|
927
|
+
await this.generateManifest();
|
|
928
|
+
}
|
|
929
|
+
const buildTime = Date.now() - this.buildStats.startTime;
|
|
930
|
+
console.log(`\u2705 Build completed in ${buildTime}ms`);
|
|
931
|
+
console.log(`\u{1F4C4} Generated ${this.buildStats.pagesGenerated} pages`);
|
|
932
|
+
console.log(`\u{1F4E6} Processed ${this.buildStats.assetsProcessed} assets`);
|
|
933
|
+
return this.getBuildResult();
|
|
934
|
+
} catch (error) {
|
|
935
|
+
this.buildStats.errors.push(error);
|
|
936
|
+
console.error("\u274C Build failed:", error);
|
|
937
|
+
throw error;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
async generatePages() {
|
|
941
|
+
for (const [route, pageConfig] of this.pageRegistry) {
|
|
942
|
+
try {
|
|
943
|
+
await this.generatePage(route, pageConfig);
|
|
944
|
+
this.buildStats.pagesGenerated++;
|
|
945
|
+
} catch (error) {
|
|
946
|
+
console.error(`Failed to generate page ${route}:`, error);
|
|
947
|
+
this.buildStats.errors.push({ route, error });
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
async generatePage(route, pageConfig) {
|
|
952
|
+
const { component, options } = pageConfig;
|
|
953
|
+
if (!component) {
|
|
954
|
+
throw new Error(`No component found for route: ${route}`);
|
|
955
|
+
}
|
|
956
|
+
const vdom = component(options.props || {});
|
|
957
|
+
const content = (0, import_core3.render)(vdom);
|
|
958
|
+
const html = this.generateHtmlDocument(content, {
|
|
959
|
+
title: options.title,
|
|
960
|
+
description: options.description,
|
|
961
|
+
keywords: options.keywords,
|
|
962
|
+
styles: options.styles || [],
|
|
963
|
+
scripts: options.scripts || [],
|
|
964
|
+
meta: options.meta || [],
|
|
965
|
+
hydrate: options.hydrate,
|
|
966
|
+
componentName: options.componentName,
|
|
967
|
+
componentProps: options.props || {},
|
|
968
|
+
...options.htmlOptions
|
|
969
|
+
});
|
|
970
|
+
const finalHtml = this.options.minifyHtml ? this.minifyHtml(html) : html;
|
|
971
|
+
const outputPath = options.generatePath || this.routeToPath(route);
|
|
972
|
+
if (outputPath) {
|
|
973
|
+
this.generatedPages.set(outputPath, {
|
|
974
|
+
html: finalHtml,
|
|
975
|
+
size: finalHtml.length,
|
|
976
|
+
route,
|
|
977
|
+
options
|
|
978
|
+
});
|
|
979
|
+
this.buildStats.totalSize += finalHtml.length;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
minifyHtml(html) {
|
|
983
|
+
return html.replace(/\s+/g, " ").replace(/>\s+</g, "><").replace(/\s+>/g, ">").replace(/<\s+/g, "<").trim();
|
|
984
|
+
}
|
|
985
|
+
async processAssets() {
|
|
986
|
+
for (const [path, asset] of this.staticAssets) {
|
|
987
|
+
try {
|
|
988
|
+
let content = asset.content;
|
|
989
|
+
if (asset.minify) {
|
|
990
|
+
content = this.minifyAsset(content, asset.type);
|
|
991
|
+
}
|
|
992
|
+
this.generatedPages.set(path, {
|
|
993
|
+
content,
|
|
994
|
+
type: asset.type,
|
|
995
|
+
size: content.length
|
|
996
|
+
});
|
|
997
|
+
this.buildStats.assetsProcessed++;
|
|
998
|
+
this.buildStats.totalSize += content.length;
|
|
999
|
+
} catch (error) {
|
|
1000
|
+
console.error(`Failed to process asset ${path}:`, error);
|
|
1001
|
+
this.buildStats.errors.push({ path, error });
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
minifyAsset(content, type) {
|
|
1006
|
+
switch (type) {
|
|
1007
|
+
case "text/css":
|
|
1008
|
+
return content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").replace(/;\s*}/g, "}").replace(/\s*{\s*/g, "{").replace(/;\s*/g, ";").trim();
|
|
1009
|
+
case "application/javascript":
|
|
1010
|
+
return content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "").replace(/\s+/g, " ").replace(/\s*([{}();,])\s*/g, "$1").trim();
|
|
1011
|
+
default:
|
|
1012
|
+
return content;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
async generateSitemap() {
|
|
1016
|
+
const pages = Array.from(this.generatedPages.keys()).filter((path) => path.endsWith(".html"));
|
|
1017
|
+
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1018
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
1019
|
+
${pages.map((path) => ` <url>
|
|
1020
|
+
<loc>${this.options.baseUrl}${path.replace("/index.html", "/")}</loc>
|
|
1021
|
+
<lastmod>${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}</lastmod>
|
|
1022
|
+
</url>`).join("\n")}
|
|
1023
|
+
</urlset>`;
|
|
1024
|
+
this.generatedPages.set("/sitemap.xml", {
|
|
1025
|
+
content: sitemap,
|
|
1026
|
+
type: "application/xml",
|
|
1027
|
+
size: sitemap.length
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
async generateManifest() {
|
|
1031
|
+
const manifest = {
|
|
1032
|
+
name: this.options.name || "Coherent.js App",
|
|
1033
|
+
short_name: this.options.shortName || "App",
|
|
1034
|
+
description: this.options.description || "",
|
|
1035
|
+
start_url: "/",
|
|
1036
|
+
display: "standalone",
|
|
1037
|
+
theme_color: this.options.themeColor || "#000000",
|
|
1038
|
+
background_color: this.options.backgroundColor || "#ffffff",
|
|
1039
|
+
icons: this.options.icons || []
|
|
1040
|
+
};
|
|
1041
|
+
const manifestJson = JSON.stringify(manifest, null, 2);
|
|
1042
|
+
this.generatedPages.set("/manifest.json", {
|
|
1043
|
+
content: manifestJson,
|
|
1044
|
+
type: "application/json",
|
|
1045
|
+
size: manifestJson.length
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
getBuildResult() {
|
|
1049
|
+
return {
|
|
1050
|
+
pages: this.generatedPages,
|
|
1051
|
+
stats: {
|
|
1052
|
+
...this.buildStats,
|
|
1053
|
+
buildTime: Date.now() - this.buildStats.startTime
|
|
1054
|
+
},
|
|
1055
|
+
success: this.buildStats.errors.length === 0
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
// Create static app factory
|
|
1059
|
+
createApp() {
|
|
1060
|
+
return {
|
|
1061
|
+
// Component registration
|
|
1062
|
+
component: (name, component, opts) => this.registerComponent(name, component, opts),
|
|
1063
|
+
// Page registration
|
|
1064
|
+
page: (route, component, opts) => this.addPage(route, component, opts),
|
|
1065
|
+
// Asset management
|
|
1066
|
+
asset: (path, content, opts) => this.addAsset(path, content, opts),
|
|
1067
|
+
// Build process
|
|
1068
|
+
build: () => this.build(),
|
|
1069
|
+
// Utilities
|
|
1070
|
+
getRuntime: () => this,
|
|
1071
|
+
getStats: () => this.buildStats,
|
|
1072
|
+
getPages: () => Array.from(this.pageRegistry.keys()),
|
|
1073
|
+
getAssets: () => Array.from(this.staticAssets.keys())
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
// Static factory methods
|
|
1077
|
+
static createApp(options = {}) {
|
|
1078
|
+
const runtime = new _StaticRuntime(options);
|
|
1079
|
+
return runtime.createApp(options);
|
|
1080
|
+
}
|
|
1081
|
+
static async buildSite(pages = {}, components = {}, options = {}) {
|
|
1082
|
+
const runtime = new _StaticRuntime(options);
|
|
1083
|
+
Object.entries(components).forEach(([name, component]) => {
|
|
1084
|
+
runtime.registerComponent(name, component);
|
|
1085
|
+
});
|
|
1086
|
+
Object.entries(pages).forEach(([route, config]) => {
|
|
1087
|
+
runtime.addPage(route, config.component, config.options);
|
|
1088
|
+
});
|
|
1089
|
+
return await runtime.build();
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
});
|
|
1094
|
+
|
|
1095
|
+
// src/runtimes/node.js
|
|
1096
|
+
var node_exports = {};
|
|
1097
|
+
__export(node_exports, {
|
|
1098
|
+
NodeRuntime: () => NodeRuntime,
|
|
1099
|
+
createNodeRuntime: () => createNodeRuntime,
|
|
1100
|
+
default: () => node_default
|
|
1101
|
+
});
|
|
1102
|
+
function createNodeRuntime(options = {}) {
|
|
1103
|
+
return new NodeRuntime(options);
|
|
1104
|
+
}
|
|
1105
|
+
var import_core4, import_http, NodeRuntime, node_default;
|
|
1106
|
+
var init_node = __esm({
|
|
1107
|
+
"src/runtimes/node.js"() {
|
|
1108
|
+
"use strict";
|
|
1109
|
+
import_core4 = require("@coherent.js/core");
|
|
1110
|
+
import_http = require("http");
|
|
1111
|
+
NodeRuntime = class {
|
|
1112
|
+
constructor(options = {}) {
|
|
1113
|
+
this.options = {
|
|
1114
|
+
port: 3e3,
|
|
1115
|
+
host: "localhost",
|
|
1116
|
+
caching: true,
|
|
1117
|
+
framework: null,
|
|
1118
|
+
// 'express', 'fastify', 'koa', or null for standalone
|
|
1119
|
+
headers: {
|
|
1120
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
1121
|
+
"Cache-Control": "public, max-age=3600",
|
|
1122
|
+
...options.headers
|
|
1123
|
+
},
|
|
1124
|
+
...options
|
|
1125
|
+
};
|
|
1126
|
+
this.componentRegistry = /* @__PURE__ */ new Map();
|
|
1127
|
+
this.routeRegistry = /* @__PURE__ */ new Map();
|
|
1128
|
+
this.middleware = [];
|
|
1129
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
1130
|
+
this.renderCount = 0;
|
|
1131
|
+
this.server = null;
|
|
1132
|
+
if (this.options.caching) {
|
|
1133
|
+
this.initializeCacheCleanup();
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
initializeCacheCleanup() {
|
|
1137
|
+
setInterval(() => {
|
|
1138
|
+
if (this.cache.size > 1e3) {
|
|
1139
|
+
const entries = Array.from(this.cache.entries());
|
|
1140
|
+
const toDelete = entries.slice(0, entries.length - 500);
|
|
1141
|
+
toDelete.forEach(([key]) => this.cache.delete(key));
|
|
1142
|
+
}
|
|
1143
|
+
}, 3e5);
|
|
1144
|
+
}
|
|
1145
|
+
// Component management
|
|
1146
|
+
registerComponent(name, component) {
|
|
1147
|
+
this.componentRegistry.set(name, component);
|
|
1148
|
+
return component;
|
|
1149
|
+
}
|
|
1150
|
+
getComponent(name) {
|
|
1151
|
+
return this.componentRegistry.get(name);
|
|
1152
|
+
}
|
|
1153
|
+
// Route management
|
|
1154
|
+
addRoute(pattern, handler) {
|
|
1155
|
+
this.routeRegistry.set(pattern, handler);
|
|
1156
|
+
}
|
|
1157
|
+
matchRoute(pathname) {
|
|
1158
|
+
for (const [pattern, handler] of this.routeRegistry.entries()) {
|
|
1159
|
+
const match = this.matchPattern(pattern, pathname);
|
|
1160
|
+
if (match) {
|
|
1161
|
+
return { handler, params: match.params };
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return null;
|
|
1165
|
+
}
|
|
1166
|
+
matchPattern(pattern, pathname) {
|
|
1167
|
+
const patternParts = pattern.split("/").filter(Boolean);
|
|
1168
|
+
const pathParts = pathname.split("/").filter(Boolean);
|
|
1169
|
+
if (patternParts.length !== pathParts.length) {
|
|
1170
|
+
return null;
|
|
1171
|
+
}
|
|
1172
|
+
const params = {};
|
|
1173
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
1174
|
+
const patternPart = patternParts[i];
|
|
1175
|
+
const pathPart = pathParts[i];
|
|
1176
|
+
if (patternPart.startsWith(":")) {
|
|
1177
|
+
params[patternPart.slice(1)] = pathPart;
|
|
1178
|
+
} else if (patternPart !== pathPart) {
|
|
1179
|
+
return null;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
return { params };
|
|
1183
|
+
}
|
|
1184
|
+
// Rendering
|
|
1185
|
+
async renderComponent(component, props = {}, options = {}) {
|
|
1186
|
+
try {
|
|
1187
|
+
const resolvedComponent = typeof component === "string" ? this.getComponent(component) : component;
|
|
1188
|
+
if (!resolvedComponent) {
|
|
1189
|
+
throw new Error(`Component not found: ${component}`);
|
|
1190
|
+
}
|
|
1191
|
+
const cacheKey = this.generateCacheKey(resolvedComponent, props);
|
|
1192
|
+
if (this.options.caching && this.cache.has(cacheKey)) {
|
|
1193
|
+
const cached = this.cache.get(cacheKey);
|
|
1194
|
+
if (Date.now() - cached.timestamp < (options.cacheMaxAge || 3e5)) {
|
|
1195
|
+
return cached.html;
|
|
1196
|
+
}
|
|
1197
|
+
this.cache.delete(cacheKey);
|
|
1198
|
+
}
|
|
1199
|
+
const vdom = resolvedComponent(props);
|
|
1200
|
+
const html = (0, import_core4.render)(vdom);
|
|
1201
|
+
if (this.options.caching && options.cacheable !== false) {
|
|
1202
|
+
this.cache.set(cacheKey, {
|
|
1203
|
+
html,
|
|
1204
|
+
timestamp: Date.now()
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
this.renderCount++;
|
|
1208
|
+
return html;
|
|
1209
|
+
} catch (error) {
|
|
1210
|
+
console.error("Node render error:", error);
|
|
1211
|
+
throw error;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
generateCacheKey(component, props) {
|
|
1215
|
+
const componentName = component.name || "anonymous";
|
|
1216
|
+
const propsHash = this.hashObject(props);
|
|
1217
|
+
return `${componentName}-${propsHash}`;
|
|
1218
|
+
}
|
|
1219
|
+
hashObject(obj) {
|
|
1220
|
+
const str = JSON.stringify(obj, Object.keys(obj).sort());
|
|
1221
|
+
let hash = 0;
|
|
1222
|
+
for (let i = 0; i < str.length; i++) {
|
|
1223
|
+
const char = str.charCodeAt(i);
|
|
1224
|
+
hash = (hash << 5) - hash + char;
|
|
1225
|
+
hash = hash & hash;
|
|
1226
|
+
}
|
|
1227
|
+
return hash.toString(36);
|
|
1228
|
+
}
|
|
1229
|
+
// HTTP Request handling (for standalone mode)
|
|
1230
|
+
async handleRequest(req, res) {
|
|
1231
|
+
try {
|
|
1232
|
+
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
1233
|
+
const pathname = url.pathname;
|
|
1234
|
+
const context = {
|
|
1235
|
+
req,
|
|
1236
|
+
res,
|
|
1237
|
+
url,
|
|
1238
|
+
pathname,
|
|
1239
|
+
params: {},
|
|
1240
|
+
query: Object.fromEntries(url.searchParams),
|
|
1241
|
+
method: req.method,
|
|
1242
|
+
headers: req.headers,
|
|
1243
|
+
runtime: this,
|
|
1244
|
+
state: {}
|
|
1245
|
+
};
|
|
1246
|
+
let middlewareIndex = 0;
|
|
1247
|
+
const next = async () => {
|
|
1248
|
+
if (middlewareIndex < this.middleware.length) {
|
|
1249
|
+
const middleware = this.middleware[middlewareIndex++];
|
|
1250
|
+
return await middleware(context, next);
|
|
1251
|
+
}
|
|
1252
|
+
};
|
|
1253
|
+
if (this.middleware.length > 0) {
|
|
1254
|
+
await next();
|
|
1255
|
+
}
|
|
1256
|
+
if (res.headersSent) {
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
const match = this.matchRoute(pathname);
|
|
1260
|
+
if (!match) {
|
|
1261
|
+
res.writeHead(404, { "Content-Type": "text/html" });
|
|
1262
|
+
res.end("<h1>404 Not Found</h1>");
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
context.params = match.params;
|
|
1266
|
+
const result = await match.handler(context);
|
|
1267
|
+
if (res.headersSent) {
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
if (typeof result === "string") {
|
|
1271
|
+
res.writeHead(200, this.options.headers);
|
|
1272
|
+
res.end(result);
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
if (result && typeof result === "object") {
|
|
1276
|
+
if (result.component) {
|
|
1277
|
+
const html = await this.renderComponent(
|
|
1278
|
+
result.component,
|
|
1279
|
+
result.props || {},
|
|
1280
|
+
result.options || {}
|
|
1281
|
+
);
|
|
1282
|
+
res.writeHead(result.status || 200, {
|
|
1283
|
+
...this.options.headers,
|
|
1284
|
+
...result.headers
|
|
1285
|
+
});
|
|
1286
|
+
res.end(html);
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
if (result.json !== void 0) {
|
|
1290
|
+
res.writeHead(result.status || 200, {
|
|
1291
|
+
"Content-Type": "application/json",
|
|
1292
|
+
...result.headers
|
|
1293
|
+
});
|
|
1294
|
+
res.end(JSON.stringify(result.json));
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
if (result.redirect) {
|
|
1298
|
+
res.writeHead(result.status || 302, {
|
|
1299
|
+
"Location": result.redirect
|
|
1300
|
+
});
|
|
1301
|
+
res.end();
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1304
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1305
|
+
res.end(JSON.stringify(result));
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
res.writeHead(200, this.options.headers);
|
|
1309
|
+
res.end(String(result));
|
|
1310
|
+
} catch (error) {
|
|
1311
|
+
console.error("Request handling error:", error);
|
|
1312
|
+
if (!res.headersSent) {
|
|
1313
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1314
|
+
res.end(JSON.stringify({ error: error.message }));
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
// Create app factory
|
|
1319
|
+
createApp() {
|
|
1320
|
+
const app = {
|
|
1321
|
+
// Component registration
|
|
1322
|
+
component: (name, component) => this.registerComponent(name, component),
|
|
1323
|
+
// Routing
|
|
1324
|
+
get: (pattern, handler) => this.addRoute(pattern, handler),
|
|
1325
|
+
post: (pattern, handler) => this.addRoute(pattern, handler),
|
|
1326
|
+
put: (pattern, handler) => this.addRoute(pattern, handler),
|
|
1327
|
+
delete: (pattern, handler) => this.addRoute(pattern, handler),
|
|
1328
|
+
route: (pattern, handler) => this.addRoute(pattern, handler),
|
|
1329
|
+
// Middleware support
|
|
1330
|
+
use: (middleware) => {
|
|
1331
|
+
if (typeof middleware !== "function") {
|
|
1332
|
+
throw new Error("Middleware must be a function");
|
|
1333
|
+
}
|
|
1334
|
+
this.middleware.push(middleware);
|
|
1335
|
+
return app;
|
|
1336
|
+
},
|
|
1337
|
+
// Server control
|
|
1338
|
+
listen: (port, callback) => {
|
|
1339
|
+
const serverPort = port || this.options.port;
|
|
1340
|
+
this.server = (0, import_http.createServer)((req, res) => this.handleRequest(req, res));
|
|
1341
|
+
this.server.listen(serverPort, this.options.host, () => {
|
|
1342
|
+
console.log(`Coherent.js Node runtime listening on http://${this.options.host}:${serverPort}`);
|
|
1343
|
+
if (callback) callback();
|
|
1344
|
+
});
|
|
1345
|
+
return this.server;
|
|
1346
|
+
},
|
|
1347
|
+
close: (callback) => {
|
|
1348
|
+
if (this.server) {
|
|
1349
|
+
this.server.close(callback);
|
|
1350
|
+
}
|
|
1351
|
+
},
|
|
1352
|
+
// Utilities
|
|
1353
|
+
render: (component, props, options) => this.renderComponent(component, props, options),
|
|
1354
|
+
getRuntime: () => this,
|
|
1355
|
+
getStats: () => ({
|
|
1356
|
+
renderCount: this.renderCount,
|
|
1357
|
+
cacheSize: this.cache.size,
|
|
1358
|
+
componentCount: this.componentRegistry.size,
|
|
1359
|
+
routeCount: this.routeRegistry.size,
|
|
1360
|
+
middlewareCount: this.middleware.length
|
|
1361
|
+
})
|
|
1362
|
+
};
|
|
1363
|
+
return app;
|
|
1364
|
+
}
|
|
1365
|
+
// Framework integration helpers
|
|
1366
|
+
expressMiddleware() {
|
|
1367
|
+
return async (req, res, next) => {
|
|
1368
|
+
req.coherent = {
|
|
1369
|
+
render: async (component, props, options) => {
|
|
1370
|
+
const html = await this.renderComponent(component, props, options);
|
|
1371
|
+
res.send(html);
|
|
1372
|
+
},
|
|
1373
|
+
runtime: this
|
|
1374
|
+
};
|
|
1375
|
+
next();
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
fastifyPlugin() {
|
|
1379
|
+
return async (fastify) => {
|
|
1380
|
+
fastify.decorate("coherent", {
|
|
1381
|
+
render: async (component, props, renderOptions) => {
|
|
1382
|
+
return await this.renderComponent(component, props, renderOptions);
|
|
1383
|
+
},
|
|
1384
|
+
runtime: this
|
|
1385
|
+
});
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
koaMiddleware() {
|
|
1389
|
+
return async (ctx, next) => {
|
|
1390
|
+
ctx.coherent = {
|
|
1391
|
+
render: async (component, props, options) => {
|
|
1392
|
+
const html = await this.renderComponent(component, props, options);
|
|
1393
|
+
ctx.type = "html";
|
|
1394
|
+
ctx.body = html;
|
|
1395
|
+
},
|
|
1396
|
+
runtime: this
|
|
1397
|
+
};
|
|
1398
|
+
await next();
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
};
|
|
1402
|
+
node_default = NodeRuntime;
|
|
1403
|
+
}
|
|
1404
|
+
});
|
|
1405
|
+
|
|
1406
|
+
// src/index.js
|
|
1407
|
+
var index_exports = {};
|
|
1408
|
+
__export(index_exports, {
|
|
1409
|
+
AssetManager: () => AssetManager,
|
|
1410
|
+
BrowserRuntime: () => BrowserRuntime,
|
|
1411
|
+
ComponentLoader: () => ComponentLoader,
|
|
1412
|
+
DesktopRuntime: () => DesktopRuntime,
|
|
1413
|
+
EdgeRuntime: () => EdgeRuntime2,
|
|
1414
|
+
ModuleResolver: () => ModuleResolver,
|
|
1415
|
+
RuntimeDetector: () => RuntimeDetector,
|
|
1416
|
+
RuntimeEnvironment: () => RuntimeEnvironment,
|
|
1417
|
+
StaticRuntime: () => StaticRuntime,
|
|
1418
|
+
UniversalLoader: () => UniversalLoader,
|
|
1419
|
+
VERSION: () => VERSION,
|
|
1420
|
+
createCoherentApp: () => createCoherentApp,
|
|
1421
|
+
createRuntime: () => createRuntime,
|
|
1422
|
+
detectRuntime: () => detectRuntime,
|
|
1423
|
+
renderApp: () => renderApp
|
|
1424
|
+
});
|
|
1425
|
+
module.exports = __toCommonJS(index_exports);
|
|
1426
|
+
__reExport(index_exports, require("@coherent.js/core"), module.exports);
|
|
1427
|
+
__reExport(index_exports, require("@coherent.js/client"), module.exports);
|
|
1428
|
+
__reExport(index_exports, require("@coherent.js/web-components"), module.exports);
|
|
1429
|
+
init_browser();
|
|
1430
|
+
init_edge();
|
|
1431
|
+
init_static();
|
|
1432
|
+
|
|
1433
|
+
// src/runtimes/desktop.js
|
|
1434
|
+
init_browser();
|
|
1435
|
+
var DesktopRuntime = class _DesktopRuntime extends BrowserRuntime {
|
|
1436
|
+
constructor(options = {}) {
|
|
1437
|
+
super({
|
|
1438
|
+
enableFileSystem: true,
|
|
1439
|
+
enableNativeAPIs: true,
|
|
1440
|
+
...options
|
|
1441
|
+
});
|
|
1442
|
+
this.desktopAPI = null;
|
|
1443
|
+
this.isElectron = typeof window !== "undefined" && !!window.require;
|
|
1444
|
+
this.isTauri = typeof window !== "undefined" && !!window.__TAURI__;
|
|
1445
|
+
}
|
|
1446
|
+
async initialize() {
|
|
1447
|
+
await super.initialize();
|
|
1448
|
+
if (this.isElectron) {
|
|
1449
|
+
this.initializeElectron();
|
|
1450
|
+
} else if (this.isTauri) {
|
|
1451
|
+
this.initializeTauri();
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
initializeElectron() {
|
|
1455
|
+
try {
|
|
1456
|
+
this.desktopAPI = {
|
|
1457
|
+
platform: "electron",
|
|
1458
|
+
fs: window.require ? window.require("fs") : null,
|
|
1459
|
+
path: window.require ? window.require("path") : null,
|
|
1460
|
+
ipcRenderer: window.require ? window.require("electron").ipcRenderer : null
|
|
1461
|
+
};
|
|
1462
|
+
} catch (error) {
|
|
1463
|
+
console.warn("Failed to initialize Electron APIs:", error);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
async initializeTauri() {
|
|
1467
|
+
try {
|
|
1468
|
+
if (window.__TAURI__) {
|
|
1469
|
+
this.desktopAPI = {
|
|
1470
|
+
platform: "tauri",
|
|
1471
|
+
fs: window.__TAURI__.fs,
|
|
1472
|
+
path: window.__TAURI__.path,
|
|
1473
|
+
invoke: window.__TAURI__.invoke
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
} catch (error) {
|
|
1477
|
+
console.warn("Failed to initialize Tauri APIs:", error);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
// Desktop-specific methods
|
|
1481
|
+
async readFile(path) {
|
|
1482
|
+
if (this.desktopAPI?.fs) {
|
|
1483
|
+
return await this.desktopAPI.fs.readTextFile(path);
|
|
1484
|
+
}
|
|
1485
|
+
throw new Error("File system access not available");
|
|
1486
|
+
}
|
|
1487
|
+
async writeFile(path, content) {
|
|
1488
|
+
if (this.desktopAPI?.fs) {
|
|
1489
|
+
return await this.desktopAPI.fs.writeTextFile(path, content);
|
|
1490
|
+
}
|
|
1491
|
+
throw new Error("File system access not available");
|
|
1492
|
+
}
|
|
1493
|
+
async showDialog(options) {
|
|
1494
|
+
if (this.isElectron && this.desktopAPI?.ipcRenderer) {
|
|
1495
|
+
return await this.desktopAPI.ipcRenderer.invoke("show-dialog", options);
|
|
1496
|
+
} else if (this.isTauri && this.desktopAPI?.invoke) {
|
|
1497
|
+
return await this.desktopAPI.invoke("show_dialog", options);
|
|
1498
|
+
}
|
|
1499
|
+
console.warn("Desktop dialog not available, rejecting by default");
|
|
1500
|
+
return Promise.resolve(false);
|
|
1501
|
+
}
|
|
1502
|
+
static createApp(options = {}) {
|
|
1503
|
+
const runtime = new _DesktopRuntime(options);
|
|
1504
|
+
return runtime.createApp(options);
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
|
|
1508
|
+
// src/loaders/universal-loader.js
|
|
1509
|
+
var UniversalLoader = class _UniversalLoader {
|
|
1510
|
+
constructor(options = {}) {
|
|
1511
|
+
this.options = {
|
|
1512
|
+
baseUrl: "",
|
|
1513
|
+
moduleMap: {},
|
|
1514
|
+
fallbackUrls: [],
|
|
1515
|
+
cache: true,
|
|
1516
|
+
...options
|
|
1517
|
+
};
|
|
1518
|
+
this.moduleCache = /* @__PURE__ */ new Map();
|
|
1519
|
+
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
1520
|
+
this.environment = this.detectEnvironment();
|
|
1521
|
+
}
|
|
1522
|
+
detectEnvironment() {
|
|
1523
|
+
if (typeof Deno !== "undefined") return "deno";
|
|
1524
|
+
if (typeof Bun !== "undefined") return "bun";
|
|
1525
|
+
if (typeof window !== "undefined") return "browser";
|
|
1526
|
+
if (typeof global !== "undefined" && typeof require !== "undefined") return "node";
|
|
1527
|
+
if (typeof WorkerGlobalScope !== "undefined") return "worker";
|
|
1528
|
+
return "unknown";
|
|
1529
|
+
}
|
|
1530
|
+
// Universal module loading
|
|
1531
|
+
async load(modulePath, options = {}) {
|
|
1532
|
+
const resolvedPath = this.resolvePath(modulePath, options);
|
|
1533
|
+
const cacheKey = resolvedPath + JSON.stringify(options);
|
|
1534
|
+
if (this.options.cache && this.moduleCache.has(cacheKey)) {
|
|
1535
|
+
return this.moduleCache.get(cacheKey);
|
|
1536
|
+
}
|
|
1537
|
+
if (this.loadingPromises.has(cacheKey)) {
|
|
1538
|
+
return this.loadingPromises.get(cacheKey);
|
|
1539
|
+
}
|
|
1540
|
+
const loadingPromise = this.loadModule(resolvedPath, options);
|
|
1541
|
+
this.loadingPromises.set(cacheKey, loadingPromise);
|
|
1542
|
+
try {
|
|
1543
|
+
const module2 = await loadingPromise;
|
|
1544
|
+
if (this.options.cache) {
|
|
1545
|
+
this.moduleCache.set(cacheKey, module2);
|
|
1546
|
+
}
|
|
1547
|
+
return module2;
|
|
1548
|
+
} finally {
|
|
1549
|
+
this.loadingPromises.delete(cacheKey);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
async loadModule(modulePath, options = {}) {
|
|
1553
|
+
switch (this.environment) {
|
|
1554
|
+
case "browser":
|
|
1555
|
+
return await this.loadBrowserModule(modulePath, options);
|
|
1556
|
+
case "node":
|
|
1557
|
+
return await this.loadNodeModule(modulePath, options);
|
|
1558
|
+
case "deno":
|
|
1559
|
+
return await this.loadDenoModule(modulePath, options);
|
|
1560
|
+
case "bun":
|
|
1561
|
+
return await this.loadBunModule(modulePath, options);
|
|
1562
|
+
case "worker":
|
|
1563
|
+
return await this.loadWorkerModule(modulePath, options);
|
|
1564
|
+
default:
|
|
1565
|
+
return await this.loadGenericModule(modulePath, options);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
async loadBrowserModule(modulePath, options = {}) {
|
|
1569
|
+
if (modulePath.startsWith("http") || modulePath.startsWith("/")) {
|
|
1570
|
+
try {
|
|
1571
|
+
return await import(modulePath);
|
|
1572
|
+
} catch {
|
|
1573
|
+
return await this.loadScript(modulePath, options);
|
|
1574
|
+
}
|
|
1575
|
+
} else {
|
|
1576
|
+
const cdnUrl = this.toCdnUrl(modulePath);
|
|
1577
|
+
return await import(cdnUrl);
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
async loadNodeModule(modulePath) {
|
|
1581
|
+
if (typeof require !== "undefined") {
|
|
1582
|
+
try {
|
|
1583
|
+
return require(modulePath);
|
|
1584
|
+
} catch {
|
|
1585
|
+
return await import(modulePath);
|
|
1586
|
+
}
|
|
1587
|
+
} else {
|
|
1588
|
+
return await import(modulePath);
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
async loadDenoModule(modulePath) {
|
|
1592
|
+
if (modulePath.startsWith("npm:")) {
|
|
1593
|
+
return await import(modulePath);
|
|
1594
|
+
} else if (modulePath.startsWith("http")) {
|
|
1595
|
+
return await import(modulePath);
|
|
1596
|
+
} else {
|
|
1597
|
+
return await import(`npm:${modulePath}`);
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
async loadBunModule(modulePath) {
|
|
1601
|
+
try {
|
|
1602
|
+
return await import(modulePath);
|
|
1603
|
+
} catch (error) {
|
|
1604
|
+
if (typeof require !== "undefined") {
|
|
1605
|
+
return require(modulePath);
|
|
1606
|
+
}
|
|
1607
|
+
throw error;
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
async loadWorkerModule(modulePath) {
|
|
1611
|
+
return await import(modulePath);
|
|
1612
|
+
}
|
|
1613
|
+
async loadGenericModule(modulePath) {
|
|
1614
|
+
return await import(modulePath);
|
|
1615
|
+
}
|
|
1616
|
+
async loadScript(src, options = {}) {
|
|
1617
|
+
return new Promise((resolve, reject) => {
|
|
1618
|
+
const script = document.createElement("script");
|
|
1619
|
+
script.type = "module";
|
|
1620
|
+
script.src = src;
|
|
1621
|
+
script.onload = () => {
|
|
1622
|
+
const moduleName = options.globalName || this.getModuleNameFromPath(src);
|
|
1623
|
+
const module2 = window[moduleName] || {};
|
|
1624
|
+
resolve(module2);
|
|
1625
|
+
};
|
|
1626
|
+
script.onerror = () => reject(new Error(`Failed to load script: ${src}`));
|
|
1627
|
+
document.head.appendChild(script);
|
|
1628
|
+
});
|
|
1629
|
+
}
|
|
1630
|
+
resolvePath(modulePath, options = {}) {
|
|
1631
|
+
if (modulePath.startsWith("http://") || modulePath.startsWith("https://")) {
|
|
1632
|
+
return modulePath;
|
|
1633
|
+
}
|
|
1634
|
+
if (modulePath.startsWith("./") || modulePath.startsWith("../")) {
|
|
1635
|
+
return this.resolveRelativePath(modulePath, options.baseUrl || this.options.baseUrl);
|
|
1636
|
+
}
|
|
1637
|
+
if (this.options.moduleMap[modulePath]) {
|
|
1638
|
+
return this.options.moduleMap[modulePath];
|
|
1639
|
+
}
|
|
1640
|
+
return this.options.baseUrl + modulePath;
|
|
1641
|
+
}
|
|
1642
|
+
resolveRelativePath(relativePath, baseUrl) {
|
|
1643
|
+
if (!baseUrl) return relativePath;
|
|
1644
|
+
const base = new URL(baseUrl, location?.href || "file:///");
|
|
1645
|
+
const resolved = new URL(relativePath, base);
|
|
1646
|
+
return resolved.href;
|
|
1647
|
+
}
|
|
1648
|
+
toCdnUrl(packageName, version = "latest") {
|
|
1649
|
+
const _cleanName = packageName.replace(/^@/, "").replace("/", "-");
|
|
1650
|
+
return `https://unpkg.com/${packageName}@${version}/dist/index.js`;
|
|
1651
|
+
}
|
|
1652
|
+
getModuleNameFromPath(path) {
|
|
1653
|
+
const filename = path.split("/").pop().split(".")[0];
|
|
1654
|
+
return filename.replace(/[-_]/g, "");
|
|
1655
|
+
}
|
|
1656
|
+
// Batch loading
|
|
1657
|
+
async loadAll(modulePaths, options = {}) {
|
|
1658
|
+
const loadPromises = modulePaths.map(
|
|
1659
|
+
(path) => this.load(path, options).catch((error) => ({ error, path }))
|
|
1660
|
+
);
|
|
1661
|
+
return await Promise.all(loadPromises);
|
|
1662
|
+
}
|
|
1663
|
+
// Preloading
|
|
1664
|
+
async preload(modulePaths, options = {}) {
|
|
1665
|
+
const preloadPromises = modulePaths.map(async (path) => {
|
|
1666
|
+
try {
|
|
1667
|
+
await this.load(path, { ...options, preload: true });
|
|
1668
|
+
return { success: true, path };
|
|
1669
|
+
} catch (error) {
|
|
1670
|
+
return { success: false, path, error };
|
|
1671
|
+
}
|
|
1672
|
+
});
|
|
1673
|
+
return await Promise.all(preloadPromises);
|
|
1674
|
+
}
|
|
1675
|
+
// Cache management
|
|
1676
|
+
clearCache() {
|
|
1677
|
+
this.moduleCache.clear();
|
|
1678
|
+
}
|
|
1679
|
+
getCacheStats() {
|
|
1680
|
+
return {
|
|
1681
|
+
size: this.moduleCache.size,
|
|
1682
|
+
modules: Array.from(this.moduleCache.keys())
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
// Environment detection helpers
|
|
1686
|
+
static isSupported() {
|
|
1687
|
+
return (() => {
|
|
1688
|
+
try {
|
|
1689
|
+
return typeof Function('return import("")') === "function";
|
|
1690
|
+
} catch {
|
|
1691
|
+
return false;
|
|
1692
|
+
}
|
|
1693
|
+
})() || typeof require !== "undefined";
|
|
1694
|
+
}
|
|
1695
|
+
static getCapabilities() {
|
|
1696
|
+
return {
|
|
1697
|
+
dynamicImport: (() => {
|
|
1698
|
+
try {
|
|
1699
|
+
return typeof Function('return import("")') === "function";
|
|
1700
|
+
} catch {
|
|
1701
|
+
return false;
|
|
1702
|
+
}
|
|
1703
|
+
})(),
|
|
1704
|
+
require: typeof require !== "undefined",
|
|
1705
|
+
fetch: typeof fetch !== "undefined",
|
|
1706
|
+
worker: typeof Worker !== "undefined",
|
|
1707
|
+
environment: new _UniversalLoader().environment
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
};
|
|
1711
|
+
var universalLoader = new UniversalLoader();
|
|
1712
|
+
|
|
1713
|
+
// src/loaders/component-loader.js
|
|
1714
|
+
var ComponentLoader = class {
|
|
1715
|
+
constructor(options = {}) {
|
|
1716
|
+
this.options = {
|
|
1717
|
+
componentRegistry: /* @__PURE__ */ new Map(),
|
|
1718
|
+
lazyLoad: true,
|
|
1719
|
+
preloadComponents: [],
|
|
1720
|
+
componentPaths: {},
|
|
1721
|
+
...options
|
|
1722
|
+
};
|
|
1723
|
+
this.loader = universalLoader;
|
|
1724
|
+
this.loadingQueue = /* @__PURE__ */ new Map();
|
|
1725
|
+
this.dependencyGraph = /* @__PURE__ */ new Map();
|
|
1726
|
+
this.loadedComponents = /* @__PURE__ */ new Set();
|
|
1727
|
+
}
|
|
1728
|
+
// Register a component with its metadata
|
|
1729
|
+
registerComponent(name, componentOrPath, options = {}) {
|
|
1730
|
+
const registration = {
|
|
1731
|
+
name,
|
|
1732
|
+
path: typeof componentOrPath === "string" ? componentOrPath : null,
|
|
1733
|
+
component: typeof componentOrPath === "function" ? componentOrPath : null,
|
|
1734
|
+
loaded: typeof componentOrPath === "function",
|
|
1735
|
+
dependencies: options.dependencies || [],
|
|
1736
|
+
lazy: options.lazy !== false,
|
|
1737
|
+
preload: options.preload || false,
|
|
1738
|
+
metadata: options.metadata || {},
|
|
1739
|
+
...options
|
|
1740
|
+
};
|
|
1741
|
+
this.options.componentRegistry.set(name, registration);
|
|
1742
|
+
if (registration.dependencies.length > 0) {
|
|
1743
|
+
this.dependencyGraph.set(name, registration.dependencies);
|
|
1744
|
+
}
|
|
1745
|
+
if (!registration.lazy && registration.path && !registration.loaded) {
|
|
1746
|
+
this.loadComponent(name);
|
|
1747
|
+
}
|
|
1748
|
+
return registration;
|
|
1749
|
+
}
|
|
1750
|
+
// Load a component by name
|
|
1751
|
+
async loadComponent(name, options = {}) {
|
|
1752
|
+
const registration = this.options.componentRegistry.get(name);
|
|
1753
|
+
if (!registration) {
|
|
1754
|
+
throw new Error(`Component '${name}' not found in registry`);
|
|
1755
|
+
}
|
|
1756
|
+
if (registration.loaded && registration.component) {
|
|
1757
|
+
return registration.component;
|
|
1758
|
+
}
|
|
1759
|
+
if (this.loadingQueue.has(name)) {
|
|
1760
|
+
return this.loadingQueue.get(name);
|
|
1761
|
+
}
|
|
1762
|
+
const loadingPromise = this.doLoadComponent(registration, options);
|
|
1763
|
+
this.loadingQueue.set(name, loadingPromise);
|
|
1764
|
+
try {
|
|
1765
|
+
const component = await loadingPromise;
|
|
1766
|
+
registration.component = component;
|
|
1767
|
+
registration.loaded = true;
|
|
1768
|
+
this.loadedComponents.add(name);
|
|
1769
|
+
return component;
|
|
1770
|
+
} finally {
|
|
1771
|
+
this.loadingQueue.delete(name);
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
async doLoadComponent(registration, options = {}) {
|
|
1775
|
+
const { name, path, dependencies } = registration;
|
|
1776
|
+
try {
|
|
1777
|
+
if (dependencies.length > 0) {
|
|
1778
|
+
await this.loadDependencies(dependencies, options);
|
|
1779
|
+
}
|
|
1780
|
+
let component;
|
|
1781
|
+
if (path) {
|
|
1782
|
+
const module2 = await this.loader.load(path, options);
|
|
1783
|
+
component = this.extractComponent(module2, name);
|
|
1784
|
+
} else if (registration.component) {
|
|
1785
|
+
component = registration.component;
|
|
1786
|
+
} else {
|
|
1787
|
+
throw new Error(`No component or path specified for '${name}'`);
|
|
1788
|
+
}
|
|
1789
|
+
return this.processComponent(component, registration, options);
|
|
1790
|
+
} catch (error) {
|
|
1791
|
+
console.error(`Failed to load component '${name}':`, error);
|
|
1792
|
+
throw error;
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
extractComponent(module2, componentName) {
|
|
1796
|
+
if (module2.default && typeof module2.default === "function") {
|
|
1797
|
+
return module2.default;
|
|
1798
|
+
}
|
|
1799
|
+
if (module2[componentName] && typeof module2[componentName] === "function") {
|
|
1800
|
+
return module2[componentName];
|
|
1801
|
+
}
|
|
1802
|
+
for (const [key, value] of Object.entries(module2)) {
|
|
1803
|
+
if (typeof value === "function" && key !== "default") {
|
|
1804
|
+
return value;
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
throw new Error(`No valid component function found in module for '${componentName}'`);
|
|
1808
|
+
}
|
|
1809
|
+
processComponent(component, registration, options = {}) {
|
|
1810
|
+
if (registration.metadata) {
|
|
1811
|
+
Object.assign(component, {
|
|
1812
|
+
$meta: registration.metadata,
|
|
1813
|
+
$name: registration.name
|
|
1814
|
+
});
|
|
1815
|
+
}
|
|
1816
|
+
if (options.wrapper) {
|
|
1817
|
+
return options.wrapper(component, registration);
|
|
1818
|
+
}
|
|
1819
|
+
return component;
|
|
1820
|
+
}
|
|
1821
|
+
async loadDependencies(dependencies, options = {}) {
|
|
1822
|
+
const dependencyPromises = dependencies.map((depName) => {
|
|
1823
|
+
return this.loadComponent(depName, options);
|
|
1824
|
+
});
|
|
1825
|
+
await Promise.all(dependencyPromises);
|
|
1826
|
+
}
|
|
1827
|
+
// Batch component loading
|
|
1828
|
+
async loadComponents(componentNames, options = {}) {
|
|
1829
|
+
const loadPromises = componentNames.map(
|
|
1830
|
+
(name) => this.loadComponent(name, options).catch((error) => ({ error, name }))
|
|
1831
|
+
);
|
|
1832
|
+
const results = await Promise.all(loadPromises);
|
|
1833
|
+
const loaded = {};
|
|
1834
|
+
const errors = [];
|
|
1835
|
+
results.forEach((result, index) => {
|
|
1836
|
+
const name = componentNames[index];
|
|
1837
|
+
if (result && result.error) {
|
|
1838
|
+
errors.push({ name, error: result.error });
|
|
1839
|
+
} else {
|
|
1840
|
+
loaded[name] = result;
|
|
1841
|
+
}
|
|
1842
|
+
});
|
|
1843
|
+
return { loaded, errors };
|
|
1844
|
+
}
|
|
1845
|
+
// Preload components
|
|
1846
|
+
async preloadComponents(componentNames = null) {
|
|
1847
|
+
const toPreload = componentNames || this.getPreloadableComponents();
|
|
1848
|
+
const preloadResults = await Promise.allSettled(
|
|
1849
|
+
toPreload.map((name) => this.loadComponent(name, { preload: true }))
|
|
1850
|
+
);
|
|
1851
|
+
const results = {
|
|
1852
|
+
successful: [],
|
|
1853
|
+
failed: []
|
|
1854
|
+
};
|
|
1855
|
+
preloadResults.forEach((result, index) => {
|
|
1856
|
+
const name = toPreload[index];
|
|
1857
|
+
if (result.status === "fulfilled") {
|
|
1858
|
+
results.successful.push(name);
|
|
1859
|
+
} else {
|
|
1860
|
+
results.failed.push({ name, error: result.reason });
|
|
1861
|
+
}
|
|
1862
|
+
});
|
|
1863
|
+
return results;
|
|
1864
|
+
}
|
|
1865
|
+
getPreloadableComponents() {
|
|
1866
|
+
return Array.from(this.options.componentRegistry.values()).filter((reg) => reg.preload && !reg.loaded).map((reg) => reg.name);
|
|
1867
|
+
}
|
|
1868
|
+
// Component discovery
|
|
1869
|
+
async discoverComponents(basePath, options = {}) {
|
|
1870
|
+
const discovered = [];
|
|
1871
|
+
try {
|
|
1872
|
+
if (typeof fetch !== "undefined") {
|
|
1873
|
+
discovered.push(...await this.discoverFromManifest(basePath, options));
|
|
1874
|
+
} else if (typeof require !== "undefined") {
|
|
1875
|
+
discovered.push(...await this.discoverFromFileSystem(basePath, options));
|
|
1876
|
+
}
|
|
1877
|
+
} catch (error) {
|
|
1878
|
+
console.warn("Component discovery failed:", error);
|
|
1879
|
+
}
|
|
1880
|
+
return discovered;
|
|
1881
|
+
}
|
|
1882
|
+
async discoverFromManifest(basePath, _options = {}) {
|
|
1883
|
+
try {
|
|
1884
|
+
const manifestUrl = `${basePath}/components.json`;
|
|
1885
|
+
const response = await fetch(manifestUrl);
|
|
1886
|
+
const manifest = await response.json();
|
|
1887
|
+
return manifest.components || [];
|
|
1888
|
+
} catch {
|
|
1889
|
+
return [];
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
async discoverFromFileSystem(basePath, _options = {}) {
|
|
1893
|
+
return [];
|
|
1894
|
+
}
|
|
1895
|
+
// Auto-registration from patterns
|
|
1896
|
+
registerComponentPattern(pattern, options = {}) {
|
|
1897
|
+
this.componentPatterns = this.componentPatterns || [];
|
|
1898
|
+
this.componentPatterns.push({ pattern, options });
|
|
1899
|
+
}
|
|
1900
|
+
// Dependency analysis
|
|
1901
|
+
analyzeDependencies() {
|
|
1902
|
+
const analysis = {
|
|
1903
|
+
circular: [],
|
|
1904
|
+
missing: [],
|
|
1905
|
+
unused: [],
|
|
1906
|
+
depth: /* @__PURE__ */ new Map()
|
|
1907
|
+
};
|
|
1908
|
+
analysis.circular = this.findCircularDependencies();
|
|
1909
|
+
analysis.missing = this.findMissingDependencies();
|
|
1910
|
+
analysis.unused = this.findUnusedComponents();
|
|
1911
|
+
analysis.depth = this.calculateDependencyDepths();
|
|
1912
|
+
return analysis;
|
|
1913
|
+
}
|
|
1914
|
+
findCircularDependencies() {
|
|
1915
|
+
const circular = [];
|
|
1916
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1917
|
+
const recursionStack = /* @__PURE__ */ new Set();
|
|
1918
|
+
const visit = (componentName, path = []) => {
|
|
1919
|
+
if (recursionStack.has(componentName)) {
|
|
1920
|
+
circular.push([...path, componentName]);
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
if (visited.has(componentName)) return;
|
|
1924
|
+
visited.add(componentName);
|
|
1925
|
+
recursionStack.add(componentName);
|
|
1926
|
+
const dependencies = this.dependencyGraph.get(componentName) || [];
|
|
1927
|
+
dependencies.forEach((dep) => {
|
|
1928
|
+
visit(dep, [...path, componentName]);
|
|
1929
|
+
});
|
|
1930
|
+
recursionStack.delete(componentName);
|
|
1931
|
+
};
|
|
1932
|
+
Array.from(this.dependencyGraph.keys()).forEach(visit);
|
|
1933
|
+
return circular;
|
|
1934
|
+
}
|
|
1935
|
+
findMissingDependencies() {
|
|
1936
|
+
const missing = [];
|
|
1937
|
+
for (const [component, dependencies] of this.dependencyGraph) {
|
|
1938
|
+
for (const dep of dependencies) {
|
|
1939
|
+
if (!this.options.componentRegistry.has(dep)) {
|
|
1940
|
+
missing.push({ component, dependency: dep });
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
return missing;
|
|
1945
|
+
}
|
|
1946
|
+
findUnusedComponents() {
|
|
1947
|
+
const used = /* @__PURE__ */ new Set();
|
|
1948
|
+
for (const dependencies of this.dependencyGraph.values()) {
|
|
1949
|
+
dependencies.forEach((dep) => used.add(dep));
|
|
1950
|
+
}
|
|
1951
|
+
const unused = [];
|
|
1952
|
+
for (const name of this.options.componentRegistry.keys()) {
|
|
1953
|
+
if (!used.has(name)) {
|
|
1954
|
+
unused.push(name);
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
return unused;
|
|
1958
|
+
}
|
|
1959
|
+
calculateDependencyDepths() {
|
|
1960
|
+
const depths = /* @__PURE__ */ new Map();
|
|
1961
|
+
const calculateDepth = (componentName, visited = /* @__PURE__ */ new Set()) => {
|
|
1962
|
+
if (depths.has(componentName)) {
|
|
1963
|
+
return depths.get(componentName);
|
|
1964
|
+
}
|
|
1965
|
+
if (visited.has(componentName)) {
|
|
1966
|
+
return Infinity;
|
|
1967
|
+
}
|
|
1968
|
+
visited.add(componentName);
|
|
1969
|
+
const dependencies = this.dependencyGraph.get(componentName) || [];
|
|
1970
|
+
const maxDepth = dependencies.length === 0 ? 0 : Math.max(...dependencies.map((dep) => calculateDepth(dep, new Set(visited)))) + 1;
|
|
1971
|
+
depths.set(componentName, maxDepth);
|
|
1972
|
+
return maxDepth;
|
|
1973
|
+
};
|
|
1974
|
+
for (const componentName of this.options.componentRegistry.keys()) {
|
|
1975
|
+
calculateDepth(componentName);
|
|
1976
|
+
}
|
|
1977
|
+
return depths;
|
|
1978
|
+
}
|
|
1979
|
+
// Utilities
|
|
1980
|
+
getRegisteredComponents() {
|
|
1981
|
+
return Array.from(this.options.componentRegistry.keys());
|
|
1982
|
+
}
|
|
1983
|
+
getLoadedComponents() {
|
|
1984
|
+
return Array.from(this.loadedComponents);
|
|
1985
|
+
}
|
|
1986
|
+
getComponentInfo(name) {
|
|
1987
|
+
return this.options.componentRegistry.get(name);
|
|
1988
|
+
}
|
|
1989
|
+
isComponentLoaded(name) {
|
|
1990
|
+
return this.loadedComponents.has(name);
|
|
1991
|
+
}
|
|
1992
|
+
clearCache() {
|
|
1993
|
+
this.loader.clearCache();
|
|
1994
|
+
this.loadingQueue.clear();
|
|
1995
|
+
}
|
|
1996
|
+
getStats() {
|
|
1997
|
+
return {
|
|
1998
|
+
registered: this.options.componentRegistry.size,
|
|
1999
|
+
loaded: this.loadedComponents.size,
|
|
2000
|
+
loading: this.loadingQueue.size,
|
|
2001
|
+
dependencies: this.dependencyGraph.size
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
};
|
|
2005
|
+
var componentLoader = new ComponentLoader();
|
|
2006
|
+
|
|
2007
|
+
// src/runtime-factory.js
|
|
2008
|
+
var RuntimeEnvironment = {
|
|
2009
|
+
BROWSER: "browser",
|
|
2010
|
+
NODE: "node",
|
|
2011
|
+
EDGE: "edge",
|
|
2012
|
+
CLOUDFLARE: "cloudflare",
|
|
2013
|
+
DENO: "deno",
|
|
2014
|
+
BUN: "bun",
|
|
2015
|
+
ELECTRON: "electron",
|
|
2016
|
+
TAURI: "tauri",
|
|
2017
|
+
STATIC: "static"
|
|
2018
|
+
};
|
|
2019
|
+
function detectRuntime() {
|
|
2020
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
2021
|
+
if (typeof window.require !== "undefined" || typeof window.process !== "undefined" && window.process.versions?.electron) {
|
|
2022
|
+
return RuntimeEnvironment.ELECTRON;
|
|
2023
|
+
}
|
|
2024
|
+
if (typeof window.__TAURI__ !== "undefined") {
|
|
2025
|
+
return RuntimeEnvironment.TAURI;
|
|
2026
|
+
}
|
|
2027
|
+
return RuntimeEnvironment.BROWSER;
|
|
2028
|
+
}
|
|
2029
|
+
if (typeof process !== "undefined") {
|
|
2030
|
+
if (process.versions?.node) {
|
|
2031
|
+
return RuntimeEnvironment.NODE;
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
if (typeof EdgeRuntime !== "undefined") {
|
|
2035
|
+
return RuntimeEnvironment.EDGE;
|
|
2036
|
+
}
|
|
2037
|
+
if (typeof caches !== "undefined" && typeof Request !== "undefined" && typeof Response !== "undefined" && typeof addEventListener !== "undefined") {
|
|
2038
|
+
return RuntimeEnvironment.CLOUDFLARE;
|
|
2039
|
+
}
|
|
2040
|
+
if (typeof Deno !== "undefined") {
|
|
2041
|
+
return RuntimeEnvironment.DENO;
|
|
2042
|
+
}
|
|
2043
|
+
if (typeof Bun !== "undefined") {
|
|
2044
|
+
return RuntimeEnvironment.BUN;
|
|
2045
|
+
}
|
|
2046
|
+
return RuntimeEnvironment.BROWSER;
|
|
2047
|
+
}
|
|
2048
|
+
async function createRuntime(options = {}) {
|
|
2049
|
+
const environment = options.environment || detectRuntime();
|
|
2050
|
+
switch (environment) {
|
|
2051
|
+
case RuntimeEnvironment.BROWSER:
|
|
2052
|
+
case RuntimeEnvironment.ELECTRON:
|
|
2053
|
+
case RuntimeEnvironment.TAURI: {
|
|
2054
|
+
const { BrowserRuntime: BrowserRuntime2 } = await Promise.resolve().then(() => (init_browser(), browser_exports));
|
|
2055
|
+
return new BrowserRuntime2(options);
|
|
2056
|
+
}
|
|
2057
|
+
case RuntimeEnvironment.EDGE:
|
|
2058
|
+
case RuntimeEnvironment.CLOUDFLARE:
|
|
2059
|
+
case RuntimeEnvironment.DENO:
|
|
2060
|
+
case RuntimeEnvironment.BUN: {
|
|
2061
|
+
const { EdgeRuntime: EdgeRuntime3 } = await Promise.resolve().then(() => (init_edge(), edge_exports));
|
|
2062
|
+
return new EdgeRuntime3(options);
|
|
2063
|
+
}
|
|
2064
|
+
case RuntimeEnvironment.NODE: {
|
|
2065
|
+
const { NodeRuntime: NodeRuntime2 } = await Promise.resolve().then(() => (init_node(), node_exports));
|
|
2066
|
+
return new NodeRuntime2(options);
|
|
2067
|
+
}
|
|
2068
|
+
case RuntimeEnvironment.STATIC: {
|
|
2069
|
+
const { StaticRuntime: StaticRuntime2 } = await Promise.resolve().then(() => (init_static(), static_exports));
|
|
2070
|
+
return new StaticRuntime2(options);
|
|
2071
|
+
}
|
|
2072
|
+
default:
|
|
2073
|
+
throw new Error(`Unsupported runtime environment: ${environment}`);
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
// src/utils/runtime-detector.js
|
|
2078
|
+
var RuntimeEnvironment2 = {
|
|
2079
|
+
BROWSER: "browser",
|
|
2080
|
+
NODE: "node",
|
|
2081
|
+
DENO: "deno",
|
|
2082
|
+
BUN: "bun",
|
|
2083
|
+
EDGE: "edge",
|
|
2084
|
+
CLOUDFLARE: "cloudflare",
|
|
2085
|
+
ELECTRON: "electron",
|
|
2086
|
+
TAURI: "tauri",
|
|
2087
|
+
WEBVIEW: "webview",
|
|
2088
|
+
STATIC: "static",
|
|
2089
|
+
UNKNOWN: "unknown"
|
|
2090
|
+
};
|
|
2091
|
+
var RuntimeDetector = class _RuntimeDetector {
|
|
2092
|
+
constructor() {
|
|
2093
|
+
this.detectionResult = null;
|
|
2094
|
+
this.capabilities = null;
|
|
2095
|
+
}
|
|
2096
|
+
// Reset detection cache (useful for testing)
|
|
2097
|
+
reset() {
|
|
2098
|
+
this.detectionResult = null;
|
|
2099
|
+
this.capabilities = null;
|
|
2100
|
+
}
|
|
2101
|
+
// Main detection method
|
|
2102
|
+
detect() {
|
|
2103
|
+
if (this.detectionResult) {
|
|
2104
|
+
return this.detectionResult;
|
|
2105
|
+
}
|
|
2106
|
+
this.detectionResult = this.performDetection();
|
|
2107
|
+
return this.detectionResult;
|
|
2108
|
+
}
|
|
2109
|
+
performDetection() {
|
|
2110
|
+
if (this.isTauri()) return RuntimeEnvironment2.TAURI;
|
|
2111
|
+
if (this.isElectron()) return RuntimeEnvironment2.ELECTRON;
|
|
2112
|
+
if (this.isWebView()) return RuntimeEnvironment2.WEBVIEW;
|
|
2113
|
+
if (this.isDeno()) return RuntimeEnvironment2.DENO;
|
|
2114
|
+
if (this.isBun()) return RuntimeEnvironment2.BUN;
|
|
2115
|
+
if (this.isCloudflareWorkers()) return RuntimeEnvironment2.CLOUDFLARE;
|
|
2116
|
+
if (this.isEdgeRuntime()) return RuntimeEnvironment2.EDGE;
|
|
2117
|
+
if (this.isBrowser()) return RuntimeEnvironment2.BROWSER;
|
|
2118
|
+
if (this.isNodeJS()) return RuntimeEnvironment2.NODE;
|
|
2119
|
+
return RuntimeEnvironment2.UNKNOWN;
|
|
2120
|
+
}
|
|
2121
|
+
// Environment-specific detection methods
|
|
2122
|
+
isBrowser() {
|
|
2123
|
+
return typeof window !== "undefined" && typeof document !== "undefined" && typeof navigator !== "undefined";
|
|
2124
|
+
}
|
|
2125
|
+
isNodeJS() {
|
|
2126
|
+
return typeof process !== "undefined" && process.versions && process.versions.node && typeof require !== "undefined";
|
|
2127
|
+
}
|
|
2128
|
+
isDeno() {
|
|
2129
|
+
return typeof Deno !== "undefined" && typeof Deno.version !== "undefined";
|
|
2130
|
+
}
|
|
2131
|
+
isBun() {
|
|
2132
|
+
return typeof Bun !== "undefined" || typeof process !== "undefined" && process.versions && process.versions.bun;
|
|
2133
|
+
}
|
|
2134
|
+
isElectron() {
|
|
2135
|
+
return typeof window !== "undefined" && typeof window.require !== "undefined" && typeof window.require("electron") !== "undefined";
|
|
2136
|
+
}
|
|
2137
|
+
isTauri() {
|
|
2138
|
+
return typeof window !== "undefined" && typeof window.__TAURI__ !== "undefined";
|
|
2139
|
+
}
|
|
2140
|
+
isWebView() {
|
|
2141
|
+
return typeof window !== "undefined" && (typeof window.webkit !== "undefined" || typeof window.external !== "undefined") && !this.isElectron() && !this.isTauri();
|
|
2142
|
+
}
|
|
2143
|
+
isCloudflareWorkers() {
|
|
2144
|
+
return typeof caches !== "undefined" && typeof fetch !== "undefined" && typeof Response !== "undefined" && typeof addEventListener !== "undefined" && typeof window === "undefined";
|
|
2145
|
+
}
|
|
2146
|
+
isEdgeRuntime() {
|
|
2147
|
+
return typeof EdgeRuntime !== "undefined" || typeof globalThis !== "undefined" && typeof globalThis.EdgeRuntime !== "undefined" || this.isVercelEdge() || this.isNetlifyEdge();
|
|
2148
|
+
}
|
|
2149
|
+
isVercelEdge() {
|
|
2150
|
+
return typeof process !== "undefined" && process.env && process.env.VERCEL === "1" && typeof EdgeRuntime !== "undefined";
|
|
2151
|
+
}
|
|
2152
|
+
isNetlifyEdge() {
|
|
2153
|
+
return typeof Netlify !== "undefined" || typeof process !== "undefined" && process.env && process.env.NETLIFY === "true";
|
|
2154
|
+
}
|
|
2155
|
+
// Detailed capability analysis
|
|
2156
|
+
getCapabilities(environment = null) {
|
|
2157
|
+
const env = environment || this.detect();
|
|
2158
|
+
if (this.capabilities && !environment) {
|
|
2159
|
+
return this.capabilities;
|
|
2160
|
+
}
|
|
2161
|
+
const capabilities = this.analyzeCapabilities(env);
|
|
2162
|
+
if (!environment) {
|
|
2163
|
+
this.capabilities = capabilities;
|
|
2164
|
+
}
|
|
2165
|
+
return capabilities;
|
|
2166
|
+
}
|
|
2167
|
+
analyzeCapabilities(environment) {
|
|
2168
|
+
const base = {
|
|
2169
|
+
environment,
|
|
2170
|
+
dom: false,
|
|
2171
|
+
ssr: false,
|
|
2172
|
+
filesystem: false,
|
|
2173
|
+
fetch: false,
|
|
2174
|
+
websockets: false,
|
|
2175
|
+
workers: false,
|
|
2176
|
+
storage: false,
|
|
2177
|
+
crypto: false,
|
|
2178
|
+
streams: false,
|
|
2179
|
+
modules: {
|
|
2180
|
+
esm: false,
|
|
2181
|
+
commonjs: false,
|
|
2182
|
+
dynamicImport: false
|
|
2183
|
+
},
|
|
2184
|
+
apis: {
|
|
2185
|
+
console: false,
|
|
2186
|
+
timers: false,
|
|
2187
|
+
events: false,
|
|
2188
|
+
url: false,
|
|
2189
|
+
base64: false
|
|
2190
|
+
}
|
|
2191
|
+
};
|
|
2192
|
+
switch (environment) {
|
|
2193
|
+
case RuntimeEnvironment2.BROWSER:
|
|
2194
|
+
return {
|
|
2195
|
+
...base,
|
|
2196
|
+
dom: true,
|
|
2197
|
+
fetch: typeof fetch !== "undefined",
|
|
2198
|
+
websockets: typeof WebSocket !== "undefined",
|
|
2199
|
+
workers: typeof Worker !== "undefined",
|
|
2200
|
+
storage: typeof localStorage !== "undefined",
|
|
2201
|
+
crypto: typeof crypto !== "undefined",
|
|
2202
|
+
streams: typeof ReadableStream !== "undefined",
|
|
2203
|
+
modules: {
|
|
2204
|
+
esm: true,
|
|
2205
|
+
commonjs: false,
|
|
2206
|
+
dynamicImport: (() => {
|
|
2207
|
+
try {
|
|
2208
|
+
return typeof Function('return import("")') === "function";
|
|
2209
|
+
} catch {
|
|
2210
|
+
return false;
|
|
2211
|
+
}
|
|
2212
|
+
})()
|
|
2213
|
+
},
|
|
2214
|
+
apis: {
|
|
2215
|
+
console: typeof console !== "undefined",
|
|
2216
|
+
timers: typeof setTimeout !== "undefined",
|
|
2217
|
+
events: typeof EventTarget !== "undefined",
|
|
2218
|
+
url: typeof URL !== "undefined",
|
|
2219
|
+
base64: typeof btoa !== "undefined"
|
|
2220
|
+
}
|
|
2221
|
+
};
|
|
2222
|
+
case RuntimeEnvironment2.NODE:
|
|
2223
|
+
return {
|
|
2224
|
+
...base,
|
|
2225
|
+
ssr: true,
|
|
2226
|
+
filesystem: true,
|
|
2227
|
+
fetch: typeof fetch !== "undefined",
|
|
2228
|
+
websockets: true,
|
|
2229
|
+
crypto: true,
|
|
2230
|
+
streams: true,
|
|
2231
|
+
modules: {
|
|
2232
|
+
esm: true,
|
|
2233
|
+
commonjs: true,
|
|
2234
|
+
dynamicImport: (() => {
|
|
2235
|
+
try {
|
|
2236
|
+
return typeof Function('return import("")') === "function";
|
|
2237
|
+
} catch {
|
|
2238
|
+
return false;
|
|
2239
|
+
}
|
|
2240
|
+
})()
|
|
2241
|
+
},
|
|
2242
|
+
apis: {
|
|
2243
|
+
console: true,
|
|
2244
|
+
timers: true,
|
|
2245
|
+
events: true,
|
|
2246
|
+
url: typeof URL !== "undefined",
|
|
2247
|
+
base64: typeof Buffer !== "undefined"
|
|
2248
|
+
}
|
|
2249
|
+
};
|
|
2250
|
+
case RuntimeEnvironment2.DENO:
|
|
2251
|
+
return {
|
|
2252
|
+
...base,
|
|
2253
|
+
ssr: true,
|
|
2254
|
+
filesystem: typeof Deno.readTextFile !== "undefined",
|
|
2255
|
+
fetch: typeof fetch !== "undefined",
|
|
2256
|
+
websockets: typeof WebSocket !== "undefined",
|
|
2257
|
+
crypto: typeof crypto !== "undefined",
|
|
2258
|
+
streams: typeof ReadableStream !== "undefined",
|
|
2259
|
+
modules: {
|
|
2260
|
+
esm: true,
|
|
2261
|
+
commonjs: false,
|
|
2262
|
+
dynamicImport: true
|
|
2263
|
+
},
|
|
2264
|
+
apis: {
|
|
2265
|
+
console: true,
|
|
2266
|
+
timers: true,
|
|
2267
|
+
events: true,
|
|
2268
|
+
url: typeof URL !== "undefined",
|
|
2269
|
+
base64: typeof btoa !== "undefined"
|
|
2270
|
+
}
|
|
2271
|
+
};
|
|
2272
|
+
case RuntimeEnvironment2.BUN:
|
|
2273
|
+
return {
|
|
2274
|
+
...base,
|
|
2275
|
+
ssr: true,
|
|
2276
|
+
filesystem: true,
|
|
2277
|
+
fetch: typeof fetch !== "undefined",
|
|
2278
|
+
websockets: typeof WebSocket !== "undefined",
|
|
2279
|
+
crypto: typeof crypto !== "undefined",
|
|
2280
|
+
streams: typeof ReadableStream !== "undefined",
|
|
2281
|
+
modules: {
|
|
2282
|
+
esm: true,
|
|
2283
|
+
commonjs: true,
|
|
2284
|
+
dynamicImport: true
|
|
2285
|
+
},
|
|
2286
|
+
apis: {
|
|
2287
|
+
console: true,
|
|
2288
|
+
timers: true,
|
|
2289
|
+
events: true,
|
|
2290
|
+
url: typeof URL !== "undefined",
|
|
2291
|
+
base64: typeof btoa !== "undefined"
|
|
2292
|
+
}
|
|
2293
|
+
};
|
|
2294
|
+
case RuntimeEnvironment2.CLOUDFLARE:
|
|
2295
|
+
return {
|
|
2296
|
+
...base,
|
|
2297
|
+
ssr: true,
|
|
2298
|
+
fetch: typeof fetch !== "undefined",
|
|
2299
|
+
websockets: typeof WebSocket !== "undefined",
|
|
2300
|
+
storage: typeof caches !== "undefined",
|
|
2301
|
+
crypto: typeof crypto !== "undefined",
|
|
2302
|
+
streams: typeof ReadableStream !== "undefined",
|
|
2303
|
+
modules: {
|
|
2304
|
+
esm: true,
|
|
2305
|
+
commonjs: false,
|
|
2306
|
+
dynamicImport: true
|
|
2307
|
+
},
|
|
2308
|
+
apis: {
|
|
2309
|
+
console: true,
|
|
2310
|
+
timers: true,
|
|
2311
|
+
events: true,
|
|
2312
|
+
url: typeof URL !== "undefined",
|
|
2313
|
+
base64: typeof btoa !== "undefined"
|
|
2314
|
+
}
|
|
2315
|
+
};
|
|
2316
|
+
case RuntimeEnvironment2.ELECTRON:
|
|
2317
|
+
return {
|
|
2318
|
+
...base,
|
|
2319
|
+
dom: true,
|
|
2320
|
+
ssr: true,
|
|
2321
|
+
filesystem: true,
|
|
2322
|
+
fetch: typeof fetch !== "undefined",
|
|
2323
|
+
websockets: typeof WebSocket !== "undefined",
|
|
2324
|
+
workers: typeof Worker !== "undefined",
|
|
2325
|
+
storage: typeof localStorage !== "undefined",
|
|
2326
|
+
crypto: typeof crypto !== "undefined",
|
|
2327
|
+
streams: typeof ReadableStream !== "undefined",
|
|
2328
|
+
modules: {
|
|
2329
|
+
esm: true,
|
|
2330
|
+
commonjs: true,
|
|
2331
|
+
dynamicImport: true
|
|
2332
|
+
},
|
|
2333
|
+
apis: {
|
|
2334
|
+
console: true,
|
|
2335
|
+
timers: true,
|
|
2336
|
+
events: true,
|
|
2337
|
+
url: typeof URL !== "undefined",
|
|
2338
|
+
base64: typeof btoa !== "undefined"
|
|
2339
|
+
}
|
|
2340
|
+
};
|
|
2341
|
+
case RuntimeEnvironment2.TAURI:
|
|
2342
|
+
return {
|
|
2343
|
+
...base,
|
|
2344
|
+
dom: true,
|
|
2345
|
+
ssr: true,
|
|
2346
|
+
filesystem: typeof window !== "undefined" && typeof window.__TAURI__ !== "undefined",
|
|
2347
|
+
fetch: typeof fetch !== "undefined",
|
|
2348
|
+
websockets: typeof WebSocket !== "undefined",
|
|
2349
|
+
storage: typeof localStorage !== "undefined",
|
|
2350
|
+
crypto: typeof crypto !== "undefined",
|
|
2351
|
+
streams: typeof ReadableStream !== "undefined",
|
|
2352
|
+
modules: {
|
|
2353
|
+
esm: true,
|
|
2354
|
+
commonjs: false,
|
|
2355
|
+
dynamicImport: true
|
|
2356
|
+
},
|
|
2357
|
+
apis: {
|
|
2358
|
+
console: true,
|
|
2359
|
+
timers: true,
|
|
2360
|
+
events: true,
|
|
2361
|
+
url: typeof URL !== "undefined",
|
|
2362
|
+
base64: typeof btoa !== "undefined"
|
|
2363
|
+
}
|
|
2364
|
+
};
|
|
2365
|
+
default:
|
|
2366
|
+
return base;
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
// Get detailed runtime information
|
|
2370
|
+
getRuntimeInfo() {
|
|
2371
|
+
const environment = this.detect();
|
|
2372
|
+
const capabilities = this.getCapabilities(environment);
|
|
2373
|
+
return {
|
|
2374
|
+
environment,
|
|
2375
|
+
capabilities,
|
|
2376
|
+
version: this.getRuntimeVersion(environment),
|
|
2377
|
+
features: this.getAvailableFeatures(),
|
|
2378
|
+
userAgent: this.getUserAgent(),
|
|
2379
|
+
platform: this.getPlatformInfo()
|
|
2380
|
+
};
|
|
2381
|
+
}
|
|
2382
|
+
// Alias method for backward compatibility
|
|
2383
|
+
getEnvironmentInfo() {
|
|
2384
|
+
return this.getRuntimeInfo();
|
|
2385
|
+
}
|
|
2386
|
+
getRuntimeVersion(environment) {
|
|
2387
|
+
switch (environment) {
|
|
2388
|
+
case RuntimeEnvironment2.NODE:
|
|
2389
|
+
return typeof process !== "undefined" ? process.version : null;
|
|
2390
|
+
case RuntimeEnvironment2.DENO:
|
|
2391
|
+
return typeof Deno !== "undefined" ? Deno.version.deno : null;
|
|
2392
|
+
case RuntimeEnvironment2.BUN:
|
|
2393
|
+
return typeof Bun !== "undefined" ? Bun.version : typeof process !== "undefined" ? process.versions.bun : null;
|
|
2394
|
+
case RuntimeEnvironment2.BROWSER:
|
|
2395
|
+
return typeof navigator !== "undefined" ? navigator.userAgent : null;
|
|
2396
|
+
default:
|
|
2397
|
+
return null;
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
getAvailableFeatures() {
|
|
2401
|
+
const features = [];
|
|
2402
|
+
if (typeof fetch !== "undefined") features.push("fetch");
|
|
2403
|
+
if (typeof WebSocket !== "undefined") features.push("websockets");
|
|
2404
|
+
if (typeof Worker !== "undefined") features.push("workers");
|
|
2405
|
+
if (typeof crypto !== "undefined") features.push("crypto");
|
|
2406
|
+
if (typeof localStorage !== "undefined") features.push("localStorage");
|
|
2407
|
+
if (typeof sessionStorage !== "undefined") features.push("sessionStorage");
|
|
2408
|
+
if (typeof IndexedDB !== "undefined") features.push("indexedDB");
|
|
2409
|
+
if (typeof WebAssembly !== "undefined") features.push("webassembly");
|
|
2410
|
+
if (typeof SharedArrayBuffer !== "undefined") features.push("sharedArrayBuffer");
|
|
2411
|
+
if (typeof BigInt !== "undefined") features.push("bigint");
|
|
2412
|
+
if ((() => {
|
|
2413
|
+
try {
|
|
2414
|
+
return typeof Function('return import("")') === "function";
|
|
2415
|
+
} catch {
|
|
2416
|
+
return false;
|
|
2417
|
+
}
|
|
2418
|
+
})()) features.push("dynamicImport");
|
|
2419
|
+
return features;
|
|
2420
|
+
}
|
|
2421
|
+
getUserAgent() {
|
|
2422
|
+
if (typeof navigator !== "undefined" && navigator.userAgent) {
|
|
2423
|
+
return navigator.userAgent;
|
|
2424
|
+
}
|
|
2425
|
+
return null;
|
|
2426
|
+
}
|
|
2427
|
+
getPlatformInfo() {
|
|
2428
|
+
if (typeof navigator !== "undefined") {
|
|
2429
|
+
return {
|
|
2430
|
+
platform: navigator.platform,
|
|
2431
|
+
language: navigator.language,
|
|
2432
|
+
cookieEnabled: navigator.cookieEnabled,
|
|
2433
|
+
onLine: navigator.onLine
|
|
2434
|
+
};
|
|
2435
|
+
}
|
|
2436
|
+
if (typeof process !== "undefined") {
|
|
2437
|
+
return {
|
|
2438
|
+
platform: process.platform,
|
|
2439
|
+
arch: process.arch,
|
|
2440
|
+
version: process.version,
|
|
2441
|
+
pid: process.pid
|
|
2442
|
+
};
|
|
2443
|
+
}
|
|
2444
|
+
if (typeof Deno !== "undefined") {
|
|
2445
|
+
return {
|
|
2446
|
+
os: Deno.build.os,
|
|
2447
|
+
arch: Deno.build.arch,
|
|
2448
|
+
version: Deno.version
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
return null;
|
|
2452
|
+
}
|
|
2453
|
+
// Compatibility checking
|
|
2454
|
+
isCompatible(requirements) {
|
|
2455
|
+
const capabilities = this.getCapabilities();
|
|
2456
|
+
for (const [feature, required] of Object.entries(requirements)) {
|
|
2457
|
+
if (required && !capabilities[feature]) {
|
|
2458
|
+
return false;
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
return true;
|
|
2462
|
+
}
|
|
2463
|
+
getIncompatibilities(requirements) {
|
|
2464
|
+
const capabilities = this.getCapabilities();
|
|
2465
|
+
const incompatibilities = [];
|
|
2466
|
+
for (const [feature, required] of Object.entries(requirements)) {
|
|
2467
|
+
if (required && !capabilities[feature]) {
|
|
2468
|
+
incompatibilities.push(feature);
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
return incompatibilities;
|
|
2472
|
+
}
|
|
2473
|
+
// Static methods for quick access
|
|
2474
|
+
static detect() {
|
|
2475
|
+
return new _RuntimeDetector().detect();
|
|
2476
|
+
}
|
|
2477
|
+
static getCapabilities(environment = null) {
|
|
2478
|
+
return new _RuntimeDetector().getCapabilities(environment);
|
|
2479
|
+
}
|
|
2480
|
+
static getRuntimeInfo() {
|
|
2481
|
+
return new _RuntimeDetector().getRuntimeInfo();
|
|
2482
|
+
}
|
|
2483
|
+
static isCompatible(requirements) {
|
|
2484
|
+
return new _RuntimeDetector().isCompatible(requirements);
|
|
2485
|
+
}
|
|
2486
|
+
};
|
|
2487
|
+
function detectRuntime2() {
|
|
2488
|
+
return RuntimeDetector.detect();
|
|
2489
|
+
}
|
|
2490
|
+
var runtimeDetector = new RuntimeDetector();
|
|
2491
|
+
|
|
2492
|
+
// src/utils/module-resolver.js
|
|
2493
|
+
var ModuleResolver = class {
|
|
2494
|
+
constructor(options = {}) {
|
|
2495
|
+
this.options = {
|
|
2496
|
+
baseUrl: "",
|
|
2497
|
+
paths: {},
|
|
2498
|
+
aliases: {},
|
|
2499
|
+
extensions: [".js", ".mjs", ".cjs", ".ts", ".jsx", ".tsx"],
|
|
2500
|
+
moduleMap: {},
|
|
2501
|
+
cdnTemplate: "https://unpkg.com/{name}@{version}/{path}",
|
|
2502
|
+
fallbacks: [],
|
|
2503
|
+
...options
|
|
2504
|
+
};
|
|
2505
|
+
this.environment = detectRuntime2();
|
|
2506
|
+
this.resolutionCache = /* @__PURE__ */ new Map();
|
|
2507
|
+
}
|
|
2508
|
+
// Main resolution method
|
|
2509
|
+
resolve(modulePath, context = {}) {
|
|
2510
|
+
const cacheKey = this.getCacheKey(modulePath, context);
|
|
2511
|
+
if (this.resolutionCache.has(cacheKey)) {
|
|
2512
|
+
return this.resolutionCache.get(cacheKey);
|
|
2513
|
+
}
|
|
2514
|
+
const resolved = this.doResolve(modulePath, context);
|
|
2515
|
+
this.resolutionCache.set(cacheKey, resolved);
|
|
2516
|
+
return resolved;
|
|
2517
|
+
}
|
|
2518
|
+
doResolve(modulePath, context = {}) {
|
|
2519
|
+
const pathInfo = this.analyzePath(modulePath);
|
|
2520
|
+
switch (pathInfo.type) {
|
|
2521
|
+
case "absolute":
|
|
2522
|
+
return this.resolveAbsolute(pathInfo, context);
|
|
2523
|
+
case "relative":
|
|
2524
|
+
return this.resolveRelative(pathInfo, context);
|
|
2525
|
+
case "package":
|
|
2526
|
+
return this.resolvePackage(pathInfo, context);
|
|
2527
|
+
case "alias":
|
|
2528
|
+
return this.resolveAlias(pathInfo, context);
|
|
2529
|
+
case "mapped":
|
|
2530
|
+
return this.resolveMapped(pathInfo, context);
|
|
2531
|
+
default:
|
|
2532
|
+
throw new Error(`Unable to resolve module: ${modulePath}`);
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
analyzePath(modulePath) {
|
|
2536
|
+
if (/^https?:\/\//.test(modulePath)) {
|
|
2537
|
+
return { type: "absolute", path: modulePath, original: modulePath };
|
|
2538
|
+
}
|
|
2539
|
+
if (modulePath.startsWith("file://")) {
|
|
2540
|
+
return { type: "absolute", path: modulePath, original: modulePath };
|
|
2541
|
+
}
|
|
2542
|
+
if (modulePath.startsWith("./") || modulePath.startsWith("../")) {
|
|
2543
|
+
return { type: "relative", path: modulePath, original: modulePath };
|
|
2544
|
+
}
|
|
2545
|
+
if (this.options.moduleMap[modulePath]) {
|
|
2546
|
+
return {
|
|
2547
|
+
type: "mapped",
|
|
2548
|
+
path: modulePath,
|
|
2549
|
+
mapped: this.options.moduleMap[modulePath],
|
|
2550
|
+
original: modulePath
|
|
2551
|
+
};
|
|
2552
|
+
}
|
|
2553
|
+
const aliasKey = Object.keys(this.options.aliases).find(
|
|
2554
|
+
(alias) => modulePath.startsWith(`${alias}/`) || modulePath === alias
|
|
2555
|
+
);
|
|
2556
|
+
if (aliasKey) {
|
|
2557
|
+
return {
|
|
2558
|
+
type: "alias",
|
|
2559
|
+
path: modulePath,
|
|
2560
|
+
alias: aliasKey,
|
|
2561
|
+
remainder: modulePath.slice(aliasKey.length + 1),
|
|
2562
|
+
original: modulePath
|
|
2563
|
+
};
|
|
2564
|
+
}
|
|
2565
|
+
return { type: "package", path: modulePath, original: modulePath };
|
|
2566
|
+
}
|
|
2567
|
+
resolveAbsolute(pathInfo) {
|
|
2568
|
+
return {
|
|
2569
|
+
resolved: pathInfo.path,
|
|
2570
|
+
type: "absolute",
|
|
2571
|
+
original: pathInfo.original
|
|
2572
|
+
};
|
|
2573
|
+
}
|
|
2574
|
+
resolveRelative(pathInfo, context) {
|
|
2575
|
+
let baseUrl = context.baseUrl || this.options.baseUrl || "";
|
|
2576
|
+
if (this.environment === RuntimeEnvironment2.BROWSER && !baseUrl) {
|
|
2577
|
+
baseUrl = window.location.href;
|
|
2578
|
+
}
|
|
2579
|
+
if (!baseUrl) {
|
|
2580
|
+
throw new Error(`Cannot resolve relative path "${pathInfo.path}" without base URL`);
|
|
2581
|
+
}
|
|
2582
|
+
const resolved = new URL(pathInfo.path, baseUrl).href;
|
|
2583
|
+
return {
|
|
2584
|
+
resolved,
|
|
2585
|
+
type: "relative",
|
|
2586
|
+
original: pathInfo.original,
|
|
2587
|
+
baseUrl
|
|
2588
|
+
};
|
|
2589
|
+
}
|
|
2590
|
+
resolvePackage(pathInfo, context) {
|
|
2591
|
+
const packageName = this.parsePackageName(pathInfo.path);
|
|
2592
|
+
switch (this.environment) {
|
|
2593
|
+
case RuntimeEnvironment2.BROWSER:
|
|
2594
|
+
return this.resolveBrowserPackage(packageName, context);
|
|
2595
|
+
case RuntimeEnvironment2.NODE:
|
|
2596
|
+
return this.resolveNodePackage(packageName, context);
|
|
2597
|
+
case RuntimeEnvironment2.DENO:
|
|
2598
|
+
return this.resolveDenoPackage(packageName, context);
|
|
2599
|
+
case RuntimeEnvironment2.BUN:
|
|
2600
|
+
return this.resolveBunPackage(packageName, context);
|
|
2601
|
+
case RuntimeEnvironment2.CLOUDFLARE:
|
|
2602
|
+
case RuntimeEnvironment2.EDGE:
|
|
2603
|
+
return this.resolveEdgePackage(packageName, context);
|
|
2604
|
+
default:
|
|
2605
|
+
return this.resolveGenericPackage(packageName, context);
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
parsePackageName(modulePath) {
|
|
2609
|
+
const parts = modulePath.split("/");
|
|
2610
|
+
if (modulePath.startsWith("@")) {
|
|
2611
|
+
return {
|
|
2612
|
+
name: `${parts[0]}/${parts[1]}`,
|
|
2613
|
+
subpath: parts.slice(2).join("/"),
|
|
2614
|
+
scope: parts[0],
|
|
2615
|
+
packageName: parts[1]
|
|
2616
|
+
};
|
|
2617
|
+
} else {
|
|
2618
|
+
return {
|
|
2619
|
+
name: parts[0],
|
|
2620
|
+
subpath: parts.slice(1).join("/"),
|
|
2621
|
+
scope: null,
|
|
2622
|
+
packageName: parts[0]
|
|
2623
|
+
};
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
resolveBrowserPackage(packageInfo, context) {
|
|
2627
|
+
const cdnUrl = this.resolveToCdn(packageInfo, context);
|
|
2628
|
+
return {
|
|
2629
|
+
resolved: cdnUrl,
|
|
2630
|
+
type: "package",
|
|
2631
|
+
strategy: "cdn",
|
|
2632
|
+
original: packageInfo.name + (packageInfo.subpath ? `/${packageInfo.subpath}` : ""),
|
|
2633
|
+
package: packageInfo
|
|
2634
|
+
};
|
|
2635
|
+
}
|
|
2636
|
+
resolveNodePackage(packageInfo) {
|
|
2637
|
+
const modulePath = packageInfo.name + (packageInfo.subpath ? `/${packageInfo.subpath}` : "");
|
|
2638
|
+
return {
|
|
2639
|
+
resolved: modulePath,
|
|
2640
|
+
type: "package",
|
|
2641
|
+
strategy: "node",
|
|
2642
|
+
original: modulePath,
|
|
2643
|
+
package: packageInfo
|
|
2644
|
+
};
|
|
2645
|
+
}
|
|
2646
|
+
resolveDenoPackage(packageInfo) {
|
|
2647
|
+
const modulePath = `npm:${packageInfo.name}${packageInfo.subpath ? `/${packageInfo.subpath}` : ""}`;
|
|
2648
|
+
return {
|
|
2649
|
+
resolved: modulePath,
|
|
2650
|
+
type: "package",
|
|
2651
|
+
strategy: "deno-npm",
|
|
2652
|
+
original: packageInfo.name + (packageInfo.subpath ? `/${packageInfo.subpath}` : ""),
|
|
2653
|
+
package: packageInfo
|
|
2654
|
+
};
|
|
2655
|
+
}
|
|
2656
|
+
resolveBunPackage(packageInfo) {
|
|
2657
|
+
const modulePath = packageInfo.name + (packageInfo.subpath ? `/${packageInfo.subpath}` : "");
|
|
2658
|
+
return {
|
|
2659
|
+
resolved: modulePath,
|
|
2660
|
+
type: "package",
|
|
2661
|
+
strategy: "bun",
|
|
2662
|
+
original: modulePath,
|
|
2663
|
+
package: packageInfo
|
|
2664
|
+
};
|
|
2665
|
+
}
|
|
2666
|
+
resolveEdgePackage(packageInfo, context) {
|
|
2667
|
+
const cdnUrl = this.resolveToCdn(packageInfo, context);
|
|
2668
|
+
return {
|
|
2669
|
+
resolved: cdnUrl,
|
|
2670
|
+
type: "package",
|
|
2671
|
+
strategy: "edge-cdn",
|
|
2672
|
+
original: packageInfo.name + (packageInfo.subpath ? `/${packageInfo.subpath}` : ""),
|
|
2673
|
+
package: packageInfo
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2676
|
+
resolveGenericPackage(packageInfo) {
|
|
2677
|
+
const modulePath = packageInfo.name + (packageInfo.subpath ? `/${packageInfo.subpath}` : "");
|
|
2678
|
+
return {
|
|
2679
|
+
resolved: modulePath,
|
|
2680
|
+
type: "package",
|
|
2681
|
+
strategy: "generic",
|
|
2682
|
+
original: modulePath,
|
|
2683
|
+
package: packageInfo
|
|
2684
|
+
};
|
|
2685
|
+
}
|
|
2686
|
+
resolveToCdn(packageInfo, context = {}) {
|
|
2687
|
+
const version = context.version || "latest";
|
|
2688
|
+
const subpath = packageInfo.subpath || "dist/index.js";
|
|
2689
|
+
return this.options.cdnTemplate.replace("{name}", packageInfo.name).replace("{version}", version).replace("{path}", subpath);
|
|
2690
|
+
}
|
|
2691
|
+
resolveAlias(pathInfo, context) {
|
|
2692
|
+
const aliasTarget = this.options.aliases[pathInfo.alias];
|
|
2693
|
+
const resolvedPath = pathInfo.remainder ? `${aliasTarget}/${pathInfo.remainder}` : aliasTarget;
|
|
2694
|
+
const resolved = this.doResolve(resolvedPath, context);
|
|
2695
|
+
return {
|
|
2696
|
+
...resolved,
|
|
2697
|
+
type: "alias",
|
|
2698
|
+
alias: pathInfo.alias,
|
|
2699
|
+
aliasTarget,
|
|
2700
|
+
original: pathInfo.original
|
|
2701
|
+
};
|
|
2702
|
+
}
|
|
2703
|
+
resolveMapped(pathInfo, context) {
|
|
2704
|
+
const mapped = pathInfo.mapped;
|
|
2705
|
+
if (typeof mapped === "function") {
|
|
2706
|
+
const result = mapped(pathInfo.path, context);
|
|
2707
|
+
return {
|
|
2708
|
+
resolved: result,
|
|
2709
|
+
type: "mapped",
|
|
2710
|
+
original: pathInfo.original,
|
|
2711
|
+
mapFunction: true
|
|
2712
|
+
};
|
|
2713
|
+
}
|
|
2714
|
+
return {
|
|
2715
|
+
resolved: mapped,
|
|
2716
|
+
type: "mapped",
|
|
2717
|
+
original: pathInfo.original
|
|
2718
|
+
};
|
|
2719
|
+
}
|
|
2720
|
+
// Path utilities
|
|
2721
|
+
addExtension(path, extensions = null) {
|
|
2722
|
+
const exts = extensions || this.options.extensions;
|
|
2723
|
+
if (exts.some((ext) => path.endsWith(ext))) {
|
|
2724
|
+
return path;
|
|
2725
|
+
}
|
|
2726
|
+
return path + exts[0];
|
|
2727
|
+
}
|
|
2728
|
+
stripExtension(path) {
|
|
2729
|
+
const ext = this.options.extensions.find((e) => path.endsWith(e));
|
|
2730
|
+
return ext ? path.slice(0, -ext.length) : path;
|
|
2731
|
+
}
|
|
2732
|
+
isRelative(path) {
|
|
2733
|
+
return path.startsWith("./") || path.startsWith("../");
|
|
2734
|
+
}
|
|
2735
|
+
isAbsolute(path) {
|
|
2736
|
+
return /^https?:\/\//.test(path) || path.startsWith("file://");
|
|
2737
|
+
}
|
|
2738
|
+
// Configuration methods
|
|
2739
|
+
addAlias(alias, target) {
|
|
2740
|
+
this.options.aliases[alias] = target;
|
|
2741
|
+
this.clearCache();
|
|
2742
|
+
}
|
|
2743
|
+
addMapping(from, to) {
|
|
2744
|
+
this.options.moduleMap[from] = to;
|
|
2745
|
+
this.clearCache();
|
|
2746
|
+
}
|
|
2747
|
+
setBaseUrl(baseUrl) {
|
|
2748
|
+
this.options.baseUrl = baseUrl;
|
|
2749
|
+
this.clearCache();
|
|
2750
|
+
}
|
|
2751
|
+
setCdnTemplate(template) {
|
|
2752
|
+
this.options.cdnTemplate = template;
|
|
2753
|
+
this.clearCache();
|
|
2754
|
+
}
|
|
2755
|
+
// Path patterns and wildcards
|
|
2756
|
+
resolvePattern(pattern, replacements = {}) {
|
|
2757
|
+
let resolved = pattern;
|
|
2758
|
+
Object.entries(replacements).forEach(([key, value]) => {
|
|
2759
|
+
resolved = resolved.replace(new RegExp(`\\{${key}\\}`, "g"), value);
|
|
2760
|
+
});
|
|
2761
|
+
return resolved;
|
|
2762
|
+
}
|
|
2763
|
+
// Batch resolution
|
|
2764
|
+
resolveAll(modulePaths, context = {}) {
|
|
2765
|
+
return modulePaths.map((path) => {
|
|
2766
|
+
try {
|
|
2767
|
+
return { path, resolution: this.resolve(path, context), success: true };
|
|
2768
|
+
} catch (error) {
|
|
2769
|
+
return { path, error, success: false };
|
|
2770
|
+
}
|
|
2771
|
+
});
|
|
2772
|
+
}
|
|
2773
|
+
// Cache management
|
|
2774
|
+
getCacheKey(modulePath, context) {
|
|
2775
|
+
return `${modulePath}::${JSON.stringify(context)}`;
|
|
2776
|
+
}
|
|
2777
|
+
clearCache() {
|
|
2778
|
+
this.resolutionCache.clear();
|
|
2779
|
+
}
|
|
2780
|
+
getCacheStats() {
|
|
2781
|
+
return {
|
|
2782
|
+
size: this.resolutionCache.size,
|
|
2783
|
+
keys: Array.from(this.resolutionCache.keys())
|
|
2784
|
+
};
|
|
2785
|
+
}
|
|
2786
|
+
// Validation
|
|
2787
|
+
validateResolution(resolution) {
|
|
2788
|
+
if (!resolution || !resolution.resolved) {
|
|
2789
|
+
return { valid: false, error: "Invalid resolution object" };
|
|
2790
|
+
}
|
|
2791
|
+
switch (resolution.type) {
|
|
2792
|
+
case "absolute":
|
|
2793
|
+
if (!this.isAbsolute(resolution.resolved)) {
|
|
2794
|
+
return { valid: false, error: "Absolute resolution must be a valid URL" };
|
|
2795
|
+
}
|
|
2796
|
+
break;
|
|
2797
|
+
case "relative":
|
|
2798
|
+
if (!resolution.baseUrl) {
|
|
2799
|
+
return { valid: false, error: "Relative resolution must include baseUrl" };
|
|
2800
|
+
}
|
|
2801
|
+
break;
|
|
2802
|
+
}
|
|
2803
|
+
return { valid: true };
|
|
2804
|
+
}
|
|
2805
|
+
// Debug utilities
|
|
2806
|
+
debug(modulePath, context = {}) {
|
|
2807
|
+
const pathInfo = this.analyzePath(modulePath);
|
|
2808
|
+
const resolution = this.resolve(modulePath, context);
|
|
2809
|
+
const validation = this.validateResolution(resolution);
|
|
2810
|
+
return {
|
|
2811
|
+
input: modulePath,
|
|
2812
|
+
context,
|
|
2813
|
+
pathInfo,
|
|
2814
|
+
resolution,
|
|
2815
|
+
validation,
|
|
2816
|
+
environment: this.environment,
|
|
2817
|
+
options: this.options
|
|
2818
|
+
};
|
|
2819
|
+
}
|
|
2820
|
+
};
|
|
2821
|
+
var moduleResolver = new ModuleResolver();
|
|
2822
|
+
|
|
2823
|
+
// src/utils/asset-manager.js
|
|
2824
|
+
var AssetManager = class {
|
|
2825
|
+
constructor(options = {}) {
|
|
2826
|
+
this.options = {
|
|
2827
|
+
baseUrl: "",
|
|
2828
|
+
assetPaths: {},
|
|
2829
|
+
preloadAssets: [],
|
|
2830
|
+
lazyLoad: true,
|
|
2831
|
+
cacheAssets: true,
|
|
2832
|
+
optimizeImages: true,
|
|
2833
|
+
inlineThreshold: 1024,
|
|
2834
|
+
// Inline assets smaller than this (bytes)
|
|
2835
|
+
supportedFormats: {
|
|
2836
|
+
images: ["png", "jpg", "jpeg", "gif", "svg", "webp", "avif"],
|
|
2837
|
+
styles: ["css"],
|
|
2838
|
+
fonts: ["woff", "woff2", "ttf", "otf"],
|
|
2839
|
+
scripts: ["js", "mjs"]
|
|
2840
|
+
},
|
|
2841
|
+
...options
|
|
2842
|
+
};
|
|
2843
|
+
this.environment = detectRuntime2();
|
|
2844
|
+
this.loadedAssets = /* @__PURE__ */ new Map();
|
|
2845
|
+
this.loadingAssets = /* @__PURE__ */ new Map();
|
|
2846
|
+
this.assetCache = /* @__PURE__ */ new Map();
|
|
2847
|
+
}
|
|
2848
|
+
// Main asset loading method
|
|
2849
|
+
async loadAsset(assetPath, options = {}) {
|
|
2850
|
+
const resolvedPath = this.resolvePath(assetPath, options);
|
|
2851
|
+
const assetType = this.getAssetType(resolvedPath);
|
|
2852
|
+
const cacheKey = this.getCacheKey(resolvedPath, options);
|
|
2853
|
+
if (this.options.cacheAssets && this.loadedAssets.has(cacheKey)) {
|
|
2854
|
+
return this.loadedAssets.get(cacheKey);
|
|
2855
|
+
}
|
|
2856
|
+
if (this.loadingAssets.has(cacheKey)) {
|
|
2857
|
+
return this.loadingAssets.get(cacheKey);
|
|
2858
|
+
}
|
|
2859
|
+
const loadingPromise = this.doLoadAsset(resolvedPath, assetType, options);
|
|
2860
|
+
this.loadingAssets.set(cacheKey, loadingPromise);
|
|
2861
|
+
try {
|
|
2862
|
+
const asset = await loadingPromise;
|
|
2863
|
+
if (this.options.cacheAssets) {
|
|
2864
|
+
this.loadedAssets.set(cacheKey, asset);
|
|
2865
|
+
}
|
|
2866
|
+
return asset;
|
|
2867
|
+
} finally {
|
|
2868
|
+
this.loadingAssets.delete(cacheKey);
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
async doLoadAsset(assetPath, assetType, options = {}) {
|
|
2872
|
+
switch (assetType) {
|
|
2873
|
+
case "css":
|
|
2874
|
+
return await this.loadStylesheet(assetPath, options);
|
|
2875
|
+
case "image":
|
|
2876
|
+
return await this.loadImage(assetPath, options);
|
|
2877
|
+
case "font":
|
|
2878
|
+
return await this.loadFont(assetPath, options);
|
|
2879
|
+
case "script":
|
|
2880
|
+
return await this.loadScript(assetPath, options);
|
|
2881
|
+
case "data":
|
|
2882
|
+
return await this.loadData(assetPath, options);
|
|
2883
|
+
default:
|
|
2884
|
+
return await this.loadGeneric(assetPath, options);
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
// CSS loading
|
|
2888
|
+
async loadStylesheet(cssPath, options = {}) {
|
|
2889
|
+
if (this.environment === RuntimeEnvironment2.BROWSER) {
|
|
2890
|
+
return await this.loadBrowserStylesheet(cssPath, options);
|
|
2891
|
+
} else {
|
|
2892
|
+
return await this.loadServerStylesheet(cssPath, options);
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
async loadBrowserStylesheet(cssPath, options = {}) {
|
|
2896
|
+
return new Promise((resolve, reject) => {
|
|
2897
|
+
const existing = document.querySelector(`link[href="${cssPath}"]`);
|
|
2898
|
+
if (existing) {
|
|
2899
|
+
resolve({ element: existing, cached: true });
|
|
2900
|
+
return;
|
|
2901
|
+
}
|
|
2902
|
+
const link = document.createElement("link");
|
|
2903
|
+
link.rel = "stylesheet";
|
|
2904
|
+
link.href = cssPath;
|
|
2905
|
+
if (options.media) link.media = options.media;
|
|
2906
|
+
if (options.crossorigin) link.crossOrigin = options.crossorigin;
|
|
2907
|
+
link.onload = () => {
|
|
2908
|
+
resolve({ element: link, loaded: true });
|
|
2909
|
+
};
|
|
2910
|
+
link.onerror = () => {
|
|
2911
|
+
reject(new Error(`Failed to load stylesheet: ${cssPath}`));
|
|
2912
|
+
};
|
|
2913
|
+
document.head.appendChild(link);
|
|
2914
|
+
});
|
|
2915
|
+
}
|
|
2916
|
+
async loadServerStylesheet(cssPath) {
|
|
2917
|
+
try {
|
|
2918
|
+
const response = await fetch(cssPath);
|
|
2919
|
+
const content = await response.text();
|
|
2920
|
+
return {
|
|
2921
|
+
content,
|
|
2922
|
+
path: cssPath,
|
|
2923
|
+
inline: true
|
|
2924
|
+
};
|
|
2925
|
+
} catch (error) {
|
|
2926
|
+
throw new Error(`Failed to load stylesheet: ${cssPath} - ${error.message}`);
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
// Image loading
|
|
2930
|
+
async loadImage(imagePath, options = {}) {
|
|
2931
|
+
if (this.environment === RuntimeEnvironment2.BROWSER) {
|
|
2932
|
+
return await this.loadBrowserImage(imagePath, options);
|
|
2933
|
+
} else {
|
|
2934
|
+
return await this.loadServerImage(imagePath, options);
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
async loadBrowserImage(imagePath, options = {}) {
|
|
2938
|
+
return new Promise((resolve, reject) => {
|
|
2939
|
+
const img = new Image();
|
|
2940
|
+
if (options.crossorigin) img.crossOrigin = options.crossorigin;
|
|
2941
|
+
if (options.loading) img.loading = options.loading;
|
|
2942
|
+
if (options.sizes) img.sizes = options.sizes;
|
|
2943
|
+
if (options.srcset) img.srcset = options.srcset;
|
|
2944
|
+
img.onload = () => {
|
|
2945
|
+
resolve({
|
|
2946
|
+
element: img,
|
|
2947
|
+
width: img.naturalWidth,
|
|
2948
|
+
height: img.naturalHeight,
|
|
2949
|
+
path: imagePath
|
|
2950
|
+
});
|
|
2951
|
+
};
|
|
2952
|
+
img.onerror = () => {
|
|
2953
|
+
reject(new Error(`Failed to load image: ${imagePath}`));
|
|
2954
|
+
};
|
|
2955
|
+
img.src = imagePath;
|
|
2956
|
+
});
|
|
2957
|
+
}
|
|
2958
|
+
async loadServerImage(imagePath) {
|
|
2959
|
+
try {
|
|
2960
|
+
const response = await fetch(imagePath);
|
|
2961
|
+
const blob = await response.blob();
|
|
2962
|
+
return {
|
|
2963
|
+
blob,
|
|
2964
|
+
size: blob.size,
|
|
2965
|
+
type: blob.type,
|
|
2966
|
+
path: imagePath
|
|
2967
|
+
};
|
|
2968
|
+
} catch (error) {
|
|
2969
|
+
throw new Error(`Failed to load image: ${imagePath} - ${error.message}`);
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
// Font loading
|
|
2973
|
+
async loadFont(fontPath, options = {}) {
|
|
2974
|
+
if (this.environment === RuntimeEnvironment2.BROWSER && "fonts" in document) {
|
|
2975
|
+
return await this.loadBrowserFont(fontPath, options);
|
|
2976
|
+
} else {
|
|
2977
|
+
return await this.loadGeneric(fontPath, options);
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
async loadBrowserFont(fontPath, options = {}) {
|
|
2981
|
+
try {
|
|
2982
|
+
const fontFace = new FontFace(
|
|
2983
|
+
options.family || "CustomFont",
|
|
2984
|
+
`url(${fontPath})`,
|
|
2985
|
+
{
|
|
2986
|
+
style: options.style || "normal",
|
|
2987
|
+
weight: options.weight || "normal",
|
|
2988
|
+
stretch: options.stretch || "normal"
|
|
2989
|
+
}
|
|
2990
|
+
);
|
|
2991
|
+
await fontFace.load();
|
|
2992
|
+
document.fonts.add(fontFace);
|
|
2993
|
+
return {
|
|
2994
|
+
fontFace,
|
|
2995
|
+
family: options.family,
|
|
2996
|
+
loaded: true
|
|
2997
|
+
};
|
|
2998
|
+
} catch (error) {
|
|
2999
|
+
throw new Error(`Failed to load font: ${fontPath} - ${error.message}`);
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
// Script loading
|
|
3003
|
+
async loadScript(scriptPath, options = {}) {
|
|
3004
|
+
if (this.environment === RuntimeEnvironment2.BROWSER) {
|
|
3005
|
+
return await this.loadBrowserScript(scriptPath, options);
|
|
3006
|
+
} else {
|
|
3007
|
+
return await this.loadServerScript(scriptPath, options);
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
async loadBrowserScript(scriptPath, options = {}) {
|
|
3011
|
+
return new Promise((resolve, reject) => {
|
|
3012
|
+
const existing = document.querySelector(`script[src="${scriptPath}"]`);
|
|
3013
|
+
if (existing) {
|
|
3014
|
+
resolve({ element: existing, cached: true });
|
|
3015
|
+
return;
|
|
3016
|
+
}
|
|
3017
|
+
const script = document.createElement("script");
|
|
3018
|
+
script.src = scriptPath;
|
|
3019
|
+
if (options.type) script.type = options.type;
|
|
3020
|
+
if (options.async !== void 0) script.async = options.async;
|
|
3021
|
+
if (options.defer !== void 0) script.defer = options.defer;
|
|
3022
|
+
if (options.crossorigin) script.crossOrigin = options.crossorigin;
|
|
3023
|
+
script.onload = () => {
|
|
3024
|
+
resolve({ element: script, loaded: true });
|
|
3025
|
+
};
|
|
3026
|
+
script.onerror = () => {
|
|
3027
|
+
reject(new Error(`Failed to load script: ${scriptPath}`));
|
|
3028
|
+
};
|
|
3029
|
+
document.head.appendChild(script);
|
|
3030
|
+
});
|
|
3031
|
+
}
|
|
3032
|
+
async loadServerScript(scriptPath, options = {}) {
|
|
3033
|
+
try {
|
|
3034
|
+
const response = await fetch(scriptPath);
|
|
3035
|
+
const content = await response.text();
|
|
3036
|
+
return {
|
|
3037
|
+
content,
|
|
3038
|
+
path: scriptPath,
|
|
3039
|
+
type: options.type || "text/javascript"
|
|
3040
|
+
};
|
|
3041
|
+
} catch (error) {
|
|
3042
|
+
throw new Error(`Failed to load script: ${scriptPath} - ${error.message}`);
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
// Data loading (JSON, XML, etc.)
|
|
3046
|
+
async loadData(dataPath) {
|
|
3047
|
+
try {
|
|
3048
|
+
const response = await fetch(dataPath);
|
|
3049
|
+
const contentType = response.headers.get("content-type") || "";
|
|
3050
|
+
let data;
|
|
3051
|
+
if (contentType.includes("application/json")) {
|
|
3052
|
+
data = await response.json();
|
|
3053
|
+
} else if (contentType.includes("text/xml") || contentType.includes("application/xml")) {
|
|
3054
|
+
const text = await response.text();
|
|
3055
|
+
data = this.parseXML(text);
|
|
3056
|
+
} else {
|
|
3057
|
+
data = await response.text();
|
|
3058
|
+
}
|
|
3059
|
+
return {
|
|
3060
|
+
data,
|
|
3061
|
+
contentType,
|
|
3062
|
+
path: dataPath
|
|
3063
|
+
};
|
|
3064
|
+
} catch (error) {
|
|
3065
|
+
throw new Error(`Failed to load data: ${dataPath} - ${error.message}`);
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
parseXML(xmlString) {
|
|
3069
|
+
if (typeof DOMParser !== "undefined") {
|
|
3070
|
+
const parser = new DOMParser();
|
|
3071
|
+
return parser.parseFromString(xmlString, "text/xml");
|
|
3072
|
+
}
|
|
3073
|
+
return xmlString;
|
|
3074
|
+
}
|
|
3075
|
+
// Generic loading
|
|
3076
|
+
async loadGeneric(assetPath) {
|
|
3077
|
+
try {
|
|
3078
|
+
const response = await fetch(assetPath);
|
|
3079
|
+
const blob = await response.blob();
|
|
3080
|
+
return {
|
|
3081
|
+
blob,
|
|
3082
|
+
size: blob.size,
|
|
3083
|
+
type: blob.type,
|
|
3084
|
+
path: assetPath
|
|
3085
|
+
};
|
|
3086
|
+
} catch (error) {
|
|
3087
|
+
throw new Error(`Failed to load asset: ${assetPath} - ${error.message}`);
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
// Path resolution
|
|
3091
|
+
resolvePath(assetPath, options = {}) {
|
|
3092
|
+
if (typeof assetPath !== "string") {
|
|
3093
|
+
throw new Error(`Expected string path, got ${typeof assetPath}: ${assetPath}`);
|
|
3094
|
+
}
|
|
3095
|
+
if (assetPath.startsWith("http://") || assetPath.startsWith("https://")) {
|
|
3096
|
+
return assetPath;
|
|
3097
|
+
}
|
|
3098
|
+
if (assetPath.startsWith("data:")) {
|
|
3099
|
+
return assetPath;
|
|
3100
|
+
}
|
|
3101
|
+
if (assetPath.startsWith("blob:")) {
|
|
3102
|
+
return assetPath;
|
|
3103
|
+
}
|
|
3104
|
+
if (this.options.assetPaths[assetPath]) {
|
|
3105
|
+
return this.options.assetPaths[assetPath];
|
|
3106
|
+
}
|
|
3107
|
+
const baseUrl = options.baseUrl || this.options.baseUrl;
|
|
3108
|
+
if (baseUrl) {
|
|
3109
|
+
return new URL(assetPath, baseUrl).href;
|
|
3110
|
+
}
|
|
3111
|
+
return assetPath;
|
|
3112
|
+
}
|
|
3113
|
+
// Asset type detection
|
|
3114
|
+
getAssetType(assetPath) {
|
|
3115
|
+
const extension = this.getFileExtension(assetPath).toLowerCase();
|
|
3116
|
+
if (this.options.supportedFormats.images.includes(extension)) {
|
|
3117
|
+
return "image";
|
|
3118
|
+
}
|
|
3119
|
+
if (this.options.supportedFormats.styles.includes(extension)) {
|
|
3120
|
+
return "css";
|
|
3121
|
+
}
|
|
3122
|
+
if (this.options.supportedFormats.fonts.includes(extension)) {
|
|
3123
|
+
return "font";
|
|
3124
|
+
}
|
|
3125
|
+
if (this.options.supportedFormats.scripts.includes(extension)) {
|
|
3126
|
+
return "script";
|
|
3127
|
+
}
|
|
3128
|
+
if (["json", "xml"].includes(extension)) {
|
|
3129
|
+
return "data";
|
|
3130
|
+
}
|
|
3131
|
+
return "generic";
|
|
3132
|
+
}
|
|
3133
|
+
getFileExtension(path) {
|
|
3134
|
+
const cleanPath = path.split("?")[0].split("#")[0];
|
|
3135
|
+
const parts = cleanPath.split(".");
|
|
3136
|
+
return parts.length > 1 ? parts.pop() : "";
|
|
3137
|
+
}
|
|
3138
|
+
// Batch operations
|
|
3139
|
+
async loadAssets(assetPaths, options = {}) {
|
|
3140
|
+
const loadPromises = assetPaths.map(
|
|
3141
|
+
(path) => this.loadAsset(path, options).catch((error) => ({ error, path }))
|
|
3142
|
+
);
|
|
3143
|
+
const results = await Promise.all(loadPromises);
|
|
3144
|
+
return {
|
|
3145
|
+
successful: results.filter((r) => !r.error),
|
|
3146
|
+
failed: results.filter((r) => r.error)
|
|
3147
|
+
};
|
|
3148
|
+
}
|
|
3149
|
+
// Preloading
|
|
3150
|
+
async preloadAssets(assetPaths = null) {
|
|
3151
|
+
const toPreload = assetPaths || this.options.preloadAssets;
|
|
3152
|
+
if (this.environment === RuntimeEnvironment2.BROWSER) {
|
|
3153
|
+
return await this.preloadBrowserAssets(toPreload);
|
|
3154
|
+
} else {
|
|
3155
|
+
return await this.loadAssets(toPreload, { preload: true });
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
async preloadBrowserAssets(assetPaths) {
|
|
3159
|
+
const preloadPromises = assetPaths.map(async (assetPath) => {
|
|
3160
|
+
try {
|
|
3161
|
+
const link = document.createElement("link");
|
|
3162
|
+
link.rel = "preload";
|
|
3163
|
+
link.href = this.resolvePath(assetPath);
|
|
3164
|
+
const assetType = this.getAssetType(assetPath);
|
|
3165
|
+
switch (assetType) {
|
|
3166
|
+
case "css":
|
|
3167
|
+
link.as = "style";
|
|
3168
|
+
break;
|
|
3169
|
+
case "script":
|
|
3170
|
+
link.as = "script";
|
|
3171
|
+
break;
|
|
3172
|
+
case "font":
|
|
3173
|
+
link.as = "font";
|
|
3174
|
+
link.crossOrigin = "anonymous";
|
|
3175
|
+
break;
|
|
3176
|
+
case "image":
|
|
3177
|
+
link.as = "image";
|
|
3178
|
+
break;
|
|
3179
|
+
}
|
|
3180
|
+
document.head.appendChild(link);
|
|
3181
|
+
return { success: true, path: assetPath };
|
|
3182
|
+
} catch (error) {
|
|
3183
|
+
return { success: false, path: assetPath, error };
|
|
3184
|
+
}
|
|
3185
|
+
});
|
|
3186
|
+
return await Promise.all(preloadPromises);
|
|
3187
|
+
}
|
|
3188
|
+
// Cache management
|
|
3189
|
+
getCacheKey(assetPath, options) {
|
|
3190
|
+
return `${assetPath}::${JSON.stringify(options)}`;
|
|
3191
|
+
}
|
|
3192
|
+
clearCache() {
|
|
3193
|
+
this.loadedAssets.clear();
|
|
3194
|
+
this.assetCache.clear();
|
|
3195
|
+
}
|
|
3196
|
+
getCacheStats() {
|
|
3197
|
+
return {
|
|
3198
|
+
loaded: this.loadedAssets.size,
|
|
3199
|
+
loading: this.loadingAssets.size,
|
|
3200
|
+
cached: this.assetCache.size
|
|
3201
|
+
};
|
|
3202
|
+
}
|
|
3203
|
+
// Asset optimization
|
|
3204
|
+
shouldInline(assetPath, size = null) {
|
|
3205
|
+
if (size && size <= this.options.inlineThreshold) {
|
|
3206
|
+
return true;
|
|
3207
|
+
}
|
|
3208
|
+
return false;
|
|
3209
|
+
}
|
|
3210
|
+
async optimizeImage(imagePath, options = {}) {
|
|
3211
|
+
return await this.loadImage(imagePath, options);
|
|
3212
|
+
}
|
|
3213
|
+
// Utilities
|
|
3214
|
+
addAssetPath(alias, path) {
|
|
3215
|
+
this.options.assetPaths[alias] = path;
|
|
3216
|
+
}
|
|
3217
|
+
setBaseUrl(baseUrl) {
|
|
3218
|
+
this.options.baseUrl = baseUrl;
|
|
3219
|
+
}
|
|
3220
|
+
isAssetLoaded(assetPath) {
|
|
3221
|
+
const resolvedPath = this.resolvePath(assetPath);
|
|
3222
|
+
return this.loadedAssets.has(this.getCacheKey(resolvedPath, {}));
|
|
3223
|
+
}
|
|
3224
|
+
getLoadedAssets() {
|
|
3225
|
+
return Array.from(this.loadedAssets.keys());
|
|
3226
|
+
}
|
|
3227
|
+
};
|
|
3228
|
+
var assetManager = new AssetManager();
|
|
3229
|
+
|
|
3230
|
+
// src/index.js
|
|
3231
|
+
async function createCoherentApp(options = {}) {
|
|
3232
|
+
const runtime = await createRuntime(options);
|
|
3233
|
+
return runtime.createApp(options);
|
|
3234
|
+
}
|
|
3235
|
+
function renderApp(component, props = {}, target = null) {
|
|
3236
|
+
const runtime = detectRuntime();
|
|
3237
|
+
if (typeof runtime === "object" && runtime.renderApp) {
|
|
3238
|
+
return runtime.renderApp(component, props, target);
|
|
3239
|
+
}
|
|
3240
|
+
throw new Error("renderApp requires a proper runtime implementation");
|
|
3241
|
+
}
|
|
3242
|
+
if (typeof window !== "undefined") {
|
|
3243
|
+
window.Coherent = {
|
|
3244
|
+
// Core functionality
|
|
3245
|
+
render: async (obj) => {
|
|
3246
|
+
const { render: render5 } = await import("@coherent.js/core");
|
|
3247
|
+
return render5(obj);
|
|
3248
|
+
},
|
|
3249
|
+
// Hydration
|
|
3250
|
+
hydrate: async (element, component, props) => {
|
|
3251
|
+
const { hydrate: hydrate2 } = await import("@coherent.js/client");
|
|
3252
|
+
return hydrate2(element, component, props);
|
|
3253
|
+
},
|
|
3254
|
+
// Web Components
|
|
3255
|
+
defineComponent: async (name, component, options) => {
|
|
3256
|
+
const { defineComponent } = await import("@coherent.js/web-components");
|
|
3257
|
+
return defineComponent(name, component, options);
|
|
3258
|
+
},
|
|
3259
|
+
// Universal app creation
|
|
3260
|
+
createApp: createCoherentApp,
|
|
3261
|
+
renderApp,
|
|
3262
|
+
// Version info
|
|
3263
|
+
VERSION: "1.1.1"
|
|
3264
|
+
};
|
|
3265
|
+
if (document.querySelector("[data-coherent-auto]")) {
|
|
3266
|
+
document.addEventListener("DOMContentLoaded", async () => {
|
|
3267
|
+
const { autoHydrate: autoHydrate2 } = await import("@coherent.js/client");
|
|
3268
|
+
autoHydrate2(window.componentRegistry || {});
|
|
3269
|
+
});
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
var VERSION = "1.1.1";
|
|
3273
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
3274
|
+
0 && (module.exports = {
|
|
3275
|
+
AssetManager,
|
|
3276
|
+
BrowserRuntime,
|
|
3277
|
+
ComponentLoader,
|
|
3278
|
+
DesktopRuntime,
|
|
3279
|
+
EdgeRuntime,
|
|
3280
|
+
ModuleResolver,
|
|
3281
|
+
RuntimeDetector,
|
|
3282
|
+
RuntimeEnvironment,
|
|
3283
|
+
StaticRuntime,
|
|
3284
|
+
UniversalLoader,
|
|
3285
|
+
VERSION,
|
|
3286
|
+
createCoherentApp,
|
|
3287
|
+
createRuntime,
|
|
3288
|
+
detectRuntime,
|
|
3289
|
+
renderApp,
|
|
3290
|
+
...require("@coherent.js/core"),
|
|
3291
|
+
...require("@coherent.js/client"),
|
|
3292
|
+
...require("@coherent.js/web-components")
|
|
3293
|
+
});
|
|
3294
|
+
//# sourceMappingURL=coherent-universal.cjs.map
|