octane 0.2.12 → 0.2.13

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 (243) hide show
  1. package/README.md +5 -0
  2. package/dist/behavior-root.d.ts +13 -3
  3. package/dist/behavior-root.js +28 -5
  4. package/dist/cjs/behavior-root.cjs +32 -6
  5. package/dist/cjs/class-names.cjs +49 -0
  6. package/dist/cjs/constants.cjs +9 -0
  7. package/dist/cjs/css.cjs +6 -27
  8. package/dist/cjs/data-encoding.cjs +160 -0
  9. package/dist/cjs/dom-binding-handoff.cjs +93 -0
  10. package/dist/cjs/dom-binding-protocol.cjs +115 -0
  11. package/dist/cjs/dom-binding-styles.cjs +292 -0
  12. package/dist/cjs/dom-bindings.cjs +700 -0
  13. package/dist/cjs/dom-focused-move.cjs +66 -0
  14. package/dist/cjs/dom-tables.cjs +4 -94
  15. package/dist/cjs/error-codes.client.generated.cjs +33 -0
  16. package/dist/cjs/error-codes.server.generated.cjs +19 -0
  17. package/dist/cjs/hydration/control-capture.cjs +244 -0
  18. package/dist/cjs/hydration/event-capture.cjs +125 -43
  19. package/dist/cjs/hydration/interaction-config.cjs +50 -2
  20. package/dist/cjs/hydration-markers.cjs +37 -0
  21. package/dist/cjs/independent-hydration-protocol.cjs +106 -0
  22. package/dist/cjs/index.cjs +6 -0
  23. package/dist/cjs/runtime.cjs +2791 -215
  24. package/dist/cjs/runtime.server.cjs +716 -76
  25. package/dist/cjs/server/early-signals.cjs +45 -0
  26. package/dist/cjs/server/index.cjs +44 -0
  27. package/dist/cjs/server/rpc-batch.cjs +149 -0
  28. package/dist/cjs/server/rpc-stream.cjs +146 -0
  29. package/dist/cjs/server/rpc.cjs +34 -15
  30. package/dist/cjs/server/signal-query-observation.cjs +158 -0
  31. package/dist/cjs/server/streamed-region.cjs +52 -0
  32. package/dist/cjs/server/streamed-signals.cjs +512 -0
  33. package/dist/cjs/server-call.cjs +103 -0
  34. package/dist/cjs/server-rpc-batch-client.cjs +141 -0
  35. package/dist/cjs/server-rpc-client.cjs +94 -27
  36. package/dist/cjs/server-rpc-protocol.cjs +141 -0
  37. package/dist/cjs/server-rpc-stream-client.cjs +118 -0
  38. package/dist/cjs/signals/actions.cjs +474 -0
  39. package/dist/cjs/signals/client.cjs +4 -1
  40. package/dist/cjs/signals/computations.cjs +460 -0
  41. package/dist/cjs/signals/control-binding.cjs +368 -0
  42. package/dist/cjs/signals/derived-facade.cjs +50 -0
  43. package/dist/cjs/signals/document-owner.cjs +71 -0
  44. package/dist/cjs/signals/early-values.cjs +155 -0
  45. package/dist/cjs/signals/encoding.cjs +6 -95
  46. package/dist/cjs/signals/engine.cjs +276 -12
  47. package/dist/cjs/signals/errors.cjs +18 -0
  48. package/dist/cjs/signals/facade.cjs +477 -0
  49. package/dist/cjs/signals/graph.cjs +163 -20
  50. package/dist/cjs/signals/handle-protocol.cjs +36 -0
  51. package/dist/cjs/signals/index.cjs +81 -2
  52. package/dist/cjs/signals/native-read-client.cjs +10 -0
  53. package/dist/cjs/signals/owner-context.cjs +112 -0
  54. package/dist/cjs/signals/query-attempt-observer.cjs +68 -0
  55. package/dist/cjs/signals/query-facade.cjs +72 -0
  56. package/dist/cjs/signals/read-protocol.cjs +32 -0
  57. package/dist/cjs/signals/requests.cjs +287 -14
  58. package/dist/cjs/signals/scalar-computations.cjs +76 -0
  59. package/dist/cjs/signals/server.cjs +4 -1
  60. package/dist/cjs/signals/transition-candidate.cjs +567 -0
  61. package/dist/cjs/signals/transition-state.cjs +106 -0
  62. package/dist/cjs/signals/types.cjs +50 -0
  63. package/dist/cjs/stream-protocol.cjs +3 -0
  64. package/dist/cjs/streamed-signals-protocol.cjs +159 -0
  65. package/dist/cjs/style-values.cjs +122 -0
  66. package/dist/cjs/version.cjs +1 -1
  67. package/dist/class-names.d.ts +5 -0
  68. package/dist/class-names.js +25 -0
  69. package/dist/compiler/bundler.js +34 -6
  70. package/dist/compiler/compile.js +2234 -559
  71. package/dist/compiler/dom-binding-program.js +935 -0
  72. package/dist/compiler/dom-binding-request.js +57 -0
  73. package/dist/compiler/dom-bindings.js +2245 -0
  74. package/dist/compiler/hook-deps.js +26 -0
  75. package/dist/compiler/hydrate-boundaries.js +358 -15
  76. package/dist/compiler/index.d.ts +38 -1
  77. package/dist/compiler/index.js +1 -0
  78. package/dist/compiler/native-attribute-reads.js +127 -0
  79. package/dist/compiler/native-read-diagnostics.js +48 -9
  80. package/dist/compiler/native-read-types.js +55 -32
  81. package/dist/compiler/server-context.js +118 -0
  82. package/dist/compiler/signal-attempt-reads.js +479 -0
  83. package/dist/compiler/signal-declarations.js +557 -0
  84. package/dist/compiler/signal-start-reads.js +413 -0
  85. package/dist/compiler/slot-hooks.js +57 -10
  86. package/dist/compiler/template-ir.js +200 -0
  87. package/dist/compiler/typescript.d.ts +2 -0
  88. package/dist/compiler/typescript.js +2 -0
  89. package/dist/compiler/vite.d.ts +3 -1
  90. package/dist/compiler/vite.js +122 -4
  91. package/dist/compiler/volar.d.ts +6 -1
  92. package/dist/compiler/volar.js +674 -143
  93. package/dist/constants.d.ts +1 -0
  94. package/dist/constants.js +10 -0
  95. package/dist/css.d.ts +2 -5
  96. package/dist/css.js +2 -23
  97. package/dist/data-encoding.d.ts +9 -0
  98. package/dist/data-encoding.js +134 -0
  99. package/dist/dom-binding-classes.d.ts +15 -0
  100. package/dist/dom-binding-classes.js +129 -0
  101. package/dist/dom-binding-controls.d.ts +2 -0
  102. package/dist/dom-binding-controls.js +6 -0
  103. package/dist/dom-binding-handoff.d.ts +55 -0
  104. package/dist/dom-binding-handoff.js +62 -0
  105. package/dist/dom-binding-program.d.ts +300 -0
  106. package/dist/dom-binding-program.js +1625 -0
  107. package/dist/dom-binding-projections.d.ts +15 -0
  108. package/dist/dom-binding-projections.js +187 -0
  109. package/dist/dom-binding-protocol.d.ts +13 -0
  110. package/dist/dom-binding-protocol.js +88 -0
  111. package/dist/dom-binding-signals.d.ts +21 -0
  112. package/dist/dom-binding-signals.js +109 -0
  113. package/dist/dom-binding-styles.d.ts +17 -0
  114. package/dist/dom-binding-styles.js +272 -0
  115. package/dist/dom-bindings.d.ts +89 -0
  116. package/dist/dom-bindings.js +670 -0
  117. package/dist/dom-focused-move.d.ts +6 -0
  118. package/dist/dom-focused-move.js +42 -0
  119. package/dist/dom-tables.d.ts +1 -3
  120. package/dist/dom-tables.js +1 -91
  121. package/dist/error-codes.client.generated.d.ts +9 -0
  122. package/dist/error-codes.client.generated.js +33 -0
  123. package/dist/error-codes.server.generated.d.ts +5 -0
  124. package/dist/error-codes.server.generated.js +19 -0
  125. package/dist/hydration/control-capture.d.ts +62 -0
  126. package/dist/hydration/control-capture.js +223 -0
  127. package/dist/hydration/document-lifecycle.d.ts +23 -0
  128. package/dist/hydration/document-lifecycle.js +80 -0
  129. package/dist/hydration/event-capture.d.ts +20 -1
  130. package/dist/hydration/event-capture.js +128 -42
  131. package/dist/hydration/independent-island.d.ts +45 -0
  132. package/dist/hydration/independent-island.js +233 -0
  133. package/dist/hydration/index.d.ts +8 -1
  134. package/dist/hydration/index.js +55 -1
  135. package/dist/hydration/interaction-config.d.ts +5 -0
  136. package/dist/hydration/interaction-config.js +44 -1
  137. package/dist/hydration/stream-delivery.d.ts +32 -0
  138. package/dist/hydration/stream-delivery.js +333 -0
  139. package/dist/hydration/stream-receiver.d.ts +26 -0
  140. package/dist/hydration/stream-receiver.js +204 -0
  141. package/dist/hydration/stream-result-receiver.d.ts +70 -0
  142. package/dist/hydration/stream-result-receiver.js +246 -0
  143. package/dist/hydration/streamed-signals.d.ts +44 -0
  144. package/dist/hydration/streamed-signals.js +186 -0
  145. package/dist/hydration/types.d.ts +6 -0
  146. package/dist/hydration-markers.d.ts +7 -0
  147. package/dist/hydration-markers.js +10 -0
  148. package/dist/independent-hydration-protocol.d.ts +31 -0
  149. package/dist/independent-hydration-protocol.js +80 -0
  150. package/dist/index.d.ts +2 -0
  151. package/dist/index.js +4 -0
  152. package/dist/internal/signal-read.d.ts +1 -0
  153. package/dist/internal/signal-read.js +4 -0
  154. package/dist/jsx-runtime.d.ts +45 -6
  155. package/dist/public-types.d.ts +15 -1
  156. package/dist/runtime.d.ts +259 -21
  157. package/dist/runtime.js +2812 -220
  158. package/dist/runtime.server.d.ts +86 -6
  159. package/dist/runtime.server.js +712 -76
  160. package/dist/server/early-signals.d.ts +14 -0
  161. package/dist/server/early-signals.js +34 -0
  162. package/dist/server/index.d.ts +10 -2
  163. package/dist/server/index.js +48 -1
  164. package/dist/server/rpc-batch.d.ts +17 -0
  165. package/dist/server/rpc-batch.js +129 -0
  166. package/dist/server/rpc-stream.d.ts +9 -0
  167. package/dist/server/rpc-stream.js +125 -0
  168. package/dist/server/rpc.d.ts +5 -1
  169. package/dist/server/rpc.js +37 -13
  170. package/dist/server/signal-query-observation.d.ts +3 -0
  171. package/dist/server/signal-query-observation.js +134 -0
  172. package/dist/server/streamed-region.d.ts +15 -0
  173. package/dist/server/streamed-region.js +30 -0
  174. package/dist/server/streamed-signals.d.ts +45 -0
  175. package/dist/server/streamed-signals.js +488 -0
  176. package/dist/server-call.d.ts +41 -0
  177. package/dist/server-call.js +75 -0
  178. package/dist/server-rpc-batch-client.d.ts +7 -0
  179. package/dist/server-rpc-batch-client.js +119 -0
  180. package/dist/server-rpc-client.d.ts +3 -1
  181. package/dist/server-rpc-client.js +99 -27
  182. package/dist/server-rpc-protocol.d.ts +47 -0
  183. package/dist/server-rpc-protocol.js +109 -0
  184. package/dist/server-rpc-stream-client.d.ts +5 -0
  185. package/dist/server-rpc-stream-client.js +98 -0
  186. package/dist/signals/actions.d.ts +12 -0
  187. package/dist/signals/actions.js +466 -0
  188. package/dist/signals/client.d.ts +2 -0
  189. package/dist/signals/client.js +1 -0
  190. package/dist/signals/computations.d.ts +37 -0
  191. package/dist/signals/computations.js +455 -0
  192. package/dist/signals/control-binding.d.ts +31 -0
  193. package/dist/signals/control-binding.js +353 -0
  194. package/dist/signals/derived-facade.d.ts +3 -0
  195. package/dist/signals/derived-facade.js +25 -0
  196. package/dist/signals/document-owner.d.ts +10 -0
  197. package/dist/signals/document-owner.js +43 -0
  198. package/dist/signals/early-values.d.ts +24 -0
  199. package/dist/signals/early-values.js +124 -0
  200. package/dist/signals/encoding.d.ts +1 -3
  201. package/dist/signals/encoding.js +3 -93
  202. package/dist/signals/engine.d.ts +53 -4
  203. package/dist/signals/engine.js +275 -16
  204. package/dist/signals/errors.d.ts +7 -0
  205. package/dist/signals/errors.js +16 -0
  206. package/dist/signals/facade.d.ts +74 -0
  207. package/dist/signals/facade.js +452 -0
  208. package/dist/signals/graph.d.ts +50 -5
  209. package/dist/signals/graph.js +170 -19
  210. package/dist/signals/handle-protocol.d.ts +4 -0
  211. package/dist/signals/handle-protocol.js +11 -0
  212. package/dist/signals/index.d.ts +12 -3
  213. package/dist/signals/index.js +71 -2
  214. package/dist/signals/native-read-client.d.ts +3 -0
  215. package/dist/signals/native-read-client.js +10 -0
  216. package/dist/signals/owner-context.d.ts +22 -0
  217. package/dist/signals/owner-context.js +77 -0
  218. package/dist/signals/query-attempt-observer.d.ts +49 -0
  219. package/dist/signals/query-attempt-observer.js +41 -0
  220. package/dist/signals/query-facade.d.ts +3 -0
  221. package/dist/signals/query-facade.js +49 -0
  222. package/dist/signals/read-protocol.d.ts +32 -3
  223. package/dist/signals/read-protocol.js +26 -0
  224. package/dist/signals/requests.d.ts +38 -5
  225. package/dist/signals/requests.js +298 -15
  226. package/dist/signals/scalar-computations.d.ts +2 -0
  227. package/dist/signals/scalar-computations.js +60 -0
  228. package/dist/signals/server.d.ts +2 -0
  229. package/dist/signals/server.js +1 -0
  230. package/dist/signals/transition-candidate.d.ts +71 -0
  231. package/dist/signals/transition-candidate.js +557 -0
  232. package/dist/signals/transition-state.d.ts +51 -0
  233. package/dist/signals/transition-state.js +70 -0
  234. package/dist/signals/types.d.ts +95 -5
  235. package/dist/signals/types.js +20 -0
  236. package/dist/stream-protocol.d.ts +0 -5
  237. package/dist/stream-protocol.js +3 -0
  238. package/dist/streamed-signals-protocol.d.ts +60 -0
  239. package/dist/streamed-signals-protocol.js +130 -0
  240. package/dist/style-values.d.ts +3 -0
  241. package/dist/style-values.js +96 -0
  242. package/dist/version.js +1 -1
  243. package/package.json +37 -1
