@timber-js/app 0.2.0-alpha.152 → 0.2.0-alpha.153

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 (56) hide show
  1. package/dist/_chunks/actions-8lJZYYGq.js +298 -0
  2. package/dist/_chunks/actions-8lJZYYGq.js.map +1 -0
  3. package/dist/_chunks/{cache-api-Co-yI-gP.js → cache-api-e1E4i3Vy.js} +3 -26
  4. package/dist/_chunks/cache-api-e1E4i3Vy.js.map +1 -0
  5. package/dist/_chunks/{cli-schema-sync-DJDdyEae.js → cli-schema-sync-ChsRzw8o.js} +2 -2
  6. package/dist/_chunks/{cli-schema-sync-DJDdyEae.js.map → cli-schema-sync-ChsRzw8o.js.map} +1 -1
  7. package/dist/_chunks/{cli-schema-sync-D_IhHEUW.js → cli-schema-sync-D4urWkeV.js} +1 -1
  8. package/dist/_chunks/{actions-a0RczDnB.js → logger-DvmCWhN9.js} +665 -274
  9. package/dist/_chunks/logger-DvmCWhN9.js.map +1 -0
  10. package/dist/_chunks/plugin-context-GfDWsdd2.js.map +1 -1
  11. package/dist/_chunks/{walkers-DvWDj453.js → walkers-DZuFKqFX.js} +2 -2
  12. package/dist/_chunks/{walkers-DvWDj453.js.map → walkers-DZuFKqFX.js.map} +1 -1
  13. package/dist/cache/index.js +1 -1
  14. package/dist/cli.js +1 -1
  15. package/dist/client/browser-dev.d.ts +3 -0
  16. package/dist/client/browser-dev.d.ts.map +1 -1
  17. package/dist/config-types.d.ts +8 -0
  18. package/dist/config-types.d.ts.map +1 -1
  19. package/dist/config-validation.d.ts.map +1 -1
  20. package/dist/index.js +193 -48
  21. package/dist/index.js.map +1 -1
  22. package/dist/plugin-context.d.ts +9 -0
  23. package/dist/plugin-context.d.ts.map +1 -1
  24. package/dist/plugins/build-report.d.ts +13 -0
  25. package/dist/plugins/build-report.d.ts.map +1 -1
  26. package/dist/plugins/chunks.d.ts +11 -4
  27. package/dist/plugins/chunks.d.ts.map +1 -1
  28. package/dist/plugins/client-chunks.d.ts +23 -22
  29. package/dist/plugins/client-chunks.d.ts.map +1 -1
  30. package/dist/routing/index.js +2 -2
  31. package/dist/server/index.js +2 -2
  32. package/dist/server/internal.js +65 -2
  33. package/dist/server/internal.js.map +1 -1
  34. package/dist/server/logger.d.ts.map +1 -1
  35. package/dist/server/pipeline.d.ts.map +1 -1
  36. package/dist/server/primitives.d.ts +8 -0
  37. package/dist/server/primitives.d.ts.map +1 -1
  38. package/dist/server/stream-utils.d.ts +11 -0
  39. package/dist/server/stream-utils.d.ts.map +1 -1
  40. package/package.json +4 -4
  41. package/src/client/browser-dev.ts +3 -0
  42. package/src/config-types.ts +8 -0
  43. package/src/config-validation.ts +16 -0
  44. package/src/index.ts +2 -2
  45. package/src/plugin-context.ts +9 -0
  46. package/src/plugins/build-report.ts +105 -10
  47. package/src/plugins/chunks.ts +74 -5
  48. package/src/plugins/client-chunks.ts +73 -42
  49. package/src/server/logger.ts +5 -0
  50. package/src/server/pipeline.ts +13 -0
  51. package/src/server/primitives.ts +29 -0
  52. package/src/server/stream-utils.ts +73 -0
  53. package/dist/_chunks/actions-a0RczDnB.js.map +0 -1
  54. package/dist/_chunks/cache-api-Co-yI-gP.js.map +0 -1
  55. package/dist/_chunks/logger-CM0clugc.js +0 -645
  56. package/dist/_chunks/logger-CM0clugc.js.map +0 -1
