olova 2.0.55 → 2.0.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +28 -288
  2. package/dist/chunk-23UAGQ6N.js +2208 -0
  3. package/dist/chunk-23UAGQ6N.js.map +1 -0
  4. package/dist/chunk-D7SIC5TC.js +367 -0
  5. package/dist/chunk-D7SIC5TC.js.map +1 -0
  6. package/dist/entry-server.cjs +2341 -0
  7. package/dist/entry-server.cjs.map +1 -0
  8. package/dist/entry-server.js +114 -0
  9. package/dist/entry-server.js.map +1 -0
  10. package/dist/entry-worker.cjs +2354 -0
  11. package/dist/entry-worker.cjs.map +1 -0
  12. package/dist/entry-worker.js +126 -0
  13. package/dist/entry-worker.js.map +1 -0
  14. package/dist/main.cjs +18 -0
  15. package/dist/main.cjs.map +1 -0
  16. package/dist/main.js +16 -0
  17. package/dist/main.js.map +1 -0
  18. package/dist/olova.cjs +1684 -0
  19. package/dist/olova.cjs.map +1 -0
  20. package/dist/olova.d.cts +72 -0
  21. package/dist/olova.d.ts +72 -0
  22. package/dist/olova.js +1325 -0
  23. package/dist/olova.js.map +1 -0
  24. package/dist/performance.cjs +386 -0
  25. package/dist/performance.cjs.map +1 -0
  26. package/dist/performance.js +3 -0
  27. package/dist/performance.js.map +1 -0
  28. package/dist/router.cjs +646 -0
  29. package/dist/router.cjs.map +1 -0
  30. package/dist/router.d.cts +113 -0
  31. package/dist/router.d.ts +113 -0
  32. package/dist/router.js +632 -0
  33. package/dist/router.js.map +1 -0
  34. package/main.tsx +76 -0
  35. package/olova.ts +619 -0
  36. package/package.json +42 -61
  37. package/src/entry-server.tsx +165 -0
  38. package/src/entry-worker.tsx +201 -0
  39. package/src/generator/index.ts +409 -0
  40. package/src/hydration/flight.ts +320 -0
  41. package/src/hydration/index.ts +12 -0
  42. package/src/hydration/types.ts +225 -0
  43. package/src/logger.ts +182 -0
  44. package/src/main.tsx +24 -0
  45. package/src/performance.ts +488 -0
  46. package/src/plugin/index.ts +204 -0
  47. package/src/router/ErrorBoundary.tsx +145 -0
  48. package/src/router/Link.tsx +117 -0
  49. package/src/router/OlovaRouter.tsx +354 -0
  50. package/src/router/Outlet.tsx +8 -0
  51. package/src/router/context.ts +117 -0
  52. package/src/router/index.ts +29 -0
  53. package/src/router/matching.ts +63 -0
  54. package/src/router/router.tsx +23 -0
  55. package/src/router/search-params.ts +29 -0
  56. package/src/scanner/index.ts +116 -0
  57. package/src/types/index.ts +191 -0
  58. package/src/utils/export.ts +85 -0
  59. package/src/utils/index.ts +4 -0
  60. package/src/utils/naming.ts +54 -0
  61. package/src/utils/path.ts +45 -0
  62. package/tsup.config.ts +35 -0
  63. package/CHANGELOG.md +0 -31
  64. package/LICENSE +0 -21
  65. package/dist/index.cjs +0 -883
  66. package/dist/index.cjs.map +0 -1
  67. package/dist/index.d.cts +0 -138
  68. package/dist/index.d.ts +0 -138
  69. package/dist/index.js +0 -832
  70. package/dist/index.js.map +0 -1
  71. package/dist/plugin.cjs +0 -927
  72. package/dist/plugin.cjs.map +0 -1
  73. package/dist/plugin.d.cts +0 -18
  74. package/dist/plugin.d.ts +0 -18
  75. package/dist/plugin.js +0 -894
  76. package/dist/plugin.js.map +0 -1
  77. package/dist/ssg.cjs +0 -637
  78. package/dist/ssg.cjs.map +0 -1
  79. package/dist/ssg.d.cts +0 -191
  80. package/dist/ssg.d.ts +0 -191
  81. package/dist/ssg.js +0 -585
  82. package/dist/ssg.js.map +0 -1
  83. package/dist/types-BT6YsBGO.d.cts +0 -143
  84. package/dist/types-BT6YsBGO.d.ts +0 -143