@@ -0,0 +1,200 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Template IR + origin recording (`inspect: true`). Static template HTML is
3
+ // runtime DATA, not JavaScript syntax: the browser-facing `template(html)` ABI
4
+ // intentionally stays a string. The compiler represents that data as a
5
+ // structured tree of elements and typed data chunks until allocTemplate
6
+ // serializes the completed template exactly once. Child templates compose by
7
+ // transferring nodes, so no intermediate HTML is joined and no origin offsets
8
+ // need to be shifted during construction. Origin spans remain local to their
9
+ // chunk; the one serializer shifts them into final logical-HTML coordinates.
10
+ //
11
+ // Origin collection stays gated on `ctx.inspect`. The normal compile path pays
12
+ // for the template chunks (the structural representation replacing string
13
+ // concatenation) but not for source-span arrays.
14
+ // ---------------------------------------------------------------------------
15
+
16
+ /**
17
+ * @typedef {{ start: number, end: number, srcStart: number, srcEnd: number,
18
+ * kind: 'tag-open' | 'tag-close' | 'attr-name' | 'attr-value' | 'text' }} TemplateOrigin
19
+ */
20
+
21
+ /**
22
+ * @typedef {'syntax' | 'tag-open' | 'tag-close' | 'attribute' | 'text' |
23
+ * 'anchor' | 'fragment-open' | 'fragment-close' | 'raw'} TemplatePartKind
24
+ */
25
+
26
+ /**
27
+ * @typedef {{
28
+ * type: 'TemplatePart',
29
+ * kind: TemplatePartKind,
30
+ * value: string,
31
+ * origins: TemplateOrigin[] | null,
32
+ * length: number,
33
+ * }} TemplatePart
34
+ */
35
+
36
+ /**
37
+ * @typedef {{
38
+ * type: 'TemplateElement',
39
+ * tag: string,
40
+ * namespace: string,
41
+ * synthetic: boolean,
42
+ * opening: TemplatePart,
43
+ * attributes: TemplatePart[],
44
+ * openingEnd: TemplatePart,
45
+ * children: TemplateNode[],
46
+ * closing: TemplatePart | null,
47
+ * length: number,
48
+ * }} TemplateElement
49
+ */
50
+
51
+ /** @typedef {TemplatePart | TemplateElement} TemplateNode */
52
+
53
+ /**
54
+ * @typedef {{
55
+ * type: 'Template',
56
+ * parts: TemplateNode[],
57
+ * length: number,
58
+ * }} TemplateIR
59
+ */
60
+
61
+ /** @returns {TemplateIR} */
62
+ export function createTemplateIr() {
63
+ return { type: 'Template', parts: [], length: 0 };
64
+ }
65
+
66
+ /**
67
+ * @param {string} value
68
+ * @param {TemplatePartKind} [kind]
69
+ * @param {TemplateOrigin[] | null} [origins]
70
+ * @returns {TemplatePart}
71
+ */
72
+ export function createTemplatePart(value, kind = 'raw', origins = null) {
73
+ return { type: 'TemplatePart', kind, value, origins, length: value.length };
74
+ }
75
+
76
+ /** @param {TemplateIR} template @param {TemplateNode} node */
77
+ export function appendTemplateNode(template, node) {
78
+ template.parts.push(node);
79
+ template.length += node.length;
80
+ }
81
+
82
+ /**
83
+ * @param {TemplateIR} template
84
+ * @param {string} value
85
+ * @param {TemplatePartKind} [kind]
86
+ * @param {TemplateOrigin[] | null} [origins]
87
+ */
88
+ export function appendTemplatePart(template, value, kind = 'raw', origins = null) {
89
+ if (value === '') return;
90
+ appendTemplateNode(template, createTemplatePart(value, kind, origins));
91
+ }
92
+
93
+ /** @param {TemplateIR} into @param {TemplateIR} child */
94
+ export function appendTemplateIr(into, child) {
95
+ if (child.length === 0) return;
96
+ for (const part of child.parts) into.parts.push(part);
97
+ into.length += child.length;
98
+ }
99
+
100
+ /**
101
+ * @param {string} value
102
+ * @param {TemplatePartKind} [kind]
103
+ * @param {TemplateOrigin[] | null} [origins]
104
+ * @returns {TemplateIR}
105
+ */
106
+ export function templatePart(value, kind = 'raw', origins = null) {
107
+ const template = createTemplateIr();
108
+ appendTemplatePart(template, value, kind, origins);
109
+ return template;
110
+ }
111
+
112
+ /**
113
+ * @param {string} tag
114
+ * @param {string} namespace
115
+ * @param {boolean} voidElement
116
+ * @param {TemplateIR} attributes
117
+ * @param {TemplateIR} children
118
+ * @param {TemplateOrigin[] | null} openOrigins
119
+ * @param {TemplateOrigin[] | null} closeOrigins
120
+ * @param {boolean} [synthetic]
121
+ * @returns {TemplateIR}
122
+ */
123
+ export function templateElement(
124
+ tag,
125
+ namespace,
126
+ voidElement,
127
+ attributes,
128
+ children,
129
+ openOrigins,
130
+ closeOrigins,
131
+ synthetic = false,
132
+ ) {
133
+ const opening = createTemplatePart(`<${tag}`, 'tag-open', openOrigins);
134
+ const openingEnd = createTemplatePart(voidElement ? '/>' : '>', 'syntax');
135
+ const closing = voidElement ? null : createTemplatePart(`</${tag}>`, 'tag-close', closeOrigins);
136
+ const node = {
137
+ type: 'TemplateElement',
138
+ tag,
139
+ namespace,
140
+ synthetic,
141
+ opening,
142
+ attributes: /** @type {TemplatePart[]} */ (attributes.parts),
143
+ openingEnd,
144
+ children: children.parts,
145
+ closing,
146
+ length:
147
+ opening.value.length +
148
+ attributes.length +
149
+ openingEnd.value.length +
150
+ children.length +
151
+ (closing === null ? 0 : closing.value.length),
152
+ };
153
+ const template = createTemplateIr();
154
+ appendTemplateNode(template, node);
155
+ return template;
156
+ }
157
+
158
+ /**
159
+ * Serialize the completed template once. The IR already contains the exact
160
+ * runtime bytes; this pass only joins them and converts chunk-local origins to
161
+ * final logical-HTML offsets.
162
+ *
163
+ * @param {TemplateIR} template
164
+ */
165
+ export function serializeTemplateIr(template) {
166
+ const values = [];
167
+ let origins = null;
168
+ let offset = 0;
169
+ const appendPart = (part) => {
170
+ values.push(part.value);
171
+ if (part.origins !== null) {
172
+ origins ??= [];
173
+ for (const origin of part.origins) {
174
+ origins.push({
175
+ start: origin.start + offset,
176
+ end: origin.end + offset,
177
+ srcStart: origin.srcStart,
178
+ srcEnd: origin.srcEnd,
179
+ kind: origin.kind,
180
+ });
181
+ }
182
+ }
183
+ offset += part.value.length;
184
+ };
185
+ const visit = (node) => {
186
+ if (node.type === 'TemplatePart') {
187
+ appendPart(node);
188
+ return;
189
+ }
190
+ appendPart(node.opening);
191
+ for (const attribute of node.attributes) appendPart(attribute);
192
+ appendPart(node.openingEnd);
193
+ for (const child of node.children) visit(child);
194
+ if (node.closing !== null) appendPart(node.closing);
195
+ };
196
+ for (const node of template.parts) {
197
+ visit(node);
198
+ }
199
+ return { html: values.join(''), origins };
200
+ }
@@ -23,6 +23,8 @@ export interface TextTypeProjectOptions {
23
23
  root?: string;
24
24
  /** The same renderer configuration used by the Octane compiler. */
25
25
  renderers?: unknown;
26
+ /** The same native attribute contracts used by runtime compilation. */
27
+ knownAttributeSpreads?: readonly import('./index.js').KnownAttributeSpread[];
26
28
  }
