@timber-js/app 0.2.0-alpha.2 → 0.2.0-alpha.4

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 (77) 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-B4WUeqJ-.js +75 -0
  4. package/dist/_chunks/debug-B4WUeqJ-.js.map +1 -0
  5. package/dist/_chunks/{format-DNt20Kt8.js → format-CwdaB0_2.js} +3 -2
  6. package/dist/_chunks/format-CwdaB0_2.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-CZJi4CuK.js} +5 -4
  12. package/dist/_chunks/request-context-CZJi4CuK.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/client/top-loader.d.ts.map +1 -1
  25. package/dist/cookies/index.js +4 -4
  26. package/dist/index.d.ts +38 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +22 -6
  29. package/dist/index.js.map +1 -1
  30. package/dist/plugins/build-report.d.ts +11 -1
  31. package/dist/plugins/build-report.d.ts.map +1 -1
  32. package/dist/plugins/entries.d.ts.map +1 -1
  33. package/dist/plugins/server-bundle.d.ts.map +1 -1
  34. package/dist/routing/index.js +1 -1
  35. package/dist/search-params/index.js +1 -1
  36. package/dist/server/access-gate.d.ts.map +1 -1
  37. package/dist/server/action-client.d.ts.map +1 -1
  38. package/dist/server/debug.d.ts +51 -0
  39. package/dist/server/debug.d.ts.map +1 -0
  40. package/dist/server/deny-renderer.d.ts.map +1 -1
  41. package/dist/server/dev-warnings.d.ts.map +1 -1
  42. package/dist/server/index.js +14 -13
  43. package/dist/server/index.js.map +1 -1
  44. package/dist/server/logger.d.ts.map +1 -1
  45. package/dist/server/primitives.d.ts.map +1 -1
  46. package/dist/server/request-context.d.ts.map +1 -1
  47. package/dist/server/response-cache.d.ts +53 -0
  48. package/dist/server/response-cache.d.ts.map +1 -0
  49. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  50. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  51. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  52. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  53. package/dist/server/rsc-prop-warnings.d.ts.map +1 -1
  54. package/dist/shims/image.d.ts +15 -15
  55. package/package.json +1 -1
  56. package/src/client/stale-reload.ts +1 -1
  57. package/src/client/top-loader.tsx +18 -15
  58. package/src/index.ts +40 -0
  59. package/src/plugins/build-report.ts +23 -3
  60. package/src/plugins/entries.ts +2 -0
  61. package/src/plugins/server-bundle.ts +4 -0
  62. package/src/server/access-gate.tsx +3 -2
  63. package/src/server/action-client.ts +3 -2
  64. package/src/server/debug.ts +99 -0
  65. package/src/server/deny-renderer.ts +3 -2
  66. package/src/server/dev-warnings.ts +2 -1
  67. package/src/server/logger.ts +4 -3
  68. package/src/server/primitives.ts +2 -1
  69. package/src/server/request-context.ts +3 -2
  70. package/src/server/response-cache.ts +277 -0
  71. package/src/server/rsc-entry/index.ts +36 -9
  72. package/src/server/rsc-entry/rsc-payload.ts +4 -1
  73. package/src/server/rsc-entry/rsc-stream.ts +2 -1
  74. package/src/server/rsc-entry/ssr-renderer.ts +6 -2
  75. package/src/server/rsc-prop-warnings.ts +3 -1
  76. package/dist/_chunks/format-DNt20Kt8.js.map +0 -1
  77. 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;AA8YD,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.2",