package/dist/olova.cjs ADDED
@@ -0,0 +1,1684 @@
1
+ 'use strict';
2
+
3
+ var fs3 = require('fs');
4
+ var fs4 = require('fs/promises');
5
+ var path5 = require('path');
6
+ var url = require('url');
7
+ var mdx = require('@mdx-js/rollup');
8
+ var vite = require('vite');
9
+ var pc = require('picocolors');
10
+ var util = require('util');
11
+ var zlib = require('zlib');
12
+
13
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
+
15
+ var fs3__default = /*#__PURE__*/_interopDefault(fs3);
16
+ var fs4__default = /*#__PURE__*/_interopDefault(fs4);
17
+ var path5__default = /*#__PURE__*/_interopDefault(path5);
18
+ var mdx__default = /*#__PURE__*/_interopDefault(mdx);
19
+ var pc__default = /*#__PURE__*/_interopDefault(pc);
20
+ var zlib__default = /*#__PURE__*/_interopDefault(zlib);
21
+
22
+ // ../node_modules/tsup/assets/cjs_shims.js
23
+ var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
24
+ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
25
+ function extractBalancedBraces(content, startIndex) {
26
+ if (content[startIndex] !== "{") return null;
27
+ let depth = 0;
28
+ for (let i = startIndex; i < content.length; i++) {
29
+ if (content[i] === "{") depth++;
30
+ else if (content[i] === "}") {
31
+ depth--;
32
+ if (depth === 0) return content.substring(startIndex, i + 1);
33
+ }
34
+ }
35
+ return null;
36
+ }
37
+ function extractMetadataSource(content) {
38
+ const match = content.match(/export\s+(?:const|let|var)\s+metadata\s*(?::\s*\w+\s*)?=\s*/);
39
+ if (!match || match.index === void 0) return void 0;
40
+ const afterEquals = match.index + match[0].length;
41
+ return extractBalancedBraces(content, afterEquals) || void 0;
42
+ }
43
+ function detectExportType(filePath) {
44
+ try {
45
+ const content = fs3__default.default.readFileSync(filePath, "utf-8");
46
+ const hasMetadata = /export\s+(?:const|let|var)\s+metadata\s*/.test(content) || /export\s*\{\s*metadata\s*\}/.test(content);
47
+ const hasRoute = /export\s+(?:const|let|var)\s+route\s*=/.test(content) || /export\s*\{\s*route\s*\}/.test(content);
48
+ const hasGetStaticPaths = /export\s+(?:async\s+)?function\s+getStaticPaths/.test(content) || /export\s+(?:const|let|var)\s+getStaticPaths\s*=/.test(content) || /export\s*\{[^}]*getStaticPaths[^}]*\}/.test(content);
49
+ const hasLoader = /export\s+(?:async\s+)?function\s+loader/.test(content) || /export\s+(?:const|let|var)\s+loader\s*=/.test(content) || /export\s*\{[^}]*loader[^}]*\}/.test(content);
50
+ const metadataSource = extractMetadataSource(content);
51
+ if (filePath.toLowerCase().endsWith(".mdx")) {
52
+ return {
53
+ hasDefault: true,
54
+ namedExport: null,
55
+ hasMetadata: !!metadataSource,
56
+ hasRoute: false,
57
+ hasGetStaticPaths: false,
58
+ hasLoader: false,
59
+ metadataSource
60
+ };
61
+ }
62
+ if (/export\s+default\s+/.test(content)) {
63
+ return { hasDefault: true, namedExport: null, hasMetadata, metadataSource, hasRoute, hasGetStaticPaths, hasLoader };
64
+ }
65
+ const namedMatch = content.match(/export\s+(?:const|function|class)\s+(\w+)/);
66
+ if (namedMatch) {
67
+ return { hasDefault: false, namedExport: namedMatch[1], hasMetadata, metadataSource, hasRoute, hasGetStaticPaths, hasLoader };
68
+ }
69
+ const exportMatch = content.match(/export\s*\{\s*(\w+)(?:\s+as\s+default)?\s*\}/);
70
+ if (exportMatch) {
71
+ if (content.includes("as default")) {
72
+ return { hasDefault: true, namedExport: null, hasMetadata, metadataSource, hasRoute, hasGetStaticPaths, hasLoader };
73
+ }
74
+ return { hasDefault: false, namedExport: exportMatch[1], hasMetadata, metadataSource, hasRoute, hasGetStaticPaths, hasLoader };
75
+ }
76
+ return { hasDefault: false, namedExport: null, hasMetadata, metadataSource, hasRoute, hasGetStaticPaths, hasLoader };
77
+ } catch {
78
+ return { hasDefault: true, namedExport: null, hasMetadata: false, hasRoute: false, hasGetStaticPaths: false, hasLoader: false };
79
+ }
80
+ }
81
+
82
+ // src/utils/naming.ts
83
+ function getRouteName(path6) {
84
+ if (path6 === "/" || path6 === "") return "Root";
85
+ const segments = path6.replace(/^\/|\/$/g, "").split(/[\\/]/);
86
+ const nameSegments = segments.map((segment) => {
87
+ let cleanSegment = segment;
88
+ if (cleanSegment.startsWith(":")) {
89
+ cleanSegment = cleanSegment.slice(1);
90
+ }
91
+ if (cleanSegment.startsWith("[") && cleanSegment.endsWith("]")) {
92
+ cleanSegment = cleanSegment.slice(1, -1);
93
+ if (cleanSegment.startsWith("...")) {
94
+ cleanSegment = cleanSegment.slice(3);
95
+ }
96
+ }
97
+ if (cleanSegment === "*") {
98
+ return "All";
99
+ }
100
+ if (cleanSegment.toLowerCase() === "index") {
101
+ return "";
102
+ }
103
+ if (cleanSegment.startsWith("(") && cleanSegment.endsWith(")")) {
104
+ cleanSegment = cleanSegment.slice(1, -1);
105
+ }
106
+ return capitalize(cleanSegment);
107
+ });
108
+ const finalName = nameSegments.join("");
109
+ if (/^\d/.test(finalName)) {
110
+ return "Page" + finalName;
111
+ }
112
+ return finalName;
113
+ }
114
+ function capitalize(str) {
115
+ return str.charAt(0).toUpperCase() + str.slice(1).replace(/[^a-zA-Z0-9]/g, "");
116
+ }
117
+
118
+ // src/utils/path.ts
119
+ function parseDynamicSegment(segment) {
120
+ if (segment.match(/^\[\.\.\.(.+)\]$/)) {
121
+ const paramName = segment.match(/^\[\.\.\.(.+)\]$/)?.[1] || "slug";
122
+ return { isDynamic: true, paramName, isCatchAll: true };
123
+ }
124
+ const bracketMatch = segment.match(/^\[(.+)\]$/);
125
+ if (bracketMatch) {
126
+ return { isDynamic: true, paramName: bracketMatch[1], isCatchAll: false };
127
+ }
128
+ return { isDynamic: false, paramName: null, isCatchAll: false };
129
+ }
130
+ function isRouteGroup(segment) {
131
+ return /^\(.+\)$/.test(segment);
132
+ }
133
+ function pathToRoute(relativePath, sep) {
134
+ const params = [];
135
+ let hasCatchAll = false;
136
+ const segments = relativePath.split(sep).filter(Boolean);
137
+ const routeSegments = segments.filter((segment) => !isRouteGroup(segment)).map((segment) => {
138
+ const { isDynamic, paramName, isCatchAll } = parseDynamicSegment(segment);
139
+ if (isDynamic && paramName) {
140
+ params.push(paramName);
141
+ if (isCatchAll) {
142
+ hasCatchAll = true;
143
+ return `*`;
144
+ }
145
+ return `:${paramName}`;
146
+ }
147
+ return segment;
148
+ });
149
+ const routePath = "/" + routeSegments.join("/");
150
+ return { routePath: routePath === "/" ? "/" : routePath, params, hasCatchAll };
151
+ }
152
+
153
+ // src/generator/index.ts
154
+ function stripImportExtension(filePath) {
155
+ return filePath.replace(/\.tsx?$/, "");
156
+ }
157
+ function pathToRouteId(routePath) {
158
+ if (routePath === "/") return "_root";
159
+ return routePath.replace(/^\//, "").replace(/\//g, "_").replace(/:/g, "$").replace(/\*/g, "$catchall");
160
+ }
161
+ function extractParamNames(routePath) {
162
+ const params = [];
163
+ for (const segment of routePath.split("/")) {
164
+ if (segment.startsWith(":")) params.push(segment.slice(1));
165
+ else if (segment === "*") params.push("*");
166
+ }
167
+ return params;
168
+ }
169
+ function generateParamType(routePath) {
170
+ const params = extractParamNames(routePath);
171
+ if (params.length === 0) return null;
172
+ const fields = params.map(
173
+ (p) => p === "*" ? "'*': string" : `${p}: string`
174
+ );
175
+ return `{ ${fields.join("; ")} }`;
176
+ }
177
+ function generateRouteTree(routes, notFoundPages, layouts, loadingPages, errorPages, middlewares, srcDir, packageName = "olovastart") {
178
+ const usedNames = /* @__PURE__ */ new Map();
179
+ const getUniqueName = (baseName) => {
180
+ const count = usedNames.get(baseName) || 0;
181
+ usedNames.set(baseName, count + 1);
182
+ return count === 0 ? baseName : `${baseName}${count}`;
183
+ };
184
+ const getRouteName2 = (filePath, suffix = "") => {
185
+ const relPath = path5__default.default.relative(srcDir, filePath);
186
+ const pathNoExt = relPath.replace(/\.(tsx?|mdx)$/, "");
187
+ if (pathNoExt === "" || pathNoExt === "." || pathNoExt === "index") {
188
+ return getUniqueName("Root" + suffix);
189
+ }
190
+ const name = getRouteName(pathNoExt);
191
+ if (!name) return getUniqueName("Root" + suffix);
192
+ if (suffix && name.toLowerCase().endsWith(suffix.toLowerCase())) {
193
+ return getUniqueName(name);
194
+ }
195
+ return getUniqueName(name + suffix);
196
+ };
197
+ const findClosestEntry = (routePath, entries) => {
198
+ let best = null;
199
+ for (const entry of entries) {
200
+ const ep = entry.path;
201
+ if (ep === "/" || routePath === ep || routePath.startsWith(ep + "/")) {
202
+ if (!best || ep.length > best.path.length) best = entry;
203
+ }
204
+ }
205
+ return best;
206
+ };
207
+ const routeNames = [];
208
+ const routeImports = routes.map((route) => {
209
+ const relativePath = stripImportExtension("./" + path5__default.default.relative(srcDir, route.component).replace(/\\/g, "/"));
210
+ const moduleName = getRouteName2(route.component, "RouteModule");
211
+ const lazyName = getRouteName2(route.component, "Route");
212
+ routeNames.push({ moduleName, lazyName, eager: true });
213
+ return `import * as ${moduleName} from '${relativePath}';`;
214
+ }).join("\n");
215
+ const notFoundNames = [];
216
+ const notFoundImports = notFoundPages.map((nf) => {
217
+ const relativePath = stripImportExtension("./" + path5__default.default.relative(srcDir, nf.filePath).replace(/\\/g, "/"));
218
+ if (nf.hasMetadata) {
219
+ const moduleName = getRouteName2(nf.filePath, "NotFoundModule");
220
+ notFoundNames.push(moduleName);
221
+ return `import * as ${moduleName} from '${relativePath}';`;
222
+ }
223
+ const importName = getRouteName2(nf.filePath, "NotFound");
224
+ notFoundNames.push(importName);
225
+ if (nf.hasDefault) return `import ${importName} from '${relativePath}';`;
226
+ if (nf.namedExport) return `import { ${nf.namedExport} as ${importName} } from '${relativePath}';`;
227
+ return `import ${importName} from '${relativePath}';`;
228
+ }).join("\n");
229
+ const layoutNames = [];
230
+ const layoutImports = layouts.map((layout) => {
231
+ const relativePath = stripImportExtension("./" + path5__default.default.relative(srcDir, layout.filePath).replace(/\\/g, "/"));
232
+ if (layout.hasMetadata) {
233
+ const moduleName = getRouteName2(layout.filePath, "LayoutModule");
234
+ layoutNames.push(moduleName);
235
+ return `import * as ${moduleName} from '${relativePath}';`;
236
+ }
237
+ const importName = getRouteName2(layout.filePath, "Layout");
238
+ layoutNames.push(importName);
239
+ if (layout.hasDefault) return `import ${importName} from '${relativePath}';`;
240
+ if (layout.namedExport) return `import { ${layout.namedExport} as ${importName} } from '${relativePath}';`;
241
+ return `import ${importName} from '${relativePath}';`;
242
+ }).join("\n");
243
+ const loadingNames = [];
244
+ const loadingImports = loadingPages.map((lp) => {
245
+ const relativePath = stripImportExtension("./" + path5__default.default.relative(srcDir, lp.filePath).replace(/\\/g, "/"));
246
+ const importName = getRouteName2(lp.filePath, "Loading");
247
+ loadingNames.push(importName);
248
+ if (lp.hasDefault) return `import ${importName} from '${relativePath}';`;
249
+ if (lp.namedExport) return `import { ${lp.namedExport} as ${importName} } from '${relativePath}';`;
250
+ return `import ${importName} from '${relativePath}';`;
251
+ }).join("\n");
252
+ const errorNames = [];
253
+ const errorImports = errorPages.map((ep) => {
254
+ const relativePath = stripImportExtension("./" + path5__default.default.relative(srcDir, ep.filePath).replace(/\\/g, "/"));
255
+ const importName = getRouteName2(ep.filePath, "Error");
256
+ errorNames.push(importName);
257
+ if (ep.hasDefault) return `import ${importName} from '${relativePath}';`;
258
+ if (ep.namedExport) return `import { ${ep.namedExport} as ${importName} } from '${relativePath}';`;
259
+ return `import ${importName} from '${relativePath}';`;
260
+ }).join("\n");
261
+ const middlewareNames = [];
262
+ const middlewareImports = middlewares.map((mw) => {
263
+ const relativePath = stripImportExtension("./" + path5__default.default.relative(srcDir, mw.filePath).replace(/\\/g, "/"));
264
+ const importName = getRouteName2(mw.filePath, "Middleware");
265
+ middlewareNames.push(importName);
266
+ if (mw.hasDefault) return `import ${importName} from '${relativePath}';`;
267
+ if (mw.namedExport) return `import { ${mw.namedExport} as ${importName} } from '${relativePath}';`;
268
+ return `import ${importName} from '${relativePath}';`;
269
+ }).join("\n");
270
+ const routeObjects = routes.map((route, index) => {
271
+ const { moduleName, lazyName, eager } = routeNames[index];
272
+ const component = eager ? `${moduleName}.default` : lazyName;
273
+ const routeId = pathToRouteId(route.path);
274
+ const fields = [
275
+ `id: '${routeId}'`,
276
+ `path: '${route.path}'`,
277
+ `component: ${component}`
278
+ ];
279
+ if (route.params && route.params.length > 0) {
280
+ fields.push(`params: [${route.params.map((p) => `'${p}'`).join(", ")}]`);
281
+ }
282
+ if (route.metadataSource) {
283
+ fields.push(`metadata: ${route.metadataSource}`);
284
+ } else if (route.hasMetadata) {
285
+ fields.push(`metadata: ${moduleName}.metadata`);
286
+ }
287
+ if (route.hasGetStaticPaths) {
288
+ fields.push(`getStaticPaths: ${moduleName}.getStaticPaths`);
289
+ }
290
+ if (route.hasLoader) {
291
+ fields.push(`loader: ${moduleName}.loader`);
292
+ }
293
+ const closestLoading = findClosestEntry(route.path, loadingPages);
294
+ if (closestLoading) {
295
+ const idx = loadingPages.indexOf(closestLoading);
296
+ fields.push(`loading: ${loadingNames[idx]}`);
297
+ }
298
+ const closestError = findClosestEntry(route.path, errorPages);
299
+ if (closestError) {
300
+ const idx = errorPages.indexOf(closestError);
301
+ fields.push(`error: ${errorNames[idx]}`);
302
+ }
303
+ return ` {
304
+ ${fields.join(",\n ")}
305
+ }`;
306
+ }).join(",\n");
307
+ const notFoundObjects = notFoundPages.map((nf, index) => {
308
+ const name = notFoundNames[index];
309
+ const isModule = nf.hasMetadata;
310
+ const component = isModule ? `${name}.default` : name;
311
+ const fields = [
312
+ `pathPrefix: '${nf.pathPrefix}'`,
313
+ `component: ${component}`
314
+ ];
315
+ if (isModule) fields.push(`metadata: ${name}.metadata`);
316
+ return ` {
317
+ ${fields.join(",\n ")}
318
+ }`;
319
+ }).join(",\n");
320
+ const layoutObjects = layouts.map((layout, index) => {
321
+ const name = layoutNames[index];
322
+ const isModule = layout.hasMetadata;
323
+ const component = isModule ? `${name}.default` : name;
324
+ const childRouteIds = routes.filter((r) => {
325
+ if (layout.path === "/") return true;
326
+ return r.path === layout.path || r.path.startsWith(layout.path + "/");
327
+ }).map((r) => `'${pathToRouteId(r.path)}'`);
328
+ const fields = [
329
+ `path: '${layout.path}'`,
330
+ `layout: ${component}`,
331
+ `children: [${childRouteIds.join(", ")}]`
332
+ ];
333
+ if (isModule) fields.push(`metadata: ${name}.metadata`);
334
+ return ` {
335
+ ${fields.join(",\n ")}
336
+ }`;
337
+ }).join(",\n");
338
+ const middlewareEntries = middlewares.map((mw, index) => {
339
+ return ` '${mw.path}': ${middlewareNames[index]}`;
340
+ }).join(",\n");
341
+ const routeParamTypes = routes.filter((r) => r.params && r.params.length > 0).map((r) => {
342
+ const paramType = generateParamType(r.path);
343
+ return paramType ? ` '${r.path}': ${paramType};` : null;
344
+ }).filter(Boolean).join("\n");
345
+ const routePaths = routes.length > 0 ? routes.map((r) => `'${r.path}'`).join(" | ") : "never";
346
+ const routeIds = routes.length > 0 ? routes.map((r) => `'${pathToRouteId(r.path)}'`).join(" | ") : "never";
347
+ const manifestEntries = routes.map((r) => {
348
+ const paramNames = extractParamNames(r.path);
349
+ const isDynamic = paramNames.length > 0;
350
+ const hasCatchAll = r.path.includes("*");
351
+ return ` '${pathToRouteId(r.path)}': { id: '${pathToRouteId(r.path)}', path: '${r.path}', params: [${paramNames.map((p) => `'${p}'`).join(", ")}], isDynamic: ${isDynamic}, hasCatchAll: ${hasCatchAll}, hasMetadata: ${r.hasMetadata}, hasGetStaticPaths: ${r.hasGetStaticPaths} }`;
352
+ }).join(",\n");
353
+ const allImports = [
354
+ routeImports,
355
+ notFoundImports,
356
+ layoutImports,
357
+ loadingImports,
358
+ errorImports,
359
+ middlewareImports
360
+ ].filter(Boolean).join("\n");
361
+ return `/* prettier-ignore-start */
362
+
363
+ /* eslint-disable */
364
+
365
+ // @ts-nocheck
366
+
367
+ // noinspection JSUnusedGlobalSymbols
368
+
369
+ /**
370
+ * This file was automatically generated by Olova Router.
371
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source route files
372
+ * and regenerate this file by running the dev server or build command.
373
+ *
374
+ * @generated Olova Route Tree
375
+ * @routes ${routes.length}
376
+ * @layouts ${layouts.length}
377
+ * @404s ${notFoundPages.length}
378
+ * @loading ${loadingPages.length}
379
+ * @errors ${errorPages.length}
380
+ * @middleware ${middlewares.length}
381
+ */
382
+
383
+ import { lazy } from 'react';
384
+ import {
385
+ createLink,
386
+ OlovaRouter,
387
+ Outlet,
388
+ redirect,
389
+ useIsNavigating,
390
+ useNavigationEvent,
391
+ useParams,
392
+ usePathname,
393
+ useRedirect,
394
+ useRouter,
395
+ useSearchParams,
396
+ useSelectedLayoutSegment,
397
+ useSelectedLayoutSegments,
398
+ } from '${packageName}/router';
399
+ ${allImports}
400
+
401
+ /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
402
+ * Route Definitions
403
+ * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
404
+
405
+ export const routes = [
406
+ ${routeObjects}
407
+ ];
408
+
409
+ export const notFoundPages = [
410
+ ${notFoundObjects}
411
+ ];
412
+
413
+ export const layouts = [
414
+ ${layoutObjects}
415
+ ];
416
+ ${middlewares.length > 0 ? `
417
+ export const middlewares = {
418
+ ${middlewareEntries}
419
+ };
420
+ ` : `
421
+ export const middlewares = {};
422
+ `}
423
+ /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
424
+ * Route Manifest (build-time introspection, sitemap generation, etc.)
425
+ * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
426
+
427
+ export const routeManifest = {
428
+ ${manifestEntries}
429
+ } as const;
430
+
431
+ /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
432
+ * Type-Safe Route Types
433
+ * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
434
+
435
+ export type RoutePaths = ${routePaths};
436
+
437
+ export type RouteIds = ${routeIds};
438
+
439
+ export interface RouteParams {
440
+ ${routeParamTypes || " // No dynamic routes"}
441
+ }
442
+
443
+ export type ParamsFor<P extends RoutePaths> = P extends keyof RouteParams ? RouteParams[P] : Record<string, never>;
444
+
445
+ /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
446
+ * Route Lookup Helpers
447
+ * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
448
+
449
+ const _routeById = new Map(routes.map(r => [r.id, r]));
450
+
451
+ export function getRouteById(id: RouteIds) {
452
+ return _routeById.get(id);
453
+ }
454
+
455
+ export function getRouteByPath(path: RoutePaths) {
456
+ return routes.find(r => r.path === path);
457
+ }
458
+
459
+ /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
460
+ * Exports
461
+ * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
462
+
463
+ export const Link = createLink<RoutePaths>();
464
+
465
+ export {
466
+ OlovaRouter,
467
+ Outlet,
468
+ redirect,
469
+ useIsNavigating,
470
+ useNavigationEvent,
471
+ useParams,
472
+ usePathname,
473
+ useRedirect,
474
+ useRouter,
475
+ useSearchParams,
476
+ useSelectedLayoutSegment,
477
+ useSelectedLayoutSegments,
478
+ };
479
+
480
+ export type {
481
+ NavigateOptions,
482
+ NotFoundPageConfig,
483
+ SearchParams,
484
+ SetSearchParamsOptions,
485
+ LayoutRoute,
486
+ Metadata,
487
+ } from '${packageName}/router';
488
+
489
+ /* prettier-ignore-end */
490
+ `;
491
+ }
492
+ var RESERVED_NAMES = /* @__PURE__ */ new Set([
493
+ "index",
494
+ "layout",
495
+ "loading",
496
+ "error",
497
+ "404",
498
+ "middleware",
499
+ "App",
500
+ "main",
501
+ "route.tree"
502
+ ]);
503
+ function scanDirectory(dir, rootDir, extensions, routes, notFoundPages, layouts, loadingPages, errorPages, middlewares, isRoot = false) {
504
+ if (!fs3__default.default.existsSync(dir)) return;
505
+ const entries = fs3__default.default.readdirSync(dir, { withFileTypes: true });
506
+ for (const entry of entries) {
507
+ const fullPath = path5__default.default.join(dir, entry.name);
508
+ if (entry.isDirectory()) {
509
+ if (entry.name === "node_modules" || entry.name === "assets" || entry.name.startsWith("_")) continue;
510
+ scanDirectory(fullPath, rootDir, extensions, routes, notFoundPages, layouts, loadingPages, errorPages, middlewares, false);
511
+ } else if (entry.isFile()) {
512
+ const ext = path5__default.default.extname(entry.name);
513
+ const baseName = path5__default.default.basename(entry.name, ext);
514
+ if (baseName === "layout" && extensions.includes(ext)) {
515
+ const relativePath = path5__default.default.relative(rootDir, dir);
516
+ const { routePath } = pathToRoute(relativePath, path5__default.default.sep);
517
+ layouts.push({
518
+ path: isRoot ? "/" : routePath,
519
+ filePath: fullPath
520
+ });
521
+ } else if (baseName === "loading" && extensions.includes(ext)) {
522
+ const relativePath = path5__default.default.relative(rootDir, dir);
523
+ const { routePath } = pathToRoute(relativePath, path5__default.default.sep);
524
+ loadingPages.push({
525
+ path: isRoot ? "/" : routePath,
526
+ filePath: fullPath
527
+ });
528
+ } else if (baseName === "error" && extensions.includes(ext)) {
529
+ const relativePath = path5__default.default.relative(rootDir, dir);
530
+ const { routePath } = pathToRoute(relativePath, path5__default.default.sep);
531
+ errorPages.push({
532
+ path: isRoot ? "/" : routePath,
533
+ filePath: fullPath
534
+ });
535
+ } else if (baseName === "middleware" && extensions.includes(ext)) {
536
+ const relativePath = path5__default.default.relative(rootDir, dir);
537
+ const { routePath } = pathToRoute(relativePath, path5__default.default.sep);
538
+ middlewares.push({
539
+ path: isRoot ? "/" : routePath,
540
+ filePath: fullPath
541
+ });
542
+ } else if (baseName === "404" && extensions.includes(ext)) {
543
+ const relativeParts = path5__default.default.relative(rootDir, dir).split(path5__default.default.sep).filter(Boolean);
544
+ const filteredParts = relativeParts.filter((p) => !isRouteGroup(p));
545
+ const pathPrefix = isRoot ? "" : "/" + filteredParts.join("/");
546
+ notFoundPages.push({ pathPrefix: pathPrefix || "", filePath: fullPath });
547
+ } else if (isRoot && baseName === "App" && extensions.includes(ext)) {
548
+ routes.push({ path: "/", filePath: fullPath, isDynamic: false, params: [] });
549
+ } else if (!isRoot && baseName === "index" && extensions.includes(ext)) {
550
+ const relativePath = path5__default.default.relative(rootDir, path5__default.default.dirname(fullPath));
551
+ const { routePath, params } = pathToRoute(relativePath, path5__default.default.sep);
552
+ routes.push({ path: routePath, filePath: fullPath, isDynamic: params.length > 0, params });
553
+ } else if (!RESERVED_NAMES.has(baseName) && !baseName.endsWith(".d") && !baseName.startsWith("_") && extensions.includes(ext)) {
554
+ const relativePath = path5__default.default.relative(rootDir, fullPath);
555
+ const relativePathNoExt = relativePath.substring(0, relativePath.length - ext.length);
556
+ const { routePath, params } = pathToRoute(relativePathNoExt, path5__default.default.sep);
557
+ routes.push({ path: routePath, filePath: fullPath, isDynamic: params.length > 0, params });
558
+ }
559
+ }
560
+ }
561
+ }
562
+ function scanRoutes(rootDir, extensions) {
563
+ const routes = [];
564
+ const notFoundPages = [];
565
+ const layouts = [];
566
+ const loadingPages = [];
567
+ const errorPages = [];
568
+ const middlewares = [];
569
+ const absoluteRoot = path5__default.default.isAbsolute(rootDir) ? rootDir : path5__default.default.resolve(rootDir);
570
+ if (!fs3__default.default.existsSync(absoluteRoot)) {
571
+ throw new Error(`Olova Router: Root directory does not exist: ${absoluteRoot}`);
572
+ }
573
+ scanDirectory(absoluteRoot, absoluteRoot, extensions, routes, notFoundPages, layouts, loadingPages, errorPages, middlewares, true);
574
+ routes.sort((a, b) => a.isDynamic !== b.isDynamic ? a.isDynamic ? 1 : -1 : a.path.localeCompare(b.path));
575
+ notFoundPages.sort((a, b) => b.pathPrefix.length - a.pathPrefix.length);
576
+ layouts.sort((a, b) => a.path.length - b.path.length);
577
+ loadingPages.sort((a, b) => b.path.length - a.path.length);
578
+ errorPages.sort((a, b) => b.path.length - a.path.length);
579
+ middlewares.sort((a, b) => a.path.length - b.path.length);
580
+ return { routes, notFoundPages, layouts, loadingPages, errorPages, middlewares };
581
+ }
582
+
583
+ // src/plugin/index.ts
584
+ function olovaRouter(options = {}) {
585
+ const rootDir = options.rootDir || "src";
586
+ const extensions = options.extensions || [".tsx", ".ts", ".mdx"];
587
+ const packageName = options.packageName || "olovastart";
588
+ let config;
589
+ let absoluteRootDir;
590
+ let watcher = null;
591
+ let timer = null;
592
+ function generateRouteTreeFile() {
593
+ const { routes, notFoundPages, layouts, loadingPages, errorPages, middlewares } = scanRoutes(absoluteRootDir, extensions);
594
+ const routeConfigs = routes.map((r) => {
595
+ let exportInfo = detectExportType(r.filePath);
596
+ if (r.filePath.toLowerCase().endsWith(".mdx")) {
597
+ exportInfo = {
598
+ ...exportInfo,
599
+ hasDefault: true,
600
+ namedExport: null
601
+ };
602
+ }
603
+ return {
604
+ path: r.path,
605
+ component: r.filePath.replace(/\\/g, "/"),
606
+ params: r.params.length > 0 ? r.params : void 0,
607
+ hasDefault: exportInfo.hasDefault,
608
+ namedExport: exportInfo.namedExport,
609
+ hasMetadata: exportInfo.hasMetadata,
610
+ metadataSource: exportInfo.metadataSource,
611
+ hasRoute: exportInfo.hasRoute,
612
+ hasGetStaticPaths: exportInfo.hasGetStaticPaths,
613
+ hasLoader: exportInfo.hasLoader
614
+ };
615
+ });
616
+ const notFoundConfigs = notFoundPages.map((nf) => {
617
+ const exportInfo = detectExportType(nf.filePath);
618
+ return {
619
+ pathPrefix: nf.pathPrefix,
620
+ filePath: nf.filePath.replace(/\\/g, "/"),
621
+ hasDefault: exportInfo.hasDefault,
622
+ namedExport: exportInfo.namedExport,
623
+ hasMetadata: exportInfo.hasMetadata
624
+ };
625
+ });
626
+ const layoutConfigs = layouts.map((l) => {
627
+ const exportInfo = detectExportType(l.filePath);
628
+ return {
629
+ path: l.path,
630
+ filePath: l.filePath.replace(/\\/g, "/"),
631
+ hasDefault: exportInfo.hasDefault,
632
+ namedExport: exportInfo.namedExport,
633
+ hasMetadata: exportInfo.hasMetadata
634
+ };
635
+ });
636
+ const loadingConfigs = loadingPages.map((lp) => {
637
+ const exportInfo = detectExportType(lp.filePath);
638
+ return {
639
+ path: lp.path,
640
+ filePath: lp.filePath.replace(/\\/g, "/"),
641
+ hasDefault: exportInfo.hasDefault,
642
+ namedExport: exportInfo.namedExport
643
+ };
644
+ });
645
+ const errorConfigs = errorPages.map((ep) => {
646
+ const exportInfo = detectExportType(ep.filePath);
647
+ return {
648
+ path: ep.path,
649
+ filePath: ep.filePath.replace(/\\/g, "/"),
650
+ hasDefault: exportInfo.hasDefault,
651
+ namedExport: exportInfo.namedExport
652
+ };
653
+ });
654
+ const middlewareConfigs = middlewares.map((mw) => {
655
+ const exportInfo = detectExportType(mw.filePath);
656
+ return {
657
+ path: mw.path,
658
+ filePath: mw.filePath.replace(/\\/g, "/"),
659
+ hasDefault: exportInfo.hasDefault,
660
+ namedExport: exportInfo.namedExport
661
+ };
662
+ });
663
+ const content = generateRouteTree(routeConfigs, notFoundConfigs, layoutConfigs, loadingConfigs, errorConfigs, middlewareConfigs, absoluteRootDir, packageName);
664
+ const treePath = path5__default.default.resolve(absoluteRootDir, "route.tree.ts");
665
+ const existing = fs3__default.default.existsSync(treePath) ? fs3__default.default.readFileSync(treePath, "utf-8") : "";
666
+ if (existing !== content) {
667
+ fs3__default.default.writeFileSync(treePath, content);
668
+ console.log("\x1B[32m[olova]\x1B[0m Route tree updated");
669
+ }
670
+ }
671
+ function startWatcher() {
672
+ if (watcher) return;
673
+ watcher = fs3__default.default.watch(absoluteRootDir, { recursive: true }, (eventType, filename) => {
674
+ if (!filename) return;
675
+ if (filename.includes("route.tree.ts")) return;
676
+ const ext = path5__default.default.extname(filename);
677
+ const isConfiguredExtension = extensions.includes(ext);
678
+ const isIndexFile = filename.includes("index") && isConfiguredExtension;
679
+ const isAppFile = filename.includes("App") && isConfiguredExtension;
680
+ const is404File = filename.includes("404") && isConfiguredExtension;
681
+ const isLayoutFile = filename.includes("layout") && isConfiguredExtension;
682
+ const isLoadingFile = filename.includes("loading") && isConfiguredExtension;
683
+ const isErrorFile = filename.includes("error") && isConfiguredExtension;
684
+ const isMiddlewareFile = filename.includes("middleware") && isConfiguredExtension;
685
+ const isDirectory = !filename.includes(".");
686
+ const isDynamicSegment = filename.includes("[");
687
+ const isRenameEvent = eventType === "rename";
688
+ if (isIndexFile || isAppFile || is404File || isLayoutFile || isLoadingFile || isErrorFile || isMiddlewareFile || isDirectory || isDynamicSegment || isRenameEvent) {
689
+ if (isIndexFile && filename) {
690
+ const fullPath = path5__default.default.join(absoluteRootDir, filename);
691
+ if (fs3__default.default.existsSync(fullPath)) {
692
+ const stat = fs3__default.default.statSync(fullPath);
693
+ if (stat.size === 0 && !filename.endsWith(".mdx")) {
694
+ const relativeDir = path5__default.default.relative(absoluteRootDir, path5__default.default.dirname(fullPath));
695
+ const pascalCaseName = getRouteName(relativeDir);
696
+ const boilerplate = `
697
+ export const metadata = {
698
+ title: "${pascalCaseName}",
699
+ description: "${pascalCaseName} page",
700
+ }
701
+
702
+ export default function ${pascalCaseName}() {
703
+ return (
704
+ <div>
705
+ <h1>${pascalCaseName}</h1>
706
+ </div>
707
+ );
708
+ }
709
+ `;
710
+ fs3__default.default.writeFileSync(fullPath, boilerplate);
711
+ console.log(`\x1B[32m[olova]\x1B[0m Generated boilerplate for ${filename}`);
712
+ }
713
+ }
714
+ }
715
+ if (timer) clearTimeout(timer);
716
+ timer = setTimeout(() => {
717
+ try {
718
+ generateRouteTreeFile();
719
+ } catch (error2) {
720
+ console.error("\x1B[31m[olova]\x1B[0m Error generating route tree:", error2);
721
+ }
722
+ }, 100);
723
+ }
724
+ });
725
+ console.log("\x1B[32m[olova]\x1B[0m Watching for route changes...");
726
+ }
727
+ const routerPlugin = {
728
+ name: "olova-router",
729
+ configResolved(resolvedConfig) {
730
+ config = resolvedConfig;
731
+ absoluteRootDir = path5__default.default.resolve(config.root, rootDir);
732
+ },
733
+ buildStart() {
734
+ generateRouteTreeFile();
735
+ if (config.command === "serve") {
736
+ startWatcher();
737
+ }
738
+ },
739
+ buildEnd() {
740
+ if (watcher) {
741
+ watcher.close();
742
+ watcher = null;
743
+ }
744
+ }
745
+ };
746
+ return [
747
+ { enforce: "pre", ...mdx__default.default() },
748
+ routerPlugin
749
+ ];
750
+ }
751
+ var VERSION = "0.0.14";
752
+ function printBanner() {
753
+ console.log("");
754
+ console.log(pc__default.default.cyan(` \u25B2 Olova`) + pc__default.default.dim(` ${VERSION}`));
755
+ console.log("");
756
+ }
757
+ function printDevReady(url, networkUrl) {
758
+ console.log("");
759
+ console.log(` ${pc__default.default.green("\u2713")} ${pc__default.default.bold("Ready")} in ${pc__default.default.cyan("~1s")}`);
760
+ console.log("");
761
+ console.log(` ${pc__default.default.dim("Local:")} ${pc__default.default.cyan(url)}`);
762
+ if (networkUrl) {
763
+ console.log(` ${pc__default.default.dim("Network:")} ${pc__default.default.cyan(networkUrl)}`);
764
+ }
765
+ console.log("");
766
+ }
767
+ function printBuildStart() {
768
+ console.log("");
769
+ console.log(` ${pc__default.default.dim("Creating an optimized production build...")}`);
770
+ console.log("");
771
+ }
772
+ function printSSGStart(buildId) {
773
+ console.log("");
774
+ console.log(pc__default.default.bold(pc__default.default.cyan(` \u2713 Compiled successfully`)));
775
+ console.log("");
776
+ console.log(` ${pc__default.default.dim("Build ID:")} ${pc__default.default.yellow(buildId)}`);
777
+ console.log("");
778
+ }
779
+ function printRoutes(routes) {
780
+ console.log(` ${pc__default.default.bold("Route")}${" ".repeat(32)}${pc__default.default.bold("Type")}`);
781
+ console.log(` ${pc__default.default.dim("\u250C")}${pc__default.default.dim("\u2500".repeat(43))}${pc__default.default.dim("\u2510")}`);
782
+ for (const route of routes) {
783
+ const icon = route.type === "static" ? pc__default.default.green("\u25CB") : pc__default.default.magenta("\u03BB");
784
+ const typeLabel = route.type === "static" ? pc__default.default.green("Static") : pc__default.default.magenta("Dynamic");
785
+ const pathDisplay = route.path === "/" ? "/" : route.path;
786
+ const padding = " ".repeat(Math.max(1, 35 - pathDisplay.length));
787
+ console.log(` ${pc__default.default.dim("\u2502")} ${icon} ${pc__default.default.white(pathDisplay)}${padding}${typeLabel}`);
788
+ }
789
+ console.log(` ${pc__default.default.dim("\u2514")}${pc__default.default.dim("\u2500".repeat(43))}${pc__default.default.dim("\u2518")}`);
790
+ console.log("");
791
+ }
792
+ function printPageGenerated(path6, hasFlightData = true) {
793
+ const badge = hasFlightData ? pc__default.default.dim(pc__default.default.cyan(" [Flight]")) : "";
794
+ console.log(` ${pc__default.default.dim("\u2713")} ${pc__default.default.dim("Generated")} ${pc__default.default.white(path6)}${badge}`);
795
+ }
796
+ function printPageError(path6, error2) {
797
+ console.log(` ${pc__default.default.red("\u2717")} ${pc__default.default.red("Failed")} ${path6}`);
798
+ console.log(` ${pc__default.default.dim(error2)}`);
799
+ }
800
+ function printSSGComplete(stats) {
801
+ console.log("");
802
+ console.log(` ${pc__default.default.dim("\u2500".repeat(45))}`);
803
+ console.log("");
804
+ if (stats.failedPages > 0) {
805
+ console.log(` ${pc__default.default.yellow("\u26A0")} ${pc__default.default.yellow("Build completed with warnings")}`);
806
+ } else {
807
+ console.log(` ${pc__default.default.green("\u2713")} ${pc__default.default.green("Build completed successfully")}`);
808
+ }
809
+ console.log("");
810
+ console.log(` ${pc__default.default.dim("Pages:")} ${pc__default.default.bold(stats.successPages.toString())} generated`);
811
+ if (stats.failedPages > 0) {
812
+ console.log(` ${pc__default.default.red(stats.failedPages.toString())} failed`);
813
+ }
814
+ console.log(` ${pc__default.default.dim("Time:")} ${pc__default.default.cyan(stats.buildTime + "ms")}`);
815
+ console.log("");
816
+ }
817
+ function printFlightInfo() {
818
+ console.log(` ${pc__default.default.cyan("\u25CB")} ${pc__default.default.dim("Flight hydration enabled")}`);
819
+ console.log(` ${pc__default.default.dim("\u2022 JSON-LD structured data")}`);
820
+ console.log(` ${pc__default.default.dim("\u2022 Resource hints")}`);
821
+ console.log(` ${pc__default.default.dim("\u2022 $OLOVA global")}`);
822
+ console.log("");
823
+ }
824
+ function info(message) {
825
+ console.log(` ${pc__default.default.cyan("\u25CB")} ${message}`);
826
+ }
827
+ function success(message) {
828
+ console.log(` ${pc__default.default.green("\u2713")} ${pc__default.default.green(message)}`);
829
+ }
830
+ function warn(message) {
831
+ console.log(` ${pc__default.default.yellow("\u26A0")} ${pc__default.default.yellow(message)}`);
832
+ }
833
+ function error(message) {
834
+ console.log(` ${pc__default.default.red("\u2717")} ${pc__default.default.red(message)}`);
835
+ }
836
+ function printSSRRender(path6) {
837
+ console.log(` ${pc__default.default.cyan("\u2192")} ${pc__default.default.dim("SSR")} ${path6}`);
838
+ }
839
+ var logger_default = {
840
+ printBanner,
841
+ printDevReady,
842
+ printBuildStart,
843
+ printSSGStart,
844
+ printRoutes,
845
+ printPageGenerated,
846
+ printPageError,
847
+ printSSGComplete,
848
+ printFlightInfo,
849
+ printSSRRender,
850
+ info,
851
+ success,
852
+ warn,
853
+ error
854
+ };
855
+ var gzip = util.promisify(zlib__default.default.gzip);
856
+ var brotliCompress = util.promisify(zlib__default.default.brotliCompress);
857
+ function createManualChunks() {
858
+ const seenModules = /* @__PURE__ */ new Map();
859
+ return (id, { getModuleInfo }) => {
860
+ if (id.includes("node_modules/react-dom")) {
861
+ return "vendor-react-dom";
862
+ }
863
+ if (id.includes("node_modules/react")) {
864
+ return "vendor-react";
865
+ }
866
+ if (id.includes("olova-router") || id.includes("olovastart/dist/router")) {
867
+ return "framework-router";
868
+ }
869
+ if (id.includes("node_modules")) {
870
+ const match = id.match(/node_modules[\\/]([^/\\]+)/);
871
+ if (match) {
872
+ const pkg = match[1];
873
+ if (["scheduler", "object-assign", "prop-types"].includes(pkg)) {
874
+ return "vendor-react";
875
+ }
876
+ if (["lodash", "moment", "axios", "date-fns"].includes(pkg)) {
877
+ return `vendor-${pkg}`;
878
+ }
879
+ }
880
+ return "vendor";
881
+ }
882
+ if (id.includes("/components/")) {
883
+ return "common-components";
884
+ }
885
+ if (id.includes("/utils/") || id.includes("/lib/") || id.includes("/helpers/")) {
886
+ return "common-utils";
887
+ }
888
+ if (id.endsWith(".css") || id.endsWith(".scss")) {
889
+ return void 0;
890
+ }
891
+ if (id.includes("/(auth)/") || id.includes("\\(auth)\\") || id.includes("/search/") || id.includes("\\search\\")) {
892
+ return "page-auth";
893
+ }
894
+ if (id.includes("/src/") && (id.endsWith("/index.tsx") || id.endsWith("/index.mdx"))) {
895
+ const moduleInfo = getModuleInfo(id);
896
+ if (moduleInfo) {
897
+ for (const importer of moduleInfo.importers) {
898
+ if (importer.includes("/src/") && importer.includes("/index.") && !importer.includes(id)) {
899
+ return "common-routes";
900
+ }
901
+ }
902
+ }
903
+ const routeMatch = id.match(/[\\/]src[\\/](.+?)[\\/]index\.(tsx|mdx)$/);
904
+ if (routeMatch) {
905
+ const routePath = routeMatch[1].replace(/\([^)]+\)[\\/]/g, "").replace(/\[.*?\]/g, "dynamic").replace(/[\\/]/g, "-");
906
+ const baseRoute = routePath.split("-")[0];
907
+ if (seenModules.has(baseRoute)) {
908
+ const existingChunk = seenModules.get(baseRoute);
909
+ if (existingChunk.startsWith("page-")) {
910
+ return existingChunk;
911
+ }
912
+ }
913
+ const chunkName = `page-${routePath}`;
914
+ seenModules.set(baseRoute, chunkName);
915
+ return chunkName;
916
+ }
917
+ }
918
+ return void 0;
919
+ };
920
+ }
921
+ function compressionPlugin(options = {}) {
922
+ const {
923
+ gzip: enableGzip = true,
924
+ brotli: enableBrotli = true,
925
+ threshold = 1024,
926
+ extensions = ["js", "css", "html", "json", "svg", "xml"]
927
+ } = options;
928
+ let config;
929
+ return {
930
+ name: "olova-compression",
931
+ apply: "build",
932
+ configResolved(resolvedConfig) {
933
+ config = resolvedConfig;
934
+ },
935
+ async closeBundle() {
936
+ if (config.command !== "build" || config.build.ssr) return;
937
+ const outDir = config.build.outDir;
938
+ const stats = { gzip: 0, brotli: 0, skipped: 0 };
939
+ const files = await findFilesToCompress(outDir, extensions);
940
+ for (const file of files) {
941
+ const content = await fs4__default.default.readFile(file);
942
+ if (content.length < threshold) {
943
+ stats.skipped++;
944
+ continue;
945
+ }
946
+ if (enableGzip) {
947
+ try {
948
+ const compressed = await gzip(content, { level: 9 });
949
+ await fs4__default.default.writeFile(`${file}.gz`, compressed);
950
+ stats.gzip++;
951
+ } catch (e) {
952
+ }
953
+ }
954
+ if (enableBrotli) {
955
+ try {
956
+ const compressed = await brotliCompress(content, {
957
+ params: {
958
+ [zlib__default.default.constants.BROTLI_PARAM_QUALITY]: 11
959
+ }
960
+ });
961
+ await fs4__default.default.writeFile(`${file}.br`, compressed);
962
+ stats.brotli++;
963
+ } catch (e) {
964
+ }
965
+ }
966
+ }
967
+ if (stats.gzip > 0 || stats.brotli > 0) {
968
+ logger_default.info(`Compressed ${stats.gzip} files (gzip), ${stats.brotli} files (brotli)`);
969
+ }
970
+ }
971
+ };
972
+ }
973
+ function chunkAnalysisPlugin(options = {}) {
974
+ const {
975
+ chunkSizeWarning = true,
976
+ maxChunkSize = 250
977
+ } = options;
978
+ const chunks = [];
979
+ return {
980
+ name: "olova-chunk-analysis",
981
+ apply: "build",
982
+ generateBundle(_options, bundle) {
983
+ for (const [fileName, chunk] of Object.entries(bundle)) {
984
+ if (chunk.type === "chunk") {
985
+ const sizeKB = Buffer.byteLength(chunk.code, "utf8") / 1024;
986
+ let type = "other";
987
+ if (fileName.includes("vendor")) type = "vendor";
988
+ else if (fileName.includes("framework")) type = "framework";
989
+ else if (fileName.includes("common")) type = "common";
990
+ else if (fileName.includes("page-")) type = "route";
991
+ chunks.push({
992
+ name: fileName,
993
+ size: Math.round(sizeKB * 100) / 100,
994
+ isEntry: chunk.isEntry,
995
+ type
996
+ });
997
+ if (chunkSizeWarning && sizeKB > maxChunkSize) {
998
+ logger_default.warn(`Chunk "${fileName}" is ${sizeKB.toFixed(2)}KB (exceeds ${maxChunkSize}KB limit)`);
999
+ }
1000
+ }
1001
+ }
1002
+ },
1003
+ closeBundle() {
1004
+ if (chunks.length === 0) return;
1005
+ chunks.sort((a, b) => b.size - a.size);
1006
+ console.log("");
1007
+ logger_default.info("Bundle Analysis:");
1008
+ const typeGroups = {};
1009
+ let totalSize = 0;
1010
+ for (const chunk of chunks) {
1011
+ typeGroups[chunk.type] = (typeGroups[chunk.type] || 0) + chunk.size;
1012
+ totalSize += chunk.size;
1013
+ }
1014
+ console.log(` Vendor: ${(typeGroups.vendor || 0).toFixed(2)} KB`);
1015
+ console.log(` Framework: ${(typeGroups.framework || 0).toFixed(2)} KB`);
1016
+ console.log(` Common: ${(typeGroups.common || 0).toFixed(2)} KB`);
1017
+ console.log(` Routes: ${(typeGroups.route || 0).toFixed(2)} KB`);
1018
+ console.log(` Other: ${(typeGroups.other || 0).toFixed(2)} KB`);
1019
+ console.log(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
1020
+ console.log(` Total: ${totalSize.toFixed(2)} KB`);
1021
+ console.log("");
1022
+ }
1023
+ };
1024
+ }
1025
+ function generatePreloadHints(chunks, entryChunk) {
1026
+ const hints = [];
1027
+ hints.push({
1028
+ href: `/${entryChunk}`,
1029
+ as: "script",
1030
+ priority: "critical"
1031
+ });
1032
+ for (const chunk of chunks) {
1033
+ if (chunk === entryChunk) continue;
1034
+ if (chunk.includes("vendor")) {
1035
+ hints.push({
1036
+ href: `/${chunk}`,
1037
+ as: "script",
1038
+ priority: "high"
1039
+ });
1040
+ } else if (chunk.includes("framework")) {
1041
+ hints.push({
1042
+ href: `/${chunk}`,
1043
+ as: "script",
1044
+ priority: "high"
1045
+ });
1046
+ } else if (chunk.includes("common")) {
1047
+ hints.push({
1048
+ href: `/${chunk}`,
1049
+ as: "script",
1050
+ priority: "high"
1051
+ });
1052
+ } else if (chunk.includes("page-")) {
1053
+ hints.push({
1054
+ href: `/${chunk}`,
1055
+ as: "script",
1056
+ priority: "low"
1057
+ });
1058
+ }
1059
+ }
1060
+ return hints;
1061
+ }
1062
+ function generatePreloadTags(hints) {
1063
+ return hints.map((hint) => {
1064
+ const rel = hint.priority === "low" ? "prefetch" : "modulepreload";
1065
+ const crossorigin = hint.crossorigin ? " crossorigin" : "";
1066
+ return `<link rel="${rel}" href="${hint.href}"${crossorigin}>`;
1067
+ }).join("");
1068
+ }
1069
+ async function findFilesToCompress(dir, extensions) {
1070
+ const files = [];
1071
+ try {
1072
+ const entries = await fs4__default.default.readdir(dir, { withFileTypes: true });
1073
+ for (const entry of entries) {
1074
+ const fullPath = path5__default.default.join(dir, entry.name);
1075
+ if (entry.isDirectory()) {
1076
+ files.push(...await findFilesToCompress(fullPath, extensions));
1077
+ } else if (entry.isFile()) {
1078
+ const ext = path5__default.default.extname(entry.name).slice(1);
1079
+ if (extensions.includes(ext)) {
1080
+ files.push(fullPath);
1081
+ }
1082
+ }
1083
+ }
1084
+ } catch (e) {
1085
+ }
1086
+ return files;
1087
+ }
1088
+ function olovaPerformance(options = {}) {
1089
+ return [
1090
+ chunkAnalysisPlugin(options),
1091
+ compressionPlugin(options)
1092
+ ];
1093
+ }
1094
+
1095
+ // src/hydration/flight.ts
1096
+ function safeStringify(data) {
1097
+ return JSON.stringify(data).replace(/[<>\/\u2028\u2029]/g, (char) => {
1098
+ switch (char) {
1099
+ case "<":
1100
+ return "\\u003c";
1101
+ case ">":
1102
+ return "\\u003e";
1103
+ case "/":
1104
+ return "\\u002f";
1105
+ case "\u2028":
1106
+ return "\\u2028";
1107
+ case "\u2029":
1108
+ return "\\u2029";
1109
+ default:
1110
+ return char;
1111
+ }
1112
+ });
1113
+ }
1114
+ function generatePageName(route) {
1115
+ if (route === "/") return "HomePage";
1116
+ return route.slice(1).split("/").filter(Boolean).map((s) => s.charAt(0).toUpperCase() + s.slice(1).replace(/[^a-zA-Z0-9]/g, "")).join("") + "Page";
1117
+ }
1118
+ function generatePattern(route) {
1119
+ if (route === "/") return "/";
1120
+ return route.replace(/\[\.\.\.([^\]]+)\]/g, "*").replace(/\[([^\]]+)\]/g, ":$1");
1121
+ }
1122
+ function generateFlightRuntime() {
1123
+ return `<script>
1124
+ (function(){
1125
+ var f=self.__olova_f||[];
1126
+ var p={R:'$route',M:'$meta',T:'$tree',D:'$schema',A:'$assets',H:'$hints',S:'$state',L:'$loader',Q:'$query'};
1127
+ var g=self.$OLOVA={};
1128
+ function h(c){var t=c[1],d=c[2];if(t==='E')return;var k=p[t];if(k){if(t==='L'||t==='Q'){g[k]={data:d,timestamp:c[3]||Date.now()}}else{g[k]=d}}}
1129
+ for(var i=0;i<f.length;i++)h(f[i]);
1130
+ self.__olova_f={push:h,length:0};
1131
+ })();
1132
+ </script>`;
1133
+ }
1134
+ function generateOlovaHydration(data, buildId) {
1135
+ const meta = data.metadata || {};
1136
+ const chunks = [];
1137
+ const routeData = {
1138
+ path: data.route,
1139
+ params: data.params || {},
1140
+ pattern: generatePattern(data.route),
1141
+ isStatic: data.isStatic ?? true,
1142
+ buildId
1143
+ };
1144
+ chunks.push(`<script>(self.__olova_f=self.__olova_f||[]).push([0,"R",${safeStringify(routeData)}])</script>`);
1145
+ const metadataData = {
1146
+ title: meta.title || "Olova App",
1147
+ description: meta.description || "",
1148
+ keywords: Array.isArray(meta.keywords) ? meta.keywords : [],
1149
+ robots: meta.robots || "index, follow",
1150
+ canonical: meta.canonical || null,
1151
+ og: {
1152
+ type: "website",
1153
+ locale: "en_US",
1154
+ ...meta.openGraph || {}
1155
+ },
1156
+ twitter: {
1157
+ card: "summary_large_image",
1158
+ ...meta.twitter || {}
1159
+ }
1160
+ };
1161
+ chunks.push(`<script>(self.__olova_f).push([1,"M",${safeStringify(metadataData)}])</script>`);
1162
+ const treeData = {
1163
+ layout: "RootLayout",
1164
+ page: generatePageName(data.route),
1165
+ template: null,
1166
+ loading: null,
1167
+ error: null,
1168
+ notFound: null
1169
+ };
1170
+ chunks.push(`<script>(self.__olova_f).push([2,"T",${safeStringify(treeData)}])</script>`);
1171
+ const assetsData = {
1172
+ chunks: data.chunks || [],
1173
+ styles: [],
1174
+ prefetch: (data.chunks || []).slice(0, 5)
1175
+ };
1176
+ chunks.push(`<script>(self.__olova_f).push([3,"A",${safeStringify(assetsData)}])</script>`);
1177
+ const hintsData = {
1178
+ dnsPrefetch: ["fonts.googleapis.com", "fonts.gstatic.com"],
1179
+ preconnect: ["https://fonts.googleapis.com", "https://fonts.gstatic.com"],
1180
+ modulePreload: (data.chunks || []).slice(0, 3)
1181
+ };
1182
+ chunks.push(`<script>(self.__olova_f).push([4,"H",${safeStringify(hintsData)}])</script>`);
1183
+ const stateData = {
1184
+ hydrated: false,
1185
+ streaming: false,
1186
+ ready: true,
1187
+ timestamp: Date.now(),
1188
+ version: "1.0.0",
1189
+ buildId
1190
+ };
1191
+ chunks.push(`<script>(self.__olova_f).push([5,"S",${safeStringify(stateData)}])</script>`);
1192
+ if (data.loaderData) {
1193
+ chunks.push(`<script>(self.__olova_f).push([6,"L",${safeStringify(data.loaderData)},${Date.now()}])</script>`);
1194
+ }
1195
+ if (data.queryState) {
1196
+ chunks.push(`<script>(self.__olova_f).push([7,"Q",${safeStringify(data.queryState)},${Date.now()}])</script>`);
1197
+ }
1198
+ chunks.push(`<script>(self.__olova_f).push([8,"E",null])</script>`);
1199
+ chunks.push(generateFlightRuntime());
1200
+ return chunks.join("");
1201
+ }
1202
+ function generateJsonLd(data) {
1203
+ const meta = data.metadata || {};
1204
+ const jsonLd = {
1205
+ "@context": "https://schema.org",
1206
+ "@graph": [
1207
+ {
1208
+ "@type": "WebPage",
1209
+ "@id": data.route,
1210
+ name: meta.title || "Olova App",
1211
+ description: meta.description || "",
1212
+ url: data.route,
1213
+ isPartOf: {
1214
+ "@type": "WebSite",
1215
+ name: "Olova App"
1216
+ }
1217
+ },
1218
+ {
1219
+ "@type": "BreadcrumbList",
1220
+ itemListElement: data.route.split("/").filter(Boolean).map((segment, index, arr) => ({
1221
+ "@type": "ListItem",
1222
+ position: index + 1,
1223
+ name: segment.charAt(0).toUpperCase() + segment.slice(1),
1224
+ item: "/" + arr.slice(0, index + 1).join("/")
1225
+ }))
1226
+ }
1227
+ ]
1228
+ };
1229
+ if (meta.schema) {
1230
+ const graph = jsonLd["@graph"];
1231
+ if (Array.isArray(meta.schema)) {
1232
+ graph.push(...meta.schema);
1233
+ } else {
1234
+ graph.push(meta.schema);
1235
+ }
1236
+ }
1237
+ return `<script type="application/ld+json">${JSON.stringify(jsonLd)}</script>`;
1238
+ }
1239
+ function generateResourceHints(data) {
1240
+ const hints = [];
1241
+ hints.push(`<link rel="dns-prefetch" href="//fonts.googleapis.com">`);
1242
+ hints.push(`<link rel="dns-prefetch" href="//fonts.gstatic.com">`);
1243
+ hints.push(`<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>`);
1244
+ hints.push(`<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>`);
1245
+ if (data.chunks) {
1246
+ for (const chunk of data.chunks.slice(0, 3)) {
1247
+ hints.push(`<link rel="modulepreload" href="/${chunk}">`);
1248
+ }
1249
+ }
1250
+ return hints.join("");
1251
+ }
1252
+ function generateBuildId() {
1253
+ const timestamp = Date.now().toString(36);
1254
+ const random = Math.random().toString(36).substring(2, 8);
1255
+ return `${timestamp}-${random}`;
1256
+ }
1257
+
1258
+ // olova.ts
1259
+ function olova(options = {}) {
1260
+ const virtualModuleId = "virtual:olova-entry";
1261
+ const serverVirtualModuleId = "virtual:olova-server-entry";
1262
+ const workerVirtualModuleId = "virtual:olova-worker-entry";
1263
+ const appVirtualModuleId = "virtual:olova-app";
1264
+ const resolvedAppVirtualModuleId = "\0" + appVirtualModuleId;
1265
+ let config;
1266
+ const htmlContent = `<!--app-html-->`;
1267
+ const minifyHtml = (html) => {
1268
+ return html.replace(/>\s+</g, "><").replace(/\s{2,}/g, " ").replace(/<!--[\s\S]*?-->/g, "").trim();
1269
+ };
1270
+ return [
1271
+ olovaRouter({ packageName: options.packageName }),
1272
+ {
1273
+ name: "vite-plugin-olova",
1274
+ config(userConfig, { isSsrBuild }) {
1275
+ const perfEnabled = options.performance?.enabled !== false;
1276
+ if (isSsrBuild) {
1277
+ return {
1278
+ build: {
1279
+ rollupOptions: {
1280
+ input: userConfig.build?.rollupOptions?.input || virtualModuleId,
1281
+ output: {
1282
+ // Simple output for SSR
1283
+ entryFileNames: "index.js",
1284
+ chunkFileNames: "[name].js",
1285
+ assetFileNames: "[name].[ext]",
1286
+ format: "esm",
1287
+ manualChunks: void 0
1288
+ }
1289
+ }
1290
+ }
1291
+ };
1292
+ }
1293
+ const buildConfig = {
1294
+ // Output directory for assets
1295
+ assetsDir: "assets/_olova",
1296
+ // Report compressed size in build output
1297
+ reportCompressedSize: true,
1298
+ rollupOptions: {
1299
+ input: userConfig.build?.rollupOptions?.input || virtualModuleId,
1300
+ output: {
1301
+ // Optimized chunk naming for caching
1302
+ chunkFileNames: "assets/_olova/[name]-[hash].js",
1303
+ entryFileNames: "assets/_olova/[name]-[hash].js",
1304
+ assetFileNames: "assets/_olova/[name]-[hash].[ext]",
1305
+ // Enable smart code splitting
1306
+ ...perfEnabled && {
1307
+ manualChunks: createManualChunks()
1308
+ }
1309
+ }
1310
+ },
1311
+ // Increase warning limit since we're doing smart chunking
1312
+ chunkSizeWarningLimit: 500,
1313
+ // Inline small assets (< 4KB)
1314
+ assetsInlineLimit: 4096,
1315
+ // Enable terser minification for smaller bundles
1316
+ minify: "terser",
1317
+ terserOptions: {
1318
+ compress: {
1319
+ // Aggressive optimizations for production
1320
+ drop_console: false,
1321
+ // Keep console for debugging
1322
+ drop_debugger: true,
1323
+ pure_funcs: ["console.debug"],
1324
+ passes: 2
1325
+ },
1326
+ mangle: {
1327
+ properties: false
1328
+ },
1329
+ format: {
1330
+ comments: false
1331
+ }
1332
+ },
1333
+ // Disable source maps for smaller builds
1334
+ sourcemap: false,
1335
+ // CSS code splitting
1336
+ cssCodeSplit: true,
1337
+ // Target modern browsers (smaller bundles)
1338
+ target: "es2020"
1339
+ };
1340
+ return {
1341
+ build: buildConfig,
1342
+ // Optimize deps for faster dev startup
1343
+ optimizeDeps: {
1344
+ include: ["react", "react-dom"],
1345
+ exclude: ["olova"]
1346
+ },
1347
+ // SSR options
1348
+ ssr: {
1349
+ noExternal: ["olova"]
1350
+ },
1351
+ // esbuild optimizations
1352
+ esbuild: {
1353
+ treeShaking: true,
1354
+ legalComments: "none"
1355
+ },
1356
+ // Preview server configuration (for testing production builds)
1357
+ preview: {
1358
+ headers: {
1359
+ // Long-term caching for static assets
1360
+ "Cache-Control": "public, max-age=31536000"
1361
+ }
1362
+ }
1363
+ };
1364
+ },
1365
+ async configResolved(resolvedConfig) {
1366
+ config = resolvedConfig;
1367
+ },
1368
+ async resolveId(id) {
1369
+ if (id === virtualModuleId || id === serverVirtualModuleId || id === workerVirtualModuleId) {
1370
+ const isServer = id === serverVirtualModuleId;
1371
+ const isWorker = id === workerVirtualModuleId;
1372
+ const fileName = isWorker ? "entry-worker" : isServer ? "entry-server" : "main";
1373
+ const possibleLocalPaths = [
1374
+ path5__default.default.resolve(config.root, `src/${fileName}.tsx`),
1375
+ path5__default.default.resolve(config.root, `src/${fileName}.ts`),
1376
+ path5__default.default.resolve(config.root, `${fileName}.tsx`),
1377
+ path5__default.default.resolve(config.root, `plugins/${fileName}.tsx`)
1378
+ ];
1379
+ for (const p of possibleLocalPaths) {
1380
+ if (fs3.existsSync(p)) return p;
1381
+ }
1382
+ const exportName = isWorker ? "olova/entry-worker" : isServer ? "olova/entry-server" : "olova/main";
1383
+ try {
1384
+ const resolved = await this.resolve(exportName, void 0, { skipSelf: true });
1385
+ if (resolved && !resolved.external) {
1386
+ return resolved.id;
1387
+ }
1388
+ } catch (e) {
1389
+ }
1390
+ const pkgDir = path5__default.default.dirname(url.fileURLToPath(importMetaUrl));
1391
+ const possiblePkgPaths = [
1392
+ path5__default.default.resolve(pkgDir, `dist/${fileName}.js`),
1393
+ path5__default.default.resolve(pkgDir, `${fileName}.js`),
1394
+ path5__default.default.resolve(pkgDir, `${fileName}.mjs`),
1395
+ path5__default.default.resolve(pkgDir, `${fileName}.ts`),
1396
+ path5__default.default.resolve(pkgDir, `${fileName}.tsx`),
1397
+ path5__default.default.resolve(pkgDir, `src/${fileName}.tsx`),
1398
+ path5__default.default.resolve(pkgDir, `src/${fileName}.ts`),
1399
+ // If running from dist, check parent directories
1400
+ path5__default.default.resolve(pkgDir, "..", `dist/${fileName}.js`),
1401
+ path5__default.default.resolve(pkgDir, "..", `${fileName}.js`),
1402
+ path5__default.default.resolve(pkgDir, "..", `${fileName}.tsx`),
1403
+ path5__default.default.resolve(pkgDir, "..", `src/${fileName}.tsx`)
1404
+ ];
1405
+ for (const p of possiblePkgPaths) {
1406
+ if (fs3.existsSync(p)) return p;
1407
+ }
1408
+ }
1409
+ if (id === appVirtualModuleId) {
1410
+ return resolvedAppVirtualModuleId;
1411
+ }
1412
+ return null;
1413
+ },
1414
+ load(id) {
1415
+ if (id === resolvedAppVirtualModuleId) {
1416
+ return `
1417
+ export { OlovaRouter, Outlet, routes, layouts, notFoundPages } from '@/route.tree';
1418
+ import '@/index.css';
1419
+ `;
1420
+ }
1421
+ return null;
1422
+ },
1423
+ configureServer(server) {
1424
+ const devBuildId = generateBuildId();
1425
+ logger_default.printBanner();
1426
+ server.middlewares.use(async (req, res, next) => {
1427
+ const url = req.url?.split("?")[0];
1428
+ if (url === "/" || url === "/index.html" || req.headers.accept?.includes("text/html") && !url?.match(/\.[a-z]+$/)) {
1429
+ try {
1430
+ logger_default.printSSRRender(url || "/");
1431
+ let template = htmlContent;
1432
+ const { render } = await server.ssrLoadModule(
1433
+ serverVirtualModuleId
1434
+ );
1435
+ const renderResult = await render(url || "/");
1436
+ const appHtml = typeof renderResult === "string" ? renderResult : renderResult.html;
1437
+ const routeMetadata = typeof renderResult === "string" ? {} : renderResult.metadata || {};
1438
+ const loaderData = typeof renderResult === "string" ? void 0 : renderResult.loaderData;
1439
+ const queryState = typeof renderResult === "string" ? void 0 : renderResult.queryState;
1440
+ let fullHtml = template.replace("<!--app-html-->", appHtml);
1441
+ const hydrationData = {
1442
+ route: url || "/",
1443
+ params: {},
1444
+ metadata: routeMetadata,
1445
+ chunks: [],
1446
+ // Dev mode doesn't have pre-built chunks
1447
+ isStatic: false,
1448
+ loaderData,
1449
+ queryState
1450
+ };
1451
+ const flightScripts = generateOlovaHydration(hydrationData, devBuildId);
1452
+ const jsonLdScript = generateJsonLd(hydrationData);
1453
+ const resourceHints = `<link rel="dns-prefetch" href="//fonts.googleapis.com"><link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>`;
1454
+ if (fullHtml.includes("</head>")) {
1455
+ fullHtml = fullHtml.replace("</head>", `${jsonLdScript}${resourceHints}</head>`);
1456
+ }
1457
+ if (fullHtml.includes("</body>")) {
1458
+ fullHtml = fullHtml.replace(
1459
+ "</body>",
1460
+ `${flightScripts}<script type="module" src="/@id/${virtualModuleId}"></script></body>`
1461
+ );
1462
+ } else {
1463
+ fullHtml += `${flightScripts}<script type="module" src="/@id/${virtualModuleId}"></script>`;
1464
+ }
1465
+ fullHtml = await server.transformIndexHtml(url || "/", fullHtml);
1466
+ if (!fullHtml.trim().toLowerCase().startsWith("<!doctype html>")) {
1467
+ fullHtml = `<!DOCTYPE html>${fullHtml}`;
1468
+ }
1469
+ res.statusCode = 200;
1470
+ res.setHeader("Content-Type", "text/html");
1471
+ res.end(minifyHtml(fullHtml));
1472
+ return;
1473
+ } catch (e) {
1474
+ server.ssrFixStacktrace(e);
1475
+ console.error(e);
1476
+ res.statusCode = 500;
1477
+ res.end(e.stack);
1478
+ return;
1479
+ }
1480
+ }
1481
+ next();
1482
+ });
1483
+ },
1484
+ async writeBundle(_options, bundle) {
1485
+ if (config.command === "serve" || config.build.ssr) return;
1486
+ const buildStartTime = Date.now();
1487
+ logger_default.printBuildStart();
1488
+ const outDir = config.build.outDir;
1489
+ const serverOutDir = path5__default.default.resolve(config.root, "dist/server");
1490
+ const clientEntry = Object.values(bundle).find(
1491
+ (chunk) => chunk.type === "chunk" && chunk.isEntry && (chunk.facadeModuleId?.includes("main") || chunk.name === "main")
1492
+ );
1493
+ const clientEntryFileName = clientEntry ? clientEntry.fileName : "assets/index.js";
1494
+ const cssAssets = Object.values(bundle).filter(
1495
+ (chunk) => chunk.type === "asset" && chunk.fileName.endsWith(".css")
1496
+ );
1497
+ const cssLinks = cssAssets.map(
1498
+ (css) => `<link rel="stylesheet" crossorigin href="/${css.fileName}">`
1499
+ ).join("");
1500
+ await vite.build({
1501
+ configFile: config.configFile,
1502
+ root: config.root,
1503
+ build: {
1504
+ ssr: true,
1505
+ emptyOutDir: false,
1506
+ outDir: serverOutDir,
1507
+ minify: false,
1508
+ // Keep readable for debugging
1509
+ rollupOptions: {
1510
+ input: { index: serverVirtualModuleId },
1511
+ output: {
1512
+ entryFileNames: "index.js",
1513
+ chunkFileNames: "[name].js",
1514
+ assetFileNames: "[name].[ext]",
1515
+ format: "esm",
1516
+ // Explicitly set to undefined to prevent client-side chunking config
1517
+ manualChunks: void 0
1518
+ }
1519
+ }
1520
+ },
1521
+ logLevel: "error"
1522
+ });
1523
+ const serverEntryPath = path5__default.default.resolve(serverOutDir, "index.js");
1524
+ const serverEntryUrl = url.pathToFileURL(serverEntryPath).toString();
1525
+ const { routes } = await import(serverEntryUrl);
1526
+ const paths = ["/"];
1527
+ function extractPaths(routesArr) {
1528
+ routesArr.forEach((r) => {
1529
+ if (r.path && !r.path.includes("*") && !r.path.includes(":")) {
1530
+ paths.push(r.path);
1531
+ }
1532
+ });
1533
+ }
1534
+ if (Array.isArray(routes)) extractPaths(routes);
1535
+ if (Array.isArray(routes)) {
1536
+ for (const r of routes) {
1537
+ const isDynamic = r.path.includes(":") || r.path.includes("*");
1538
+ if (r.getStaticPaths && isDynamic) {
1539
+ try {
1540
+ const staticPaths = await r.getStaticPaths();
1541
+ if (Array.isArray(staticPaths)) {
1542
+ for (const entry of staticPaths) {
1543
+ let expandedPath = r.path;
1544
+ if (entry.params) {
1545
+ for (const [key, value] of Object.entries(entry.params)) {
1546
+ expandedPath = expandedPath.replace(`:${key}`, value);
1547
+ expandedPath = expandedPath.replace("*", value);
1548
+ }
1549
+ }
1550
+ paths.push(expandedPath);
1551
+ }
1552
+ logger_default.info(`getStaticPaths for ${r.path}: ${staticPaths.length} paths expanded`);
1553
+ }
1554
+ } catch (e) {
1555
+ logger_default.warn(`getStaticPaths() failed for ${r.path}: ${e.message}`);
1556
+ }
1557
+ }
1558
+ }
1559
+ }
1560
+ if (options.staticPaths) {
1561
+ options.staticPaths.forEach((p) => paths.push(p));
1562
+ }
1563
+ const uniquePaths = [...new Set(paths)];
1564
+ const buildId = generateBuildId();
1565
+ logger_default.printSSGStart(buildId);
1566
+ const routeInfo = uniquePaths.map((p) => ({
1567
+ path: p,
1568
+ type: p.includes(":") || p.includes("*") ? "dynamic" : "static"
1569
+ }));
1570
+ logger_default.printRoutes(routeInfo);
1571
+ logger_default.printFlightInfo();
1572
+ const jsChunks = Object.values(bundle).filter((chunk) => chunk.type === "chunk" && chunk.fileName.endsWith(".js")).map((chunk) => chunk.fileName);
1573
+ let successCount = 0;
1574
+ let failCount = 0;
1575
+ for (const p of uniquePaths) {
1576
+ try {
1577
+ if (typeof globalThis.window !== "undefined") {
1578
+ globalThis.window.location.pathname = p;
1579
+ }
1580
+ const cacheBuster = `?t=${Date.now()}-${Math.random()}`;
1581
+ const { render } = await import(serverEntryUrl + cacheBuster);
1582
+ const renderResult = await render(p);
1583
+ const appHtml = typeof renderResult === "string" ? renderResult : renderResult.html;
1584
+ const routeMetadata = typeof renderResult === "string" ? {} : renderResult.metadata || {};
1585
+ const loaderData = typeof renderResult === "string" ? void 0 : renderResult.loaderData;
1586
+ const queryState = typeof renderResult === "string" ? void 0 : renderResult.queryState;
1587
+ let html = htmlContent.replace("<!--app-html-->", appHtml);
1588
+ const preloadHints = generatePreloadHints(jsChunks, clientEntryFileName);
1589
+ const preloadTags = generatePreloadTags(preloadHints);
1590
+ const hydrationData = {
1591
+ route: p,
1592
+ params: {},
1593
+ metadata: routeMetadata,
1594
+ chunks: jsChunks,
1595
+ isStatic: true,
1596
+ loaderData,
1597
+ queryState
1598
+ };
1599
+ const flightScripts = generateOlovaHydration(hydrationData, buildId);
1600
+ const jsonLdScript = generateJsonLd(hydrationData);
1601
+ const resourceHints = generateResourceHints(hydrationData);
1602
+ if (html.includes("</head>")) {
1603
+ html = html.replace("</head>", `${jsonLdScript}${resourceHints}${cssLinks}${preloadTags}</head>`);
1604
+ }
1605
+ if (html.includes("</body>")) {
1606
+ html = html.replace(
1607
+ "</body>",
1608
+ `${flightScripts}<script type="module" src="/${clientEntryFileName}"></script></body>`
1609
+ );
1610
+ } else {
1611
+ html += `${flightScripts}<script type="module" src="/${clientEntryFileName}"></script>`;
1612
+ }
1613
+ if (!html.trim().toLowerCase().startsWith("<!doctype html>")) {
1614
+ html = `<!DOCTYPE html>${html}`;
1615
+ }
1616
+ const itemPath = p === "/" ? "index.html" : `${p.substring(1)}/index.html`;
1617
+ const finalPath = path5__default.default.resolve(outDir, itemPath);
1618
+ await fs4__default.default.mkdir(path5__default.default.dirname(finalPath), { recursive: true });
1619
+ await fs4__default.default.writeFile(finalPath, minifyHtml(html));
1620
+ logger_default.printPageGenerated(itemPath, true);
1621
+ successCount++;
1622
+ } catch (e) {
1623
+ logger_default.printPageError(p, e.message);
1624
+ failCount++;
1625
+ }
1626
+ }
1627
+ try {
1628
+ const notFoundPath = "/__olova_404__";
1629
+ if (typeof globalThis.window !== "undefined") {
1630
+ globalThis.window.location.pathname = notFoundPath;
1631
+ }
1632
+ const cacheBuster404 = `?t=${Date.now()}-${Math.random()}`;
1633
+ const { render: render404 } = await import(serverEntryUrl + cacheBuster404);
1634
+ const result404 = await render404(notFoundPath);
1635
+ const html404Content = typeof result404 === "string" ? result404 : result404.html;
1636
+ let html404 = htmlContent.replace("<!--app-html-->", html404Content);
1637
+ const preloadHints404 = generatePreloadHints(jsChunks, clientEntryFileName);
1638
+ const preloadTags404 = generatePreloadTags(preloadHints404);
1639
+ const hydrationData404 = {
1640
+ route: "/404",
1641
+ params: {},
1642
+ metadata: { title: "404 - Page Not Found" },
1643
+ chunks: jsChunks,
1644
+ isStatic: true
1645
+ };
1646
+ const flightScripts404 = generateOlovaHydration(hydrationData404, buildId);
1647
+ const jsonLd404 = generateJsonLd(hydrationData404);
1648
+ const resourceHints404 = generateResourceHints(hydrationData404);
1649
+ if (html404.includes("</head>")) {
1650
+ html404 = html404.replace("</head>", `${jsonLd404}${resourceHints404}${cssLinks}${preloadTags404}</head>`);
1651
+ }
1652
+ if (html404.includes("</body>")) {
1653
+ html404 = html404.replace("</body>", `${flightScripts404}<script type="module" src="/${clientEntryFileName}"></script></body>`);
1654
+ } else {
1655
+ html404 += `${flightScripts404}<script type="module" src="/${clientEntryFileName}"></script>`;
1656
+ }
1657
+ if (!html404.trim().toLowerCase().startsWith("<!doctype html>")) {
1658
+ html404 = `<!DOCTYPE html>${html404}`;
1659
+ }
1660
+ const notFoundFinalPath = path5__default.default.resolve(outDir, "404.html");
1661
+ await fs4__default.default.writeFile(notFoundFinalPath, minifyHtml(html404));
1662
+ logger_default.printPageGenerated("404.html", true);
1663
+ successCount++;
1664
+ } catch (e) {
1665
+ logger_default.warn(`Failed to generate 404.html: ${e.message}`);
1666
+ }
1667
+ await fs4__default.default.rm(serverOutDir, { recursive: true, force: true });
1668
+ const buildTime = Date.now() - buildStartTime;
1669
+ logger_default.printSSGComplete({
1670
+ totalPages: successCount,
1671
+ successPages: successCount,
1672
+ failedPages: failCount,
1673
+ buildTime
1674
+ });
1675
+ }
1676
+ },
1677
+ // Add performance optimization plugins
1678
+ ...options.performance?.enabled !== false ? olovaPerformance(options.performance) : []
1679
+ ];
1680
+ }
1681
+
1682
+ exports.olova = olova;
1683
+ //# sourceMappingURL=olova.cjs.map
1684
+ //# sourceMappingURL=olova.cjs.map