@kimesh/kit 0.0.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,2795 @@
1
+ import { createRequire } from "node:module";
2
+ import { createHooks } from "hookable";
3
+ import { snakeCase } from "scule";
4
+ import { klona } from "klona/json";
5
+ import destr from "destr";
6
+ import { pathToFileURL } from "node:url";
7
+ import consola from "consola";
8
+ import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
9
+ import { dirname, isAbsolute, join, resolve } from "node:path";
10
+ import fg from "fast-glob";
11
+ import { basename, extname, isAbsolute as isAbsolute$1, join as join$1, relative, resolve as resolve$1 } from "pathe";
12
+ import ignore from "ignore";
13
+ import pc from "picocolors";
14
+ import { defu } from "defu";
15
+ import { loadEnv, mergeConfig } from "vite";
16
+ import vue from "@vitejs/plugin-vue";
17
+ import { kimeshRouterGenerator } from "@kimesh/router-generator";
18
+ import { generateLayerAliases, generateLayerAliases as generateLayerAliases$1, mergeLayerConfigs, prepareLayers, prepareLayers as prepareLayers$1, resolveLayers } from "@kimesh/layers";
19
+ import { buildImportRegistry, generateDts, kimeshAutoImport, kimeshAutoImport as kimeshAutoImport$1, scanExports } from "@kimesh/auto-import";
20
+ import { loadConfig as loadConfig$1 } from "c12";
21
+
22
+ //#region src/runtime-config.ts
23
+ /**
24
+ * @kimesh/kit - Runtime Configuration Processing
25
+ *
26
+ * Utilities for processing environment variables and merging with runtime config.
27
+ * Phase 1: Build-time only, all config is public.
28
+ */
29
+ /** Default environment variable prefix */
30
+ const ENV_PREFIX = "KIMESH_";
31
+ /**
32
+ * Convert a config key path to environment variable name.
33
+ *
34
+ * @param keys - Array of keys representing the path (e.g., ['features', 'darkMode'])
35
+ * @param prefix - Environment variable prefix (default: 'KIMESH_')
36
+ * @returns Environment variable name (e.g., 'KIMESH_FEATURES_DARK_MODE')
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * keyToEnv(['apiBase']) // => 'KIMESH_API_BASE'
41
+ * keyToEnv(['features', 'darkMode']) // => 'KIMESH_FEATURES_DARK_MODE'
42
+ * ```
43
+ */
44
+ function keyToEnv(keys, prefix = ENV_PREFIX) {
45
+ return prefix + keys.map((key) => snakeCase(key).toUpperCase()).join("_");
46
+ }
47
+ /**
48
+ * Convert environment variable name to config key path.
49
+ *
50
+ * Note: This function uses a best-effort heuristic for reverse conversion.
51
+ * Since SNAKE_CASE to camelCase is ambiguous (e.g., API_BASE could be 'apiBase' or 'apibase'),
52
+ * this function assumes each underscore-separated segment is a word boundary.
53
+ *
54
+ * @param envKey - Environment variable name
55
+ * @param prefix - Environment variable prefix (default: 'KIMESH_')
56
+ * @returns Array of keys or null if the env var doesn't match the prefix
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * envToKey('KIMESH_API_BASE') // => ['apiBase']
61
+ * envToKey('KIMESH_FEATURES_DARK_MODE') // => ['features', 'darkMode']
62
+ * ```
63
+ */
64
+ function envToKey(envKey, prefix = ENV_PREFIX) {
65
+ if (!envKey.startsWith(prefix)) return null;
66
+ const rest = envKey.slice(prefix.length);
67
+ if (!rest) return null;
68
+ return rest.toLowerCase().split("_").reduce((acc, part, i) => {
69
+ if (i === 0) acc.push(part);
70
+ else if (part) {
71
+ const last = acc[acc.length - 1];
72
+ acc[acc.length - 1] = last + part.charAt(0).toUpperCase() + part.slice(1);
73
+ }
74
+ return acc;
75
+ }, []);
76
+ }
77
+ /**
78
+ * Check if a value at the given path exists in the config object.
79
+ * This helps determine if an env var corresponds to an existing config key.
80
+ */
81
+ function hasConfigPath(config, keys) {
82
+ let current = config;
83
+ for (const key of keys) {
84
+ if (current === null || typeof current !== "object") return false;
85
+ if (!(key in current)) return false;
86
+ current = current[key];
87
+ }
88
+ return true;
89
+ }
90
+ /**
91
+ * Get all possible key paths from environment variable name.
92
+ * Since SNAKE_CASE conversion is ambiguous, this generates multiple candidates.
93
+ *
94
+ * @param envKey - Environment variable name (without prefix)
95
+ * @returns Array of possible key path interpretations
96
+ */
97
+ function getPossiblePaths(envKey) {
98
+ const parts = envKey.toLowerCase().split("_");
99
+ const paths = [];
100
+ function generateGroupings(parts$1, current, start) {
101
+ if (start >= parts$1.length) {
102
+ paths.push([...current]);
103
+ return;
104
+ }
105
+ for (let end = start + 1; end <= parts$1.length; end++) {
106
+ const segment = parts$1.slice(start, end).reduce((acc, part, i) => {
107
+ if (i === 0) return part;
108
+ return acc + part.charAt(0).toUpperCase() + part.slice(1);
109
+ }, "");
110
+ current.push(segment);
111
+ generateGroupings(parts$1, current, end);
112
+ current.pop();
113
+ }
114
+ }
115
+ generateGroupings(parts, [], 0);
116
+ return paths;
117
+ }
118
+ /**
119
+ * Find the best matching config path for an environment variable.
120
+ * Prioritizes existing paths in the config, falls back to single camelCase key.
121
+ */
122
+ function findBestPath(envKey, config, prefix) {
123
+ if (!envKey.startsWith(prefix)) return null;
124
+ const rest = envKey.slice(prefix.length);
125
+ if (!rest) return null;
126
+ const possiblePaths = getPossiblePaths(rest);
127
+ for (const path of possiblePaths) if (hasConfigPath(config, path)) return path;
128
+ return [rest.toLowerCase().split("_").reduce((acc, part, i) => {
129
+ if (i === 0) return part;
130
+ return acc + part.charAt(0).toUpperCase() + part.slice(1);
131
+ }, "")];
132
+ }
133
+ /**
134
+ * Set a value at a nested path in an object, creating intermediate objects as needed.
135
+ */
136
+ function setNestedValue(obj, keys, value) {
137
+ let current = obj;
138
+ for (let i = 0; i < keys.length - 1; i++) {
139
+ const key = keys[i];
140
+ if (!(key in current) || typeof current[key] !== "object" || current[key] === null) current[key] = {};
141
+ current = current[key];
142
+ }
143
+ current[keys[keys.length - 1]] = value;
144
+ }
145
+ /**
146
+ * Apply environment variables to runtime config.
147
+ *
148
+ * Scans the environment for `KIMESH_*` variables and overlays them onto
149
+ * the config object. Called at build time to bake env values into the bundle.
150
+ *
151
+ * @param config - Base runtime config from kimesh.config.ts
152
+ * @param opts - Options for environment processing
153
+ * @returns Merged config with env overrides
154
+ *
155
+ * @example
156
+ * ```ts
157
+ * // Given:
158
+ * // KIMESH_API_BASE=https://api.example.com
159
+ * // KIMESH_DEBUG=true
160
+ *
161
+ * const config = applyEnv({
162
+ * apiBase: '/api',
163
+ * debug: false,
164
+ * });
165
+ *
166
+ * // Result:
167
+ * // { apiBase: 'https://api.example.com', debug: true }
168
+ * ```
169
+ */
170
+ function applyEnv(config, opts = {}) {
171
+ const { prefix = ENV_PREFIX, env = process.env } = opts;
172
+ const result = klona(config);
173
+ for (const [key, value] of Object.entries(env)) {
174
+ if (value === void 0) continue;
175
+ if (!key.startsWith(prefix)) continue;
176
+ const configPath = findBestPath(key, result, prefix);
177
+ if (!configPath || configPath.length === 0) continue;
178
+ setNestedValue(result, configPath, destr(value));
179
+ }
180
+ return result;
181
+ }
182
+ /**
183
+ * Create an empty runtime config object.
184
+ * Used as a default when no config is provided.
185
+ */
186
+ function createDefaultRuntimeConfig() {
187
+ return {};
188
+ }
189
+
190
+ //#endregion
191
+ //#region src/core/kimesh.ts
192
+ /**
193
+ * @kimesh/kit - Core Kimesh Context Implementation
194
+ *
195
+ * The Kimesh class is the central context for all module operations.
196
+ */
197
+ /**
198
+ * Create empty registries
199
+ */
200
+ function createEmptyRegistries() {
201
+ return {
202
+ vitePlugins: [],
203
+ aliases: [],
204
+ templates: [],
205
+ typeTemplates: [],
206
+ imports: [],
207
+ importsDirs: [],
208
+ importsPresets: [],
209
+ components: [],
210
+ componentsDirs: [],
211
+ componentResolvers: [],
212
+ routes: [],
213
+ routeMiddleware: [],
214
+ runtimePlugins: []
215
+ };
216
+ }
217
+ /**
218
+ * Create a new Kimesh context
219
+ */
220
+ function createKimesh(options) {
221
+ const hooks = createHooks();
222
+ const registries = createEmptyRegistries();
223
+ const resolvedRuntimeConfig = applyEnv(options.config.runtimeConfig || createDefaultRuntimeConfig());
224
+ const kimeshOptions = {
225
+ dev: options.dev ?? process.env.NODE_ENV !== "production",
226
+ root: options.root,
227
+ buildDir: options.buildDir,
228
+ config: options.config,
229
+ layers: options.layers,
230
+ runtimeConfig: {
231
+ public: resolvedRuntimeConfig,
232
+ private: {}
233
+ }
234
+ };
235
+ return {
236
+ options: kimeshOptions,
237
+ hooks,
238
+ _registries: registries,
239
+ get layers() {
240
+ return kimeshOptions.layers;
241
+ },
242
+ get root() {
243
+ return kimeshOptions.root;
244
+ },
245
+ get buildDir() {
246
+ return kimeshOptions.buildDir;
247
+ },
248
+ hook(name, handler, opts) {
249
+ return hooks.hook(name, handler, opts);
250
+ },
251
+ callHook(name, ...args) {
252
+ return hooks.callHook(name, ...args);
253
+ },
254
+ hookOnce(name, handler) {
255
+ return hooks.hookOnce(name, handler);
256
+ }
257
+ };
258
+ }
259
+ let currentKimesh;
260
+ /**
261
+ * Set the current Kimesh context (internal use)
262
+ */
263
+ function _setKimeshContext(kimesh) {
264
+ currentKimesh = kimesh;
265
+ }
266
+ /**
267
+ * Get the current Kimesh context
268
+ * @throws Error if not in a Kimesh context
269
+ */
270
+ function useKimesh() {
271
+ if (!currentKimesh) throw new Error("[kimesh] useKimesh() called outside of Kimesh context. Make sure you're calling this within a module setup function.");
272
+ return currentKimesh;
273
+ }
274
+ /**
275
+ * Try to get the current Kimesh context
276
+ * @returns Kimesh instance or undefined if not in context
277
+ */
278
+ function tryUseKimesh() {
279
+ return currentKimesh;
280
+ }
281
+
282
+ //#endregion
283
+ //#region src/core/module.ts
284
+ /**
285
+ * @kimesh/kit - Module Definition & Execution
286
+ */
287
+ /**
288
+ * Define a Kimesh module with full type inference
289
+ *
290
+ * @example
291
+ * ```ts
292
+ * export default defineKimeshModule<{ apiKey: string }>({
293
+ * meta: {
294
+ * name: "@kimesh/analytics",
295
+ * configKey: "analytics",
296
+ * },
297
+ * defaults: {
298
+ * apiKey: "",
299
+ * },
300
+ * hooks: {
301
+ * "ready": (kimesh) => {
302
+ * console.log("Kimesh is ready!");
303
+ * },
304
+ * },
305
+ * async setup(options, kimesh) {
306
+ * // Module setup logic
307
+ * },
308
+ * });
309
+ * ```
310
+ */
311
+ function defineKimeshModule(definition) {
312
+ return {
313
+ _def: definition,
314
+ meta: {
315
+ name: definition.meta?.name ?? "anonymous-module",
316
+ version: definition.meta?.version ?? "0.0.0",
317
+ configKey: definition.meta?.configKey ?? "",
318
+ compatibility: definition.meta?.compatibility ?? {}
319
+ },
320
+ async getDefaults(kimesh) {
321
+ if (!definition.defaults) return {};
322
+ if (typeof definition.defaults === "function") return await definition.defaults(kimesh);
323
+ return definition.defaults;
324
+ },
325
+ async setup(options, kimesh) {
326
+ if (definition.hooks) {
327
+ for (const [hookName, handler] of Object.entries(definition.hooks)) if (handler) kimesh.hook(hookName, handler);
328
+ }
329
+ if (definition.setup) await definition.setup(options, kimesh);
330
+ }
331
+ };
332
+ }
333
+ /**
334
+ * Resolve a string module name to an actual module
335
+ */
336
+ async function resolveStringModule(moduleName, kimesh) {
337
+ try {
338
+ const requirePath = kimesh.root + "/package.json";
339
+ const require = createRequire(pathToFileURL(requirePath).href);
340
+ let modulePath;
341
+ try {
342
+ modulePath = require.resolve(moduleName);
343
+ consola.debug(`[Kimesh] Resolved module "${moduleName}" to ${modulePath}`);
344
+ } catch (err) {
345
+ consola.debug(`[Kimesh] Failed to resolve "${moduleName}" from ${requirePath}:`, err);
346
+ throw new Error(`Module "${moduleName}" not found. Make sure it's installed in your project.`);
347
+ }
348
+ const imported = await import(pathToFileURL(modulePath).href);
349
+ const module = imported.default || imported;
350
+ if (module && typeof module === "object" && "_def" in module) return module;
351
+ if (module && typeof module === "object" && "setup" in module) return defineKimeshModule(module);
352
+ throw new Error(`Module "${moduleName}" does not export a valid Kimesh module. Make sure the module uses defineKimeshModule() or exports a valid module definition.`);
353
+ } catch (error) {
354
+ if (error instanceof Error) throw error;
355
+ throw new Error(`Failed to load module "${moduleName}": ${error}`);
356
+ }
357
+ }
358
+ /**
359
+ * Normalize module input (string, module, or [module, options] tuple)
360
+ */
361
+ async function normalizeModuleInput(input, kimesh) {
362
+ if (typeof input === "string") return {
363
+ module: await resolveStringModule(input, kimesh),
364
+ options: {}
365
+ };
366
+ if (Array.isArray(input)) {
367
+ const [moduleOrString, options] = input;
368
+ if (typeof moduleOrString === "string") return {
369
+ module: await resolveStringModule(moduleOrString, kimesh),
370
+ options: options ?? {}
371
+ };
372
+ return {
373
+ module: moduleOrString,
374
+ options: options ?? {}
375
+ };
376
+ }
377
+ return {
378
+ module: input,
379
+ options: {}
380
+ };
381
+ }
382
+ /**
383
+ * Execute a single module
384
+ */
385
+ async function executeModule(moduleInput, kimesh) {
386
+ const { module, options: userOptions } = await normalizeModuleInput(moduleInput, kimesh);
387
+ const defaults = await module.getDefaults(kimesh);
388
+ const configKey = module.meta.configKey;
389
+ const configOptions = configKey ? kimesh.options.config[configKey] ?? {} : {};
390
+ const mergedOptions = {
391
+ ...defaults,
392
+ ...configOptions,
393
+ ...userOptions
394
+ };
395
+ _setKimeshContext(kimesh);
396
+ try {
397
+ await module.setup(mergedOptions, kimesh);
398
+ } finally {
399
+ _setKimeshContext(void 0);
400
+ }
401
+ }
402
+ /**
403
+ * Extract module name from various input formats
404
+ */
405
+ function getModuleName(input) {
406
+ if (typeof input === "string") return input;
407
+ if (Array.isArray(input)) {
408
+ const first = input[0];
409
+ if (typeof first === "string") return first;
410
+ return first.meta?.name ?? "unknown";
411
+ }
412
+ return input.meta?.name ?? "unknown";
413
+ }
414
+ /**
415
+ * Execute all modules in order
416
+ */
417
+ async function executeModules(modules, kimesh) {
418
+ await kimesh.callHook("modules:before", kimesh);
419
+ for (const moduleInput of modules) try {
420
+ await executeModule(moduleInput, kimesh);
421
+ } catch (error) {
422
+ const moduleName = getModuleName(moduleInput);
423
+ consola.error(`[Kimesh] Failed to execute module "${moduleName}":`, error);
424
+ }
425
+ await kimesh.callHook("modules:done", kimesh);
426
+ }
427
+
428
+ //#endregion
429
+ //#region src/core/plugin.ts
430
+ /**
431
+ * Define a Kimesh plugin (lightweight Vite plugin wrapper)
432
+ *
433
+ * @example
434
+ * ```ts
435
+ * export default defineKimeshPlugin({
436
+ * name: "@kimesh/icons",
437
+ * setup(kimesh) {
438
+ * return Icons({
439
+ * compiler: "vue3",
440
+ * autoInstall: true,
441
+ * });
442
+ * },
443
+ * });
444
+ * ```
445
+ */
446
+ function defineKimeshPlugin(definition) {
447
+ return {
448
+ _def: definition,
449
+ name: definition.name,
450
+ getPlugins(kimesh) {
451
+ const result = definition.setup(kimesh);
452
+ return Array.isArray(result) ? result : [result];
453
+ }
454
+ };
455
+ }
456
+
457
+ //#endregion
458
+ //#region src/kit/vite.ts
459
+ /**
460
+ * Add a Vite plugin to the build
461
+ *
462
+ * @example
463
+ * ```ts
464
+ * addVitePlugin(myPlugin());
465
+ * addVitePlugin(myPlugin(), { enforce: "pre" });
466
+ * ```
467
+ */
468
+ function addVitePlugin(plugin, options) {
469
+ _addVitePlugin(useKimesh(), plugin, options);
470
+ }
471
+ /**
472
+ * Internal: Add Vite plugin with explicit Kimesh context
473
+ */
474
+ function _addVitePlugin(kimesh, plugin, options) {
475
+ const plugins = Array.isArray(plugin) ? plugin : [plugin];
476
+ const registry = kimesh._registries.vitePlugins;
477
+ for (const p of plugins) {
478
+ if (!p) continue;
479
+ const entry = {
480
+ plugin: p,
481
+ enforce: options?.enforce,
482
+ order: options?.order,
483
+ meta: { name: p.name }
484
+ };
485
+ if (options?.prepend) registry.unshift(entry);
486
+ else registry.push(entry);
487
+ }
488
+ }
489
+ /**
490
+ * Add a build plugin (alias for addVitePlugin with default order)
491
+ */
492
+ function addBuildPlugin(plugin, options) {
493
+ addVitePlugin(plugin, options);
494
+ }
495
+
496
+ //#endregion
497
+ //#region src/kit/alias.ts
498
+ /**
499
+ * Add an alias
500
+ *
501
+ * @example
502
+ * ```ts
503
+ * addAlias("#my-module", "/path/to/module");
504
+ * addAlias("@/components", "./src/components");
505
+ * ```
506
+ */
507
+ function addAlias(find, replacement) {
508
+ _addAlias(useKimesh(), find, replacement);
509
+ }
510
+ /**
511
+ * Internal: Add alias with explicit Kimesh context
512
+ */
513
+ function _addAlias(kimesh, find, replacement) {
514
+ const alias = {
515
+ find,
516
+ replacement
517
+ };
518
+ kimesh._registries.aliases.push(alias);
519
+ }
520
+ /**
521
+ * Resolve an alias to its actual path
522
+ */
523
+ function resolveAlias(alias) {
524
+ return _resolveAlias(useKimesh(), alias);
525
+ }
526
+ /**
527
+ * Check if an alias matches a given find pattern
528
+ */
529
+ function matchesAlias(alias, find) {
530
+ if (typeof find === "string") return alias === find || alias.startsWith(find + "/");
531
+ return find.test(alias);
532
+ }
533
+ /**
534
+ * Internal: Resolve alias with explicit Kimesh context
535
+ */
536
+ function _resolveAlias(kimesh, alias) {
537
+ for (const entry of kimesh._registries.aliases) if (matchesAlias(alias, entry.find)) return alias.replace(entry.find, entry.replacement);
538
+ }
539
+
540
+ //#endregion
541
+ //#region src/kit/templates.ts
542
+ /**
543
+ * @kimesh/kit - Template Utilities
544
+ */
545
+ /**
546
+ * Add a template to be generated
547
+ *
548
+ * @example
549
+ * ```ts
550
+ * addTemplate({
551
+ * filename: "my-config.ts",
552
+ * getContents: ({ kimesh }) => `export default ${JSON.stringify(config)}`,
553
+ * });
554
+ * ```
555
+ */
556
+ function addTemplate(template) {
557
+ _addTemplate(useKimesh(), template);
558
+ }
559
+ /**
560
+ * Internal: Add template with explicit Kimesh context
561
+ */
562
+ function _addTemplate(kimesh, template) {
563
+ kimesh._registries.templates.push(template);
564
+ }
565
+ /**
566
+ * Add a type template (.d.ts) to be generated
567
+ *
568
+ * @example
569
+ * ```ts
570
+ * addTypeTemplate({
571
+ * filename: "components.d.ts",
572
+ * getContents: ({ kimesh }) => generateComponentTypes(kimesh),
573
+ * });
574
+ * ```
575
+ */
576
+ function addTypeTemplate(template) {
577
+ _addTypeTemplate(useKimesh(), template);
578
+ }
579
+ /**
580
+ * Internal: Add type template with explicit Kimesh context
581
+ */
582
+ function _addTypeTemplate(kimesh, template) {
583
+ kimesh._registries.typeTemplates.push(template);
584
+ }
585
+ /**
586
+ * Ensure build directory exists
587
+ */
588
+ function ensureBuildDir(kimesh) {
589
+ if (!existsSync(kimesh.buildDir)) mkdirSync(kimesh.buildDir, { recursive: true });
590
+ }
591
+ /**
592
+ * Generate and write all templates
593
+ */
594
+ async function writeTemplates(kimesh) {
595
+ ensureBuildDir(kimesh);
596
+ const results = [];
597
+ for (const template of kimesh._registries.templates) {
598
+ const resolved = await resolveTemplate(kimesh, template);
599
+ if (resolved) {
600
+ if (template.write !== false) writeTemplate(resolved);
601
+ results.push(resolved);
602
+ }
603
+ }
604
+ for (const template of kimesh._registries.typeTemplates) {
605
+ const resolved = await resolveTemplate(kimesh, template);
606
+ if (resolved) {
607
+ writeTemplate(resolved);
608
+ results.push(resolved);
609
+ }
610
+ }
611
+ return results;
612
+ }
613
+ /**
614
+ * Resolve a single template
615
+ */
616
+ async function resolveTemplate(kimesh, template) {
617
+ let contents;
618
+ if (template.getContents) contents = await template.getContents({
619
+ ...template.data,
620
+ kimesh
621
+ });
622
+ else if (template.src) contents = readFileSync(template.src, "utf-8");
623
+ else return null;
624
+ const dst = join(kimesh.buildDir, template.filename);
625
+ return {
626
+ filename: template.filename,
627
+ dst,
628
+ contents
629
+ };
630
+ }
631
+ /**
632
+ * Write a resolved template to disk
633
+ */
634
+ function writeTemplate(template) {
635
+ const dir = dirname(template.dst);
636
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
637
+ writeFileSync(template.dst, template.contents, "utf-8");
638
+ }
639
+ /**
640
+ * Update specific templates (for HMR)
641
+ */
642
+ async function updateTemplates(kimesh, options) {
643
+ const templates = options?.filter ? kimesh._registries.templates.filter(options.filter) : kimesh._registries.templates;
644
+ const results = [];
645
+ for (const template of templates) {
646
+ const resolved = await resolveTemplate(kimesh, template);
647
+ if (resolved && template.write !== false) {
648
+ writeTemplate(resolved);
649
+ results.push(resolved);
650
+ }
651
+ }
652
+ return results;
653
+ }
654
+
655
+ //#endregion
656
+ //#region src/kit/components.ts
657
+ /**
658
+ * Add a single component
659
+ *
660
+ * @example
661
+ * ```ts
662
+ * addComponent({
663
+ * name: "MyButton",
664
+ * filePath: "./components/MyButton.vue",
665
+ * });
666
+ * ```
667
+ */
668
+ function addComponent(component) {
669
+ _addComponent(useKimesh(), component);
670
+ }
671
+ /**
672
+ * Internal: Add component with explicit Kimesh context
673
+ */
674
+ function _addComponent(kimesh, component) {
675
+ kimesh._registries.components.push(component);
676
+ }
677
+ /**
678
+ * Add a components directory
679
+ *
680
+ * @example
681
+ * ```ts
682
+ * addComponentsDir({
683
+ * path: "./components/ui",
684
+ * prefix: "Ui",
685
+ * });
686
+ * ```
687
+ */
688
+ function addComponentsDir(dir, options) {
689
+ _addComponentsDir(useKimesh(), dir, options);
690
+ }
691
+ /**
692
+ * Internal: Add components directory with explicit Kimesh context
693
+ */
694
+ function _addComponentsDir(kimesh, dir, options) {
695
+ if (options?.prepend) kimesh._registries.componentsDirs.unshift(dir);
696
+ else kimesh._registries.componentsDirs.push(dir);
697
+ }
698
+ /**
699
+ * Add a component resolver
700
+ *
701
+ * @example
702
+ * ```ts
703
+ * addComponentResolver({
704
+ * type: "component",
705
+ * resolve: (name) => {
706
+ * if (name.startsWith("Ui")) {
707
+ * return { name, from: `./components/ui/${name}.vue` };
708
+ * }
709
+ * },
710
+ * });
711
+ * ```
712
+ */
713
+ function addComponentResolver(resolver) {
714
+ _addComponentResolver(useKimesh(), resolver);
715
+ }
716
+ /**
717
+ * Internal: Add component resolver with explicit Kimesh context
718
+ */
719
+ function _addComponentResolver(kimesh, resolver) {
720
+ kimesh._registries.componentResolvers.push(resolver);
721
+ }
722
+
723
+ //#endregion
724
+ //#region src/kit/imports.ts
725
+ /**
726
+ * Add imports (auto-imports)
727
+ *
728
+ * @example
729
+ * ```ts
730
+ * addImports({ name: "useAuth", from: "./composables/auth" });
731
+ * addImports([
732
+ * { name: "ref", from: "vue" },
733
+ * { name: "computed", from: "vue" },
734
+ * ]);
735
+ * ```
736
+ */
737
+ function addImports(imports) {
738
+ _addImports(useKimesh(), imports);
739
+ }
740
+ /**
741
+ * Internal: Add imports with explicit Kimesh context
742
+ */
743
+ function _addImports(kimesh, imports) {
744
+ const importsList = Array.isArray(imports) ? imports : [imports];
745
+ kimesh._registries.imports.push(...importsList);
746
+ }
747
+ /**
748
+ * Add an imports directory
749
+ *
750
+ * @example
751
+ * ```ts
752
+ * addImportsDir("./composables");
753
+ * addImportsDir({ path: "./utils", pattern: "use*.ts" });
754
+ * ```
755
+ */
756
+ function addImportsDir(dir, options) {
757
+ _addImportsDir(useKimesh(), dir, options);
758
+ }
759
+ /**
760
+ * Internal: Add imports directory with explicit Kimesh context
761
+ */
762
+ function _addImportsDir(kimesh, dir, options) {
763
+ const dirConfig = typeof dir === "string" ? { path: dir } : dir;
764
+ if (options?.prepend) kimesh._registries.importsDirs.unshift(dirConfig);
765
+ else kimesh._registries.importsDirs.push(dirConfig);
766
+ }
767
+ /**
768
+ * Add import presets
769
+ *
770
+ * @example
771
+ * ```ts
772
+ * addImportsPreset({ from: "vue", imports: ["ref", "computed", "watch"] });
773
+ * ```
774
+ */
775
+ function addImportsPreset(preset) {
776
+ _addImportsPreset(useKimesh(), preset);
777
+ }
778
+ /**
779
+ * Internal: Add import preset with explicit Kimesh context
780
+ */
781
+ function _addImportsPreset(kimesh, preset) {
782
+ kimesh._registries.importsPresets.push(preset);
783
+ }
784
+
785
+ //#endregion
786
+ //#region src/kit/resolver.ts
787
+ /**
788
+ * @kimesh/kit - Resolver Utilities
789
+ */
790
+ /**
791
+ * Create a resolver for the current module
792
+ *
793
+ * @example
794
+ * ```ts
795
+ * const resolver = createResolver(import.meta.url);
796
+ * const runtimePath = resolver.resolve("./runtime");
797
+ * ```
798
+ */
799
+ function createResolver(base) {
800
+ const baseDir = base.startsWith("file://") ? dirname(new URL(base).pathname) : dirname(base);
801
+ return {
802
+ resolve(...paths) {
803
+ return resolve(baseDir, ...paths);
804
+ },
805
+ async resolvePath(path) {
806
+ const resolved = resolve(baseDir, path);
807
+ if (!existsSync(resolved)) throw new Error(`Path not found: ${resolved}`);
808
+ return resolved;
809
+ },
810
+ resolveAlias(alias) {
811
+ const kimesh = tryUseKimesh();
812
+ if (!kimesh) return;
813
+ return _resolveAlias(kimesh, alias);
814
+ }
815
+ };
816
+ }
817
+ /**
818
+ * Resolve a path relative to project root
819
+ */
820
+ function resolvePathFromRoot(...paths) {
821
+ return resolve(useKimesh().root, ...paths);
822
+ }
823
+ /**
824
+ * Resolve a path relative to build directory
825
+ */
826
+ function resolvePathFromBuild(...paths) {
827
+ return resolve(useKimesh().buildDir, ...paths);
828
+ }
829
+
830
+ //#endregion
831
+ //#region src/kit/runtime-plugin.ts
832
+ /**
833
+ * @kimesh/kit - Runtime Plugin Kit Utilities
834
+ *
835
+ * Functions for registering runtime plugins during module setup.
836
+ */
837
+ /**
838
+ * Extract plugin name from a file path
839
+ */
840
+ function extractPluginName(path) {
841
+ const match = path.match(/([^/\\]+?)(?:\.[^.]+)?$/);
842
+ if (!match) return "anonymous";
843
+ const filename = match[1];
844
+ const orderMatch = filename.match(/^\d+\.(.+)$/);
845
+ return orderMatch ? orderMatch[1] : filename;
846
+ }
847
+ /**
848
+ * Normalize a plugin path or entry to a standard entry format
849
+ */
850
+ function normalizeRuntimePlugin(plugin) {
851
+ if (typeof plugin === "string") return {
852
+ src: plugin,
853
+ name: extractPluginName(plugin)
854
+ };
855
+ return plugin;
856
+ }
857
+ /**
858
+ * Add a runtime plugin to the Kimesh app
859
+ *
860
+ * @example
861
+ * ```ts
862
+ * addRuntimePlugin('~/plugins/analytics.ts')
863
+ * addRuntimePlugin({ src: '~/plugins/analytics.ts', meta: { enforce: 'post' } })
864
+ * ```
865
+ */
866
+ function addRuntimePlugin(plugin, options = {}) {
867
+ const kimesh = useKimesh();
868
+ const normalized = normalizeRuntimePlugin(plugin);
869
+ if (normalized.src) kimesh._registries.runtimePlugins = kimesh._registries.runtimePlugins.filter((p) => p.src !== normalized.src);
870
+ if (options.append) kimesh._registries.runtimePlugins.push(normalized);
871
+ else kimesh._registries.runtimePlugins.unshift(normalized);
872
+ }
873
+ /**
874
+ * Remove a runtime plugin by source path
875
+ */
876
+ function removeRuntimePlugin(src) {
877
+ const kimesh = useKimesh();
878
+ kimesh._registries.runtimePlugins = kimesh._registries.runtimePlugins.filter((p) => p.src !== src);
879
+ }
880
+ /**
881
+ * Check if a runtime plugin is registered
882
+ */
883
+ function hasRuntimePlugin(src) {
884
+ return useKimesh()._registries.runtimePlugins.some((p) => p.src === src);
885
+ }
886
+ /**
887
+ * Get all registered runtime plugins
888
+ */
889
+ function getRuntimePlugins() {
890
+ return [...useKimesh()._registries.runtimePlugins];
891
+ }
892
+
893
+ //#endregion
894
+ //#region src/kit/plugin-scanner.ts
895
+ /**
896
+ * @kimesh/kit - Plugin Scanner
897
+ *
898
+ * Scans the plugins directory for auto-discovered runtime plugins.
899
+ */
900
+ const DEFAULT_EXTENSIONS = [
901
+ ".ts",
902
+ ".js",
903
+ ".mjs"
904
+ ];
905
+ const DEFAULT_IGNORE = [
906
+ "**/node_modules/**",
907
+ "**/*.d.ts",
908
+ "**/*.test.ts",
909
+ "**/*.spec.ts"
910
+ ];
911
+ /**
912
+ * Parse filename to extract order prefix and plugin name
913
+ *
914
+ * Filename conventions:
915
+ * - `auth.ts` -> name: 'auth', order: undefined
916
+ * - `01.auth.ts` -> name: 'auth', order: 1
917
+ * - `10.analytics.ts` -> name: 'analytics', order: 10
918
+ */
919
+ function parsePluginFilename(filename) {
920
+ const withoutExt = basename(filename, extname(filename));
921
+ const orderMatch = withoutExt.match(/^(\d+)\.(.+)$/);
922
+ if (orderMatch) return {
923
+ name: orderMatch[2],
924
+ order: parseInt(orderMatch[1], 10)
925
+ };
926
+ return { name: withoutExt };
927
+ }
928
+ /**
929
+ * Build glob pattern for plugin file scanning
930
+ */
931
+ function buildPluginGlobPattern(extensions) {
932
+ const normalizedExts = extensions.map((e) => e.startsWith(".") ? e.slice(1) : e);
933
+ if (normalizedExts.length === 1) return `*.${normalizedExts[0]}`;
934
+ return `*.{${normalizedExts.join(",")}}`;
935
+ }
936
+ /**
937
+ * Scan plugins directory for auto-discovered plugins
938
+ *
939
+ * @example
940
+ * ```ts
941
+ * const plugins = await scanPluginsDir('/app/src/plugins')
942
+ * // Returns: [
943
+ * // { src: '/app/src/plugins/01.auth.ts', name: 'auth', order: 1 },
944
+ * // { src: '/app/src/plugins/02.analytics.ts', name: 'analytics', order: 2 },
945
+ * // { src: '/app/src/plugins/utils.ts', name: 'utils', order: undefined },
946
+ * // ]
947
+ * ```
948
+ */
949
+ async function scanPluginsDir(pluginsDir, options = {}) {
950
+ if (!existsSync(pluginsDir)) return [];
951
+ const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
952
+ const ignore$1 = options.ignore ?? DEFAULT_IGNORE;
953
+ return (await fg(buildPluginGlobPattern(extensions), {
954
+ cwd: pluginsDir,
955
+ onlyFiles: true,
956
+ ignore: ignore$1,
957
+ absolute: false
958
+ })).map((file) => {
959
+ const { name, order } = parsePluginFilename(file);
960
+ return {
961
+ src: join$1(pluginsDir, file),
962
+ name,
963
+ order
964
+ };
965
+ }).sort((a, b) => {
966
+ if (a.order === void 0 && b.order === void 0) return a.name.localeCompare(b.name);
967
+ if (a.order === void 0) return 1;
968
+ if (b.order === void 0) return -1;
969
+ return a.order - b.order;
970
+ });
971
+ }
972
+ /**
973
+ * Check if a directory has any plugin files
974
+ */
975
+ async function hasPlugins(pluginsDir, options = {}) {
976
+ return (await scanPluginsDir(pluginsDir, options)).length > 0;
977
+ }
978
+
979
+ //#endregion
980
+ //#region src/kit/plugin-template.ts
981
+ /**
982
+ * @kimesh/kit - Plugin Template Generator
983
+ *
984
+ * Generates the #build/plugins.mjs file that exports all runtime plugins.
985
+ */
986
+ /**
987
+ * Create a valid JavaScript variable name from plugin name
988
+ */
989
+ function toVariableName(name, index) {
990
+ return `plugin_${name.replace(/[^a-zA-Z0-9_]/g, "_").replace(/^(\d)/, "_$1").replace(/_+/g, "_")}_${index}`;
991
+ }
992
+ /**
993
+ * Generate the plugins.mjs template content
994
+ *
995
+ * @example Output:
996
+ * ```js
997
+ * // Auto-discovered plugins
998
+ * import plugin_auth_0 from '../src/plugins/01.auth.ts'
999
+ * import plugin_analytics_1 from '../src/plugins/02.analytics.ts'
1000
+ *
1001
+ * // Module-registered plugins
1002
+ * import plugin_icons_2 from '@kimesh/icons/runtime/plugin'
1003
+ *
1004
+ * export const plugins = [
1005
+ * plugin_auth_0,
1006
+ * plugin_analytics_1,
1007
+ * plugin_icons_2,
1008
+ * ]
1009
+ *
1010
+ * export default plugins
1011
+ * ```
1012
+ */
1013
+ function generatePluginsTemplate(options) {
1014
+ const { discoveredPlugins, registeredPlugins, buildDir } = options;
1015
+ const imports = [];
1016
+ const pluginVars = [];
1017
+ let index = 0;
1018
+ if (discoveredPlugins.length > 0) {
1019
+ imports.push("// Auto-discovered plugins");
1020
+ for (const plugin of discoveredPlugins) {
1021
+ const varName = toVariableName(plugin.name, index);
1022
+ const importPath = relative(buildDir, plugin.src).replace(/\.ts$/, "");
1023
+ imports.push(`import ${varName} from '${importPath}'`);
1024
+ pluginVars.push(varName);
1025
+ index++;
1026
+ }
1027
+ }
1028
+ const pluginsWithSrc = registeredPlugins.filter((p) => p.src);
1029
+ if (pluginsWithSrc.length > 0) {
1030
+ if (imports.length > 0) imports.push("");
1031
+ imports.push("// Module-registered plugins");
1032
+ for (const plugin of pluginsWithSrc) {
1033
+ const varName = toVariableName(plugin.name || "module", index);
1034
+ const importPath = plugin.src.startsWith("@") || plugin.src.startsWith(".") ? plugin.src : relative(buildDir, plugin.src).replace(/\.ts$/, "");
1035
+ imports.push(`import ${varName} from '${importPath}'`);
1036
+ pluginVars.push(varName);
1037
+ index++;
1038
+ }
1039
+ }
1040
+ if (pluginVars.length === 0) return `/**
1041
+ * Kimesh Runtime Plugins
1042
+ * Auto-generated by @kimesh/kit - Do not edit manually
1043
+ */
1044
+
1045
+ export const plugins = []
1046
+
1047
+ export default plugins
1048
+ `;
1049
+ const pluginsList = pluginVars.map((v) => ` ${v},`).join("\n");
1050
+ return `/**
1051
+ * Kimesh Runtime Plugins
1052
+ * Auto-generated by @kimesh/kit - Do not edit manually
1053
+ */
1054
+
1055
+ ${imports.join("\n")}
1056
+
1057
+ export const plugins = [
1058
+ ${pluginsList}
1059
+ ]
1060
+
1061
+ export default plugins
1062
+ `;
1063
+ }
1064
+ /**
1065
+ * Add plugins template to Kimesh registries
1066
+ */
1067
+ function addPluginsTemplate(kimesh, discoveredPlugins) {
1068
+ kimesh._registries.templates.push({
1069
+ filename: "plugins.mjs",
1070
+ getContents: ({ kimesh: km }) => {
1071
+ return generatePluginsTemplate({
1072
+ discoveredPlugins,
1073
+ registeredPlugins: km._registries.runtimePlugins,
1074
+ buildDir: km.buildDir
1075
+ });
1076
+ }
1077
+ });
1078
+ }
1079
+
1080
+ //#endregion
1081
+ //#region src/types/config.ts
1082
+ /**
1083
+ * Default aliases provided by Kimesh.
1084
+ * Templates use placeholders: <srcDir>, <rootDir>
1085
+ * These are replaced at build time with actual paths.
1086
+ */
1087
+ const DEFAULT_ALIASES = {
1088
+ "~": "<srcDir>",
1089
+ "@": "<srcDir>",
1090
+ "~~": "<rootDir>",
1091
+ "@@": "<rootDir>",
1092
+ "#build": "<rootDir>/.kimesh",
1093
+ "#app": "<rootDir>/.kimesh/app"
1094
+ };
1095
+ /**
1096
+ * Default file/folder ignore patterns
1097
+ */
1098
+ const DEFAULT_IGNORE_PATTERNS = [
1099
+ "**/*.stories.{js,cts,mts,ts,jsx,tsx}",
1100
+ "**/*.{spec,test}.{js,cts,mts,ts,jsx,tsx}",
1101
+ "**/*.d.{cts,mts,ts}",
1102
+ "**/.{git,cache,data,output}",
1103
+ "**/*.sock",
1104
+ ".kimesh",
1105
+ "**/node_modules",
1106
+ "**/-*.*"
1107
+ ];
1108
+ /**
1109
+ * Define Kimesh configuration with type inference.
1110
+ */
1111
+ function defineKmConfig(config) {
1112
+ return config;
1113
+ }
1114
+
1115
+ //#endregion
1116
+ //#region src/kit/alias-utils.ts
1117
+ /**
1118
+ * @kimesh/kit - Alias Resolution Utilities
1119
+ *
1120
+ * Utilities for resolving and processing path aliases.
1121
+ */
1122
+ /**
1123
+ * Resolve an alias path template to an actual path
1124
+ *
1125
+ * @param template - Alias path template (e.g., "/<srcDir>/components")
1126
+ * @param srcDir - Source directory path
1127
+ * @param rootDir - Root directory path
1128
+ * @returns Resolved absolute path
1129
+ */
1130
+ function resolveAliasPath(template, srcDir, rootDir) {
1131
+ return template.replace(/<srcDir>/g, srcDir).replace(/<rootDir>/g, rootDir);
1132
+ }
1133
+ /**
1134
+ * Build resolved aliases from config
1135
+ *
1136
+ * @param config - Kimesh configuration
1137
+ * @param srcDir - Source directory (default: rootDir/src)
1138
+ * @param rootDir - Root directory
1139
+ * @returns Resolved alias map
1140
+ */
1141
+ function buildAliases(config, srcDir, rootDir) {
1142
+ const aliases = {};
1143
+ for (const [alias, template] of Object.entries(DEFAULT_ALIASES)) aliases[alias] = resolveAliasPath(template, srcDir, rootDir);
1144
+ if (config.alias) for (const [alias, path] of Object.entries(config.alias)) aliases[alias] = isAbsolute(path) ? path : resolve(rootDir, path);
1145
+ return aliases;
1146
+ }
1147
+ /**
1148
+ * Convert aliases to Vite's resolve.alias format
1149
+ *
1150
+ * @param aliases - Alias map
1151
+ * @returns Array of Vite alias entries
1152
+ */
1153
+ function toViteAliases(aliases) {
1154
+ return Object.entries(aliases).map(([find, replacement]) => ({
1155
+ find,
1156
+ replacement
1157
+ }));
1158
+ }
1159
+ /**
1160
+ * Generate TypeScript path mappings from aliases
1161
+ *
1162
+ * @param aliases - Alias map
1163
+ * @param rootDir - Root directory for relative paths
1164
+ * @returns TypeScript compilerOptions.paths object
1165
+ */
1166
+ function toTsConfigPaths(aliases, rootDir) {
1167
+ const paths = {};
1168
+ for (const [alias, absolutePath] of Object.entries(aliases)) {
1169
+ const relativePath = absolutePath.startsWith(rootDir) ? "./" + absolutePath.slice(rootDir.length + 1) : absolutePath;
1170
+ paths[alias] = [relativePath];
1171
+ paths[`${alias}/*`] = [`${relativePath}/*`];
1172
+ }
1173
+ return paths;
1174
+ }
1175
+ /**
1176
+ * Normalize debug configuration to DebugConfig object
1177
+ *
1178
+ * @param debug - Debug config from KimeshConfig (boolean or DebugConfig)
1179
+ * @returns Normalized DebugConfig
1180
+ */
1181
+ function normalizeDebugConfig(debug$1) {
1182
+ if (!debug$1) return {};
1183
+ if (debug$1 === true) return {
1184
+ hooks: true,
1185
+ modules: true,
1186
+ layers: true,
1187
+ config: true,
1188
+ vite: true,
1189
+ routes: true,
1190
+ imports: true
1191
+ };
1192
+ return debug$1;
1193
+ }
1194
+ /**
1195
+ * Check if a specific debug option is enabled
1196
+ *
1197
+ * @param debug - Debug config
1198
+ * @param option - Debug option to check
1199
+ * @returns Whether the option is enabled
1200
+ */
1201
+ function isDebugEnabled(debug$1, option) {
1202
+ if (!debug$1) return false;
1203
+ if (debug$1 === true) return true;
1204
+ return !!debug$1[option];
1205
+ }
1206
+
1207
+ //#endregion
1208
+ //#region src/kit/ignore-utils.ts
1209
+ /**
1210
+ * @kimesh/kit - Ignore Patterns Utilities
1211
+ *
1212
+ * Utilities for handling file ignore patterns using node-ignore.
1213
+ */
1214
+ /**
1215
+ * Create an ignore instance with default and custom patterns
1216
+ *
1217
+ * @param config - Kimesh configuration
1218
+ * @returns Configured ignore instance
1219
+ */
1220
+ function createIgnoreFilter(config) {
1221
+ const ig = ignore(config.ignoreOptions);
1222
+ ig.add(DEFAULT_IGNORE_PATTERNS);
1223
+ if (config.ignore) ig.add(config.ignore);
1224
+ const prefix = config.ignorePrefix ?? "-";
1225
+ if (prefix) ig.add(`**/${prefix}*`);
1226
+ return ig;
1227
+ }
1228
+ /**
1229
+ * Check if a file should be ignored
1230
+ *
1231
+ * @param ig - Ignore instance
1232
+ * @param filePath - Relative file path to check
1233
+ * @returns Whether the file should be ignored
1234
+ */
1235
+ function shouldIgnore(ig, filePath) {
1236
+ const normalizedPath = filePath.replace(/\\/g, "/");
1237
+ return ig.ignores(normalizedPath);
1238
+ }
1239
+ /**
1240
+ * Filter an array of paths, removing ignored ones
1241
+ *
1242
+ * @param ig - Ignore instance
1243
+ * @param paths - Array of relative paths
1244
+ * @returns Array of non-ignored paths
1245
+ */
1246
+ function filterIgnored(ig, paths) {
1247
+ return paths.filter((p) => !shouldIgnore(ig, p));
1248
+ }
1249
+ /**
1250
+ * Create a simple matcher function for ignore patterns
1251
+ *
1252
+ * @param config - Kimesh configuration
1253
+ * @returns A function that returns true if a path should be ignored
1254
+ */
1255
+ function createIgnoreMatcher(config) {
1256
+ const ig = createIgnoreFilter(config);
1257
+ return (filePath) => shouldIgnore(ig, filePath);
1258
+ }
1259
+ /**
1260
+ * Get all active ignore patterns from config
1261
+ *
1262
+ * @param config - Kimesh configuration
1263
+ * @returns Array of all ignore patterns
1264
+ */
1265
+ function getIgnorePatterns(config) {
1266
+ const patterns = [...DEFAULT_IGNORE_PATTERNS];
1267
+ if (config.ignore) patterns.push(...config.ignore);
1268
+ const prefix = config.ignorePrefix ?? "-";
1269
+ if (prefix) patterns.push(`**/${prefix}*`);
1270
+ return patterns;
1271
+ }
1272
+
1273
+ //#endregion
1274
+ //#region src/kit/route-rules.ts
1275
+ /**
1276
+ * Match a route path against a pattern
1277
+ *
1278
+ * Supports:
1279
+ * - Exact matches: `/about`
1280
+ * - Wildcards: `/admin/**` (matches `/admin/users`, `/admin/users/123`)
1281
+ * - Single segment wildcards: `/users/*` (matches `/users/123` but not `/users/123/posts`)
1282
+ *
1283
+ * @param pattern - Route pattern (e.g., `/admin/**`)
1284
+ * @param routePath - Actual route path (e.g., `/admin/users`)
1285
+ * @returns Whether the pattern matches the path
1286
+ */
1287
+ function matchRoutePattern(pattern, routePath) {
1288
+ const normalizedPattern = pattern.replace(/\/+/g, "/").replace(/\/$/, "");
1289
+ const normalizedPath = routePath.replace(/\/+/g, "/").replace(/\/$/, "");
1290
+ let regexPattern = normalizedPattern.replace(/\/\*\*/g, "___DOUBLE_WILDCARD___").replace(/\*/g, "___SINGLE_WILDCARD___").replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/___DOUBLE_WILDCARD___/g, "(?:/.*)?").replace(/___SINGLE_WILDCARD___/g, "[^/]+");
1291
+ return (/* @__PURE__ */ new RegExp(`^${regexPattern}$`)).test(normalizedPath);
1292
+ }
1293
+ /**
1294
+ * Find matching route rules for a given path
1295
+ *
1296
+ * @param routeRules - Route rules configuration
1297
+ * @param routePath - Route path to match
1298
+ * @returns Array of matching rules in order of specificity (most specific first)
1299
+ */
1300
+ function findMatchingRules(routeRules, routePath) {
1301
+ const matches = [];
1302
+ for (const [pattern, rule] of Object.entries(routeRules)) if (matchRoutePattern(pattern, routePath)) {
1303
+ let specificity = 0;
1304
+ if (!pattern.includes("*")) specificity = 1e3;
1305
+ else if (pattern.includes("**")) specificity = pattern.split("/").length;
1306
+ else specificity = pattern.split("/").length * 10;
1307
+ matches.push({
1308
+ pattern,
1309
+ rule,
1310
+ specificity
1311
+ });
1312
+ }
1313
+ matches.sort((a, b) => b.specificity - a.specificity);
1314
+ return matches.map(({ pattern, rule }) => ({
1315
+ pattern,
1316
+ rule
1317
+ }));
1318
+ }
1319
+ /**
1320
+ * Merge multiple route rules into a single rule
1321
+ *
1322
+ * Later rules override earlier rules for same properties.
1323
+ *
1324
+ * @param rules - Array of route rules to merge
1325
+ * @returns Merged route rule
1326
+ */
1327
+ function mergeRouteRules(rules) {
1328
+ const merged = {};
1329
+ for (const rule of rules) {
1330
+ if (rule.redirect !== void 0) merged.redirect = rule.redirect;
1331
+ if (rule.prerender !== void 0) merged.prerender = rule.prerender;
1332
+ if (rule.cache !== void 0) if (typeof rule.cache === "boolean") merged.cache = rule.cache;
1333
+ else if (typeof merged.cache === "object" && typeof rule.cache === "object") merged.cache = {
1334
+ ...merged.cache,
1335
+ ...rule.cache
1336
+ };
1337
+ else merged.cache = rule.cache;
1338
+ if (rule.headers) merged.headers = {
1339
+ ...merged.headers,
1340
+ ...rule.headers
1341
+ };
1342
+ if (rule.cors !== void 0) if (typeof rule.cors === "boolean") merged.cors = rule.cors;
1343
+ else if (typeof merged.cors === "object" && typeof rule.cors === "object") merged.cors = {
1344
+ ...merged.cors,
1345
+ ...rule.cors
1346
+ };
1347
+ else merged.cors = rule.cors;
1348
+ if (rule.meta) merged.meta = {
1349
+ ...merged.meta,
1350
+ ...rule.meta
1351
+ };
1352
+ }
1353
+ return merged;
1354
+ }
1355
+ /**
1356
+ * Get the effective route rule for a path
1357
+ *
1358
+ * @param config - Kimesh configuration
1359
+ * @param routePath - Route path to get rule for
1360
+ * @returns Merged route rule or undefined if no rules match
1361
+ */
1362
+ function getRouteRule(config, routePath) {
1363
+ if (!config.routeRules) return;
1364
+ const matches = findMatchingRules(config.routeRules, routePath);
1365
+ if (matches.length === 0) return;
1366
+ return mergeRouteRules(matches.reverse().map((m) => m.rule));
1367
+ }
1368
+ /**
1369
+ * Check if a route should be redirected
1370
+ *
1371
+ * @param rule - Route rule
1372
+ * @returns Redirect information or undefined
1373
+ */
1374
+ function getRedirectInfo(rule) {
1375
+ if (!rule.redirect) return;
1376
+ if (typeof rule.redirect === "string") return {
1377
+ to: rule.redirect,
1378
+ statusCode: 302
1379
+ };
1380
+ return {
1381
+ to: rule.redirect.to,
1382
+ statusCode: rule.redirect.statusCode ?? 302
1383
+ };
1384
+ }
1385
+ /**
1386
+ * Generate route rules manifest for build output
1387
+ *
1388
+ * @param config - Kimesh configuration
1389
+ * @returns Route rules manifest object
1390
+ */
1391
+ function generateRouteRulesManifest(config) {
1392
+ return config.routeRules ?? {};
1393
+ }
1394
+
1395
+ //#endregion
1396
+ //#region src/kit/debug.ts
1397
+ /**
1398
+ * @kimesh/kit - Debug Utilities
1399
+ *
1400
+ * Utilities for debug mode logging and diagnostics.
1401
+ */
1402
+ let cachedDebugConfig = null;
1403
+ /**
1404
+ * Set the debug configuration
1405
+ *
1406
+ * @param config - Kimesh configuration
1407
+ */
1408
+ function setDebugConfig(config) {
1409
+ if (!config.debug) {
1410
+ cachedDebugConfig = null;
1411
+ return;
1412
+ }
1413
+ if (config.debug === true) cachedDebugConfig = {
1414
+ hooks: true,
1415
+ modules: true,
1416
+ layers: true,
1417
+ config: true,
1418
+ vite: true,
1419
+ routes: true,
1420
+ imports: true
1421
+ };
1422
+ else cachedDebugConfig = config.debug;
1423
+ }
1424
+ /**
1425
+ * Check if debug mode is enabled for a specific category
1426
+ *
1427
+ * @param category - Debug category to check
1428
+ * @returns Whether debug is enabled for this category
1429
+ */
1430
+ function isDebug(category) {
1431
+ if (!cachedDebugConfig) return false;
1432
+ if (!category) return true;
1433
+ return !!cachedDebugConfig[category];
1434
+ }
1435
+ /**
1436
+ * Debug logger that only logs when debug mode is enabled
1437
+ */
1438
+ const debug = {
1439
+ hook(hookName, ...args) {
1440
+ if (!isDebug("hooks")) return;
1441
+ consola.debug(pc.gray(`[hook] ${pc.cyan(hookName)}`), ...args);
1442
+ },
1443
+ module(moduleName, message, ...args) {
1444
+ if (!isDebug("modules")) return;
1445
+ consola.debug(pc.gray(`[module] ${pc.magenta(moduleName)}: ${message}`), ...args);
1446
+ },
1447
+ layer(layerName, message, ...args) {
1448
+ if (!isDebug("layers")) return;
1449
+ consola.debug(pc.gray(`[layer] ${pc.yellow(layerName)}: ${message}`), ...args);
1450
+ },
1451
+ config(message, ...args) {
1452
+ if (!isDebug("config")) return;
1453
+ consola.debug(pc.gray(`[config] ${message}`), ...args);
1454
+ },
1455
+ vite(message, ...args) {
1456
+ if (!isDebug("vite")) return;
1457
+ consola.debug(pc.gray(`[vite] ${message}`), ...args);
1458
+ },
1459
+ route(routePath, message, ...args) {
1460
+ if (!isDebug("routes")) return;
1461
+ consola.debug(pc.gray(`[route] ${pc.green(routePath)}: ${message}`), ...args);
1462
+ },
1463
+ import(name, message, ...args) {
1464
+ if (!isDebug("imports")) return;
1465
+ consola.debug(pc.gray(`[import] ${pc.blue(name)}: ${message}`), ...args);
1466
+ },
1467
+ timing(label, startTime) {
1468
+ if (!cachedDebugConfig) return;
1469
+ const duration = performance.now() - startTime;
1470
+ consola.debug(pc.gray(`[timing] ${label}: ${pc.bold(duration.toFixed(2))}ms`));
1471
+ },
1472
+ startTiming(label) {
1473
+ const start = performance.now();
1474
+ return () => debug.timing(label, start);
1475
+ }
1476
+ };
1477
+ /**
1478
+ * Create a scoped debug logger for a specific module
1479
+ *
1480
+ * @param scope - Module or component name
1481
+ * @returns Scoped debug logger
1482
+ */
1483
+ function createDebugLogger(scope) {
1484
+ return {
1485
+ log(message, ...args) {
1486
+ if (!cachedDebugConfig) return;
1487
+ consola.debug(pc.gray(`[${scope}] ${message}`), ...args);
1488
+ },
1489
+ info(message, ...args) {
1490
+ if (!cachedDebugConfig) return;
1491
+ consola.info(pc.gray(`[${scope}] ${message}`), ...args);
1492
+ },
1493
+ warn(message, ...args) {
1494
+ if (!cachedDebugConfig) return;
1495
+ consola.warn(`[${scope}] ${message}`, ...args);
1496
+ },
1497
+ error(message, ...args) {
1498
+ consola.error(`[${scope}] ${message}`, ...args);
1499
+ },
1500
+ timing: debug.startTiming
1501
+ };
1502
+ }
1503
+ /**
1504
+ * Log a debug table (formatted key-value pairs)
1505
+ *
1506
+ * @param title - Table title
1507
+ * @param data - Data to display
1508
+ */
1509
+ function debugTable(title, data) {
1510
+ if (!cachedDebugConfig) return;
1511
+ consola.debug(pc.bold(pc.cyan(`\n${title}:`)));
1512
+ const maxKeyLength = Math.max(...Object.keys(data).map((k) => k.length));
1513
+ for (const [key, value] of Object.entries(data)) {
1514
+ const paddedKey = key.padEnd(maxKeyLength);
1515
+ const formattedValue = typeof value === "object" ? JSON.stringify(value, null, 2) : String(value);
1516
+ consola.debug(pc.gray(` ${paddedKey} : ${formattedValue}`));
1517
+ }
1518
+ }
1519
+
1520
+ //#endregion
1521
+ //#region src/kit/tsconfig-generator.ts
1522
+ /**
1523
+ * @kimesh/kit - TypeScript Configuration Generator
1524
+ *
1525
+ * Auto-generates TypeScript configurations with alias path mappings.
1526
+ * Similar to Nuxt's .nuxt/tsconfig.json generation.
1527
+ */
1528
+ /**
1529
+ * Generate tsconfig.json content for .kimesh directory
1530
+ *
1531
+ * This generates a tsconfig that can be extended by the project's tsconfig.json,
1532
+ * providing automatic TypeScript support for all aliases.
1533
+ *
1534
+ * @param options - Generation options
1535
+ * @returns TSConfig JSON object
1536
+ */
1537
+ function generateTsConfig(options) {
1538
+ const { rootDir, srcDir, buildDir, aliases, layerAliases = {}, moduleAliases = {}, internalAliases = {}, include = ["../src/**/*", "./**/*"], exclude = ["../node_modules"] } = options;
1539
+ const allAliases = {
1540
+ ...aliases,
1541
+ ...layerAliases,
1542
+ ...moduleAliases,
1543
+ ...internalAliases
1544
+ };
1545
+ const paths = {};
1546
+ for (const [alias, absolutePath] of Object.entries(allAliases)) {
1547
+ const relativePath = relative(buildDir, absolutePath);
1548
+ const normalizedPath = relativePath.startsWith("..") ? relativePath : "./" + relativePath;
1549
+ paths[alias] = [normalizedPath];
1550
+ paths[`${alias}/*`] = [`${normalizedPath}/*`];
1551
+ }
1552
+ return {
1553
+ compilerOptions: {
1554
+ target: "ESNext",
1555
+ module: "ESNext",
1556
+ moduleResolution: "bundler",
1557
+ strict: true,
1558
+ jsx: "preserve",
1559
+ sourceMap: true,
1560
+ resolveJsonModule: true,
1561
+ esModuleInterop: true,
1562
+ lib: ["ESNext", "DOM"],
1563
+ skipLibCheck: true,
1564
+ noEmit: true,
1565
+ baseUrl: ".",
1566
+ paths
1567
+ },
1568
+ include,
1569
+ exclude
1570
+ };
1571
+ }
1572
+ /**
1573
+ * Write generated tsconfig.json to .kimesh directory
1574
+ *
1575
+ * @param options - Generation options
1576
+ */
1577
+ function writeTsConfig(options) {
1578
+ const { buildDir } = options;
1579
+ mkdirSync(buildDir, { recursive: true });
1580
+ const tsconfig = generateTsConfig(options);
1581
+ writeFileSync(join$1(buildDir, "tsconfig.json"), JSON.stringify(tsconfig, null, 2), "utf-8");
1582
+ }
1583
+
1584
+ //#endregion
1585
+ //#region src/kit/phase2-utils.ts
1586
+ /**
1587
+ * @kimesh/kit - Phase 2 Configuration Utilities
1588
+ *
1589
+ * Utility functions for Phase 2 configuration options:
1590
+ * - Directory resolution (2.1)
1591
+ * - Build config defaults (2.2)
1592
+ * - Dev server config merging (2.3)
1593
+ * - TypeScript config extension (2.4)
1594
+ * - Watch pattern handling (2.5)
1595
+ */
1596
+ /**
1597
+ * Default source directory
1598
+ */
1599
+ const DEFAULT_SRC_DIR = "src";
1600
+ /**
1601
+ * Default build directory
1602
+ */
1603
+ const DEFAULT_BUILD_DIR = ".kimesh";
1604
+ /**
1605
+ * Resolve all directory paths from configuration.
1606
+ *
1607
+ * @param config - Kimesh configuration
1608
+ * @param rootDir - Project root directory
1609
+ * @returns Resolved absolute paths for all directories
1610
+ *
1611
+ * @example
1612
+ * ```ts
1613
+ * const dirs = resolveDirectories(config, process.cwd())
1614
+ * console.log(dirs.srcDir) // '/path/to/project/src'
1615
+ * console.log(dirs.buildDir) // '/path/to/project/.kimesh'
1616
+ * ```
1617
+ */
1618
+ function resolveDirectories(config, rootDir) {
1619
+ const srcDirName = config.srcDir ?? DEFAULT_SRC_DIR;
1620
+ const srcDir = isAbsolute$1(srcDirName) ? srcDirName : resolve$1(rootDir, srcDirName);
1621
+ const buildDirName = config.buildDir ?? DEFAULT_BUILD_DIR;
1622
+ const buildDir = isAbsolute$1(buildDirName) ? buildDirName : resolve$1(rootDir, buildDirName);
1623
+ const dirConfig = {
1624
+ assets: config.dir?.assets ?? "assets",
1625
+ plugins: config.dir?.plugins ?? "plugins",
1626
+ public: config.dir?.public ?? "public",
1627
+ shared: config.dir?.shared ?? "shared"
1628
+ };
1629
+ return {
1630
+ rootDir,
1631
+ srcDir,
1632
+ buildDir,
1633
+ assetsDir: resolve$1(srcDir, dirConfig.assets),
1634
+ pluginsDir: resolve$1(srcDir, dirConfig.plugins),
1635
+ sharedDir: resolve$1(srcDir, dirConfig.shared),
1636
+ publicDir: resolve$1(rootDir, dirConfig.public)
1637
+ };
1638
+ }
1639
+ /**
1640
+ * Normalize analyze configuration to consistent object format.
1641
+ *
1642
+ * @param analyze - Build analyze config (boolean or object)
1643
+ * @returns Normalized analyze config object
1644
+ *
1645
+ * @example
1646
+ * ```ts
1647
+ * normalizeAnalyzeConfig(true) // { enabled: true, openAnalyzer: false, reportFilename: 'report.html' }
1648
+ * normalizeAnalyzeConfig(false) // { enabled: false, openAnalyzer: false, reportFilename: 'report.html' }
1649
+ * ```
1650
+ */
1651
+ function normalizeAnalyzeConfig(analyze) {
1652
+ if (typeof analyze === "boolean") return {
1653
+ enabled: analyze,
1654
+ openAnalyzer: false,
1655
+ reportFilename: "report.html"
1656
+ };
1657
+ return {
1658
+ enabled: analyze?.enabled ?? false,
1659
+ openAnalyzer: analyze?.openAnalyzer ?? false,
1660
+ reportFilename: analyze?.reportFilename ?? "report.html"
1661
+ };
1662
+ }
1663
+ /**
1664
+ * Resolve build configuration with defaults.
1665
+ *
1666
+ * @param config - Build configuration
1667
+ * @returns Resolved build config with all defaults applied
1668
+ *
1669
+ * @example
1670
+ * ```ts
1671
+ * const buildConfig = resolveBuildConfig({ analyze: true })
1672
+ * console.log(buildConfig.target) // 'esnext'
1673
+ * ```
1674
+ */
1675
+ function resolveBuildConfig(config) {
1676
+ return {
1677
+ analyze: normalizeAnalyzeConfig(config?.analyze),
1678
+ sourcemap: config?.sourcemap ?? false,
1679
+ target: config?.target ?? "esnext",
1680
+ minify: config?.minify ?? "esbuild"
1681
+ };
1682
+ }
1683
+ /**
1684
+ * Normalize HTTPS configuration.
1685
+ *
1686
+ * @param https - HTTPS config (boolean or object)
1687
+ * @returns Normalized HTTPS config
1688
+ */
1689
+ function normalizeHttpsConfig(https) {
1690
+ if (typeof https === "boolean") return { enabled: https };
1691
+ if (https) return {
1692
+ enabled: true,
1693
+ key: https.key,
1694
+ cert: https.cert
1695
+ };
1696
+ return { enabled: false };
1697
+ }
1698
+ /**
1699
+ * Normalize CORS configuration.
1700
+ *
1701
+ * @param cors - CORS config (boolean or object)
1702
+ * @returns Normalized CORS config
1703
+ */
1704
+ function normalizeCorsConfig(cors) {
1705
+ if (typeof cors === "boolean") return {
1706
+ enabled: cors,
1707
+ origin: cors ? "*" : void 0
1708
+ };
1709
+ if (cors) return {
1710
+ enabled: true,
1711
+ origin: cors.origin,
1712
+ methods: cors.methods,
1713
+ allowedHeaders: cors.allowedHeaders,
1714
+ exposedHeaders: cors.exposedHeaders,
1715
+ credentials: cors.credentials,
1716
+ maxAge: cors.maxAge
1717
+ };
1718
+ return { enabled: false };
1719
+ }
1720
+ /**
1721
+ * Resolve dev server configuration with defaults.
1722
+ *
1723
+ * @param config - Dev server configuration
1724
+ * @returns Resolved dev config with all defaults applied
1725
+ */
1726
+ function resolveDevConfig(config) {
1727
+ return {
1728
+ port: config?.port ?? 3e3,
1729
+ host: config?.host ?? "localhost",
1730
+ open: config?.open ?? false,
1731
+ https: normalizeHttpsConfig(config?.https),
1732
+ proxy: config?.proxy ?? {},
1733
+ cors: normalizeCorsConfig(config?.cors),
1734
+ strictPort: config?.strictPort ?? false
1735
+ };
1736
+ }
1737
+ /**
1738
+ * Resolve watch configuration with defaults.
1739
+ *
1740
+ * @param watch - Watch patterns array
1741
+ * @param watchers - Watchers configuration
1742
+ * @returns Resolved watch config
1743
+ */
1744
+ function resolveWatchConfig(watch, watchers) {
1745
+ return {
1746
+ patterns: watch ?? [],
1747
+ chokidar: watchers?.chokidar ?? {}
1748
+ };
1749
+ }
1750
+ /**
1751
+ * Merge chokidar options with defaults.
1752
+ *
1753
+ * @param options - User-provided chokidar options
1754
+ * @returns Merged chokidar options
1755
+ */
1756
+ function mergeChokidarOptions(options) {
1757
+ return defu(options ?? {}, {
1758
+ persistent: true,
1759
+ usePolling: false,
1760
+ interval: 100,
1761
+ binaryInterval: 300,
1762
+ atomic: false
1763
+ });
1764
+ }
1765
+ /**
1766
+ * Convert watch config to Vite watch options.
1767
+ *
1768
+ * @param config - Resolved watch configuration
1769
+ * @returns Vite-compatible watch options
1770
+ */
1771
+ function toViteWatchOptions(config) {
1772
+ const merged = mergeChokidarOptions(config.chokidar);
1773
+ return {
1774
+ usePolling: merged.usePolling,
1775
+ interval: merged.interval,
1776
+ binaryInterval: merged.binaryInterval,
1777
+ ignored: merged.ignored
1778
+ };
1779
+ }
1780
+
1781
+ //#endregion
1782
+ //#region src/vite/entry.ts
1783
+ /**
1784
+ * Generate the entry point code for a Kimesh app
1785
+ */
1786
+ function generateEntryCode(options) {
1787
+ const { hasContext, hasPlugins: hasPlugins$1 } = options;
1788
+ const imports = [
1789
+ `import { createKimeshApp } from '@kimesh/router-runtime'`,
1790
+ `import { routes } from '#kimesh/routes'`,
1791
+ `import App from '#kimesh/app'`
1792
+ ];
1793
+ if (hasContext) imports.push(`import createContext from '#kimesh/context'`);
1794
+ if (hasPlugins$1) imports.push(`import { plugins } from '#kimesh/plugins'`);
1795
+ const optionLines = [` runtimeConfig: __KIMESH_CONFIG__,`, ` layersConfig: __KIMESH_LAYERS_CONFIG__,`];
1796
+ if (hasContext) optionLines.push(` context: createContext(),`);
1797
+ if (hasPlugins$1) optionLines.push(` plugins,`);
1798
+ const optionsBlock = `\n${optionLines.join("\n")}`;
1799
+ return `${imports.join("\n")}
1800
+
1801
+ declare const __KIMESH_CONFIG__: Record<string, unknown>
1802
+ declare const __KIMESH_LAYERS_CONFIG__: Record<string, Record<string, unknown>>
1803
+
1804
+ async function bootstrap() {
1805
+ const app = await createKimeshApp({
1806
+ rootComponent: App,
1807
+ routes,${optionsBlock}
1808
+ })
1809
+
1810
+ app.mount('#app')
1811
+ }
1812
+
1813
+ bootstrap()
1814
+ `;
1815
+ }
1816
+ /**
1817
+ * Generate context type declaration file for host app
1818
+ */
1819
+ function generateContextTypes() {
1820
+ return `/* eslint-disable */
1821
+ /* prettier-ignore */
1822
+ // Auto-generated by @kimesh/kit
1823
+ // Do not edit this file manually
1824
+
1825
+ import type { AppContext } from '../src/app.context'
1826
+
1827
+ declare module '@kimesh/router-runtime' {
1828
+ interface KimeshContext extends AppContext {}
1829
+ }
1830
+
1831
+ export {}
1832
+ `;
1833
+ }
1834
+ /**
1835
+ * Generate context type declaration file for a layer
1836
+ * @param hostContextPath - Relative path from layer's .kimesh to host's app.context.ts
1837
+ */
1838
+ function generateLayerContextTypes(hostContextPath) {
1839
+ return `/* eslint-disable */
1840
+ /* prettier-ignore */
1841
+ // Auto-generated by @kimesh/kit
1842
+ // Do not edit this file manually
1843
+
1844
+ import type { AppContext } from '${hostContextPath}'
1845
+
1846
+ declare module '@kimesh/router-runtime' {
1847
+ interface KimeshContext extends AppContext {}
1848
+ }
1849
+
1850
+ export {}
1851
+ `;
1852
+ }
1853
+
1854
+ //#endregion
1855
+ //#region src/vite/html.ts
1856
+ /**
1857
+ * Generate the HTML template for a Kimesh app
1858
+ */
1859
+ function generateHtml(title) {
1860
+ return `<!DOCTYPE html>
1861
+ <html lang="en">
1862
+ <head>
1863
+ <meta charset="UTF-8">
1864
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1865
+ <title>${title}</title>
1866
+ </head>
1867
+ <body>
1868
+ <div id="app"></div>
1869
+ <script type="module" src="/.kimesh/entry.ts"><\/script>
1870
+ </body>
1871
+ </html>`;
1872
+ }
1873
+
1874
+ //#endregion
1875
+ //#region src/hmr/watcher.ts
1876
+ /**
1877
+ * Create HMR watcher for Kimesh layers
1878
+ */
1879
+ function createHMRWatcher(options) {
1880
+ const { server, layers, debug: debug$1 } = options;
1881
+ const log = (...args) => {
1882
+ if (debug$1) consola.debug("[kimesh:hmr]", ...args);
1883
+ };
1884
+ /**
1885
+ * Detect which layer a file belongs to
1886
+ */
1887
+ function detectLayer(filePath) {
1888
+ const sortedLayers = [...layers].sort((a, b) => b.path.length - a.path.length);
1889
+ for (const layer of sortedLayers) if (filePath.startsWith(layer.path)) return layer;
1890
+ }
1891
+ /**
1892
+ * Check if path contains a directory segment (cross-platform)
1893
+ */
1894
+ function pathContains(filePath, segment) {
1895
+ return filePath.includes(`/${segment}/`) || filePath.includes(`\\${segment}\\`);
1896
+ }
1897
+ /**
1898
+ * Detect file category based on path
1899
+ */
1900
+ function detectCategory(filePath) {
1901
+ if (pathContains(filePath, "routes")) return "route";
1902
+ if (pathContains(filePath, "components")) return "component";
1903
+ if (pathContains(filePath, "composables")) return "composable";
1904
+ if (filePath.includes("kimesh.config")) return "config";
1905
+ return "other";
1906
+ }
1907
+ /**
1908
+ * Handle file change
1909
+ */
1910
+ async function handleChange(file, type) {
1911
+ const startTime = performance.now();
1912
+ const layer = detectLayer(file);
1913
+ const category = detectCategory(file);
1914
+ const context = {
1915
+ file,
1916
+ type,
1917
+ layer,
1918
+ category
1919
+ };
1920
+ log(`File ${type}: ${file}`, layer ? `[${layer.name}]` : "[app]", `(${category})`);
1921
+ switch (category) {
1922
+ case "route":
1923
+ await handleRouteChange(context);
1924
+ break;
1925
+ case "component":
1926
+ await handleComponentChange(context);
1927
+ break;
1928
+ case "composable":
1929
+ await handleComposableChange(context);
1930
+ break;
1931
+ case "config":
1932
+ await handleConfigChange(context);
1933
+ break;
1934
+ default: break;
1935
+ }
1936
+ log(`HMR handled in ${(performance.now() - startTime).toFixed(1)}ms`);
1937
+ }
1938
+ /**
1939
+ * Handle route file change
1940
+ */
1941
+ async function handleRouteChange(context) {
1942
+ const routesModule = server.moduleGraph.getModuleById("\0virtual:kimesh-routes");
1943
+ if (routesModule) {
1944
+ server.moduleGraph.invalidateModule(routesModule);
1945
+ log("Invalidated virtual:kimesh-routes");
1946
+ }
1947
+ if (context.type === "add" || context.type === "unlink") {
1948
+ server.ws.send({
1949
+ type: "full-reload",
1950
+ path: "*"
1951
+ });
1952
+ log("Triggered full reload for route structure change");
1953
+ } else {
1954
+ const module = server.moduleGraph.getModuleById(context.file);
1955
+ if (module) {
1956
+ server.moduleGraph.invalidateModule(module);
1957
+ server.ws.send({
1958
+ type: "update",
1959
+ updates: [{
1960
+ type: "js-update",
1961
+ path: context.file,
1962
+ acceptedPath: context.file,
1963
+ timestamp: Date.now()
1964
+ }]
1965
+ });
1966
+ }
1967
+ }
1968
+ }
1969
+ /**
1970
+ * Handle component file change
1971
+ */
1972
+ async function handleComponentChange(context) {
1973
+ if (context.type === "add" || context.type === "unlink") {
1974
+ const autoImportModule = server.moduleGraph.getModuleById("\0virtual:kimesh-auto-imports");
1975
+ if (autoImportModule) {
1976
+ server.moduleGraph.invalidateModule(autoImportModule);
1977
+ log("Invalidated auto-import registry for component change");
1978
+ }
1979
+ }
1980
+ }
1981
+ /**
1982
+ * Handle composable file change
1983
+ */
1984
+ async function handleComposableChange(context) {
1985
+ const module = server.moduleGraph.getModuleById(context.file);
1986
+ if (module) {
1987
+ const importers = collectImporters(module);
1988
+ for (const importer of importers) server.moduleGraph.invalidateModule(importer);
1989
+ server.moduleGraph.invalidateModule(module);
1990
+ log(`Invalidated ${importers.size + 1} modules for composable change`);
1991
+ server.ws.send({
1992
+ type: "update",
1993
+ updates: Array.from(importers).map((m) => ({
1994
+ type: "js-update",
1995
+ path: m.file,
1996
+ acceptedPath: m.file,
1997
+ timestamp: Date.now()
1998
+ }))
1999
+ });
2000
+ }
2001
+ if (context.type === "add" || context.type === "unlink") {
2002
+ const autoImportModule = server.moduleGraph.getModuleById("\0virtual:kimesh-auto-imports");
2003
+ if (autoImportModule) server.moduleGraph.invalidateModule(autoImportModule);
2004
+ }
2005
+ }
2006
+ /**
2007
+ * Handle config file change
2008
+ */
2009
+ async function handleConfigChange(context) {
2010
+ consola.info(`[kimesh] Config changed${context.layer ? ` in ${context.layer.name}` : ""}, restart required`);
2011
+ server.ws.send({
2012
+ type: "full-reload",
2013
+ path: "*"
2014
+ });
2015
+ }
2016
+ /**
2017
+ * Collect all modules that import a given module (recursive)
2018
+ */
2019
+ function collectImporters(module, seen = /* @__PURE__ */ new Set()) {
2020
+ const importers = /* @__PURE__ */ new Set();
2021
+ for (const importer of module.importers) if (!seen.has(importer)) {
2022
+ seen.add(importer);
2023
+ importers.add(importer);
2024
+ const nestedImporters = collectImporters(importer, seen);
2025
+ for (const nested of nestedImporters) importers.add(nested);
2026
+ }
2027
+ return importers;
2028
+ }
2029
+ return {
2030
+ handleChange,
2031
+ detectLayer,
2032
+ detectCategory
2033
+ };
2034
+ }
2035
+
2036
+ //#endregion
2037
+ //#region src/errors/formatter.ts
2038
+ /**
2039
+ * @kimesh/kit - Error Formatter
2040
+ *
2041
+ * Enhanced error messages with layer context and suggestions.
2042
+ */
2043
+ /**
2044
+ * Format an error with layer context
2045
+ */
2046
+ function formatError(error, context) {
2047
+ const title = pc.red(pc.bold(`✖ ${error.name || "Error"}`));
2048
+ let message = error.message;
2049
+ let location;
2050
+ const suggestions = [];
2051
+ if (context?.file) {
2052
+ const layerInfo = context.layer ? pc.dim(` [${context.layer.name}]`) : "";
2053
+ if (context.line) location = pc.cyan(`${context.file}:${context.line}${context.column ? `:${context.column}` : ""}`) + layerInfo;
2054
+ else location = pc.cyan(context.file) + layerInfo;
2055
+ }
2056
+ if (error.message.includes("Cannot find module")) {
2057
+ suggestions.push("Check if the import path is correct");
2058
+ suggestions.push("Ensure the dependency is installed");
2059
+ if (context?.layer) suggestions.push(`Try using the layer alias: #${context.layer.name}/...`);
2060
+ }
2061
+ if (error.message.includes("is not defined")) {
2062
+ suggestions.push("Add the missing import or ensure auto-import is enabled");
2063
+ suggestions.push("Check if the export exists in the source file");
2064
+ }
2065
+ if (error.message.includes("Duplicate route")) {
2066
+ suggestions.push("Routes in the app take precedence over layer routes");
2067
+ suggestions.push("Use a different path or remove the conflicting route");
2068
+ }
2069
+ let formatted = `\n${title}\n`;
2070
+ if (location) formatted += `\n${pc.dim("Location:")} ${location}\n`;
2071
+ formatted += `\n${message}\n`;
2072
+ if (context?.snippet) formatted += `\n${pc.dim("Code:")}\n${context.snippet}\n`;
2073
+ if (suggestions.length > 0) {
2074
+ formatted += `\n${pc.yellow("Suggestions:")}\n`;
2075
+ for (const suggestion of suggestions) formatted += ` ${pc.dim("•")} ${suggestion}\n`;
2076
+ }
2077
+ return {
2078
+ title: error.name || "Error",
2079
+ message,
2080
+ location,
2081
+ suggestions: suggestions.length > 0 ? suggestions : void 0,
2082
+ formatted
2083
+ };
2084
+ }
2085
+ /**
2086
+ * Format a warning message
2087
+ */
2088
+ function formatWarning(message, context) {
2089
+ let output = pc.yellow(pc.bold("⚠ Warning"));
2090
+ if (context?.layer) output += pc.dim(` [${context.layer.name}]`);
2091
+ output += `\n${message}`;
2092
+ if (context?.file) output += pc.dim(`\n at ${context.file}`);
2093
+ return output;
2094
+ }
2095
+ /**
2096
+ * Get suggestions for resolving a conflict based on type
2097
+ */
2098
+ function getConflictSuggestions(type, name, winner) {
2099
+ if (type === "route") return ["Use different route paths", "Configure basePath in layer config"];
2100
+ return [`Use prefixed imports: ${name} → ${winner}${capitalize(name)}`, `Add prefix in layer config: components.prefix: '${capitalize(winner)}'`];
2101
+ }
2102
+ /**
2103
+ * Format a conflict warning
2104
+ */
2105
+ function formatConflictWarning(type, name, sources, winner) {
2106
+ let output = pc.yellow(pc.bold(`⚠ ${capitalize(type)} Conflict`));
2107
+ output += `\n\n${pc.bold(name)} is defined in multiple layers:\n`;
2108
+ for (const source of sources) {
2109
+ const isWinner = source.layer === winner;
2110
+ const marker = isWinner ? pc.green("✓") : pc.dim("○");
2111
+ const layerName = isWinner ? pc.green(source.layer) : pc.dim(source.layer);
2112
+ output += ` ${marker} ${layerName}\n`;
2113
+ output += pc.dim(` ${source.path}\n`);
2114
+ }
2115
+ output += `\n${pc.dim("Using:")} ${pc.green(winner)} (highest priority)\n`;
2116
+ output += `\n${pc.yellow("Suggestions:")}\n`;
2117
+ for (const suggestion of getConflictSuggestions(type, name, winner)) output += ` ${pc.dim("•")} ${suggestion}\n`;
2118
+ return output;
2119
+ }
2120
+ /**
2121
+ * Format timing info for debug
2122
+ */
2123
+ function formatTiming(operation, timeMs, details) {
2124
+ const color = timeMs < 50 ? pc.green : timeMs < 200 ? pc.yellow : pc.red;
2125
+ let output = `${pc.dim("[timing]")} ${operation}: ${color(`${timeMs.toFixed(1)}ms`)}`;
2126
+ if (details) {
2127
+ const detailStr = Object.entries(details).map(([k, v]) => `${k}=${v}`).join(", ");
2128
+ output += pc.dim(` (${detailStr})`);
2129
+ }
2130
+ return output;
2131
+ }
2132
+ /**
2133
+ * Create a timing logger
2134
+ */
2135
+ function createTimer(operation, debug$1 = false) {
2136
+ const start = performance.now();
2137
+ return { end(details) {
2138
+ const elapsed = performance.now() - start;
2139
+ if (debug$1) console.log(formatTiming(operation, elapsed, details));
2140
+ return elapsed;
2141
+ } };
2142
+ }
2143
+ function capitalize(str) {
2144
+ return str.charAt(0).toUpperCase() + str.slice(1);
2145
+ }
2146
+
2147
+ //#endregion
2148
+ //#region src/vite/plugin.ts
2149
+ /**
2150
+ * Find workspace root by traversing up and looking for workspaces config
2151
+ */
2152
+ function findWorkspaceRoot(startDir) {
2153
+ let current = startDir;
2154
+ for (let i = 0; i < 10; i++) {
2155
+ const pkgPath = join$1(current, "package.json");
2156
+ if (existsSync(pkgPath)) try {
2157
+ if (JSON.parse(readFileSync(pkgPath, "utf-8")).workspaces || existsSync(join$1(current, "pnpm-workspace.yaml"))) return current;
2158
+ } catch {}
2159
+ const parent = resolve$1(current, "..");
2160
+ if (parent === current) break;
2161
+ current = parent;
2162
+ }
2163
+ return startDir;
2164
+ }
2165
+ /**
2166
+ * Process all configured modules using the new v2 system
2167
+ */
2168
+ async function processModules(kimesh, debug$1) {
2169
+ const modules = kimesh.options.config.modules;
2170
+ if (!modules || modules.length === 0) return;
2171
+ const moduleTimer = createTimer("Module processing", debug$1);
2172
+ try {
2173
+ await executeModules(modules, kimesh);
2174
+ moduleTimer.end({ count: modules.length });
2175
+ } catch (error) {
2176
+ moduleTimer.end({ error: true });
2177
+ consola.error("[Kimesh] Module processing failed:", error);
2178
+ }
2179
+ }
2180
+ /**
2181
+ * Extract module names from config (filters out inline module objects)
2182
+ */
2183
+ function extractModuleNames$1(modules) {
2184
+ if (!modules) return [];
2185
+ const names = [];
2186
+ for (const mod of modules) if (typeof mod === "string") names.push(mod);
2187
+ else if (Array.isArray(mod) && typeof mod[0] === "string") names.push(mod[0]);
2188
+ return names;
2189
+ }
2190
+ /**
2191
+ * Generate modules.ts that imports all configured modules
2192
+ * AND references their augment.d.ts files for type declarations
2193
+ */
2194
+ function generateModulesTypeDeclaration(modules, buildDir) {
2195
+ const moduleNames = extractModuleNames$1(modules);
2196
+ if (moduleNames.length === 0) return;
2197
+ const imports = moduleNames.map((name) => `import "${name}";`).join("\n");
2198
+ const content = `/**
2199
+ * Module type declarations - Auto-generated by Kimesh
2200
+ * This file imports all modules to enable their type augmentations.
2201
+ *
2202
+ * DO NOT EDIT - This file is regenerated when modules change.
2203
+ */
2204
+
2205
+ ${moduleNames.map((name) => `/// <reference path="../node_modules/${name}/augment.d.ts" />`).join("\n")}
2206
+
2207
+ ${imports}
2208
+ `;
2209
+ mkdirSync(buildDir, { recursive: true });
2210
+ writeFileSync(join$1(buildDir, "modules.ts"), content, "utf-8");
2211
+ }
2212
+ /**
2213
+ * Kimesh Vite plugin
2214
+ * Sets up Vue with Vite 8 + Rolldown + File-based routing + Layers + Auto-Import
2215
+ */
2216
+ function kimeshPlugin(options = {}) {
2217
+ const config = options.config || {};
2218
+ const debug$1 = options.debug ?? false;
2219
+ const { plugins: userPlugins = [], ...userViteOptions } = config.vite || {};
2220
+ const allUserPlugins = [...userPlugins, ...options.additionalPlugins || []];
2221
+ const state = {
2222
+ resolvedLayers: [],
2223
+ root: "",
2224
+ generatedDir: "",
2225
+ kimesh: null,
2226
+ hasPlugins: false
2227
+ };
2228
+ const layersConfig = {
2229
+ enabled: options.layers?.enabled ?? config.layers?.enabled ?? "all",
2230
+ excluded: options.layers?.excluded ?? config.layers?.excluded ?? []
2231
+ };
2232
+ const mainPlugin = {
2233
+ name: "kimesh:main",
2234
+ enforce: "pre",
2235
+ async config(viteConfig, { command, mode }) {
2236
+ consola.debug(`[Kimesh] Configuring for ${command} mode`);
2237
+ const configRoot = viteConfig.root || process.cwd();
2238
+ state.root = configRoot;
2239
+ const resolvedDirs = resolveDirectories(config, configRoot);
2240
+ state.generatedDir = resolvedDirs.buildDir;
2241
+ const resolvedBuildConfig = resolveBuildConfig(config.build);
2242
+ const resolvedDevConfig = resolveDevConfig(config.dev);
2243
+ const resolvedWatchConfig = resolveWatchConfig(config.watch, config.watchers);
2244
+ if (debug$1) {
2245
+ consola.info(`[Kimesh] Resolved directories:`);
2246
+ consola.info(` - srcDir: ${resolvedDirs.srcDir}`);
2247
+ consola.info(` - buildDir: ${resolvedDirs.buildDir}`);
2248
+ consola.info(` - pluginsDir: ${resolvedDirs.pluginsDir}`);
2249
+ }
2250
+ const envVars = loadEnv(mode, configRoot, "KIMESH_");
2251
+ const layerTimer = createTimer("Layer resolution", debug$1);
2252
+ try {
2253
+ state.resolvedLayers = await prepareLayers$1(configRoot, {
2254
+ enabled: layersConfig.enabled,
2255
+ excluded: layersConfig.excluded
2256
+ });
2257
+ layerTimer.end({ count: state.resolvedLayers.length });
2258
+ if (debug$1 || state.resolvedLayers.length > 1) {
2259
+ consola.info(`[Kimesh] Resolved ${state.resolvedLayers.length} layers:`);
2260
+ for (const layer of state.resolvedLayers) consola.info(` - ${layer.name} (priority: ${layer.priority}, path: ${layer.path})`);
2261
+ }
2262
+ } catch (error) {
2263
+ layerTimer.end({ error: true });
2264
+ consola.warn(`[Kimesh] Layer resolution failed: ${error}`);
2265
+ state.resolvedLayers = [];
2266
+ }
2267
+ const layerAliases = generateLayerAliases$1(state.resolvedLayers);
2268
+ state.kimesh = createKimesh({
2269
+ config,
2270
+ layers: state.resolvedLayers,
2271
+ root: configRoot,
2272
+ buildDir: state.generatedDir,
2273
+ dev: command === "serve"
2274
+ });
2275
+ await processModules(state.kimesh, debug$1);
2276
+ if (config.app?.head) {
2277
+ const headPluginSrc = "@kimesh/head/plugin";
2278
+ if (!state.kimesh._registries.runtimePlugins.some((p) => p.src === headPluginSrc)) {
2279
+ state.kimesh._registries.runtimePlugins.unshift({
2280
+ src: headPluginSrc,
2281
+ name: "head"
2282
+ });
2283
+ if (debug$1) consola.info("[Kimesh] Auto-registered @kimesh/head plugin (app.head configured)");
2284
+ }
2285
+ }
2286
+ let discoveredPlugins = await scanPluginsDir(resolvedDirs.pluginsDir);
2287
+ for (const layer of state.resolvedLayers) {
2288
+ const layerPlugins = await scanPluginsDir(join$1(layer.path, "src", "plugins"));
2289
+ discoveredPlugins = discoveredPlugins.concat(layerPlugins);
2290
+ }
2291
+ const hasRegisteredPlugins = state.kimesh._registries.runtimePlugins.length > 0;
2292
+ state.hasPlugins = discoveredPlugins.length > 0 || hasRegisteredPlugins;
2293
+ if (state.hasPlugins) {
2294
+ addPluginsTemplate(state.kimesh, discoveredPlugins);
2295
+ if (debug$1) {
2296
+ consola.info(`[Kimesh] Found ${discoveredPlugins.length} auto-discovered plugins`);
2297
+ consola.info(`[Kimesh] Found ${state.kimesh._registries.runtimePlugins.length} module-registered plugins`);
2298
+ }
2299
+ }
2300
+ generateModulesTypeDeclaration(config.modules, state.generatedDir);
2301
+ await writeTemplates(state.kimesh);
2302
+ const userAliases = buildAliases(config, resolvedDirs.srcDir, configRoot);
2303
+ const moduleAliases = {};
2304
+ for (const alias of state.kimesh._registries.aliases) if (typeof alias.find === "string") moduleAliases[alias.find] = alias.replacement;
2305
+ const appVuePath = resolve$1(resolvedDirs.srcDir, "app.vue");
2306
+ const internalAliases = {
2307
+ "#kimesh/routes": join$1(resolvedDirs.buildDir, "routes.gen.ts"),
2308
+ "#kimesh/app": existsSync(appVuePath) ? appVuePath : "@kimesh/router-runtime/default-app",
2309
+ "#kimesh/context": join$1(resolvedDirs.srcDir, "app.context.ts"),
2310
+ "#kimesh/plugins": join$1(resolvedDirs.buildDir, "plugins.mjs")
2311
+ };
2312
+ writeTsConfig({
2313
+ rootDir: configRoot,
2314
+ srcDir: resolvedDirs.srcDir,
2315
+ buildDir: state.generatedDir,
2316
+ aliases: userAliases,
2317
+ layerAliases,
2318
+ moduleAliases,
2319
+ internalAliases,
2320
+ include: [
2321
+ "../src/**/*",
2322
+ "./**/*",
2323
+ "../kimesh.config.ts"
2324
+ ],
2325
+ exclude: ["../node_modules"]
2326
+ });
2327
+ if (debug$1) consola.info(`[Kimesh] Generated .kimesh/tsconfig.json with ${Object.keys(userAliases).length} aliases`);
2328
+ const layerDirs = state.resolvedLayers.map((layer) => layer.path);
2329
+ const workspaceRoot = findWorkspaceRoot(configRoot);
2330
+ const workspacePackages = resolve$1(workspaceRoot, "packages");
2331
+ const nodeModules = resolve$1(workspaceRoot, "node_modules");
2332
+ if (command === "build") {
2333
+ if (!existsSync(resolvedDirs.buildDir)) mkdirSync(resolvedDirs.buildDir, { recursive: true });
2334
+ writeFileSync(join$1(resolvedDirs.buildDir, "index.html"), generateHtml(config.name || "Kimesh App"), "utf-8");
2335
+ const hasContext = existsSync(join$1(resolvedDirs.srcDir, "app.context.ts"));
2336
+ writeFileSync(join$1(resolvedDirs.buildDir, "entry.ts"), generateEntryCode({
2337
+ hasContext,
2338
+ hasPlugins: state.hasPlugins
2339
+ }), "utf-8");
2340
+ if (hasContext) writeFileSync(join$1(resolvedDirs.buildDir, "context.d.ts"), generateContextTypes(), "utf-8");
2341
+ }
2342
+ const layerRuntimeConfigs = state.resolvedLayers.slice().sort((a, b) => b.priority - a.priority).map((layer) => layer.runtimeConfig).filter(Boolean);
2343
+ const processedRuntimeConfig = applyEnv(defu(config.runtimeConfig || createDefaultRuntimeConfig(), ...layerRuntimeConfigs), { env: envVars });
2344
+ const layerConfigMap = {};
2345
+ for (const layer of state.resolvedLayers) if (layer.runtimeConfig) layerConfigMap[layer.name] = layer.runtimeConfig;
2346
+ return mergeConfig({
2347
+ define: {
2348
+ __KIMESH_DEV__: command === "serve",
2349
+ __KIMESH_NAME__: JSON.stringify(config.name || "kimesh-app"),
2350
+ __KIMESH_LAYERS__: JSON.stringify(state.resolvedLayers.map((l) => l.name)),
2351
+ __KIMESH_CONFIG__: JSON.stringify(processedRuntimeConfig),
2352
+ __KIMESH_LAYERS_CONFIG__: JSON.stringify(layerConfigMap)
2353
+ },
2354
+ resolve: { alias: {
2355
+ "#kimesh/routes": join$1(resolvedDirs.buildDir, "routes.gen.ts"),
2356
+ "#kimesh/app": existsSync(appVuePath) ? appVuePath : "@kimesh/router-runtime/default-app",
2357
+ "#kimesh/context": join$1(resolvedDirs.srcDir, "app.context.ts"),
2358
+ "#kimesh/plugins": join$1(resolvedDirs.buildDir, "plugins.mjs"),
2359
+ ...userAliases,
2360
+ ...layerAliases,
2361
+ ...moduleAliases
2362
+ } },
2363
+ server: {
2364
+ port: resolvedDevConfig.port,
2365
+ host: resolvedDevConfig.host,
2366
+ open: resolvedDevConfig.open,
2367
+ strictPort: resolvedDevConfig.strictPort,
2368
+ fs: { allow: [
2369
+ configRoot,
2370
+ ...layerDirs,
2371
+ workspaceRoot,
2372
+ workspacePackages,
2373
+ nodeModules
2374
+ ] },
2375
+ watch: toViteWatchOptions(resolvedWatchConfig)
2376
+ },
2377
+ build: {
2378
+ target: resolvedBuildConfig.target,
2379
+ sourcemap: resolvedBuildConfig.sourcemap,
2380
+ minify: resolvedBuildConfig.minify,
2381
+ rollupOptions: command === "build" ? { input: join$1(resolvedDirs.buildDir, "index.html") } : void 0
2382
+ }
2383
+ }, userViteOptions);
2384
+ },
2385
+ configResolved(resolvedConfig) {
2386
+ state.root = resolvedConfig.root;
2387
+ state.generatedDir = resolveDirectories(config, state.root).buildDir;
2388
+ consola.debug(`[Kimesh] Config resolved, mode: ${resolvedConfig.mode}`);
2389
+ },
2390
+ async buildStart() {
2391
+ if (!existsSync(state.generatedDir)) mkdirSync(state.generatedDir, { recursive: true });
2392
+ const contextPath = join$1(state.root, "src", "app.context.ts");
2393
+ const hasContext = existsSync(contextPath);
2394
+ const entryPath = join$1(state.generatedDir, "entry.ts");
2395
+ writeFileSync(entryPath, generateEntryCode({
2396
+ hasContext,
2397
+ hasPlugins: state.hasPlugins
2398
+ }), "utf-8");
2399
+ consola.debug(`[Kimesh] Generated entry file: ${entryPath}`);
2400
+ if (hasContext) {
2401
+ const contextTypesPath = join$1(state.generatedDir, "context.d.ts");
2402
+ writeFileSync(contextTypesPath, generateContextTypes(), "utf-8");
2403
+ consola.debug(`[Kimesh] Generated context types: ${contextTypesPath}`);
2404
+ for (const layer of state.resolvedLayers) {
2405
+ if (layer.isApp) continue;
2406
+ let layerRoot = layer.path;
2407
+ try {
2408
+ layerRoot = realpathSync(layer.path);
2409
+ } catch {}
2410
+ const layerKimeshDir = join$1(layerRoot, ".kimesh");
2411
+ if (!existsSync(layerKimeshDir)) mkdirSync(layerKimeshDir, { recursive: true });
2412
+ const hostContextPath = relative(layerKimeshDir, contextPath).replace(/\.ts$/, "");
2413
+ const layerContextTypesPath = join$1(layerKimeshDir, "context.d.ts");
2414
+ writeFileSync(layerContextTypesPath, generateLayerContextTypes(hostContextPath), "utf-8");
2415
+ consola.debug(`[Kimesh] Generated layer context types: ${layerContextTypesPath}`);
2416
+ }
2417
+ }
2418
+ const htmlPath = join$1(state.generatedDir, "index.html");
2419
+ writeFileSync(htmlPath, generateHtml(config.name || "Kimesh App"), "utf-8");
2420
+ consola.debug(`[Kimesh] Generated HTML file: ${htmlPath}`);
2421
+ },
2422
+ configureServer(server) {
2423
+ const hmrWatcher = createHMRWatcher({
2424
+ server,
2425
+ layers: state.resolvedLayers,
2426
+ debug: debug$1
2427
+ });
2428
+ for (const layer of state.resolvedLayers) if (!layer.isApp) {
2429
+ server.watcher.add(layer.path);
2430
+ consola.debug(`[Kimesh] Watching layer: ${layer.name}`);
2431
+ }
2432
+ const handleWatchEvent = (event) => (file) => {
2433
+ const layer = hmrWatcher.detectLayer(file);
2434
+ if (layer && !layer.isApp) hmrWatcher.handleChange(file, event);
2435
+ };
2436
+ server.watcher.on("change", handleWatchEvent("change"));
2437
+ server.watcher.on("add", handleWatchEvent("add"));
2438
+ server.watcher.on("unlink", handleWatchEvent("unlink"));
2439
+ server.middlewares.use(async (req, res, next) => {
2440
+ const url = req.url || "/";
2441
+ if (url.includes(".") || url.startsWith("/@") || url.startsWith("/__") || url.startsWith("/node_modules")) return next();
2442
+ try {
2443
+ const html = readFileSync(join$1(state.generatedDir, "index.html"), "utf-8");
2444
+ const transformed = await server.transformIndexHtml(url, html);
2445
+ res.setHeader("Content-Type", "text/html");
2446
+ res.end(transformed);
2447
+ } catch (e) {
2448
+ next(e);
2449
+ }
2450
+ });
2451
+ }
2452
+ };
2453
+ const routerPlugin = kimeshRouterGenerator({
2454
+ routesDir: config.router?.routesDir ?? "routes",
2455
+ importMode: config.router?.importMode ?? "async",
2456
+ debug: debug$1,
2457
+ getLayerRoutes: () => {
2458
+ return state.resolvedLayers.filter((l) => !l.isApp).map((layer) => {
2459
+ const routesFolder = layer.config.routes?.folder || "routes";
2460
+ const routesDir = join$1(layer.path, "src", routesFolder);
2461
+ return {
2462
+ layerName: layer.name,
2463
+ routesDir,
2464
+ layerPath: layer.path,
2465
+ basePath: layer.config.routes?.basePath,
2466
+ priority: layer.priority
2467
+ };
2468
+ });
2469
+ }
2470
+ });
2471
+ const internalPlugins = [
2472
+ mainPlugin,
2473
+ kimeshAutoImport$1({
2474
+ getSources: () => {
2475
+ return state.resolvedLayers.map((layer) => ({
2476
+ layer: layer.name,
2477
+ priority: layer.priority,
2478
+ layerPath: layer.path,
2479
+ config: {
2480
+ composables: { dirs: layer.config.composables?.dirs || ["composables"] },
2481
+ components: {
2482
+ dirs: layer.config.components?.dirs || ["components"],
2483
+ prefix: layer.isApp ? void 0 : layer.config.components?.prefix
2484
+ },
2485
+ utils: { dirs: layer.config.utils?.dirs || ["utils"] },
2486
+ stores: { dirs: layer.config.stores?.dirs || ["stores"] },
2487
+ presets: layer.isApp ? config.autoImport?.presets || [
2488
+ "vue",
2489
+ "vue-router",
2490
+ "kimesh"
2491
+ ] : void 0
2492
+ }
2493
+ }));
2494
+ },
2495
+ getLayers: () => {
2496
+ return state.resolvedLayers.map((layer) => ({
2497
+ name: layer.name,
2498
+ path: layer.path,
2499
+ isApp: layer.isApp
2500
+ }));
2501
+ },
2502
+ dts: config.autoImport?.dts !== false ? state.generatedDir || ".kimesh" : false,
2503
+ debug: debug$1
2504
+ }),
2505
+ vue(),
2506
+ routerPlugin
2507
+ ];
2508
+ const modulePluginsWrapper = {
2509
+ name: "kimesh:module-plugins-wrapper",
2510
+ async resolveId(id, importer, options$1) {
2511
+ const modulePlugins = state.kimesh?._registries.vitePlugins ?? [];
2512
+ for (const entry of modulePlugins) {
2513
+ const plugin = entry.plugin;
2514
+ if (typeof plugin.resolveId === "function") {
2515
+ const result = await plugin.resolveId.call(this, id, importer, options$1);
2516
+ if (result != null) return result;
2517
+ }
2518
+ }
2519
+ return null;
2520
+ },
2521
+ async load(id, options$1) {
2522
+ const modulePlugins = state.kimesh?._registries.vitePlugins ?? [];
2523
+ for (const entry of modulePlugins) {
2524
+ const plugin = entry.plugin;
2525
+ if (typeof plugin.load === "function") {
2526
+ const result = await plugin.load.call(this, id, options$1);
2527
+ if (result != null) return result;
2528
+ }
2529
+ }
2530
+ return null;
2531
+ },
2532
+ async transform(code, id, options$1) {
2533
+ let currentCode = code;
2534
+ const modulePlugins = state.kimesh?._registries.vitePlugins ?? [];
2535
+ for (const entry of modulePlugins) {
2536
+ const plugin = entry.plugin;
2537
+ if (typeof plugin.transform === "function") {
2538
+ const result = await plugin.transform.call(this, currentCode, id, options$1);
2539
+ if (result != null) currentCode = typeof result === "string" ? result : result.code;
2540
+ }
2541
+ }
2542
+ return currentCode !== code ? currentCode : null;
2543
+ }
2544
+ };
2545
+ return [
2546
+ ...internalPlugins,
2547
+ modulePluginsWrapper,
2548
+ ...allUserPlugins
2549
+ ];
2550
+ }
2551
+
2552
+ //#endregion
2553
+ //#region src/config.ts
2554
+ /**
2555
+ * Load kimesh.config.ts using c12
2556
+ */
2557
+ async function loadConfig(options = {}) {
2558
+ const { config, configFile } = await loadConfig$1({
2559
+ name: "kimesh",
2560
+ cwd: options.root || process.cwd(),
2561
+ configFile: options.configFile,
2562
+ defaultConfig: {
2563
+ name: "kimesh-app",
2564
+ dev: {
2565
+ port: 3e3,
2566
+ host: "localhost"
2567
+ }
2568
+ }
2569
+ });
2570
+ if (configFile) consola.debug(`[Kimesh] Config loaded from: ${configFile}`);
2571
+ return config || {};
2572
+ }
2573
+
2574
+ //#endregion
2575
+ //#region src/prepare.ts
2576
+ /**
2577
+ * @kimesh/kit - Prepare Utilities
2578
+ *
2579
+ * Generates the .kimesh directory with TypeScript configurations,
2580
+ * type declarations, and other generated files needed for IDE support.
2581
+ *
2582
+ * Similar to `nuxt prepare` - run before IDE work for full type support.
2583
+ */
2584
+ /**
2585
+ * Prepare the .kimesh directory for TypeScript support
2586
+ *
2587
+ * This function generates all necessary files in the .kimesh directory
2588
+ * to enable TypeScript autocompletion and type checking before running
2589
+ * the dev server.
2590
+ *
2591
+ * @param options - Prepare options
2592
+ * @returns Result with generated file information
2593
+ *
2594
+ * @example
2595
+ * ```ts
2596
+ * import { prepare } from '@kimesh/kit'
2597
+ *
2598
+ * await prepare({ root: process.cwd() })
2599
+ * ```
2600
+ */
2601
+ async function prepare(options = {}) {
2602
+ const root = resolve$1(options.root || process.cwd());
2603
+ const buildDir = join$1(root, ".kimesh");
2604
+ const srcDir = join$1(root, "src");
2605
+ const verbose = options.verbose ?? false;
2606
+ const generatedFiles = [];
2607
+ if (verbose) consola.info(`[Kimesh] Preparing project at ${root}`);
2608
+ const config = await loadConfig({
2609
+ root,
2610
+ configFile: options.configFile
2611
+ });
2612
+ if (verbose) consola.info(`[Kimesh] Loaded config: ${config.name || "kimesh-app"}`);
2613
+ if (!existsSync(buildDir)) mkdirSync(buildDir, { recursive: true });
2614
+ let resolvedLayers = [];
2615
+ try {
2616
+ resolvedLayers = await prepareLayers$1(root, {
2617
+ enabled: config.layers?.enabled ?? "all",
2618
+ excluded: config.layers?.excluded ?? []
2619
+ });
2620
+ if (verbose) consola.info(`[Kimesh] Resolved ${resolvedLayers.length} layers`);
2621
+ } catch (error) {
2622
+ consola.warn(`[Kimesh] Layer resolution failed: ${error}`);
2623
+ }
2624
+ const layerAliases = generateLayerAliases$1(resolvedLayers);
2625
+ const userAliases = buildAliases(config, srcDir, root);
2626
+ const kimeshDir = resolve$1(root, ".kimesh");
2627
+ const appVuePath = resolve$1(root, "src/app.vue");
2628
+ const internalAliases = {
2629
+ "#kimesh/routes": join$1(kimeshDir, "routes.gen.ts"),
2630
+ "#kimesh/app": existsSync(appVuePath) ? appVuePath : "@kimesh/router-runtime/default-app",
2631
+ "#kimesh/context": join$1(root, "src", "app.context.ts"),
2632
+ "#kimesh/plugins": join$1(kimeshDir, "plugins.mjs")
2633
+ };
2634
+ writeTsConfig({
2635
+ rootDir: root,
2636
+ srcDir,
2637
+ buildDir,
2638
+ aliases: userAliases,
2639
+ layerAliases,
2640
+ moduleAliases: {},
2641
+ internalAliases,
2642
+ include: [
2643
+ "../src/**/*",
2644
+ "./**/*",
2645
+ "../kimesh.config.ts"
2646
+ ],
2647
+ exclude: ["../node_modules"]
2648
+ });
2649
+ generatedFiles.push("tsconfig.json");
2650
+ if (verbose) consola.success(`[Kimesh] Generated .kimesh/tsconfig.json`);
2651
+ const routesStubPath = join$1(buildDir, "routes.gen.ts");
2652
+ if (!existsSync(routesStubPath)) {
2653
+ writeFileSync(routesStubPath, `/**
2654
+ * Kimesh Routes - Auto-generated
2655
+ *
2656
+ * This file is a stub generated by 'km prepare'.
2657
+ * It will be populated with actual routes when running 'km dev' or 'km build'.
2658
+ *
2659
+ * DO NOT EDIT - This file is regenerated automatically.
2660
+ */
2661
+
2662
+ import type { RouteRecordRaw } from 'vue-router'
2663
+
2664
+ export const routes: RouteRecordRaw[] = []
2665
+ `, "utf-8");
2666
+ generatedFiles.push("routes.gen.ts");
2667
+ if (verbose) consola.success(`[Kimesh] Generated .kimesh/routes.gen.ts (stub)`);
2668
+ }
2669
+ const pluginsStubPath = join$1(buildDir, "plugins.mjs");
2670
+ if (!existsSync(pluginsStubPath)) {
2671
+ writeFileSync(pluginsStubPath, `/**
2672
+ * Kimesh Plugins - Auto-generated
2673
+ *
2674
+ * This file is a stub generated by 'km prepare'.
2675
+ * It will be populated with actual plugins when running 'km dev' or 'km build'.
2676
+ *
2677
+ * DO NOT EDIT - This file is regenerated automatically.
2678
+ */
2679
+
2680
+ export default []
2681
+ `, "utf-8");
2682
+ generatedFiles.push("plugins.mjs");
2683
+ if (verbose) consola.success(`[Kimesh] Generated .kimesh/plugins.mjs (stub)`);
2684
+ }
2685
+ const modulesPath = join$1(buildDir, "modules.ts");
2686
+ const moduleNames = extractModuleNames(config.modules);
2687
+ if (moduleNames.length > 0) {
2688
+ const imports = moduleNames.map((name) => `import "${name}";`).join("\n");
2689
+ writeFileSync(modulesPath, `/**
2690
+ * Module type declarations - Auto-generated by Kimesh
2691
+ *
2692
+ * DO NOT EDIT - This file is regenerated when modules change.
2693
+ */
2694
+
2695
+ ${moduleNames.map((name) => `/// <reference path="../node_modules/${name}/augment.d.ts" />`).join("\n")}
2696
+
2697
+ ${imports}
2698
+ `, "utf-8");
2699
+ generatedFiles.push("modules.ts");
2700
+ if (verbose) consola.success(`[Kimesh] Generated .kimesh/modules.ts`);
2701
+ }
2702
+ if (existsSync(join$1(root, "src", "app.context.ts"))) {
2703
+ writeFileSync(join$1(buildDir, "context.d.ts"), `/**
2704
+ * Kimesh Context Types - Auto-generated
2705
+ *
2706
+ * DO NOT EDIT - This file is regenerated automatically.
2707
+ */
2708
+
2709
+ import type { AppContext as UserAppContext } from '../src/app.context'
2710
+
2711
+ declare module '@kimesh/router-runtime' {
2712
+ interface AppContext extends UserAppContext {}
2713
+ }
2714
+ `, "utf-8");
2715
+ generatedFiles.push("context.d.ts");
2716
+ if (verbose) consola.success(`[Kimesh] Generated .kimesh/context.d.ts`);
2717
+ }
2718
+ const autoImportsPath = join$1(buildDir, "auto-imports.d.ts");
2719
+ if (!existsSync(autoImportsPath)) {
2720
+ writeFileSync(autoImportsPath, `/**
2721
+ * Kimesh Auto-Imports - Auto-generated
2722
+ *
2723
+ * This file is a stub generated by 'km prepare'.
2724
+ * It will be populated with actual imports when running 'km dev' or 'km build'.
2725
+ *
2726
+ * DO NOT EDIT - This file is regenerated automatically.
2727
+ */
2728
+
2729
+ export {}
2730
+
2731
+ declare global {
2732
+ // Vue imports will be auto-detected
2733
+ const ref: typeof import('vue')['ref']
2734
+ const reactive: typeof import('vue')['reactive']
2735
+ const computed: typeof import('vue')['computed']
2736
+ const watch: typeof import('vue')['watch']
2737
+ const watchEffect: typeof import('vue')['watchEffect']
2738
+ const onMounted: typeof import('vue')['onMounted']
2739
+ const onUnmounted: typeof import('vue')['onUnmounted']
2740
+ const defineProps: typeof import('vue')['defineProps']
2741
+ const defineEmits: typeof import('vue')['defineEmits']
2742
+ const withDefaults: typeof import('vue')['withDefaults']
2743
+
2744
+ // Vue Router imports
2745
+ const useRoute: typeof import('vue-router')['useRoute']
2746
+ const useRouter: typeof import('vue-router')['useRouter']
2747
+ }
2748
+ `, "utf-8");
2749
+ generatedFiles.push("auto-imports.d.ts");
2750
+ if (verbose) consola.success(`[Kimesh] Generated .kimesh/auto-imports.d.ts (stub)`);
2751
+ }
2752
+ const componentsPath = join$1(buildDir, "components.d.ts");
2753
+ if (!existsSync(componentsPath)) {
2754
+ writeFileSync(componentsPath, `/**
2755
+ * Kimesh Components - Auto-generated
2756
+ *
2757
+ * This file is a stub generated by 'km prepare'.
2758
+ * It will be populated with actual components when running 'km dev' or 'km build'.
2759
+ *
2760
+ * DO NOT EDIT - This file is regenerated automatically.
2761
+ */
2762
+
2763
+ export {}
2764
+
2765
+ declare module 'vue' {
2766
+ export interface GlobalComponents {
2767
+ // Component types will be populated by auto-import
2768
+ }
2769
+ }
2770
+ `, "utf-8");
2771
+ generatedFiles.push("components.d.ts");
2772
+ if (verbose) consola.success(`[Kimesh] Generated .kimesh/components.d.ts (stub)`);
2773
+ }
2774
+ const aliasCount = Object.keys(userAliases).length + Object.keys(layerAliases).length + Object.keys(internalAliases).length;
2775
+ return {
2776
+ buildDir,
2777
+ layerCount: resolvedLayers.length,
2778
+ aliasCount,
2779
+ generatedFiles
2780
+ };
2781
+ }
2782
+ /**
2783
+ * Extract module names from config (filters out inline module objects)
2784
+ */
2785
+ function extractModuleNames(modules) {
2786
+ if (!modules) return [];
2787
+ const names = [];
2788
+ for (const mod of modules) if (typeof mod === "string") names.push(mod);
2789
+ else if (Array.isArray(mod) && typeof mod[0] === "string") names.push(mod[0]);
2790
+ return names;
2791
+ }
2792
+
2793
+ //#endregion
2794
+ export { DEFAULT_ALIASES, DEFAULT_IGNORE_PATTERNS, addAlias, addBuildPlugin, addComponent, addComponentResolver, addComponentsDir, addImports, addImportsDir, addImportsPreset, addPluginsTemplate, addRuntimePlugin, addTemplate, addTypeTemplate, addVitePlugin, applyEnv, buildAliases, buildImportRegistry, createDebugLogger, createDefaultRuntimeConfig, createHMRWatcher, createIgnoreFilter, createIgnoreMatcher, createKimesh, createResolver, createTimer, debug, debugTable, defineKimeshModule, defineKimeshPlugin, defineKmConfig, envToKey, executeModule, executeModules, filterIgnored, findMatchingRules, formatConflictWarning, formatError, formatTiming, formatWarning, generateDts, generateLayerAliases, generatePluginsTemplate, generateRouteRulesManifest, getIgnorePatterns, getRedirectInfo, getRouteRule, getRuntimePlugins, hasPlugins, hasRuntimePlugin, isDebug, isDebugEnabled, keyToEnv, kimeshAutoImport, kimeshPlugin, loadConfig, matchRoutePattern, mergeLayerConfigs, mergeRouteRules, normalizeDebugConfig, normalizeModuleInput, prepare, prepareLayers, removeRuntimePlugin, resolveAlias, resolveAliasPath, resolveLayers, resolvePathFromBuild, resolvePathFromRoot, scanExports, scanPluginsDir, setDebugConfig, shouldIgnore, toTsConfigPaths, toViteAliases, tryUseKimesh, updateTemplates, useKimesh, writeTemplates };
2795
+ //# sourceMappingURL=index.mjs.map