27
29
 
28
30
  export interface TextTypeProject {
@@ -421,6 +421,7 @@ export function createTextTypeProject(options) {
421
421
  try {
422
422
  compilation = compileToVolarMappings(source, rendererFilename(file, rendererRoot), {
423
423
  renderers,
424
+ knownAttributeSpreads: options.knownAttributeSpreads,
424
425
  });
425
426
  } catch {
426
427
  // Broken authored syntax is not evidence. Passing the authored text
@@ -495,6 +496,7 @@ export function createTextTypeProject(options) {
495
496
  options: program.getCompilerOptions(),
496
497
  references: loadConfig().projectReferences ?? [],
497
498
  renderers: renderers.signature,
499
+ knownAttributeSpreads: options.knownAttributeSpreads,
498
500
  rendererRoot,
499
501
  roots: roots(),
500
502
  inputs,
@@ -1,5 +1,5 @@
1
1
  import type { Plugin } from 'vite';
2
- import type { OctaneCssModuleConstants } from './index.js';
2
+ import type { KnownAttributeSpread, OctaneCssModuleConstants } from './index.js';
3
3
 
4
4
  export type { OctaneCssModuleConstants } from './index.js';
5
5
 
@@ -87,6 +87,8 @@ export interface OctaneVitePluginOptions {
87
87
  * @default false
88
88
  */
89
89
  strong?: boolean;
90
+ /** Trusted adapter output shapes; imported calls keep one evaluation per native host. */
91
+ knownAttributeSpreads?: readonly KnownAttributeSpread[];
90
92
  /**
91
93
  * @experimental Infer primitive child text from a TypeScript project in
92
94
  * one-shot production builds. Serve and watched builds retain syntax
@@ -19,6 +19,7 @@ import * as nodePath from 'node:path';
19
19
  import { parseModule } from '@tsrx/core';
20
20
  import {
21
21
  CLIENT_REFERENCE_MANIFEST_FILENAME,
22
+ INDEPENDENT_HYDRATION_MANIFEST_FILENAME,
22
23
  cleanModuleId,
23
24
  createClientReferenceManifest,
24
25
  createOctaneCompiler,
@@ -40,6 +41,7 @@ const PROFILE_DEFINE = '__OCTANE_PROFILE_ENABLED__';
40
41
  const VOID_EXPORTS_META = 'octane:void-component-exports';
41
42
  const DESCRIPTOR_CHILDREN_EXPORTS_META = 'octane:descriptor-children-exports';
42
43
  const CLIENT_REFERENCE_META = 'octane:client-reference';
44
+ const INDEPENDENT_WIDGETS_META = 'octane:independent-widgets';
43
45
  const DESCRIPTOR_PREFLIGHT_AUTHORITY = Symbol('octane.descriptor-preflight');
44
46
 
45
47
  function realRoot(path) {
@@ -68,6 +70,77 @@ function clientReferenceManifest(context, bundle) {
68
70
  return createClientReferenceManifest(entries);
69
71
  }
70
72
 
73
+ function independentWidgetManifest(context, bundle, clientBuildId) {
74
+ if (
75
+ clientBuildId !== undefined &&
76
+ (typeof clientBuildId !== 'string' || clientBuildId.length === 0)
77
+ ) {
78
+ throw new Error('Octane client build identity must be a non-empty string.');
79
+ }
80
+ const chunks = Object.values(bundle).filter((output) => output.type === 'chunk');
81
+ const chunksByFile = new Map(chunks.map((chunk) => [chunk.fileName, chunk]));
82
+ const collectStyles = (chunk, seen = new Set()) => {
83
+ if (seen.has(chunk.fileName)) return [];
84
+ seen.add(chunk.fileName);
85
+ const styles = [...(chunk.viteMetadata?.importedCss ?? [])];
86
+ for (const imported of [...(chunk.imports ?? []), ...(chunk.dynamicImports ?? [])]) {
87
+ const dependency = chunksByFile.get(imported);
88
+ if (dependency !== undefined) styles.push(...collectStyles(dependency, seen));
89
+ }
90
+ return styles;
91
+ };
92
+ const widgets = {};
93
+ for (const sourceChunk of chunks) {
94
+ for (const sourceModuleId of Object.keys(sourceChunk.modules ?? {})) {
95
+ const templates = context.getModuleInfo(sourceModuleId)?.meta?.[INDEPENDENT_WIDGETS_META];
96
+ if (!Array.isArray(templates)) continue;
97
+ for (const template of templates) {
98
+ const query = template.request.slice(template.request.indexOf('?'));
99
+ const entry = chunks.find((chunk) =>
100
+ Object.keys(chunk.modules ?? {}).some(
101
+ (moduleId) =>
102
+ cleanModuleId(moduleId) === cleanModuleId(sourceModuleId) && moduleId.includes(query),
103
+ ),
104
+ );
105
+ if (entry === undefined) {
106
+ throw new Error(
107
+ `Octane independent Hydrate ${JSON.stringify(template.boundaryId)} has no emitted activation chunk.`,
108
+ );
109
+ }
110
+ widgets[template.boundaryId] = {
111
+ version: 1,
112
+ boundaryId: template.boundaryId,
113
+ moduleId: entry.fileName,
114
+ exportName: template.exportName,
115
+ captureSchema: template.captureSchema,
116
+ hookSeed: template.hookSeed,
117
+ idSeed: template.idSeed,
118
+ signalSites: template.signalSites,
119
+ styles: [...new Set(collectStyles(entry))].sort(),
120
+ parentDependencies: false,
121
+ };
122
+ }
123
+ }
124
+ }
125
+ const records = Object.fromEntries(
126
+ Object.entries(widgets).sort(([left], [right]) => left.localeCompare(right)),
127
+ );
128
+ const buildId =
129
+ clientBuildId ??
130
+ nodeCrypto
131
+ .createHash('sha256')
132
+ .update(
133
+ JSON.stringify(
134
+ chunks
135
+ .map((chunk) => [chunk.fileName, chunk.code])
136
+ .sort(([a], [b]) => a.localeCompare(b)),
137
+ ),
138
+ )
139
+ .digest('base64url')
140
+ .slice(0, 16);
141
+ return { version: 1, buildId, widgets: records };
142
+ }
143
+
71
144
  function voidImportKey(request, imported) {
72
145
  return `${request}\0${imported}`;
73
146
  }
@@ -684,6 +757,7 @@ export function octane(options = {}) {
684
757
  exclude: options.exclude,
685
758
  profile: profileEnabled,
686
759
  strong: options.strong,
760
+ knownAttributeSpreads: options.knownAttributeSpreads,
687
761
  renderers: options.renderers,
688
762
  requireDirective,
689
763
  warn,
@@ -704,6 +778,7 @@ export function octane(options = {}) {
704
778
  exclude: options.exclude,
705
779
  profile: profileEnabled,
706
780
  strong: options.strong,
781
+ knownAttributeSpreads: options.knownAttributeSpreads,
707
782
  renderers: options.renderers,
708
783
  requireDirective,
709
784
  warn,
@@ -813,13 +888,43 @@ export function octane(options = {}) {
813
888
  },
814
889
  generateBundle(_outputOptions, bundle) {
815
890
  if (!emitClientReferenceManifest) return;
816
- const manifest = clientReferenceManifest(this, bundle);
817
- if (Object.keys(manifest.references).length === 0) return;
891
+ const clientReferences = clientReferenceManifest(this, bundle);
892
+ if (Object.keys(clientReferences.references).length > 0) {
893
+ this.emitFile({
894
+ type: 'asset',
895
+ fileName: CLIENT_REFERENCE_MANIFEST_FILENAME,
896
+ source: JSON.stringify(clientReferences, null, 2) + '\n',
897
+ });
898
+ }
899
+ const independentWidgets = independentWidgetManifest(
900
+ this,
901
+ bundle,
902
+ options.__clientBuildId?.(),
903
+ );
818
904
  this.emitFile({
819
905
  type: 'asset',
820
- fileName: CLIENT_REFERENCE_MANIFEST_FILENAME,
821
- source: JSON.stringify(manifest, null, 2) + '\n',
906
+ fileName: 'octane-client-build.json',
907
+ source:
908
+ JSON.stringify(
909
+ {
910
+ version: 1,
911
+ buildId: independentWidgets.buildId,
912
+ mode: 'production',
913
+ capabilities: {
914
+ independentHydration: Object.keys(independentWidgets.widgets).length > 0,
915
+ },
916
+ },
917
+ null,
918
+ 2,
919
+ ) + '\n',
822
920
  });
921
+ if (Object.keys(independentWidgets.widgets).length > 0) {
922
+ this.emitFile({
923
+ type: 'asset',
924
+ fileName: INDEPENDENT_HYDRATION_MANIFEST_FILENAME,
925
+ source: JSON.stringify(independentWidgets, null, 2) + '\n',
926
+ });
927
+ }
823
928
  },
824
929
  async resolveId(source, importer, resolveOptions) {
825
930
  if (!resolveOptions?.ssr) return null;
@@ -931,6 +1036,7 @@ export function octane(options = {}) {
931
1036
  }),
932
1037
  });
933
1038
  if (result === null) {
1039
+ options.__onIndependentWidgets?.(id, environment, [], false);
934
1040
  if (propagatedExports.length === 0) return null;
935
1041
  return {
936
1042
  code,
@@ -943,11 +1049,23 @@ export function octane(options = {}) {
943
1049
  };
944
1050
  }
945
1051
  cssImports?.consume(result.cssModuleConstantImports);
1052
+ options.__onIndependentWidgets?.(
1053
+ id,
1054
+ environment,
1055
+ Array.isArray(result.independentWidgets) ? result.independentWidgets : [],
1056
+ result.streamedSignals === true,
1057
+ );
946
1058
  for (const dependency of result.dependencies) this.addWatchFile?.(dependency);
947
1059
  const meta = {};
1060
+ if (result.bindingConstants !== undefined) {
1061
+ meta['octane:binding-constants'] = result.bindingConstants;
1062
+ }
948
1063
  if (result.clientReference !== undefined) {
949
1064
  meta[CLIENT_REFERENCE_META] = result.clientReference;
950
1065
  }
1066
+ if (Array.isArray(result.independentWidgets) && result.independentWidgets.length > 0) {
1067
+ meta[INDEPENDENT_WIDGETS_META] = result.independentWidgets;
1068
+ }
951
1069
  if (result.kind === 'compile' && Array.isArray(result.voidComponentExports)) {
952
1070
  meta[VOID_EXPORTS_META] = {
953
1071
  exports: result.voidComponentExports ?? [],
@@ -3,7 +3,12 @@
3
3
  export function compileToVolarMappings(
4
4
  source: string,
5
5
  filename?: string,
6
- options?: { loose?: boolean; renderers?: unknown; strong?: boolean },
6
+ options?: {
7
+ loose?: boolean;
8
+ renderers?: unknown;
9
+ strong?: boolean;
10
+ knownAttributeSpreads?: readonly import('./index.js').KnownAttributeSpread[];
11
+ },
7
12
  ): import('./index.js').VolarCompileResult;
8
13
 
9
14
  /** Virtual TSX and authored ranges used by compiler inspection tooling. */