@wular/pnext 0.0.1

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 (371) hide show
  1. package/README.md +153 -0
  2. package/bin/pnext +67 -0
  3. package/config/lint/base.js +48 -0
  4. package/config/ts/base.json +26 -0
  5. package/config/ts/react.json +13 -0
  6. package/package.json +70 -0
  7. package/reference/compat.md +63 -0
  8. package/reference/config.md +120 -0
  9. package/reference/css.md +58 -0
  10. package/reference/dev.md +69 -0
  11. package/reference/env.md +40 -0
  12. package/reference/metadata.md +86 -0
  13. package/reference/navigation.md +149 -0
  14. package/reference/overview.md +35 -0
  15. package/reference/performance.md +97 -0
  16. package/reference/rendering.md +127 -0
  17. package/reference/routing.md +167 -0
  18. package/reference/typegen.md +64 -0
  19. package/src/api/cache.ts +80 -0
  20. package/src/api/client-cache.ts +9 -0
  21. package/src/api/client-navigation.ts +279 -0
  22. package/src/api/dynamic.tsx +102 -0
  23. package/src/api/link.tsx +119 -0
  24. package/src/api/navigation.ts +198 -0
  25. package/src/api/router/events.ts +53 -0
  26. package/src/api/router/history.ts +70 -0
  27. package/src/api/router/hub.ts +194 -0
  28. package/src/api/router/policies.ts +107 -0
  29. package/src/api/router/runtime.ts +5238 -0
  30. package/src/api/router/types.ts +299 -0
  31. package/src/api/router.ts +167 -0
  32. package/src/api/server.ts +323 -0
  33. package/src/api/suspense.ts +16 -0
  34. package/src/cache/context.ts +61 -0
  35. package/src/cli/adapters/vercel-warm.ts +375 -0
  36. package/src/cli/adapters/vercel.ts +1310 -0
  37. package/src/cli/analyze-print.ts +181 -0
  38. package/src/cli/analyze.ts +328 -0
  39. package/src/cli/boot-trace.ts +29 -0
  40. package/src/cli/build.ts +3114 -0
  41. package/src/cli/dev.ts +276 -0
  42. package/src/cli/index.ts +196 -0
  43. package/src/cli/named-bin.ts +119 -0
  44. package/src/cli/serve-ui.ts +160 -0
  45. package/src/cli/start.ts +1425 -0
  46. package/src/client/build.ts +2136 -0
  47. package/src/client/chunk-fold.ts +526 -0
  48. package/src/client/entry.ts +1525 -0
  49. package/src/client/paths.ts +22 -0
  50. package/src/client/prebuilt.ts +621 -0
  51. package/src/client/profile.ts +75 -0
  52. package/src/client/react-compiler.ts +94 -0
  53. package/src/client/reference-stub.ts +145 -0
  54. package/src/client/reference.ts +47 -0
  55. package/src/compat/actions/action-client.ts +531 -0
  56. package/src/compat/actions/action-dispatch.ts +676 -0
  57. package/src/compat/actions/action-router.ts +40 -0
  58. package/src/compat/actions/action-shared.ts +95 -0
  59. package/src/compat/actions/client-plugin.ts +135 -0
  60. package/src/compat/actions/client-stub.ts +65 -0
  61. package/src/compat/actions/config.ts +164 -0
  62. package/src/compat/actions/detect.ts +208 -0
  63. package/src/compat/actions/discovery.ts +244 -0
  64. package/src/compat/actions/early-submit.ts +40 -0
  65. package/src/compat/actions/endpoint.ts +602 -0
  66. package/src/compat/actions/flight.ts +52 -0
  67. package/src/compat/actions/form-state.ts +73 -0
  68. package/src/compat/actions/hoist.ts +485 -0
  69. package/src/compat/actions/ids.ts +39 -0
  70. package/src/compat/actions/index.ts +41 -0
  71. package/src/compat/actions/instances.ts +144 -0
  72. package/src/compat/actions/origin.ts +109 -0
  73. package/src/compat/actions/protocol.ts +125 -0
  74. package/src/compat/actions/registry.ts +74 -0
  75. package/src/compat/actions/rewrite.ts +282 -0
  76. package/src/compat/actions/serve.ts +414 -0
  77. package/src/compat/actions/server-tag.ts +21 -0
  78. package/src/compat/actions/unrecognized-error.ts +30 -0
  79. package/src/compat/adapter/build-complete.ts +257 -0
  80. package/src/compat/bundler/bun-externals.ts +53 -0
  81. package/src/compat/bundler/cjs-exports.ts +542 -0
  82. package/src/compat/bundler/config.ts +363 -0
  83. package/src/compat/bundler/externals.ts +34 -0
  84. package/src/compat/bundler/import-meta-url.ts +60 -0
  85. package/src/compat/bundler/modularize-imports.ts +119 -0
  86. package/src/compat/bundler/new-url-asset.ts +87 -0
  87. package/src/compat/bundler/optimize-package-imports.ts +273 -0
  88. package/src/compat/bundler/polyfill.ts +88 -0
  89. package/src/compat/bundler/react-compiler.ts +61 -0
  90. package/src/compat/bundler/react-profiler.tsx +25 -0
  91. package/src/compat/bundler/relay-transform.ts +116 -0
  92. package/src/compat/bundler/require-context.ts +281 -0
  93. package/src/compat/bundler/resolve-extensions.ts +75 -0
  94. package/src/compat/bundler/source-cache.ts +61 -0
  95. package/src/compat/bundler/static-imports.ts +25 -0
  96. package/src/compat/bundler/symlink-imports.ts +119 -0
  97. package/src/compat/bundler/tsconfig-paths.ts +50 -0
  98. package/src/compat/bundler/wasm.ts +153 -0
  99. package/src/compat/bundler/webpack-loaders.ts +685 -0
  100. package/src/compat/bundler/worker.ts +278 -0
  101. package/src/compat/cache/build-flags.ts +81 -0
  102. package/src/compat/cache/build-prerender-errors.ts +163 -0
  103. package/src/compat/cache/custom-handler.ts +159 -0
  104. package/src/compat/cache/fetch-patch.ts +745 -0
  105. package/src/compat/cache/handler.ts +100 -0
  106. package/src/compat/cache/modern-handler.ts +275 -0
  107. package/src/compat/cache/resume-data-cache.ts +143 -0
  108. package/src/compat/cache/revalidate.ts +759 -0
  109. package/src/compat/cache/runtime-error.ts +124 -0
  110. package/src/compat/cache/use-cache-transform.ts +961 -0
  111. package/src/compat/cache/use-cache.ts +1695 -0
  112. package/src/compat/cache-control.ts +269 -0
  113. package/src/compat/client/base-path.ts +64 -0
  114. package/src/compat/client/css-order.ts +36 -0
  115. package/src/compat/client/errors/control-flow.ts +92 -0
  116. package/src/compat/client/errors/error-boundary.ts +222 -0
  117. package/src/compat/client/errors/global-error.ts +238 -0
  118. package/src/compat/client/errors/install.ts +217 -0
  119. package/src/compat/client/errors/lazy.ts +53 -0
  120. package/src/compat/client/errors/primitive-throw.ts +126 -0
  121. package/src/compat/client/errors/soft-refresh.ts +14 -0
  122. package/src/compat/client/link-status.ts +86 -0
  123. package/src/compat/client/nav-compat-runtime.ts +57 -0
  124. package/src/compat/client/nav-compat.ts +42 -0
  125. package/src/compat/client/navigation-scroll.ts +154 -0
  126. package/src/compat/client/optimistic-routing.ts +206 -0
  127. package/src/compat/client/prefetch-cache.ts +111 -0
  128. package/src/compat/client/route-announcer.ts +72 -0
  129. package/src/compat/client/segment-cache-policy.ts +159 -0
  130. package/src/compat/client/segment-cache.ts +1077 -0
  131. package/src/compat/client/segment-prefetch.ts +375 -0
  132. package/src/compat/client/trailing-slash.ts +24 -0
  133. package/src/compat/css/chunking.ts +254 -0
  134. package/src/compat/css/inline-css.ts +73 -0
  135. package/src/compat/css/lightningcss.ts +90 -0
  136. package/src/compat/css/modules.ts +373 -0
  137. package/src/compat/css/nonce.ts +30 -0
  138. package/src/compat/css/sass-plugin.ts +65 -0
  139. package/src/compat/css/sass.ts +392 -0
  140. package/src/compat/css/styled-jsx-runtime.ts +80 -0
  141. package/src/compat/css/styled-jsx.ts +49 -0
  142. package/src/compat/edge-runtime.ts +71 -0
  143. package/src/compat/export/client.ts +112 -0
  144. package/src/compat/export/index.ts +272 -0
  145. package/src/compat/export/standalone.ts +207 -0
  146. package/src/compat/image-optimizer/cache.ts +119 -0
  147. package/src/compat/image-optimizer/detect.ts +143 -0
  148. package/src/compat/image-optimizer/index.ts +601 -0
  149. package/src/compat/image-optimizer/source.ts +243 -0
  150. package/src/compat/index.ts +458 -0
  151. package/src/compat/lifecycle/after-scope.ts +86 -0
  152. package/src/compat/lifecycle/after.ts +173 -0
  153. package/src/compat/lifecycle/error-funnel.ts +306 -0
  154. package/src/compat/lifecycle/error-serialize.ts +87 -0
  155. package/src/compat/lifecycle/error-ui.ts +167 -0
  156. package/src/compat/lifecycle/instrumentation-client.ts +138 -0
  157. package/src/compat/lifecycle/instrumentation.ts +277 -0
  158. package/src/compat/lifecycle/node-console.ts +19 -0
  159. package/src/compat/lifecycle/testmode.ts +263 -0
  160. package/src/compat/mdx/compile.ts +219 -0
  161. package/src/compat/mdx/next-mdx-stub.ts +46 -0
  162. package/src/compat/mdx/plugin.ts +37 -0
  163. package/src/compat/metadata-route-artifacts.ts +458 -0
  164. package/src/compat/metadata.ts +295 -0
  165. package/src/compat/middleware/manifest.ts +210 -0
  166. package/src/compat/misc/action-return.ts +173 -0
  167. package/src/compat/next/cache.ts +211 -0
  168. package/src/compat/next/canonical-url.ts +35 -0
  169. package/src/compat/next/client-cache.ts +57 -0
  170. package/src/compat/next/client-navigation.ts +313 -0
  171. package/src/compat/next/client-only.ts +3 -0
  172. package/src/compat/next/client-script.tsx +215 -0
  173. package/src/compat/next/client-server.ts +39 -0
  174. package/src/compat/next/config-loader.ts +569 -0
  175. package/src/compat/next/config.ts +29 -0
  176. package/src/compat/next/constants.cjs +6 -0
  177. package/src/compat/next/constants.ts +6 -0
  178. package/src/compat/next/custom-server.ts +236 -0
  179. package/src/compat/next/dist/client/components/app-router-headers.ts +32 -0
  180. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +38 -0
  181. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -0
  182. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -0
  183. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -0
  184. package/src/compat/next/dynamic.tsx +46 -0
  185. package/src/compat/next/error.tsx +148 -0
  186. package/src/compat/next/font/cache.ts +171 -0
  187. package/src/compat/next/font/google.ts +2 -0
  188. package/src/compat/next/font/index.ts +8 -0
  189. package/src/compat/next/font/local.ts +5 -0
  190. package/src/compat/next/font/runtime-client.ts +71 -0
  191. package/src/compat/next/font/runtime.ts +974 -0
  192. package/src/compat/next/font/shared.ts +281 -0
  193. package/src/compat/next/form.tsx +156 -0
  194. package/src/compat/next/head.tsx +10 -0
  195. package/src/compat/next/headers.ts +247 -0
  196. package/src/compat/next/image/config.ts +196 -0
  197. package/src/compat/next/image/optimizer.ts +96 -0
  198. package/src/compat/next/image/patterns.ts +103 -0
  199. package/src/compat/next/image/shared.ts +141 -0
  200. package/src/compat/next/image/static-metadata.ts +283 -0
  201. package/src/compat/next/image/validate.ts +269 -0
  202. package/src/compat/next/image-client.tsx +215 -0
  203. package/src/compat/next/image-props.ts +575 -0
  204. package/src/compat/next/image-usage.ts +102 -0
  205. package/src/compat/next/image.tsx +56 -0
  206. package/src/compat/next/index.ts +1 -0
  207. package/src/compat/next/legacy-image.tsx +97 -0
  208. package/src/compat/next/link-usage.ts +29 -0
  209. package/src/compat/next/link-validation-transform.ts +200 -0
  210. package/src/compat/next/link.tsx +466 -0
  211. package/src/compat/next/navigation.cjs +21 -0
  212. package/src/compat/next/navigation.ts +188 -0
  213. package/src/compat/next/offline.ts +51 -0
  214. package/src/compat/next/og.ts +324 -0
  215. package/src/compat/next/optimistic-route-state.ts +188 -0
  216. package/src/compat/next/preferred-region.ts +39 -0
  217. package/src/compat/next/redirects.ts +131 -0
  218. package/src/compat/next/resource-hints.ts +136 -0
  219. package/src/compat/next/rewrites.ts +350 -0
  220. package/src/compat/next/root-params.ts +142 -0
  221. package/src/compat/next/router.cjs +49 -0
  222. package/src/compat/next/router.ts +143 -0
  223. package/src/compat/next/script.tsx +355 -0
  224. package/src/compat/next/server-only.ts +3 -0
  225. package/src/compat/next/server.ts +28 -0
  226. package/src/compat/next/svgr.ts +58 -0
  227. package/src/compat/next/telemetry.ts +77 -0
  228. package/src/compat/next/user-agent.ts +100 -0
  229. package/src/compat/next/web-vitals.ts +56 -0
  230. package/src/compat/otel/api.ts +95 -0
  231. package/src/compat/otel/client-trace-metadata.ts +71 -0
  232. package/src/compat/otel/fetch-span.ts +77 -0
  233. package/src/compat/otel/tracer.ts +944 -0
  234. package/src/compat/pages/client-plugin.ts +108 -0
  235. package/src/compat/pages/index.ts +527 -0
  236. package/src/compat/pages/router-state.ts +94 -0
  237. package/src/compat/ppr/io.ts +38 -0
  238. package/src/compat/ppr/missing-root-params.ts +105 -0
  239. package/src/compat/ppr/root-params-scan.ts +164 -0
  240. package/src/compat/ppr/root-params-transform.ts +75 -0
  241. package/src/compat/ppr/root-params.ts +129 -0
  242. package/src/compat/ppr/segment-config-incompat.ts +34 -0
  243. package/src/compat/protocol.ts +202 -0
  244. package/src/compat/react/client.ts +59 -0
  245. package/src/compat/react/compiler-runtime.ts +60 -0
  246. package/src/compat/react/dom-client.ts +115 -0
  247. package/src/compat/react/dom-react-server.ts +20 -0
  248. package/src/compat/react/dom-server.ts +40 -0
  249. package/src/compat/react/dom.ts +154 -0
  250. package/src/compat/react/preact.ts +522 -0
  251. package/src/compat/react/react-server.ts +84 -0
  252. package/src/compat/react/router-shim.ts +26 -0
  253. package/src/compat/react/server-component-use.ts +48 -0
  254. package/src/compat/react/server-inserted-html.ts +87 -0
  255. package/src/compat/react/server.ts +156 -0
  256. package/src/compat/react/view-transition.ts +60 -0
  257. package/src/compat/register/actions.ts +875 -0
  258. package/src/compat/register/boot.ts +141 -0
  259. package/src/compat/register/build-tier.ts +11 -0
  260. package/src/compat/register/build.ts +182 -0
  261. package/src/compat/register/bundler.ts +587 -0
  262. package/src/compat/register/cache.ts +85 -0
  263. package/src/compat/register/client-errors.ts +18 -0
  264. package/src/compat/register/config.ts +17 -0
  265. package/src/compat/register/css-extras.ts +120 -0
  266. package/src/compat/register/edge-runtime.ts +6 -0
  267. package/src/compat/register/errors.ts +46 -0
  268. package/src/compat/register/export.ts +23 -0
  269. package/src/compat/register/font.ts +36 -0
  270. package/src/compat/register/hooks.ts +34 -0
  271. package/src/compat/register/image.ts +133 -0
  272. package/src/compat/register/index.ts +111 -0
  273. package/src/compat/register/instrumentation-client.ts +35 -0
  274. package/src/compat/register/lifecycle.ts +86 -0
  275. package/src/compat/register/mdx.ts +48 -0
  276. package/src/compat/register/middleware.ts +36 -0
  277. package/src/compat/register/misc.ts +44 -0
  278. package/src/compat/register/otel.ts +288 -0
  279. package/src/compat/register/pages-api.ts +473 -0
  280. package/src/compat/register/ppr.ts +56 -0
  281. package/src/compat/register/protocol.ts +57 -0
  282. package/src/compat/register/proxy.ts +127 -0
  283. package/src/compat/register/render.ts +268 -0
  284. package/src/compat/register/routing.ts +410 -0
  285. package/src/compat/register/segment.ts +1903 -0
  286. package/src/compat/register/static-image.ts +21 -0
  287. package/src/compat/register/typed-routes.ts +35 -0
  288. package/src/compat/register/usecache.ts +131 -0
  289. package/src/compat/register/validation.ts +56 -0
  290. package/src/compat/segment/loading-boundary.ts +113 -0
  291. package/src/compat/segment/page-slot.ts +200 -0
  292. package/src/compat/segment/tree.ts +481 -0
  293. package/src/compat/segment/vary-key.ts +102 -0
  294. package/src/compat/segment/vary-params.ts +551 -0
  295. package/src/compat/static-params.ts +33 -0
  296. package/src/compat/tsconfig-defaults.ts +301 -0
  297. package/src/compat/typecheck/index.ts +1481 -0
  298. package/src/compat/typecheck/worker.ts +26 -0
  299. package/src/compat/typed-routes/index.ts +92 -0
  300. package/src/compat/typed-routes/manifest.ts +356 -0
  301. package/src/compat/typed-routes/typegen.ts +566 -0
  302. package/src/compat/validation/errors.ts +159 -0
  303. package/src/compat/validation/index.ts +1770 -0
  304. package/src/compat/validation/prerender-diagnostics.ts +1508 -0
  305. package/src/compat-bootstrap.ts +67 -0
  306. package/src/config.ts +218 -0
  307. package/src/css/build.ts +697 -0
  308. package/src/css/index.ts +2 -0
  309. package/src/css/postcss.ts +236 -0
  310. package/src/css/worker.ts +34 -0
  311. package/src/dev/client-actions.ts +35 -0
  312. package/src/dev/client-chunk-store.ts +92 -0
  313. package/src/dev/client-key-cache.ts +178 -0
  314. package/src/dev/global-css-cache.ts +212 -0
  315. package/src/dev/imports.ts +2430 -0
  316. package/src/dev/module-cache.ts +721 -0
  317. package/src/dev/module-generations.ts +38 -0
  318. package/src/dev/module-transform.ts +188 -0
  319. package/src/dev/node-module-bundle-cache.ts +63 -0
  320. package/src/dev/restart-cache.ts +10 -0
  321. package/src/dev/route-bundle-key-cache.ts +154 -0
  322. package/src/dev/route-facts-cache.ts +223 -0
  323. package/src/dev/server.ts +1710 -0
  324. package/src/dynamic/source.ts +307 -0
  325. package/src/dynamic/tree-shake.ts +262 -0
  326. package/src/env.ts +92 -0
  327. package/src/extensions.ts +1898 -0
  328. package/src/index.ts +34 -0
  329. package/src/internal.ts +43 -0
  330. package/src/islands/boundary-error.ts +8 -0
  331. package/src/islands/static-children.ts +37 -0
  332. package/src/islands/static-slots.ts +106 -0
  333. package/src/ppr-postpone.ts +24 -0
  334. package/src/ppr.ts +784 -0
  335. package/src/proxy.ts +752 -0
  336. package/src/render/hooks.ts +384 -0
  337. package/src/render/index.ts +1 -0
  338. package/src/render/island-context.ts +47 -0
  339. package/src/render/metadata.ts +857 -0
  340. package/src/render/renderer.ts +7391 -0
  341. package/src/render/resource-hints.ts +44 -0
  342. package/src/render/slots.tsx +679 -0
  343. package/src/request/context.ts +396 -0
  344. package/src/resolve/engine.ts +219 -0
  345. package/src/resolve/imports.ts +1104 -0
  346. package/src/resolve/scan-facts.ts +474 -0
  347. package/src/resolve/source-text.ts +86 -0
  348. package/src/routing/forwarded.ts +41 -0
  349. package/src/routing/handler.ts +271 -0
  350. package/src/routing/href.ts +203 -0
  351. package/src/routing/metadata.ts +1018 -0
  352. package/src/routing/request-runtime.ts +43 -0
  353. package/src/routing/routes.ts +2560 -0
  354. package/src/routing/slots.ts +432 -0
  355. package/src/runtime/server.ts +3453 -0
  356. package/src/runtime/vendor.ts +1160 -0
  357. package/src/style-modules.d.ts +9 -0
  358. package/src/typegen.ts +151 -0
  359. package/src/types.ts +725 -0
  360. package/src/utils/ansi.ts +9 -0
  361. package/src/utils/content-type.ts +31 -0
  362. package/src/utils/decode.ts +7 -0
  363. package/src/utils/dev-profile.ts +31 -0
  364. package/src/utils/error-log.ts +29 -0
  365. package/src/utils/fs-cache.ts +31 -0
  366. package/src/utils/fs.ts +119 -0
  367. package/src/utils/html.ts +46 -0
  368. package/src/utils/serialize.ts +378 -0
  369. package/src/utils/source.ts +35 -0
  370. package/src/utils/verbose.ts +39 -0
  371. package/tsconfig.json +10 -0
