@timber-js/app 0.1.0

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 (310) hide show
  1. package/bin/timber.mjs +5 -0
  2. package/dist/_chunks/error-boundary-dj-WO5uq.js +121 -0
  3. package/dist/_chunks/error-boundary-dj-WO5uq.js.map +1 -0
  4. package/dist/_chunks/format-DNt20Kt8.js +163 -0
  5. package/dist/_chunks/format-DNt20Kt8.js.map +1 -0
  6. package/dist/_chunks/interception-DIaZN1bF.js +669 -0
  7. package/dist/_chunks/interception-DIaZN1bF.js.map +1 -0
  8. package/dist/_chunks/metadata-routes-BDnswgRO.js +141 -0
  9. package/dist/_chunks/metadata-routes-BDnswgRO.js.map +1 -0
  10. package/dist/_chunks/registry-DUIpYD_x.js +20 -0
  11. package/dist/_chunks/registry-DUIpYD_x.js.map +1 -0
  12. package/dist/_chunks/request-context-D6XHINkR.js +330 -0
  13. package/dist/_chunks/request-context-D6XHINkR.js.map +1 -0
  14. package/dist/_chunks/tracing-BtOwb8O6.js +174 -0
  15. package/dist/_chunks/tracing-BtOwb8O6.js.map +1 -0
  16. package/dist/_chunks/use-cookie-8ZlA0rr3.js +125 -0
  17. package/dist/_chunks/use-cookie-8ZlA0rr3.js.map +1 -0
  18. package/dist/adapters/cloudflare.d.ts +92 -0
  19. package/dist/adapters/cloudflare.d.ts.map +1 -0
  20. package/dist/adapters/cloudflare.js +188 -0
  21. package/dist/adapters/cloudflare.js.map +1 -0
  22. package/dist/adapters/nitro.d.ts +72 -0
  23. package/dist/adapters/nitro.d.ts.map +1 -0
  24. package/dist/adapters/nitro.js +217 -0
  25. package/dist/adapters/nitro.js.map +1 -0
  26. package/dist/adapters/types.d.ts +53 -0
  27. package/dist/adapters/types.d.ts.map +1 -0
  28. package/dist/cache/index.d.ts +52 -0
  29. package/dist/cache/index.d.ts.map +1 -0
  30. package/dist/cache/index.js +283 -0
  31. package/dist/cache/index.js.map +1 -0
  32. package/dist/cache/redis-handler.d.ts +45 -0
  33. package/dist/cache/redis-handler.d.ts.map +1 -0
  34. package/dist/cache/register-cached-function.d.ts +17 -0
  35. package/dist/cache/register-cached-function.d.ts.map +1 -0
  36. package/dist/cache/singleflight.d.ts +11 -0
  37. package/dist/cache/singleflight.d.ts.map +1 -0
  38. package/dist/cache/stable-stringify.d.ts +7 -0
  39. package/dist/cache/stable-stringify.d.ts.map +1 -0
  40. package/dist/cache/timber-cache.d.ts +21 -0
  41. package/dist/cache/timber-cache.d.ts.map +1 -0
  42. package/dist/cli.d.ts +44 -0
  43. package/dist/cli.d.ts.map +1 -0
  44. package/dist/cli.js +135 -0
  45. package/dist/cli.js.map +1 -0
  46. package/dist/client/browser-entry.d.ts +22 -0
  47. package/dist/client/browser-entry.d.ts.map +1 -0
  48. package/dist/client/error-boundary.d.ts +42 -0
  49. package/dist/client/error-boundary.d.ts.map +1 -0
  50. package/dist/client/form.d.ts +115 -0
  51. package/dist/client/form.d.ts.map +1 -0
  52. package/dist/client/head.d.ts +16 -0
  53. package/dist/client/head.d.ts.map +1 -0
  54. package/dist/client/history.d.ts +29 -0
  55. package/dist/client/history.d.ts.map +1 -0
  56. package/dist/client/index.d.ts +32 -0
  57. package/dist/client/index.d.ts.map +1 -0
  58. package/dist/client/index.js +1218 -0
  59. package/dist/client/index.js.map +1 -0
  60. package/dist/client/link-navigate-interceptor.d.ts +28 -0
  61. package/dist/client/link-navigate-interceptor.d.ts.map +1 -0
  62. package/dist/client/link-status-provider.d.ts +11 -0
  63. package/dist/client/link-status-provider.d.ts.map +1 -0
  64. package/dist/client/link.d.ts +119 -0
  65. package/dist/client/link.d.ts.map +1 -0
  66. package/dist/client/nuqs-adapter.d.ts +11 -0
  67. package/dist/client/nuqs-adapter.d.ts.map +1 -0
  68. package/dist/client/router-ref.d.ts +11 -0
  69. package/dist/client/router-ref.d.ts.map +1 -0
  70. package/dist/client/router.d.ts +85 -0
  71. package/dist/client/router.d.ts.map +1 -0
  72. package/dist/client/segment-cache.d.ts +88 -0
  73. package/dist/client/segment-cache.d.ts.map +1 -0
  74. package/dist/client/segment-context.d.ts +32 -0
  75. package/dist/client/segment-context.d.ts.map +1 -0
  76. package/dist/client/ssr-data.d.ts +64 -0
  77. package/dist/client/ssr-data.d.ts.map +1 -0
  78. package/dist/client/types.d.ts +5 -0
  79. package/dist/client/types.d.ts.map +1 -0
  80. package/dist/client/unload-guard.d.ts +18 -0
  81. package/dist/client/unload-guard.d.ts.map +1 -0
  82. package/dist/client/use-cookie.d.ts +37 -0
  83. package/dist/client/use-cookie.d.ts.map +1 -0
  84. package/dist/client/use-link-status.d.ts +35 -0
  85. package/dist/client/use-link-status.d.ts.map +1 -0
  86. package/dist/client/use-navigation-pending.d.ts +26 -0
  87. package/dist/client/use-navigation-pending.d.ts.map +1 -0
  88. package/dist/client/use-params.d.ts +50 -0
  89. package/dist/client/use-params.d.ts.map +1 -0
  90. package/dist/client/use-pathname.d.ts +20 -0
  91. package/dist/client/use-pathname.d.ts.map +1 -0
  92. package/dist/client/use-query-states.d.ts +36 -0
  93. package/dist/client/use-query-states.d.ts.map +1 -0
  94. package/dist/client/use-router.d.ts +39 -0
  95. package/dist/client/use-router.d.ts.map +1 -0
  96. package/dist/client/use-search-params.d.ts +24 -0
  97. package/dist/client/use-search-params.d.ts.map +1 -0
  98. package/dist/client/use-selected-layout-segment.d.ts +68 -0
  99. package/dist/client/use-selected-layout-segment.d.ts.map +1 -0
  100. package/dist/content/index.d.ts +11 -0
  101. package/dist/content/index.d.ts.map +1 -0
  102. package/dist/content/index.js +2 -0
  103. package/dist/cookies/define-cookie.d.ts +61 -0
  104. package/dist/cookies/define-cookie.d.ts.map +1 -0
  105. package/dist/cookies/index.d.ts +3 -0
  106. package/dist/cookies/index.d.ts.map +1 -0
  107. package/dist/cookies/index.js +82 -0
  108. package/dist/cookies/index.js.map +1 -0
  109. package/dist/fonts/ast.d.ts +38 -0
  110. package/dist/fonts/ast.d.ts.map +1 -0
  111. package/dist/fonts/css.d.ts +43 -0
  112. package/dist/fonts/css.d.ts.map +1 -0
  113. package/dist/fonts/fallbacks.d.ts +36 -0
  114. package/dist/fonts/fallbacks.d.ts.map +1 -0
  115. package/dist/fonts/google.d.ts +122 -0
  116. package/dist/fonts/google.d.ts.map +1 -0
  117. package/dist/fonts/local.d.ts +76 -0
  118. package/dist/fonts/local.d.ts.map +1 -0
  119. package/dist/fonts/types.d.ts +85 -0
  120. package/dist/fonts/types.d.ts.map +1 -0
  121. package/dist/index.d.ts +150 -0
  122. package/dist/index.d.ts.map +1 -0
  123. package/dist/index.js +14701 -0
  124. package/dist/index.js.map +1 -0
  125. package/dist/plugins/adapter-build.d.ts +18 -0
  126. package/dist/plugins/adapter-build.d.ts.map +1 -0
  127. package/dist/plugins/build-manifest.d.ts +79 -0
  128. package/dist/plugins/build-manifest.d.ts.map +1 -0
  129. package/dist/plugins/build-report.d.ts +63 -0
  130. package/dist/plugins/build-report.d.ts.map +1 -0
  131. package/dist/plugins/cache-transform.d.ts +36 -0
  132. package/dist/plugins/cache-transform.d.ts.map +1 -0
  133. package/dist/plugins/chunks.d.ts +45 -0
  134. package/dist/plugins/chunks.d.ts.map +1 -0
  135. package/dist/plugins/content.d.ts +19 -0
  136. package/dist/plugins/content.d.ts.map +1 -0
  137. package/dist/plugins/dev-error-overlay.d.ts +60 -0
  138. package/dist/plugins/dev-error-overlay.d.ts.map +1 -0
  139. package/dist/plugins/dev-logs.d.ts +46 -0
  140. package/dist/plugins/dev-logs.d.ts.map +1 -0
  141. package/dist/plugins/dev-server.d.ts +22 -0
  142. package/dist/plugins/dev-server.d.ts.map +1 -0
  143. package/dist/plugins/dynamic-transform.d.ts +72 -0
  144. package/dist/plugins/dynamic-transform.d.ts.map +1 -0
  145. package/dist/plugins/entries.d.ts +21 -0
  146. package/dist/plugins/entries.d.ts.map +1 -0
  147. package/dist/plugins/fonts.d.ts +77 -0
  148. package/dist/plugins/fonts.d.ts.map +1 -0
  149. package/dist/plugins/mdx.d.ts +21 -0
  150. package/dist/plugins/mdx.d.ts.map +1 -0
  151. package/dist/plugins/react-prod.d.ts +18 -0
  152. package/dist/plugins/react-prod.d.ts.map +1 -0
  153. package/dist/plugins/routing.d.ts +13 -0
  154. package/dist/plugins/routing.d.ts.map +1 -0
  155. package/dist/plugins/server-action-exports.d.ts +26 -0
  156. package/dist/plugins/server-action-exports.d.ts.map +1 -0
  157. package/dist/plugins/server-bundle.d.ts +15 -0
  158. package/dist/plugins/server-bundle.d.ts.map +1 -0
  159. package/dist/plugins/shims.d.ts +18 -0
  160. package/dist/plugins/shims.d.ts.map +1 -0
  161. package/dist/plugins/static-build.d.ts +55 -0
  162. package/dist/plugins/static-build.d.ts.map +1 -0
  163. package/dist/routing/codegen.d.ts +29 -0
  164. package/dist/routing/codegen.d.ts.map +1 -0
  165. package/dist/routing/index.d.ts +8 -0
  166. package/dist/routing/index.d.ts.map +1 -0
  167. package/dist/routing/index.js +2 -0
  168. package/dist/routing/interception.d.ts +46 -0
  169. package/dist/routing/interception.d.ts.map +1 -0
  170. package/dist/routing/scanner.d.ts +28 -0
  171. package/dist/routing/scanner.d.ts.map +1 -0
  172. package/dist/routing/status-file-lint.d.ts +33 -0
  173. package/dist/routing/status-file-lint.d.ts.map +1 -0
  174. package/dist/routing/types.d.ts +81 -0
  175. package/dist/routing/types.d.ts.map +1 -0
  176. package/dist/search-params/analyze.d.ts +54 -0
  177. package/dist/search-params/analyze.d.ts.map +1 -0
  178. package/dist/search-params/codecs.d.ts +53 -0
  179. package/dist/search-params/codecs.d.ts.map +1 -0
  180. package/dist/search-params/create.d.ts +106 -0
  181. package/dist/search-params/create.d.ts.map +1 -0
  182. package/dist/search-params/index.d.ts +7 -0
  183. package/dist/search-params/index.d.ts.map +1 -0
  184. package/dist/search-params/index.js +300 -0
  185. package/dist/search-params/index.js.map +1 -0
  186. package/dist/search-params/registry.d.ts +20 -0
  187. package/dist/search-params/registry.d.ts.map +1 -0
  188. package/dist/server/access-gate.d.ts +42 -0
  189. package/dist/server/access-gate.d.ts.map +1 -0
  190. package/dist/server/action-client.d.ts +190 -0
  191. package/dist/server/action-client.d.ts.map +1 -0
  192. package/dist/server/action-handler.d.ts +48 -0
  193. package/dist/server/action-handler.d.ts.map +1 -0
  194. package/dist/server/actions.d.ts +108 -0
  195. package/dist/server/actions.d.ts.map +1 -0
  196. package/dist/server/asset-headers.d.ts +42 -0
  197. package/dist/server/asset-headers.d.ts.map +1 -0
  198. package/dist/server/body-limits.d.ts +30 -0
  199. package/dist/server/body-limits.d.ts.map +1 -0
  200. package/dist/server/build-manifest.d.ts +120 -0
  201. package/dist/server/build-manifest.d.ts.map +1 -0
  202. package/dist/server/canonicalize.d.ts +30 -0
  203. package/dist/server/canonicalize.d.ts.map +1 -0
  204. package/dist/server/client-module-map.d.ts +47 -0
  205. package/dist/server/client-module-map.d.ts.map +1 -0
  206. package/dist/server/csrf.d.ts +34 -0
  207. package/dist/server/csrf.d.ts.map +1 -0
  208. package/dist/server/deny-renderer.d.ts +49 -0
  209. package/dist/server/deny-renderer.d.ts.map +1 -0
  210. package/dist/server/dev-logger.d.ts +44 -0
  211. package/dist/server/dev-logger.d.ts.map +1 -0
  212. package/dist/server/dev-span-processor.d.ts +29 -0
  213. package/dist/server/dev-span-processor.d.ts.map +1 -0
  214. package/dist/server/dev-warnings.d.ts +129 -0
  215. package/dist/server/dev-warnings.d.ts.map +1 -0
  216. package/dist/server/early-hints-sender.d.ts +38 -0
  217. package/dist/server/early-hints-sender.d.ts.map +1 -0
  218. package/dist/server/early-hints.d.ts +83 -0
  219. package/dist/server/early-hints.d.ts.map +1 -0
  220. package/dist/server/error-boundary-wrapper.d.ts +17 -0
  221. package/dist/server/error-boundary-wrapper.d.ts.map +1 -0
  222. package/dist/server/error-formatter.d.ts +17 -0
  223. package/dist/server/error-formatter.d.ts.map +1 -0
  224. package/dist/server/flush.d.ts +74 -0
  225. package/dist/server/flush.d.ts.map +1 -0
  226. package/dist/server/form-data.d.ts +60 -0
  227. package/dist/server/form-data.d.ts.map +1 -0
  228. package/dist/server/form-flash.d.ts +78 -0
  229. package/dist/server/form-flash.d.ts.map +1 -0
  230. package/dist/server/html-injectors.d.ts +101 -0
  231. package/dist/server/html-injectors.d.ts.map +1 -0
  232. package/dist/server/index.d.ts +54 -0
  233. package/dist/server/index.d.ts.map +1 -0
  234. package/dist/server/index.js +2925 -0
  235. package/dist/server/index.js.map +1 -0
  236. package/dist/server/instrumentation.d.ts +61 -0
  237. package/dist/server/instrumentation.d.ts.map +1 -0
  238. package/dist/server/logger.d.ts +83 -0
  239. package/dist/server/logger.d.ts.map +1 -0
  240. package/dist/server/manifest-status-resolver.d.ts +58 -0
  241. package/dist/server/manifest-status-resolver.d.ts.map +1 -0
  242. package/dist/server/metadata-render.d.ts +20 -0
  243. package/dist/server/metadata-render.d.ts.map +1 -0
  244. package/dist/server/metadata-routes.d.ts +67 -0
  245. package/dist/server/metadata-routes.d.ts.map +1 -0
  246. package/dist/server/metadata.d.ts +67 -0
  247. package/dist/server/metadata.d.ts.map +1 -0
  248. package/dist/server/middleware-runner.d.ts +21 -0
  249. package/dist/server/middleware-runner.d.ts.map +1 -0
  250. package/dist/server/nuqs-ssr-provider.d.ts +28 -0
  251. package/dist/server/nuqs-ssr-provider.d.ts.map +1 -0
  252. package/dist/server/pipeline.d.ts +81 -0
  253. package/dist/server/pipeline.d.ts.map +1 -0
  254. package/dist/server/prerender.d.ts +77 -0
  255. package/dist/server/prerender.d.ts.map +1 -0
  256. package/dist/server/primitives.d.ts +131 -0
  257. package/dist/server/primitives.d.ts.map +1 -0
  258. package/dist/server/proxy.d.ts +23 -0
  259. package/dist/server/proxy.d.ts.map +1 -0
  260. package/dist/server/request-context.d.ts +175 -0
  261. package/dist/server/request-context.d.ts.map +1 -0
  262. package/dist/server/route-element-builder.d.ts +66 -0
  263. package/dist/server/route-element-builder.d.ts.map +1 -0
  264. package/dist/server/route-handler.d.ts +35 -0
  265. package/dist/server/route-handler.d.ts.map +1 -0
  266. package/dist/server/route-matcher.d.ts +78 -0
  267. package/dist/server/route-matcher.d.ts.map +1 -0
  268. package/dist/server/rsc-entry/api-handler.d.ts +11 -0
  269. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -0
  270. package/dist/server/rsc-entry/error-renderer.d.ts +30 -0
  271. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -0
  272. package/dist/server/rsc-entry/helpers.d.ts +73 -0
  273. package/dist/server/rsc-entry/helpers.d.ts.map +1 -0
  274. package/dist/server/rsc-entry/index.d.ts +11 -0
  275. package/dist/server/rsc-entry/index.d.ts.map +1 -0
  276. package/dist/server/rsc-entry/ssr-bridge.d.ts +6 -0
  277. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -0
  278. package/dist/server/slot-resolver.d.ts +34 -0
  279. package/dist/server/slot-resolver.d.ts.map +1 -0
  280. package/dist/server/ssr-entry.d.ts +73 -0
  281. package/dist/server/ssr-entry.d.ts.map +1 -0
  282. package/dist/server/ssr-render.d.ts +67 -0
  283. package/dist/server/ssr-render.d.ts.map +1 -0
  284. package/dist/server/status-code-resolver.d.ts +77 -0
  285. package/dist/server/status-code-resolver.d.ts.map +1 -0
  286. package/dist/server/tracing.d.ts +99 -0
  287. package/dist/server/tracing.d.ts.map +1 -0
  288. package/dist/server/tree-builder.d.ts +116 -0
  289. package/dist/server/tree-builder.d.ts.map +1 -0
  290. package/dist/server/types.d.ts +231 -0
  291. package/dist/server/types.d.ts.map +1 -0
  292. package/dist/shims/font-google.d.ts +41 -0
  293. package/dist/shims/font-google.d.ts.map +1 -0
  294. package/dist/shims/headers.d.ts +11 -0
  295. package/dist/shims/headers.d.ts.map +1 -0
  296. package/dist/shims/image.d.ts +328 -0
  297. package/dist/shims/image.d.ts.map +1 -0
  298. package/dist/shims/link.d.ts +9 -0
  299. package/dist/shims/link.d.ts.map +1 -0
  300. package/dist/shims/navigation-client.d.ts +25 -0
  301. package/dist/shims/navigation-client.d.ts.map +1 -0
  302. package/dist/shims/navigation.d.ts +25 -0
  303. package/dist/shims/navigation.d.ts.map +1 -0
  304. package/dist/utils/directive-parser.d.ts +70 -0
  305. package/dist/utils/directive-parser.d.ts.map +1 -0
  306. package/dist/utils/format.d.ts +6 -0
  307. package/dist/utils/format.d.ts.map +1 -0
  308. package/dist/utils/startup-timer.d.ts +34 -0
  309. package/dist/utils/startup-timer.d.ts.map +1 -0
  310. package/package.json +140 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACrE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvF,UAAU,CAAC,IAAI,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjE;AAGD,MAAM,WAAW,YAAY,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;IAC1C,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,yBAAyB;IACxC,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,kBAAmB,YAAW,YAAY;IACrD,OAAO,CAAC,KAAK,CAA4E;IACzF,OAAO,CAAC,OAAO,CAAS;gBAEZ,IAAI,CAAC,EAAE,yBAAyB;IAItC,GAAG,CAAC,GAAG,EAAE,MAAM;;;;IAYf,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE;IAuBtE,UAAU,CAAC,IAAI,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE;IAarD,gDAAgD;IAChD,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF;AAED,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,YAAY,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,283 @@
