kimu-core 0.4.1

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.
Files changed (146) hide show
  1. package/.editorconfig +30 -0
  2. package/.gitattributes +11 -0
  3. package/.github/FUNDING.yml +8 -0
  4. package/.github/copilot-instructions.md +103 -0
  5. package/.github/kimu-copilot-instructions.md +3779 -0
  6. package/.github/workflows/deploy-demo.yml +39 -0
  7. package/AUTHORS.md +20 -0
  8. package/CHANGELOG.md +20 -0
  9. package/CODE_GUIDELINES.md +165 -0
  10. package/CODE_OF_CONDUCT.md +47 -0
  11. package/CONTRIBUTING.md +62 -0
  12. package/FUNDING.md +31 -0
  13. package/ISSUE_GUIDELINES.md +74 -0
  14. package/LICENSE +17 -0
  15. package/LICENSE.it.md +17 -0
  16. package/MPL-2.0.txt +373 -0
  17. package/NOTICE +65 -0
  18. package/README-KIMU.md +40 -0
  19. package/README.it.md +208 -0
  20. package/README.md +266 -0
  21. package/SECURITY.md +64 -0
  22. package/docs/get-started-en.md +207 -0
  23. package/docs/images/icon.svg +64 -0
  24. package/docs/images/logo_kimu.png +0 -0
  25. package/docs/index.md +29 -0
  26. package/env/dev.config.json +6 -0
  27. package/env/local.config.json +6 -0
  28. package/env/prod.config.json +6 -0
  29. package/env/staging.config.json +6 -0
  30. package/env/test.config.json +4 -0
  31. package/icon.svg +10 -0
  32. package/logo_kimu.png +0 -0
  33. package/package.json +79 -0
  34. package/public/favicon.svg +64 -0
  35. package/public/logo_kimu.svg +1 -0
  36. package/scripts/build-all-config.js +59 -0
  37. package/scripts/build-all-core.js +65 -0
  38. package/scripts/build-all-extensions.js +64 -0
  39. package/scripts/build-all-modules.js +99 -0
  40. package/scripts/build-extension.js +60 -0
  41. package/scripts/clear-kimu-build.js +31 -0
  42. package/scripts/generate-kimu-build-config.js +79 -0
  43. package/scripts/install-module.js +162 -0
  44. package/scripts/list-modules.js +109 -0
  45. package/scripts/minify-css-assets.js +82 -0
  46. package/scripts/remove-module.js +122 -0
  47. package/scripts/utils/fix-imports.js +85 -0
  48. package/src/assets/index.css +43 -0
  49. package/src/assets/kimu-style.css +84 -0
  50. package/src/assets/style.css +116 -0
  51. package/src/config/kimu-base-config.json +5 -0
  52. package/src/core/index.ts +47 -0
  53. package/src/core/kimu-app.ts +76 -0
  54. package/src/core/kimu-asset-manager.ts +167 -0
  55. package/src/core/kimu-component-element.ts +325 -0
  56. package/src/core/kimu-component.ts +33 -0
  57. package/src/core/kimu-engine.ts +188 -0
  58. package/src/core/kimu-extension-manager.ts +281 -0
  59. package/src/core/kimu-global-styles.ts +136 -0
  60. package/src/core/kimu-module-manager.ts +69 -0
  61. package/src/core/kimu-module.ts +21 -0
  62. package/src/core/kimu-path-config.ts +127 -0
  63. package/src/core/kimu-reactive.ts +196 -0
  64. package/src/core/kimu-render.ts +91 -0
  65. package/src/core/kimu-store.ts +147 -0
  66. package/src/core/kimu-types.ts +65 -0
  67. package/src/extensions/.gitkeep +0 -0
  68. package/src/extensions/extensions-manifest.json +13 -0
  69. package/src/extensions/kimu-home/component.ts +80 -0
  70. package/src/extensions/kimu-home/lang/en.json +5 -0
  71. package/src/extensions/kimu-home/lang/it.json +5 -0
  72. package/src/extensions/kimu-home/style.css +61 -0
  73. package/src/extensions/kimu-home/view.html +51 -0
  74. package/src/index.html +26 -0
  75. package/src/main.ts +68 -0
  76. package/src/modules/.gitkeep +0 -0
  77. package/src/modules/README.md +79 -0
  78. package/src/modules/i18n/README.it.md +63 -0
  79. package/src/modules/i18n/README.md +63 -0
  80. package/src/modules/i18n/kimu-global-lang.ts +26 -0
  81. package/src/modules/i18n/kimu-i18n-service.ts +108 -0
  82. package/src/modules/i18n/manifest.json +22 -0
  83. package/src/modules/i18n/module.ts +39 -0
  84. package/src/modules/modules-manifest.json +12 -0
  85. package/src/modules-repository/README.md +108 -0
  86. package/src/modules-repository/api-axios/CHANGELOG.md +48 -0
  87. package/src/modules-repository/api-axios/QUICK-REFERENCE.md +178 -0
  88. package/src/modules-repository/api-axios/README.md +304 -0
  89. package/src/modules-repository/api-axios/api-axios-service.ts +355 -0
  90. package/src/modules-repository/api-axios/examples.ts +293 -0
  91. package/src/modules-repository/api-axios/index.ts +19 -0
  92. package/src/modules-repository/api-axios/interfaces.ts +71 -0
  93. package/src/modules-repository/api-axios/module.ts +41 -0
  94. package/src/modules-repository/api-core/CHANGELOG.md +42 -0
  95. package/src/modules-repository/api-core/QUICK-REFERENCE.md +192 -0
  96. package/src/modules-repository/api-core/README.md +435 -0
  97. package/src/modules-repository/api-core/api-core-service.ts +289 -0
  98. package/src/modules-repository/api-core/examples.ts +432 -0
  99. package/src/modules-repository/api-core/index.ts +8 -0
  100. package/src/modules-repository/api-core/interfaces.ts +83 -0
  101. package/src/modules-repository/api-core/module.ts +30 -0
  102. package/src/modules-repository/event-bus/README.md +273 -0
  103. package/src/modules-repository/event-bus/event-bus-service.ts +176 -0
  104. package/src/modules-repository/event-bus/module.ts +30 -0
  105. package/src/modules-repository/i18n/README.it.md +63 -0
  106. package/src/modules-repository/i18n/README.md +63 -0
  107. package/src/modules-repository/i18n/kimu-global-lang.ts +26 -0
  108. package/src/modules-repository/i18n/kimu-i18n-service.ts +108 -0
  109. package/src/modules-repository/i18n/manifest.json +22 -0
  110. package/src/modules-repository/i18n/module.ts +39 -0
  111. package/src/modules-repository/notification/README.md +423 -0
  112. package/src/modules-repository/notification/module.ts +30 -0
  113. package/src/modules-repository/notification/notification-service.ts +436 -0
  114. package/src/modules-repository/router/README.it.md +39 -0
  115. package/src/modules-repository/router/README.md +39 -0
  116. package/src/modules-repository/router/manifest.json +21 -0
  117. package/src/modules-repository/router/module.ts +23 -0
  118. package/src/modules-repository/router/router.ts +144 -0
  119. package/src/modules-repository/state/README.md +409 -0
  120. package/src/modules-repository/state/module.ts +30 -0
  121. package/src/modules-repository/state/state-service.ts +296 -0
  122. package/src/modules-repository/theme/README.md +267 -0
  123. package/src/modules-repository/theme/module.ts +30 -0
  124. package/src/modules-repository/theme/pre-build.js +40 -0
  125. package/src/modules-repository/theme/theme-service.ts +389 -0
  126. package/src/modules-repository/theme/themes/theme-cherry-blossom.css +78 -0
  127. package/src/modules-repository/theme/themes/theme-cozy.css +111 -0
  128. package/src/modules-repository/theme/themes/theme-cyberpunk.css +150 -0
  129. package/src/modules-repository/theme/themes/theme-dark.css +79 -0
  130. package/src/modules-repository/theme/themes/theme-forest.css +171 -0
  131. package/src/modules-repository/theme/themes/theme-gold.css +100 -0
  132. package/src/modules-repository/theme/themes/theme-high-contrast.css +126 -0
  133. package/src/modules-repository/theme/themes/theme-lava.css +101 -0
  134. package/src/modules-repository/theme/themes/theme-lavender.css +90 -0
  135. package/src/modules-repository/theme/themes/theme-light.css +79 -0
  136. package/src/modules-repository/theme/themes/theme-matrix.css +103 -0
  137. package/src/modules-repository/theme/themes/theme-midnight.css +81 -0
  138. package/src/modules-repository/theme/themes/theme-nord.css +94 -0
  139. package/src/modules-repository/theme/themes/theme-ocean.css +84 -0
  140. package/src/modules-repository/theme/themes/theme-retro80s.css +343 -0
  141. package/src/modules-repository/theme/themes/theme-sunset.css +62 -0
  142. package/src/modules-repository/theme/themes-config.d.ts +27 -0
  143. package/src/modules-repository/theme/themes-config.json +213 -0
  144. package/src/vite-env.d.ts +1 -0
  145. package/tsconfig.json +33 -0
  146. package/vite.config.ts +99 -0