@@ -0,0 +1,119 @@
1
+ // ---------------------------------------------------------------------------
2
+ // /_next/image disk cache (COMPAT).
3
+ //
4
+ // Next's exact on-disk layout: <distDir>/cache/images/<cacheKey>/ holding one
5
+ // file named `${maxAge}.${expireAt}.${etag}.${upstreamEtag}.${extension}`.
6
+ // The e2e suites read this directory directly (file names must embed the etag,
7
+ // rewrites must change mtimes on stale-while-revalidate refreshes), so the
8
+ // layout is contract, not implementation detail. A byte-budget sweep enforces
9
+ // images.maximumDiskCacheSize (0 disables writes entirely).
10
+ // ---------------------------------------------------------------------------
11
+
12
+ import { createHash } from 'node:crypto';
13
+ import { promises as fs } from 'node:fs';
14
+ import path from 'node:path';
15
+
16
+ export const IMAGE_CACHE_VERSION = 4;
17
+
18
+ export function getHash(items: (string | number | Buffer)[]): string {
19
+ const hash = createHash('sha256');
20
+ for (const item of items) {
21
+ hash.update(typeof item === 'number' ? String(item) : item);
22
+ }
23
+ return hash.digest('base64url');
24
+ }
25
+
26
+ export interface ImageCacheEntry {
27
+ buffer: Buffer;
28
+ etag: string;
29
+ upstreamEtag: string;
30
+ extension: string;
31
+ maxAge: number;
32
+ expireAt: number;
33
+ }
34
+
35
+ export function imageCacheDir(root: string): string {
36
+ return path.join(root, '.next', 'cache', 'images');
37
+ }
38
+
39
+ export async function readCacheEntry(
40
+ cacheDir: string,
41
+ cacheKey: string,
42
+ ): Promise<ImageCacheEntry | undefined> {
43
+ try {
44
+ const dir = path.join(cacheDir, cacheKey);
45
+ const files = await fs.readdir(dir);
46
+ const file = files[0];
47
+ if (!file) return undefined;
48
+ const [maxAgeSt, expireAtSt, etag, upstreamEtag, extension] = file.split('.', 5);
49
+ if (!etag || !upstreamEtag || !extension) return undefined;
50
+ const buffer = await fs.readFile(path.join(dir, file));
51
+ return {
52
+ buffer,
53
+ etag,
54
+ upstreamEtag,
55
+ extension,
56
+ maxAge: Number(maxAgeSt),
57
+ expireAt: Number(expireAtSt),
58
+ };
59
+ } catch {
60
+ return undefined;
61
+ }
62
+ }
63
+
64
+ export async function writeCacheEntry(
65
+ cacheDir: string,
66
+ cacheKey: string,
67
+ entry: ImageCacheEntry,
68
+ maximumDiskCacheSize: number | undefined,
69
+ ): Promise<void> {
70
+ if (maximumDiskCacheSize === 0) return;
71
+ if (maximumDiskCacheSize !== undefined && entry.buffer.byteLength > maximumDiskCacheSize) {
72
+ return;
73
+ }
74
+ try {
75
+ const dir = path.join(cacheDir, cacheKey);
76
+ const filename = path.join(
77
+ dir,
78
+ `${entry.maxAge}.${entry.expireAt}.${entry.etag}.${entry.upstreamEtag}.${entry.extension}`,
79
+ );
80
+ await fs.rm(dir, { recursive: true, force: true }).catch(() => undefined);
81
+ await fs.mkdir(dir, { recursive: true });
82
+ await fs.writeFile(filename, entry.buffer);
83
+ if (maximumDiskCacheSize !== undefined) {
84
+ await evictToBudget(cacheDir, cacheKey, maximumDiskCacheSize);
85
+ }
86
+ } catch (err) {
87
+ console.error(`Failed to write image to cache ${cacheKey}`, err);
88
+ }
89
+ }
90
+
91
+ // Drop oldest-expiring entries (never the one just written) until the cache
92
+ // dir fits the byte budget.
93
+ async function evictToBudget(
94
+ cacheDir: string,
95
+ keepKey: string,
96
+ maximumDiskCacheSize: number,
97
+ ): Promise<void> {
98
+ const keys = await fs.readdir(cacheDir).catch(() => [] as string[]);
99
+ const entries: { key: string; size: number; expireAt: number }[] = [];
100
+ let total = 0;
101
+ for (const key of keys) {
102
+ const dir = path.join(cacheDir, key);
103
+ const files = await fs.readdir(dir).catch(() => [] as string[]);
104
+ const file = files[0];
105
+ if (!file) continue;
106
+ const stat = await fs.stat(path.join(dir, file)).catch(() => null);
107
+ if (!stat) continue;
108
+ total += stat.size;
109
+ entries.push({ key, size: stat.size, expireAt: Number(file.split('.', 2)[1]) || 0 });
110
+ }
111
+ if (total <= maximumDiskCacheSize) return;
112
+ entries.sort((a, b) => a.expireAt - b.expireAt);
113
+ for (const entry of entries) {
114
+ if (total <= maximumDiskCacheSize) break;
115
+ if (entry.key === keepKey) continue;
116
+ await fs.rm(path.join(cacheDir, entry.key), { recursive: true, force: true }).catch(() => undefined);
117
+ total -= entry.size;
118
+ }
119
+ }
@@ -0,0 +1,143 @@
1
+ // /_next/image content sniffing (COMPAT). Magic-byte content-type detection, animated-image detection,
2
+ // and the content-type/file-extension maps - mirrors Next's detectContentType / is-animated /
3
+ // serve-static tables so the optimizer classifies sources (bypass vs optimize vs reject) exactly like
4
+ // Next.
5
+
6
+ export const AVIF = 'image/avif';
7
+ export const WEBP = 'image/webp';
8
+ export const PNG = 'image/png';
9
+ export const JPEG = 'image/jpeg';
10
+ export const JXL = 'image/jxl';
11
+ export const JP2 = 'image/jp2';
12
+ export const HEIC = 'image/heic';
13
+ export const GIF = 'image/gif';
14
+ export const SVG = 'image/svg+xml';
15
+ export const ICO = 'image/x-icon';
16
+ export const ICNS = 'image/x-icns';
17
+ export const TIFF = 'image/tiff';
18
+ export const BMP = 'image/bmp';
19
+ export const PDF = 'application/pdf';
20
+
21
+ /** Animated variants of these are served as-is (never re-encoded). */
22
+ export const ANIMATABLE_TYPES = [WEBP, PNG, GIF];
23
+ /** Types sharp never re-encodes — passthrough with the original bytes. */
24
+ export const BYPASS_TYPES = [SVG, ICO, ICNS, BMP, JXL, HEIC];
25
+
26
+ const EXTENSION_BY_TYPE: Record<string, string> = {
27
+ [AVIF]: 'avif',
28
+ [WEBP]: 'webp',
29
+ [PNG]: 'png',
30
+ [JPEG]: 'jpeg',
31
+ [JXL]: 'jxl',
32
+ [JP2]: 'jp2',
33
+ [HEIC]: 'heic',
34
+ [GIF]: 'gif',
35
+ [SVG]: 'svg',
36
+ [ICO]: 'ico',
37
+ [ICNS]: 'icns',
38
+ [TIFF]: 'tiff',
39
+ [BMP]: 'bmp',
40
+ };
41
+
42
+ const TYPE_BY_EXTENSION: Record<string, string> = Object.fromEntries(
43
+ Object.entries(EXTENSION_BY_TYPE).map(([type, ext]) => [ext, type]),
44
+ );
45
+
46
+ /** File extension for a content type (Next's getExtension); undefined if unknown. */
47
+ export function extensionForType(contentType: string): string | undefined {
48
+ return EXTENSION_BY_TYPE[contentType];
49
+ }
50
+
51
+ /** Content type for a cache-file extension (Next's getContentType). */
52
+ export function typeForExtension(extension: string): string | undefined {
53
+ return TYPE_BY_EXTENSION[extension];
54
+ }
55
+
56
+ function startsWithBytes(buffer: Buffer, bytes: number[]): boolean {
57
+ // A zero in the signature is a wildcard byte (Next's convention).
58
+ return bytes.every((b, i) => !b || buffer[i] === b);
59
+ }
60
+
61
+ /**
62
+ * Sniff the image content type from the first bytes of the buffer. Mirrors
63
+ * Next's detectContentType signature table; returns null for non-images and
64
+ * unknown formats.
65
+ */
66
+ export function detectContentType(buffer: Buffer): string | null {
67
+ if (buffer.byteLength === 0) return null;
68
+ if ([0xff, 0xd8, 0xff].every((b, i) => buffer[i] === b)) return JPEG;
69
+ if ([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a].every((b, i) => buffer[i] === b)) {
70
+ return PNG;
71
+ }
72
+ if ([0x47, 0x49, 0x46, 0x38].every((b, i) => buffer[i] === b)) return GIF;
73
+ if (startsWithBytes(buffer, [0x52, 0x49, 0x46, 0x46, 0, 0, 0, 0, 0x57, 0x45, 0x42, 0x50])) {
74
+ return WEBP;
75
+ }
76
+ if ([0x3c, 0x3f, 0x78, 0x6d, 0x6c].every((b, i) => buffer[i] === b)) return SVG;
77
+ if ([0x3c, 0x73, 0x76, 0x67].every((b, i) => buffer[i] === b)) return SVG;
78
+ if (startsWithBytes(buffer, [0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x61, 0x76, 0x69, 0x66])) {
79
+ return AVIF;
80
+ }
81
+ if ([0x00, 0x00, 0x01, 0x00].every((b, i) => buffer[i] === b)) return ICO;
82
+ if ([0x69, 0x63, 0x6e, 0x73].every((b, i) => buffer[i] === b)) return ICNS;
83
+ if ([0x49, 0x49, 0x2a, 0x00].every((b, i) => buffer[i] === b)) return TIFF;
84
+ if ([0x4d, 0x4d, 0x00, 0x2a].every((b, i) => buffer[i] === b)) return TIFF;
85
+ if ([0x42, 0x4d].every((b, i) => buffer[i] === b)) return BMP;
86
+ if ([0xff, 0x0a].every((b, i) => buffer[i] === b)) return JXL;
87
+ if (
88
+ [0x00, 0x00, 0x00, 0x0c, 0x4a, 0x58, 0x4c, 0x20, 0x0d, 0x0a, 0x87, 0x0a].every(
89
+ (b, i) => buffer[i] === b,
90
+ )
91
+ ) {
92
+ return JXL;
93
+ }
94
+ if (startsWithBytes(buffer, [0, 0, 0, 0, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63])) {
95
+ return HEIC;
96
+ }
97
+ if ([0x25, 0x50, 0x44, 0x46, 0x2d].every((b, i) => buffer[i] === b)) return PDF;
98
+ if (
99
+ [0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a].every(
100
+ (b, i) => buffer[i] === b,
101
+ )
102
+ ) {
103
+ return JP2;
104
+ }
105
+ // SVG documents may start with whitespace/comments/doctype before <svg.
106
+ const head = buffer.toString('utf8', 0, Math.min(buffer.length, 512)).trimStart();
107
+ if (/^(<\?xml|<!doctype svg|<svg)/i.test(head)) return SVG;
108
+ return null;
109
+ }
110
+
111
+ /** True when a gif/apng/webp buffer contains multiple frames (Next's is-animated). */
112
+ export function isAnimated(buffer: Buffer): boolean {
113
+ // GIF: more than one Graphics Control Extension block (0x21 0xF9 0x04).
114
+ if (buffer.length > 6 && buffer.toString('ascii', 0, 3) === 'GIF') {
115
+ let frames = 0;
116
+ for (let i = 0; i < buffer.length - 2; i++) {
117
+ if (buffer[i] === 0x21 && buffer[i + 1] === 0xf9 && buffer[i + 2] === 0x04) {
118
+ frames++;
119
+ if (frames > 1) return true;
120
+ }
121
+ }
122
+ return false;
123
+ }
124
+ // APNG: an acTL chunk appearing before the first IDAT chunk.
125
+ if (
126
+ buffer.length > 8 &&
127
+ [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a].every((b, i) => buffer[i] === b)
128
+ ) {
129
+ const actl = buffer.indexOf('acTL');
130
+ if (actl === -1) return false;
131
+ const idat = buffer.indexOf('IDAT');
132
+ return idat === -1 || actl < idat;
133
+ }
134
+ // WebP: an ANIM chunk inside a VP8X container.
135
+ if (
136
+ buffer.length > 16 &&
137
+ buffer.toString('ascii', 0, 4) === 'RIFF' &&
138
+ buffer.toString('ascii', 8, 12) === 'WEBP'
139
+ ) {
140
+ return buffer.includes('ANIM');
141
+ }
142
+ return false;
143
+ }