1
+ import { t as addSpanEvent } from "../_chunks/tracing-BtOwb8O6.js";
2
+ import { createHash } from "node:crypto";
3
+ //#region src/cache/redis-handler.ts
4
+ var KEY_PREFIX = "timber:cache:";
5
+ var TAG_PREFIX = "timber:tag:";
6
+ /**
7
+ * Redis-backed CacheHandler for distributed caching.
8
+ *
9
+ * All instances sharing the same Redis see each other's cache entries and
10
+ * invalidations. Tag-based invalidation uses Redis Sets to track which keys
11
+ * belong to which tags.
12
+ *
13
+ * Bring your own Redis client — any client implementing the RedisClient
14
+ * interface works (ioredis, node-redis, @upstash/redis, etc.).
15
+ */
16
+ var RedisCacheHandler = class {
17
+ client;
18
+ prefix;
19
+ constructor(client, opts) {
20
+ this.client = client;
21
+ this.prefix = opts?.prefix ?? "";
22
+ }
23
+ cacheKey(key) {
24
+ return `${this.prefix}${KEY_PREFIX}${key}`;
25
+ }
26
+ tagKey(tag) {
27
+ return `${this.prefix}${TAG_PREFIX}${tag}`;
28
+ }
29
+ async get(key) {
30
+ const raw = await this.client.get(this.cacheKey(key));
31
+ if (raw === null) return null;
32
+ const entry = JSON.parse(raw);
33
+ const stale = Date.now() > entry.expiresAt;
34
+ return {
35
+ value: entry.value,
36
+ stale
37
+ };
38
+ }
39
+ async set(key, value, opts) {
40
+ const ck = this.cacheKey(key);
41
+ const expiresAt = Date.now() + opts.ttl * 1e3;
42
+ const payload = JSON.stringify({
43
+ value,
44
+ expiresAt
45
+ });
46
+ const redisTtlSeconds = Math.max(opts.ttl * 2 + 60, 120);
47
+ await this.client.set(ck, payload, "EX", redisTtlSeconds);
48
+ for (const tag of opts.tags) await this.client.sadd(this.tagKey(tag), key);
49
+ }
50
+ async invalidate(opts) {
51
+ if (opts.key) await this.client.del(this.cacheKey(opts.key));
52
+ if (opts.tag) {
53
+ const tk = this.tagKey(opts.tag);
54
+ const keys = await this.client.smembers(tk);
55
+ if (keys.length > 0) {
56
+ const cacheKeys = keys.map((k) => this.cacheKey(k));
57
+ await this.client.del(cacheKeys);
58
+ }
59
+ await this.client.del(tk);
60
+ }
61
+ }
62
+ };
63
+ //#endregion
64
+ //#region src/cache/stable-stringify.ts
65
+ /**
66
+ * Deterministic JSON serialization with sorted object keys.
67
+ * Used for cache key generation — ensures { a: 1, b: 2 } and { b: 2, a: 1 }
68
+ * produce the same string.
69
+ */
70
+ function stableStringify(value) {
71
+ if (value === null || value === void 0) return JSON.stringify(value);
72
+ if (typeof value !== "object") return JSON.stringify(value);
73
+ if (Array.isArray(value)) return "[" + value.map((item) => stableStringify(item)).join(",") + "]";
74
+ const obj = value;
75
+ const keys = Object.keys(obj).sort();
76
+ const pairs = [];
77
+ for (const key of keys) {
78
+ if (obj[key] === void 0) continue;
79
+ pairs.push(JSON.stringify(key) + ":" + stableStringify(obj[key]));
80
+ }
81
+ return "{" + pairs.join(",") + "}";
82
+ }
83
+ //#endregion
84
+ //#region src/cache/singleflight.ts
85
+ function createSingleflight() {
86
+ const inflight = /* @__PURE__ */ new Map();
87
+ return { do(key, fn) {
88
+ const existing = inflight.get(key);
89
+ if (existing) return existing;
90
+ const promise = fn().finally(() => {
91
+ inflight.delete(key);
92
+ });
93
+ inflight.set(key, promise);
94
+ return promise;
95
+ } };
96
+ }
97
+ //#endregion
98
+ //#region src/cache/timber-cache.ts
99
+ var singleflight$1 = createSingleflight();
100
+ /**
101
+ * Generate a SHA-256 cache key from function identity and serialized args.
102
+ */
103
+ function defaultKeyGenerator(fnId, args) {
104
+ const raw = fnId + ":" + stableStringify(args);
105
+ return createHash("sha256").update(raw).digest("hex");
106
+ }
107
+ /**
108
+ * Resolve tags from the options — supports static array or function form.
109
+ */
110
+ function resolveTags$1(opts, args) {
111
+ if (!opts.tags) return [];
112
+ if (Array.isArray(opts.tags)) return opts.tags;
113
+ return opts.tags(...args);
114
+ }
115
+ var fnIdCounter = 0;
116
+ /**
117
+ * Creates a cached wrapper around an async function.
118
+ *
119
+ * - SHA-256 default keys with normalized JSON args
120
+ * - Singleflight: concurrent misses → single execution
121
+ * - SWR: serve stale immediately, background refetch
122
+ * - Tags as string[] or function of args
123
+ * - No ALS dependency
124
+ *
125
+ * Cache hits/misses are recorded as OTEL span events on the enclosing
126
+ * span (not child spans). The DevSpanProcessor reads these for dev log output.
127
+ */
128
+ function createCache(fn, opts, handler) {
129
+ const fnId = `timber-cache:${fnIdCounter++}`;
130
+ return async (...args) => {
131
+ const key = opts.key ? opts.key(...args) : defaultKeyGenerator(fnId, args);
132
+ const cacheStart = performance.now();
133
+ const cached = await handler.get(key);
134
+ if (cached && !cached.stale) {
135
+ await addSpanEvent("timber.cache.hit", {
136
+ key,
137
+ duration_ms: Math.round(performance.now() - cacheStart)
138
+ });
139
+ return cached.value;
140
+ }
141
+ if (cached && cached.stale && opts.staleWhileRevalidate) {
142
+ await addSpanEvent("timber.cache.hit", {
143
+ key,
144
+ duration_ms: Math.round(performance.now() - cacheStart),
145
+ stale: true
146
+ });
147
+ singleflight$1.do(`swr:${key}`, async () => {
148
+ try {
149
+ const fresh = await fn(...args);
150
+ const tags = resolveTags$1(opts, args);
151
+ await handler.set(key, fresh, {
152
+ ttl: opts.ttl,
153
+ tags
154
+ });
155
+ } catch {}
156
+ }).catch(() => {});
157
+ return cached.value;
158
+ }
159
+ const result = await singleflight$1.do(key, () => fn(...args));
160
+ const tags = resolveTags$1(opts, args);
161
+ await handler.set(key, result, {
162
+ ttl: opts.ttl,
163
+ tags
164
+ });
165
+ await addSpanEvent("timber.cache.miss", {
166
+ key,
167
+ duration_ms: Math.round(performance.now() - cacheStart)
168
+ });
169
+ return result;
170
+ };
171
+ }
172
+ /**
173
+ * Invalidate cache entries by tag or key.
174
+ */
175
+ createCache.invalidate = async function invalidate(handler, opts) {
176
+ await handler.invalidate(opts);
177
+ };
178
+ //#endregion
179
+ //#region src/cache/register-cached-function.ts
180
+ var singleflight = createSingleflight();
181
+ var REQUEST_SPECIFIC_PROPS = new Set([
182
+ "cookies",
183
+ "cookie",
184
+ "session",
185
+ "sessionId",
186
+ "token",
187
+ "authorization",
188
+ "auth",
189
+ "headers"
190
+ ]);
191
+ /**
192
+ * Generate a SHA-256 cache key from a stable function ID and serialized args.
193
+ */
194
+ function generateKey(id, args) {
195
+ const raw = id + ":" + stableStringify(args);
196
+ return createHash("sha256").update(raw).digest("hex");
197
+ }
198
+ /**
199
+ * Resolve tags from options — supports static array or function form.
200
+ */
201
+ function resolveTags(opts, args) {
202
+ if (!opts.tags) return [];
203
+ if (Array.isArray(opts.tags)) return opts.tags;
204
+ return opts.tags(...args);
205
+ }
206
+ /**
207
+ * Checks if component props contain request-specific keys and emits a dev warning.
208
+ * Only runs when process.env.NODE_ENV !== 'production'.
209
+ */
210
+ function warnRequestSpecificProps(id, props) {
211
+ if (typeof props !== "object" || props === null) return;
212
+ const suspicious = Object.keys(props).filter((k) => REQUEST_SPECIFIC_PROPS.has(k.toLowerCase()));
213
+ if (suspicious.length > 0) console.warn(`[timber] "use cache" component ${id} received request-specific props: ${suspicious.join(", ")}. This may serve one user's cached render to another user. Remove request-specific data from props or remove "use cache".`);
214
+ }
215
+ /**
216
+ * Runtime for the "use cache" directive transform. Wraps an async function
217
+ * with caching using the same cache handler as timber.cache.
218
+ *
219
+ * The stable `id` (file path + function name) ensures cache keys are consistent
220
+ * across builds. Args/props are hashed with SHA-256 for the per-call key.
221
+ */
222
+ function registerCachedFunction(fn, opts, handler) {
223
+ return async (...args) => {
224
+ if (opts.isComponent && process.env.NODE_ENV !== "production" && args.length > 0) warnRequestSpecificProps(opts.id, args[0]);
225
+ const key = generateKey(opts.id, args);
226
+ const cached = await handler.get(key);
227
+ if (cached && !cached.stale) return cached.value;
228
+ const result = await singleflight.do(key, () => fn(...args));
229
+ const tags = resolveTags(opts, args);
230
+ await handler.set(key, result, {
231
+ ttl: opts.ttl,
232
+ tags
233
+ });
234
+ return result;
235
+ };
236
+ }
237
+ //#endregion
238
+ //#region src/cache/index.ts
239
+ var MemoryCacheHandler = class {
240
+ store = /* @__PURE__ */ new Map();
241
+ maxSize;
242
+ constructor(opts) {
243
+ this.maxSize = opts?.maxSize ?? 1e3;
244
+ }
245
+ async get(key) {
246
+ const entry = this.store.get(key);
247
+ if (!entry) return null;
248
+ this.store.delete(key);
249
+ this.store.set(key, entry);
250
+ const stale = Date.now() > entry.expiresAt;
251
+ return {
252
+ value: entry.value,
253
+ stale
254
+ };
255
+ }
256
+ async set(key, value, opts) {
257
+ if (this.store.has(key)) this.store.delete(key);
258
+ while (this.store.size >= this.maxSize) {
259
+ const oldest = this.store.keys().next().value;
260
+ if (oldest !== void 0) this.store.delete(oldest);
261
+ else break;
262
+ }
263
+ this.store.set(key, {
264
+ value,
265
+ expiresAt: Date.now() + opts.ttl * 1e3,
266
+ tags: opts.tags
267
+ });
268
+ }
269
+ async invalidate(opts) {
270
+ if (opts.key) this.store.delete(opts.key);
271
+ if (opts.tag) {
272
+ for (const [key, entry] of this.store) if (entry.tags.includes(opts.tag)) this.store.delete(key);
273
+ }
274
+ }
275
+ /** Number of entries currently in the cache. */
276
+ get size() {
277
+ return this.store.size;
278
+ }
279
+ };
280
+ //#endregion
281
+ export { MemoryCacheHandler, RedisCacheHandler, createCache, createSingleflight, registerCachedFunction, stableStringify };
282
+
283
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/cache/redis-handler.ts","../../src/cache/stable-stringify.ts","../../src/cache/singleflight.ts","../../src/cache/timber-cache.ts","../../src/cache/register-cached-function.ts","../../src/cache/index.ts"],"sourcesContent":["import type { CacheHandler } from './index';\n\n/**\n * Minimal Redis client interface — compatible with ioredis, node-redis, and\n * Cloudflare Workers Redis bindings. We depend on the interface, not the\n * implementation, so users bring their own Redis client.\n */\nexport interface RedisClient {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, ...args: unknown[]): Promise<unknown>;\n del(key: string | string[]): Promise<number>;\n sadd(key: string, ...members: string[]): Promise<number>;\n smembers(key: string): Promise<string[]>;\n}\n\nconst KEY_PREFIX = 'timber:cache:';\nconst TAG_PREFIX = 'timber:tag:';\n\n/**\n * Redis-backed CacheHandler for distributed caching.\n *\n * All instances sharing the same Redis see each other's cache entries and\n * invalidations. Tag-based invalidation uses Redis Sets to track which keys\n * belong to which tags.\n *\n * Bring your own Redis client — any client implementing the RedisClient\n * interface works (ioredis, node-redis, @upstash/redis, etc.).\n */\nexport class RedisCacheHandler implements CacheHandler {\n private client: RedisClient;\n private prefix: string;\n\n constructor(client: RedisClient, opts?: { prefix?: string }) {\n this.client = client;\n this.prefix = opts?.prefix ?? '';\n }\n\n private cacheKey(key: string): string {\n return `${this.prefix}${KEY_PREFIX}${key}`;\n }\n\n private tagKey(tag: string): string {\n return `${this.prefix}${TAG_PREFIX}${tag}`;\n }\n\n async get(key: string): Promise<{ value: unknown; stale: boolean } | null> {\n const raw = await this.client.get(this.cacheKey(key));\n if (raw === null) return null;\n\n const entry = JSON.parse(raw) as { value: unknown; expiresAt: number };\n const stale = Date.now() > entry.expiresAt;\n return { value: entry.value, stale };\n }\n\n async set(key: string, value: unknown, opts: { ttl: number; tags: string[] }): Promise<void> {\n const ck = this.cacheKey(key);\n const expiresAt = Date.now() + opts.ttl * 1000;\n const payload = JSON.stringify({ value, expiresAt });\n\n // Redis TTL with generous margin beyond the logical TTL to allow SWR reads\n // on stale entries. The logical staleness is determined by expiresAt.\n // We use 2x TTL + 60s as the Redis expiry so stale entries remain\n // available for SWR background refetches.\n const redisTtlSeconds = Math.max(opts.ttl * 2 + 60, 120);\n await this.client.set(ck, payload, 'EX', redisTtlSeconds);\n\n // Track key membership in each tag set\n for (const tag of opts.tags) {\n await this.client.sadd(this.tagKey(tag), key);\n }\n }\n\n async invalidate(opts: { key?: string; tag?: string }): Promise<void> {\n if (opts.key) {\n await this.client.del(this.cacheKey(opts.key));\n }\n\n if (opts.tag) {\n const tk = this.tagKey(opts.tag);\n const keys = await this.client.smembers(tk);\n\n if (keys.length > 0) {\n const cacheKeys = keys.map((k) => this.cacheKey(k));\n await this.client.del(cacheKeys);\n }\n\n // Clean up the tag set itself\n await this.client.del(tk);\n }\n }\n}\n","/**\n * Deterministic JSON serialization with sorted object keys.\n * Used for cache key generation — ensures { a: 1, b: 2 } and { b: 2, a: 1 }\n * produce the same string.\n */\nexport function stableStringify(value: unknown): string {\n if (value === null || value === undefined) return JSON.stringify(value);\n if (typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) {\n return '[' + value.map((item) => stableStringify(item)).join(',') + ']';\n }\n\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const pairs: string[] = [];\n for (const key of keys) {\n if (obj[key] === undefined) continue;\n pairs.push(JSON.stringify(key) + ':' + stableStringify(obj[key]));\n }\n return '{' + pairs.join(',') + '}';\n}\n","/**\n * Singleflight coalesces concurrent calls with the same key into a single\n * execution. All callers receive the same result (or error).\n *\n * Per-process, in-memory. Each process coalesces independently.\n */\nexport interface Singleflight {\n do<T>(key: string, fn: () => Promise<T>): Promise<T>;\n}\n\nexport function createSingleflight(): Singleflight {\n const inflight = new Map<string, Promise<unknown>>();\n\n return {\n do<T>(key: string, fn: () => Promise<T>): Promise<T> {\n const existing = inflight.get(key);\n if (existing) return existing as Promise<T>;\n\n const promise = fn().finally(() => {\n inflight.delete(key);\n });\n inflight.set(key, promise);\n return promise;\n },\n };\n}\n","import { createHash } from 'node:crypto';\nimport type { CacheHandler, CacheOptions } from './index';\nimport { stableStringify } from './stable-stringify';\nimport { createSingleflight } from './singleflight';\nimport { addSpanEvent } from '#/server/tracing.js';\n\nconst singleflight = createSingleflight();\n\n/**\n * Generate a SHA-256 cache key from function identity and serialized args.\n */\nfunction defaultKeyGenerator(fnId: string, args: unknown[]): string {\n const raw = fnId + ':' + stableStringify(args);\n return createHash('sha256').update(raw).digest('hex');\n}\n\n/**\n * Resolve tags from the options — supports static array or function form.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction resolveTags<Fn extends (...args: any[]) => any>(\n opts: CacheOptions<Fn>,\n args: Parameters<Fn>\n): string[] {\n if (!opts.tags) return [];\n if (Array.isArray(opts.tags)) return opts.tags;\n return opts.tags(...args);\n}\n\n// Counter for generating unique function IDs when no explicit key is provided.\nlet fnIdCounter = 0;\n\n/**\n * Creates a cached wrapper around an async function.\n *\n * - SHA-256 default keys with normalized JSON args\n * - Singleflight: concurrent misses → single execution\n * - SWR: serve stale immediately, background refetch\n * - Tags as string[] or function of args\n * - No ALS dependency\n *\n * Cache hits/misses are recorded as OTEL span events on the enclosing\n * span (not child spans). The DevSpanProcessor reads these for dev log output.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function createCache<Fn extends (...args: any[]) => Promise<any>>(\n fn: Fn,\n opts: CacheOptions<Fn>,\n handler: CacheHandler\n): (...args: Parameters<Fn>) => Promise<Awaited<ReturnType<Fn>>> {\n const fnId = `timber-cache:${fnIdCounter++}`;\n\n return async (...args: Parameters<Fn>): Promise<Awaited<ReturnType<Fn>>> => {\n const key = opts.key ? opts.key(...args) : defaultKeyGenerator(fnId, args);\n\n const cacheStart = performance.now();\n const cached = await handler.get(key);\n\n if (cached && !cached.stale) {\n // Record as OTEL span event on enclosing span (not a child span)\n await addSpanEvent('timber.cache.hit', {\n key,\n duration_ms: Math.round(performance.now() - cacheStart),\n });\n return cached.value as Awaited<ReturnType<Fn>>;\n }\n\n if (cached && cached.stale && opts.staleWhileRevalidate) {\n // Record stale cache hit as OTEL span event\n await addSpanEvent('timber.cache.hit', {\n key,\n duration_ms: Math.round(performance.now() - cacheStart),\n stale: true,\n });\n // Serve stale immediately, trigger background refetch\n singleflight\n .do(`swr:${key}`, async () => {\n try {\n const fresh = await fn(...args);\n const tags = resolveTags(opts, args);\n await handler.set(key, fresh, { ttl: opts.ttl, tags });\n } catch {\n // Failed refetch — stale entry continues to be served.\n // Error is swallowed per design doc: \"Error is logged.\"\n }\n })\n .catch(() => {\n // Singleflight promise rejection handled — stale continues.\n });\n return cached.value as Awaited<ReturnType<Fn>>;\n }\n\n // Cache miss (or stale without SWR) — execute with singleflight\n const result = await singleflight.do(key, () => fn(...args));\n const tags = resolveTags(opts, args);\n await handler.set(key, result, { ttl: opts.ttl, tags });\n\n // Record cache miss as OTEL span event\n await addSpanEvent('timber.cache.miss', {\n key,\n duration_ms: Math.round(performance.now() - cacheStart),\n });\n\n return result as Awaited<ReturnType<Fn>>;\n };\n}\n\n/**\n * Invalidate cache entries by tag or key.\n */\ncreateCache.invalidate = async function invalidate(\n handler: CacheHandler,\n opts: { key?: string; tag?: string }\n): Promise<void> {\n await handler.invalidate(opts);\n};\n","import { createHash } from 'node:crypto';\nimport type { CacheHandler } from './index';\nimport { stableStringify } from './stable-stringify';\nimport { createSingleflight } from './singleflight';\n\nconst singleflight = createSingleflight();\n\n// Prop names that suggest request-specific data — triggers dev warning for \"use cache\" components.\nconst REQUEST_SPECIFIC_PROPS = new Set([\n 'cookies',\n 'cookie',\n 'session',\n 'sessionId',\n 'token',\n 'authorization',\n 'auth',\n 'headers',\n]);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface RegisterCachedFunctionOptions<Fn extends (...args: any[]) => any> {\n ttl: number;\n id: string;\n tags?: string[] | ((...args: Parameters<Fn>) => string[]);\n /** True when the cached function is a React component (PascalCase name). */\n isComponent?: boolean;\n}\n\n/**\n * Generate a SHA-256 cache key from a stable function ID and serialized args.\n */\nfunction generateKey(id: string, args: unknown[]): string {\n const raw = id + ':' + stableStringify(args);\n return createHash('sha256').update(raw).digest('hex');\n}\n\n/**\n * Resolve tags from options — supports static array or function form.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction resolveTags<Fn extends (...args: any[]) => any>(\n opts: RegisterCachedFunctionOptions<Fn>,\n args: Parameters<Fn>\n): string[] {\n if (!opts.tags) return [];\n if (Array.isArray(opts.tags)) return opts.tags;\n return opts.tags(...args);\n}\n\n/**\n * Checks if component props contain request-specific keys and emits a dev warning.\n * Only runs when process.env.NODE_ENV !== 'production'.\n */\nfunction warnRequestSpecificProps(id: string, props: unknown): void {\n if (typeof props !== 'object' || props === null) return;\n const keys = Object.keys(props);\n const suspicious = keys.filter((k) => REQUEST_SPECIFIC_PROPS.has(k.toLowerCase()));\n if (suspicious.length > 0) {\n console.warn(\n `[timber] \"use cache\" component ${id} received request-specific props: ${suspicious.join(', ')}. ` +\n `This may serve one user's cached render to another user. ` +\n `Remove request-specific data from props or remove \"use cache\".`\n );\n }\n}\n\n/**\n * Runtime for the \"use cache\" directive transform. Wraps an async function\n * with caching using the same cache handler as timber.cache.\n *\n * The stable `id` (file path + function name) ensures cache keys are consistent\n * across builds. Args/props are hashed with SHA-256 for the per-call key.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function registerCachedFunction<Fn extends (...args: any[]) => Promise<any>>(\n fn: Fn,\n opts: RegisterCachedFunctionOptions<Fn>,\n handler: CacheHandler\n): (...args: Parameters<Fn>) => Promise<Awaited<ReturnType<Fn>>> {\n return async (...args: Parameters<Fn>): Promise<Awaited<ReturnType<Fn>>> => {\n // Dev-mode warning for components with request-specific props\n if (opts.isComponent && process.env.NODE_ENV !== 'production' && args.length > 0) {\n warnRequestSpecificProps(opts.id, args[0]);\n }\n\n const key = generateKey(opts.id, args);\n const cached = await handler.get(key);\n\n if (cached && !cached.stale) {\n return cached.value as Awaited<ReturnType<Fn>>;\n }\n\n // Cache miss or stale — execute with singleflight\n const result = await singleflight.do(key, () => fn(...args));\n const tags = resolveTags(opts, args);\n await handler.set(key, result, { ttl: opts.ttl, tags });\n return result as Awaited<ReturnType<Fn>>;\n };\n}\n","// @timber/app/cache — Caching primitives\n\nexport interface CacheHandler {\n get(key: string): Promise<{ value: unknown; stale: boolean } | null>;\n set(key: string, value: unknown, opts: { ttl: number; tags: string[] }): Promise<void>;\n invalidate(opts: { key?: string; tag?: string }): Promise<void>;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface CacheOptions<Fn extends (...args: any[]) => any> {\n ttl: number;\n key?: (...args: Parameters<Fn>) => string;\n staleWhileRevalidate?: boolean;\n tags?: string[] | ((...args: Parameters<Fn>) => string[]);\n}\n\nexport interface MemoryCacheHandlerOptions {\n /** Maximum number of entries. Oldest accessed entries are evicted first. Default: 1000. */\n maxSize?: number;\n}\n\nexport class MemoryCacheHandler implements CacheHandler {\n private store = new Map<string, { value: unknown; expiresAt: number; tags: string[] }>();\n private maxSize: number;\n\n constructor(opts?: MemoryCacheHandlerOptions) {\n this.maxSize = opts?.maxSize ?? 1000;\n }\n\n async get(key: string) {\n const entry = this.store.get(key);\n if (!entry) return null;\n\n // Move to end of Map (most recently used) for LRU ordering\n this.store.delete(key);\n this.store.set(key, entry);\n\n const stale = Date.now() > entry.expiresAt;\n return { value: entry.value, stale };\n }\n\n async set(key: string, value: unknown, opts: { ttl: number; tags: string[] }) {\n // If key already exists, delete first to refresh insertion order\n if (this.store.has(key)) {\n this.store.delete(key);\n }\n\n // Evict oldest entries (front of Map) if at capacity\n while (this.store.size >= this.maxSize) {\n const oldest = this.store.keys().next().value;\n if (oldest !== undefined) {\n this.store.delete(oldest);\n } else {\n break;\n }\n }\n\n this.store.set(key, {\n value,\n expiresAt: Date.now() + opts.ttl * 1000,\n tags: opts.tags,\n });\n }\n\n async invalidate(opts: { key?: string; tag?: string }) {\n if (opts.key) {\n this.store.delete(opts.key);\n }\n if (opts.tag) {\n for (const [key, entry] of this.store) {\n if (entry.tags.includes(opts.tag)) {\n this.store.delete(key);\n }\n }\n }\n }\n\n /** Number of entries currently in the cache. */\n get size(): number {\n return this.store.size;\n }\n}\n\nexport { RedisCacheHandler } from './redis-handler';\nexport type { RedisClient } from './redis-handler';\nexport { createCache } from './timber-cache';\nexport { registerCachedFunction } from './register-cached-function';\nexport type { RegisterCachedFunctionOptions } from './register-cached-function';\nexport { stableStringify } from './stable-stringify';\nexport { createSingleflight } from './singleflight';\nexport type { Singleflight } from './singleflight';\n"],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { CacheHandler } from './index';
2
+ /**
3
+ * Minimal Redis client interface — compatible with ioredis, node-redis, and
4
+ * Cloudflare Workers Redis bindings. We depend on the interface, not the
5
+ * implementation, so users bring their own Redis client.
6
+ */
7
+ export interface RedisClient {
8
+ get(key: string): Promise<string | null>;
9
+ set(key: string, value: string, ...args: unknown[]): Promise<unknown>;
10
+ del(key: string | string[]): Promise<number>;
11
+ sadd(key: string, ...members: string[]): Promise<number>;
12
+ smembers(key: string): Promise<string[]>;
13
+ }
14
+ /**
15
+ * Redis-backed CacheHandler for distributed caching.
16
+ *
17
+ * All instances sharing the same Redis see each other's cache entries and
18
+ * invalidations. Tag-based invalidation uses Redis Sets to track which keys
19
+ * belong to which tags.
20
+ *
21
+ * Bring your own Redis client — any client implementing the RedisClient
22
+ * interface works (ioredis, node-redis, @upstash/redis, etc.).
23
+ */
24
+ export declare class RedisCacheHandler implements CacheHandler {
25
+ private client;
26
+ private prefix;
27
+ constructor(client: RedisClient, opts?: {
28
+ prefix?: string;
29
+ });
30
+ private cacheKey;
31
+ private tagKey;
32
+ get(key: string): Promise<{
33
+ value: unknown;
34
+ stale: boolean;
35
+ } | null>;
36
+ set(key: string, value: unknown, opts: {
37
+ ttl: number;
38
+ tags: string[];
39
+ }): Promise<void>;
40
+ invalidate(opts: {
41
+ key?: string;
42
+ tag?: string;
43
+ }): Promise<void>;
44
+ }
45
+ //# sourceMappingURL=redis-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-handler.d.ts","sourceRoot":"","sources":["../../src/cache/redis-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC1C;AAKD;;;;;;;;;GASG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IACpD,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAK3D,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,MAAM;IAIR,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IASpE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBtF,UAAU,CAAC,IAAI,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAkBtE"}
@@ -0,0 +1,17 @@
1
+ import type { CacheHandler } from './index';
2
+ export interface RegisterCachedFunctionOptions<Fn extends (...args: any[]) => any> {
3
+ ttl: number;
4
+ id: string;
5
+ tags?: string[] | ((...args: Parameters<Fn>) => string[]);
6
+ /** True when the cached function is a React component (PascalCase name). */
7
+ isComponent?: boolean;
8
+ }
9
+ /**
10
+ * Runtime for the "use cache" directive transform. Wraps an async function
11
+ * with caching using the same cache handler as timber.cache.
12
+ *
13
+ * The stable `id` (file path + function name) ensures cache keys are consistent
14
+ * across builds. Args/props are hashed with SHA-256 for the per-call key.
15
+ */
16
+ export declare function registerCachedFunction<Fn extends (...args: any[]) => Promise<any>>(fn: Fn, opts: RegisterCachedFunctionOptions<Fn>, handler: CacheHandler): (...args: Parameters<Fn>) => Promise<Awaited<ReturnType<Fn>>>;
17
+ //# sourceMappingURL=register-cached-function.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-cached-function.d.ts","sourceRoot":"","sources":["../../src/cache/register-cached-function.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAmB5C,MAAM,WAAW,6BAA6B,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;IAC/E,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC;IAC1D,4EAA4E;IAC5E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAwCD;;;;;;GAMG;AAEH,wBAAgB,sBAAsB,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,EAChF,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,6BAA6B,CAAC,EAAE,CAAC,EACvC,OAAO,EAAE,YAAY,GACpB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAoB/D"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Singleflight coalesces concurrent calls with the same key into a single
3
+ * execution. All callers receive the same result (or error).
4
+ *
5
+ * Per-process, in-memory. Each process coalesces independently.
6
+ */
7
+ export interface Singleflight {
8
+ do<T>(key: string, fn: () => Promise<T>): Promise<T>;
9
+ }
10
+ export declare function createSingleflight(): Singleflight;
11
+ //# sourceMappingURL=singleflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"singleflight.d.ts","sourceRoot":"","sources":["../../src/cache/singleflight.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACtD;AAED,wBAAgB,kBAAkB,IAAI,YAAY,CAejD"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Deterministic JSON serialization with sorted object keys.
3
+ * Used for cache key generation — ensures { a: 1, b: 2 } and { b: 2, a: 1 }
4
+ * produce the same string.
5
+ */
6
+ export declare function stableStringify(value: unknown): string;
7
+ //# sourceMappingURL=stable-stringify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stable-stringify.d.ts","sourceRoot":"","sources":["../../src/cache/stable-stringify.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAetD"}
@@ -0,0 +1,21 @@
1
+ import type { CacheHandler, CacheOptions } from './index';
2
+ /**
3
+ * Creates a cached wrapper around an async function.
4
+ *
5
+ * - SHA-256 default keys with normalized JSON args
6
+ * - Singleflight: concurrent misses → single execution
7
+ * - SWR: serve stale immediately, background refetch
8
+ * - Tags as string[] or function of args
9
+ * - No ALS dependency
10
+ *
11
+ * Cache hits/misses are recorded as OTEL span events on the enclosing
12
+ * span (not child spans). The DevSpanProcessor reads these for dev log output.
13
+ */
14
+ export declare function createCache<Fn extends (...args: any[]) => Promise<any>>(fn: Fn, opts: CacheOptions<Fn>, handler: CacheHandler): (...args: Parameters<Fn>) => Promise<Awaited<ReturnType<Fn>>>;
15
+ export declare namespace createCache {
16
+ var invalidate: (handler: CacheHandler, opts: {
17
+ key?: string;
18
+ tag?: string;
19
+ }) => Promise<void>;
20
+ }
21
+ //# sourceMappingURL=timber-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timber-cache.d.ts","sourceRoot":"","sources":["../../src/cache/timber-cache.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA+B1D;;;;;;;;;;;GAWG;AAEH,wBAAgB,WAAW,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,EACrE,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC,EACtB,OAAO,EAAE,YAAY,GACpB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAwD/D;yBA5De,WAAW;8BAkEhB,YAAY,QACf;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,KACnC,OAAO,CAAC,IAAI,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+ declare const COMMANDS: readonly ["dev", "build", "preview", "check"];
3
+ type Command = (typeof COMMANDS)[number];
4
+ export interface ParsedArgs {
5
+ command: Command;
6
+ config: string | undefined;
7
+ }
8
+ export interface CommandOptions {
9
+ config?: string;
10
+ }
11
+ /**
12
+ * Parse CLI arguments into a structured command + options.
13
+ * Accepts: timber <command> [--config|-c <path>]
14
+ */
15
+ export declare function parseArgs(args: string[]): ParsedArgs;
16
+ /**
17
+ * Start the Vite dev server.
18
+ * Middleware re-runs on file change via HMR wiring in timber-routing.
19
+ */
20
+ export declare function runDev(options: CommandOptions): Promise<void>;
21
+ /**
22
+ * Run the production build using createBuilder + buildApp.
23
+ * Direct build() calls do NOT trigger the RSC plugin's multi-environment
24
+ * pipeline — createBuilder/buildApp is required.
25
+ */
26
+ export declare function runBuild(options: CommandOptions): Promise<void>;
27
+ /**
28
+ * Determine whether to use the adapter's preview or Vite's built-in preview.
29
+ * Exported for testing — the actual runPreview function uses this internally.
30
+ */
31
+ export declare function resolvePreviewStrategy(adapter: import('./adapters/types').TimberPlatformAdapter | undefined): 'adapter' | 'vite';
32
+ /**
33
+ * Serve the production build for local testing.
34
+ * If the adapter provides a preview() method, it takes priority.
35
+ * Otherwise falls back to Vite's built-in preview server.
36
+ */
37
+ export declare function runPreview(options: CommandOptions): Promise<void>;
38
+ /**
39
+ * Validate types and routes without producing build output.
40
+ * Runs tsgo --noEmit for type checking.
41
+ */
42
+ export declare function runCheck(options: CommandOptions): Promise<void>;
43
+ export {};
44
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAaA,QAAA,MAAM,QAAQ,+CAAgD,CAAC;AAC/D,KAAK,OAAO,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzC,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAuBpD;AAID;;;GAGG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAOnE;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,kBAAkB,EAAE,qBAAqB,GAAG,SAAS,GACpE,SAAS,GAAG,MAAM,CAKpB;AA2BD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBvE;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAerE"}
package/dist/cli.js ADDED
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+ //#region src/cli.ts
3
+ var COMMANDS = [
4
+ "dev",
5
+ "build",
6
+ "preview",
7
+ "check"
8
+ ];
9
+ /**
10
+ * Parse CLI arguments into a structured command + options.
11
+ * Accepts: timber <command> [--config|-c <path>]
12
+ */
13
+ function parseArgs(args) {
14
+ if (args.length === 0) throw new Error("No command provided. Usage: timber <dev|build|preview|check> [--config <path>]");
15
+ const command = args[0];
16
+ if (!COMMANDS.includes(command)) throw new Error(`Unknown command: ${command}. Available commands: ${COMMANDS.join(", ")}`);
17
+ let config;
18
+ for (let i = 1; i < args.length; i++) if (args[i] === "--config" || args[i] === "-c") {
19
+ config = args[++i];
20
+ if (!config) throw new Error("--config requires a path argument");
21
+ }
22
+ return {
23
+ command,
24
+ config
25
+ };
26
+ }
27
+ /**
28
+ * Start the Vite dev server.
29
+ * Middleware re-runs on file change via HMR wiring in timber-routing.
30
+ */
31
+ async function runDev(options) {
32
+ const { createServer } = await import("vite");
33
+ const server = await createServer({ configFile: options.config });
34
+ await server.listen();
35
+ server.printUrls();
36
+ }
37
+ /**
38
+ * Run the production build using createBuilder + buildApp.
39
+ * Direct build() calls do NOT trigger the RSC plugin's multi-environment
40
+ * pipeline — createBuilder/buildApp is required.
41
+ */
42
+ async function runBuild(options) {
43
+ const { createBuilder } = await import("vite");
44
+ await (await createBuilder({ configFile: options.config })).buildApp();
45
+ }
46
+ /**
47
+ * Determine whether to use the adapter's preview or Vite's built-in preview.
48
+ * Exported for testing — the actual runPreview function uses this internally.
49
+ */
50
+ function resolvePreviewStrategy(adapter) {
51
+ if (adapter && typeof adapter.preview === "function") return "adapter";
52
+ return "vite";
53
+ }
54
+ /**
55
+ * Load timber.config.ts from the project root.
56
+ * Returns the config object with adapter, output, etc.
57
+ * Returns null if no config file is found.
58
+ */
59
+ async function loadTimberConfig(root) {
60
+ const { existsSync } = await import("node:fs");
61
+ const { join } = await import("node:path");
62
+ const { pathToFileURL } = await import("node:url");
63
+ for (const name of [
64
+ "timber.config.ts",
65
+ "timber.config.js",
66
+ "timber.config.mjs"
67
+ ]) {
68
+ const configPath = join(root, name);
69
+ if (existsSync(configPath)) {
70
+ const mod = await import(pathToFileURL(configPath).href);
71
+ return mod.default ?? mod;
72
+ }
73
+ }
74
+ return null;
75
+ }
76
+ /**
77
+ * Serve the production build for local testing.
78
+ * If the adapter provides a preview() method, it takes priority.
79
+ * Otherwise falls back to Vite's built-in preview server.
80
+ */
81
+ async function runPreview(options) {
82
+ const { join } = await import("node:path");
83
+ const root = process.cwd();
84
+ const config = await loadTimberConfig(root).catch(() => null);
85
+ const adapter = config?.adapter;
86
+ if (resolvePreviewStrategy(adapter) === "adapter") {
87
+ const buildDir = join(root, ".timber", "build");
88
+ const timberConfig = { output: config?.output ?? "server" };
89
+ await adapter.preview(timberConfig, buildDir);
90
+ return;
91
+ }
92
+ const { preview } = await import("vite");
93
+ (await preview({ configFile: options.config })).printUrls();
94
+ }
95
+ /**
96
+ * Validate types and routes without producing build output.
97
+ * Runs tsgo --noEmit for type checking.
98
+ */
99
+ async function runCheck(options) {
100
+ const { execFile } = await import("node:child_process");
101
+ await new Promise((resolve, reject) => {
102
+ execFile("tsgo", ["--noEmit", ...options.config ? ["--project", options.config] : []], (err, stdout, stderr) => {
103
+ if (stdout) process.stdout.write(stdout);
104
+ if (stderr) process.stderr.write(stderr);
105
+ if (err) reject(/* @__PURE__ */ new Error(`Type check failed with exit code ${err.code}`));
106
+ else resolve();
107
+ });
108
+ });
109
+ }
110
+ async function main() {
111
+ const parsed = parseArgs(process.argv.slice(2));
112
+ const options = { config: parsed.config };
113
+ switch (parsed.command) {
114
+ case "dev":
115
+ await runDev(options);
116
+ break;
117
+ case "build":
118
+ await runBuild(options);
119
+ break;
120
+ case "preview":
121
+ await runPreview(options);
122
+ break;
123
+ case "check":
124
+ await runCheck(options);
125
+ break;
126
+ }
127
+ }
128
+ if (typeof process !== "undefined" && process.argv[1] && import.meta.url.endsWith(process.argv[1])) main().catch((err) => {
129
+ console.error(err.message);
130
+ process.exit(1);
131
+ });
132
+ //#endregion
133
+ export { parseArgs, resolvePreviewStrategy, runBuild, runCheck, runDev, runPreview };
134
+
135
+ //# sourceMappingURL=cli.js.map