@devlusoft/devix 0.1.0

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 (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +216 -0
  3. package/bin/devix.js +2 -0
  4. package/dist/cli/build.d.ts +1 -0
  5. package/dist/cli/build.js +286 -0
  6. package/dist/cli/build.js.map +7 -0
  7. package/dist/cli/dev.d.ts +1 -0
  8. package/dist/cli/dev.js +361 -0
  9. package/dist/cli/dev.js.map +7 -0
  10. package/dist/cli/generate.d.ts +1 -0
  11. package/dist/cli/generate.js +389 -0
  12. package/dist/cli/generate.js.map +7 -0
  13. package/dist/cli/index.d.ts +2 -0
  14. package/dist/cli/index.js +649 -0
  15. package/dist/cli/index.js.map +7 -0
  16. package/dist/cli/start.d.ts +1 -0
  17. package/dist/cli/start.js +78 -0
  18. package/dist/cli/start.js.map +7 -0
  19. package/dist/config.d.ts +21 -0
  20. package/dist/config.js +17 -0
  21. package/dist/config.js.map +7 -0
  22. package/dist/runtime/api-context.d.ts +20 -0
  23. package/dist/runtime/api-context.js +18 -0
  24. package/dist/runtime/api-context.js.map +7 -0
  25. package/dist/runtime/client-router.d.ts +13 -0
  26. package/dist/runtime/client-router.js +59 -0
  27. package/dist/runtime/client-router.js.map +7 -0
  28. package/dist/runtime/context.d.ts +27 -0
  29. package/dist/runtime/context.js +15 -0
  30. package/dist/runtime/context.js.map +7 -0
  31. package/dist/runtime/error-boundary.d.ts +19 -0
  32. package/dist/runtime/error-boundary.js +37 -0
  33. package/dist/runtime/error-boundary.js.map +7 -0
  34. package/dist/runtime/head.d.ts +3 -0
  35. package/dist/runtime/head.js +69 -0
  36. package/dist/runtime/head.js.map +7 -0
  37. package/dist/runtime/index.d.ts +5 -0
  38. package/dist/runtime/index.js +300 -0
  39. package/dist/runtime/index.js.map +7 -0
  40. package/dist/runtime/link.d.ts +8 -0
  41. package/dist/runtime/link.js +43 -0
  42. package/dist/runtime/link.js.map +7 -0
  43. package/dist/runtime/metadata.d.ts +10 -0
  44. package/dist/runtime/metadata.js +22 -0
  45. package/dist/runtime/metadata.js.map +7 -0
  46. package/dist/runtime/router-provider.d.ts +22 -0
  47. package/dist/runtime/router-provider.js +259 -0
  48. package/dist/runtime/router-provider.js.map +7 -0
  49. package/dist/server/api-router.d.ts +21 -0
  50. package/dist/server/api-router.js +64 -0
  51. package/dist/server/api-router.js.map +7 -0
  52. package/dist/server/api.d.ts +2 -0
  53. package/dist/server/api.js +123 -0
  54. package/dist/server/api.js.map +7 -0
  55. package/dist/server/collect-css.d.ts +2 -0
  56. package/dist/server/collect-css.js +15 -0
  57. package/dist/server/collect-css.js.map +7 -0
  58. package/dist/server/index.d.ts +6 -0
  59. package/dist/server/index.js +133 -0
  60. package/dist/server/index.js.map +7 -0
  61. package/dist/server/pages-router.d.ts +21 -0
  62. package/dist/server/pages-router.js +64 -0
  63. package/dist/server/pages-router.js.map +7 -0
  64. package/dist/server/render.d.ts +34 -0
  65. package/dist/server/render.js +306 -0
  66. package/dist/server/render.js.map +7 -0
  67. package/dist/server/routes.d.ts +11 -0
  68. package/dist/server/routes.js +42 -0
  69. package/dist/server/routes.js.map +7 -0
  70. package/dist/server/types.d.ts +49 -0
  71. package/dist/server/types.js +1 -0
  72. package/dist/server/types.js.map +7 -0
  73. package/dist/types.d.ts +35 -0
  74. package/dist/types.js +1 -0
  75. package/dist/types.js.map +7 -0
  76. package/dist/utils/async.d.ts +1 -0
  77. package/dist/utils/async.js +14 -0
  78. package/dist/utils/async.js.map +7 -0
  79. package/dist/utils/banner.d.ts +1 -0
  80. package/dist/utils/banner.js +34 -0
  81. package/dist/utils/banner.js.map +7 -0
  82. package/dist/utils/duration.d.ts +1 -0
  83. package/dist/utils/duration.js +22 -0
  84. package/dist/utils/duration.js.map +7 -0
  85. package/dist/utils/html.d.ts +2 -0
  86. package/dist/utils/html.js +12 -0
  87. package/dist/utils/html.js.map +7 -0
  88. package/dist/utils/patterns.d.ts +1 -0
  89. package/dist/utils/patterns.js +8 -0
  90. package/dist/utils/patterns.js.map +7 -0
  91. package/dist/vite/codegen/api.d.ts +6 -0
  92. package/dist/vite/codegen/api.js +23 -0
  93. package/dist/vite/codegen/api.js.map +7 -0
  94. package/dist/vite/codegen/client-routes.d.ts +6 -0
  95. package/dist/vite/codegen/client-routes.js +36 -0
  96. package/dist/vite/codegen/client-routes.js.map +7 -0
  97. package/dist/vite/codegen/context.d.ts +1 -0
  98. package/dist/vite/codegen/context.js +10 -0
  99. package/dist/vite/codegen/context.js.map +7 -0
  100. package/dist/vite/codegen/entry-client.d.ts +5 -0
  101. package/dist/vite/codegen/entry-client.js +64 -0
  102. package/dist/vite/codegen/entry-client.js.map +7 -0
  103. package/dist/vite/codegen/render.d.ts +6 -0
  104. package/dist/vite/codegen/render.js +31 -0
  105. package/dist/vite/codegen/render.js.map +7 -0
  106. package/dist/vite/index.d.ts +3 -0
  107. package/dist/vite/index.js +225 -0
  108. package/dist/vite/index.js.map +7 -0
  109. package/package.json +77 -0
@@ -0,0 +1,133 @@
1
+ // src/utils/patterns.ts
2
+ function routePattern(rel) {
3
+ return rel.replace(/\.(tsx|ts|jsx|js)$/, "").replace(/\(.*?\)\//g, "").replace(/^index$|\/index$/, "").replace(/\[([^\]]+)]/g, ":$1") || "/";
4
+ }
5
+
6
+ // src/server/pages-router.ts
7
+ function keyToRoutePattern(key, pagesDir) {
8
+ const rel = key.slice(pagesDir.length + 1).replace(/\\/g, "/");
9
+ const pattern = routePattern(rel);
10
+ return pattern === "/" ? "/" : `/${pattern}`;
11
+ }
12
+ function keyToDir(key) {
13
+ return key.slice(0, key.lastIndexOf("/"));
14
+ }
15
+ var cache = null;
16
+ function buildPages(pageKeys, layoutKeys, pagesDir) {
17
+ if (cache) return cache;
18
+ const pages = [];
19
+ const layouts = [];
20
+ for (const key of layoutKeys) {
21
+ layouts.push({ dir: keyToDir(key), key });
22
+ }
23
+ for (const key of pageKeys) {
24
+ const pattern = keyToRoutePattern(key, pagesDir);
25
+ const params = [...pattern.matchAll(/:([^/]+)/g)].map((m) => m[1]);
26
+ const regexStr = pattern.replace(/:[^/]+/g, "([^/]+)").replace(/\//g, "\\/");
27
+ pages.push({ path: pattern, key, params, regex: new RegExp(`^${regexStr}$`) });
28
+ }
29
+ pages.sort((a, b) => {
30
+ const aScore = (a.path.match(/:/g) || []).length;
31
+ const bScore = (b.path.match(/:/g) || []).length;
32
+ if (aScore !== bScore) return aScore - bScore;
33
+ return b.path.length - a.path.length;
34
+ });
35
+ cache = { pages, layouts };
36
+ return cache;
37
+ }
38
+ function collectLayoutChain(pageKey, layouts) {
39
+ const pageDir = keyToDir(pageKey);
40
+ return layouts.filter((layout) => pageDir.startsWith(layout.dir)).sort((a, b) => a.dir.split("/").length - b.dir.split("/").length);
41
+ }
42
+ function matchPage(pathname, pages) {
43
+ for (const page of pages) {
44
+ const match = pathname.match(page.regex);
45
+ if (match) {
46
+ const params = {};
47
+ page.params.forEach((name, i) => {
48
+ params[name] = decodeURIComponent(match[i + 1]);
49
+ });
50
+ return { page, params };
51
+ }
52
+ }
53
+ return null;
54
+ }
55
+
56
+ // src/server/api-router.ts
57
+ function keyToRoutePattern2(key, apiDir) {
58
+ const rel = key.slice(apiDir.length + 1).replace(/\\/g, "/");
59
+ const pattern = routePattern(rel);
60
+ return pattern === "/" ? "/api" : `/api/${pattern}`.replace("/api//", "/api/");
61
+ }
62
+ function keyToDir2(key) {
63
+ return key.slice(0, key.lastIndexOf("/"));
64
+ }
65
+ var cache2 = null;
66
+ function buildRoutes(routeKeys, middlewareKeys, apiDir) {
67
+ if (cache2) return cache2;
68
+ const routes = [];
69
+ const middlewares = [];
70
+ for (const key of middlewareKeys) {
71
+ middlewares.push({ dir: keyToDir2(key), key });
72
+ }
73
+ for (const key of routeKeys) {
74
+ const pattern = keyToRoutePattern2(key, apiDir);
75
+ const params = [...pattern.matchAll(/:([^/]+)/g)].map((m) => m[1]);
76
+ const regexStr = pattern.replace(/:[^/]+/g, "([^/]+)").replace(/\//g, "\\/");
77
+ routes.push({ path: pattern, key, params, regex: new RegExp(`^${regexStr}$`) });
78
+ }
79
+ routes.sort((a, b) => {
80
+ const aScore = (a.path.match(/:/g) || []).length;
81
+ const bScore = (b.path.match(/:/g) || []).length;
82
+ if (aScore !== bScore) return aScore - bScore;
83
+ return b.path.length - a.path.length;
84
+ });
85
+ cache2 = { routes, middlewares };
86
+ return cache2;
87
+ }
88
+ function collectMiddlewareChain(routeKey, middlewares) {
89
+ const routeDir = keyToDir2(routeKey);
90
+ return middlewares.filter((mw) => routeDir.startsWith(mw.dir)).sort((a, b) => a.dir.split("/").length - b.dir.split("/").length);
91
+ }
92
+ function matchRoute(pathname, routes) {
93
+ for (const route of routes) {
94
+ const match = pathname.match(route.regex);
95
+ if (match) {
96
+ const params = {};
97
+ route.params.forEach((name, i) => {
98
+ params[name] = decodeURIComponent(match[i + 1]);
99
+ });
100
+ return { route, params };
101
+ }
102
+ }
103
+ return null;
104
+ }
105
+
106
+ // src/runtime/metadata.ts
107
+ async function resolveMetadata(module, ctx) {
108
+ const metadata = module.generateMetadata ? await module.generateMetadata(ctx) : module.metadata ?? {};
109
+ const viewport = module.generateViewport ? await module.generateViewport(ctx) : module.viewport;
110
+ return { metadata, viewport };
111
+ }
112
+ function mergeMetadata(...sources) {
113
+ const result = {};
114
+ for (const source of sources) {
115
+ if (!source) continue;
116
+ const { og, twitter, ...rest } = source;
117
+ Object.assign(result, rest);
118
+ if (og) result.og = { ...result.og, ...og };
119
+ if (twitter) result.twitter = { ...result.twitter, ...twitter };
120
+ }
121
+ return result;
122
+ }
123
+ export {
124
+ buildPages,
125
+ buildRoutes,
126
+ collectLayoutChain,
127
+ collectMiddlewareChain,
128
+ matchPage,
129
+ matchRoute,
130
+ mergeMetadata,
131
+ resolveMetadata
132
+ };
133
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/patterns.ts", "../../src/server/pages-router.ts", "../../src/server/api-router.ts", "../../src/runtime/metadata.ts"],
4
+ "sourcesContent": ["export function routePattern(rel: string): string {\n return rel\n .replace(/\\.(tsx|ts|jsx|js)$/, '')\n .replace(/\\(.*?\\)\\//g, '')\n .replace(/^index$|\\/index$/, '')\n .replace(/\\[([^\\]]+)]/g, ':$1')\n || '/'\n}", "import {routePattern} from \"../utils/patterns\";\n\nexport interface Page {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface Layout {\n dir: string\n key: string\n}\n\nexport interface PagesResult {\n pages: Page[]\n layouts: Layout[]\n}\n\nfunction keyToRoutePattern(key: string, pagesDir: string): string {\n const rel = key.slice(pagesDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === \"/\" ? \"/\" : `/${pattern}`\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: PagesResult | null = null\n\nexport function invalidatePagesCache() {\n cache = null\n}\n\nexport function buildPages(pageKeys: string[], layoutKeys: string[], pagesDir: string): PagesResult {\n if (cache) return cache\n\n const pages: Page[] = []\n const layouts: Layout[] = []\n\n for (const key of layoutKeys) {\n layouts.push({dir: keyToDir(key), key})\n }\n\n for (const key of pageKeys) {\n const pattern = keyToRoutePattern(key, pagesDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n pages.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n\n pages.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {pages, layouts}\n return cache\n}\n\nexport function collectLayoutChain(pageKey: string, layouts: Layout[]): Layout[] {\n const pageDir = keyToDir(pageKey)\n\n return layouts\n .filter(layout => pageDir.startsWith(layout.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchPage(pathname: string, pages: Page[]): {\n page: Page\n params: Record<string, string>\n} | null {\n for (const page of pages) {\n const match = pathname.match(page.regex)\n if (match) {\n const params: Record<string, string> = {}\n page.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {page, params}\n }\n }\n return null\n}\n", "import {routePattern} from \"../utils/patterns\";\n\nexport interface ApiRoute {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface ApiMiddleware {\n dir: string\n key: string\n}\n\nexport interface ApiResult {\n routes: ApiRoute[]\n middlewares: ApiMiddleware[]\n}\n\nfunction keyToRoutePattern(key: string, apiDir: string): string {\n const rel = key.slice(apiDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === '/' ? '/api' : `/api/${pattern}`.replace('/api//', '/api/')\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: ApiResult | null = null\n\nexport function invalidateApiCache() {\n cache = null\n}\n\nexport function buildRoutes(routeKeys: string[], middlewareKeys: string[], apiDir: string): ApiResult {\n if (cache) return cache\n\n const routes: ApiRoute[] = []\n const middlewares: ApiMiddleware[] = []\n\n for (const key of middlewareKeys) {\n middlewares.push({dir: keyToDir(key), key})\n }\n\n for (const key of routeKeys) {\n const pattern = keyToRoutePattern(key, apiDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n routes.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n routes.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {routes, middlewares}\n return cache\n}\n\nexport function collectMiddlewareChain(routeKey: string, middlewares: ApiMiddleware[]): ApiMiddleware[] {\n const routeDir = keyToDir(routeKey)\n\n return middlewares\n .filter(mw => routeDir.startsWith(mw.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchRoute(\n pathname: string,\n routes: ApiRoute[]\n): {route: ApiRoute; params: Record<string, string>} | null {\n for (const route of routes) {\n const match = pathname.match(route.regex)\n if (match) {\n const params: Record<string, string> = {}\n route.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {route, params}\n }\n }\n return null\n}\n", "import {LayoutModule, PageModule} from \"../server\";\nimport {LoaderContext, Metadata, Viewport} from \"../types\"\n\nexport interface ResolvedMeta {\n metadata: Metadata\n viewport?: Viewport\n}\n\nexport async function resolveMetadata(module: PageModule | LayoutModule, ctx: LoaderContext & {\n loaderData: unknown\n}): Promise<ResolvedMeta> {\n const metadata = module.generateMetadata\n ? await module.generateMetadata(ctx)\n : module.metadata ?? {}\n\n const viewport = module.generateViewport\n ? await module.generateViewport(ctx)\n : module.viewport\n\n return {metadata, viewport}\n}\n\nexport function mergeMetadata(...sources: (Metadata | null | undefined)[]): Metadata {\n const result: Metadata = {}\n\n for (const source of sources) {\n if (!source) continue\n const { og, twitter, ...rest } = source\n Object.assign(result, rest)\n if (og) result.og = { ...result.og, ...og }\n if (twitter) result.twitter = { ...result.twitter, ...twitter }\n }\n\n return result\n}"],
5
+ "mappings": "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",
6
+ "names": ["keyToRoutePattern", "keyToDir", "cache", "cache", "keyToDir", "keyToRoutePattern"]
7
+ }
@@ -0,0 +1,21 @@
1
+ export interface Page {
2
+ path: string;
3
+ key: string;
4
+ params: string[];
5
+ regex: RegExp;
6
+ }
7
+ export interface Layout {
8
+ dir: string;
9
+ key: string;
10
+ }
11
+ export interface PagesResult {
12
+ pages: Page[];
13
+ layouts: Layout[];
14
+ }
15
+ export declare function invalidatePagesCache(): void;
16
+ export declare function buildPages(pageKeys: string[], layoutKeys: string[], pagesDir: string): PagesResult;
17
+ export declare function collectLayoutChain(pageKey: string, layouts: Layout[]): Layout[];
18
+ export declare function matchPage(pathname: string, pages: Page[]): {
19
+ page: Page;
20
+ params: Record<string, string>;
21
+ } | null;
@@ -0,0 +1,64 @@
1
+ // src/utils/patterns.ts
2
+ function routePattern(rel) {
3
+ return rel.replace(/\.(tsx|ts|jsx|js)$/, "").replace(/\(.*?\)\//g, "").replace(/^index$|\/index$/, "").replace(/\[([^\]]+)]/g, ":$1") || "/";
4
+ }
5
+
6
+ // src/server/pages-router.ts
7
+ function keyToRoutePattern(key, pagesDir) {
8
+ const rel = key.slice(pagesDir.length + 1).replace(/\\/g, "/");
9
+ const pattern = routePattern(rel);
10
+ return pattern === "/" ? "/" : `/${pattern}`;
11
+ }
12
+ function keyToDir(key) {
13
+ return key.slice(0, key.lastIndexOf("/"));
14
+ }
15
+ var cache = null;
16
+ function invalidatePagesCache() {
17
+ cache = null;
18
+ }
19
+ function buildPages(pageKeys, layoutKeys, pagesDir) {
20
+ if (cache) return cache;
21
+ const pages = [];
22
+ const layouts = [];
23
+ for (const key of layoutKeys) {
24
+ layouts.push({ dir: keyToDir(key), key });
25
+ }
26
+ for (const key of pageKeys) {
27
+ const pattern = keyToRoutePattern(key, pagesDir);
28
+ const params = [...pattern.matchAll(/:([^/]+)/g)].map((m) => m[1]);
29
+ const regexStr = pattern.replace(/:[^/]+/g, "([^/]+)").replace(/\//g, "\\/");
30
+ pages.push({ path: pattern, key, params, regex: new RegExp(`^${regexStr}$`) });
31
+ }
32
+ pages.sort((a, b) => {
33
+ const aScore = (a.path.match(/:/g) || []).length;
34
+ const bScore = (b.path.match(/:/g) || []).length;
35
+ if (aScore !== bScore) return aScore - bScore;
36
+ return b.path.length - a.path.length;
37
+ });
38
+ cache = { pages, layouts };
39
+ return cache;
40
+ }
41
+ function collectLayoutChain(pageKey, layouts) {
42
+ const pageDir = keyToDir(pageKey);
43
+ return layouts.filter((layout) => pageDir.startsWith(layout.dir)).sort((a, b) => a.dir.split("/").length - b.dir.split("/").length);
44
+ }
45
+ function matchPage(pathname, pages) {
46
+ for (const page of pages) {
47
+ const match = pathname.match(page.regex);
48
+ if (match) {
49
+ const params = {};
50
+ page.params.forEach((name, i) => {
51
+ params[name] = decodeURIComponent(match[i + 1]);
52
+ });
53
+ return { page, params };
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+ export {
59
+ buildPages,
60
+ collectLayoutChain,
61
+ invalidatePagesCache,
62
+ matchPage
63
+ };
64
+ //# sourceMappingURL=pages-router.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/patterns.ts", "../../src/server/pages-router.ts"],
4
+ "sourcesContent": ["export function routePattern(rel: string): string {\n return rel\n .replace(/\\.(tsx|ts|jsx|js)$/, '')\n .replace(/\\(.*?\\)\\//g, '')\n .replace(/^index$|\\/index$/, '')\n .replace(/\\[([^\\]]+)]/g, ':$1')\n || '/'\n}", "import {routePattern} from \"../utils/patterns\";\n\nexport interface Page {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface Layout {\n dir: string\n key: string\n}\n\nexport interface PagesResult {\n pages: Page[]\n layouts: Layout[]\n}\n\nfunction keyToRoutePattern(key: string, pagesDir: string): string {\n const rel = key.slice(pagesDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === \"/\" ? \"/\" : `/${pattern}`\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: PagesResult | null = null\n\nexport function invalidatePagesCache() {\n cache = null\n}\n\nexport function buildPages(pageKeys: string[], layoutKeys: string[], pagesDir: string): PagesResult {\n if (cache) return cache\n\n const pages: Page[] = []\n const layouts: Layout[] = []\n\n for (const key of layoutKeys) {\n layouts.push({dir: keyToDir(key), key})\n }\n\n for (const key of pageKeys) {\n const pattern = keyToRoutePattern(key, pagesDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n pages.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n\n pages.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {pages, layouts}\n return cache\n}\n\nexport function collectLayoutChain(pageKey: string, layouts: Layout[]): Layout[] {\n const pageDir = keyToDir(pageKey)\n\n return layouts\n .filter(layout => pageDir.startsWith(layout.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchPage(pathname: string, pages: Page[]): {\n page: Page\n params: Record<string, string>\n} | null {\n for (const page of pages) {\n const match = pathname.match(page.regex)\n if (match) {\n const params: Record<string, string> = {}\n page.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {page, params}\n }\n }\n return null\n}\n"],
5
+ "mappings": ";AAAO,SAAS,aAAa,KAAqB;AAC9C,SAAO,IACE,QAAQ,sBAAsB,EAAE,EAChC,QAAQ,cAAc,EAAE,EACxB,QAAQ,oBAAoB,EAAE,EAC9B,QAAQ,gBAAgB,KAAK,KAC/B;AACX;;;ACYA,SAAS,kBAAkB,KAAa,UAA0B;AAC9D,QAAM,MAAM,IAAI,MAAM,SAAS,SAAS,CAAC,EAAE,QAAQ,OAAO,GAAG;AAC7D,QAAM,UAAU,aAAa,GAAG;AAChC,SAAO,YAAY,MAAM,MAAM,IAAI,OAAO;AAC9C;AAEA,SAAS,SAAS,KAAqB;AACnC,SAAO,IAAI,MAAM,GAAG,IAAI,YAAY,GAAG,CAAC;AAC5C;AAEA,IAAI,QAA4B;AAEzB,SAAS,uBAAuB;AACnC,UAAQ;AACZ;AAEO,SAAS,WAAW,UAAoB,YAAsB,UAA+B;AAChG,MAAI,MAAO,QAAO;AAElB,QAAM,QAAgB,CAAC;AACvB,QAAM,UAAoB,CAAC;AAE3B,aAAW,OAAO,YAAY;AAC1B,YAAQ,KAAK,EAAC,KAAK,SAAS,GAAG,GAAG,IAAG,CAAC;AAAA,EAC1C;AAEA,aAAW,OAAO,UAAU;AACxB,UAAM,UAAU,kBAAkB,KAAK,QAAQ;AAC/C,UAAM,SAAS,CAAC,GAAG,QAAQ,SAAS,WAAW,CAAC,EAAE,IAAI,OAAK,EAAE,CAAC,CAAC;AAC/D,UAAM,WAAW,QACZ,QAAQ,WAAW,SAAS,EAC5B,QAAQ,OAAO,KAAK;AACzB,UAAM,KAAK,EAAC,MAAM,SAAS,KAAK,QAAQ,OAAO,IAAI,OAAO,IAAI,QAAQ,GAAG,EAAC,CAAC;AAAA,EAC/E;AAEA,QAAM,KAAK,CAAC,GAAG,MAAM;AACjB,UAAM,UAAU,EAAE,KAAK,MAAM,IAAI,KAAK,CAAC,GAAG;AAC1C,UAAM,UAAU,EAAE,KAAK,MAAM,IAAI,KAAK,CAAC,GAAG;AAC1C,QAAI,WAAW,OAAQ,QAAO,SAAS;AACvC,WAAO,EAAE,KAAK,SAAS,EAAE,KAAK;AAAA,EAClC,CAAC;AAED,UAAQ,EAAC,OAAO,QAAO;AACvB,SAAO;AACX;AAEO,SAAS,mBAAmB,SAAiB,SAA6B;AAC7E,QAAM,UAAU,SAAS,OAAO;AAEhC,SAAO,QACF,OAAO,YAAU,QAAQ,WAAW,OAAO,GAAG,CAAC,EAC/C,KAAK,CAAC,GAAG,MAAM,EAAE,IAAI,MAAM,GAAG,EAAE,SAAS,EAAE,IAAI,MAAM,GAAG,EAAE,MAAM;AACzE;AAEO,SAAS,UAAU,UAAkB,OAGnC;AACL,aAAW,QAAQ,OAAO;AACtB,UAAM,QAAQ,SAAS,MAAM,KAAK,KAAK;AACvC,QAAI,OAAO;AACP,YAAM,SAAiC,CAAC;AACxC,WAAK,OAAO,QAAQ,CAAC,MAAM,MAAM;AAC7B,eAAO,IAAI,IAAI,mBAAmB,MAAM,IAAI,CAAC,CAAC;AAAA,MAClD,CAAC;AACD,aAAO,EAAC,MAAM,OAAM;AAAA,IACxB;AAAA,EACJ;AACA,SAAO;AACX;",
6
+ "names": []
7
+ }
@@ -0,0 +1,34 @@
1
+ import type { PageGlob } from './types';
2
+ import type { Manifest } from "vite";
3
+ export declare function runLoader(url: string, request: Request, glob: PageGlob, options?: {
4
+ loaderTimeout?: number;
5
+ }): Promise<{
6
+ loaderData: null;
7
+ params: {};
8
+ layouts: never[];
9
+ metadata: null;
10
+ viewport: undefined;
11
+ } | {
12
+ loaderData: unknown;
13
+ params: Record<string, string>;
14
+ layouts: {
15
+ loaderData: unknown;
16
+ }[];
17
+ metadata: import("../types").Metadata;
18
+ viewport: import("../types").Viewport | undefined;
19
+ }>;
20
+ export declare function render(url: string, request: Request, glob: PageGlob, options?: {
21
+ manifest?: Manifest;
22
+ loaderTimeout?: number;
23
+ }): Promise<{
24
+ html: string;
25
+ statusCode: number;
26
+ headers: {
27
+ Location: string | undefined;
28
+ };
29
+ } | {
30
+ html: string;
31
+ statusCode: number;
32
+ headers: Record<string, string>;
33
+ }>;
34
+ export declare function getStaticRoutes(glob: PageGlob): Promise<string[]>;
@@ -0,0 +1,306 @@
1
+ // src/server/render.tsx
2
+ import { createElement } from "react";
3
+ import { renderToString, renderToStaticMarkup } from "react-dom/server";
4
+
5
+ // src/runtime/head.tsx
6
+ import { Fragment, jsx } from "react/jsx-runtime";
7
+ function collectTags(metadata, viewport) {
8
+ const tags = [];
9
+ if (metadata.title)
10
+ tags.push({ tag: "title", children: metadata.title });
11
+ if (metadata.description)
12
+ tags.push({ tag: "meta", name: "description", content: metadata.description });
13
+ if (metadata.keywords?.length)
14
+ tags.push({ tag: "meta", name: "keywords", content: metadata.keywords.join(", ") });
15
+ const ogTitle = metadata.og?.title ?? metadata.title;
16
+ if (ogTitle) tags.push({ tag: "meta", property: "og:title", content: ogTitle });
17
+ const ogDesc = metadata.og?.description ?? metadata.description;
18
+ if (ogDesc) tags.push({ tag: "meta", property: "og:description", content: ogDesc });
19
+ if (metadata.og?.image) tags.push({ tag: "meta", property: "og:image", content: metadata.og.image });
20
+ if (metadata.og?.type) tags.push({ tag: "meta", property: "og:type", content: metadata.og.type });
21
+ if (metadata.og?.url) tags.push({ tag: "meta", property: "og:url", content: metadata.og.url });
22
+ const twTitle = metadata.twitter?.title ?? metadata.title;
23
+ if (twTitle) tags.push({ tag: "meta", name: "twitter:title", content: twTitle });
24
+ const twDesc = metadata.twitter?.description ?? metadata.description;
25
+ if (twDesc) tags.push({ tag: "meta", name: "twitter:description", content: twDesc });
26
+ if (metadata.twitter?.card) tags.push({
27
+ tag: "meta",
28
+ name: "twitter:card",
29
+ content: metadata.twitter.card
30
+ });
31
+ if (metadata.twitter?.image) tags.push({
32
+ tag: "meta",
33
+ name: "twitter:image",
34
+ content: metadata.twitter.image
35
+ });
36
+ if (metadata.twitter?.creator) tags.push({
37
+ tag: "meta",
38
+ name: "twitter:creator",
39
+ content: metadata.twitter.creator
40
+ });
41
+ if (metadata.canonical) tags.push({ tag: "link", rel: "canonical", href: metadata.canonical });
42
+ if (metadata.robots) tags.push({ tag: "meta", name: "robots", content: metadata.robots });
43
+ if (metadata.alternates) {
44
+ for (const [lang, href] of Object.entries(metadata.alternates))
45
+ tags.push({ tag: "link", rel: "alternate", href, hrefLang: lang });
46
+ }
47
+ if (viewport) {
48
+ const parts = [];
49
+ if (viewport.width !== void 0) parts.push(`width=${viewport.width}`);
50
+ if (viewport.initialScale !== void 0) parts.push(`initial-scale=${viewport.initialScale}`);
51
+ if (viewport.maximumScale !== void 0) parts.push(`maximum-scale=${viewport.maximumScale}`);
52
+ if (viewport.userScalable !== void 0) parts.push(`user-scalable=${viewport.userScalable ? "yes" : "no"}`);
53
+ if (parts.length) tags.push({ tag: "meta", name: "viewport", content: parts.join(", ") });
54
+ if (viewport.themeColor) tags.push({
55
+ tag: "meta",
56
+ name: "theme-color",
57
+ content: viewport.themeColor
58
+ });
59
+ }
60
+ return tags;
61
+ }
62
+ function buildHeadNodes(metadata, viewport) {
63
+ const tags = collectTags(metadata, viewport);
64
+ return /* @__PURE__ */ jsx(Fragment, { children: tags.map((t, i) => {
65
+ if (t.tag === "title") return /* @__PURE__ */ jsx("title", { children: t.children }, i);
66
+ if (t.tag === "link") return /* @__PURE__ */ jsx("link", { rel: t.rel, href: t.href, hrefLang: t.hrefLang }, i);
67
+ return /* @__PURE__ */ jsx("meta", { name: t.name, property: t.property, content: t.content }, i);
68
+ }) });
69
+ }
70
+
71
+ // src/utils/patterns.ts
72
+ function routePattern(rel) {
73
+ return rel.replace(/\.(tsx|ts|jsx|js)$/, "").replace(/\(.*?\)\//g, "").replace(/^index$|\/index$/, "").replace(/\[([^\]]+)]/g, ":$1") || "/";
74
+ }
75
+
76
+ // src/server/pages-router.ts
77
+ function keyToRoutePattern(key, pagesDir) {
78
+ const rel = key.slice(pagesDir.length + 1).replace(/\\/g, "/");
79
+ const pattern = routePattern(rel);
80
+ return pattern === "/" ? "/" : `/${pattern}`;
81
+ }
82
+ function keyToDir(key) {
83
+ return key.slice(0, key.lastIndexOf("/"));
84
+ }
85
+ var cache = null;
86
+ function buildPages(pageKeys, layoutKeys, pagesDir) {
87
+ if (cache) return cache;
88
+ const pages = [];
89
+ const layouts = [];
90
+ for (const key of layoutKeys) {
91
+ layouts.push({ dir: keyToDir(key), key });
92
+ }
93
+ for (const key of pageKeys) {
94
+ const pattern = keyToRoutePattern(key, pagesDir);
95
+ const params = [...pattern.matchAll(/:([^/]+)/g)].map((m) => m[1]);
96
+ const regexStr = pattern.replace(/:[^/]+/g, "([^/]+)").replace(/\//g, "\\/");
97
+ pages.push({ path: pattern, key, params, regex: new RegExp(`^${regexStr}$`) });
98
+ }
99
+ pages.sort((a, b) => {
100
+ const aScore = (a.path.match(/:/g) || []).length;
101
+ const bScore = (b.path.match(/:/g) || []).length;
102
+ if (aScore !== bScore) return aScore - bScore;
103
+ return b.path.length - a.path.length;
104
+ });
105
+ cache = { pages, layouts };
106
+ return cache;
107
+ }
108
+ function collectLayoutChain(pageKey, layouts) {
109
+ const pageDir = keyToDir(pageKey);
110
+ return layouts.filter((layout) => pageDir.startsWith(layout.dir)).sort((a, b) => a.dir.split("/").length - b.dir.split("/").length);
111
+ }
112
+ function matchPage(pathname, pages) {
113
+ for (const page of pages) {
114
+ const match = pathname.match(page.regex);
115
+ if (match) {
116
+ const params = {};
117
+ page.params.forEach((name, i) => {
118
+ params[name] = decodeURIComponent(match[i + 1]);
119
+ });
120
+ return { page, params };
121
+ }
122
+ }
123
+ return null;
124
+ }
125
+
126
+ // src/runtime/metadata.ts
127
+ async function resolveMetadata(module, ctx) {
128
+ const metadata = module.generateMetadata ? await module.generateMetadata(ctx) : module.metadata ?? {};
129
+ const viewport = module.generateViewport ? await module.generateViewport(ctx) : module.viewport;
130
+ return { metadata, viewport };
131
+ }
132
+ function mergeMetadata(...sources) {
133
+ const result = {};
134
+ for (const source of sources) {
135
+ if (!source) continue;
136
+ const { og, twitter, ...rest } = source;
137
+ Object.assign(result, rest);
138
+ if (og) result.og = { ...result.og, ...og };
139
+ if (twitter) result.twitter = { ...result.twitter, ...twitter };
140
+ }
141
+ return result;
142
+ }
143
+
144
+ // src/runtime/context.tsx
145
+ import { createContext } from "react";
146
+ var g = globalThis;
147
+ g.__devix_RouterContext__ ??= createContext(null);
148
+ var RouterContext = g.__devix_RouterContext__;
149
+ g.__devix_PageMetaContext__ ??= createContext(null);
150
+ g.__devix_RouteDataContext__ ??= createContext(null);
151
+ var PageMetaContext = g.__devix_PageMetaContext__;
152
+ var RouteDataContext = g.__devix_RouteDataContext__;
153
+
154
+ // src/utils/html.ts
155
+ function safeJsonStringify(value) {
156
+ return JSON.stringify(value).replace(/<\/script>/gi, "<\\/script>");
157
+ }
158
+ function escapeAttr(value) {
159
+ return value.replace(/"/g, "&quot;");
160
+ }
161
+
162
+ // src/utils/async.ts
163
+ function withTimeout(promise, ms) {
164
+ let timer;
165
+ return Promise.race([
166
+ promise.finally(() => clearTimeout(timer)),
167
+ new Promise((_, reject) => {
168
+ timer = setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms);
169
+ })
170
+ ]);
171
+ }
172
+
173
+ // src/server/render.tsx
174
+ var DEV_CLIENT_ENTRY = "/@id/virtual:devix/entry-client";
175
+ async function resolvePageData(pathname, request, glob, timeout) {
176
+ const { pages, layouts } = buildPages(Object.keys(glob.pages), Object.keys(glob.layouts), glob.pagesDir);
177
+ const matched = matchPage(pathname, pages);
178
+ if (!matched) return null;
179
+ const { page, params } = matched;
180
+ const layoutChain = collectLayoutChain(page.key, layouts);
181
+ const ctx = { params, request };
182
+ const pageMod = await glob.pages[page.key]();
183
+ if (pageMod.guard) {
184
+ const redirect = await pageMod.guard(ctx);
185
+ if (redirect) return { redirect };
186
+ }
187
+ const loaderData = pageMod.loader ? await withTimeout(pageMod.loader(ctx), timeout) : null;
188
+ const layoutMods = await Promise.all(
189
+ layoutChain.map((l) => glob.layouts[l.key]())
190
+ );
191
+ const layoutsData = await withTimeout(
192
+ Promise.all(layoutMods.map((mod) => mod.loader ? mod.loader(ctx) : null)),
193
+ timeout
194
+ );
195
+ const pageMeta = await resolveMetadata(pageMod, { ...ctx, loaderData });
196
+ const layoutsMeta = await Promise.all(
197
+ layoutMods.map((mod, i) => resolveMetadata(mod, { ...ctx, loaderData: layoutsData[i] }))
198
+ );
199
+ const metadata = mergeMetadata(...layoutsMeta.map((m) => m.metadata), pageMeta.metadata);
200
+ const viewport = pageMeta.viewport ?? layoutsMeta.findLast((m) => m.viewport)?.viewport;
201
+ const rootLayoutMod = layoutMods[0];
202
+ const lang = rootLayoutMod?.generateLang ? await rootLayoutMod.generateLang({ ...ctx, loaderData }) : rootLayoutMod?.lang ?? "en";
203
+ return { pageMod, layoutMods, params, loaderData, layoutsData, metadata, viewport, lang };
204
+ }
205
+ async function runLoader(url, request, glob, options) {
206
+ const { pathname } = new URL(url, "http://localhost");
207
+ let result;
208
+ try {
209
+ const timeout = options?.loaderTimeout ?? 1e4;
210
+ result = await resolvePageData(pathname, request, glob, timeout);
211
+ } catch (err) {
212
+ console.error("[devix] render error:", err);
213
+ return { loaderData: null, params: {}, layouts: [], metadata: null, viewport: void 0 };
214
+ }
215
+ if (!result || "redirect" in result) {
216
+ return { loaderData: null, params: {}, layouts: [], metadata: null, viewport: void 0 };
217
+ }
218
+ const { loaderData, params, layoutsData, metadata, viewport } = result;
219
+ return {
220
+ loaderData,
221
+ params,
222
+ layouts: layoutsData.map((loaderData2) => ({ loaderData: loaderData2 })),
223
+ metadata,
224
+ viewport
225
+ };
226
+ }
227
+ async function render(url, request, glob, options) {
228
+ const clientEntry = options?.manifest ? `/${Object.values(options.manifest).find((chunk) => chunk.isEntry)?.file}` : DEV_CLIENT_ENTRY;
229
+ const cssFiles = options?.manifest ? Object.values(options.manifest).find((chunk) => chunk.isEntry)?.css ?? [] : [];
230
+ const cssLinks = cssFiles.map((f) => `<link rel="stylesheet" href="/${f}">`).join("");
231
+ const { pathname } = new URL(url, "http://localhost");
232
+ let result;
233
+ try {
234
+ const timeout = options?.loaderTimeout ?? 1e4;
235
+ result = await resolvePageData(pathname, request, glob, timeout);
236
+ } catch (err) {
237
+ console.error("[devix] render error:", err);
238
+ const html2 = `<html lang="en"><head><meta charset="utf-8">${cssLinks}</head><body><script>window.__DEVIX__=null;window.__LOADER_DATA__=null;window.__LAYOUTS_DATA__=[];</script><script type="module" src="${clientEntry}"></script><div id="devix-root"></div></body></html>`;
239
+ return { html: html2, statusCode: 500, headers: {} };
240
+ }
241
+ if (!result) {
242
+ const dataScript2 = `<script>window.__DEVIX__=${safeJsonStringify({
243
+ metadata: null,
244
+ viewport: void 0,
245
+ clientEntry
246
+ })};window.__LOADER_DATA__=null;window.__LAYOUTS_DATA__=[];</script>`;
247
+ const clientScript2 = `<script type="module" src="${clientEntry}"></script>`;
248
+ const html2 = `<html lang="en"><head><meta charset="utf-8">${cssLinks}${dataScript2}</head><body><div id="devix-root"></div>${clientScript2}</body></html>`;
249
+ return { html: html2, statusCode: 404, headers: {} };
250
+ }
251
+ if ("redirect" in result) {
252
+ return { html: "", statusCode: 302, headers: { Location: result.redirect } };
253
+ }
254
+ const { pageMod, layoutMods, params, loaderData, layoutsData, metadata, viewport, lang } = result;
255
+ let tree = createElement(
256
+ RouteDataContext,
257
+ { value: { loaderData, params } },
258
+ createElement(pageMod.default, { data: loaderData, params, url: pathname })
259
+ );
260
+ for (let i = layoutMods.length - 1; i >= 0; i--) {
261
+ const layoutData = layoutsData[i];
262
+ tree = createElement(
263
+ RouteDataContext,
264
+ { value: { loaderData: layoutData, params } },
265
+ createElement(layoutMods[i].default, { data: layoutData, params }, tree)
266
+ );
267
+ }
268
+ const content = renderToString(tree);
269
+ const headTags = metadata ? renderToStaticMarkup(buildHeadNodes(metadata, viewport)) : "";
270
+ const dataScript = `<script>window.__DEVIX__=${safeJsonStringify({
271
+ metadata,
272
+ viewport,
273
+ clientEntry
274
+ })};window.__LOADER_DATA__=${safeJsonStringify(loaderData)};window.__LAYOUTS_DATA__=${safeJsonStringify(layoutsData)};</script>`;
275
+ const clientScript = `<script type="module" src="${clientEntry}"></script>`;
276
+ const customHeaders = pageMod.headers ?? {};
277
+ const html = `<html lang="${escapeAttr(lang)}"><head><meta charset="utf-8">${headTags}${cssLinks}${dataScript}</head><body><div id="devix-root">${content}</div>${clientScript}</body></html>`;
278
+ return { html, statusCode: 200, headers: customHeaders };
279
+ }
280
+ async function getStaticRoutes(glob) {
281
+ const { pages } = buildPages(Object.keys(glob.pages), Object.keys(glob.layouts), glob.pagesDir);
282
+ const urls = [];
283
+ for (const page of pages) {
284
+ if (page.params.length === 0) {
285
+ urls.push(page.path);
286
+ } else {
287
+ const mod = await glob.pages[page.key]();
288
+ if (!mod.generateStaticParams) continue;
289
+ const paramSets = await mod.generateStaticParams();
290
+ for (const params of paramSets) {
291
+ let url = page.path;
292
+ for (const [key, value] of Object.entries(params)) {
293
+ url = url.replace(`:${key}`, encodeURIComponent(value));
294
+ }
295
+ urls.push(url);
296
+ }
297
+ }
298
+ }
299
+ return urls;
300
+ }
301
+ export {
302
+ getStaticRoutes,
303
+ render,
304
+ runLoader
305
+ };
306
+ //# sourceMappingURL=render.js.map