@timber-js/app 0.2.0-alpha.3 → 0.2.0-alpha.5

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 (85) hide show
  1. package/dist/_chunks/{als-registry-k-AtAQ9R.js → als-registry-B7DbZ2hS.js} +1 -1
  2. package/dist/_chunks/{als-registry-k-AtAQ9R.js.map → als-registry-B7DbZ2hS.js.map} +1 -1
  3. package/dist/_chunks/debug-gwlJkDuf.js +108 -0
  4. package/dist/_chunks/debug-gwlJkDuf.js.map +1 -0
  5. package/dist/_chunks/{format-DNt20Kt8.js → format-DviM89f0.js} +3 -2
  6. package/dist/_chunks/format-DviM89f0.js.map +1 -0
  7. package/dist/_chunks/{interception-DGDIjDbR.js → interception-BOoWmLUA.js} +2 -2
  8. package/dist/_chunks/{interception-DGDIjDbR.js.map → interception-BOoWmLUA.js.map} +1 -1
  9. package/dist/_chunks/{metadata-routes-CQCnF4VK.js → metadata-routes-Cjmvi3rQ.js} +1 -1
  10. package/dist/_chunks/{metadata-routes-CQCnF4VK.js.map → metadata-routes-Cjmvi3rQ.js.map} +1 -1
  11. package/dist/_chunks/{request-context-CRj2Zh1E.js → request-context-DIkVh_jG.js} +5 -4
  12. package/dist/_chunks/request-context-DIkVh_jG.js.map +1 -0
  13. package/dist/_chunks/{ssr-data-DLnbYpj1.js → ssr-data-MjmprTmO.js} +1 -1
  14. package/dist/_chunks/{ssr-data-DLnbYpj1.js.map → ssr-data-MjmprTmO.js.map} +1 -1
  15. package/dist/_chunks/{tracing-DF0G3FB7.js → tracing-Cwn7697K.js} +2 -2
  16. package/dist/_chunks/{tracing-DF0G3FB7.js.map → tracing-Cwn7697K.js.map} +1 -1
  17. package/dist/_chunks/{use-cookie-dDbpCTx-.js → use-cookie-DX-l1_5E.js} +2 -2
  18. package/dist/_chunks/{use-cookie-dDbpCTx-.js.map → use-cookie-DX-l1_5E.js.map} +1 -1
  19. package/dist/_chunks/{use-query-states-DAhgj8Gx.js → use-query-states-D5KaffOK.js} +1 -1
  20. package/dist/_chunks/{use-query-states-DAhgj8Gx.js.map → use-query-states-D5KaffOK.js.map} +1 -1
  21. package/dist/cache/index.js +2 -2
  22. package/dist/client/error-boundary.js +1 -1
  23. package/dist/client/index.js +3 -3
  24. package/dist/cookies/index.js +4 -4
  25. package/dist/fonts/local.d.ts +4 -2
  26. package/dist/fonts/local.d.ts.map +1 -1
  27. package/dist/index.d.ts +38 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +211 -14
  30. package/dist/index.js.map +1 -1
  31. package/dist/plugins/build-report.d.ts +11 -1
  32. package/dist/plugins/build-report.d.ts.map +1 -1
  33. package/dist/plugins/entries.d.ts +7 -0
  34. package/dist/plugins/entries.d.ts.map +1 -1
  35. package/dist/plugins/fonts.d.ts +2 -1
  36. package/dist/plugins/fonts.d.ts.map +1 -1
  37. package/dist/plugins/mdx.d.ts +6 -0
  38. package/dist/plugins/mdx.d.ts.map +1 -1
  39. package/dist/plugins/server-bundle.d.ts.map +1 -1
  40. package/dist/routing/index.js +1 -1
  41. package/dist/search-params/index.js +1 -1
  42. package/dist/server/access-gate.d.ts.map +1 -1
  43. package/dist/server/action-client.d.ts.map +1 -1
  44. package/dist/server/debug.d.ts +82 -0
  45. package/dist/server/debug.d.ts.map +1 -0
  46. package/dist/server/deny-renderer.d.ts.map +1 -1
  47. package/dist/server/dev-warnings.d.ts.map +1 -1
  48. package/dist/server/index.js +14 -13
  49. package/dist/server/index.js.map +1 -1
  50. package/dist/server/logger.d.ts.map +1 -1
  51. package/dist/server/primitives.d.ts.map +1 -1
  52. package/dist/server/request-context.d.ts.map +1 -1
  53. package/dist/server/response-cache.d.ts +53 -0
  54. package/dist/server/response-cache.d.ts.map +1 -0
  55. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  56. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  57. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  58. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  59. package/dist/server/rsc-prop-warnings.d.ts.map +1 -1
  60. package/dist/shims/image.d.ts +15 -15
  61. package/package.json +1 -1
  62. package/src/client/stale-reload.ts +1 -1
  63. package/src/fonts/local.ts +7 -3
  64. package/src/index.ts +40 -0
  65. package/src/plugins/build-report.ts +23 -3
  66. package/src/plugins/entries.ts +9 -4
  67. package/src/plugins/fonts.ts +106 -5
  68. package/src/plugins/mdx.ts +9 -5
  69. package/src/plugins/server-bundle.ts +4 -0
  70. package/src/server/access-gate.tsx +3 -2
  71. package/src/server/action-client.ts +8 -4
  72. package/src/server/debug.ts +137 -0
  73. package/src/server/deny-renderer.ts +3 -2
  74. package/src/server/dev-warnings.ts +2 -1
  75. package/src/server/logger.ts +4 -3
  76. package/src/server/primitives.ts +2 -1
  77. package/src/server/request-context.ts +3 -2
  78. package/src/server/response-cache.ts +277 -0
  79. package/src/server/rsc-entry/index.ts +51 -13
  80. package/src/server/rsc-entry/rsc-payload.ts +4 -1
  81. package/src/server/rsc-entry/rsc-stream.ts +2 -1
  82. package/src/server/rsc-entry/ssr-renderer.ts +6 -2
  83. package/src/server/rsc-prop-warnings.ts +3 -1
  84. package/dist/_chunks/format-DNt20Kt8.js.map +0 -1
  85. package/dist/_chunks/request-context-CRj2Zh1E.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,6FAA6F;AAC7F,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1D;AAMD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAEpD;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,YAAY,GAAG,IAAI,CAE/C;AAsBD,4CAA4C;AAC5C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAEP;AAED,0CAA0C;AAC1C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAE/E;AAED,+CAA+C;AAC/C,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAEP;AAED,kDAAkD;AAClD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,IAAI,CAEP;AAED,6DAA6D;AAC7D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAM/F;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAQ3F;AAED,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAM5D;AAED,sEAAsE;AACtE,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED,sDAAsD;AACtD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAEnE;AAED,6DAA6D;AAC7D,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAEpF;AAED,oCAAoC;AACpC,wBAAgB,YAAY,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAE7D"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,6FAA6F;AAC7F,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1D;AAMD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAEpD;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,YAAY,GAAG,IAAI,CAE/C;AAsBD,4CAA4C;AAC5C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAEP;AAED,0CAA0C;AAC1C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAE/E;AAED,+CAA+C;AAC/C,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAEP;AAED,kDAAkD;AAClD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,IAAI,CAEP;AAED,6DAA6D;AAC7D,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAM/F;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAQ3F;AAED,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAM5D;AAED,sEAAsE;AACtE,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED,sDAAsD;AACtD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAEnE;AAED,6DAA6D;AAC7D,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAEpF;AAED,oCAAoC;AACpC,wBAAgB,YAAY,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAE7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/server/primitives.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAKnD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAS,GAAG,MAAM,GAAG,IAAI,CA8DhF;AAsBD;;;GAGG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,CAAC;gBAEhC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB;IAOnD;;;;OAIG;IACH,IAAI,UAAU,IAAI,MAAM,GAAG,SAAS,CAqBnC;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,MAAM,GAAE,MAAY,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,KAAK,CASzE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,IAAI,KAAK,CAEhC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAIX;;;GAGG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAM7C;AAKD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAY,GAAG,KAAK,CAWlE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAErD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,GAAE,MAAY,GAAG,KAAK,CAoB9F;AAID;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAChC,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,gBAAgB,GAAG,gBAAgB;IAEjD,IAAI,EAAE,KAAK,CAAC;IACZ,IAAI,EAAE,KAAK,CAAC;CACb;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,WAAW,CACtB,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,gBAAgB,GAAG,gBAAgB,CACjD,SAAQ,KAAK;IACb,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;CAcpE;AAID,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC7C;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAqBrF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAID;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,SAAQ,KAAK;aAGrB,KAAK,EAAE,OAAO;gBAD9B,OAAO,EAAE,MAAM,EACC,KAAK,EAAE,OAAO;CAKjC"}
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/server/primitives.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAMnD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAS,GAAG,MAAM,GAAG,IAAI,CA8DhF;AAsBD;;;GAGG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,CAAC;gBAEhC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB;IAOnD;;;;OAIG;IACH,IAAI,UAAU,IAAI,MAAM,GAAG,SAAS,CAqBnC;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,MAAM,GAAE,MAAY,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,KAAK,CASzE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,IAAI,KAAK,CAEhC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAIX;;;GAGG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAM7C;AAKD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAY,GAAG,KAAK,CAWlE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAErD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,GAAE,MAAY,GAAG,KAAK,CAoB9F;AAID;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAChC,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,gBAAgB,GAAG,gBAAgB;IAEjD,IAAI,EAAE,KAAK,CAAC;IACZ,IAAI,EAAE,KAAK,CAAC;CACb;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,WAAW,CACtB,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,gBAAgB,GAAG,gBAAgB,CACjD,SAAQ,KAAK;IACb,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;CAcpE;AAID,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC7C;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAqBrF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAID;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,SAAQ,KAAK;aAGrB,KAAK,EAAE,OAAO;gBAD9B,OAAO,EAAE,MAAM,EACC,KAAK,EAAE,OAAO;CAKjC"}
@@ -1 +1 @@
1
- {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Render-level response deduplication and short-TTL LRU cache.
3
+ *
4
+ * Two layers of optimization:
5
+ *
6
+ * 1. **Singleflight** — concurrent requests to the same URL share a single
7
+ * render. Uses createSingleflight() from cache/singleflight.ts.
8
+ *
9
+ * 2. **LRU cache** — recently rendered responses are reused without
10
+ * re-executing the RSC-to-SSR pipeline. Entries have a short TTL
11
+ * (default 5s) and the cache has a bounded size (default 150 entries).
12
+ *
13
+ * Cache keys are compound: method + pathname + isRscPayload. Responses
14
+ * with Set-Cookie headers are never cached (they contain user-specific
15
+ * state). When `publicOnly` is true (default), requests with Cookie or
16
+ * Authorization headers bypass the cache entirely.
17
+ *
18
+ * See design/02-rendering-pipeline.md, design/31-benchmarking.md.
19
+ */
20
+ export interface ResponseCacheConfig {
21
+ /** Maximum number of entries in the LRU cache. Default: 150. */
22
+ maxSize?: number;
23
+ /** TTL for cached entries in milliseconds. Default: 5000 (5s). */
24
+ ttlMs?: number;
25
+ /**
26
+ * When true (default), requests with Cookie or Authorization headers
27
+ * bypass the cache entirely. This prevents sharing user-specific
28
+ * responses across requests.
29
+ */
30
+ publicOnly?: boolean;
31
+ }
32
+ export interface ResolvedResponseCacheConfig {
33
+ maxSize: number;
34
+ ttlMs: number;
35
+ publicOnly: boolean;
36
+ }
37
+ export declare function resolveResponseCacheConfig(config?: ResponseCacheConfig | false): ResolvedResponseCacheConfig | null;
38
+ export interface ResponseCache {
39
+ /**
40
+ * Wrap a render function with singleflight dedup + LRU caching.
41
+ * Returns the cached Response or executes the render function.
42
+ */
43
+ getOrRender(req: Request, isRscPayload: boolean, renderFn: () => Promise<Response>): Promise<Response>;
44
+ /** Number of entries currently in the LRU cache. */
45
+ readonly size: number;
46
+ /** Clear all cached entries. */
47
+ clear(): void;
48
+ }
49
+ /**
50
+ * Create a response cache with singleflight deduplication and LRU caching.
51
+ */
52
+ export declare function createResponseCache(config: ResolvedResponseCacheConfig): ResponseCache;
53
+ //# sourceMappingURL=response-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-cache.d.ts","sourceRoot":"","sources":["../../src/server/response-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,0BAA0B,CACxC,MAAM,CAAC,EAAE,mBAAmB,GAAG,KAAK,GACnC,2BAA2B,GAAG,IAAI,CASpC;AAoFD,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,WAAW,CACT,GAAG,EAAE,OAAO,EACZ,YAAY,EAAE,OAAO,EACrB,QAAQ,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAChC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAErB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,gCAAgC;IAChC,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,2BAA2B,GAAG,aAAa,CAqHtF"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AA0EA;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAE/F;AAyXD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAIzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;8BA7P3C,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;AA+PhD,wBAAiE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AAgFA;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAE/F;AAyZD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAIzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;8BA7P3C,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;AA+PhD,wBAAiE"}
@@ -1 +1 @@
1
- {"version":3,"file":"rsc-payload.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAQrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,oBAAoB,EAAE,EACxC,YAAY,EAAE,WAAW,EAAE,EAC3B,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,eAAe,CAAC,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,QAAQ,CAAC,CAuFnB"}
1
+ {"version":3,"file":"rsc-payload.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAQrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,oBAAoB,EAAE,EACxC,YAAY,EAAE,WAAW,EAAE,EAC3B,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,eAAe,CAAC,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,QAAQ,CAAC,CA0FnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAe,MAAM,wBAAwB,CAAC;AAKjF;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,WAAW,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACxD;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;IAClD,OAAO,EAAE,aAAa,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,GAAG,eAAe,CA8G1F"}
1
+ {"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAe,MAAM,wBAAwB,CAAC;AAMjF;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,WAAW,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACxD;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;IAClD,OAAO,EAAE,aAAa,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,GAAG,eAAe,CA8G1F"}
@@ -1 +1 @@
1
- {"version":3,"file":"ssr-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/ssr-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAYrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,UAAU,gBAAgB;IACxB,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACtC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,KAAK,EAAE,UAAU,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,qBAAqB,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA+JjF"}
1
+ {"version":3,"file":"ssr-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/ssr-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAYrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,UAAU,gBAAgB;IACxB,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACtC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,KAAK,EAAE,UAAU,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,qBAAqB,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAmKjF"}
@@ -1 +1 @@
1
- {"version":3,"file":"rsc-prop-warnings.d.ts","sourceRoot":"","sources":["../../src/server/rsc-prop-warnings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;CACpB;AAkFD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAU9F;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,uBAAuB,EAC7B,WAAW,CAAC,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,CAeR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAUrF"}
1
+ {"version":3,"file":"rsc-prop-warnings.d.ts","sourceRoot":"","sources":["../../src/server/rsc-prop-warnings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;CACpB;AAkFD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAU9F;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,uBAAuB,EAC7B,WAAW,CAAC,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,CAeR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAUrF"}
@@ -51,17 +51,17 @@ export declare function Image({ priority: _priority, quality: _quality, fill: _f
51
51
  autoCapitalize?: "off" | "none" | "on" | "sentences" | "words" | "characters" | undefined | (string & {});
52
52
  autoFocus?: boolean | undefined;
53
53
  className?: string | undefined;
54
- contentEditable?: (boolean | "true" | "false") | "inherit" | "plaintext-only" | undefined;
54
+ contentEditable?: (boolean | "false" | "true") | "inherit" | "plaintext-only" | undefined;
55
55
  contextMenu?: string | undefined;
56
56
  dir?: string | undefined;
57
- draggable?: (boolean | "true" | "false") | undefined;
57
+ draggable?: (boolean | "false" | "true") | undefined;
58
58
  enterKeyHint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined;
59
59
  hidden?: boolean | undefined;
60
60
  id?: string | undefined;
61
61
  lang?: string | undefined;
62
62
  nonce?: string | undefined;
63
63
  slot?: string | undefined;
64
- spellCheck?: (boolean | "true" | "false") | undefined;
64
+ spellCheck?: (boolean | "false" | "true") | undefined;
65
65
  style?: import("react").CSSProperties | undefined;
66
66
  tabIndex?: number | undefined;
67
67
  title?: string | undefined;
@@ -99,11 +99,11 @@ export declare function Image({ priority: _priority, quality: _quality, fill: _f
99
99
  exportparts?: string | undefined;
100
100
  part?: string | undefined;
101
101
  "aria-activedescendant"?: string | undefined;
102
- "aria-atomic"?: (boolean | "true" | "false") | undefined;
102
+ "aria-atomic"?: (boolean | "false" | "true") | undefined;
103
103
  "aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined;
104
104
  "aria-braillelabel"?: string | undefined;
105
105
  "aria-brailleroledescription"?: string | undefined;
106
- "aria-busy"?: (boolean | "true" | "false") | undefined;
106
+ "aria-busy"?: (boolean | "false" | "true") | undefined;
107
107
  "aria-checked"?: boolean | "false" | "mixed" | "true" | undefined;
108
108
  "aria-colcount"?: number | undefined;
109
109
  "aria-colindex"?: number | undefined;
@@ -114,37 +114,37 @@ export declare function Image({ priority: _priority, quality: _quality, fill: _f
114
114
  "aria-describedby"?: string | undefined;
115
115
  "aria-description"?: string | undefined;
116
116
  "aria-details"?: string | undefined;
117
- "aria-disabled"?: (boolean | "true" | "false") | undefined;
117
+ "aria-disabled"?: (boolean | "false" | "true") | undefined;
118
118
  "aria-dropeffect"?: "none" | "copy" | "execute" | "link" | "move" | "popup" | undefined;
119
119
  "aria-errormessage"?: string | undefined;
120
- "aria-expanded"?: (boolean | "true" | "false") | undefined;
120
+ "aria-expanded"?: (boolean | "false" | "true") | undefined;
121
121
  "aria-flowto"?: string | undefined;
122
- "aria-grabbed"?: (boolean | "true" | "false") | undefined;
122
+ "aria-grabbed"?: (boolean | "false" | "true") | undefined;
123
123
  "aria-haspopup"?: boolean | "false" | "true" | "menu" | "listbox" | "tree" | "grid" | "dialog" | undefined;
124
- "aria-hidden"?: (boolean | "true" | "false") | undefined;
124
+ "aria-hidden"?: (boolean | "false" | "true") | undefined;
125
125
  "aria-invalid"?: boolean | "false" | "true" | "grammar" | "spelling" | undefined;
126
126
  "aria-keyshortcuts"?: string | undefined;
127
127
  "aria-label"?: string | undefined;
128
128
  "aria-labelledby"?: string | undefined;
129
129
  "aria-level"?: number | undefined;
130
130
  "aria-live"?: "off" | "assertive" | "polite" | undefined;
131
- "aria-modal"?: (boolean | "true" | "false") | undefined;
132
- "aria-multiline"?: (boolean | "true" | "false") | undefined;
133
- "aria-multiselectable"?: (boolean | "true" | "false") | undefined;
131
+ "aria-modal"?: (boolean | "false" | "true") | undefined;
132
+ "aria-multiline"?: (boolean | "false" | "true") | undefined;
133
+ "aria-multiselectable"?: (boolean | "false" | "true") | undefined;
134
134
  "aria-orientation"?: "horizontal" | "vertical" | undefined;
135
135
  "aria-owns"?: string | undefined;
136
136
  "aria-placeholder"?: string | undefined;
137
137
  "aria-posinset"?: number | undefined;
138
138
  "aria-pressed"?: boolean | "false" | "mixed" | "true" | undefined;
139
- "aria-readonly"?: (boolean | "true" | "false") | undefined;
139
+ "aria-readonly"?: (boolean | "false" | "true") | undefined;
140
140
  "aria-relevant"?: "additions" | "additions removals" | "additions text" | "all" | "removals" | "removals additions" | "removals text" | "text" | "text additions" | "text removals" | undefined;
141
- "aria-required"?: (boolean | "true" | "false") | undefined;
141
+ "aria-required"?: (boolean | "false" | "true") | undefined;
142
142
  "aria-roledescription"?: string | undefined;
143
143
  "aria-rowcount"?: number | undefined;
144
144
  "aria-rowindex"?: number | undefined;
145
145
  "aria-rowindextext"?: string | undefined;
146
146
  "aria-rowspan"?: number | undefined;
147
- "aria-selected"?: (boolean | "true" | "false") | undefined;
147
+ "aria-selected"?: (boolean | "false" | "true") | undefined;
148
148
  "aria-setsize"?: number | undefined;
149
149
  "aria-sort"?: "none" | "ascending" | "descending" | "other" | undefined;
150
150
  "aria-valuemax"?: number | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timber-js/app",
3
- "version": "0.2.0-alpha.3",
3
+ "version": "0.2.0-alpha.5",
4
4
  "description": "Vite-native React framework for Cloudflare Workers — correct HTTP semantics, real status codes, pages that work without JavaScript",
5
5
  "keywords": [
6
6
  "cloudflare-workers",
@@ -29,7 +29,7 @@ const RELOAD_FLAG_KEY = '__timber_stale_reload';
29
29
  export function isStaleClientReference(error: unknown): boolean {
30
30
  if (!(error instanceof Error)) return false;
31
31
  const msg = error.message;
32
- return msg.includes('Could not find the module');
32
+ return msg.includes('Could not find the module') || msg.includes('client reference not found');
33
33
  }
34
34
 
35
35
  /**
@@ -100,18 +100,22 @@ export function generateFamilyName(sources: LocalFontSrc[]): string {
100
100
  * Generate @font-face descriptors for local font sources.
101
101
  *
102
102
  * Each source entry produces one @font-face rule. The `src` descriptor
103
- * uses a `url()` pointing to the resolved file path with the inferred format.
103
+ * uses a `url()` pointing to the served path under `/_timber/fonts/`.
104
+ * The `urlPrefix` defaults to `/_timber/fonts` — the path used by both
105
+ * the dev server middleware and the production build output.
104
106
  */
105
107
  export function generateLocalFontFaces(
106
108
  family: string,
107
109
  sources: LocalFontSrc[],
108
- display: string
110
+ display: string,
111
+ urlPrefix = '/_timber/fonts'
109
112
  ): FontFaceDescriptor[] {
110
113
  return sources.map((entry) => {
111
114
  const format = inferFontFormat(entry.path);
115
+ const basename = entry.path.split('/').pop() ?? entry.path;
112
116
  return {
113
117
  family,
114
- src: `url('${entry.path}') format('${format}')`,
118
+ src: `url('${urlPrefix}/${basename}') format('${format}')`,
115
119
  weight: entry.weight,
116
120
  style: entry.style,
117
121
  display,
package/src/index.ts CHANGED
@@ -46,6 +46,18 @@ export interface ResolvedClientJavascript {
46
46
 
47
47
  export interface TimberUserConfig {
48
48
  output?: 'server' | 'static';
49
+ /**
50
+ * Enable timber debug logging in production builds.
51
+ *
52
+ * When `true`, timber's own diagnostics (dev warnings, verbose logging)
53
+ * are active even in production mode. React stays in production mode —
54
+ * only timber's logs are affected.
55
+ *
56
+ * Can also be enabled at runtime via the `TIMBER_DEBUG` environment variable.
57
+ *
58
+ * Default: `false`.
59
+ */
60
+ debug?: boolean;
49
61
  /**
50
62
  * Control client-side JavaScript output.
51
63
  *
@@ -134,6 +146,34 @@ export interface TimberUserConfig {
134
146
  /** CSS z-index. Default: 1600. */
135
147
  zIndex?: number;
136
148
  };
149
+ /**
150
+ * Response-level caching and deduplication.
151
+ *
152
+ * When enabled, concurrent requests to the same URL share a single render
153
+ * (singleflight), and recently rendered responses are reused from a short-TTL
154
+ * LRU cache without re-executing the RSC-to-SSR pipeline.
155
+ *
156
+ * Set to `false` to disable entirely. Default: enabled with sensible defaults.
157
+ *
158
+ * See design/31-benchmarking.md for performance context.
159
+ */
160
+ responseCache?:
161
+ | false
162
+ | {
163
+ /** Maximum number of entries in the LRU cache. Default: 150. */
164
+ maxSize?: number;
165
+ /** TTL for cached entries in milliseconds. Default: 5000 (5s). */
166
+ ttlMs?: number;
167
+ /**
168
+ * When true (default), requests with Cookie or Authorization headers
169
+ * bypass the cache entirely. This prevents sharing user-specific
170
+ * responses across requests.
171
+ *
172
+ * Set to false to cache all responses regardless of auth state.
173
+ * Only do this if your pages are truly public and don't vary by user.
174
+ */
175
+ publicOnly?: boolean;
176
+ };
137
177
  }
138
178
 
139
179
  /**
@@ -80,7 +80,17 @@ interface RouteInfo {
80
80
  entryFilePath: string | null;
81
81
  }
82
82
 
83
- /** Walk the route tree and collect all leaf routes (pages + API endpoints). */
83
+ /**
84
+ * Walk the route tree and collect all leaf routes (pages + API endpoints).
85
+ *
86
+ * Parallel slots (`@artists`, `@shows`, etc.) are intentionally skipped —
87
+ * they render alongside the parent page at the same URL and are not
88
+ * separately URL-addressable. Their JS is captured in shared/layout chunks.
89
+ *
90
+ * After collection, entries are deduplicated by URL path so that overlapping
91
+ * route groups (e.g. `(browse)` and `(marketing)` both producing `/`) only
92
+ * appear once. The entry with the largest route-specific size wins.
93
+ */
84
94
  export function collectRoutes(tree: RouteTree): RouteInfo[] {
85
95
  const routes: RouteInfo[] = [];
86
96
 
@@ -95,12 +105,22 @@ export function collectRoutes(tree: RouteTree): RouteInfo[] {
95
105
  routes.push({ path, segments: currentChain, entryFilePath: node.route.filePath });
96
106
  }
97
107
 
108
+ // Recurse into child segments only — skip parallel slots (node.slots)
98
109
  for (const child of node.children) walk(child, currentChain);
99
- for (const slot of node.slots.values()) walk(slot, currentChain);
100
110
  }
101
111
 
102
112
  walk(tree.root, []);
103
- return routes;
113
+
114
+ // Deduplicate entries with the same URL path (e.g. from overlapping route groups).
115
+ // Keep the entry with the longest segment chain (most specific match).
116
+ const seen = new Map<string, RouteInfo>();
117
+ for (const route of routes) {
118
+ const existing = seen.get(route.path);
119
+ if (!existing || route.segments.length > existing.segments.length) {
120
+ seen.set(route.path, route);
121
+ }
122
+ }
123
+ return Array.from(seen.values());
104
124
  }
105
125
 
106
126
  // ─── Report formatting ────────────────────────────────────────────────────
@@ -110,6 +110,8 @@ function generateConfigModule(ctx: PluginContext): string {
110
110
  slowRequestMs: ctx.config.slowRequestMs ?? 3000,
111
111
  cookieSecrets,
112
112
  topLoader: ctx.config.topLoader,
113
+ responseCache: ctx.config.responseCache,
114
+ debug: ctx.config.debug ?? false,
113
115
  };
114
116
 
115
117
  return [
@@ -128,11 +130,14 @@ function generateConfigModule(ctx: PluginContext): string {
128
130
  * Checks for instrumentation.ts, .js, and .mjs — matching the same
129
131
  * extensions as timber.config.ts detection.
130
132
  */
131
- function detectInstrumentationFile(root: string): string | null {
133
+ export function detectInstrumentationFile(root: string): string | null {
132
134
  const extensions = ['.ts', '.js', '.mjs'];
133
- for (const ext of extensions) {
134
- const candidate = resolve(root, `instrumentation${ext}`);
135
- if (existsSync(candidate)) return candidate;
135
+ const dirs = [root, resolve(root, 'src')];
136
+ for (const dir of dirs) {
137
+ for (const ext of extensions) {
138
+ const candidate = resolve(dir, `instrumentation${ext}`);
139
+ if (existsSync(candidate)) return candidate;
140
+ }
136
141
  }
137
142
  return null;
138
143
  }
@@ -14,13 +14,15 @@
14
14
  * Design doc: 24-fonts.md
15
15
  */
16
16
 
17
- import type { Plugin } from 'vite';
17
+ import type { Plugin, ViteDevServer } from 'vite';
18
+ import { readFileSync, existsSync } from 'node:fs';
19
+ import { resolve, normalize } from 'node:path';
18
20
  import type { PluginContext } from '#/index.js';
19
21
  import type { ExtractedFont, GoogleFontConfig } from '#/fonts/types.js';
20
22
  import type { ManifestFontEntry } from '#/server/build-manifest.js';
21
- import { generateVariableClass, generateFontFamilyClass } from '#/fonts/css.js';
23
+ import { generateVariableClass, generateFontFamilyClass, generateFontFaces } from '#/fonts/css.js';
22
24
  import { generateFallbackCss, buildFontStack } from '#/fonts/fallbacks.js';
23
- import { processLocalFont } from '#/fonts/local.js';
25
+ import { processLocalFont, generateLocalFontFaces } from '#/fonts/local.js';
24
26
  import { inferFontFormat } from '#/fonts/local.js';
25
27
  import { downloadAndCacheFonts, type CachedFont } from '#/fonts/google.js';
26
28
  import {
@@ -31,8 +33,10 @@ import {
31
33
 
32
34
  const VIRTUAL_GOOGLE = '@timber/fonts/google';
33
35
  const VIRTUAL_LOCAL = '@timber/fonts/local';
36
+ const VIRTUAL_FONT_CSS = 'virtual:timber-fonts-css';
34
37
  const RESOLVED_GOOGLE = '\0@timber/fonts/google';
35
38
  const RESOLVED_LOCAL = '\0@timber/fonts/local';
39
+ const RESOLVED_FONT_CSS = '\0virtual:timber-fonts-css';
36
40
 
37
41
  /**
38
42
  * Registry of fonts extracted during transform.
@@ -245,12 +249,20 @@ function generateLocalVirtualModule(): string {
245
249
  /**
246
250
  * Generate the CSS output for all extracted fonts.
247
251
  *
248
- * Includes @font-face rules, fallback @font-face rules, and scoped classes.
252
+ * Includes @font-face rules for local fonts, fallback @font-face rules,
253
+ * and scoped classes.
249
254
  */
250
255
  export function generateAllFontCss(registry: FontRegistry): string {
251
256
  const cssParts: string[] = [];
252
257
 
253
258
  for (const font of registry.values()) {
259
+ // Generate @font-face rules for local fonts
260
+ if (font.provider === 'local' && font.localSources) {
261
+ const faces = generateLocalFontFaces(font.family, font.localSources, font.display);
262
+ const faceCss = generateFontFaces(faces);
263
+ if (faceCss) cssParts.push(faceCss);
264
+ }
265
+
254
266
  // Generate fallback @font-face if metrics are available
255
267
  const fallbackCss = generateFallbackCss(font.family);
256
268
  if (fallbackCss) cssParts.push(fallbackCss);
@@ -359,23 +371,83 @@ export function timberFonts(ctx: PluginContext): Plugin {
359
371
  name: 'timber-fonts',
360
372
 
361
373
  /**
362
- * Resolve `@timber/fonts/google` and `@timber/fonts/local` to virtual modules.
374
+ * Resolve `@timber/fonts/google`, `@timber/fonts/local`, and the
375
+ * virtual font CSS module to internal IDs.
363
376
  */
364
377
  resolveId(id: string) {
365
378
  if (id === VIRTUAL_GOOGLE) return RESOLVED_GOOGLE;
366
379
  if (id === VIRTUAL_LOCAL) return RESOLVED_LOCAL;
380
+ if (id === VIRTUAL_FONT_CSS) return RESOLVED_FONT_CSS;
367
381
  return null;
368
382
  },
369
383
 
370
384
  /**
371
385
  * Return generated source for font virtual modules.
386
+ *
387
+ * The font CSS virtual module returns the combined @font-face rules,
388
+ * fallback CSS, and scoped classes for all registered fonts.
372
389
  */
373
390
  load(id: string) {
374
391
  if (id === RESOLVED_GOOGLE) return generateGoogleVirtualModule(registry);
375
392
  if (id === RESOLVED_LOCAL) return generateLocalVirtualModule();
393
+ if (id === RESOLVED_FONT_CSS) return generateAllFontCss(registry);
376
394
  return null;
377
395
  },
378
396
 
397
+ /**
398
+ * Serve local font files in dev mode under `/_timber/fonts/`.
399
+ *
400
+ * Only files that are registered in the font registry (via localSources)
401
+ * are served. Paths are validated to prevent directory traversal.
402
+ */
403
+ configureServer(server: ViteDevServer) {
404
+ server.middlewares.use((req, res, next) => {
405
+ const url = req.url;
406
+ if (!url || !url.startsWith('/_timber/fonts/')) return next();
407
+
408
+ const requestedFilename = url.slice('/_timber/fonts/'.length);
409
+ // Reject path traversal attempts
410
+ if (requestedFilename.includes('..') || requestedFilename.includes('/')) {
411
+ res.statusCode = 400;
412
+ res.end('Bad request');
413
+ return;
414
+ }
415
+
416
+ // Find the matching font file in the registry
417
+ for (const font of registry.values()) {
418
+ if (font.provider !== 'local' || !font.localSources) continue;
419
+ for (const src of font.localSources) {
420
+ const basename = src.path.split('/').pop() ?? '';
421
+ if (basename === requestedFilename) {
422
+ const absolutePath = normalize(resolve(src.path));
423
+ // Verify the resolved path hasn't escaped (extra safety)
424
+ if (!existsSync(absolutePath)) {
425
+ res.statusCode = 404;
426
+ res.end('Not found');
427
+ return;
428
+ }
429
+ const data = readFileSync(absolutePath);
430
+ const ext = absolutePath.split('.').pop()?.toLowerCase();
431
+ const mimeMap: Record<string, string> = {
432
+ woff2: 'font/woff2',
433
+ woff: 'font/woff',
434
+ ttf: 'font/ttf',
435
+ otf: 'font/otf',
436
+ eot: 'application/vnd.ms-fontopen',
437
+ };
438
+ res.setHeader('Content-Type', mimeMap[ext ?? ''] ?? 'application/octet-stream');
439
+ res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
440
+ res.setHeader('Access-Control-Allow-Origin', '*');
441
+ res.end(data);
442
+ return;
443
+ }
444
+ }
445
+ }
446
+
447
+ next();
448
+ });
449
+ },
450
+
379
451
  /**
380
452
  * Download and cache Google Fonts during production builds.
381
453
  *
@@ -525,6 +597,35 @@ export function timberFonts(ctx: PluginContext): Plugin {
525
597
  });
526
598
  }
527
599
 
600
+ // Emit local font files as assets
601
+ for (const font of registry.values()) {
602
+ if (font.provider !== 'local' || !font.localSources) continue;
603
+ for (const src of font.localSources) {
604
+ const absolutePath = normalize(resolve(src.path));
605
+ if (!existsSync(absolutePath)) {
606
+ this.warn(`Local font file not found: ${absolutePath}`);
607
+ continue;
608
+ }
609
+ const basename = src.path.split('/').pop() ?? src.path;
610
+ const data = readFileSync(absolutePath);
611
+ this.emitFile({
612
+ type: 'asset',
613
+ fileName: `_timber/fonts/${basename}`,
614
+ source: data,
615
+ });
616
+ }
617
+ }
618
+
619
+ // Emit the combined font CSS as an asset
620
+ const fontCss = generateAllFontCss(registry);
621
+ if (fontCss) {
622
+ this.emitFile({
623
+ type: 'asset',
624
+ fileName: '_timber/fonts/fonts.css',
625
+ source: fontCss,
626
+ });
627
+ }
628
+
528
629
  if (!ctx.buildManifest) return;
529
630
 
530
631
  // Build a lookup from font family → cached files for manifest entries
@@ -16,19 +16,23 @@ import type { PluginContext } from '#/index.js';
16
16
  const MDX_EXTENSIONS = ['mdx', 'md'];
17
17
 
18
18
  /**
19
- * Check if mdx-components.tsx (or .ts, .jsx, .js) exists at the project root.
19
+ * Check if mdx-components.tsx (or .ts, .jsx, .js) exists at the project root
20
+ * or in src/. Root takes precedence, matching Next.js behavior.
20
21
  * Returns the absolute path if found, otherwise undefined.
21
22
  */
22
- function findMdxComponents(root: string): string | undefined {
23
+ export function findMdxComponents(root: string): string | undefined {
23
24
  const candidates = [
24
25
  'mdx-components.tsx',
25
26
  'mdx-components.ts',
26
27
  'mdx-components.jsx',
27
28
  'mdx-components.js',
28
29
  ];
29
- for (const name of candidates) {
30
- const p = join(root, name);
31
- if (existsSync(p)) return p;
30
+ const dirs = [root, join(root, 'src')];
31
+ for (const dir of dirs) {
32
+ for (const name of candidates) {
33
+ const p = join(dir, name);
34
+ if (existsSync(p)) return p;
35
+ }
32
36
  }
33
37
  return undefined;
34
38
  }
@@ -65,6 +65,10 @@ export function timberServerBundle(): Plugin[] {
65
65
  // eliminated by Rollup's tree-shaking. Without this, the runtime
66
66
  // check falls through on platforms where process.env is empty
67
67
  // (e.g. Cloudflare Workers), causing dev code to run in production.
68
+ // Define process.env.NODE_ENV so dev-only React code is tree-shaken.
69
+ // TIMBER_DEBUG is intentionally NOT defined here — it must remain a
70
+ // runtime check so `isDebug()` in server/debug.ts can read it at
71
+ // request time. See TIM-365.
68
72
  const serverDefine = {
69
73
  'process.env.NODE_ENV': JSON.stringify('production'),
70
74
  };
@@ -16,6 +16,7 @@
16
16
  import { DenySignal, RedirectSignal } from './primitives.js';
17
17
  import type { AccessGateProps, SlotAccessGateProps, ReactElement } from './tree-builder.js';
18
18
  import { withSpan, setSpanAttribute } from './tracing.js';
19
+ import { isDebug } from './debug.js';
19
20
 
20
21
  // ─── AccessGate ─────────────────────────────────────────────────────────────
21
22
 
@@ -114,7 +115,7 @@ export async function SlotAccessGate(props: SlotAccessGateProps): Promise<ReactE
114
115
  // slot would redirect the entire page, which breaks the contract that
115
116
  // slot failure is graceful degradation.
116
117
  if (error instanceof RedirectSignal) {
117
- if (process.env.NODE_ENV !== 'production') {
118
+ if (isDebug()) {
118
119
  console.error(
119
120
  '[timber] redirect() is not allowed in slot access.ts. ' +
120
121
  'Slots use deny() for graceful degradation — denied.tsx → default.tsx → null. ' +
@@ -127,7 +128,7 @@ export async function SlotAccessGate(props: SlotAccessGateProps): Promise<ReactE
127
128
 
128
129
  // Unhandled error — re-throw so error boundaries can catch it.
129
130
  // Dev-mode warning: slot access should use deny(), not throw.
130
- if (process.env.NODE_ENV !== 'production') {
131
+ if (isDebug()) {
131
132
  console.warn(
132
133
  '[timber] Unhandled error in slot access.ts. ' +
133
134
  'Use deny() for access control, not unhandled throws.',