@@ -0,0 +1,325 @@
1
+ import { KimuEngine } from './kimu-engine';
2
+ import { KimuExtensionManager } from './kimu-extension-manager';
3
+ import { KimuExtensionMeta } from './kimu-types';
4
+ import { KimuPathConfig } from './kimu-path-config';
5
+ import { KimuGlobalStyles } from './kimu-global-styles';
6
+ import {
7
+ initReactiveProperties,
8
+ getObservedAttributes,
9
+ handleAttributeChange
10
+ } from './kimu-reactive';
11
+
12
+ /**
13
+ * The `KimuComponentElement` class serves as the base class for all components and extensions
14
+ * in the Kimu framework. It provides lifecycle hooks, metadata management, and utility methods
15
+ * for rendering and managing resources.
16
+ *
17
+ * Key functionalities:
18
+ * - Provides lifecycle hooks (`onInit`, `onRender`, `onDestroy`) for component management.
19
+ * - Manages metadata associated with the component.
20
+ * - Handles template rendering and resource loading.
21
+ * - Supports dependency injection and external asset management.
22
+ *
23
+ * This class is designed to be extended by custom components and used with the `@KimuComponent` decorator.
24
+ */
25
+ export abstract class KimuComponentElement extends HTMLElement {
26
+
27
+ /**
28
+ * Static method to get observed attributes from reactive properties
29
+ * This enables automatic attribute reflection for @property decorated properties
30
+ */
31
+ static get observedAttributes(): string[] {
32
+ return getObservedAttributes(this);
33
+ }
34
+
35
+ /** Global optimization settings - simplified */
36
+ private static _optimizationSettings = {
37
+ enableTemplateCache: true,
38
+ enableFileCache: true,
39
+ enableRenderDebouncing: true,
40
+ enableErrorBoundaries: true, // New: Safe error isolation
41
+ cacheMaxSize: 50, // New: Cache size limiting
42
+ enableAssetPreloading: false // New: Asset preloading (opt-in)
43
+ };
44
+
45
+ /**
46
+ * Configure global optimization settings for all components
47
+ */
48
+ static configureOptimizations(settings: Partial<typeof KimuComponentElement._optimizationSettings>) {
49
+ Object.assign(this._optimizationSettings, settings);
50
+
51
+ // Apply cache size settings to KimuEngine
52
+ if (settings.cacheMaxSize !== undefined) {
53
+ KimuEngine.configureCaching(settings.cacheMaxSize);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Get current optimization settings (for debugging)
59
+ */
60
+ static getOptimizationSettings() {
61
+ return { ...this._optimizationSettings };
62
+ }
63
+
64
+ /**
65
+ * Preload critical assets for better performance
66
+ */
67
+ static async preloadAssets(assetPaths: string[]): Promise<void> {
68
+ if (!this._optimizationSettings.enableAssetPreloading) {
69
+ console.warn('[KimuComponentElement] Asset preloading is disabled');
70
+ return;
71
+ }
72
+
73
+ return KimuEngine.preloadAssets(assetPaths);
74
+ }
75
+
76
+ /**
77
+ * Force refresh without optimizations (for debugging)
78
+ */
79
+ async forceRefresh(): Promise<void> {
80
+ if (!this._renderFn) {
81
+ console.warn('[KimuComponentElement] ⚠️ Template render function (_renderFn) not initialized for component:', this.tagName);
82
+ return;
83
+ }
84
+
85
+ // Force render immediately without debouncing
86
+ const currentData = this.getData();
87
+ await KimuEngine.render(this, currentData, this._renderFn!);
88
+ this.onRender();
89
+ }
90
+
91
+ /** Private reference to the KimuApp singleton (lazy loaded) */
92
+ private _app: any = null;
93
+ /** Each component must provide data for rendering */
94
+ getData(): Record<string, any> {
95
+ return {};
96
+ }
97
+
98
+ /** Lifecycle: initialization */
99
+ onInit(): void { }
100
+
101
+ /** Called every time after a render or refresh */
102
+ onRender(): void { }
103
+
104
+ /** Lifecycle: destruction */
105
+ onDestroy(): void { }
106
+
107
+ /** Optional error handling hook - override in components that need custom error handling */
108
+ onError?(error: Error): void;
109
+
110
+ /** Hook for loading the template */
111
+ private _renderFn?: (html: any, data: Record<string, any>) => any;
112
+
113
+ /** Lifecycle: destruction (override for custom cleanup, calls onDestroy by default) */
114
+ _onDestroyInternal(): void {
115
+ this.onDestroy();
116
+ }
117
+
118
+ /**
119
+ * Returns the KimuApp singleton, importing it dynamically only once.
120
+ * Usage: await this.getApp() in your extension/component.
121
+ */
122
+ protected async getApp(): Promise<any> {
123
+ if (this._app) {
124
+ return this._app;
125
+ }
126
+ // Dynamically import KimuApp to avoid circular dependencies
127
+ const { KimuApp } = await import('./kimu-app');
128
+ this._app = KimuApp.getInstance();
129
+ return this._app;
130
+ }
131
+
132
+ /**
133
+ * Constructor for the Kimu component.
134
+ * Initializes the shadow DOM and attaches it to the component.
135
+ */
136
+ constructor() {
137
+ super();
138
+ this.attachShadow({ mode: 'open' });
139
+ //console.log("\n\n###### META DATA: ", this.getMeta());
140
+ }
141
+
142
+ /**
143
+ * Called when an observed attribute changes
144
+ * This is part of the Web Components lifecycle and enables attribute reflection
145
+ */
146
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {
147
+ // Handle reactive property attribute changes
148
+ handleAttributeChange(this, name, oldValue, newValue);
149
+ }
150
+
151
+ /** Shortcut for querying the DOM */
152
+ $(selector: string): HTMLElement | null {
153
+ return this.shadowRoot?.querySelector(selector) ?? null;
154
+ }
155
+
156
+ /** Retrieves metadata associated with the component */
157
+ protected getMeta(): KimuExtensionMeta {
158
+ return (this.constructor as any).__kimu_meta__ as KimuExtensionMeta;
159
+ }
160
+
161
+ /**
162
+ * Hook called automatically by the browser when the component is connected to the DOM.
163
+ * Method automatically called by the browser when the component is connected.
164
+ */
165
+ async connectedCallback(): Promise<void> {
166
+ const meta = this.getMeta();
167
+ //console.log('[KimuComponentElement] Init tag:', this.tagName, 'meta:', meta);
168
+ if (!meta || !meta.tag) {
169
+ console.warn('[KimuComponentElement] ❌ No metadata found for the component:', this.tagName , " - meta:", meta);
170
+ return;
171
+ }
172
+
173
+ // Initialize reactive properties from HTML attributes
174
+ initReactiveProperties(this);
175
+
176
+ // Load dependencies - use Promise.all for parallel loading
177
+ if (meta.dependencies?.length) {
178
+ const manager = KimuExtensionManager.getInstance();
179
+ await Promise.all(meta.dependencies.map(dep => manager.load(dep)));
180
+ }
181
+
182
+ // Inject all registered global styles (kimu-style.css + theme CSS, etc.)
183
+ const globalStyles = KimuGlobalStyles.getGlobalStyles();
184
+ for (const style of globalStyles) {
185
+ await KimuEngine.injectStyle(this, style.path, style.id);
186
+ }
187
+
188
+ // Inject external styles (if present, just once)
189
+ if (meta.style) {
190
+ let styleId = `kimu-style-ext-${meta.tag}`;
191
+ const cssPath = KimuPathConfig.resolvePath(`extensions/${meta.basePath}/${meta.style}`);
192
+ await KimuEngine.injectStyle(this, cssPath, styleId);
193
+ }
194
+
195
+ // Compile the template on the first connection
196
+ if (meta.template) {
197
+ const templatePath = KimuPathConfig.resolvePath(`extensions/${meta.basePath}/${meta.template}`);
198
+ // Use template caching based on global settings
199
+ const useCache = KimuComponentElement._optimizationSettings.enableTemplateCache;
200
+ this._renderFn = await KimuEngine.loadTemplate(templatePath, useCache);
201
+ }
202
+
203
+ // Initial render - wait for completion before calling onInit
204
+ await this.refresh(); // Render the template with data and wait for completion
205
+ // Call the initialization hook - DOM is now guaranteed to be ready
206
+ this.onInit(); // Call once, after DOM is fully rendered
207
+ }
208
+
209
+ /**
210
+ * Forces a refresh of the interface component
211
+ * Note: For @property decorated properties, this is called automatically.
212
+ * Manual calls are only needed for non-reactive state changes.
213
+ */
214
+ async refresh(): Promise<void> {
215
+ if (!this._renderFn) {
216
+ console.warn('[KimuComponentElement] ⚠️ Template render function (_renderFn) not initialized for component:', this.tagName);
217
+ return;
218
+ }
219
+
220
+ // Skip debouncing if disabled or call directly
221
+ if (!KimuComponentElement._optimizationSettings.enableRenderDebouncing) {
222
+ await this._doRender();
223
+ return;
224
+ }
225
+
226
+ // Use the same RAF batching mechanism as kimu-reactive
227
+ // This ensures consistent behavior across manual and reactive updates
228
+ if ((this as any).__kimu_render_pending__) {
229
+ return; // Already scheduled
230
+ }
231
+
232
+ (this as any).__kimu_render_pending__ = true;
233
+
234
+ return new Promise<void>((resolve) => {
235
+ requestAnimationFrame(async () => {
236
+ try {
237
+ await this._doRender();
238
+ resolve();
239
+ } catch (error) {
240
+ console.error('[KimuComponentElement] Render error:', error);
241
+ resolve(); // Resolve anyway to prevent hanging
242
+ } finally {
243
+ (this as any).__kimu_render_pending__ = false;
244
+ }
245
+ });
246
+ });
247
+ }
248
+
249
+ /**
250
+ * Internal render method - simplified without snapshot optimization
251
+ */
252
+ private async _doRender(): Promise<void> {
253
+ if (!KimuComponentElement._optimizationSettings.enableErrorBoundaries) {
254
+ // Original behavior without error boundaries
255
+ const currentData = this.getData();
256
+ await KimuEngine.render(this, currentData, this._renderFn!);
257
+ this.onRender();
258
+ return;
259
+ }
260
+
261
+ // Safe rendering with error boundaries
262
+ try {
263
+ const currentData = this.getData();
264
+ await KimuEngine.render(this, currentData, this._renderFn!);
265
+ this.onRender();
266
+ } catch (error) {
267
+ console.error(`[${this.tagName}] Render error:`, error);
268
+ console.error('Component data:', this.getData());
269
+
270
+ // Fallback UI - safe and informative
271
+ if (this.shadowRoot) {
272
+ this.shadowRoot.innerHTML = `
273
+ <div style="
274
+ color: #721c24;
275
+ background-color: #f8d7da;
276
+ border: 1px solid #f5c6cb;
277
+ padding: 10px;
278
+ border-radius: 4px;
279
+ font-family: monospace;
280
+ font-size: 12px;
281
+ ">
282
+ <strong>⚠️ Component Error</strong><br>
283
+ <em>${this.tagName}</em><br>
284
+ ${error instanceof Error ? error.message : 'Unknown error'}
285
+ </div>
286
+ `;
287
+ }
288
+
289
+ // Call error hook if available
290
+ if (typeof this.onError === 'function') {
291
+ try {
292
+ this.onError(error instanceof Error ? error : new Error(String(error)));
293
+ } catch (hookError) {
294
+ console.error(`[${this.tagName}] Error in onError hook:`, hookError);
295
+ }
296
+ }
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Hook called automatically when the component is disconnected from the DOM.
302
+ * Method automatically called on logout.
303
+ */
304
+ disconnectedCallback(): void {
305
+ // Clean up RAF batching state
306
+ (this as any).__kimu_render_pending__ = false;
307
+
308
+ // Call the destruction hook
309
+ this._onDestroyInternal();
310
+ }
311
+
312
+ /** Loads a resource from an external file */
313
+ loadResource(file: string): Promise<any> {
314
+ const path = this.getMeta()?.path;
315
+ if (!path) throw new Error('Extension without valid path');
316
+ const resourcePath = KimuPathConfig.resolvePath(`extensions/${path}/resources/${file}`);
317
+ return fetch(resourcePath).then(r => r.json());
318
+ }
319
+
320
+ /** Loads an asset from an external file */
321
+ loadAssetUrl(file: string): string {
322
+ const path = this.getMeta()?.path;
323
+ return KimuPathConfig.resolvePath(`extensions/${path}/assets/${file}`);
324
+ }
325
+ }
@@ -0,0 +1,33 @@
1
+ import { KimuExtensionMeta } from "./kimu-types";
2
+
3
+ /**
4
+ * Decorator to define a Kimu component with static metadata.
5
+ *
6
+ * This script defines the `@KimuComponent` decorator, which is used to register
7
+ * custom components in the Kimu framework with static metadata.
8
+ *
9
+ * Key functionalities:
10
+ * - Allows defining metadata for components, such as tag name, template path, and style path.
11
+ * - Automatically sets default paths for the template and style if not provided.
12
+ * - Registers the custom element with the browser using `customElements.define`.
13
+ * - Attaches static metadata directly to the class for later use.
14
+ *
15
+ * @param meta - Metadata describing the component, including tag name, paths, and dependencies.
16
+ */
17
+ export function KimuComponent(meta: KimuExtensionMeta) {
18
+ return function <T extends CustomElementConstructor>(target: T) {
19
+ // Sets the base path as a fallback (e.g., extensions/hello)
20
+ const basePath = meta.path ?? `extensions/${meta.tag}`;
21
+
22
+ // Sets default paths for the template and style if not specified
23
+ meta.basePath = basePath;
24
+ meta.template = meta.template ?? 'view.html'; //`${basePath}/view.html`;
25
+ meta.style = meta.style ?? 'style.css'; //`${basePath}/style.css`;
26
+
27
+ // Registers the custom element with the browser
28
+ customElements.define(meta.tag, target);
29
+
30
+ // Attaches static metadata directly to the class for later use
31
+ (target as any).__kimu_meta__ = meta;
32
+ };
33
+ }
@@ -0,0 +1,188 @@
1
+ import { TemplateResult } from 'lit';
2
+ import { KimuRender } from './kimu-render';
3
+ import { KimuAssetManager } from './kimu-asset-manager';
4
+
5
+ /**
6
+ * The `KimuEngine` class provides core functionalities for rendering, template management,
7
+ * and component loading in the Kimu framework. It acts as a bridge between the rendering engine
8
+ * (Lit) and the asset manager, enabling dynamic and reactive UI updates.
9
+ *
10
+ * Key functionalities:
11
+ * - Injects styles into the Shadow DOM of components.
12
+ * - Loads and compiles HTML templates into Lit rendering functions.
13
+ * - Provides reactive rendering capabilities using Lit.
14
+ * - Dynamically loads and registers custom components.
15
+ */
16
+ export class KimuEngine {
17
+
18
+ /** Cache for compiled templates to avoid recompilation */
19
+ private static _templateCache = new Map<string, any>();
20
+
21
+ /** Cache access tracking for LRU eviction */
22
+ private static _cacheAccessTime = new Map<string, number>();
23
+
24
+ /** Maximum cache size to prevent memory issues */
25
+ private static _maxCacheSize = 50;
26
+
27
+ /**
28
+ * Safely evict oldest cache entries when limit is reached
29
+ */
30
+ private static _evictOldestEntries(): void {
31
+ if (this._templateCache.size < this._maxCacheSize) return;
32
+
33
+ // Get entries sorted by access time (oldest first)
34
+ const entriesToEvict = Array.from(this._cacheAccessTime.entries())
35
+ .sort(([, a], [, b]) => a - b)
36
+ .slice(0, Math.floor(this._templateCache.size * 0.2)) // Evict 20%
37
+ .map(([path]) => path);
38
+
39
+ // Remove from both caches
40
+ entriesToEvict.forEach(path => {
41
+ this._templateCache.delete(path);
42
+ this._cacheAccessTime.delete(path);
43
+ });
44
+
45
+ if (entriesToEvict.length > 0) {
46
+ console.log(`[KimuEngine] Evicted ${entriesToEvict.length} old template cache entries`);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Configure cache settings
52
+ */
53
+ static configureCaching(maxSize: number = 50): void {
54
+ this._maxCacheSize = maxSize;
55
+ }
56
+
57
+ /**
58
+ * Clear all caches (for debugging/testing)
59
+ */
60
+ static clearCaches(): void {
61
+ this._templateCache.clear();
62
+ this._cacheAccessTime.clear();
63
+ }
64
+
65
+ /**
66
+ * Preload critical assets to improve performance
67
+ */
68
+ static async preloadAssets(paths: string[]): Promise<void> {
69
+ if (paths.length === 0) return;
70
+
71
+ console.log(`[KimuEngine] Preloading ${paths.length} assets...`);
72
+
73
+ // Preload in parallel but with limited concurrency to avoid overwhelming the browser
74
+ const BATCH_SIZE = 5;
75
+ const batches = [];
76
+
77
+ for (let i = 0; i < paths.length; i += BATCH_SIZE) {
78
+ batches.push(paths.slice(i, i + BATCH_SIZE));
79
+ }
80
+
81
+ for (const batch of batches) {
82
+ const promises = batch.map(async (path) => {
83
+ try {
84
+ if (path.endsWith('.html')) {
85
+ // Preload template
86
+ await this.loadTemplate(path, true);
87
+ } else if (path.endsWith('.css')) {
88
+ // Preload style (just fetch to cache)
89
+ await KimuAssetManager.fetchFile(path);
90
+ } else {
91
+ // Generic asset preload
92
+ await KimuAssetManager.fetchFile(path);
93
+ }
94
+ } catch (error) {
95
+ console.warn(`[KimuEngine] Failed to preload asset: ${path}`, error);
96
+ }
97
+ });
98
+
99
+ await Promise.all(promises);
100
+ }
101
+
102
+ console.log(`[KimuEngine] Preloading completed`);
103
+ }
104
+
105
+ /**
106
+ * Injects an inline style from a file into the Shadow DOM of a component.
107
+ *
108
+ * @param component - The target component.
109
+ * @param stylePath - Path to the style file.
110
+ * @param styleId - Optional ID for the style element.
111
+ */
112
+ static async injectStyle(component: HTMLElement, stylePath: string, styleId: string | null = null): Promise<void> {
113
+ return KimuAssetManager.injectStyle(component, stylePath, styleId);
114
+ }
115
+
116
+ /**
117
+ * Loads and compiles an HTML template from a file into a Lit rendering function.
118
+ *
119
+ * @param path - Path to the template file.
120
+ * @param useCache - Whether to use template cache (default: true)
121
+ * @returns A compiled Lit rendering function.
122
+ * @throws Error if the template file is not found.
123
+ */
124
+ static async loadTemplate(path: string, useCache: boolean = true) {
125
+ // Check cache first (if caching is enabled)
126
+ if (useCache && this._templateCache.has(path)) {
127
+ // Update access time for LRU
128
+ this._cacheAccessTime.set(path, Date.now());
129
+ return this._templateCache.get(path);
130
+ }
131
+
132
+ //console.log(`[KimuEngine] 🔄 Loading template: ${path}`);
133
+ const template: string | null = await KimuAssetManager.fetchFile(path);
134
+ if (!template) {
135
+ throw new Error(`[KimuEngine] ⚠️ Template not found: ${template}`);
136
+ }
137
+
138
+ const compiledTemplate = KimuRender.loadTemplate(template);
139
+
140
+ // Cache the compiled template (if caching is enabled)
141
+ if (useCache) {
142
+ // Check if we need to evict old entries first
143
+ this._evictOldestEntries();
144
+
145
+ this._templateCache.set(path, compiledTemplate);
146
+ this._cacheAccessTime.set(path, Date.now());
147
+ }
148
+
149
+ return compiledTemplate;
150
+ }
151
+
152
+ /**
153
+ * Compiles an HTML string into a dynamic Lit rendering function.
154
+ *
155
+ * @param template - The HTML string to compile.
156
+ * @returns A Lit rendering function.
157
+ */
158
+ static compileTemplate(template: string): (html: typeof import('lit').html, data: Record<string, any>) => TemplateResult {
159
+ return KimuRender.compileTemplate(template);
160
+ }
161
+
162
+ /**
163
+ * Performs reactive rendering using Lit.
164
+ *
165
+ * @param component - The target component.
166
+ * @param data - Data to be passed to the rendering function.
167
+ * @param renderFn - The Lit rendering function.
168
+ */
169
+ static render(component: HTMLElement, data: Record<string, any>, renderFn: (html: any, data: Record<string, any>) => TemplateResult): void {
170
+ KimuRender.render(component, data, renderFn);
171
+ }
172
+
173
+ /**
174
+ * Loads a component from a specified path and registers it if not already registered.
175
+ *
176
+ * @param tag - The tag name of the component.
177
+ * @param path - Path to the component module.
178
+ * @returns The loaded module.
179
+ */
180
+ static async loadComponent(tag: string, path: string): Promise<any> {
181
+ if (customElements.get(tag)) {
182
+ return; // Already registered
183
+ }
184
+ const module = await import(/* @vite-ignore */ path);
185
+ return module;
186
+ }
187
+
188
+ }