3
+ "version": "0.2.0-alpha.4",
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
  /**
@@ -60,6 +60,7 @@ const DEFAULT_Z_INDEX = 1600;
60
60
  // Unique keyframes name to avoid collisions with user styles.
61
61
  const CRAWL_KEYFRAMES = '__timber_top_loader_crawl';
62
62
  const APPEAR_KEYFRAMES = '__timber_top_loader_appear';
63
+ const FINISH_KEYFRAMES = '__timber_top_loader_finish';
63
64
 
64
65
  // Track whether the @keyframes rules have been injected into the document.
65
66
  let keyframesInjected = false;
@@ -83,6 +84,11 @@ function ensureKeyframes(): void {
83
84
  from { opacity: 0; }
84
85
  to { opacity: 1; }
85
86
  }
87
+ @keyframes ${FINISH_KEYFRAMES} {
88
+ 0% { width: 90%; opacity: 1; }
89
+ 50% { width: 100%; opacity: 1; }
90
+ 100% { width: 100%; opacity: 0; }
91
+ }
86
92
  `;
87
93
  document.head.appendChild(style);
88
94
  keyframesInjected = true;
@@ -161,14 +167,13 @@ export function TopLoader({ config }: { config?: TopLoaderConfig }): React.React
161
167
  ].join(', '),
162
168
  }
163
169
  : {
164
- // Finishing: snap to 100% width (200ms), THEN fade out (200ms).
165
- // The opacity transition is delayed so the user sees the bar
166
- // reach 100% before it disappears. Without the delay, both
167
- // transitions run simultaneously and the bar fades before the
168
- // fill animation is visible.
169
- width: '100%',
170
- opacity: 0,
171
- transition: 'width 200ms ease, opacity 200ms ease 200ms',
170
+ // Finishing: fill to 100% then fade out via a keyframe animation.
171
+ // We use a keyframe instead of a CSS transition because the
172
+ // animation-to-transition handoff is unreliable the browser
173
+ // may not capture the animated width as the transition's "from"
174
+ // value when both the animation removal and transition are
175
+ // applied in the same render frame.
176
+ animation: `${FINISH_KEYFRAMES} 400ms ease forwards`,
172
177
  }),
173
178
  ...(shadow
174
179
  ? {
@@ -177,12 +182,10 @@ export function TopLoader({ config }: { config?: TopLoaderConfig }): React.React
177
182
  : {}),
178
183
  };
179
184
 
180
- // Clean up the finishing phase when the CSS transition completes.
181
- // onTransitionEnd fires once per transitioned property — we act on
182
- // the first one (opacity) and ignore subsequent (width).
183
- const handleTransitionEnd = phase === 'finishing'
184
- ? (e: React.TransitionEvent) => {
185
- if (e.propertyName === 'opacity') {
185
+ // Clean up the finishing phase when the finish animation completes.
186
+ const handleAnimationEnd = phase === 'finishing'
187
+ ? (e: React.AnimationEvent) => {
188
+ if (e.animationName === FINISH_KEYFRAMES) {
186
189
  setPhase('hidden');
187
190
  }
188
191
  }
@@ -195,6 +198,6 @@ export function TopLoader({ config }: { config?: TopLoaderConfig }): React.React
195
198
  'aria-hidden': 'true',
196
199
  'data-timber-top-loader': '',
197
200
  },
198
- createElement('div', { style: barStyle, onTransitionEnd: handleTransitionEnd })
201
+ createElement('div', { style: barStyle, onAnimationEnd: handleAnimationEnd })
199
202
  );
200
203
  }
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 [
@@ -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.',
@@ -184,6 +184,7 @@ async function runActionMiddleware<TCtx>(
184
184
  // Re-export parseFormData for use throughout the framework
185
185
  import { parseFormData } from './form-data.js';
186
186
  import { formatSize } from '#/utils/format.js';
187
+ import { isDebug } from './debug.js';
187
188
 
188
189
  /**
189
190
  * Extract validation errors from a schema error.
@@ -247,7 +248,7 @@ export function handleActionError(error: unknown): ActionResult<never> {
247
248
  }
248
249
 
249
250
  // In dev, include the message for debugging
250
- const isDev = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production';
251
+ const isDev = isDebug();
251
252
  return {
252
253
  serverError: {
253
254
  code: 'INTERNAL_ERROR',
@@ -413,7 +414,7 @@ export function validated<TInput, TData>(
413
414
  * In production, validation errors are only returned to the client.
414
415
  */
