@pyreon/zero 0.12.1 → 0.12.2
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/index.js +1476 -82
- package/lib/index.js.map +1 -1
- package/lib/types/adapters/cloudflare.d.ts +26 -0
- package/lib/types/adapters/cloudflare.d.ts.map +1 -0
- package/lib/types/adapters/index.d.ts +3 -0
- package/lib/types/adapters/index.d.ts.map +1 -1
- package/lib/types/adapters/netlify.d.ts +21 -0
- package/lib/types/adapters/netlify.d.ts.map +1 -0
- package/lib/types/adapters/vercel.d.ts +21 -0
- package/lib/types/adapters/vercel.d.ts.map +1 -0
- package/lib/types/ai.d.ts +182 -0
- package/lib/types/ai.d.ts.map +1 -0
- package/lib/types/csp.d.ts +107 -0
- package/lib/types/csp.d.ts.map +1 -0
- package/lib/types/env.d.ts +118 -0
- package/lib/types/env.d.ts.map +1 -0
- package/lib/types/favicon.d.ts +42 -0
- package/lib/types/favicon.d.ts.map +1 -1
- package/lib/types/index.d.ts +13 -3
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/logger.d.ts +68 -0
- package/lib/types/logger.d.ts.map +1 -0
- package/lib/types/meta.d.ts +36 -0
- package/lib/types/meta.d.ts.map +1 -1
- package/lib/types/og-image.d.ts +107 -0
- package/lib/types/og-image.d.ts.map +1 -0
- package/lib/types/types.d.ts +1 -1
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +35 -10
- package/src/adapters/cloudflare.ts +82 -0
- package/src/adapters/index.ts +13 -1
- package/src/adapters/netlify.ts +84 -0
- package/src/adapters/vercel.ts +84 -0
- package/src/ai.ts +623 -0
- package/src/csp.ts +207 -0
- package/src/env.ts +344 -0
- package/src/favicon.ts +221 -80
- package/src/index.ts +41 -2
- package/src/logger.ts +144 -0
- package/src/meta.tsx +84 -2
- package/src/og-image.ts +378 -0
- package/src/types.ts +1 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request logging middleware.
|
|
3
|
+
*
|
|
4
|
+
* Logs HTTP requests with method, path, status, and duration.
|
|
5
|
+
* Supports custom formatters and log levels.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { loggerMiddleware } from "@pyreon/zero"
|
|
10
|
+
*
|
|
11
|
+
* export default defineConfig({
|
|
12
|
+
* middleware: [loggerMiddleware()],
|
|
13
|
+
* })
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import type { Middleware } from '@pyreon/server';
|
|
17
|
+
export interface LoggerConfig {
|
|
18
|
+
/**
|
|
19
|
+
* Log level — controls which requests are logged.
|
|
20
|
+
* - "all": log every request
|
|
21
|
+
* - "none": disable logging
|
|
22
|
+
* Default: "all"
|
|
23
|
+
*/
|
|
24
|
+
level?: 'all' | 'none';
|
|
25
|
+
/**
|
|
26
|
+
* Custom log formatter. Receives request details and returns
|
|
27
|
+
* the string to log (or null to skip).
|
|
28
|
+
*/
|
|
29
|
+
format?: (entry: LogEntry) => string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Skip logging for these path prefixes.
|
|
32
|
+
* Default: ["/__", "/@", "/node_modules"]
|
|
33
|
+
*/
|
|
34
|
+
skip?: string[];
|
|
35
|
+
/**
|
|
36
|
+
* Enable colorized output (ANSI codes).
|
|
37
|
+
* Default: true in development, false in production.
|
|
38
|
+
*/
|
|
39
|
+
colors?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface LogEntry {
|
|
42
|
+
method: string;
|
|
43
|
+
path: string;
|
|
44
|
+
duration: number;
|
|
45
|
+
timestamp: Date;
|
|
46
|
+
userAgent?: string | undefined;
|
|
47
|
+
ip?: string | undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Request logging middleware.
|
|
51
|
+
*
|
|
52
|
+
* Logs incoming requests with method, path, and duration.
|
|
53
|
+
* Runs in middleware phase — logs timing from middleware start to
|
|
54
|
+
* microtask completion (approximate request duration).
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* // Basic usage
|
|
59
|
+
* loggerMiddleware()
|
|
60
|
+
*
|
|
61
|
+
* // Custom format
|
|
62
|
+
* loggerMiddleware({
|
|
63
|
+
* format: (e) => `${e.method} ${e.path} (${e.duration}ms)`,
|
|
64
|
+
* })
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function loggerMiddleware(config?: LoggerConfig): Middleware;
|
|
68
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,UAAU,EAAqB,MAAM,gBAAgB,CAAA;AAEnE,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IACtB;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,MAAM,GAAG,IAAI,CAAA;IAC3C;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACxB;AAsCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,UAAU,CAsClE"}
|
package/lib/types/meta.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { VNodeChild } from '@pyreon/core';
|
|
2
|
+
import type { FaviconPluginConfig } from './favicon';
|
|
2
3
|
import type { I18nRoutingConfig } from './i18n-routing';
|
|
3
4
|
export interface MetaProps {
|
|
4
5
|
/** Page title. Accepts reactive accessor `() => string`. */
|
|
@@ -11,6 +12,10 @@ export interface MetaProps {
|
|
|
11
12
|
image?: string;
|
|
12
13
|
/** Image alt text for accessibility. */
|
|
13
14
|
imageAlt?: string;
|
|
15
|
+
/** Image width in pixels (og:image:width). Helps crawlers layout before loading. */
|
|
16
|
+
imageWidth?: number;
|
|
17
|
+
/** Image height in pixels (og:image:height). */
|
|
18
|
+
imageHeight?: number;
|
|
14
19
|
/** Open Graph type. Default: "website" */
|
|
15
20
|
type?: 'website' | 'article' | 'product' | 'profile';
|
|
16
21
|
/** Site name for og:site_name. */
|
|
@@ -30,6 +35,8 @@ export interface MetaProps {
|
|
|
30
35
|
}>;
|
|
31
36
|
/** Robots directives. Default: "index, follow" */
|
|
32
37
|
robots?: string;
|
|
38
|
+
/** Convenience: set `true` to emit `noindex, nofollow`. Overrides `robots`. */
|
|
39
|
+
noIndex?: boolean;
|
|
33
40
|
/** Published time (ISO 8601) for article type. */
|
|
34
41
|
publishedTime?: string;
|
|
35
42
|
/** Modified time (ISO 8601) for article type. */
|
|
@@ -46,6 +53,19 @@ export interface MetaProps {
|
|
|
46
53
|
property?: string;
|
|
47
54
|
content: string;
|
|
48
55
|
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Open Graph video URL. Also sets og:video:type if the URL ends with
|
|
58
|
+
* a known extension (.mp4, .webm).
|
|
59
|
+
*/
|
|
60
|
+
video?: string;
|
|
61
|
+
/** Video width in pixels. */
|
|
62
|
+
videoWidth?: number;
|
|
63
|
+
/** Video height in pixels. */
|
|
64
|
+
videoHeight?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Open Graph audio URL.
|
|
67
|
+
*/
|
|
68
|
+
audio?: string;
|
|
49
69
|
/**
|
|
50
70
|
* I18n routing config — when provided, auto-generates hreflang alternate
|
|
51
71
|
* links for all locales based on the current path.
|
|
@@ -54,6 +74,22 @@ export interface MetaProps {
|
|
|
54
74
|
i18n?: I18nRoutingConfig;
|
|
55
75
|
/** Base URL for building absolute hreflang URLs. e.g. "https://example.com" */
|
|
56
76
|
origin?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Favicon plugin config — when provided, injects locale-aware favicon
|
|
79
|
+
* `<link>` tags into `<head>`. Uses the current locale to select
|
|
80
|
+
* the correct favicon set.
|
|
81
|
+
*/
|
|
82
|
+
favicon?: FaviconPluginConfig;
|
|
83
|
+
/**
|
|
84
|
+
* OG image template name — auto-resolves to the correct locale-specific
|
|
85
|
+
* OG image path generated by `ogImagePlugin`.
|
|
86
|
+
* Sets both `og:image` and `twitter:image` unless `image` is also provided.
|
|
87
|
+
*/
|
|
88
|
+
ogTemplate?: string;
|
|
89
|
+
/** Output directory for OG images. Default: "og" */
|
|
90
|
+
ogImageDir?: string;
|
|
91
|
+
/** OG image format. Default: "png" */
|
|
92
|
+
ogImageFormat?: 'png' | 'jpeg';
|
|
57
93
|
children?: VNodeChild;
|
|
58
94
|
}
|
|
59
95
|
/**
|
package/lib/types/meta.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/meta.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAE9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/meta.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
export interface OgImageLayer {
|
|
3
|
+
/**
|
|
4
|
+
* Text content. Can be:
|
|
5
|
+
* - A string (same for all locales)
|
|
6
|
+
* - A record mapping locale → text
|
|
7
|
+
* - A function receiving locale and returning text
|
|
8
|
+
*/
|
|
9
|
+
text: string | Record<string, string> | ((locale: string) => string);
|
|
10
|
+
/** X position — number (px) or string with % (e.g. "50%"). Default: "50%" */
|
|
11
|
+
x?: number | string;
|
|
12
|
+
/** Y position — number (px) or string with % (e.g. "40%"). Default: "50%" */
|
|
13
|
+
y?: number | string;
|
|
14
|
+
/** Font size in px. Default: 64 */
|
|
15
|
+
fontSize?: number;
|
|
16
|
+
/** Font family. Default: "sans-serif" */
|
|
17
|
+
fontFamily?: string;
|
|
18
|
+
/** Font weight. Default: "bold" */
|
|
19
|
+
fontWeight?: string;
|
|
20
|
+
/** Text color. Default: "#ffffff" */
|
|
21
|
+
color?: string;
|
|
22
|
+
/** Text anchor (alignment). Default: "middle" */
|
|
23
|
+
textAnchor?: 'start' | 'middle' | 'end';
|
|
24
|
+
/** Max width in px before wrapping. Default: 80% of image width. */
|
|
25
|
+
maxWidth?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface OgImageTemplate {
|
|
28
|
+
/** Template name — used for output file naming. */
|
|
29
|
+
name: string;
|
|
30
|
+
/**
|
|
31
|
+
* Background: path to an image file, or a solid color config.
|
|
32
|
+
*
|
|
33
|
+
* @example "./src/assets/og-bg.jpg"
|
|
34
|
+
* @example { color: "#0066ff", width: 1200, height: 630 }
|
|
35
|
+
*/
|
|
36
|
+
background: string | {
|
|
37
|
+
color: string;
|
|
38
|
+
width?: number;
|
|
39
|
+
height?: number;
|
|
40
|
+
};
|
|
41
|
+
/** Output width. Default: 1200 */
|
|
42
|
+
width?: number;
|
|
43
|
+
/** Output height. Default: 630 */
|
|
44
|
+
height?: number;
|
|
45
|
+
/** Output format. Default: "png" */
|
|
46
|
+
format?: 'png' | 'jpeg';
|
|
47
|
+
/** JPEG quality (1-100). Default: 90 */
|
|
48
|
+
quality?: number;
|
|
49
|
+
/** Text layers to overlay on the background. */
|
|
50
|
+
layers?: OgImageLayer[];
|
|
51
|
+
}
|
|
52
|
+
export interface OgImagePluginConfig {
|
|
53
|
+
/** Templates to generate. */
|
|
54
|
+
templates: OgImageTemplate[];
|
|
55
|
+
/** Locales to generate for. When omitted, generates a single image per template. */
|
|
56
|
+
locales?: string[];
|
|
57
|
+
/** Output directory prefix. Default: "og" */
|
|
58
|
+
outDir?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build an SVG overlay with text layers.
|
|
62
|
+
* @internal Exported for testing.
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildTextOverlaySvg(layers: OgImageLayer[], width: number, height: number, locale: string): string;
|
|
65
|
+
/**
|
|
66
|
+
* Render an OG image from a template for a specific locale.
|
|
67
|
+
* @internal Exported for testing.
|
|
68
|
+
*/
|
|
69
|
+
export declare function renderOgImage(template: OgImageTemplate, locale: string, rootDir: string): Promise<Uint8Array | null>;
|
|
70
|
+
/**
|
|
71
|
+
* Compute the OG image path for a template and locale.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* ogImagePath("default", "de") // → "/og/default-de.png"
|
|
76
|
+
* ogImagePath("default") // → "/og/default.png"
|
|
77
|
+
* ogImagePath("hero", "en", "images") // → "/images/hero-en.png"
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare function ogImagePath(templateName: string, locale?: string, outDir?: string, format?: 'png' | 'jpeg'): string;
|
|
81
|
+
/**
|
|
82
|
+
* OG image generation Vite plugin.
|
|
83
|
+
*
|
|
84
|
+
* Generates Open Graph images at build time. In dev, generates on-demand.
|
|
85
|
+
* Requires `sharp` as an optional dependency.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* // vite.config.ts
|
|
90
|
+
* import { ogImagePlugin } from "@pyreon/zero/og-image"
|
|
91
|
+
*
|
|
92
|
+
* export default {
|
|
93
|
+
* plugins: [
|
|
94
|
+
* ogImagePlugin({
|
|
95
|
+
* locales: ["en", "de"],
|
|
96
|
+
* templates: [{
|
|
97
|
+
* name: "default",
|
|
98
|
+
* background: { color: "#0066ff" },
|
|
99
|
+
* layers: [{ text: { en: "Hello", de: "Hallo" }, fontSize: 72 }],
|
|
100
|
+
* }],
|
|
101
|
+
* }),
|
|
102
|
+
* ],
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export declare function ogImagePlugin(config: OgImagePluginConfig): Plugin;
|
|
107
|
+
//# sourceMappingURL=og-image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"og-image.d.ts","sourceRoot":"","sources":["../../src/og-image.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAclC,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;IACpE,6EAA6E;IAC7E,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,6EAA6E;IAC7E,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iDAAiD;IACjD,UAAU,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAA;IACvC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;OAKG;IACH,UAAU,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACvE,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oCAAoC;IACpC,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IACvB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,6BAA6B;IAC7B,SAAS,EAAE,eAAe,EAAE,CAAA;IAC5B,oFAAoF;IACpF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AA0BD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EAAE,EACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,MAAM,CA0DR;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAuC5B;AAID;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,SAAO,EACb,MAAM,GAAE,KAAK,GAAG,MAAc,GAC7B,MAAM,CAIR;AAID;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAkFjE"}
|
package/lib/types/types.d.ts
CHANGED
|
@@ -58,7 +58,7 @@ export interface ZeroConfig {
|
|
|
58
58
|
/** ISR config — only used when mode is "isr". */
|
|
59
59
|
isr?: ISRConfig;
|
|
60
60
|
/** Deploy adapter. Default: "node" */
|
|
61
|
-
adapter?: 'node' | 'bun' | 'static';
|
|
61
|
+
adapter?: 'node' | 'bun' | 'static' | 'vercel' | 'cloudflare' | 'netlify';
|
|
62
62
|
/** Base URL path. Default: "/" */
|
|
63
63
|
base?: string;
|
|
64
64
|
/** App-level middleware applied to all routes. */
|
package/lib/types/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAIhD,kEAAkE;AAClE,MAAM,WAAW,WAAW;IAC1B,4CAA4C;IAC5C,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,qEAAqE;IACrE,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,mDAAmD;IACnD,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACjD,4BAA4B;IAC5B,UAAU,CAAC,EAAE,UAAU,GAAG,UAAU,EAAE,CAAA;IACtC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,sBAAsB;IACtB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB;AAED,uCAAuC;AACvC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,0BAA0B;AAC1B,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAID,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAA;AAEtD,MAAM,WAAW,SAAS;IACxB,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAA;CACnB;AAID,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,UAAU,CAAA;IAEjB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAE9B,mBAAmB;IACnB,GAAG,CAAC,EAAE;QACJ,wCAAwC;QACxC,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;KAC3B,CAAA;IAED,kDAAkD;IAClD,GAAG,CAAC,EAAE;QACJ,wDAAwD;QACxD,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;KACxD,CAAA;IAED,iDAAiD;IACjD,GAAG,CAAC,EAAE,SAAS,CAAA;IAEf,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/zero",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2",
|
|
4
4
|
"description": "Pyreon Zero — zero-config full-stack framework powered by Pyreon and Vite",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Vit Bokisch",
|
|
@@ -117,15 +117,40 @@
|
|
|
117
117
|
"import": "./lib/favicon.js",
|
|
118
118
|
"types": "./lib/types/favicon.d.ts"
|
|
119
119
|
},
|
|
120
|
+
"./og-image": {
|
|
121
|
+
"bun": "./src/og-image.ts",
|
|
122
|
+
"import": "./lib/og-image.js",
|
|
123
|
+
"types": "./lib/types/og-image.d.ts"
|
|
124
|
+
},
|
|
120
125
|
"./i18n": {
|
|
121
126
|
"bun": "./src/i18n-routing.ts",
|
|
122
127
|
"import": "./lib/i18n-routing.js",
|
|
123
128
|
"types": "./lib/types/i18n-routing.d.ts"
|
|
124
129
|
},
|
|
130
|
+
"./ai": {
|
|
131
|
+
"bun": "./src/ai.ts",
|
|
132
|
+
"import": "./lib/ai.js",
|
|
133
|
+
"types": "./lib/types/ai.d.ts"
|
|
134
|
+
},
|
|
125
135
|
"./middleware": {
|
|
126
136
|
"bun": "./src/middleware.ts",
|
|
127
137
|
"import": "./lib/middleware.js",
|
|
128
138
|
"types": "./lib/types/middleware.d.ts"
|
|
139
|
+
},
|
|
140
|
+
"./csp": {
|
|
141
|
+
"bun": "./src/csp.ts",
|
|
142
|
+
"import": "./lib/csp.js",
|
|
143
|
+
"types": "./lib/types/csp.d.ts"
|
|
144
|
+
},
|
|
145
|
+
"./env": {
|
|
146
|
+
"bun": "./src/env.ts",
|
|
147
|
+
"import": "./lib/env.js",
|
|
148
|
+
"types": "./lib/types/env.d.ts"
|
|
149
|
+
},
|
|
150
|
+
"./logger": {
|
|
151
|
+
"bun": "./src/logger.ts",
|
|
152
|
+
"import": "./lib/logger.js",
|
|
153
|
+
"types": "./lib/types/logger.d.ts"
|
|
129
154
|
}
|
|
130
155
|
},
|
|
131
156
|
"scripts": {
|
|
@@ -136,17 +161,17 @@
|
|
|
136
161
|
"lint": "oxlint ."
|
|
137
162
|
},
|
|
138
163
|
"dependencies": {
|
|
139
|
-
"@pyreon/core": "^0.12.
|
|
140
|
-
"@pyreon/head": "^0.12.
|
|
141
|
-
"@pyreon/meta": "^0.12.
|
|
142
|
-
"@pyreon/router": "^0.12.
|
|
143
|
-
"@pyreon/runtime-dom": "^0.12.
|
|
144
|
-
"@pyreon/runtime-server": "^0.12.
|
|
145
|
-
"@pyreon/server": "^0.12.
|
|
146
|
-
"@pyreon/vite-plugin": "^0.12.
|
|
164
|
+
"@pyreon/core": "^0.12.2",
|
|
165
|
+
"@pyreon/head": "^0.12.2",
|
|
166
|
+
"@pyreon/meta": "^0.12.2",
|
|
167
|
+
"@pyreon/router": "^0.12.2",
|
|
168
|
+
"@pyreon/runtime-dom": "^0.12.2",
|
|
169
|
+
"@pyreon/runtime-server": "^0.12.2",
|
|
170
|
+
"@pyreon/server": "^0.12.2",
|
|
171
|
+
"@pyreon/vite-plugin": "^0.12.2",
|
|
147
172
|
"vite": "^8.0.0"
|
|
148
173
|
},
|
|
149
174
|
"peerDependencies": {
|
|
150
|
-
"@pyreon/reactivity": "^0.12.
|
|
175
|
+
"@pyreon/reactivity": "^0.12.2"
|
|
151
176
|
}
|
|
152
177
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Adapter, AdapterBuildOptions } from '../types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cloudflare Pages adapter — generates output for Cloudflare Pages with Functions.
|
|
5
|
+
*
|
|
6
|
+
* Produces:
|
|
7
|
+
* - Client assets in the output directory root (served as static)
|
|
8
|
+
* - `_worker.js` — Cloudflare Pages Function for SSR
|
|
9
|
+
*
|
|
10
|
+
* Note: Cloudflare Pages Functions have a ~1MB module size limit.
|
|
11
|
+
* For large apps, configure Vite's SSR build to bundle server code:
|
|
12
|
+
* `ssr: { noExternal: true }` in vite.config.ts.
|
|
13
|
+
*
|
|
14
|
+
* Deploy with: `npx wrangler pages deploy ./dist`
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* // zero.config.ts
|
|
19
|
+
* import { defineConfig } from "@pyreon/zero"
|
|
20
|
+
*
|
|
21
|
+
* export default defineConfig({
|
|
22
|
+
* adapter: "cloudflare",
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function cloudflareAdapter(): Adapter {
|
|
27
|
+
return {
|
|
28
|
+
name: 'cloudflare',
|
|
29
|
+
async build(options: AdapterBuildOptions) {
|
|
30
|
+
const { writeFile, cp, mkdir } = await import('node:fs/promises')
|
|
31
|
+
const { join } = await import('node:path')
|
|
32
|
+
|
|
33
|
+
const outDir = options.outDir
|
|
34
|
+
await mkdir(outDir, { recursive: true })
|
|
35
|
+
|
|
36
|
+
// Copy client assets to root (Cloudflare serves static files from root)
|
|
37
|
+
await cp(options.clientOutDir, outDir, { recursive: true })
|
|
38
|
+
|
|
39
|
+
// Copy server build
|
|
40
|
+
await cp(join(options.serverEntry, '..'), join(outDir, '_server'), {
|
|
41
|
+
recursive: true,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// Generate Cloudflare Pages _worker.js (ES module format)
|
|
45
|
+
const workerEntry = `
|
|
46
|
+
import handler from "./_server/entry-server.js"
|
|
47
|
+
|
|
48
|
+
export default {
|
|
49
|
+
async fetch(request, env, ctx) {
|
|
50
|
+
const url = new URL(request.url)
|
|
51
|
+
|
|
52
|
+
// Let Cloudflare serve static assets (files with extensions)
|
|
53
|
+
// This check is a fallback — Pages routes static files automatically
|
|
54
|
+
const ext = url.pathname.split(".").pop()
|
|
55
|
+
if (ext && ext !== url.pathname && !url.pathname.endsWith("/")) {
|
|
56
|
+
// Cloudflare Pages handles static assets automatically via its asset binding
|
|
57
|
+
// Only reach here if the file doesn't exist — fall through to SSR
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// SSR handler
|
|
61
|
+
try {
|
|
62
|
+
return await handler(request)
|
|
63
|
+
} catch (err) {
|
|
64
|
+
return new Response("Internal Server Error", { status: 500 })
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
`.trimStart()
|
|
69
|
+
|
|
70
|
+
await writeFile(join(outDir, '_worker.js'), workerEntry)
|
|
71
|
+
|
|
72
|
+
// Cloudflare Pages config — _routes.json for routing
|
|
73
|
+
const routesConfig = {
|
|
74
|
+
version: 1,
|
|
75
|
+
include: ['/*'],
|
|
76
|
+
exclude: ['/assets/*', '/favicon.*', '/site.webmanifest', '/robots.txt', '/sitemap.xml'],
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
await writeFile(join(outDir, '_routes.json'), JSON.stringify(routesConfig, null, 2))
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
}
|
package/src/adapters/index.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
export { bunAdapter } from './bun'
|
|
2
|
+
export { cloudflareAdapter } from './cloudflare'
|
|
3
|
+
export { netlifyAdapter } from './netlify'
|
|
2
4
|
export { nodeAdapter } from './node'
|
|
3
5
|
export { staticAdapter } from './static'
|
|
6
|
+
export { vercelAdapter } from './vercel'
|
|
4
7
|
|
|
5
8
|
import type { Adapter, ZeroConfig } from '../types'
|
|
6
9
|
import { bunAdapter } from './bun'
|
|
10
|
+
import { cloudflareAdapter } from './cloudflare'
|
|
11
|
+
import { netlifyAdapter } from './netlify'
|
|
7
12
|
import { nodeAdapter } from './node'
|
|
8
13
|
import { staticAdapter } from './static'
|
|
14
|
+
import { vercelAdapter } from './vercel'
|
|
9
15
|
|
|
10
16
|
/**
|
|
11
17
|
* Resolve the adapter from config.
|
|
@@ -21,7 +27,13 @@ export function resolveAdapter(config: ZeroConfig): Adapter {
|
|
|
21
27
|
return bunAdapter()
|
|
22
28
|
case 'static':
|
|
23
29
|
return staticAdapter()
|
|
30
|
+
case 'vercel':
|
|
31
|
+
return vercelAdapter()
|
|
32
|
+
case 'cloudflare':
|
|
33
|
+
return cloudflareAdapter()
|
|
34
|
+
case 'netlify':
|
|
35
|
+
return netlifyAdapter()
|
|
24
36
|
default:
|
|
25
|
-
throw new Error(`[zero] Unknown adapter: "${name}". Use "node", "bun", or "
|
|
37
|
+
throw new Error(`[zero] Unknown adapter: "${name}". Use "node", "bun", "static", "vercel", "cloudflare", or "netlify".`)
|
|
26
38
|
}
|
|
27
39
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Adapter, AdapterBuildOptions } from '../types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Netlify adapter — generates output for Netlify Functions (v2).
|
|
5
|
+
*
|
|
6
|
+
* Produces:
|
|
7
|
+
* - Client assets in `publish/` directory
|
|
8
|
+
* - `netlify/functions/ssr.mjs` — Netlify Function for SSR
|
|
9
|
+
* - `netlify.toml` — routing configuration
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // zero.config.ts
|
|
14
|
+
* import { defineConfig } from "@pyreon/zero"
|
|
15
|
+
*
|
|
16
|
+
* export default defineConfig({
|
|
17
|
+
* adapter: "netlify",
|
|
18
|
+
* })
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function netlifyAdapter(): Adapter {
|
|
22
|
+
return {
|
|
23
|
+
name: 'netlify',
|
|
24
|
+
async build(options: AdapterBuildOptions) {
|
|
25
|
+
const { writeFile, cp, mkdir } = await import('node:fs/promises')
|
|
26
|
+
const { join } = await import('node:path')
|
|
27
|
+
|
|
28
|
+
const outDir = options.outDir
|
|
29
|
+
const publishDir = join(outDir, 'publish')
|
|
30
|
+
const functionsDir = join(outDir, 'netlify', 'functions')
|
|
31
|
+
|
|
32
|
+
await mkdir(publishDir, { recursive: true })
|
|
33
|
+
await mkdir(functionsDir, { recursive: true })
|
|
34
|
+
|
|
35
|
+
// Copy client assets to publish/
|
|
36
|
+
await cp(options.clientOutDir, publishDir, { recursive: true })
|
|
37
|
+
|
|
38
|
+
// Copy server build to functions directory
|
|
39
|
+
await cp(join(options.serverEntry, '..'), join(functionsDir, '_server'), {
|
|
40
|
+
recursive: true,
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// Generate Netlify Function (v2 format — ESM, Web-standard Request/Response)
|
|
44
|
+
const funcEntry = `
|
|
45
|
+
import handler from "./_server/entry-server.js"
|
|
46
|
+
|
|
47
|
+
export default async function(req, context) {
|
|
48
|
+
try {
|
|
49
|
+
return await handler(req)
|
|
50
|
+
} catch (err) {
|
|
51
|
+
return new Response("Internal Server Error", { status: 500 })
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const config = {
|
|
56
|
+
path: "/*",
|
|
57
|
+
preferStatic: true,
|
|
58
|
+
}
|
|
59
|
+
`.trimStart()
|
|
60
|
+
|
|
61
|
+
await writeFile(join(functionsDir, 'ssr.mjs'), funcEntry)
|
|
62
|
+
|
|
63
|
+
// Generate netlify.toml
|
|
64
|
+
const toml = `
|
|
65
|
+
[build]
|
|
66
|
+
publish = "publish"
|
|
67
|
+
functions = "netlify/functions"
|
|
68
|
+
|
|
69
|
+
[[headers]]
|
|
70
|
+
for = "/assets/*"
|
|
71
|
+
[headers.values]
|
|
72
|
+
Cache-Control = "public, max-age=31536000, immutable"
|
|
73
|
+
|
|
74
|
+
[[redirects]]
|
|
75
|
+
from = "/*"
|
|
76
|
+
to = "/.netlify/functions/ssr"
|
|
77
|
+
status = 200
|
|
78
|
+
conditions = {Role = ["admin", "user", ""]}
|
|
79
|
+
`.trimStart()
|
|
80
|
+
|
|
81
|
+
await writeFile(join(outDir, 'netlify.toml'), toml)
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Adapter, AdapterBuildOptions } from '../types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Vercel adapter — generates output for Vercel's Build Output API v3.
|
|
5
|
+
*
|
|
6
|
+
* Produces a `.vercel/output` directory with:
|
|
7
|
+
* - `static/` — client-side assets (JS, CSS, images)
|
|
8
|
+
* - `functions/ssr.func/` — serverless function for SSR
|
|
9
|
+
* - `config.json` — routing configuration
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // zero.config.ts
|
|
14
|
+
* import { defineConfig } from "@pyreon/zero"
|
|
15
|
+
*
|
|
16
|
+
* export default defineConfig({
|
|
17
|
+
* adapter: "vercel",
|
|
18
|
+
* })
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function vercelAdapter(): Adapter {
|
|
22
|
+
return {
|
|
23
|
+
name: 'vercel',
|
|
24
|
+
async build(options: AdapterBuildOptions) {
|
|
25
|
+
const { writeFile, cp, mkdir } = await import('node:fs/promises')
|
|
26
|
+
const { join } = await import('node:path')
|
|
27
|
+
|
|
28
|
+
const vercelDir = join(options.outDir, '.vercel', 'output')
|
|
29
|
+
const staticDir = join(vercelDir, 'static')
|
|
30
|
+
const funcDir = join(vercelDir, 'functions', 'ssr.func')
|
|
31
|
+
|
|
32
|
+
await mkdir(staticDir, { recursive: true })
|
|
33
|
+
await mkdir(funcDir, { recursive: true })
|
|
34
|
+
|
|
35
|
+
// Copy client assets to static/
|
|
36
|
+
await cp(options.clientOutDir, staticDir, { recursive: true })
|
|
37
|
+
|
|
38
|
+
// Copy server build to function directory
|
|
39
|
+
await cp(join(options.serverEntry, '..'), funcDir, { recursive: true })
|
|
40
|
+
|
|
41
|
+
// Generate serverless function entry
|
|
42
|
+
const funcEntry = `
|
|
43
|
+
export default async function handler(req) {
|
|
44
|
+
const handler = (await import("./entry-server.js")).default
|
|
45
|
+
return handler(req)
|
|
46
|
+
}
|
|
47
|
+
`.trimStart()
|
|
48
|
+
|
|
49
|
+
await writeFile(join(funcDir, 'index.js'), funcEntry)
|
|
50
|
+
|
|
51
|
+
// Function config
|
|
52
|
+
await writeFile(
|
|
53
|
+
join(funcDir, '.vc-config.json'),
|
|
54
|
+
JSON.stringify(
|
|
55
|
+
{
|
|
56
|
+
runtime: 'nodejs20.x',
|
|
57
|
+
handler: 'index.js',
|
|
58
|
+
launcherType: 'Nodejs',
|
|
59
|
+
},
|
|
60
|
+
null,
|
|
61
|
+
2,
|
|
62
|
+
),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
// Vercel Build Output config
|
|
66
|
+
const config = {
|
|
67
|
+
version: 3,
|
|
68
|
+
routes: [
|
|
69
|
+
// Serve static assets directly
|
|
70
|
+
{
|
|
71
|
+
src: '/assets/(.*)',
|
|
72
|
+
headers: { 'Cache-Control': 'public, max-age=31536000, immutable' },
|
|
73
|
+
},
|
|
74
|
+
// Favicon and manifest
|
|
75
|
+
{ src: '/(favicon\\..*|site\\.webmanifest|robots\\.txt|sitemap\\.xml)', dest: '/$1' },
|
|
76
|
+
// All other routes → SSR function
|
|
77
|
+
{ src: '/(.*)', dest: '/ssr' },
|
|
78
|
+
],
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await writeFile(join(vercelDir, 'config.json'), JSON.stringify(config, null, 2))
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
}
|