@pyreon/zero 0.24.5 → 0.24.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/package.json +10 -39
  2. package/src/actions.ts +0 -196
  3. package/src/adapters/bun.ts +0 -114
  4. package/src/adapters/cloudflare.ts +0 -166
  5. package/src/adapters/index.ts +0 -61
  6. package/src/adapters/netlify.ts +0 -154
  7. package/src/adapters/node.ts +0 -163
  8. package/src/adapters/static.ts +0 -42
  9. package/src/adapters/validate.ts +0 -23
  10. package/src/adapters/vercel.ts +0 -182
  11. package/src/adapters/warn-missing-env.ts +0 -49
  12. package/src/ai.ts +0 -623
  13. package/src/api-routes.ts +0 -219
  14. package/src/app.ts +0 -92
  15. package/src/cache.ts +0 -136
  16. package/src/client.ts +0 -143
  17. package/src/compression.ts +0 -116
  18. package/src/config.ts +0 -35
  19. package/src/cors.ts +0 -94
  20. package/src/csp.ts +0 -226
  21. package/src/entry-server.ts +0 -224
  22. package/src/env.ts +0 -344
  23. package/src/error-overlay.ts +0 -118
  24. package/src/favicon.ts +0 -841
  25. package/src/font.ts +0 -511
  26. package/src/fs-router.ts +0 -1519
  27. package/src/i18n-routing.ts +0 -533
  28. package/src/icon.tsx +0 -182
  29. package/src/icons-plugin.ts +0 -296
  30. package/src/image-plugin.ts +0 -751
  31. package/src/image-types.ts +0 -60
  32. package/src/image.tsx +0 -340
  33. package/src/index.ts +0 -92
  34. package/src/isr.ts +0 -394
  35. package/src/link.tsx +0 -304
  36. package/src/logger.ts +0 -144
  37. package/src/manifest.ts +0 -787
  38. package/src/meta.tsx +0 -354
  39. package/src/middleware.ts +0 -65
  40. package/src/not-found.ts +0 -44
  41. package/src/og-image.ts +0 -378
  42. package/src/rate-limit.ts +0 -140
  43. package/src/script.tsx +0 -260
  44. package/src/seo.ts +0 -617
  45. package/src/server.ts +0 -89
  46. package/src/sharp.d.ts +0 -22
  47. package/src/ssg-plugin.ts +0 -1582
  48. package/src/testing.ts +0 -146
  49. package/src/theme.tsx +0 -257
  50. package/src/types.ts +0 -624
  51. package/src/utils/use-intersection-observer.ts +0 -36
  52. package/src/utils/with-headers.ts +0 -13
  53. package/src/vercel-revalidate-handler.ts +0 -204
  54. package/src/vite-plugin.ts +0 -848