415
416
  function logValidationFailure(errors: ValidationErrors): void {
416
- const isDev = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production';
417
+ const isDev = isDebug();
417
418
  if (!isDev) return;
418
419
 
419
420
  const fields = Object.entries(errors)
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Runtime debug flag for timber.js.
3
+ *
4
+ * Provides `isDebug()` — a runtime check that returns true when timber's
5
+ * debug/warning logging should be active. This is true in two cases:
6
+ *
7
+ * 1. Development mode: `process.env.NODE_ENV !== 'production'`
8
+ * (statically replaced and tree-shaken in production builds — zero cost)
9
+ *
10
+ * 2. TIMBER_DEBUG flag: A runtime environment variable that survives
11
+ * production builds. When set to any truthy value ("1", "true", etc.),
12
+ * timber's own diagnostics are re-enabled without affecting React's mode.
13
+ *
14
+ * The TIMBER_DEBUG check uses a dynamic property access pattern that
15
+ * prevents the bundler from statically replacing or eliminating it.
16
+ *
17
+ * Usage:
18
+ * In Cloudflare Workers wrangler.toml:
19
+ * [vars]
20
+ * TIMBER_DEBUG = "1"
21
+ *
22
+ * In Node.js:
23
+ * TIMBER_DEBUG=1 node server.js
24
+ *
25
+ * In timber.config.ts:
26
+ * export default { debug: true }
27
+ *
28
+ * See design/18-build-system.md for build pipeline details.
29
+ */
30
+
31
+ // ─── Debug Flag ─────────────────────────────────────────────────────────────
32
+
33
+ /**
34
+ * Config-level debug override. Set via `setDebugFromConfig()` during
35
+ * initialization when timber.config.ts has `debug: true`.
36
+ */
37
+ let _configDebug = false;
38
+
39
+ /**
40
+ * Set the debug flag from timber.config.ts.
41
+ * Called during handler initialization.
42
+ */
43
+ export function setDebugFromConfig(debug: boolean): void {
44
+ _configDebug = debug;
45
+ }
46
+
47
+ /**
48
+ * Check if timber debug logging is active.
49
+ *
50
+ * Returns true if ANY of these conditions hold:
51
+ * - NODE_ENV is not 'production' (standard dev mode)
52
+ * - TIMBER_DEBUG environment variable is set to a truthy value at runtime
53
+ * - timber.config.ts has `debug: true`
54
+ *
55
+ * The TIMBER_DEBUG check is deliberately written as a dynamic property
56
+ * access so bundlers cannot statically replace it. The `_envKey` variable
57
+ * prevents the bundler from seeing `process.env.TIMBER_DEBUG` as a
58
+ * compile-time constant.
59
+ *
60
+ * This function is intentionally NOT inlineable — it reads runtime state.
61
+ */
62
+ export function isDebug(): boolean {
63
+ // Fast path: dev mode (statically replaced to `true` in dev, `false` in prod)
64
+ if (process.env.NODE_ENV !== 'production') return true;
65
+
66
+ // Config override
67
+ if (_configDebug) return true;
68
+
69
+ // Runtime env var check — uses dynamic access to prevent static replacement.
70
+ // In production builds, process.env.NODE_ENV is statically replaced, but
71
+ // TIMBER_DEBUG must survive as a runtime check. The dynamic key access
72
+ // pattern ensures the bundler treats this as opaque.
73
+ return _readTimberDebugEnv();
74
+ }
75
+
76
+ /**
77
+ * Read TIMBER_DEBUG from the environment at runtime.
78
+ *
79
+ * Extracted to a separate function to:
80
+ * 1. Prevent bundler inlining (cross-module function calls are not inlined)
81
+ * 2. Handle platforms where `process` may not exist (Cloudflare Workers)
82
+ * 3. Support globalThis.__TIMBER_DEBUG for programmatic control
83
+ */
84
+ function _readTimberDebugEnv(): boolean {
85
+ // globalThis override — useful for programmatic control and testing
86
+ if ((globalThis as Record<string, unknown>).__TIMBER_DEBUG) return true;
87
+
88
+ // process.env — works in Node.js and platforms that polyfill process
89
+ try {
90
+ const key = 'TIMBER_DEBUG';
91
+ const val =
92
+ typeof process !== 'undefined' && process.env ? (process.env as Record<string, string | undefined>)[key] : undefined;
93
+ if (val && val !== '0' && val !== 'false') return true;
94
+ } catch {
95
+ // process may not exist or env may throw — safe to ignore
96
+ }
97
+
98
+ return false;
99
+ }
@@ -20,6 +20,7 @@ import { renderToReadableStream } from '#/rsc-runtime/rsc.js';
20
20
 
21
21
  import { DenySignal } from './primitives.js';
22
22
  import { logRenderError } from './logger.js';
23
+ import { isDebug } from './debug.js';
23
24
  import { resolveMetadata, renderMetadataToElements } from './metadata.js';
24
25
  import { resolveManifestStatusFile } from './manifest-status-resolver.js';
25
26
  import type { ManifestSegmentNode } from './route-matcher.js';
@@ -94,7 +95,7 @@ export async function renderDenyPage(
94
95
 
95
96
  // Dev warning: JSON status file exists but is shadowed by the component chain.
96
97
  // This helps developers understand why their .json file isn't being served.
97
- if (process.env.NODE_ENV !== 'production') {
98
+ if (isDebug()) {
98
99
  const jsonResolution = resolveManifestStatusFile(deny.status, segments, 'json');
99
100
  if (jsonResolution) {
100
101
  console.warn(
@@ -133,7 +134,7 @@ export async function renderDenyPage(
133
134
  const { component } = layoutsToWrap[i];
134
135
  element = h(component, null, element);
135
136
  }
136
- } else if (process.env.NODE_ENV !== 'production') {
137
+ } else if (isDebug()) {
137
138
  // Dev-mode: warn if shell=false might conflict with Suspense
138
139
  // The actual Suspense boundary check happens at render time in the pipeline.
139
140
  // This is a preemptive log for developer awareness.
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
  import type { ViteDevServer } from 'vite';
18
+ import { isDebug } from './debug.js';
18
19
 
19
20
  // ─── Warning IDs ───────────────────────────────────────────────────────────
20
21
 
@@ -54,7 +55,7 @@ export function setViteServer(server: ViteDevServer | null): void {
54
55
  }
55
56
 
56
57
  function isDev(): boolean {
57
- return process.env.NODE_ENV !== 'production';
58
+ return isDebug();
58
59
  }
59
60
 
60
61
  /**