@@ -66,6 +66,15 @@ export interface PluginContext {
66
66
  * populate per-route modulepreload entries from clientReferenceDeps.
67
67
  */
68
68
  routeClientRefKeys?: Map<string, Set<string>>;
69
+ /**
70
+ * Maps absolute module IDs of client references in non-facade RSC
71
+ * chunks to the absolute paths of their consuming facade modules.
72
+ * Built during the RSC `generateBundle` phase by timber-chunks,
73
+ * consumed by `clientChunkGroup` to reclassify `shared:` modules
74
+ * that are only used by a single route boundary.
75
+ * See design/27-chunking-strategy.md, TIM-1107.
76
+ */
77
+ sharedModuleFacades?: Map<string, string[]>;
69
78
  }
70
79
  /**
71
80
  * Resolve the app directory. Checks (in order):
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-context.d.ts","sourceRoot":"","sources":["../src/plugin-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAA0B,MAAM,mBAAmB,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAGnE,YAAY,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAIlF,qEAAqE;AACrE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,wBAAwB,CAc1F;AAID;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,gBAAgB,CAAC;IACzB,+CAA+C;IAC/C,gBAAgB,EAAE,wBAAwB,CAAC;IAC3C,uFAAuF;IACvF,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,GAAG,EAAE,OAAO,CAAC;IACb,gFAAgF;IAChF,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IACpC,uEAAuE;IACvE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mFAAmF;IACnF,KAAK,EAAE,YAAY,CAAC;IACpB,0FAA0F;IAC1F,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC;;;;;;;;OAQG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;CAC/C;AAID;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAmBzE;AAID,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,aAAa,CAgB3F;AAID,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,QAA0B,CAAC;AAEzD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,cAAc,CAAC,EAAE,MAAM,EACvB,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,CAQR;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CA6B9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAqB1E;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,gBAAgB,GAC3B,MAAM,EAAE,CAgBV;AAWD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,gBAAgB,GAC3B,gBAAgB,CAiBlB"}
1
+ {"version":3,"file":"plugin-context.d.ts","sourceRoot":"","sources":["../src/plugin-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAA0B,MAAM,mBAAmB,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAGnE,YAAY,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAIlF,qEAAqE;AACrE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,wBAAwB,CAc1F;AAID;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,gBAAgB,CAAC;IACzB,+CAA+C;IAC/C,gBAAgB,EAAE,wBAAwB,CAAC;IAC3C,uFAAuF;IACvF,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,GAAG,EAAE,OAAO,CAAC;IACb,gFAAgF;IAChF,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IACpC,uEAAuE;IACvE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mFAAmF;IACnF,KAAK,EAAE,YAAY,CAAC;IACpB,0FAA0F;IAC1F,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACrC;;;;;;;;OAQG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC7C;AAID;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAmBzE;AAID,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,aAAa,CAgB3F;AAID,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,QAA0B,CAAC;AAEzD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,cAAc,CAAC,EAAE,MAAM,EACvB,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,CAQR;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CA6B9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAqB1E;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,gBAAgB,GAC3B,MAAM,EAAE,CAgBV;AAWD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,gBAAgB,GAC3B,gBAAgB,CAiBlB"}
@@ -55,6 +55,10 @@ interface RouteInfo {
55
55
  export declare function collectRoutes(tree: RouteTree): RouteInfo[];
56
56
  /** Produce formatted report lines for the Vite logger. */
57
57
  export declare function buildRouteReport(entries: RouteEntry[], sharedSize: number): string[];