@@ -1,204 +0,0 @@
1
- /**
2
- * M3.1 — Drop-in Vercel revalidate webhook handler.
3
- *
4
- * Pre-M3.1 the `vercelAdapter.revalidate(path)` (PR I) POSTed to
5
- * `/api/_pyreon-revalidate?path=...&secret=...` — a CONVENTION that users
6
- * had to implement themselves. This helper scaffolds the convention:
7
- *
8
- * // src/routes/api/_pyreon-revalidate.ts (or `pages/api/...` in
9
- * // Next-style apps deployed to Vercel)
10
- * export { vercelRevalidateHandler as default } from '@pyreon/zero/server'
11
- *
12
- * The handler validates the secret query param against
13
- * `VERCEL_REVALIDATE_TOKEN`, validates the path is in the build-time
14
- * revalidate manifest, and calls Vercel's `res.revalidate(path)` API.
15
- *
16
- * Returns a standard `(req: Request) => Response` Web API handler — works
17
- * with Vercel Edge functions, Node serverless functions (via Vercel's
18
- * `@vercel/node` adapter that bridges Node `req`/`res` to Web standard
19
- * fetch shapes), and the in-process `mode: 'ssr'` runtime.
20
- *
21
- * @example
22
- * // src/routes/api/_pyreon-revalidate.ts
23
- * import { vercelRevalidateHandler } from '@pyreon/zero/server'
24
- *
25
- * export const POST = vercelRevalidateHandler({
26
- * // Optional — defaults to reading `_pyreon-revalidate.json` from cwd.
27
- * manifestPath: './dist/_pyreon-revalidate.json',
28
- * })
29
- *
30
- * @example
31
- * // Custom revalidate impl (e.g. for a self-hosted Pyreon SSR runtime
32
- * // that wants build-time revalidate behavior without Vercel's
33
- * // `res.revalidate()` API):
34
- * export const POST = vercelRevalidateHandler({
35
- * onRevalidate: async (path) => {
36
- * // Clear your in-process ISR cache, emit a metrics event, etc.
37
- * await myCache.invalidate(path)
38
- * },
39
- * })
40
- */
41
-
42
- import { readFile } from 'node:fs/promises'
43
- import { resolve } from 'node:path'
44
-
45
- /**
46
- * Build-time revalidate manifest written by `ssgPlugin` (PR I).
47
- * Shape: `{ revalidate: { '/posts/1': 60, '/posts/2': 60, '/about': 3600 } }`.
48
- */
49
- interface RevalidateManifest {
50
- revalidate: Record<string, number | false>
51
- }
52
-
53
- export interface VercelRevalidateHandlerOptions {
54
- /**
55
- * Absolute or cwd-relative path to the `_pyreon-revalidate.json` manifest.
56
- * Defaults to `./dist/_pyreon-revalidate.json` (the standard SSG output).
57
- *
58
- * The handler refuses to revalidate paths NOT in this manifest — protects
59
- * against arbitrary-path revalidation attacks even when the secret leaks.
60
- */
61
- manifestPath?: string
62
-
63
- /**
64
- * Custom revalidation impl. Defaults to calling Vercel's `res.revalidate()`
65
- * API via the dynamic `@vercel/node`-bridged response object on globalThis
66
- * (Vercel injects it for serverless functions).
67
- *
68
- * Supply this when running OUTSIDE Vercel (self-hosted SSR with a custom
69
- * in-process ISR cache, edge runtimes that have their own purge API, etc.).
70
- * Receives the validated path; throw to signal failure (handler returns 500).
71
- */
72
- onRevalidate?: (path: string) => void | Promise<void>
73
-
74
- /**
75
- * Override the env-var name the handler reads the secret from. Default
76
- * `VERCEL_REVALIDATE_TOKEN` matches the adapter's `revalidate()` write.
77
- * Useful when adopting the helper outside Vercel and the production
78
- * webhook uses a different secret name.
79
- */
80
- secretEnvVar?: string
81
- }
82
-
83
- /**
84
- * Create the Web-standard request handler. Reads the manifest once on first
85
- * invocation (cached in-process) so repeated revalidations don't re-read the
86
- * file. Manifest read failures cache the failure too — until next process
87
- * restart, all requests get the same 500 response (signals deploy-time misconfig).
88
- */
89
- export function vercelRevalidateHandler(
90
- options: VercelRevalidateHandlerOptions = {},
91
- ): (req: Request) => Promise<Response> {
92
- const manifestPath = options.manifestPath ?? './dist/_pyreon-revalidate.json'
93
- const secretEnvVar = options.secretEnvVar ?? 'VERCEL_REVALIDATE_TOKEN'
94
-
95
- // Manifest cache: loaded once per process. A nullish value means "not yet
96
- // loaded"; a `{ error: ... }` shape means "load failed, every subsequent
97
- // request gets 500 until restart". A `{ manifest: ... }` shape is the
98
- // happy path.
99
- let cache: { manifest: RevalidateManifest } | { error: unknown } | null = null
100
-
101
- return async function handler(req: Request): Promise<Response> {
102
- // Validate request shape: only POST, with `?path=&secret=` query.
103
- if (req.method !== 'POST') {
104
- return new Response(`Method ${req.method} not allowed`, { status: 405 })
105
- }
106
-
107
- const url = new URL(req.url)
108
- const path = url.searchParams.get('path')
109
- const secret = url.searchParams.get('secret')
110
-
111
- if (!path || !secret) {
112
- return new Response('Bad Request: missing path or secret', { status: 400 })
113
- }
114
-
115
- // Validate the secret against the env var. Constant-time-ish: we
116
- // compare strings of equal length; mismatched lengths short-circuit
117
- // (acceptable — the attacker can already see the response time
118
- // difference via fetch behavior). The env-var-missing case fails
119
- // CLOSED (401) — production webhooks shouldn't accept requests when
120
- // the server hasn't been configured.
121
- const expected = process.env[secretEnvVar]
122
- if (!expected) {
123
- return new Response(
124
- `Server misconfigured: ${secretEnvVar} env var not set`,
125
- { status: 500 },
126
- )
127
- }
128
- if (secret !== expected) {
129
- return new Response('Forbidden: invalid secret', { status: 403 })
130
- }
131
-
132
- // Load the manifest (once per process). On read failure, cache the
133
- // error so subsequent requests get fast 500s — saves rep eated stat
134
- // calls for a broken deploy.
135
- if (cache === null) {
136
- try {
137
- const fileContent = await readFile(resolve(process.cwd(), manifestPath), 'utf-8')
138
- const parsed = JSON.parse(fileContent) as RevalidateManifest
139
- if (typeof parsed?.revalidate !== 'object' || parsed.revalidate === null) {
140
- throw new Error(
141
- `Malformed revalidate manifest at ${manifestPath}: missing or non-object \`revalidate\` field`,
142
- )
143
- }
144
- cache = { manifest: parsed }
145
- } catch (err) {
146
- cache = { error: err }
147
- }
148
- }
149
- if ('error' in cache) {
150
- return new Response(
151
- `Server misconfigured: revalidate manifest at ${manifestPath} unreadable or malformed`,
152
- { status: 500 },
153
- )
154
- }
155
-
156
- // Validate the path is in the manifest — refuses arbitrary-path
157
- // revalidation even with a valid secret. Closes the
158
- // "secret leaked once → attacker revalidates anything" footgun.
159
- if (!Object.prototype.hasOwnProperty.call(cache.manifest.revalidate, path)) {
160
- return new Response(
161
- `Path "${path}" not in revalidate manifest`,
162
- { status: 404 },
163
- )
164
- }
165
-
166
- // Run the revalidation. Custom impl OR fallback to a structured
167
- // response that downstream Vercel-style code can adapt
168
- // (Vercel's `res.revalidate()` API can't be called from a
169
- // Web-standard handler without the `@vercel/node` bridge — the
170
- // user wires that themselves OR uses the `onRevalidate` callback).
171
- if (options.onRevalidate) {
172
- try {
173
- await options.onRevalidate(path)
174
- } catch (err) {
175
- return new Response(
176
- `Revalidation failed for "${path}": ${err instanceof Error ? err.message : String(err)}`,
177
- { status: 500 },
178
- )
179
- }
180
- }
181
-
182
- return new Response(JSON.stringify({ revalidated: true, path }), {
183
- status: 200,
184
- headers: { 'Content-Type': 'application/json' },
185
- })
186
- }
187
- }
188
-
189
- /**
190
- * Reset the in-process manifest cache. Test-only — production code never
191
- * reaches this. Used by unit tests to exercise the "manifest changed
192
- * between requests" path without spinning up a new handler.
193
- * @internal
194
- */
195
- export function _resetVercelRevalidateHandlerCache(
196
- handler: (req: Request) => Promise<Response>,
197
- ): void {
198
- // The cache lives in the closure; tests instantiate a fresh handler per
199
- // run rather than mutating an existing one. Kept here as a no-op marker
200
- // for the API contract — if cache invalidation surfaces as a real need
201
- // (e.g. hot-reload of the manifest after a deploy without restart), the
202
- // implementation can flip to a module-level WeakMap<handler, cache>.
203
- void handler
204
- }