@pyreon/zero 0.11.5 → 0.11.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.
@@ -1,7 +1,7 @@
1
- import { existsSync } from "node:fs"
2
- import { mkdir, readFile, writeFile } from "node:fs/promises"
3
- import { basename, extname, join } from "node:path"
4
- import type { Plugin } from "vite"
1
+ import { existsSync } from 'node:fs'
2
+ import { mkdir, readFile, writeFile } from 'node:fs/promises'
3
+ import { basename, extname, join } from 'node:path'
4
+ import type { Plugin } from 'vite'
5
5
 
6
6
  let sharpWarned = false
7
7
  function warnSharpMissing() {
@@ -9,7 +9,7 @@ function warnSharpMissing() {
9
9
  sharpWarned = true
10
10
  // biome-ignore lint/suspicious/noConsole: intentional build-time warning
11
11
  console.warn(
12
- "\n[zero:image] sharp not installed — images will not be optimized. Install for full support: bun add -D sharp\n",
12
+ '\n[zero:image] sharp not installed — images will not be optimized. Install for full support: bun add -D sharp\n',
13
13
  )
14
14
  }
15
15
 
@@ -44,7 +44,7 @@ export interface ImagePluginConfig {
44
44
  include?: RegExp
45
45
  }
46
46
 
47
- export type ImageFormat = "webp" | "avif" | "jpeg" | "png"
47
+ export type ImageFormat = 'webp' | 'avif' | 'jpeg' | 'png'
48
48
 
49
49
  /** Per-format source set for <picture> <source> elements. */
50
50
  export interface FormatSource {
@@ -99,39 +99,39 @@ const IMAGE_EXT_RE = /\.(jpe?g|png|webp|avif)$/i
99
99
  */
100
100
  export function imagePlugin(config: ImagePluginConfig = {}): Plugin {
101
101
  const defaultWidths = config.widths ?? [640, 1024, 1920]
102
- const defaultFormats = config.formats ?? ["webp"]
102
+ const defaultFormats = config.formats ?? ['webp']
103
103
  const quality = config.quality ?? 80
104
104
  const placeholderSize = config.placeholderSize ?? 16
105
- const outSubDir = config.outDir ?? "assets/img"
105
+ const outSubDir = config.outDir ?? 'assets/img'
106
106
  const include = config.include ?? IMAGE_EXT_RE
107
107
 
108
- let root = ""
109
- let outDir = ""
108
+ let root = ''
109
+ let outDir = ''
110
110
  let isBuild = false
111
111
 
112
112
  return {
113
- name: "pyreon-zero-images",
114
- enforce: "pre",
113
+ name: 'pyreon-zero-images',
114
+ enforce: 'pre',
115
115
 
116
116
  configResolved(resolvedConfig) {
117
117
  root = resolvedConfig.root
118
118
  outDir = resolvedConfig.build.outDir
119
- isBuild = resolvedConfig.command === "build"
119
+ isBuild = resolvedConfig.command === 'build'
120
120
  },
121
121
 
122
122
  async resolveId(id) {
123
123
  // Handle ?optimize query on image imports
124
- if (id.includes("?optimize") && include.test(id.split("?")[0]!)) {
124
+ if (id.includes('?optimize') && include.test(id.split('?')[0]!)) {
125
125
  return `\0virtual:zero-image:${id}`
126
126
  }
127
127
  return null
128
128
  },
129
129
 
130
130
  async load(id) {
131
- if (!id.startsWith("\0virtual:zero-image:")) return null
131
+ if (!id.startsWith('\0virtual:zero-image:')) return null
132
132
 
133
- const rawPath = id.replace("\0virtual:zero-image:", "").split("?")[0] ?? id
134
- const absPath = rawPath.startsWith("/") ? join(root, "public", rawPath) : rawPath
133
+ const rawPath = id.replace('\0virtual:zero-image:', '').split('?')[0] ?? id
134
+ const absPath = rawPath.startsWith('/') ? join(root, 'public', rawPath) : rawPath
135
135
 
136
136
  if (!isBuild) {
137
137
  const result = await loadDevImage(absPath, rawPath, placeholderSize)
@@ -161,16 +161,16 @@ async function loadDevImage(
161
161
  placeholderSize: number,
162
162
  ): Promise<ProcessedImage> {
163
163
  const metadata = await getImageMetadata(absPath)
164
- const publicPath = rawPath.startsWith("/") ? rawPath : `/@fs/${absPath}`
164
+ const publicPath = rawPath.startsWith('/') ? rawPath : `/@fs/${absPath}`
165
165
 
166
166
  return {
167
167
  src: publicPath,
168
- srcset: "",
168
+ srcset: '',
169
169
  width: metadata.width,
170
170
  height: metadata.height,
171
171
  placeholder: await generateBlurPlaceholder(absPath, placeholderSize),
172
172
  formats: [],
173
- sources: [{ src: publicPath, width: metadata.width, format: "original" }],
173
+ sources: [{ src: publicPath, width: metadata.width, format: 'original' }],
174
174
  }
175
175
  }
176
176
 
@@ -178,13 +178,13 @@ async function emitProcessedSources(
178
178
  processed: ProcessedImage,
179
179
  outSubDir: string,
180
180
  ctx: {
181
- emitFile: (f: { type: "asset"; fileName: string; source: Uint8Array }) => void
181
+ emitFile: (f: { type: 'asset'; fileName: string; source: Uint8Array }) => void
182
182
  },
183
183
  ) {
184
184
  for (const source of processed.sources) {
185
185
  const fileName = join(outSubDir, basename(source.src))
186
186
  const content = await readFile(source.src)
187
- ctx.emitFile({ type: "asset", fileName, source: content })
187
+ ctx.emitFile({ type: 'asset', fileName, source: content })
188
188
  source.src = `/${fileName}`
189
189
  }
190
190
  }
@@ -201,11 +201,11 @@ function rebuildFormatSrcsets(processed: ProcessedImage, fallbackPath: string) {
201
201
  }
202
202
  processed.formats = [...formatGroups.entries()].map(([fmt, entries]) => ({
203
203
  type: `image/${fmt}`,
204
- srcset: entries.join(", "),
204
+ srcset: entries.join(', '),
205
205
  }))
206
206
 
207
207
  const lastFormat = processed.formats.at(-1)
208
- processed.srcset = lastFormat?.srcset ?? ""
208
+ processed.srcset = lastFormat?.srcset ?? ''
209
209
  processed.src = processed.sources.at(-1)?.src ?? fallbackPath
210
210
  }
211
211
 
@@ -257,8 +257,8 @@ async function processImage(absPath: string, opts: ProcessOptions): Promise<Proc
257
257
  }
258
258
 
259
259
  const formats: FormatSource[] = [...formatGroups.entries()].map(([fmt, group]) => ({
260
- type: `image/${fmt === "jpeg" ? "jpeg" : fmt}`,
261
- srcset: group.map((s) => `${s.src} ${s.width}w`).join(", "),
260
+ type: `image/${fmt === 'jpeg' ? 'jpeg' : fmt}`,
261
+ srcset: group.map((s) => `${s.src} ${s.width}w`).join(', '),
262
262
  }))
263
263
 
264
264
  // Fallback: last format's srcset
@@ -270,7 +270,7 @@ async function processImage(absPath: string, opts: ProcessOptions): Promise<Proc
270
270
 
271
271
  return {
272
272
  src: fallbackSources[fallbackSources.length - 1]?.src ?? absPath,
273
- srcset: fallbackFormat?.srcset ?? "",
273
+ srcset: fallbackFormat?.srcset ?? '',
274
274
  width: metadata.width,
275
275
  height: metadata.height,
276
276
  placeholder,
@@ -293,23 +293,23 @@ async function getImageMetadata(absPath: string): Promise<ImageMetadata> {
293
293
  const buffer = await readFile(absPath)
294
294
  const ext = extname(absPath).toLowerCase()
295
295
 
296
- if (ext === ".png") {
296
+ if (ext === '.png') {
297
297
  // PNG: width at bytes 16-19, height at 20-23 (big-endian)
298
298
  const width = buffer.readUInt32BE(16)
299
299
  const height = buffer.readUInt32BE(20)
300
- return { width, height, format: "png" }
300
+ return { width, height, format: 'png' }
301
301
  }
302
302
 
303
- if (ext === ".jpg" || ext === ".jpeg") {
303
+ if (ext === '.jpg' || ext === '.jpeg') {
304
304
  // JPEG: scan for SOF markers
305
305
  const dimensions = parseJpegDimensions(buffer)
306
- return { ...dimensions, format: "jpeg" }
306
+ return { ...dimensions, format: 'jpeg' }
307
307
  }
308
308
 
309
- if (ext === ".webp") {
309
+ if (ext === '.webp') {
310
310
  // WebP: VP8 header
311
311
  const dimensions = parseWebPDimensions(buffer)
312
- return { ...dimensions, format: "webp" }
312
+ return { ...dimensions, format: 'webp' }
313
313
  }
314
314
 
315
315
  // Fallback
@@ -343,21 +343,21 @@ export function parseWebPDimensions(buffer: Buffer): {
343
343
  height: number
344
344
  } {
345
345
  // RIFF header: bytes 0-3 = "RIFF", 8-11 = "WEBP"
346
- const chunk = buffer.toString("ascii", 12, 16)
347
- if (chunk === "VP8 ") {
346
+ const chunk = buffer.toString('ascii', 12, 16)
347
+ if (chunk === 'VP8 ') {
348
348
  // Lossy VP8
349
349
  const width = buffer.readUInt16LE(26) & 0x3fff
350
350
  const height = buffer.readUInt16LE(28) & 0x3fff
351
351
  return { width, height }
352
352
  }
353
- if (chunk === "VP8L") {
353
+ if (chunk === 'VP8L') {
354
354
  // Lossless VP8L
355
355
  const bits = buffer.readUInt32LE(21)
356
356
  const width = (bits & 0x3fff) + 1
357
357
  const height = ((bits >> 14) & 0x3fff) + 1
358
358
  return { width, height }
359
359
  }
360
- if (chunk === "VP8X") {
360
+ if (chunk === 'VP8X') {
361
361
  // Extended VP8X
362
362
  const width = 1 + ((buffer[24]! | (buffer[25]! << 8) | (buffer[26]! << 16)) & 0xffffff)
363
363
  const height = 1 + ((buffer[27]! | (buffer[28]! << 8) | (buffer[29]! << 16)) & 0xffffff)
@@ -379,20 +379,20 @@ async function resizeImage(
379
379
  ): Promise<void> {
380
380
  try {
381
381
  // Try sharp (the standard Node.js image processing library)
382
- const sharp = await import("sharp").then((m) => m.default ?? m)
382
+ const sharp = await import('sharp').then((m) => m.default ?? m)
383
383
  let pipeline = sharp(input).resize(width)
384
384
 
385
385
  switch (format) {
386
- case "webp":
386
+ case 'webp':
387
387
  pipeline = pipeline.webp({ quality })
388
388
  break
389
- case "avif":
389
+ case 'avif':
390
390
  pipeline = pipeline.avif({ quality })
391
391
  break
392
- case "jpeg":
392
+ case 'jpeg':
393
393
  pipeline = pipeline.jpeg({ quality, mozjpeg: true })
394
394
  break
395
- case "png":
395
+ case 'png':
396
396
  pipeline = pipeline.png({ compressionLevel: 9 })
397
397
  break
398
398
  }
@@ -411,14 +411,14 @@ async function resizeImage(
411
411
  */
412
412
  async function generateBlurPlaceholder(input: string, size: number): Promise<string> {
413
413
  try {
414
- const sharp = await import("sharp").then((m) => m.default ?? m)
414
+ const sharp = await import('sharp').then((m) => m.default ?? m)
415
415
  const buffer = await sharp(input)
416
- .resize(size, size, { fit: "inside" })
416
+ .resize(size, size, { fit: 'inside' })
417
417
  .blur(2)
418
418
  .webp({ quality: 20 })
419
419
  .toBuffer()
420
420
 
421
- return `data:image/webp;base64,${buffer.toString("base64")}`
421
+ return `data:image/webp;base64,${buffer.toString('base64')}`
422
422
  } catch {
423
423
  // sharp not available — return a transparent placeholder
424
424
  return "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1' height='1'%3E%3C/svg%3E"
package/src/image.tsx CHANGED
@@ -1,8 +1,8 @@
1
- import type { VNodeChild } from "@pyreon/core"
2
- import { createRef } from "@pyreon/core"
3
- import { signal } from "@pyreon/reactivity"
4
- import type { FormatSource } from "./image-plugin"
5
- import { useIntersectionObserver } from "./utils/use-intersection-observer"
1
+ import type { VNodeChild } from '@pyreon/core'
2
+ import { createRef } from '@pyreon/core'
3
+ import { signal } from '@pyreon/reactivity'
4
+ import type { FormatSource } from './image-plugin'
5
+ import { useIntersectionObserver } from './utils/use-intersection-observer'
6
6
 
7
7
  // ─── Image optimization component ───────────────────────────────────────────
8
8
  //
@@ -30,7 +30,7 @@ export interface ImageProps {
30
30
  /** Per-format source sets for <picture>. Provided automatically by imagePlugin. */
31
31
  formats?: FormatSource[]
32
32
  /** Loading strategy. "lazy" uses IntersectionObserver, "eager" loads immediately. Default: "lazy" */
33
- loading?: "lazy" | "eager"
33
+ loading?: 'lazy' | 'eager'
34
34
  /** Mark as priority (LCP image). Disables lazy loading, adds fetchPriority="high". */
35
35
  priority?: boolean
36
36
  /** Low-quality placeholder image URL or base64 data URI for blur-up effect. */
@@ -40,9 +40,9 @@ export interface ImageProps {
40
40
  /** Inline styles. */
41
41
  style?: string
42
42
  /** CSS object-fit. Default: "cover" */
43
- fit?: "cover" | "contain" | "fill" | "none" | "scale-down"
43
+ fit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'
44
44
  /** Decode async. Default: true */
45
- decoding?: "sync" | "async" | "auto"
45
+ decoding?: 'sync' | 'async' | 'auto'
46
46
  }
47
47
 
48
48
  export interface ImageSource {
@@ -64,19 +64,19 @@ export interface ImageSource {
64
64
  * <Image src="/hero.jpg" alt="Hero" width={1200} height={630} />
65
65
  */
66
66
  export function Image(props: ImageProps): VNodeChild {
67
- const isEager = props.priority || props.loading === "eager"
67
+ const isEager = props.priority || props.loading === 'eager'
68
68
  const loaded = signal(isEager)
69
69
  const inView = signal(isEager)
70
70
  const containerRef = createRef<HTMLElement>()
71
71
 
72
72
  // Resolve srcset from string or array
73
73
  const resolvedSrcset =
74
- typeof props.srcset === "string"
74
+ typeof props.srcset === 'string'
75
75
  ? props.srcset
76
- : props.srcset?.map((s) => `${s.src} ${s.width}w`).join(", ")
76
+ : props.srcset?.map((s) => `${s.src} ${s.width}w`).join(', ')
77
77
 
78
- const sizes = props.sizes ?? "100vw"
79
- const fit = props.fit ?? "cover"
78
+ const sizes = props.sizes ?? '100vw'
79
+ const fit = props.fit ?? 'cover'
80
80
  const hasFormats = props.formats && props.formats.length > 0
81
81
  const aspectRatio = `${props.width} / ${props.height}`
82
82
 
@@ -89,37 +89,37 @@ export function Image(props: ImageProps): VNodeChild {
89
89
 
90
90
  // Static styles (don't depend on signals)
91
91
  const containerStyle = [
92
- "position: relative",
93
- "overflow: hidden",
92
+ 'position: relative',
93
+ 'overflow: hidden',
94
94
  `aspect-ratio: ${aspectRatio}`,
95
95
  `max-width: ${props.width}px`,
96
- "width: 100%",
96
+ 'width: 100%',
97
97
  props.style,
98
98
  ]
99
99
  .filter(Boolean)
100
- .join("; ")
100
+ .join('; ')
101
101
 
102
102
  const imgEl = (
103
103
  <img
104
- src={() => (inView() ? props.src : "")}
105
- srcSet={() => (!hasFormats && inView() && resolvedSrcset ? resolvedSrcset : "")}
104
+ src={() => (inView() ? props.src : '')}
105
+ srcSet={() => (!hasFormats && inView() && resolvedSrcset ? resolvedSrcset : '')}
106
106
  sizes={resolvedSrcset ? sizes : undefined}
107
107
  alt={props.alt}
108
108
  width={props.width}
109
109
  height={props.height}
110
- loading={isEager ? "eager" : "lazy"}
111
- decoding={props.decoding ?? "async"}
112
- fetchPriority={props.priority ? "high" : undefined}
110
+ loading={isEager ? 'eager' : 'lazy'}
111
+ decoding={props.decoding ?? 'async'}
112
+ fetchPriority={props.priority ? 'high' : undefined}
113
113
  onLoad={() => loaded.set(true)}
114
114
  style={() =>
115
115
  [
116
- "display: block",
117
- "width: 100%",
118
- "height: 100%",
116
+ 'display: block',
117
+ 'width: 100%',
118
+ 'height: 100%',
119
119
  `object-fit: ${fit}`,
120
- "transition: opacity 0.3s ease",
121
- props.placeholder && !loaded() ? "opacity: 0" : "opacity: 1",
122
- ].join("; ")
120
+ 'transition: opacity 0.3s ease',
121
+ props.placeholder && !loaded() ? 'opacity: 0' : 'opacity: 1',
122
+ ].join('; ')
123
123
  }
124
124
  />
125
125
  )
@@ -134,16 +134,16 @@ export function Image(props: ImageProps): VNodeChild {
134
134
  loading="eager"
135
135
  style={() =>
136
136
  [
137
- "position: absolute",
138
- "inset: 0",
139
- "width: 100%",
140
- "height: 100%",
141
- "object-fit: cover",
142
- "filter: blur(20px)",
143
- "transform: scale(1.1)",
144
- "transition: opacity 0.4s ease",
145
- loaded() ? "opacity: 0; pointer-events: none" : "opacity: 1",
146
- ].join("; ")
137
+ 'position: absolute',
138
+ 'inset: 0',
139
+ 'width: 100%',
140
+ 'height: 100%',
141
+ 'object-fit: cover',
142
+ 'filter: blur(20px)',
143
+ 'transform: scale(1.1)',
144
+ 'transition: opacity 0.4s ease',
145
+ loaded() ? 'opacity: 0; pointer-events: none' : 'opacity: 1',
146
+ ].join('; ')
147
147
  }
148
148
  />
149
149
  )}
@@ -152,7 +152,7 @@ export function Image(props: ImageProps): VNodeChild {
152
152
  {props.formats?.map((fmt) => (
153
153
  <source
154
154
  type={fmt.type}
155
- srcSet={() => (inView() ? (fmt.srcset ?? "") : "")}
155
+ srcSet={() => (inView() ? (fmt.srcset ?? '') : '')}
156
156
  sizes={sizes}
157
157
  />
158
158
  ))}
package/src/index.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  // ─── Core ─────────────────────────────────────────────────────────────────────
2
2
 
3
- export type { CreateAppOptions } from "./app"
4
- export { createApp } from "./app"
5
- export type { CreateServerOptions } from "./entry-server"
6
- export { createServer } from "./entry-server"
3
+ export type { CreateAppOptions } from './app'
4
+ export { createApp } from './app'
5
+ export type { CreateServerOptions } from './entry-server'
6
+ export { createServer } from './entry-server'
7
7
 
8
8
  // ─── Vite plugin ─────────────────────────────────────────────────────────────
9
9
 
10
- export { zeroPlugin as default } from "./vite-plugin"
10
+ export { zeroPlugin as default } from './vite-plugin'
11
11
 
12
12
  // ─── File-system routing ─────────────────────────────────────────────────────
13
13
 
@@ -17,38 +17,33 @@ export {
17
17
  generateRouteModule,
18
18
  parseFileRoutes,
19
19
  scanRouteFiles,
20
- } from "./fs-router"
20
+ } from './fs-router'
21
21
 
22
22
  // ─── Config ──────────────────────────────────────────────────────────────────
23
23
 
24
- export { defineConfig, resolveConfig } from "./config"
24
+ export { defineConfig, resolveConfig } from './config'
25
25
 
26
26
  // ─── ISR ─────────────────────────────────────────────────────────────────────
27
27
 
28
- export { createISRHandler } from "./isr"
28
+ export { createISRHandler } from './isr'
29
29
 
30
30
  // ─── Adapters ────────────────────────────────────────────────────────────────
31
31
 
32
- export {
33
- bunAdapter,
34
- nodeAdapter,
35
- resolveAdapter,
36
- staticAdapter,
37
- } from "./adapters"
32
+ export { bunAdapter, nodeAdapter, resolveAdapter, staticAdapter } from './adapters'
38
33
 
39
34
  // ─── Components ─────────────────────────────────────────────────────────────
40
35
 
41
- export type { ImageProps, ImageSource } from "./image"
42
- export { Image } from "./image"
43
- export type { LinkProps, LinkRenderProps, UseLinkReturn } from "./link"
44
- export { createLink, Link, useLink } from "./link"
45
- export type { ScriptProps, ScriptStrategy } from "./script"
46
- export { Script } from "./script"
36
+ export type { ImageProps, ImageSource } from './image'
37
+ export { Image } from './image'
38
+ export type { LinkProps, LinkRenderProps, UseLinkReturn } from './link'
39
+ export { createLink, Link, useLink } from './link'
40
+ export type { ScriptProps, ScriptStrategy } from './script'
41
+ export { Script } from './script'
47
42
 
48
43
  // ─── Middleware ──────────────────────────────────────────────────────────────
49
44
 
50
- export type { CacheConfig, CacheRule } from "./cache"
51
- export { cacheMiddleware, securityHeaders, varyEncoding } from "./cache"
45
+ export type { CacheConfig, CacheRule } from './cache'
46
+ export { cacheMiddleware, securityHeaders, varyEncoding } from './cache'
52
47
 
53
48
  // ─── Font optimization ─────────────────────────────────────────────────────
54
49
 
@@ -60,22 +55,17 @@ export type {
60
55
  GoogleFontStatic,
61
56
  GoogleFontVariable,
62
57
  LocalFont,
63
- } from "./font"
64
- export { fontPlugin, fontVariables } from "./font"
58
+ } from './font'
59
+ export { fontPlugin, fontVariables } from './font'
65
60
 
66
61
  // ─── Image processing ──────────────────────────────────────────────────────
67
62
 
68
- export type {
69
- FormatSource,
70
- ImageFormat,
71
- ImagePluginConfig,
72
- ProcessedImage,
73
- } from "./image-plugin"
74
- export { imagePlugin } from "./image-plugin"
63
+ export type { FormatSource, ImageFormat, ImagePluginConfig, ProcessedImage } from './image-plugin'
64
+ export { imagePlugin } from './image-plugin'
75
65
 
76
66
  // ─── Theme ──────────────────────────────────────────────────────────────────
77
67
 
78
- export type { Theme } from "./theme"
68
+ export type { Theme } from './theme'
79
69
  export {
80
70
  initTheme,
81
71
  resolvedTheme,
@@ -84,7 +74,7 @@ export {
84
74
  theme,
85
75
  themeScript,
86
76
  toggleTheme,
87
- } from "./theme"
77
+ } from './theme'
88
78
 
89
79
  // ─── SEO ────────────────────────────────────────────────────────────────────
90
80
 
@@ -96,14 +86,8 @@ export type {
96
86
  SeoPluginConfig,
97
87
  SitemapConfig,
98
88
  SitemapEntry,
99
- } from "./seo"
100
- export {
101
- generateRobots,
102
- generateSitemap,
103
- jsonLd,
104
- seoMiddleware,
105
- seoPlugin,
106
- } from "./seo"
89
+ } from './seo'
90
+ export { generateRobots, generateSitemap, jsonLd, seoMiddleware, seoPlugin } from './seo'
107
91
 
108
92
  // ─── API routes ──────────────────────────────────────────────────────────────
109
93
 
@@ -113,32 +97,28 @@ export type {
113
97
  ApiRouteEntry,
114
98
  ApiRouteModule,
115
99
  HttpMethod,
116
- } from "./api-routes"
117
- export { createApiMiddleware, generateApiRouteModule } from "./api-routes"
100
+ } from './api-routes'
101
+ export { createApiMiddleware, generateApiRouteModule } from './api-routes'
118
102
 
119
103
  // ─── CORS ────────────────────────────────────────────────────────────────────
120
104
 
121
- export type { CorsConfig } from "./cors"
122
- export { corsMiddleware } from "./cors"
105
+ export type { CorsConfig } from './cors'
106
+ export { corsMiddleware } from './cors'
123
107
 
124
108
  // ─── Rate limiting ──────────────────────────────────────────────────────────
125
109
 
126
- export type { RateLimitConfig } from "./rate-limit"
127
- export { rateLimitMiddleware } from "./rate-limit"
110
+ export type { RateLimitConfig } from './rate-limit'
111
+ export { rateLimitMiddleware } from './rate-limit'
128
112
 
129
113
  // ─── Compression ────────────────────────────────────────────────────────────
130
114
 
131
- export type { CompressionConfig } from "./compression"
132
- export {
133
- compressionMiddleware,
134
- compressResponse,
135
- isCompressible,
136
- } from "./compression"
115
+ export type { CompressionConfig } from './compression'
116
+ export { compressionMiddleware, compressResponse, isCompressible } from './compression'
137
117
 
138
118
  // ─── Actions ─────────────────────────────────────────────────────────────────
139
119
 
140
- export type { Action, ActionContext, ActionHandler } from "./actions"
141
- export { createActionMiddleware, defineAction } from "./actions"
120
+ export type { Action, ActionContext, ActionHandler } from './actions'
121
+ export { createActionMiddleware, defineAction } from './actions'
142
122
 
143
123
  // ─── Types ───────────────────────────────────────────────────────────────────
144
124
 
@@ -153,4 +133,4 @@ export type {
153
133
  RouteMiddlewareEntry,
154
134
  RouteModule,
155
135
  ZeroConfig,
156
- } from "./types"
136
+ } from './types'
package/src/isr.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ISRConfig } from "./types"
1
+ import type { ISRConfig } from './types'
2
2
 
3
3
  // ─── ISR Cache ───────────────────────────────────────────────────────────────
4
4
 
@@ -28,7 +28,7 @@ export function createISRHandler(
28
28
  revalidating.add(key)
29
29
 
30
30
  try {
31
- const req = new Request(url.href, { method: "GET" })
31
+ const req = new Request(url.href, { method: 'GET' })
32
32
  const res = await handler(req)
33
33
  const html = await res.text()
34
34
  const headers: Record<string, string> = {}
@@ -46,7 +46,7 @@ export function createISRHandler(
46
46
 
47
47
  return async (req: Request): Promise<Response> => {
48
48
  // Only cache GET requests
49
- if (req.method !== "GET") {
49
+ if (req.method !== 'GET') {
50
50
  return handler(req)
51
51
  }
52
52
 
@@ -66,9 +66,9 @@ export function createISRHandler(
66
66
  status: 200,
67
67
  headers: {
68
68
  ...entry.headers,
69
- "content-type": "text/html; charset=utf-8",
70
- "x-isr-cache": age > revalidateMs ? "STALE" : "HIT",
71
- "x-isr-age": String(Math.round(age / 1000)),
69
+ 'content-type': 'text/html; charset=utf-8',
70
+ 'x-isr-cache': age > revalidateMs ? 'STALE' : 'HIT',
71
+ 'x-isr-age': String(Math.round(age / 1000)),
72
72
  },
73
73
  })
74
74
  }
@@ -87,8 +87,8 @@ export function createISRHandler(
87
87
  status: 200,
88
88
  headers: {
89
89
  ...headers,
90
- "content-type": "text/html; charset=utf-8",
91
- "x-isr-cache": "MISS",
90
+ 'content-type': 'text/html; charset=utf-8',
91
+ 'x-isr-cache': 'MISS',
92
92
  },
93
93
  })
94
94
  }