58
+ /** Check route entries against a First-Load-JS budget and return warning lines. */
59
+ export declare function buildWarnings(entries: RouteEntry[], budget?: {
60
+ firstLoadJs?: number;
61
+ }): string[];
58
62
  interface ChunkSize {
59
63
  raw: number;
60
64
  gzip: number;
@@ -62,6 +66,7 @@ interface ChunkSize {
62
66
  interface OutputChunkLike {
63
67
  type: 'chunk' | 'asset';
64
68
  fileName: string;
69
+ name?: string;
65
70
  code?: string;
66
71
  source?: string | Uint8Array;
67
72
  modules?: Record<string, unknown>;
@@ -71,5 +76,13 @@ interface OutputChunkLike {
71
76
  export declare function collectChunkSizes(bundle: Record<string, OutputChunkLike>): Map<string, ChunkSize>;
72
77
  /** Find the output chunk that contains a given input file. */
73
78
  export declare function findChunkForFile(filePath: string, bundle: Record<string, OutputChunkLike>): string | null;
79
+ /**
80
+ * Find all client bundle chunks belonging to a chunk group.
81
+ *
82
+ * Uses the chunk's `name` property (set by Rolldown from the `clientChunks`
83
+ * callback's return value) for exact matching. The `name` is the group name
84
+ * itself (e.g. `client-docs`), not the hashed filename.
85
+ */
86
+ export declare function findChunksForGroup(groupName: string, chunkSizes: Map<string, ChunkSize>, bundle?: Record<string, OutputChunkLike>): string[];
74
87
  export declare function timberBuildReport(ctx: PluginContext): Plugin;
75
88
  //# sourceMappingURL=build-report.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-report.d.ts","sourceRoot":"","sources":["../../src/plugins/build-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAU,MAAM,MAAM,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIhD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,aAAa,EAAE,MAAM,CAAC;CACvB;AAUD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,WAAW,EAAE,EACvB,UAAU,GAAE,QAAQ,GAAG,QAAmB,GACzC,SAAS,CAYX;AAID,OAAO,EAAE,UAAU,EAAE,CAAC;AAQtB,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,EAAE,CAkB1D;AAID,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAyCpF;AAcD,UAAU,SAAS;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAYjG;AAOD,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GACtC,MAAM,GAAG,IAAI,CAOf;AAwED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAwE5D"}
1
+ {"version":3,"file":"build-report.d.ts","sourceRoot":"","sources":["../../src/plugins/build-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAU,MAAM,MAAM,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIhD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,aAAa,EAAE,MAAM,CAAC;CACvB;AAUD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,WAAW,EAAE,EACvB,UAAU,GAAE,QAAQ,GAAG,QAAmB,GACzC,SAAS,CAYX;AAID,OAAO,EAAE,UAAU,EAAE,CAAC;AAQtB,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,EAAE,CAkB1D;AAID,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAyCpF;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,EAAE,CAYhG;AAcD,UAAU,SAAS;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAYjG;AAOD,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GACtC,MAAM,GAAG,IAAI,CAOf;AA0BD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAClC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GACvC,MAAM,EAAE,CAUV;AAgGD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CA+E5D"}
@@ -13,9 +13,15 @@
13
13
  * - Per-route chunks (page/layout components, only when route-specific)
14
14
  * - rolldown-runtime (Rolldown's own output, unavoidable)
15
15
  *
16
+ * Additionally, this plugin builds a facade ancestry map during the RSC
17
+ * build so that `clientChunkGroup` can reclassify `shared:` client
18
+ * references that are only consumed by a single route boundary.
19
+ * See TIM-1107, design/27-chunking-strategy.md.
20
+ *
16
21
  * Design docs: 27-chunking-strategy.md
17
22
  */
18
23
  import type { Plugin } from 'vite';
24
+ import type { PluginContext } from '../plugin-context';
19
25
  /**
20
26
  * Check if a module is part of the timber framework runtime.
21
27
  *
@@ -29,9 +35,10 @@ export declare function isTimberRuntime(id: string): boolean;
29
35
  /**
30
36
  * Create the timber-chunks Vite plugin.
31
37
  *
32
- * Currently a no-op — Rolldown's default splitting produces the desired
33
- * output (one main bundle + per-route chunks). The plugin is retained as
34
- * a hook point for future chunking adjustments.
38
+ * Rolldown's default splitting produces the desired output (one main
39
+ * bundle + per-route chunks). This plugin's main job is building the
40
+ * facade ancestry map during the RSC build so `clientChunkGroup` can
41
+ * reclassify shared client references to their correct route boundary.
35
42
  *
36
43
  * NOTE: Ideally we'd use Rolldown's `format: 'app'` (module registry format)
37
44
  * which guarantees single-copy module semantics like webpack/Turbopack.
@@ -41,5 +48,5 @@ export declare function isTimberRuntime(id: string): boolean;
41
48
  *
42
49
  * Design docs: 27-chunking-strategy.md
43
50
  */
44
- export declare function timberChunks(): Plugin;
51
+ export declare function timberChunks(ctx: PluginContext): Plugin;
45
52
  //# sourceMappingURL=chunks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chunks.d.ts","sourceRoot":"","sources":["../../src/plugins/chunks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAIrC"}
1
+ {"version":3,"file":"chunks.d.ts","sourceRoot":"","sources":["../../src/plugins/chunks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAU,MAAM,MAAM,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAOnD;AA4DD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAQvD"}
@@ -1,39 +1,40 @@
1
1
  /**
2
2
  * Client chunk grouping strategy for @vitejs/plugin-rsc.
3
3
  *
4
- * Groups client reference modules by layout boundary to balance route-scoped
5
- * code splitting with HTTP request count. A constant group name would collapse
6
- * all routes into one chunk (every page downloads every client component).
7
- * Per-serverChunk grouping creates many sub-500B files. Layout-boundary
8
- * grouping is the middle ground.
4
+ * Groups client reference modules by the **consuming route's** layout boundary
5
+ * (derived from `meta.serverChunk`), not by the module's own file location.
6
+ * This ensures components in shared directories (e.g. `components/`) land in
7
+ * the chunk of the route that uses them, not in a single catch-all chunk.
9
8
  *
10
- * See design/27-chunking-strategy.md, TIM-440, TIM-499.
9
+ * For `shared:` modules (client references in non-facade RSC chunks), the
10
+ * function consults a facade ancestry map built during the RSC build. If all
11
+ * consuming facades belong to the same route boundary, the module is
12
+ * reclassified to that boundary instead of falling through to `client-shared`.
13
+ *
14
+ * See design/27-chunking-strategy.md, TIM-440, TIM-499, TIM-1104, TIM-1107.
11
15
  */
12
16
  /**
13
17
  * Derive a chunk group name for a client reference module.
14
18
  *
15
- * Groups by the first non-group route segment under appDir so that all
16
- * client components belonging to the same layout boundary land in one
17
- * chunk. For example:
19
+ * Always derives the group from the **consuming route** (`serverChunk`'s
20
+ * facade path), not from the module's own file location. This prevents
21
+ * components in shared directories (e.g. `app/components/`, `src/lib/`)
22
+ * from collapsing into a single chunk when they're only used by one route.
23
+ *
24
+ * For `shared:` modules (non-facade RSC chunks), consults the facade
25
+ * ancestry map to reclassify modules that are only consumed by a single
26
+ * route boundary. This prevents large dependencies from polluting
27
+ * `client-shared` when they're route-scoped (TIM-1107).
28
+ *
29
+ * Examples:
18
30
  * - `facade:app/dashboard/settings/page.tsx` → `"client-dashboard"`
19
31
  * - `facade:app/(group-a)/group-page-a/page.tsx` → `"client-group-page-a"`
20
32
  * - `facade:app/layout.tsx` (root layout) → `"client-shared"`
21
- * - `shared:...` (shared across chunks) → `"client-shared"`
22
- *
23
- * When a 'use client' module lives outside the app directory (e.g. in
24
- * src/posts/ or src/components/), the function falls back to deriving
25
- * the layout boundary from the serverChunk's facade path. This prevents
26
- * lazily-loaded client dependencies (e.g. via import.meta.glob) from
27
- * being hoisted into the shared chunk when they're only used by a
28
- * specific route.
29
- *
30
- * This balances route-scoped code splitting with HTTP request count:
31
- * fewer chunks than per-serverChunk, but still avoids downloading every
32
- * client component on every page.
33
+ * - `shared:...` (shared across chunks) → reclassified or `"client-shared"`
33
34
  */
34
35
  export declare function clientChunkGroup(meta: {
35
36
  id: string;
36
37
  normalizedId: string;
37
38
  serverChunk: string;
38
- }, appDir: string, root: string): string;
39
+ }, appDir: string, root: string, sharedModuleFacades?: Map<string, string[]>): string;
39
40
  //# sourceMappingURL=client-chunks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-chunks.d.ts","sourceRoot":"","sources":["../../src/plugins/client-chunks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAoCH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EAC/D,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,MAAM,CAwCR"}
1
+ {"version":3,"file":"client-chunks.d.ts","sourceRoot":"","sources":["../../src/plugins/client-chunks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAwEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EAC/D,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,mBAAmB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAC1C,MAAM,CAiCR"}
@@ -1,4 +1,4 @@
1
1
  import { i as INTERCEPTION_MARKERS, n as classifyUrlSegment, r as DEFAULT_PAGE_EXTENSIONS, t as classifySegment } from "../_chunks/segment-classify-CDDRVKs7.js";
2
- import { s as scanRoutes } from "../_chunks/cli-schema-sync-DJDdyEae.js";
3
- import { a as generateRouteMap, i as validateSchemaAgainstRoutes, n as collectInterceptionRewrites, r as collectDynamicSegmentsFromTree, t as collectLeafRoutes } from "../_chunks/walkers-DvWDj453.js";
2
+ import { s as scanRoutes } from "../_chunks/cli-schema-sync-ChsRzw8o.js";
3
+ import { a as generateRouteMap, i as validateSchemaAgainstRoutes, n as collectInterceptionRewrites, r as collectDynamicSegmentsFromTree, t as collectLeafRoutes } from "../_chunks/walkers-DZuFKqFX.js";
4
4
  export { DEFAULT_PAGE_EXTENSIONS, INTERCEPTION_MARKERS, classifySegment, classifyUrlSegment, collectDynamicSegmentsFromTree, collectInterceptionRewrites, collectLeafRoutes, generateRouteMap, scanRoutes, validateSchemaAgainstRoutes };
@@ -1,6 +1,6 @@
1
- import { C as getTraceId, D as withSpan, S as getSpanId, _ as isDevMode, g as isDebug, k as formFlashAls, v as addSpanEvent } from "../_chunks/logger-CM0clugc.js";
1
+ import { B as addSpanEvent, C as RedirectType, E as getHeaders, F as getCookieJar, G as getTraceId, O as getSegmentParams, R as isDebug, S as waitUntil, W as getSpanId, Y as withSpan, Z as formFlashAls, _ as RedirectSignal, b as redirect, g as DenySignal, x as redirectExternal, y as deny, z as isDevMode } from "../_chunks/logger-DvmCWhN9.js";
2
2
  import { t as formatSize } from "../_chunks/format-CfwjgPz9.js";
3
- import { T as getCookieJar, a as parseFormData, d as redirectExternal, f as waitUntil, g as getHeaders, i as coerce, l as deny, n as revalidatePath, o as DenySignal, p as RedirectType, r as revalidateTag, s as RedirectSignal, u as redirect, v as getSegmentParams } from "../_chunks/actions-a0RczDnB.js";
3
+ import { a as parseFormData, i as coerce, n as revalidatePath, r as revalidateTag } from "../_chunks/actions-8lJZYYGq.js";
4
4
  //#region src/server/sensitive-fields.ts
5
5
  /**
6
6
  * Sensitive field stripping — removes password/token/CVV-style fields
@@ -1,7 +1,7 @@
1
1
  import { a as classifyMetadataRoute, i as METADATA_ROUTE_CONVENTIONS, o as getMetadataRouteAutoLink, r as canonicalize, s as getMetadataRouteServePath } from "../_chunks/canonicalize-P41GR6tY.js";
2
2
  import { n as classifyUrlSegment } from "../_chunks/segment-classify-CDDRVKs7.js";
3
- import { A as requestContextAls, C as getTraceId, D as withSpan, E as setSpanAttribute, M as timingAls, O as earlyHintsSenderAls, T as runWithTraceId, a as logProxyError, b as generateTraceId, c as logRequestReceived, d as logSwrRefetchFailed, f as logWaitUntilRejected, g as isDebug, h as swallow, i as logMiddlewareShortCircuit, l as logRouteError, m as setLogger, n as logCacheMiss, o as logRenderError, p as logWaitUntilUnsupported, r as logMiddlewareError, s as logRequestCompleted, t as getLogger, u as logSlowRequest, w as replaceTraceId, x as getOtelTraceId } from "../_chunks/logger-CM0clugc.js";
4
- import { C as setSegmentParams, E as getSetCookieHeaders, S as setMutableCookieContext, _ as getSearchParams, b as runWithRequestContext, c as RenderError, h as getHeader, i as coerce, m as applyRequestHeaderOverlay, o as DenySignal, s as RedirectSignal, t as executeAction, v as getSegmentParams, w as getCookie, x as setMatchedSegmentPath, y as markResponseFlushed } from "../_chunks/actions-a0RczDnB.js";
3
+ import { A as runWithRequestContext, D as getSearchParams, G as getTraceId, H as generateTraceId, I as getSetCookieHeaders, J as setSpanAttribute, K as replaceTraceId, M as setMutableCookieContext, N as setSegmentParams, O as getSegmentParams, P as getCookie, Q as requestContextAls, R as isDebug, T as getHeader, U as getOtelTraceId, X as earlyHintsSenderAls, Y as withSpan, _ as RedirectSignal, a as logProxyError, c as logRequestReceived, d as logSwrRefetchFailed, et as timingAls, f as logWaitUntilRejected, g as DenySignal, h as swallow, i as logMiddlewareShortCircuit, j as setMatchedSegmentPath, k as markResponseFlushed, l as logRouteError, m as setLogger, n as logCacheMiss, o as logRenderError, p as logWaitUntilUnsupported, q as runWithTraceId, r as logMiddlewareError, s as logRequestCompleted, t as getLogger, u as logSlowRequest, v as RenderError, w as applyRequestHeaderOverlay } from "../_chunks/logger-DvmCWhN9.js";
4
+ import { i as coerce, t as executeAction } from "../_chunks/actions-8lJZYYGq.js";
5
5
  import "../client/error-boundary.js";
6
6
  import { n as toBracketKey } from "../_chunks/resolve-schema-3iUvBV5T.js";
7
7
  import "../_chunks/segment-context-ZDnXDkbz.js";
@@ -84,6 +84,64 @@ function getServerTimingHeader() {
84
84
  return result || null;
85
85
  }
86
86
  //#endregion
87
+ //#region src/server/stream-utils.ts
88
+ /**
89
+ * Wrap a response body with stream-lifecycle timing instrumentation.
90
+ *
91
+ * Logs firstChunk, lastChunk, close, maxGap (largest inter-chunk gap),
92
+ * chunk count, and byte count on stream termination (clean close OR
93
+ * cancellation/disconnect). Gated behind `serverTiming: 'detailed'`.
94
+ *
95
+ * Uses a manual reader pump to guarantee logging on all termination
96
+ * paths — TransformStream.flush() is not called on cancellation.
97
+ */
98
+ function wrapResponseWithStreamTiming(body, startTime) {
99
+ let firstChunkMs = 0;
100
+ let lastChunkMs = 0;
101
+ let maxGapMs = 0;
102
+ let prevChunkTime = 0;
103
+ let chunks = 0;
104
+ let bytes = 0;
105
+ let cancelled = false;
106
+ function emitLog() {
107
+ const closeMs = Math.round(performance.now() - startTime);
108
+ console.log(`[timber] stream-lifecycle: firstChunk=${firstChunkMs}ms lastChunk=${lastChunkMs}ms close=${closeMs}ms maxGap=${maxGapMs}ms chunks=${chunks} bytes=${bytes}` + (cancelled ? " cancelled=true" : ""));
109
+ }
110
+ const reader = body.getReader();
111
+ return new ReadableStream({
112
+ async pull(controller) {
113
+ try {
114
+ const { done, value } = await reader.read();
115
+ if (done) {
116
+ emitLog();
117
+ controller.close();
118
+ return;
119
+ }
120
+ const now = performance.now();
121
+ const relativeMs = Math.round(now - startTime);
122
+ if (chunks === 0) firstChunkMs = relativeMs;
123
+ else {
124
+ const gap = Math.round(now - prevChunkTime);
125
+ if (gap > maxGapMs) maxGapMs = gap;
126
+ }
127
+ prevChunkTime = now;
128
+ lastChunkMs = relativeMs;
129
+ chunks++;
130
+ bytes += value.byteLength;
131
+ controller.enqueue(value);
132
+ } catch (err) {
133
+ emitLog();
134
+ controller.error(err);
135
+ }
136
+ },
137
+ cancel(reason) {
138
+ cancelled = true;
139
+ emitLog();
140
+ reader.cancel(reason).catch(() => {});
141
+ }
142
+ });
143
+ }
144
+ //#endregion
87
145
  //#region src/server/instrumentation.ts
88
146
  /**
89
147
  * Instrumentation — loads and runs the user's instrumentation.ts file.
@@ -2328,6 +2386,11 @@ function createPipeline(config) {
2328
2386
  const totalMs = Math.round(performance.now() - startTime);
2329
2387
  result.headers.set("Server-Timing", `total;dur=${totalMs}`);
2330
2388
  }
2389
+ if (serverTiming === "detailed" && result.body) result = new Response(wrapResponseWithStreamTiming(result.body, startTime), {
2390
+ status: result.status,
2391
+ statusText: result.statusText,
2392
+ headers: result.headers
2393
+ });
2331
2394
  return result;
2332
2395
  });
2333
2396
  const durationMs = Math.round(performance.now() - startTime);