@pyreon/zero 0.12.2 → 0.12.4
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/lib/actions.js +97 -0
- package/lib/actions.js.map +1 -0
- package/lib/ai.js +503 -0
- package/lib/ai.js.map +1 -0
- package/lib/api-routes.js +137 -0
- package/lib/api-routes.js.map +1 -0
- package/lib/compression.js +80 -0
- package/lib/compression.js.map +1 -0
- package/lib/cors.js +57 -0
- package/lib/cors.js.map +1 -0
- package/lib/csp.js +119 -0
- package/lib/csp.js.map +1 -0
- package/lib/env.js +217 -0
- package/lib/env.js.map +1 -0
- package/lib/favicon.js +424 -0
- package/lib/favicon.js.map +1 -0
- package/lib/i18n-routing.js +167 -0
- package/lib/i18n-routing.js.map +1 -0
- package/lib/index.js +340 -4015
- package/lib/index.js.map +1 -1
- package/lib/link.js +5 -0
- package/lib/link.js.map +1 -1
- package/lib/logger.js +78 -0
- package/lib/logger.js.map +1 -0
- package/lib/meta.js +310 -0
- package/lib/meta.js.map +1 -0
- package/lib/middleware.js +53 -0
- package/lib/middleware.js.map +1 -0
- package/lib/og-image.js +233 -0
- package/lib/og-image.js.map +1 -0
- package/lib/rate-limit.js +76 -0
- package/lib/rate-limit.js.map +1 -0
- package/lib/server.js +1534 -0
- package/lib/server.js.map +1 -0
- package/lib/testing.js +179 -0
- package/lib/testing.js.map +1 -0
- package/lib/theme.js +11 -2
- package/lib/theme.js.map +1 -1
- package/lib/types/actions.d.ts +27 -24
- package/lib/types/actions.d.ts.map +1 -1
- package/lib/types/ai.d.ts +76 -95
- package/lib/types/ai.d.ts.map +1 -1
- package/lib/types/api-routes.d.ts +37 -33
- package/lib/types/api-routes.d.ts.map +1 -1
- package/lib/types/cache.d.ts +26 -22
- package/lib/types/cache.d.ts.map +1 -1
- package/lib/types/client.d.ts +13 -9
- package/lib/types/client.d.ts.map +1 -1
- package/lib/types/compression.d.ts +14 -10
- package/lib/types/compression.d.ts.map +1 -1
- package/lib/types/config.d.ts +39 -4
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/cors.d.ts +20 -16
- package/lib/types/cors.d.ts.map +1 -1
- package/lib/types/csp.d.ts +42 -61
- package/lib/types/csp.d.ts.map +1 -1
- package/lib/types/env.d.ts +26 -26
- package/lib/types/env.d.ts.map +1 -1
- package/lib/types/favicon.d.ts +58 -54
- package/lib/types/favicon.d.ts.map +1 -1
- package/lib/types/font.d.ts +68 -65
- package/lib/types/font.d.ts.map +1 -1
- package/lib/types/i18n-routing.d.ts +43 -37
- package/lib/types/i18n-routing.d.ts.map +1 -1
- package/lib/types/image-plugin.d.ts +49 -45
- package/lib/types/image-plugin.d.ts.map +1 -1
- package/lib/types/image.d.ts +47 -36
- package/lib/types/image.d.ts.map +1 -1
- package/lib/types/index.d.ts +594 -56
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/link.d.ts +61 -56
- package/lib/types/link.d.ts.map +1 -1
- package/lib/types/logger.d.ts +37 -48
- package/lib/types/logger.d.ts.map +1 -1
- package/lib/types/meta.d.ts +145 -105
- package/lib/types/meta.d.ts.map +1 -1
- package/lib/types/middleware.d.ts +8 -4
- package/lib/types/middleware.d.ts.map +1 -1
- package/lib/types/og-image.d.ts +63 -59
- package/lib/types/og-image.d.ts.map +1 -1
- package/lib/types/rate-limit.d.ts +20 -16
- package/lib/types/rate-limit.d.ts.map +1 -1
- package/lib/types/script.d.ts +23 -19
- package/lib/types/script.d.ts.map +1 -1
- package/lib/types/seo.d.ts +47 -43
- package/lib/types/seo.d.ts.map +1 -1
- package/lib/types/server.d.ts +455 -0
- package/lib/types/server.d.ts.map +1 -0
- package/lib/types/testing.d.ts +64 -27
- package/lib/types/testing.d.ts.map +1 -1
- package/lib/types/theme.d.ts +22 -12
- package/lib/types/theme.d.ts.map +1 -1
- package/package.json +17 -12
- package/src/actions.ts +1 -3
- package/src/adapters/bun.ts +2 -0
- package/src/adapters/cloudflare.ts +2 -0
- package/src/adapters/netlify.ts +2 -0
- package/src/adapters/node.ts +2 -0
- package/src/adapters/validate.ts +16 -0
- package/src/adapters/vercel.ts +2 -0
- package/src/compression.ts +19 -3
- package/src/entry-server.ts +28 -5
- package/src/index.ts +20 -182
- package/src/link.tsx +6 -0
- package/src/meta.tsx +78 -16
- package/src/rate-limit.ts +11 -9
- package/src/server.ts +70 -0
- package/src/theme.tsx +12 -1
- package/src/vite-plugin.ts +5 -1
- package/lib/fs-router-Dil4IKZR.js +0 -290
- package/lib/fs-router-Dil4IKZR.js.map +0 -1
- package/lib/types/adapters/bun.d.ts +0 -6
- package/lib/types/adapters/bun.d.ts.map +0 -1
- package/lib/types/adapters/cloudflare.d.ts +0 -26
- package/lib/types/adapters/cloudflare.d.ts.map +0 -1
- package/lib/types/adapters/index.d.ts +0 -13
- package/lib/types/adapters/index.d.ts.map +0 -1
- package/lib/types/adapters/netlify.d.ts +0 -21
- package/lib/types/adapters/netlify.d.ts.map +0 -1
- package/lib/types/adapters/node.d.ts +0 -6
- package/lib/types/adapters/node.d.ts.map +0 -1
- package/lib/types/adapters/static.d.ts +0 -7
- package/lib/types/adapters/static.d.ts.map +0 -1
- package/lib/types/adapters/vercel.d.ts +0 -21
- package/lib/types/adapters/vercel.d.ts.map +0 -1
- package/lib/types/app.d.ts +0 -24
- package/lib/types/app.d.ts.map +0 -1
- package/lib/types/entry-server.d.ts +0 -37
- package/lib/types/entry-server.d.ts.map +0 -1
- package/lib/types/error-overlay.d.ts +0 -6
- package/lib/types/error-overlay.d.ts.map +0 -1
- package/lib/types/fs-router.d.ts +0 -47
- package/lib/types/fs-router.d.ts.map +0 -1
- package/lib/types/isr.d.ts +0 -9
- package/lib/types/isr.d.ts.map +0 -1
- package/lib/types/not-found.d.ts +0 -7
- package/lib/types/not-found.d.ts.map +0 -1
- package/lib/types/types.d.ts +0 -111
- package/lib/types/types.d.ts.map +0 -1
- package/lib/types/utils/use-intersection-observer.d.ts +0 -10
- package/lib/types/utils/use-intersection-observer.d.ts.map +0 -1
- package/lib/types/utils/with-headers.d.ts +0 -6
- package/lib/types/utils/with-headers.d.ts.map +0 -1
- package/lib/types/vite-plugin.d.ts +0 -17
- package/lib/types/vite-plugin.d.ts.map +0 -1
package/src/rate-limit.ts
CHANGED
|
@@ -51,18 +51,17 @@ export function rateLimitMiddleware(config: RateLimitConfig = {}): Middleware {
|
|
|
51
51
|
|
|
52
52
|
const windowMs = windowSec * 1000
|
|
53
53
|
const store = new Map<string, RateLimitEntry>()
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
const MAX_STORE_SIZE = 10000
|
|
55
|
+
let lastCleanup = Date.now()
|
|
56
|
+
|
|
57
|
+
// Inline cleanup — runs during request processing, no setInterval needed.
|
|
58
|
+
// Evicts expired entries when store exceeds half capacity or on window boundary.
|
|
59
|
+
function cleanupIfNeeded(now: number) {
|
|
60
|
+
if (store.size < MAX_STORE_SIZE / 2 && now - lastCleanup < windowMs) return
|
|
61
|
+
lastCleanup = now
|
|
58
62
|
for (const [key, entry] of store) {
|
|
59
63
|
if (entry.resetAt <= now) store.delete(key)
|
|
60
64
|
}
|
|
61
|
-
}, windowMs)
|
|
62
|
-
|
|
63
|
-
// Allow GC to clean up the interval
|
|
64
|
-
if (typeof cleanupInterval === 'object' && 'unref' in cleanupInterval) {
|
|
65
|
-
cleanupInterval.unref()
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
return (ctx: MiddlewareContext) => {
|
|
@@ -72,6 +71,9 @@ export function rateLimitMiddleware(config: RateLimitConfig = {}): Middleware {
|
|
|
72
71
|
|
|
73
72
|
const key = keyFn(ctx)
|
|
74
73
|
const now = Date.now()
|
|
74
|
+
|
|
75
|
+
cleanupIfNeeded(now)
|
|
76
|
+
|
|
75
77
|
let entry = store.get(key)
|
|
76
78
|
|
|
77
79
|
if (!entry || entry.resetAt <= now) {
|
package/src/server.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pyreon/zero/server — server-only exports.
|
|
3
|
+
*
|
|
4
|
+
* Import from this subpath for SSR, middleware, adapters, and build tools.
|
|
5
|
+
* These modules use node:fs, node:path, etc. and must NOT be imported
|
|
6
|
+
* in client-side code.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { createServer, createApp } from "@pyreon/zero/server"
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// ─── Server entry ───────────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
export type { CreateAppOptions } from "./app";
|
|
17
|
+
export { createApp } from "./app";
|
|
18
|
+
export type { CreateServerOptions } from "./entry-server";
|
|
19
|
+
export { createServer } from "./entry-server";
|
|
20
|
+
|
|
21
|
+
// ─── Config ─────────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
export { defineConfig, resolveConfig } from "./config";
|
|
24
|
+
|
|
25
|
+
// ─── File-system routing ────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
export type { GenerateRouteModuleOptions } from './fs-router'
|
|
28
|
+
export {
|
|
29
|
+
filePathToUrlPath,
|
|
30
|
+
generateMiddlewareModule,
|
|
31
|
+
generateRouteModule,
|
|
32
|
+
parseFileRoutes,
|
|
33
|
+
scanRouteFiles,
|
|
34
|
+
} from './fs-router'
|
|
35
|
+
|
|
36
|
+
// ─── ISR ────────────────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
export { createISRHandler } from "./isr";
|
|
39
|
+
|
|
40
|
+
// ─── Adapters ───────────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
bunAdapter,
|
|
44
|
+
cloudflareAdapter,
|
|
45
|
+
netlifyAdapter,
|
|
46
|
+
nodeAdapter,
|
|
47
|
+
resolveAdapter,
|
|
48
|
+
staticAdapter,
|
|
49
|
+
vercelAdapter,
|
|
50
|
+
} from "./adapters";
|
|
51
|
+
|
|
52
|
+
// ─── 404 ────────────────────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
export { render404Page } from "./not-found";
|
|
55
|
+
|
|
56
|
+
// ─── Middleware ──────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
export { compose, getContext } from "./middleware";
|
|
59
|
+
|
|
60
|
+
// ─── Vite plugin ────────────────────────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
export { zeroPlugin as default } from "./vite-plugin";
|
|
63
|
+
|
|
64
|
+
// ─── I18n server-only ───────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
createLocaleContext,
|
|
68
|
+
detectLocaleFromHeader,
|
|
69
|
+
i18nRouting,
|
|
70
|
+
} from "./i18n-routing";
|
package/src/theme.tsx
CHANGED
|
@@ -17,11 +17,22 @@ const STORAGE_KEY = 'zero-theme'
|
|
|
17
17
|
/** Reactive theme signal. */
|
|
18
18
|
export const theme = signal<Theme>('system')
|
|
19
19
|
|
|
20
|
+
/** SSR fallback when system preference can't be detected. Default: 'light'. */
|
|
21
|
+
let _ssrDefault: 'light' | 'dark' = 'light'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Set the default theme for SSR (when `matchMedia` is unavailable).
|
|
25
|
+
* Call once at server startup before rendering.
|
|
26
|
+
*/
|
|
27
|
+
export function setSSRThemeDefault(value: 'light' | 'dark'): void {
|
|
28
|
+
_ssrDefault = value
|
|
29
|
+
}
|
|
30
|
+
|
|
20
31
|
/** Computed resolved theme (what's actually applied). */
|
|
21
32
|
export function resolvedTheme(): 'light' | 'dark' {
|
|
22
33
|
const t = theme()
|
|
23
34
|
if (t === 'system') {
|
|
24
|
-
if (typeof window === 'undefined') return
|
|
35
|
+
if (typeof window === 'undefined') return _ssrDefault
|
|
25
36
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
|
26
37
|
}
|
|
27
38
|
return t
|
package/src/vite-plugin.ts
CHANGED
|
@@ -126,7 +126,11 @@ export function zeroPlugin(userConfig: ZeroConfig = {}): Plugin {
|
|
|
126
126
|
(handled) => {
|
|
127
127
|
if (!handled) next();
|
|
128
128
|
},
|
|
129
|
-
() =>
|
|
129
|
+
(err) => {
|
|
130
|
+
// oxlint-disable-next-line no-console
|
|
131
|
+
console.error('[zero] Error in 404 handler:', err);
|
|
132
|
+
next();
|
|
133
|
+
},
|
|
130
134
|
);
|
|
131
135
|
});
|
|
132
136
|
|
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
//#region \0rolldown/runtime.js
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __exportAll = (all, no_symbols) => {
|
|
4
|
-
let target = {};
|
|
5
|
-
for (var name in all) {
|
|
6
|
-
__defProp(target, name, {
|
|
7
|
-
get: all[name],
|
|
8
|
-
enumerable: true
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
if (!no_symbols) {
|
|
12
|
-
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
-
}
|
|
14
|
-
return target;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/fs-router.ts
|
|
19
|
-
var fs_router_exports = /* @__PURE__ */ __exportAll({
|
|
20
|
-
filePathToUrlPath: () => filePathToUrlPath,
|
|
21
|
-
generateMiddlewareModule: () => generateMiddlewareModule,
|
|
22
|
-
generateRouteModule: () => generateRouteModule,
|
|
23
|
-
parseFileRoutes: () => parseFileRoutes,
|
|
24
|
-
scanRouteFiles: () => scanRouteFiles
|
|
25
|
-
});
|
|
26
|
-
const ROUTE_EXTENSIONS = [
|
|
27
|
-
".tsx",
|
|
28
|
-
".jsx",
|
|
29
|
-
".ts",
|
|
30
|
-
".js"
|
|
31
|
-
];
|
|
32
|
-
/**
|
|
33
|
-
* Parse a set of file paths (relative to routes dir) into FileRoute objects.
|
|
34
|
-
*
|
|
35
|
-
* @param files Array of file paths like ["index.tsx", "users/[id].tsx"]
|
|
36
|
-
* @param defaultMode Default rendering mode from config
|
|
37
|
-
*/
|
|
38
|
-
function parseFileRoutes(files, defaultMode = "ssr") {
|
|
39
|
-
return files.filter((f) => ROUTE_EXTENSIONS.some((ext) => f.endsWith(ext))).map((filePath) => parseFilePath(filePath, defaultMode)).sort(sortRoutes);
|
|
40
|
-
}
|
|
41
|
-
function parseFilePath(filePath, defaultMode) {
|
|
42
|
-
let route = filePath;
|
|
43
|
-
for (const ext of ROUTE_EXTENSIONS) if (route.endsWith(ext)) {
|
|
44
|
-
route = route.slice(0, -ext.length);
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
const fileName = getFileName(route);
|
|
48
|
-
const isLayout = fileName === "_layout";
|
|
49
|
-
const isError = fileName === "_error";
|
|
50
|
-
const isLoading = fileName === "_loading";
|
|
51
|
-
const isNotFound = fileName === "_404" || fileName === "_not-found";
|
|
52
|
-
const isCatchAll = route.includes("[...");
|
|
53
|
-
const parts = route.split("/");
|
|
54
|
-
parts.pop();
|
|
55
|
-
const dirPath = parts.filter((s) => !(s.startsWith("(") && s.endsWith(")"))).join("/");
|
|
56
|
-
const urlPath = filePathToUrlPath(route);
|
|
57
|
-
return {
|
|
58
|
-
filePath,
|
|
59
|
-
urlPath,
|
|
60
|
-
dirPath,
|
|
61
|
-
depth: urlPath === "/" ? 0 : urlPath.split("/").filter(Boolean).length,
|
|
62
|
-
isLayout,
|
|
63
|
-
isError,
|
|
64
|
-
isLoading,
|
|
65
|
-
isNotFound,
|
|
66
|
-
isCatchAll,
|
|
67
|
-
renderMode: defaultMode
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Convert a file path (without extension) to a URL path pattern.
|
|
72
|
-
*
|
|
73
|
-
* Examples:
|
|
74
|
-
* "index" → "/"
|
|
75
|
-
* "about" → "/about"
|
|
76
|
-
* "users/index" → "/users"
|
|
77
|
-
* "users/[id]" → "/users/:id"
|
|
78
|
-
* "blog/[...slug]" → "/blog/:slug*"
|
|
79
|
-
* "(auth)/login" → "/login" (group stripped)
|
|
80
|
-
* "_layout" → "/" (layout marker)
|
|
81
|
-
*/
|
|
82
|
-
function filePathToUrlPath(filePath) {
|
|
83
|
-
const segments = filePath.split("/");
|
|
84
|
-
const urlSegments = [];
|
|
85
|
-
for (const seg of segments) {
|
|
86
|
-
if (seg.startsWith("(") && seg.endsWith(")")) continue;
|
|
87
|
-
if (seg === "_layout" || seg === "_error" || seg === "_loading" || seg === "_404" || seg === "_not-found") continue;
|
|
88
|
-
if (seg === "index") continue;
|
|
89
|
-
const catchAll = seg.match(/^\[\.\.\.(\w+)\]$/);
|
|
90
|
-
if (catchAll) {
|
|
91
|
-
urlSegments.push(`:${catchAll[1]}*`);
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
const dynamic = seg.match(/^\[(\w+)\]$/);
|
|
95
|
-
if (dynamic) {
|
|
96
|
-
urlSegments.push(`:${dynamic[1]}`);
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
urlSegments.push(seg);
|
|
100
|
-
}
|
|
101
|
-
return `/${urlSegments.join("/")}` || "/";
|
|
102
|
-
}
|
|
103
|
-
/** Sort routes: static before dynamic, catch-all last. */
|
|
104
|
-
function sortRoutes(a, b) {
|
|
105
|
-
if (a.isCatchAll !== b.isCatchAll) return a.isCatchAll ? 1 : -1;
|
|
106
|
-
if (a.isLayout !== b.isLayout) return a.isLayout ? -1 : 1;
|
|
107
|
-
const aDynamic = a.urlPath.includes(":");
|
|
108
|
-
if (aDynamic !== b.urlPath.includes(":")) return aDynamic ? 1 : -1;
|
|
109
|
-
return a.urlPath.localeCompare(b.urlPath);
|
|
110
|
-
}
|
|
111
|
-
function getFileName(filePath) {
|
|
112
|
-
const parts = filePath.split("/");
|
|
113
|
-
return parts[parts.length - 1] ?? "";
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Group flat file routes into a directory tree.
|
|
117
|
-
*/
|
|
118
|
-
function getOrCreateChild(node, segment) {
|
|
119
|
-
let child = node.children.get(segment);
|
|
120
|
-
if (!child) {
|
|
121
|
-
child = {
|
|
122
|
-
pages: [],
|
|
123
|
-
children: /* @__PURE__ */ new Map()
|
|
124
|
-
};
|
|
125
|
-
node.children.set(segment, child);
|
|
126
|
-
}
|
|
127
|
-
return child;
|
|
128
|
-
}
|
|
129
|
-
function resolveNode(root, dirPath) {
|
|
130
|
-
let node = root;
|
|
131
|
-
if (dirPath) for (const segment of dirPath.split("/")) node = getOrCreateChild(node, segment);
|
|
132
|
-
return node;
|
|
133
|
-
}
|
|
134
|
-
function placeRoute(node, route) {
|
|
135
|
-
if (route.isLayout) node.layout = route;
|
|
136
|
-
else if (route.isError) node.error = route;
|
|
137
|
-
else if (route.isLoading) node.loading = route;
|
|
138
|
-
else if (route.isNotFound) node.notFound = route;
|
|
139
|
-
else node.pages.push(route);
|
|
140
|
-
}
|
|
141
|
-
function buildRouteTree(routes) {
|
|
142
|
-
const root = {
|
|
143
|
-
pages: [],
|
|
144
|
-
children: /* @__PURE__ */ new Map()
|
|
145
|
-
};
|
|
146
|
-
for (const route of routes) placeRoute(resolveNode(root, route.dirPath), route);
|
|
147
|
-
return root;
|
|
148
|
-
}
|
|
149
|
-
function generateRouteModule(files, routesDir, options) {
|
|
150
|
-
const tree = buildRouteTree(parseFileRoutes(files));
|
|
151
|
-
const imports = [];
|
|
152
|
-
let importCounter = 0;
|
|
153
|
-
const useStaticImports = options?.staticImports ?? false;
|
|
154
|
-
function nextImport(filePath, exportName = "default") {
|
|
155
|
-
const name = `_${importCounter++}`;
|
|
156
|
-
const fullPath = `${routesDir}/${filePath}`;
|
|
157
|
-
if (exportName === "default") imports.push(`import ${name} from "${fullPath}"`);
|
|
158
|
-
else imports.push(`import { ${exportName} as ${name} } from "${fullPath}"`);
|
|
159
|
-
return name;
|
|
160
|
-
}
|
|
161
|
-
function nextLazy(filePath, loadingName, errorName) {
|
|
162
|
-
const name = `_${importCounter++}`;
|
|
163
|
-
const fullPath = `${routesDir}/${filePath}`;
|
|
164
|
-
if (useStaticImports) imports.push(`import ${name} from "${fullPath}"`);
|
|
165
|
-
else {
|
|
166
|
-
const opts = [];
|
|
167
|
-
if (loadingName) opts.push(`loading: ${loadingName}`);
|
|
168
|
-
if (errorName) opts.push(`error: ${errorName}`);
|
|
169
|
-
const optsStr = opts.length > 0 ? `, { ${opts.join(", ")} }` : "";
|
|
170
|
-
imports.push(`const ${name} = lazy(() => import("${fullPath}")${optsStr})`);
|
|
171
|
-
}
|
|
172
|
-
return name;
|
|
173
|
-
}
|
|
174
|
-
function nextModuleImport(filePath) {
|
|
175
|
-
const name = `_m${importCounter++}`;
|
|
176
|
-
const fullPath = `${routesDir}/${filePath}`;
|
|
177
|
-
imports.push(`import * as ${name} from "${fullPath}"`);
|
|
178
|
-
return name;
|
|
179
|
-
}
|
|
180
|
-
function generatePageRoute(page, indent, loadingName, errorName, notFoundName) {
|
|
181
|
-
const mod = nextModuleImport(page.filePath);
|
|
182
|
-
const comp = nextLazy(page.filePath, loadingName, errorName);
|
|
183
|
-
const props = [
|
|
184
|
-
`${indent} path: ${JSON.stringify(page.urlPath)}`,
|
|
185
|
-
`${indent} component: ${comp}`,
|
|
186
|
-
`${indent} loader: ${mod}.loader`,
|
|
187
|
-
`${indent} beforeEnter: ${mod}.guard`,
|
|
188
|
-
`${indent} meta: { ...${mod}.meta, renderMode: ${mod}.renderMode }`
|
|
189
|
-
];
|
|
190
|
-
if (errorName) props.push(`${indent} errorComponent: ${mod}.error || ${errorName}`);
|
|
191
|
-
if (notFoundName) props.push(`${indent} notFoundComponent: ${notFoundName}`);
|
|
192
|
-
return `${indent}{\n${props.join(",\n")}\n${indent}}`;
|
|
193
|
-
}
|
|
194
|
-
function wrapWithLayout(node, children, indent, errorName, notFoundName) {
|
|
195
|
-
const layout = node.layout;
|
|
196
|
-
const layoutMod = nextModuleImport(layout.filePath);
|
|
197
|
-
const layoutComp = nextImport(layout.filePath, "layout");
|
|
198
|
-
const props = [
|
|
199
|
-
`${indent}path: ${JSON.stringify(layout.urlPath)}`,
|
|
200
|
-
`${indent}component: ${layoutComp}`,
|
|
201
|
-
`${indent}loader: ${layoutMod}.loader`,
|
|
202
|
-
`${indent}beforeEnter: ${layoutMod}.guard`,
|
|
203
|
-
`${indent}meta: { ...${layoutMod}.meta, renderMode: ${layoutMod}.renderMode }`
|
|
204
|
-
];
|
|
205
|
-
if (errorName) props.push(`${indent}errorComponent: ${errorName}`);
|
|
206
|
-
if (notFoundName) props.push(`${indent}notFoundComponent: ${notFoundName}`);
|
|
207
|
-
if (children.length > 0) props.push(`${indent}children: [\n${children.join(",\n")}\n${indent}]`);
|
|
208
|
-
return `${indent}{\n${props.map((p) => ` ${p}`).join(",\n")}\n${indent}}`;
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Generate route definitions for a tree node.
|
|
212
|
-
*/
|
|
213
|
-
function generateNode(node, depth) {
|
|
214
|
-
const indent = " ".repeat(depth + 1);
|
|
215
|
-
const errorName = node.error ? nextImport(node.error.filePath) : void 0;
|
|
216
|
-
const loadingName = node.loading ? nextImport(node.loading.filePath) : void 0;
|
|
217
|
-
const notFoundName = node.notFound ? nextImport(node.notFound.filePath) : void 0;
|
|
218
|
-
const childRouteDefs = [];
|
|
219
|
-
for (const [, childNode] of node.children) childRouteDefs.push(...generateNode(childNode, depth + 1));
|
|
220
|
-
const allChildren = [...node.pages.map((page) => generatePageRoute(page, indent, loadingName, errorName, notFoundName)), ...childRouteDefs];
|
|
221
|
-
if (node.layout) return [wrapWithLayout(node, allChildren, indent, errorName, notFoundName)];
|
|
222
|
-
return allChildren;
|
|
223
|
-
}
|
|
224
|
-
const routeDefs = generateNode(tree, 0);
|
|
225
|
-
return [
|
|
226
|
-
`import { lazy } from "@pyreon/router"`,
|
|
227
|
-
"",
|
|
228
|
-
...imports,
|
|
229
|
-
"",
|
|
230
|
-
`function clean(routes) {`,
|
|
231
|
-
` return routes.map(r => {`,
|
|
232
|
-
` const c = {}`,
|
|
233
|
-
` for (const k in r) if (r[k] !== undefined) c[k] = r[k]`,
|
|
234
|
-
` if (c.children) c.children = clean(c.children)`,
|
|
235
|
-
` return c`,
|
|
236
|
-
` })`,
|
|
237
|
-
`}`,
|
|
238
|
-
"",
|
|
239
|
-
`export const routes = clean([`,
|
|
240
|
-
routeDefs.join(",\n"),
|
|
241
|
-
`])`
|
|
242
|
-
].join("\n");
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Generate a virtual module that maps URL patterns to their middleware exports.
|
|
246
|
-
* Used by the server entry to dispatch per-route middleware.
|
|
247
|
-
*/
|
|
248
|
-
function generateMiddlewareModule(files, routesDir) {
|
|
249
|
-
const routes = parseFileRoutes(files);
|
|
250
|
-
const imports = [];
|
|
251
|
-
const entries = [];
|
|
252
|
-
let counter = 0;
|
|
253
|
-
for (const route of routes) {
|
|
254
|
-
if (route.isLayout || route.isError || route.isLoading || route.isNotFound) continue;
|
|
255
|
-
const name = `_mw${counter++}`;
|
|
256
|
-
const fullPath = `${routesDir}/${route.filePath}`;
|
|
257
|
-
imports.push(`import { middleware as ${name} } from "${fullPath}"`);
|
|
258
|
-
entries.push(` { pattern: ${JSON.stringify(route.urlPath)}, middleware: ${name} }`);
|
|
259
|
-
}
|
|
260
|
-
return [
|
|
261
|
-
...imports,
|
|
262
|
-
"",
|
|
263
|
-
`export const routeMiddleware = [`,
|
|
264
|
-
entries.join(",\n"),
|
|
265
|
-
`].filter(e => e.middleware)`
|
|
266
|
-
].join("\n");
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Scan a directory for route files.
|
|
270
|
-
* Returns paths relative to the routes directory.
|
|
271
|
-
*/
|
|
272
|
-
async function scanRouteFiles(routesDir) {
|
|
273
|
-
const { readdir } = await import("node:fs/promises");
|
|
274
|
-
const { join, relative } = await import("node:path");
|
|
275
|
-
const files = [];
|
|
276
|
-
async function walk(dir) {
|
|
277
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
278
|
-
for (const entry of entries) {
|
|
279
|
-
const fullPath = join(dir, entry.name);
|
|
280
|
-
if (entry.isDirectory()) await walk(fullPath);
|
|
281
|
-
else if (ROUTE_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) files.push(relative(routesDir, fullPath));
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
await walk(routesDir);
|
|
285
|
-
return files;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
//#endregion
|
|
289
|
-
export { parseFileRoutes as a, generateRouteModule as i, fs_router_exports as n, scanRouteFiles as o, generateMiddlewareModule as r, filePathToUrlPath as t };
|
|
290
|
-
//# sourceMappingURL=fs-router-Dil4IKZR.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fs-router-Dil4IKZR.js","names":[],"sources":["../src/fs-router.ts"],"sourcesContent":["import type { FileRoute, RenderMode } from './types'\n\n// ─── File-system route conventions ──────────────────────────────────────────\n//\n// src/routes/\n// _layout.tsx → layout for all routes\n// index.tsx → /\n// about.tsx → /about\n// users/\n// _layout.tsx → layout for /users/*\n// _loading.tsx → loading fallback for /users/*\n// _error.tsx → error boundary for /users/*\n// index.tsx → /users\n// [id].tsx → /users/:id\n// [id]/\n// settings.tsx → /users/:id/settings\n// blog/\n// [...slug].tsx → /blog/* (catch-all)\n//\n// Conventions:\n// [param] → dynamic segment → :param\n// [...param] → catch-all → :param*\n// _layout → layout wrapper — must use <RouterView /> to render child routes\n// (props.children is NOT passed — the router handles nesting)\n// _error → error component\n// _loading → loading component\n// _404 → not-found component (renders on 404)\n// _not-found → alias for _404\n// (group) → route group (directory ignored in URL)\n\nconst ROUTE_EXTENSIONS = ['.tsx', '.jsx', '.ts', '.js']\n\n/**\n * Parse a set of file paths (relative to routes dir) into FileRoute objects.\n *\n * @param files Array of file paths like [\"index.tsx\", \"users/[id].tsx\"]\n * @param defaultMode Default rendering mode from config\n */\nexport function parseFileRoutes(files: string[], defaultMode: RenderMode = 'ssr'): FileRoute[] {\n return files\n .filter((f) => ROUTE_EXTENSIONS.some((ext) => f.endsWith(ext)))\n .map((filePath) => parseFilePath(filePath, defaultMode))\n .sort(sortRoutes)\n}\n\nfunction parseFilePath(filePath: string, defaultMode: RenderMode): FileRoute {\n // Remove extension\n let route = filePath\n for (const ext of ROUTE_EXTENSIONS) {\n if (route.endsWith(ext)) {\n route = route.slice(0, -ext.length)\n break\n }\n }\n\n const fileName = getFileName(route)\n const isLayout = fileName === '_layout'\n const isError = fileName === '_error'\n const isLoading = fileName === '_loading'\n const isNotFound = fileName === '_404' || fileName === '_not-found'\n const isCatchAll = route.includes('[...')\n\n // Get directory path (strip groups for consistent grouping)\n const parts = route.split('/')\n parts.pop() // remove filename\n const dirPath = parts.filter((s) => !(s.startsWith('(') && s.endsWith(')'))).join('/')\n\n // Convert file path to URL pattern\n const urlPath = filePathToUrlPath(route)\n const depth = urlPath === '/' ? 0 : urlPath.split('/').filter(Boolean).length\n\n return {\n filePath,\n urlPath,\n dirPath,\n depth,\n isLayout,\n isError,\n isLoading,\n isNotFound,\n isCatchAll,\n renderMode: defaultMode,\n }\n}\n\n/**\n * Convert a file path (without extension) to a URL path pattern.\n *\n * Examples:\n * \"index\" → \"/\"\n * \"about\" → \"/about\"\n * \"users/index\" → \"/users\"\n * \"users/[id]\" → \"/users/:id\"\n * \"blog/[...slug]\" → \"/blog/:slug*\"\n * \"(auth)/login\" → \"/login\" (group stripped)\n * \"_layout\" → \"/\" (layout marker)\n */\nexport function filePathToUrlPath(filePath: string): string {\n const segments = filePath.split('/')\n const urlSegments: string[] = []\n\n for (const seg of segments) {\n // Skip route groups \"(name)\"\n if (seg.startsWith('(') && seg.endsWith(')')) continue\n\n // Skip special files\n if (seg === '_layout' || seg === '_error' || seg === '_loading' || seg === '_404' || seg === '_not-found') continue\n\n // \"index\" maps to the parent path\n if (seg === 'index') continue\n\n // Catch-all: [...param] → :param*\n const catchAll = seg.match(/^\\[\\.\\.\\.(\\w+)\\]$/)\n if (catchAll) {\n urlSegments.push(`:${catchAll[1]}*`)\n continue\n }\n\n // Dynamic: [param] → :param\n const dynamic = seg.match(/^\\[(\\w+)\\]$/)\n if (dynamic) {\n urlSegments.push(`:${dynamic[1]}`)\n continue\n }\n\n urlSegments.push(seg)\n }\n\n const path = `/${urlSegments.join('/')}`\n return path || '/'\n}\n\n/** Sort routes: static before dynamic, catch-all last. */\nfunction sortRoutes(a: FileRoute, b: FileRoute): number {\n // Catch-all routes go last\n if (a.isCatchAll !== b.isCatchAll) return a.isCatchAll ? 1 : -1\n // Layouts go first within same depth\n if (a.isLayout !== b.isLayout) return a.isLayout ? -1 : 1\n // Static segments before dynamic\n const aDynamic = a.urlPath.includes(':')\n const bDynamic = b.urlPath.includes(':')\n if (aDynamic !== bDynamic) return aDynamic ? 1 : -1\n // Alphabetical\n return a.urlPath.localeCompare(b.urlPath)\n}\n\nfunction getFileName(filePath: string): string {\n const parts = filePath.split('/')\n return parts[parts.length - 1] ?? ''\n}\n\n// ─── Route generation (for Vite plugin) ─────────────────────────────────────\n\n/** Internal tree node for building nested route structures. */\ninterface RouteNode {\n /** Page routes at this directory level. */\n pages: FileRoute[]\n /** Layout file for this directory (if any). */\n layout?: FileRoute\n /** Error boundary file (if any). */\n error?: FileRoute\n /** Loading fallback file (if any). */\n loading?: FileRoute\n /** Not-found (404) file (if any). */\n notFound?: FileRoute\n /** Child directories. */\n children: Map<string, RouteNode>\n}\n\n/**\n * Group flat file routes into a directory tree.\n */\nfunction getOrCreateChild(node: RouteNode, segment: string): RouteNode {\n let child = node.children.get(segment)\n if (!child) {\n child = { pages: [], children: new Map() }\n node.children.set(segment, child)\n }\n return child\n}\n\nfunction resolveNode(root: RouteNode, dirPath: string): RouteNode {\n let node = root\n if (dirPath) {\n for (const segment of dirPath.split('/')) {\n node = getOrCreateChild(node, segment)\n }\n }\n return node\n}\n\nfunction placeRoute(node: RouteNode, route: FileRoute) {\n if (route.isLayout) node.layout = route\n else if (route.isError) node.error = route\n else if (route.isLoading) node.loading = route\n else if (route.isNotFound) node.notFound = route\n else node.pages.push(route)\n}\n\nfunction buildRouteTree(routes: FileRoute[]): RouteNode {\n const root: RouteNode = { pages: [], children: new Map() }\n for (const route of routes) {\n placeRoute(resolveNode(root, route.dirPath), route)\n }\n return root\n}\n\n/**\n * Generate a virtual module that exports a nested route tree.\n * Wires up layouts as parent routes with children, loaders, guards,\n * error/loading components, middleware, and meta from route module exports.\n */\nexport interface GenerateRouteModuleOptions {\n /**\n * When true, skip lazy() for route components and use static imports.\n * Use for SSG/prerender mode where all routes are rendered at build time\n * and code splitting provides no benefit. Avoids Rolldown warnings about\n * static + dynamic imports of the same module.\n */\n staticImports?: boolean\n}\n\nexport function generateRouteModule(\n files: string[],\n routesDir: string,\n options?: GenerateRouteModuleOptions,\n): string {\n const routes = parseFileRoutes(files)\n const tree = buildRouteTree(routes)\n const imports: string[] = []\n let importCounter = 0\n const useStaticImports = options?.staticImports ?? false\n\n function nextImport(filePath: string, exportName = 'default'): string {\n const name = `_${importCounter++}`\n const fullPath = `${routesDir}/${filePath}`\n if (exportName === 'default') {\n imports.push(`import ${name} from \"${fullPath}\"`)\n } else {\n imports.push(`import { ${exportName} as ${name} } from \"${fullPath}\"`)\n }\n return name\n }\n\n function nextLazy(filePath: string, loadingName?: string, errorName?: string): string {\n const name = `_${importCounter++}`\n const fullPath = `${routesDir}/${filePath}`\n\n if (useStaticImports) {\n // SSG mode: static import avoids Rolldown warnings about\n // static + dynamic imports of the same module\n imports.push(`import ${name} from \"${fullPath}\"`)\n } else {\n const opts: string[] = []\n if (loadingName) opts.push(`loading: ${loadingName}`)\n if (errorName) opts.push(`error: ${errorName}`)\n const optsStr = opts.length > 0 ? `, { ${opts.join(', ')} }` : ''\n imports.push(`const ${name} = lazy(() => import(\"${fullPath}\")${optsStr})`)\n }\n return name\n }\n\n function nextModuleImport(filePath: string): string {\n const name = `_m${importCounter++}`\n const fullPath = `${routesDir}/${filePath}`\n imports.push(`import * as ${name} from \"${fullPath}\"`)\n return name\n }\n\n function generatePageRoute(\n page: FileRoute,\n indent: string,\n loadingName: string | undefined,\n errorName: string | undefined,\n notFoundName: string | undefined,\n ): string {\n const mod = nextModuleImport(page.filePath)\n const comp = nextLazy(page.filePath, loadingName, errorName)\n\n const props: string[] = [\n `${indent} path: ${JSON.stringify(page.urlPath)}`,\n `${indent} component: ${comp}`,\n `${indent} loader: ${mod}.loader`,\n `${indent} beforeEnter: ${mod}.guard`,\n `${indent} meta: { ...${mod}.meta, renderMode: ${mod}.renderMode }`,\n ]\n\n // Only emit errorComponent when there's an actual _error file in scope\n // or the route module exports an error component. Avoids referencing\n // undefined .error exports that produce noisy bundler warnings.\n if (errorName) {\n props.push(`${indent} errorComponent: ${mod}.error || ${errorName}`)\n }\n\n if (notFoundName) {\n props.push(`${indent} notFoundComponent: ${notFoundName}`)\n }\n\n return `${indent}{\\n${props.join(',\\n')}\\n${indent}}`\n }\n\n function wrapWithLayout(\n node: RouteNode,\n children: string[],\n indent: string,\n errorName: string | undefined,\n notFoundName: string | undefined,\n ): string {\n const layout = node.layout as FileRoute\n const layoutMod = nextModuleImport(layout.filePath)\n const layoutComp = nextImport(layout.filePath, 'layout')\n\n const props: string[] = [\n `${indent}path: ${JSON.stringify(layout.urlPath)}`,\n `${indent}component: ${layoutComp}`,\n `${indent}loader: ${layoutMod}.loader`,\n `${indent}beforeEnter: ${layoutMod}.guard`,\n `${indent}meta: { ...${layoutMod}.meta, renderMode: ${layoutMod}.renderMode }`,\n ]\n if (errorName) {\n props.push(`${indent}errorComponent: ${errorName}`)\n }\n if (notFoundName) {\n props.push(`${indent}notFoundComponent: ${notFoundName}`)\n }\n if (children.length > 0) {\n props.push(`${indent}children: [\\n${children.join(',\\n')}\\n${indent}]`)\n }\n\n return `${indent}{\\n${props.map((p) => ` ${p}`).join(',\\n')}\\n${indent}}`\n }\n\n /**\n * Generate route definitions for a tree node.\n */\n function generateNode(node: RouteNode, depth: number): string[] {\n const indent = ' '.repeat(depth + 1)\n\n const errorName = node.error ? nextImport(node.error.filePath) : undefined\n const loadingName = node.loading ? nextImport(node.loading.filePath) : undefined\n const notFoundName = node.notFound ? nextImport(node.notFound.filePath) : undefined\n\n const childRouteDefs: string[] = []\n for (const [, childNode] of node.children) {\n childRouteDefs.push(...generateNode(childNode, depth + 1))\n }\n\n const pageRouteDefs = node.pages.map((page) =>\n generatePageRoute(page, indent, loadingName, errorName, notFoundName),\n )\n\n const allChildren = [...pageRouteDefs, ...childRouteDefs]\n\n if (node.layout) {\n return [wrapWithLayout(node, allChildren, indent, errorName, notFoundName)]\n }\n return allChildren\n }\n\n const routeDefs = generateNode(tree, 0)\n\n return [\n `import { lazy } from \"@pyreon/router\"`,\n '',\n ...imports,\n '',\n // Filter out undefined properties at runtime\n `function clean(routes) {`,\n ` return routes.map(r => {`,\n ` const c = {}`,\n ` for (const k in r) if (r[k] !== undefined) c[k] = r[k]`,\n ` if (c.children) c.children = clean(c.children)`,\n ` return c`,\n ` })`,\n `}`,\n '',\n `export const routes = clean([`,\n routeDefs.join(',\\n'),\n `])`,\n ].join('\\n')\n}\n\n/**\n * Generate a virtual module that maps URL patterns to their middleware exports.\n * Used by the server entry to dispatch per-route middleware.\n */\nexport function generateMiddlewareModule(files: string[], routesDir: string): string {\n const routes = parseFileRoutes(files)\n const imports: string[] = []\n const entries: string[] = []\n let counter = 0\n\n for (const route of routes) {\n if (route.isLayout || route.isError || route.isLoading || route.isNotFound) continue\n const name = `_mw${counter++}`\n const fullPath = `${routesDir}/${route.filePath}`\n imports.push(`import { middleware as ${name} } from \"${fullPath}\"`)\n entries.push(` { pattern: ${JSON.stringify(route.urlPath)}, middleware: ${name} }`)\n }\n\n return [\n ...imports,\n '',\n `export const routeMiddleware = [`,\n entries.join(',\\n'),\n `].filter(e => e.middleware)`,\n ].join('\\n')\n}\n\n/**\n * Scan a directory for route files.\n * Returns paths relative to the routes directory.\n */\nexport async function scanRouteFiles(routesDir: string): Promise<string[]> {\n const { readdir } = await import('node:fs/promises')\n const { join, relative } = await import('node:path')\n\n const files: string[] = []\n\n async function walk(dir: string) {\n const entries = await readdir(dir, { withFileTypes: true })\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n if (entry.isDirectory()) {\n await walk(fullPath)\n } else if (ROUTE_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) {\n files.push(relative(routesDir, fullPath))\n }\n }\n }\n\n await walk(routesDir)\n return files\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../../src/adapters/bun.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAuB,MAAM,UAAU,CAAA;AAE5D;;GAEG;AACH,wBAAgB,UAAU,IAAI,OAAO,CA2DpC"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { Adapter } from '../types';
|
|
2
|
-
/**
|
|
3
|
-
* Cloudflare Pages adapter — generates output for Cloudflare Pages with Functions.
|
|
4
|
-
*
|
|
5
|
-
* Produces:
|
|
6
|
-
* - Client assets in the output directory root (served as static)
|
|
7
|
-
* - `_worker.js` — Cloudflare Pages Function for SSR
|
|
8
|
-
*
|
|
9
|
-
* Note: Cloudflare Pages Functions have a ~1MB module size limit.
|
|
10
|
-
* For large apps, configure Vite's SSR build to bundle server code:
|
|
11
|
-
* `ssr: { noExternal: true }` in vite.config.ts.
|
|
12
|
-
*
|
|
13
|
-
* Deploy with: `npx wrangler pages deploy ./dist`
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```ts
|
|
17
|
-
* // zero.config.ts
|
|
18
|
-
* import { defineConfig } from "@pyreon/zero"
|
|
19
|
-
*
|
|
20
|
-
* export default defineConfig({
|
|
21
|
-
* adapter: "cloudflare",
|
|
22
|
-
* })
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
export declare function cloudflareAdapter(): Adapter;
|
|
26
|
-
//# sourceMappingURL=cloudflare.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../../src/adapters/cloudflare.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAuB,MAAM,UAAU,CAAA;AAE5D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAwD3C"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export { bunAdapter } from './bun';
|
|
2
|
-
export { cloudflareAdapter } from './cloudflare';
|
|
3
|
-
export { netlifyAdapter } from './netlify';
|
|
4
|
-
export { nodeAdapter } from './node';
|
|
5
|
-
export { staticAdapter } from './static';
|
|
6
|
-
export { vercelAdapter } from './vercel';
|
|
7
|
-
import type { Adapter, ZeroConfig } from '../types';
|
|
8
|
-
/**
|
|
9
|
-
* Resolve the adapter from config.
|
|
10
|
-
* Returns a built-in adapter or throws if unknown.
|
|
11
|
-
*/
|
|
12
|
-
export declare function resolveAdapter(config: ZeroConfig): Adapter;
|
|
13
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAQnD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAmB1D"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { Adapter } from '../types';
|
|
2
|
-
/**
|
|
3
|
-
* Netlify adapter — generates output for Netlify Functions (v2).
|
|
4
|
-
*
|
|
5
|
-
* Produces:
|
|
6
|
-
* - Client assets in `publish/` directory
|
|
7
|
-
* - `netlify/functions/ssr.mjs` — Netlify Function for SSR
|
|
8
|
-
* - `netlify.toml` — routing configuration
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```ts
|
|
12
|
-
* // zero.config.ts
|
|
13
|
-
* import { defineConfig } from "@pyreon/zero"
|
|
14
|
-
*
|
|
15
|
-
* export default defineConfig({
|
|
16
|
-
* adapter: "netlify",
|
|
17
|
-
* })
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export declare function netlifyAdapter(): Adapter;
|
|
21
|
-
//# sourceMappingURL=netlify.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"netlify.d.ts","sourceRoot":"","sources":["../../../src/adapters/netlify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAuB,MAAM,UAAU,CAAA;AAE5D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,IAAI,OAAO,CA+DxC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/adapters/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAuB,MAAM,UAAU,CAAA;AAE5D;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAwGrC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Adapter } from '../types';
|
|
2
|
-
/**
|
|
3
|
-
* Static adapter — just copies the client build output.
|
|
4
|
-
* Used with SSG mode where all pages are pre-rendered at build time.
|
|
5
|
-
*/
|
|
6
|
-
export declare function staticAdapter(): Adapter;
|
|
7
|
-
//# sourceMappingURL=static.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../../src/adapters/static.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAuB,MAAM,UAAU,CAAA;AAE5D;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAUvC"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { Adapter } from '../types';
|
|
2
|
-
/**
|
|
3
|
-
* Vercel adapter — generates output for Vercel's Build Output API v3.
|
|
4
|
-
*
|
|
5
|
-
* Produces a `.vercel/output` directory with:
|
|
6
|
-
* - `static/` — client-side assets (JS, CSS, images)
|
|
7
|
-
* - `functions/ssr.func/` — serverless function for SSR
|
|
8
|
-
* - `config.json` — routing configuration
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```ts
|
|
12
|
-
* // zero.config.ts
|
|
13
|
-
* import { defineConfig } from "@pyreon/zero"
|
|
14
|
-
*
|
|
15
|
-
* export default defineConfig({
|
|
16
|
-
* adapter: "vercel",
|
|
17
|
-
* })
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export declare function vercelAdapter(): Adapter;
|
|
21
|
-
//# sourceMappingURL=vercel.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"vercel.d.ts","sourceRoot":"","sources":["../../../src/adapters/vercel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAuB,MAAM,UAAU,CAAA;AAE5D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,IAAI,OAAO,CA+DvC"}
|
package/lib/types/app.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { ComponentFn } from '@pyreon/core';
|
|
2
|
-
import type { RouteRecord } from '@pyreon/router';
|
|
3
|
-
export interface CreateAppOptions {
|
|
4
|
-
/** Route definitions (from file-based routing or manual). */
|
|
5
|
-
routes: RouteRecord[];
|
|
6
|
-
/** Router mode. Default: "history" for SSR, "hash" for SPA. */
|
|
7
|
-
routerMode?: 'hash' | 'history';
|
|
8
|
-
/** Initial URL for SSR. */
|
|
9
|
-
url?: string;
|
|
10
|
-
/** Root layout component wrapping all routes. */
|
|
11
|
-
layout?: ComponentFn;
|
|
12
|
-
/** Global error component. */
|
|
13
|
-
errorComponent?: ComponentFn;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Create a full Zero app — assembles router, head provider, and root layout.
|
|
17
|
-
*
|
|
18
|
-
* Used internally by entry-server and entry-client.
|
|
19
|
-
*/
|
|
20
|
-
export declare function createApp(options: CreateAppOptions): {
|
|
21
|
-
App: () => import("@pyreon/core").VNode;
|
|
22
|
-
router: import("@pyreon/router").Router;
|
|
23
|
-
};
|
|
24
|
-
//# sourceMappingURL=app.d.ts.map
|
package/lib/types/app.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAS,MAAM,cAAc,CAAA;AAGtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAKjD,MAAM,WAAW,gBAAgB;IAC/B,6DAA6D;IAC7D,MAAM,EAAE,WAAW,EAAE,CAAA;IAErB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAE/B,2BAA2B;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ,iDAAiD;IACjD,MAAM,CAAC,EAAE,WAAW,CAAA;IAEpB,8BAA8B;IAC9B,cAAc,CAAC,EAAE,WAAW,CAAA;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB;;;EAuBlD"}
|