theokit 0.1.0-alpha.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.
- package/dist/build-NSKFOAFX.js +49 -0
- package/dist/build-NSKFOAFX.js.map +1 -0
- package/dist/chunk-ASGEGAWL.js +480 -0
- package/dist/chunk-ASGEGAWL.js.map +1 -0
- package/dist/chunk-ATSTRYYT.js +894 -0
- package/dist/chunk-ATSTRYYT.js.map +1 -0
- package/dist/chunk-KPU44T6G.js +71 -0
- package/dist/chunk-KPU44T6G.js.map +1 -0
- package/dist/chunk-MMZZBPMX.js +335 -0
- package/dist/chunk-MMZZBPMX.js.map +1 -0
- package/dist/chunk-N5YH2UDG.js +85 -0
- package/dist/chunk-N5YH2UDG.js.map +1 -0
- package/dist/chunk-SAVVU5LG.js +66 -0
- package/dist/chunk-SAVVU5LG.js.map +1 -0
- package/dist/chunk-TXMUCDJT.js +43 -0
- package/dist/chunk-TXMUCDJT.js.map +1 -0
- package/dist/chunk-U3OJFWK3.js +162 -0
- package/dist/chunk-U3OJFWK3.js.map +1 -0
- package/dist/cli/index.js +79 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/client/index.d.ts +37 -0
- package/dist/client/index.js +57 -0
- package/dist/client/index.js.map +1 -0
- package/dist/cloudflare-CVGN7FOU.js +88 -0
- package/dist/cloudflare-CVGN7FOU.js.map +1 -0
- package/dist/dev-7UJK3M2O.js +47 -0
- package/dist/dev-7UJK3M2O.js.map +1 -0
- package/dist/docker-M253W54T.js +101 -0
- package/dist/docker-M253W54T.js.map +1 -0
- package/dist/generate-AA7ZE42F.js +116 -0
- package/dist/generate-AA7ZE42F.js.map +1 -0
- package/dist/index.d.ts +88 -0
- package/dist/index.js +171 -0
- package/dist/index.js.map +1 -0
- package/dist/rate-limit-C6hHXIj1.d.ts +13 -0
- package/dist/routes-YP357VAC.js +60 -0
- package/dist/routes-YP357VAC.js.map +1 -0
- package/dist/server/index.d.ts +94 -0
- package/dist/server/index.js +148 -0
- package/dist/server/index.js.map +1 -0
- package/dist/start-BIS3RCFQ.js +243 -0
- package/dist/start-BIS3RCFQ.js.map +1 -0
- package/dist/vercel-747SR2FB.js +80 -0
- package/dist/vercel-747SR2FB.js.map +1 -0
- package/dist/vite-plugin/index.d.ts +12 -0
- package/dist/vite-plugin/index.js +8 -0
- package/dist/vite-plugin/index.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
nodeAdapter
|
|
4
|
+
} from "./chunk-TXMUCDJT.js";
|
|
5
|
+
import "./chunk-ASGEGAWL.js";
|
|
6
|
+
import "./chunk-MMZZBPMX.js";
|
|
7
|
+
import {
|
|
8
|
+
validateProjectStructure
|
|
9
|
+
} from "./chunk-KPU44T6G.js";
|
|
10
|
+
import {
|
|
11
|
+
loadConfig
|
|
12
|
+
} from "./chunk-N5YH2UDG.js";
|
|
13
|
+
import "./chunk-U3OJFWK3.js";
|
|
14
|
+
|
|
15
|
+
// src/adapters/types.ts
|
|
16
|
+
var VALID_TARGETS = ["node", "vercel", "cloudflare"];
|
|
17
|
+
|
|
18
|
+
// src/cli/commands/build.ts
|
|
19
|
+
async function buildCommand(options) {
|
|
20
|
+
const cwd = process.cwd();
|
|
21
|
+
const config = await loadConfig(cwd);
|
|
22
|
+
validateProjectStructure(cwd);
|
|
23
|
+
const target = options?.target ?? "node";
|
|
24
|
+
if (!VALID_TARGETS.includes(target)) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Invalid build target "${target}". Available targets: ${VALID_TARGETS.join(", ")}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
console.log(`
|
|
30
|
+
Building for ${target}...
|
|
31
|
+
`);
|
|
32
|
+
if (target === "node") {
|
|
33
|
+
await nodeAdapter.build(config, cwd);
|
|
34
|
+
} else if (target === "vercel") {
|
|
35
|
+
const { vercelAdapter } = await import("./vercel-747SR2FB.js");
|
|
36
|
+
await vercelAdapter.build(config, cwd);
|
|
37
|
+
} else if (target === "cloudflare") {
|
|
38
|
+
const { cloudflareAdapter } = await import("./cloudflare-CVGN7FOU.js");
|
|
39
|
+
await cloudflareAdapter.build(config, cwd);
|
|
40
|
+
}
|
|
41
|
+
const ssrNote = config.ssr ? " (SSR)" : "";
|
|
42
|
+
console.log(`
|
|
43
|
+
\u2713 Build complete \u2192 ${target}${ssrNote}
|
|
44
|
+
`);
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
buildCommand
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=build-NSKFOAFX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/types.ts","../src/cli/commands/build.ts"],"sourcesContent":["import type { TheoConfig } from '../config/schema.js'\n\nexport interface DeployAdapter {\n name: string\n build(config: TheoConfig, cwd: string): Promise<void>\n}\n\nexport type BuildTarget = 'node' | 'vercel' | 'cloudflare'\n\nexport const VALID_TARGETS: BuildTarget[] = ['node', 'vercel', 'cloudflare']\n","import { loadConfig } from '../../config/load-config.js'\nimport { validateProjectStructure } from '../../core/validate-structure.js'\nimport { VALID_TARGETS, type BuildTarget } from '../../adapters/types.js'\nimport { nodeAdapter } from '../../adapters/node.js'\n\nexport async function buildCommand(options?: { target?: string }): Promise<void> {\n const cwd = process.cwd()\n const config = await loadConfig(cwd)\n validateProjectStructure(cwd)\n\n const target = (options?.target ?? 'node') as BuildTarget\n\n if (!VALID_TARGETS.includes(target)) {\n throw new Error(\n `Invalid build target \"${target}\". Available targets: ${VALID_TARGETS.join(', ')}`,\n )\n }\n\n console.log(`\\n Building for ${target}...\\n`)\n\n if (target === 'node') {\n await nodeAdapter.build(config, cwd)\n } else if (target === 'vercel') {\n const { vercelAdapter } = await import('../../adapters/vercel.js')\n await vercelAdapter.build(config, cwd)\n } else if (target === 'cloudflare') {\n const { cloudflareAdapter } = await import('../../adapters/cloudflare.js')\n await cloudflareAdapter.build(config, cwd)\n }\n\n const ssrNote = config.ssr ? ' (SSR)' : ''\n console.log(`\\n ✓ Build complete → ${target}${ssrNote}\\n`)\n}\n"],"mappings":";;;;;;;;;;;;;;;AASO,IAAM,gBAA+B,CAAC,QAAQ,UAAU,YAAY;;;ACJ3E,eAAsB,aAAa,SAA8C;AAC/E,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,SAAS,MAAM,WAAW,GAAG;AACnC,2BAAyB,GAAG;AAE5B,QAAM,SAAU,SAAS,UAAU;AAEnC,MAAI,CAAC,cAAc,SAAS,MAAM,GAAG;AACnC,UAAM,IAAI;AAAA,MACR,yBAAyB,MAAM,yBAAyB,cAAc,KAAK,IAAI,CAAC;AAAA,IAClF;AAAA,EACF;AAEA,UAAQ,IAAI;AAAA,iBAAoB,MAAM;AAAA,CAAO;AAE7C,MAAI,WAAW,QAAQ;AACrB,UAAM,YAAY,MAAM,QAAQ,GAAG;AAAA,EACrC,WAAW,WAAW,UAAU;AAC9B,UAAM,EAAE,cAAc,IAAI,MAAM,OAAO,sBAA0B;AACjE,UAAM,cAAc,MAAM,QAAQ,GAAG;AAAA,EACvC,WAAW,WAAW,cAAc;AAClC,UAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,0BAA8B;AACzE,UAAM,kBAAkB,MAAM,QAAQ,GAAG;AAAA,EAC3C;AAEA,QAAM,UAAU,OAAO,MAAM,WAAW;AACxC,UAAQ,IAAI;AAAA,iCAA0B,MAAM,GAAG,OAAO;AAAA,CAAI;AAC5D;","names":[]}
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createRateLimiter,
|
|
4
|
+
createViteLoader,
|
|
5
|
+
executeAction,
|
|
6
|
+
executeRoute,
|
|
7
|
+
logRequest,
|
|
8
|
+
sendError
|
|
9
|
+
} from "./chunk-MMZZBPMX.js";
|
|
10
|
+
import {
|
|
11
|
+
matchRoute,
|
|
12
|
+
scanServerActions,
|
|
13
|
+
scanServerRoutes,
|
|
14
|
+
scanWebSocketRoutes
|
|
15
|
+
} from "./chunk-U3OJFWK3.js";
|
|
16
|
+
|
|
17
|
+
// src/vite-plugin/index.ts
|
|
18
|
+
import { resolve as resolve2, basename, dirname } from "path";
|
|
19
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
20
|
+
import { fileURLToPath } from "url";
|
|
21
|
+
|
|
22
|
+
// src/router/scan.ts
|
|
23
|
+
import { readdirSync, statSync, existsSync } from "fs";
|
|
24
|
+
import { join, resolve } from "path";
|
|
25
|
+
|
|
26
|
+
// src/router/types.ts
|
|
27
|
+
var ROUTE_FILE_NAMES = [
|
|
28
|
+
"page",
|
|
29
|
+
"layout",
|
|
30
|
+
"error",
|
|
31
|
+
"loading",
|
|
32
|
+
"not-found"
|
|
33
|
+
];
|
|
34
|
+
var ROUTE_FILE_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js"];
|
|
35
|
+
var ROUTE_FILE_REGEX = /^(page|layout|error|loading|not-found)\.(tsx|ts|jsx|js)$/;
|
|
36
|
+
function isRouteFile(filename) {
|
|
37
|
+
return ROUTE_FILE_REGEX.test(filename);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/router/scan.ts
|
|
41
|
+
function toNodeKey(name) {
|
|
42
|
+
if (name === "not-found") return "notFound";
|
|
43
|
+
return name;
|
|
44
|
+
}
|
|
45
|
+
function setRouteFile(node, key, value) {
|
|
46
|
+
switch (key) {
|
|
47
|
+
case "page":
|
|
48
|
+
node.page = value;
|
|
49
|
+
break;
|
|
50
|
+
case "layout":
|
|
51
|
+
node.layout = value;
|
|
52
|
+
break;
|
|
53
|
+
case "error":
|
|
54
|
+
node.error = value;
|
|
55
|
+
break;
|
|
56
|
+
case "loading":
|
|
57
|
+
node.loading = value;
|
|
58
|
+
break;
|
|
59
|
+
case "notFound":
|
|
60
|
+
node.notFound = value;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function scanDir(dir, segment, routePath) {
|
|
65
|
+
const node = { segment, path: routePath, children: [] };
|
|
66
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
67
|
+
for (const name of ROUTE_FILE_NAMES) {
|
|
68
|
+
const key = toNodeKey(name);
|
|
69
|
+
if (node[key] !== void 0) continue;
|
|
70
|
+
for (const ext of ROUTE_FILE_EXTENSIONS) {
|
|
71
|
+
const filename = `${name}${ext}`;
|
|
72
|
+
if (existsSync(join(dir, filename))) {
|
|
73
|
+
setRouteFile(node, key, resolve(dir, filename));
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const entry of entries) {
|
|
79
|
+
if (!entry.isDirectory()) continue;
|
|
80
|
+
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
81
|
+
const childPath = routePath === "/" ? `/${entry.name}` : `${routePath}/${entry.name}`;
|
|
82
|
+
const child = scanDir(join(dir, entry.name), entry.name, childPath);
|
|
83
|
+
const hasRouteFile = child.page || child.layout || child.error || child.loading || child.notFound;
|
|
84
|
+
if (hasRouteFile || child.children.length > 0) {
|
|
85
|
+
node.children.push(child);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return node;
|
|
89
|
+
}
|
|
90
|
+
function scanRoutes(appDir) {
|
|
91
|
+
if (!existsSync(appDir)) {
|
|
92
|
+
throw new Error(`App directory does not exist: ${appDir}`);
|
|
93
|
+
}
|
|
94
|
+
if (!statSync(appDir).isDirectory()) {
|
|
95
|
+
throw new Error(`App path is not a directory: ${appDir}`);
|
|
96
|
+
}
|
|
97
|
+
return scanDir(appDir, "", "/");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/router/generate.ts
|
|
101
|
+
function normalizePath(p) {
|
|
102
|
+
return p.replace(/\\/g, "/");
|
|
103
|
+
}
|
|
104
|
+
function safeVarName(segment, prefix) {
|
|
105
|
+
const safe = segment.replace(/[^a-zA-Z0-9]/g, "_") || "root";
|
|
106
|
+
return `${prefix}_${safe}`;
|
|
107
|
+
}
|
|
108
|
+
function generateRouteManifest(tree) {
|
|
109
|
+
const imports = [];
|
|
110
|
+
let hasLayout = false;
|
|
111
|
+
function collectImports(node) {
|
|
112
|
+
const seg = node.segment || "root";
|
|
113
|
+
if (node.page) {
|
|
114
|
+
imports.push({
|
|
115
|
+
varName: safeVarName(seg, "Page"),
|
|
116
|
+
importPath: normalizePath(node.page)
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (node.layout) {
|
|
120
|
+
hasLayout = true;
|
|
121
|
+
imports.push({
|
|
122
|
+
varName: safeVarName(seg, "Layout"),
|
|
123
|
+
importPath: normalizePath(node.layout)
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
if (node.error) {
|
|
127
|
+
imports.push({
|
|
128
|
+
varName: safeVarName(seg, "Error"),
|
|
129
|
+
importPath: normalizePath(node.error)
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (node.loading) {
|
|
133
|
+
imports.push({
|
|
134
|
+
varName: safeVarName(seg, "Loading"),
|
|
135
|
+
importPath: normalizePath(node.loading)
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (node.notFound) {
|
|
139
|
+
imports.push({
|
|
140
|
+
varName: safeVarName(seg, "NotFound"),
|
|
141
|
+
importPath: normalizePath(node.notFound)
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
for (const child of node.children) {
|
|
145
|
+
collectImports(child);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
collectImports(tree);
|
|
149
|
+
const lines = [
|
|
150
|
+
`import React, { Suspense, lazy } from 'react'`
|
|
151
|
+
];
|
|
152
|
+
if (hasLayout) {
|
|
153
|
+
lines.push(`import { Outlet } from 'react-router'`);
|
|
154
|
+
}
|
|
155
|
+
lines.push("");
|
|
156
|
+
for (const imp of imports) {
|
|
157
|
+
lines.push(
|
|
158
|
+
`const ${imp.varName} = lazy(() => import('${imp.importPath}'))`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
lines.push("");
|
|
162
|
+
function genRouteConfig(node, isRoot) {
|
|
163
|
+
const seg = node.segment || "root";
|
|
164
|
+
const childConfigs = [];
|
|
165
|
+
if (node.page) {
|
|
166
|
+
const pageVar = safeVarName(seg, "Page");
|
|
167
|
+
let pageElement = `React.createElement(${pageVar})`;
|
|
168
|
+
if (node.loading) {
|
|
169
|
+
const loadVar = safeVarName(seg, "Loading");
|
|
170
|
+
pageElement = `React.createElement(Suspense, { fallback: React.createElement(${loadVar}) }, ${pageElement})`;
|
|
171
|
+
}
|
|
172
|
+
childConfigs.push(`{ index: true, element: ${pageElement} }`);
|
|
173
|
+
}
|
|
174
|
+
for (const child of node.children) {
|
|
175
|
+
childConfigs.push(genRouteConfig(child, false));
|
|
176
|
+
}
|
|
177
|
+
if (node.notFound) {
|
|
178
|
+
const nfVar = safeVarName(seg, "NotFound");
|
|
179
|
+
childConfigs.push(
|
|
180
|
+
`{ path: '*', element: React.createElement(${nfVar}) }`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
let childrenArray = `[${childConfigs.join(", ")}]`;
|
|
184
|
+
if (node.error) {
|
|
185
|
+
const errVar = safeVarName(seg, "Error");
|
|
186
|
+
childrenArray = `[{ errorElement: React.createElement(${errVar}), children: ${childrenArray} }]`;
|
|
187
|
+
}
|
|
188
|
+
if (node.layout) {
|
|
189
|
+
const layoutVar = safeVarName(seg, "Layout");
|
|
190
|
+
const pathPart = isRoot ? `path: '/'` : `path: '${node.segment}'`;
|
|
191
|
+
return `{ ${pathPart}, element: React.createElement(${layoutVar}), children: ${childrenArray} }`;
|
|
192
|
+
}
|
|
193
|
+
if (isRoot) {
|
|
194
|
+
if (childConfigs.length === 0 && !node.page) {
|
|
195
|
+
return `{ path: '/', children: [] }`;
|
|
196
|
+
}
|
|
197
|
+
return `{ path: '/', children: ${childrenArray} }`;
|
|
198
|
+
}
|
|
199
|
+
if (node.page && node.children.length === 0 && !node.error && !node.notFound) {
|
|
200
|
+
const pageVar = safeVarName(seg, "Page");
|
|
201
|
+
let pageElement = `React.createElement(${pageVar})`;
|
|
202
|
+
if (node.loading) {
|
|
203
|
+
const loadVar = safeVarName(seg, "Loading");
|
|
204
|
+
pageElement = `React.createElement(Suspense, { fallback: React.createElement(${loadVar}) }, ${pageElement})`;
|
|
205
|
+
}
|
|
206
|
+
return `{ path: '${node.segment}', element: ${pageElement} }`;
|
|
207
|
+
}
|
|
208
|
+
return `{ path: '${node.segment}', children: ${childrenArray} }`;
|
|
209
|
+
}
|
|
210
|
+
const routeConfig = genRouteConfig(tree, true);
|
|
211
|
+
lines.push(`export const routes = [${routeConfig}]`);
|
|
212
|
+
return lines.join("\n");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// src/router/entry.ts
|
|
216
|
+
function generateEntryClient(ssr) {
|
|
217
|
+
const rootMethod = ssr ? "hydrateRoot" : "createRoot";
|
|
218
|
+
const renderCall = ssr ? ` ${rootMethod}(el,
|
|
219
|
+
React.createElement(Suspense, { fallback: null },
|
|
220
|
+
React.createElement(RouterProvider, { router })
|
|
221
|
+
)
|
|
222
|
+
)` : ` ${rootMethod}(el).render(
|
|
223
|
+
React.createElement(Suspense, { fallback: null },
|
|
224
|
+
React.createElement(RouterProvider, { router })
|
|
225
|
+
)
|
|
226
|
+
)`;
|
|
227
|
+
return [
|
|
228
|
+
`import React, { Suspense } from 'react'`,
|
|
229
|
+
`import { ${rootMethod} } from 'react-dom/client'`,
|
|
230
|
+
`import { createBrowserRouter, RouterProvider } from 'react-router'`,
|
|
231
|
+
`import { routes } from '/@theo/route-manifest'`,
|
|
232
|
+
``,
|
|
233
|
+
`const router = createBrowserRouter(routes)`,
|
|
234
|
+
`const el = document.getElementById('root')`,
|
|
235
|
+
`if (el) {`,
|
|
236
|
+
renderCall,
|
|
237
|
+
`}`
|
|
238
|
+
].join("\n");
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// src/router/entry-server.ts
|
|
242
|
+
function generateEntryServer() {
|
|
243
|
+
return [
|
|
244
|
+
`import React from 'react'`,
|
|
245
|
+
`import { renderToPipeableStream } from 'react-dom/server'`,
|
|
246
|
+
`import { createStaticHandler, createStaticRouter, StaticRouterProvider } from 'react-router'`,
|
|
247
|
+
`import { PassThrough } from 'node:stream'`,
|
|
248
|
+
`import { routes } from '/@theo/route-manifest'`,
|
|
249
|
+
``,
|
|
250
|
+
`export async function render(url) {`,
|
|
251
|
+
` const handler = createStaticHandler(routes)`,
|
|
252
|
+
` const request = new Request('http://localhost' + url)`,
|
|
253
|
+
` const context = await handler.query(request)`,
|
|
254
|
+
``,
|
|
255
|
+
` if (context instanceof Response) {`,
|
|
256
|
+
` return { redirect: context }`,
|
|
257
|
+
` }`,
|
|
258
|
+
``,
|
|
259
|
+
` const router = createStaticRouter(handler.dataRoutes, context)`,
|
|
260
|
+
` const app = React.createElement(StaticRouterProvider, { router, context })`,
|
|
261
|
+
``,
|
|
262
|
+
` return new Promise((resolve, reject) => {`,
|
|
263
|
+
` let html = ''`,
|
|
264
|
+
` const passthrough = new PassThrough()`,
|
|
265
|
+
` passthrough.on('data', (chunk) => { html += chunk.toString() })`,
|
|
266
|
+
` passthrough.on('end', () => { resolve(html) })`,
|
|
267
|
+
` passthrough.on('error', reject)`,
|
|
268
|
+
``,
|
|
269
|
+
` const { pipe } = renderToPipeableStream(app, {`,
|
|
270
|
+
` onAllReady() { pipe(passthrough) },`,
|
|
271
|
+
` onShellError(err) { reject(err) },`,
|
|
272
|
+
` onError(err) { console.error('[SSR Error]', err) },`,
|
|
273
|
+
` })`,
|
|
274
|
+
` })`,
|
|
275
|
+
`}`
|
|
276
|
+
].join("\n");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/vite-plugin/api-middleware.ts
|
|
280
|
+
import { randomUUID } from "crypto";
|
|
281
|
+
function createApiMiddleware(vite, serverDir, rateLimitConfig) {
|
|
282
|
+
const loadModule = createViteLoader(vite);
|
|
283
|
+
const rateLimiter = rateLimitConfig ? createRateLimiter(rateLimitConfig) : null;
|
|
284
|
+
return async (req, res, next) => {
|
|
285
|
+
const url = req.url ?? "";
|
|
286
|
+
if (!url.startsWith("/api/")) {
|
|
287
|
+
return next();
|
|
288
|
+
}
|
|
289
|
+
const requestId = randomUUID();
|
|
290
|
+
const start = Date.now();
|
|
291
|
+
res.setHeader("x-request-id", requestId);
|
|
292
|
+
if (rateLimiter) {
|
|
293
|
+
const check = rateLimiter(req);
|
|
294
|
+
for (const [k, v] of Object.entries(check.headers)) res.setHeader(k, v);
|
|
295
|
+
if (check.limited) {
|
|
296
|
+
sendError(res, "RATE_LIMITED", "Too many requests", 429, void 0, requestId);
|
|
297
|
+
logRequest({ method: req.method ?? "GET", url, status: 429, duration: Date.now() - start, requestId });
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
const routes = scanServerRoutes(serverDir);
|
|
302
|
+
const match = matchRoute(url, routes);
|
|
303
|
+
if (!match) {
|
|
304
|
+
sendError(res, "NOT_FOUND", "API route not found", 404, void 0, requestId);
|
|
305
|
+
logRequest({ method: req.method ?? "GET", url, status: 404, duration: Date.now() - start, requestId });
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
309
|
+
await executeRoute(match.route, method, match.params, req, res, loadModule, serverDir, requestId);
|
|
310
|
+
logRequest({ method, url, status: res.statusCode, duration: Date.now() - start, requestId });
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/vite-plugin/action-middleware.ts
|
|
315
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
316
|
+
var PREFIX = "/api/__actions/";
|
|
317
|
+
function createActionMiddleware(vite, serverDir) {
|
|
318
|
+
const loadModule = createViteLoader(vite);
|
|
319
|
+
return async (req, res, next) => {
|
|
320
|
+
const url = req.url ?? "";
|
|
321
|
+
if (!url.startsWith(PREFIX)) {
|
|
322
|
+
return next();
|
|
323
|
+
}
|
|
324
|
+
const requestId = randomUUID2();
|
|
325
|
+
const start = Date.now();
|
|
326
|
+
res.setHeader("x-request-id", requestId);
|
|
327
|
+
const pathAfterPrefix = url.slice(PREFIX.length).split("?")[0];
|
|
328
|
+
const segments = pathAfterPrefix.split("/").filter(Boolean);
|
|
329
|
+
if (segments.length < 2) {
|
|
330
|
+
sendError(res, "BAD_REQUEST", "Action URL must be /api/__actions/{file}/{exportName}", 400, void 0, requestId);
|
|
331
|
+
logRequest({ method: req.method ?? "POST", url, status: 400, duration: Date.now() - start, requestId });
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const exportName = segments[segments.length - 1];
|
|
335
|
+
const actionPath = segments.slice(0, -1).join("/");
|
|
336
|
+
const actions = scanServerActions(serverDir);
|
|
337
|
+
const action = actions.find((a) => a.actionPath === actionPath);
|
|
338
|
+
if (!action) {
|
|
339
|
+
sendError(res, "NOT_FOUND", `Action file "${actionPath}" not found`, 404, void 0, requestId);
|
|
340
|
+
logRequest({ method: req.method ?? "POST", url, status: 404, duration: Date.now() - start, requestId });
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
await executeAction(action.filePath, exportName, req, res, loadModule, serverDir, requestId);
|
|
344
|
+
logRequest({ method: req.method ?? "POST", url, status: res.statusCode, duration: Date.now() - start, requestId });
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// src/vite-plugin/index.ts
|
|
349
|
+
var VIRTUAL_ENTRY_ID = "/@theo/entry-client";
|
|
350
|
+
var RESOLVED_ENTRY_ID = "\0@theo/entry-client";
|
|
351
|
+
var VIRTUAL_MANIFEST_ID = "/@theo/route-manifest";
|
|
352
|
+
var RESOLVED_MANIFEST_ID = "\0@theo/route-manifest";
|
|
353
|
+
var VIRTUAL_ENTRY_SERVER_ID = "/@theo/entry-server";
|
|
354
|
+
var RESOLVED_ENTRY_SERVER_ID = "\0@theo/entry-server";
|
|
355
|
+
function theoPlugin(rootOrOptions) {
|
|
356
|
+
const options = typeof rootOrOptions === "string" ? { root: rootOrOptions } : rootOrOptions ?? {};
|
|
357
|
+
const projectRoot = options.root ?? process.cwd();
|
|
358
|
+
const appDir = resolve2(projectRoot, "app");
|
|
359
|
+
const ssrEnabled = options.ssr ?? false;
|
|
360
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
361
|
+
const theoSrcDir = resolve2(currentDir, "..");
|
|
362
|
+
return {
|
|
363
|
+
name: "theo",
|
|
364
|
+
config() {
|
|
365
|
+
const ext = existsSync2(resolve2(theoSrcDir, "index.ts")) ? ".ts" : ".js";
|
|
366
|
+
return {
|
|
367
|
+
envPrefix: "THEO_PUBLIC_",
|
|
368
|
+
resolve: {
|
|
369
|
+
alias: [
|
|
370
|
+
{ find: "theokit/server", replacement: resolve2(theoSrcDir, `server/index${ext}`) },
|
|
371
|
+
{ find: "theokit", replacement: resolve2(theoSrcDir, `index${ext}`) }
|
|
372
|
+
]
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
},
|
|
376
|
+
resolveId(id) {
|
|
377
|
+
if (id === VIRTUAL_ENTRY_ID) return RESOLVED_ENTRY_ID;
|
|
378
|
+
if (id === VIRTUAL_MANIFEST_ID) return RESOLVED_MANIFEST_ID;
|
|
379
|
+
if (id === VIRTUAL_ENTRY_SERVER_ID) return RESOLVED_ENTRY_SERVER_ID;
|
|
380
|
+
},
|
|
381
|
+
load(id) {
|
|
382
|
+
if (id === RESOLVED_ENTRY_ID) {
|
|
383
|
+
return generateEntryClient(ssrEnabled);
|
|
384
|
+
}
|
|
385
|
+
if (id === RESOLVED_MANIFEST_ID) {
|
|
386
|
+
const tree = scanRoutes(appDir);
|
|
387
|
+
return generateRouteManifest(tree);
|
|
388
|
+
}
|
|
389
|
+
if (id === RESOLVED_ENTRY_SERVER_ID) {
|
|
390
|
+
return generateEntryServer();
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
configureServer(server) {
|
|
394
|
+
const serverDir = resolve2(projectRoot, "server");
|
|
395
|
+
server.middlewares.use(createActionMiddleware(server, serverDir));
|
|
396
|
+
server.middlewares.use(createApiMiddleware(server, serverDir, options.rateLimit));
|
|
397
|
+
if (ssrEnabled) {
|
|
398
|
+
server.middlewares.use(async (req, res, next) => {
|
|
399
|
+
const url = req.url ?? "/";
|
|
400
|
+
if (url.startsWith("/api/") || url.startsWith("/@") || url.startsWith("/node_modules/") || url.includes(".")) {
|
|
401
|
+
return next();
|
|
402
|
+
}
|
|
403
|
+
try {
|
|
404
|
+
const indexPath = resolve2(projectRoot, "index.html");
|
|
405
|
+
let template = readFileSync(indexPath, "utf-8");
|
|
406
|
+
template = await server.transformIndexHtml(url, template);
|
|
407
|
+
const mod = await server.ssrLoadModule(VIRTUAL_ENTRY_SERVER_ID);
|
|
408
|
+
const result = await mod.render(url);
|
|
409
|
+
if (result && typeof result === "object" && "redirect" in result) {
|
|
410
|
+
res.writeHead(302, { Location: result.redirect.headers.get("location") ?? "/" });
|
|
411
|
+
res.end();
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const ssrHtml = result;
|
|
415
|
+
const rootDivMatch = template.match(/<div id=["']root["'][^>]*>/);
|
|
416
|
+
if (!rootDivMatch) {
|
|
417
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
418
|
+
res.end(template);
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const splitIdx = template.indexOf(rootDivMatch[0]) + rootDivMatch[0].length;
|
|
422
|
+
const html = template.slice(0, splitIdx) + ssrHtml + template.slice(splitIdx);
|
|
423
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
424
|
+
res.end(html);
|
|
425
|
+
} catch (err) {
|
|
426
|
+
server.ssrFixStacktrace(err);
|
|
427
|
+
console.error("[SSR Dev Error]", err);
|
|
428
|
+
return next();
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
function handleRouteChange(filePath) {
|
|
433
|
+
if (!isRouteFile(basename(filePath))) return;
|
|
434
|
+
if (!filePath.startsWith(appDir)) return;
|
|
435
|
+
const mod = server.moduleGraph.getModuleById(RESOLVED_MANIFEST_ID);
|
|
436
|
+
if (mod) {
|
|
437
|
+
server.moduleGraph.invalidateModule(mod);
|
|
438
|
+
server.ws.send({ type: "full-reload" });
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
server.watcher.on("add", handleRouteChange);
|
|
442
|
+
server.watcher.on("unlink", handleRouteChange);
|
|
443
|
+
const wsRoutes = scanWebSocketRoutes(resolve2(projectRoot, "server"));
|
|
444
|
+
if (wsRoutes.length > 0 && server.httpServer) {
|
|
445
|
+
import("ws").then(({ WebSocketServer }) => {
|
|
446
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
447
|
+
server.httpServer.on("upgrade", async (request, socket, head) => {
|
|
448
|
+
const url = request.url ?? "/";
|
|
449
|
+
if (!url.startsWith("/ws/")) return;
|
|
450
|
+
const wsPath = url.split("?")[0];
|
|
451
|
+
const match = wsRoutes.find((r) => r.wsPath === wsPath);
|
|
452
|
+
if (!match) {
|
|
453
|
+
socket.destroy();
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
const mod = await server.ssrLoadModule(match.filePath);
|
|
458
|
+
const handler = mod.default ?? mod;
|
|
459
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
460
|
+
handler.onOpen?.(ws, request);
|
|
461
|
+
ws.on("message", (data) => handler.onMessage?.(ws, data.toString()));
|
|
462
|
+
ws.on("close", (code, reason) => handler.onClose?.(ws, code, reason));
|
|
463
|
+
ws.on("error", (err) => handler.onError?.(ws, err));
|
|
464
|
+
});
|
|
465
|
+
} catch {
|
|
466
|
+
socket.destroy();
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
}).catch(() => {
|
|
470
|
+
console.warn('[Theo] WebSocket routes found but "ws" package not installed. Run: npm install ws');
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
export {
|
|
478
|
+
theoPlugin
|
|
479
|
+
};
|
|
480
|
+
//# sourceMappingURL=chunk-ASGEGAWL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vite-plugin/index.ts","../src/router/scan.ts","../src/router/types.ts","../src/router/generate.ts","../src/router/entry.ts","../src/router/entry-server.ts","../src/vite-plugin/api-middleware.ts","../src/vite-plugin/action-middleware.ts"],"sourcesContent":["import type { Plugin } from 'vite'\nimport { resolve, basename, dirname } from 'node:path'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { scanRoutes } from '../router/scan.js'\nimport { generateRouteManifest } from '../router/generate.js'\nimport { generateEntryClient } from '../router/entry.js'\nimport { generateEntryServer } from '../router/entry-server.js'\nimport { isRouteFile } from '../router/types.js'\nimport { createApiMiddleware } from './api-middleware.js'\nimport { createActionMiddleware } from './action-middleware.js'\nimport { scanWebSocketRoutes } from '../server/ws-scan.js'\nimport type { RateLimitConfig } from '../server/rate-limit.js'\n\nconst VIRTUAL_ENTRY_ID = '/@theo/entry-client'\nconst RESOLVED_ENTRY_ID = '\\0@theo/entry-client'\nconst VIRTUAL_MANIFEST_ID = '/@theo/route-manifest'\nconst RESOLVED_MANIFEST_ID = '\\0@theo/route-manifest'\nconst VIRTUAL_ENTRY_SERVER_ID = '/@theo/entry-server'\nconst RESOLVED_ENTRY_SERVER_ID = '\\0@theo/entry-server'\n\nexport interface TheoPluginOptions {\n root?: string\n rateLimit?: RateLimitConfig\n ssr?: boolean\n}\n\nexport function theoPlugin(rootOrOptions?: string | TheoPluginOptions): Plugin {\n const options = typeof rootOrOptions === 'string' ? { root: rootOrOptions } : (rootOrOptions ?? {})\n const projectRoot = options.root ?? process.cwd()\n const appDir = resolve(projectRoot, 'app')\n const ssrEnabled = options.ssr ?? false\n\n // Resolve paths for SSR module loading\n const currentDir = dirname(fileURLToPath(import.meta.url))\n const theoSrcDir = resolve(currentDir, '..')\n\n return {\n name: 'theo',\n\n config() {\n // Detect whether we're running from source (.ts) or compiled dist (.js)\n const ext = existsSync(resolve(theoSrcDir, 'index.ts')) ? '.ts' : '.js'\n return {\n envPrefix: 'THEO_PUBLIC_',\n resolve: {\n alias: [\n { find: 'theokit/server', replacement: resolve(theoSrcDir, `server/index${ext}`) },\n { find: 'theokit', replacement: resolve(theoSrcDir, `index${ext}`) },\n ],\n },\n }\n },\n\n resolveId(id: string) {\n if (id === VIRTUAL_ENTRY_ID) return RESOLVED_ENTRY_ID\n if (id === VIRTUAL_MANIFEST_ID) return RESOLVED_MANIFEST_ID\n if (id === VIRTUAL_ENTRY_SERVER_ID) return RESOLVED_ENTRY_SERVER_ID\n },\n\n load(id: string) {\n if (id === RESOLVED_ENTRY_ID) {\n return generateEntryClient(ssrEnabled)\n }\n if (id === RESOLVED_MANIFEST_ID) {\n const tree = scanRoutes(appDir)\n return generateRouteManifest(tree)\n }\n if (id === RESOLVED_ENTRY_SERVER_ID) {\n return generateEntryServer()\n }\n },\n\n configureServer(server) {\n // Server middleware (action before API — more specific prefix first)\n const serverDir = resolve(projectRoot, 'server')\n server.middlewares.use(createActionMiddleware(server, serverDir))\n server.middlewares.use(createApiMiddleware(server, serverDir, options.rateLimit))\n\n // SSR dev middleware\n if (ssrEnabled) {\n server.middlewares.use(async (req, res, next) => {\n const url = req.url ?? '/'\n // Skip API, static, and HMR requests\n if (url.startsWith('/api/') || url.startsWith('/@') || url.startsWith('/node_modules/') || url.includes('.')) {\n return next()\n }\n\n try {\n const indexPath = resolve(projectRoot, 'index.html')\n let template = readFileSync(indexPath, 'utf-8')\n template = await server.transformIndexHtml(url, template)\n\n const mod = await server.ssrLoadModule(VIRTUAL_ENTRY_SERVER_ID)\n const result = await mod.render(url)\n\n if (result && typeof result === 'object' && 'redirect' in result) {\n res.writeHead(302, { Location: (result.redirect as Response).headers.get('location') ?? '/' })\n res.end()\n return\n }\n\n // render() returns HTML string — inject into template\n const ssrHtml = result as string\n const rootDivMatch = template.match(/<div id=[\"']root[\"'][^>]*>/)\n if (!rootDivMatch) {\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(template)\n return\n }\n\n const splitIdx = template.indexOf(rootDivMatch[0]) + rootDivMatch[0].length\n const html = template.slice(0, splitIdx) + ssrHtml + template.slice(splitIdx)\n\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(html)\n } catch (err) {\n server.ssrFixStacktrace(err as Error)\n console.error('[SSR Dev Error]', err)\n // Fallback to CSR\n return next()\n }\n })\n }\n\n // Frontend HMR watcher\n function handleRouteChange(filePath: string) {\n if (!isRouteFile(basename(filePath))) return\n if (!filePath.startsWith(appDir)) return\n\n const mod = server.moduleGraph.getModuleById(RESOLVED_MANIFEST_ID)\n if (mod) {\n server.moduleGraph.invalidateModule(mod)\n server.ws.send({ type: 'full-reload' })\n }\n }\n\n server.watcher.on('add', handleRouteChange)\n server.watcher.on('unlink', handleRouteChange)\n\n // WebSocket upgrade handler (dev mode)\n const wsRoutes = scanWebSocketRoutes(resolve(projectRoot, 'server'))\n if (wsRoutes.length > 0 && server.httpServer) {\n import('ws').then(({ WebSocketServer }) => {\n const wss = new WebSocketServer({ noServer: true })\n\n server.httpServer!.on('upgrade', async (request, socket, head) => {\n const url = request.url ?? '/'\n if (!url.startsWith('/ws/')) return // Let Vite handle HMR etc.\n\n const wsPath = url.split('?')[0]\n const match = wsRoutes.find(r => r.wsPath === wsPath)\n if (!match) { socket.destroy(); return }\n\n try {\n const mod = await server.ssrLoadModule(match.filePath)\n const handler = mod.default ?? mod\n\n wss.handleUpgrade(request, socket, head, (ws) => {\n handler.onOpen?.(ws, request)\n ws.on('message', (data: Buffer) => handler.onMessage?.(ws, data.toString()))\n ws.on('close', (code: number, reason: Buffer) => handler.onClose?.(ws, code, reason))\n ws.on('error', (err: Error) => handler.onError?.(ws, err))\n })\n } catch {\n socket.destroy()\n }\n })\n }).catch(() => {\n console.warn('[Theo] WebSocket routes found but \"ws\" package not installed. Run: npm install ws')\n })\n }\n },\n }\n}\n","import { readdirSync, statSync, existsSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\nimport type { RouteNode, RouteFileName } from './types.js'\nimport { ROUTE_FILE_NAMES, ROUTE_FILE_EXTENSIONS } from './types.js'\n\nfunction toNodeKey(name: RouteFileName): 'page' | 'layout' | 'error' | 'loading' | 'notFound' {\n if (name === 'not-found') return 'notFound'\n return name as 'page' | 'layout' | 'error' | 'loading'\n}\n\nfunction setRouteFile(node: RouteNode, key: 'page' | 'layout' | 'error' | 'loading' | 'notFound', value: string): void {\n switch (key) {\n case 'page': node.page = value; break\n case 'layout': node.layout = value; break\n case 'error': node.error = value; break\n case 'loading': node.loading = value; break\n case 'notFound': node.notFound = value; break\n }\n}\n\nfunction scanDir(dir: string, segment: string, routePath: string): RouteNode {\n const node: RouteNode = { segment, path: routePath, children: [] }\n\n const entries = readdirSync(dir, { withFileTypes: true })\n\n // Check route files with extension priority (.tsx > .ts > .jsx > .js)\n for (const name of ROUTE_FILE_NAMES) {\n const key = toNodeKey(name)\n if (node[key] !== undefined) continue\n for (const ext of ROUTE_FILE_EXTENSIONS) {\n const filename = `${name}${ext}`\n if (existsSync(join(dir, filename))) {\n setRouteFile(node, key, resolve(dir, filename))\n break\n }\n }\n }\n\n // Recurse into subdirectories\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue\n\n const childPath =\n routePath === '/' ? `/${entry.name}` : `${routePath}/${entry.name}`\n const child = scanDir(join(dir, entry.name), entry.name, childPath)\n\n // Prune empty nodes\n const hasRouteFile =\n child.page ||\n child.layout ||\n child.error ||\n child.loading ||\n child.notFound\n if (hasRouteFile || child.children.length > 0) {\n node.children.push(child)\n }\n }\n\n return node\n}\n\nexport function scanRoutes(appDir: string): RouteNode {\n if (!existsSync(appDir)) {\n throw new Error(`App directory does not exist: ${appDir}`)\n }\n if (!statSync(appDir).isDirectory()) {\n throw new Error(`App path is not a directory: ${appDir}`)\n }\n return scanDir(appDir, '', '/')\n}\n","export interface RouteNode {\n segment: string\n path: string\n page?: string\n layout?: string\n error?: string\n loading?: string\n notFound?: string\n children: RouteNode[]\n}\n\nexport const ROUTE_FILE_NAMES = [\n 'page',\n 'layout',\n 'error',\n 'loading',\n 'not-found',\n] as const\n\nexport type RouteFileName = (typeof ROUTE_FILE_NAMES)[number]\n\nexport const ROUTE_FILE_EXTENSIONS = ['.tsx', '.ts', '.jsx', '.js'] as const\n\nconst ROUTE_FILE_REGEX =\n /^(page|layout|error|loading|not-found)\\.(tsx|ts|jsx|js)$/\n\nexport function isRouteFile(filename: string): boolean {\n return ROUTE_FILE_REGEX.test(filename)\n}\n","import type { RouteNode } from './types.js'\n\nfunction normalizePath(p: string): string {\n return p.replace(/\\\\/g, '/')\n}\n\nfunction safeVarName(segment: string, prefix: string): string {\n const safe = segment.replace(/[^a-zA-Z0-9]/g, '_') || 'root'\n return `${prefix}_${safe}`\n}\n\ninterface ImportEntry {\n varName: string\n importPath: string\n}\n\nexport function generateRouteManifest(tree: RouteNode): string {\n const imports: ImportEntry[] = []\n let hasLayout = false\n\n function collectImports(node: RouteNode): void {\n const seg = node.segment || 'root'\n if (node.page) {\n imports.push({\n varName: safeVarName(seg, 'Page'),\n importPath: normalizePath(node.page),\n })\n }\n if (node.layout) {\n hasLayout = true\n imports.push({\n varName: safeVarName(seg, 'Layout'),\n importPath: normalizePath(node.layout),\n })\n }\n if (node.error) {\n imports.push({\n varName: safeVarName(seg, 'Error'),\n importPath: normalizePath(node.error),\n })\n }\n if (node.loading) {\n imports.push({\n varName: safeVarName(seg, 'Loading'),\n importPath: normalizePath(node.loading),\n })\n }\n if (node.notFound) {\n imports.push({\n varName: safeVarName(seg, 'NotFound'),\n importPath: normalizePath(node.notFound),\n })\n }\n for (const child of node.children) {\n collectImports(child)\n }\n }\n\n collectImports(tree)\n\n // Build import lines\n const lines: string[] = [\n `import React, { Suspense, lazy } from 'react'`,\n ]\n\n if (hasLayout) {\n lines.push(`import { Outlet } from 'react-router'`)\n }\n\n lines.push('')\n\n for (const imp of imports) {\n lines.push(\n `const ${imp.varName} = lazy(() => import('${imp.importPath}'))`,\n )\n }\n\n lines.push('')\n\n // Generate route config\n function genRouteConfig(node: RouteNode, isRoot: boolean): string {\n const seg = node.segment || 'root'\n const childConfigs: string[] = []\n\n // Index route for this node's page\n if (node.page) {\n const pageVar = safeVarName(seg, 'Page')\n let pageElement = `React.createElement(${pageVar})`\n if (node.loading) {\n const loadVar = safeVarName(seg, 'Loading')\n pageElement = `React.createElement(Suspense, { fallback: React.createElement(${loadVar}) }, ${pageElement})`\n }\n childConfigs.push(`{ index: true, element: ${pageElement} }`)\n }\n\n // Child routes\n for (const child of node.children) {\n childConfigs.push(genRouteConfig(child, false))\n }\n\n // Not-found wildcard (only at this level)\n if (node.notFound) {\n const nfVar = safeVarName(seg, 'NotFound')\n childConfigs.push(\n `{ path: '*', element: React.createElement(${nfVar}) }`,\n )\n }\n\n // Wrap children in error boundary (pathless wrapper) if error exists\n let childrenArray = `[${childConfigs.join(', ')}]`\n if (node.error) {\n const errVar = safeVarName(seg, 'Error')\n childrenArray = `[{ errorElement: React.createElement(${errVar}), children: ${childrenArray} }]`\n }\n\n // Build route object\n if (node.layout) {\n const layoutVar = safeVarName(seg, 'Layout')\n const pathPart = isRoot\n ? `path: '/'`\n : `path: '${node.segment}'`\n return `{ ${pathPart}, element: React.createElement(${layoutVar}), children: ${childrenArray} }`\n }\n\n // No layout — if root, wrap in path '/'\n if (isRoot) {\n if (childConfigs.length === 0 && !node.page) {\n return `{ path: '/', children: [] }`\n }\n // Root without layout: children are direct routes\n return `{ path: '/', children: ${childrenArray} }`\n }\n\n // Child segment without layout — just a route\n if (node.page && node.children.length === 0 && !node.error && !node.notFound) {\n const pageVar = safeVarName(seg, 'Page')\n let pageElement = `React.createElement(${pageVar})`\n if (node.loading) {\n const loadVar = safeVarName(seg, 'Loading')\n pageElement = `React.createElement(Suspense, { fallback: React.createElement(${loadVar}) }, ${pageElement})`\n }\n return `{ path: '${node.segment}', element: ${pageElement} }`\n }\n\n // Child with children but no layout\n return `{ path: '${node.segment}', children: ${childrenArray} }`\n }\n\n const routeConfig = genRouteConfig(tree, true)\n lines.push(`export const routes = [${routeConfig}]`)\n\n return lines.join('\\n')\n}\n","export function generateEntryClient(ssr?: boolean): string {\n const rootMethod = ssr ? 'hydrateRoot' : 'createRoot'\n const renderCall = ssr\n ? ` ${rootMethod}(el,\\n React.createElement(Suspense, { fallback: null },\\n React.createElement(RouterProvider, { router })\\n )\\n )`\n : ` ${rootMethod}(el).render(\\n React.createElement(Suspense, { fallback: null },\\n React.createElement(RouterProvider, { router })\\n )\\n )`\n\n return [\n `import React, { Suspense } from 'react'`,\n `import { ${rootMethod} } from 'react-dom/client'`,\n `import { createBrowserRouter, RouterProvider } from 'react-router'`,\n `import { routes } from '/@theo/route-manifest'`,\n ``,\n `const router = createBrowserRouter(routes)`,\n `const el = document.getElementById('root')`,\n `if (el) {`,\n renderCall,\n `}`,\n ].join('\\n')\n}\n","export function generateEntryServer(): string {\n return [\n `import React from 'react'`,\n `import { renderToPipeableStream } from 'react-dom/server'`,\n `import { createStaticHandler, createStaticRouter, StaticRouterProvider } from 'react-router'`,\n `import { PassThrough } from 'node:stream'`,\n `import { routes } from '/@theo/route-manifest'`,\n ``,\n `export async function render(url) {`,\n ` const handler = createStaticHandler(routes)`,\n ` const request = new Request('http://localhost' + url)`,\n ` const context = await handler.query(request)`,\n ``,\n ` if (context instanceof Response) {`,\n ` return { redirect: context }`,\n ` }`,\n ``,\n ` const router = createStaticRouter(handler.dataRoutes, context)`,\n ` const app = React.createElement(StaticRouterProvider, { router, context })`,\n ``,\n ` return new Promise((resolve, reject) => {`,\n ` let html = ''`,\n ` const passthrough = new PassThrough()`,\n ` passthrough.on('data', (chunk) => { html += chunk.toString() })`,\n ` passthrough.on('end', () => { resolve(html) })`,\n ` passthrough.on('error', reject)`,\n ``,\n ` const { pipe } = renderToPipeableStream(app, {`,\n ` onAllReady() { pipe(passthrough) },`,\n ` onShellError(err) { reject(err) },`,\n ` onError(err) { console.error('[SSR Error]', err) },`,\n ` })`,\n ` })`,\n `}`,\n ].join('\\n')\n}\n","import type { ViteDevServer, Connect } from 'vite'\nimport { randomUUID } from 'node:crypto'\nimport { scanServerRoutes } from '../server/scan.js'\nimport { matchRoute } from '../server/match.js'\nimport { executeRoute, sendError } from '../server/execute.js'\nimport { createViteLoader } from '../server/module-loader.js'\nimport { logRequest } from '../server/logger.js'\nimport { createRateLimiter } from '../server/rate-limit.js'\nimport type { RateLimitConfig } from '../server/rate-limit.js'\n\nexport function createApiMiddleware(\n vite: ViteDevServer,\n serverDir: string,\n rateLimitConfig?: RateLimitConfig,\n): Connect.NextHandleFunction {\n const loadModule = createViteLoader(vite)\n const rateLimiter = rateLimitConfig ? createRateLimiter(rateLimitConfig) : null\n\n return async (req, res, next) => {\n const url = req.url ?? ''\n if (!url.startsWith('/api/')) {\n return next()\n }\n\n const requestId = randomUUID()\n const start = Date.now()\n res.setHeader('x-request-id', requestId)\n\n // Rate limit check\n if (rateLimiter) {\n const check = rateLimiter(req)\n for (const [k, v] of Object.entries(check.headers)) res.setHeader(k, v)\n if (check.limited) {\n sendError(res, 'RATE_LIMITED', 'Too many requests', 429, undefined, requestId)\n logRequest({ method: req.method ?? 'GET', url, status: 429, duration: Date.now() - start, requestId })\n return\n }\n }\n\n const routes = scanServerRoutes(serverDir)\n const match = matchRoute(url, routes)\n\n if (!match) {\n sendError(res, 'NOT_FOUND', 'API route not found', 404, undefined, requestId)\n logRequest({ method: req.method ?? 'GET', url, status: 404, duration: Date.now() - start, requestId })\n return\n }\n\n const method = (req.method ?? 'GET').toUpperCase()\n await executeRoute(match.route, method, match.params, req, res, loadModule, serverDir, requestId)\n logRequest({ method, url, status: res.statusCode, duration: Date.now() - start, requestId })\n }\n}\n","import type { ViteDevServer, Connect } from 'vite'\nimport { randomUUID } from 'node:crypto'\nimport { scanServerActions } from '../server/action-scan.js'\nimport { executeAction } from '../server/action-execute.js'\nimport { sendError } from '../server/execute.js'\nimport { createViteLoader } from '../server/module-loader.js'\nimport { logRequest } from '../server/logger.js'\n\nconst PREFIX = '/api/__actions/'\n\nexport function createActionMiddleware(\n vite: ViteDevServer,\n serverDir: string,\n): Connect.NextHandleFunction {\n const loadModule = createViteLoader(vite)\n return async (req, res, next) => {\n const url = req.url ?? ''\n if (!url.startsWith(PREFIX)) {\n return next()\n }\n\n const requestId = randomUUID()\n const start = Date.now()\n res.setHeader('x-request-id', requestId)\n\n const pathAfterPrefix = url.slice(PREFIX.length).split('?')[0]\n const segments = pathAfterPrefix.split('/').filter(Boolean)\n\n if (segments.length < 2) {\n sendError(res, 'BAD_REQUEST', 'Action URL must be /api/__actions/{file}/{exportName}', 400, undefined, requestId)\n logRequest({ method: req.method ?? 'POST', url, status: 400, duration: Date.now() - start, requestId })\n return\n }\n\n const exportName = segments[segments.length - 1]\n const actionPath = segments.slice(0, -1).join('/')\n\n const actions = scanServerActions(serverDir)\n const action = actions.find((a) => a.actionPath === actionPath)\n\n if (!action) {\n sendError(res, 'NOT_FOUND', `Action file \"${actionPath}\" not found`, 404, undefined, requestId)\n logRequest({ method: req.method ?? 'POST', url, status: 404, duration: Date.now() - start, requestId })\n return\n }\n\n await executeAction(action.filePath, exportName, req, res, loadModule, serverDir, requestId)\n logRequest({ method: req.method ?? 'POST', url, status: res.statusCode, duration: Date.now() - start, requestId })\n }\n}\n"],"mappings":"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","names":["resolve","existsSync","randomUUID","randomUUID","resolve","existsSync"]}
|