ripple 0.4.2 → 0.4.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 (98) hide show
  1. package/CHANGELOG.md +164 -0
  2. package/package.json +10 -4
  3. package/src/constants.js +6 -0
  4. package/src/jsx-runtime.d.ts +2 -1
  5. package/src/runtime/array.js +15 -9
  6. package/src/runtime/index-client.js +25 -7
  7. package/src/runtime/index-server.js +1 -0
  8. package/src/runtime/internal/client/attributes.js +439 -0
  9. package/src/runtime/internal/client/blocks.js +20 -20
  10. package/src/runtime/internal/client/component.js +2 -5
  11. package/src/runtime/internal/client/composite.js +295 -95
  12. package/src/runtime/internal/client/constants.js +14 -6
  13. package/src/runtime/internal/client/context.js +3 -2
  14. package/src/runtime/internal/client/css.js +11 -26
  15. package/src/runtime/internal/client/errors.js +188 -0
  16. package/src/runtime/internal/client/events.js +79 -34
  17. package/src/runtime/internal/client/expression.js +25 -120
  18. package/src/runtime/internal/client/for.js +113 -262
  19. package/src/runtime/internal/client/head.js +4 -3
  20. package/src/runtime/internal/client/html.js +5 -3
  21. package/src/runtime/internal/client/hydrate.js +484 -0
  22. package/src/runtime/internal/client/hydration-enabled.js +7 -0
  23. package/src/runtime/internal/client/hydration.js +16 -81
  24. package/src/runtime/internal/client/if.js +69 -10
  25. package/src/runtime/internal/client/index.js +18 -10
  26. package/src/runtime/internal/client/operations.js +11 -7
  27. package/src/runtime/internal/client/portal.js +3 -2
  28. package/src/runtime/internal/client/render.js +42 -325
  29. package/src/runtime/internal/client/root-boundary-enabled.js +7 -0
  30. package/src/runtime/internal/client/runtime.js +157 -371
  31. package/src/runtime/internal/client/template-ns.js +88 -0
  32. package/src/runtime/internal/client/template.js +118 -139
  33. package/src/runtime/internal/client/track-async.js +356 -0
  34. package/src/runtime/internal/client/try.js +133 -319
  35. package/src/runtime/internal/client/types.d.ts +48 -24
  36. package/src/runtime/internal/server/index.js +31 -29
  37. package/src/runtime/internal/server/prerender.js +27 -0
  38. package/src/server/index.js +1 -0
  39. package/src/utils/class-name.js +28 -0
  40. package/tests/client/basic/basic.errors.test.tsrx +3 -3
  41. package/tests/client/compiler/__snapshots__/compiler.typescript.test.tsrx.snap +0 -2
  42. package/tests/client/compiler/compiler.basic.test.tsrx +2 -2
  43. package/tests/client/compiler/compiler.tracked-access.test.tsrx +3 -3
  44. package/tests/client/composite/composite.dynamic-components.test.tsrx +40 -0
  45. package/tests/client/composite/composite.props.test.tsrx +10 -10
  46. package/tests/client/css/scoped-styles.test.tsrx +3 -1
  47. package/tests/client/derived-release.test.tsrx +3 -3
  48. package/tests/client/for-item.test.tsrx +39 -0
  49. package/tests/client/for-selector.test.tsrx +95 -0
  50. package/tests/client/svg.test.tsrx +273 -1
  51. package/tests/hydration/compiled/client/basic.js +88 -87
  52. package/tests/hydration/compiled/client/composite.js +15 -6
  53. package/tests/hydration/compiled/client/events.js +40 -48
  54. package/tests/hydration/compiled/client/for.js +191 -199
  55. package/tests/hydration/compiled/client/fragment-cursor.js +633 -334
  56. package/tests/hydration/compiled/client/head.js +22 -22
  57. package/tests/hydration/compiled/client/hmr.js +14 -5
  58. package/tests/hydration/compiled/client/html-in-template.js +5 -5
  59. package/tests/hydration/compiled/client/html.js +195 -177
  60. package/tests/hydration/compiled/client/if-children.js +136 -63
  61. package/tests/hydration/compiled/client/if-fragment-controlflow.js +63 -43
  62. package/tests/hydration/compiled/client/if.js +78 -30
  63. package/tests/hydration/compiled/client/mixed-control-flow.js +90 -72
  64. package/tests/hydration/compiled/client/nested-control-flow.js +266 -307
  65. package/tests/hydration/compiled/client/portal.js +20 -11
  66. package/tests/hydration/compiled/client/reactivity.js +29 -29
  67. package/tests/hydration/compiled/client/return.js +2 -2
  68. package/tests/hydration/compiled/client/streaming.js +33 -35
  69. package/tests/hydration/compiled/client/switch.js +25 -25
  70. package/tests/hydration/compiled/client/track-async-serialization.js +41 -41
  71. package/tests/hydration/compiled/client/try.js +15 -15
  72. package/tests/hydration/compiled/client/typed-text.js +8 -7
  73. package/tests/hydration/compiled/server/basic.js +6 -6
  74. package/tests/hydration/compiled/server/events.js +8 -8
  75. package/tests/hydration/compiled/server/for.js +22 -22
  76. package/tests/hydration/compiled/server/fragment-cursor.js +188 -52
  77. package/tests/hydration/compiled/server/head.js +6 -6
  78. package/tests/hydration/compiled/server/hmr.js +1 -1
  79. package/tests/hydration/compiled/server/html.js +1 -1
  80. package/tests/hydration/compiled/server/if-children.js +9 -9
  81. package/tests/hydration/compiled/server/if.js +5 -5
  82. package/tests/hydration/compiled/server/mixed-control-flow.js +4 -4
  83. package/tests/hydration/compiled/server/portal.js +1 -1
  84. package/tests/hydration/compiled/server/reactivity.js +9 -9
  85. package/tests/hydration/compiled/server/streaming.js +9 -9
  86. package/tests/hydration/compiled/server/switch.js +4 -4
  87. package/tests/hydration/compiled/server/track-async-serialization.js +16 -16
  88. package/tests/hydration/compiled/server/try.js +4 -4
  89. package/tests/hydration/compiled/server/typed-text.js +1 -1
  90. package/tests/hydration/components/fragment-cursor.tsrx +60 -0
  91. package/tests/hydration/components/track-async-serialization.tsrx +2 -2
  92. package/tests/hydration/fragment-cursor.test.js +34 -1
  93. package/tests/hydration/track-async-serialization.test.js +1 -1
  94. package/tests/server/basic.components.test.tsrx +3 -3
  95. package/tests/server/track-async-serialization.test.tsrx +6 -6
  96. package/tests/utils/tracked-types.test.js +3 -3
  97. package/types/index.d.ts +8 -8
  98. package/types/server.d.ts +17 -0
@@ -9,6 +9,7 @@ import {
9
9
  set_hydrating,
10
10
  set_hydration,
11
11
  } from './hydration.js';
12
+ import { HYDRATION } from 'ripple/internal/client/hydration-enabled';
12
13
 
13
14
  /**
14
15
  * @param {string} hash
@@ -19,12 +20,12 @@ export function head(hash, render_fn) {
19
20
  // The head function may be called after the first hydration pass and ssr comment nodes may still be present,
20
21
  // therefore we need to skip that when we detect that we're not in hydration mode.
21
22
  let previous_hydrate_node = null;
22
- let was_hydrating = hydrating;
23
+ let was_hydrating = HYDRATION && hydrating;
23
24
 
24
25
  /** @type {Comment | Text} */
25
26
  var anchor;
26
27
 
27
- if (hydrating) {
28
+ if (HYDRATION && hydrating) {
28
29
  previous_hydrate_node = hydrate_node;
29
30
 
30
31
  var head_anchor = get_first_child(document.head);
@@ -50,7 +51,7 @@ export function head(hash, render_fn) {
50
51
  }
51
52
  }
52
53
 
53
- if (!hydrating) {
54
+ if (!(HYDRATION && hydrating)) {
54
55
  anchor = document.head.appendChild(create_text());
55
56
  }
56
57
 
@@ -1,10 +1,12 @@
1
1
  /** @import { Block } from '#client' */
2
+ import { hydration_mismatch } from './errors.js';
2
3
 
3
4
  import { remove_block_dom, render } from './blocks.js';
4
5
  import { get_first_child, get_next_sibling } from './operations.js';
5
6
  import { active_block } from './runtime.js';
6
7
  import { assign_nodes, create_fragment_from_html } from './template.js';
7
8
  import { hydrate_next, hydrating, set_hydrate_node } from './hydration.js';
9
+ import { HYDRATION } from 'ripple/internal/client/hydration-enabled';
8
10
  import { COMMENT_NODE } from '../../../constants.js';
9
11
 
10
12
  /**
@@ -25,7 +27,7 @@ export function html(node, get_html, svg = false, mathml = false) {
25
27
  // If the HTML hasn't changed, skip the update (but still hydrate on first run)
26
28
  if (html === new_html) {
27
29
  // During hydration, we need to skip past the content and end marker even if value hasn't changed
28
- if (hydrating) {
30
+ if (HYDRATION && hydrating) {
29
31
  // The anchor is the hash comment - we need to skip past it and its content
30
32
  set_hydrate_node(anchor);
31
33
  /** @type {Node | null} */
@@ -60,7 +62,7 @@ export function html(node, get_html, svg = false, mathml = false) {
60
62
  block.s.start = block.s.end = null;
61
63
  }
62
64
 
63
- if (hydrating) {
65
+ if (HYDRATION && hydrating) {
64
66
  set_hydrate_node(anchor);
65
67
 
66
68
  /** @type {Node | null} */
@@ -75,7 +77,7 @@ export function html(node, get_html, svg = false, mathml = false) {
75
77
  }
76
78
 
77
79
  if (next === null) {
78
- throw new Error('Hydration mismatch: expected end marker for HTML block');
80
+ hydration_mismatch('HTML');
79
81
  }
80
82
 
81
83
  // Include the hash comment and end marker in the assigned nodes
@@ -0,0 +1,484 @@
1
+ /** @import { AppendIntoAnchor, Block, TryPendingFunction, TryState } from '#client' */
2
+
3
+ import {
4
+ COMMENT_NODE,
5
+ HYDRATION_END,
6
+ HYDRATION_START,
7
+ HYDRATION_START_ERRORED,
8
+ HYDRATION_START_PENDING,
9
+ STREAM_ERROR_SCRIPT_PREFIX,
10
+ TEXT_NODE,
11
+ } from '../../../constants.js';
12
+ import { is_destroyed } from './blocks.js';
13
+ import { hydration_mismatch } from './errors.js';
14
+ import { clear_expression_range } from './expression.js';
15
+ import {
16
+ hydrate_next,
17
+ hydrate_node,
18
+ hydrating,
19
+ set_hydrate_node,
20
+ set_hydration,
21
+ set_hydration_runtime,
22
+ } from './hydration.js';
23
+ import { create_text, get_next_sibling, next_sibling_getter } from './operations.js';
24
+ import { active_block, queue_microtask } from './runtime.js';
25
+ import { assign_nodes } from './template.js';
26
+ import {
27
+ boundary_branch,
28
+ catch_error,
29
+ destroy_pending,
30
+ get_boundary_with_catch,
31
+ render_resolved,
32
+ } from './try.js';
33
+
34
+ /**
35
+ * The hydration paths of the DOM runtime. `hydrate()` installs them on the
36
+ * hydration module (see `H` there); the runtime's insert, template, expression
37
+ * and boundary code calls through that object only while hydrating, so a
38
+ * client-only mount compiles and ships none of this.
39
+ * @typedef {{
40
+ * a: typeof hydrate_append;
41
+ * t: typeof hydrate_template;
42
+ * x: typeof hydrate_text;
43
+ * e: typeof expression_end;
44
+ * h: typeof hydrated_text;
45
+ * m: typeof try_marker;
46
+ * s: typeof try_slot;
47
+ * f: typeof try_fallback;
48
+ * }} HydrationRuntime
49
+ */
50
+
51
+ /** @type {HydrationRuntime} */
52
+ var runtime = {
53
+ a: hydrate_append,
54
+ t: hydrate_template,
55
+ x: hydrate_text,
56
+ e: expression_end,
57
+ h: hydrated_text,
58
+ m: try_marker,
59
+ s: try_slot,
60
+ f: try_fallback,
61
+ };
62
+
63
+ export function install_hydration() {
64
+ set_hydration_runtime(runtime);
65
+ }
66
+
67
+ /**
68
+ * The hydration path of `append`: repositions the hydration cursor instead
69
+ * of inserting.
70
+ *
71
+ * Every hydrated node, block, and component leaves the cursor on its last
72
+ * DOM node, and whoever owns the next node steps past it: a parent element
73
+ * with its sibling traversal, a control-flow block by reaching its end
74
+ * marker, an append-into sentinel by adopting the cursor as the next
75
+ * component's first node.
76
+ * @param {ChildNode | AppendIntoAnchor} anchor
77
+ * @param {Node} dom
78
+ */
79
+ function hydrate_append(anchor, dom) {
80
+ var node = /** @type {Node} */ (hydrate_node);
81
+
82
+ // The cursor descended into dom's children (child()/sibling() traversal
83
+ // inside a single-node template) without a compiler-emitted pop(): bring it
84
+ // back up to dom before deciding where to leave it.
85
+ if (node !== dom && dom.contains(node)) {
86
+ node = dom;
87
+ }
88
+
89
+ // A child component renders into the anchor it was handed, which is its
90
+ // own first node. Its content is hydrated, so leave the cursor on the
91
+ // content's last node for the parent's sibling traversal.
92
+ if (anchor === dom) {
93
+ set_hydrate_node(node);
94
+ return;
95
+ }
96
+
97
+ if (node !== dom) {
98
+ // A fragment's cursor sits on its last top-level node, past the
99
+ // template's first node: widen the block's end to cover the whole
100
+ // fragment rather than only the node assign_nodes saw.
101
+ var s = /** @type {Block} */ (active_block).s;
102
+ if (s !== null) {
103
+ s.end = node;
104
+ }
105
+ }
106
+
107
+ // Step past the content: a branch lands on its block's end marker, the
108
+ // root on the boundary's end marker, an append-into sentinel on the next
109
+ // component's first node.
110
+ set_hydrate_node(next_sibling_getter.call(node), true);
111
+ }
112
+
113
+ /**
114
+ * Scans forward from the current hydrate_node to find the matching HYDRATION_END
115
+ * comment, handling nested blocks by tracking depth.
116
+ * Should be called after hydrate_next() has consumed the opening HYDRATION_START.
117
+ * Any `[`-prefixed comment opens a nested region — this includes the plain
118
+ * `<!--[-->` markers as well as streaming slot markers (`<!--[?N-->`,
119
+ * `<!--[!N-->`), which always pair with a `<!--]-->`.
120
+ * @returns {Node} The HYDRATION_END comment node.
121
+ */
122
+ function skip_to_hydration_end() {
123
+ var depth = 0;
124
+ var node = /** @type {Node} */ (hydrate_node);
125
+ while (true) {
126
+ if (node.nodeType === COMMENT_NODE) {
127
+ var data = /** @type {Comment} */ (node).data;
128
+ if (data === HYDRATION_END) {
129
+ if (depth === 0) return node;
130
+ depth -= 1;
131
+ } else if (data.startsWith(HYDRATION_START)) {
132
+ depth += 1;
133
+ }
134
+ }
135
+ node = /** @type {Node} */ (next_sibling_getter.call(node));
136
+ }
137
+ }
138
+
139
+ /**
140
+ * The hydration path of a `template()` instance: adopts the server node(s)
141
+ * at the cursor instead of cloning.
142
+ * @param {boolean} is_fragment
143
+ * @param {number} count
144
+ * @returns {Node}
145
+ */
146
+ function hydrate_template(is_fragment, count) {
147
+ var node = /** @type {Node} */ (hydrate_node);
148
+ assign_nodes(node, is_fragment ? hydrate_fragment_end(node, count) : node);
149
+ return node;
150
+ }
151
+
152
+ /**
153
+ * The last top-level node of a hydrated fragment template. Walks using the
154
+ * compiler-provided hop count so hydration never parses template HTML.
155
+ * @param {Node} start
156
+ * @param {number} count
157
+ * @returns {Node}
158
+ */
159
+ function hydrate_fragment_end(start, count) {
160
+ var end = start;
161
+
162
+ for (var i = 1; i < count; i++) {
163
+ var next = get_next_sibling(end);
164
+
165
+ while (next !== null && next.nodeType === COMMENT_NODE) {
166
+ next = get_next_sibling(next);
167
+ }
168
+
169
+ if (next === null) {
170
+ break;
171
+ }
172
+
173
+ end = next;
174
+ }
175
+
176
+ return end;
177
+ }
178
+
179
+ /**
180
+ * The hydration path of an expression's text: adopts the server text node at
181
+ * the cursor, splitting it when the server rendered adjacent text into one.
182
+ * @param {string} value
183
+ * @param {ChildNode} anchor
184
+ * @param {boolean} assign
185
+ * @returns {void}
186
+ */
187
+ function hydrate_text(value, anchor, assign) {
188
+ var node = hydrate_node;
189
+
190
+ if (node?.nodeType === COMMENT_NODE && /** @type {Comment} */ (node).data === HYDRATION_START) {
191
+ node = get_next_sibling(node);
192
+ }
193
+
194
+ if (node?.nodeType === TEXT_NODE) {
195
+ var current_value = /** @type {Text} */ (node).nodeValue ?? '';
196
+
197
+ if (current_value !== value) {
198
+ /** @type {Text} */ (node).nodeValue = value;
199
+
200
+ if (current_value.startsWith(value)) {
201
+ var remaining = current_value.slice(value.length);
202
+
203
+ if (remaining !== '') {
204
+ var remaining_text = create_text(remaining);
205
+ /** @type {ChildNode} */ (node).after(remaining_text);
206
+ if (assign) {
207
+ assign_nodes(node, node);
208
+ }
209
+ set_hydrate_node(remaining_text);
210
+ return;
211
+ }
212
+ }
213
+ }
214
+
215
+ if (assign) {
216
+ assign_nodes(node, node);
217
+ }
218
+ set_hydrate_node(get_next_sibling(node) ?? anchor);
219
+ return;
220
+ }
221
+
222
+ var new_text = create_text(value);
223
+
224
+ if (node !== null && node !== anchor) {
225
+ /** @type {ChildNode} */ (node).before(new_text);
226
+ } else {
227
+ anchor.before(new_text);
228
+ }
229
+
230
+ if (assign) {
231
+ assign_nodes(new_text, new_text);
232
+ }
233
+ set_hydrate_node(node ?? anchor);
234
+ }
235
+
236
+ /**
237
+ * The end marker of a server-rendered expression: the `<!--]-->` that pairs
238
+ * with the `<!--[-->` at `anchor`.
239
+ * @param {Node} anchor
240
+ * @returns {Comment}
241
+ */
242
+ function expression_end(anchor) {
243
+ /** @type {Node | null} */
244
+ var current = get_next_sibling(anchor);
245
+ var depth = 0;
246
+
247
+ while (current !== null) {
248
+ if (current.nodeType === COMMENT_NODE) {
249
+ var data = /** @type {Comment} */ (current).data;
250
+
251
+ if (data === HYDRATION_START) {
252
+ depth += 1;
253
+ } else if (data === HYDRATION_END) {
254
+ if (depth === 0) {
255
+ return /** @type {Comment} */ (current);
256
+ }
257
+
258
+ depth -= 1;
259
+ }
260
+ }
261
+
262
+ current = get_next_sibling(current);
263
+ }
264
+
265
+ hydration_mismatch('expression');
266
+ }
267
+
268
+ /**
269
+ * The single text node a server-rendered expression holds between its
270
+ * markers, or null once whatever else was there is cleared.
271
+ * @param {Node} anchor
272
+ * @param {Node} end
273
+ * @returns {Text | null}
274
+ */
275
+ function hydrated_text(anchor, end) {
276
+ var first = get_next_sibling(anchor);
277
+
278
+ if (first === end) {
279
+ return null;
280
+ }
281
+
282
+ if (first?.nodeType === TEXT_NODE && get_next_sibling(first) === end) {
283
+ return /** @type {Text} */ (first);
284
+ }
285
+
286
+ clear_expression_range(anchor, end);
287
+ return null;
288
+ }
289
+
290
+ /**
291
+ * A boundary's hydration walk begins: consumes its `<!--[-->` marker, or
292
+ * adopts the streamed slot that stands in for it (see `try_slot`).
293
+ * @param {TryState} state
294
+ */
295
+ function try_marker(state) {
296
+ var marker = /** @type {Comment} */ (hydrate_node);
297
+ var data = marker.nodeType === COMMENT_NODE ? marker.data : '';
298
+
299
+ // A slot at this anchor belongs to this boundary, including the root.
300
+ if (data.startsWith(HYDRATION_START_PENDING) || data.startsWith(HYDRATION_START_ERRORED)) {
301
+ hydrate_streamed_slot(state, marker, data);
302
+ } else {
303
+ // Settled SSR content must not transition back to pending.
304
+ if (state.p !== null) {
305
+ state.h = true;
306
+ }
307
+ hydrate_next(); // consume <!--[-->
308
+ }
309
+ }
310
+
311
+ /**
312
+ * @param {TryState} state
313
+ * @param {Comment} marker
314
+ * @param {string} data
315
+ */
316
+ function hydrate_streamed_slot(state, marker, data) {
317
+ // live streamed slot
318
+ state.si = data.slice(HYDRATION_START_PENDING.length);
319
+ state.se = data.startsWith(HYDRATION_START_ERRORED);
320
+ state.so = marker;
321
+ hydrate_next(); // consume the slot wrapper open
322
+ state.sc = /** @type {Comment} */ (skip_to_hydration_end());
323
+ var fallback_start = /** @type {Comment} */ (hydrate_node);
324
+ state.sf =
325
+ !state.se &&
326
+ state.p !== null &&
327
+ fallback_start.nodeType === COMMENT_NODE &&
328
+ fallback_start.data === HYDRATION_START;
329
+ if (state.sf) {
330
+ hydrate_next(); // consume the fallback's <!--[-->
331
+ }
332
+ }
333
+
334
+ /**
335
+ * A boundary that hydrated a still-pending streamed slot: the outer walk
336
+ * continues after the slot, and the slot's chunk activates the boundary when
337
+ * it arrives.
338
+ * @param {TryState} state
339
+ */
340
+ function try_slot(state) {
341
+ // continue the outer hydration walk after the slot
342
+ set_hydrate_node(state.sc);
343
+
344
+ var registry = (window.__RIPPLE_B__ ??= {});
345
+ var unit_id = /** @type {string} */ (state.si);
346
+ if (state.se) {
347
+ // the inline runtime already emptied the slot and marked it errored
348
+ // — route the error once the surrounding hydration has finished
349
+ queue_microtask(() => route_streamed_error(state, unit_id));
350
+ } else {
351
+ registry[unit_id] = {
352
+ a: (template, errored) => activate_streamed_chunk(state, template, errored),
353
+ };
354
+ }
355
+ }
356
+
357
+ /**
358
+ * The first run of a boundary whose chunk has not arrived: hydrates its
359
+ * fallback until activation.
360
+ * @param {TryState} state
361
+ */
362
+ function try_fallback(state) {
363
+ if (state.sf) {
364
+ state.m = 1;
365
+ state.pb = boundary_branch(() => {
366
+ /** @type {TryPendingFunction} */ (state.p)(state.a);
367
+ });
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Retires the slot wrapper markers once the slot's fate is decided: the
373
+ * open comment loses its marker data (it may still serve as the boundary
374
+ * anchor, so it must stay in the DOM) and the close comment is dropped —
375
+ * keeping `[`/`]` depth balanced for scans over surrounding slots.
376
+ * @param {TryState} state
377
+ * @returns {void}
378
+ */
379
+ function neutralize_slot_markers(state) {
380
+ /** @type {Comment} */ (state.so).data = '';
381
+ /** @type {ChildNode} */ (state.sc).remove();
382
+ }
383
+
384
+ /**
385
+ * Reads the streamed unit error envelope for this slot and routes the
386
+ * error into this boundary, or the nearest catch boundary above it.
387
+ * @param {TryState} state
388
+ * @param {string} id
389
+ * @returns {void}
390
+ */
391
+ function route_streamed_error(state, id) {
392
+ if (state.b === null || is_destroyed(state.b)) {
393
+ return;
394
+ }
395
+ neutralize_slot_markers(state);
396
+ var message = 'An error occurred during server rendering';
397
+ var script = document.getElementById(STREAM_ERROR_SCRIPT_PREFIX + id);
398
+ if (script !== null) {
399
+ try {
400
+ message = JSON.parse(/** @type {string} */ (script.textContent)).message ?? message;
401
+ } catch {
402
+ // keep the generic message
403
+ }
404
+ script.remove();
405
+ }
406
+ var error = new Error(message);
407
+ if (state.c !== null) {
408
+ catch_error(state, error);
409
+ return;
410
+ }
411
+ var outer = get_boundary_with_catch(/** @type {Block} */ (state.b));
412
+ if (outer === null) {
413
+ throw error;
414
+ }
415
+ catch_error(outer.s, error);
416
+ }
417
+
418
+ /**
419
+ * Empties the streamed slot: destroys the hydrated fallback branch and
420
+ * sweeps whatever remains between the wrapper comments (leftover marker
421
+ * comments included).
422
+ * @param {TryState} state
423
+ * @returns {void}
424
+ */
425
+ function clear_streamed_slot(state) {
426
+ destroy_pending(state);
427
+ var node = /** @type {ChildNode} */ (state.so).nextSibling;
428
+ while (node !== null && node !== state.sc) {
429
+ var next = node.nextSibling;
430
+ /** @type {ChildNode} */ (node).remove();
431
+ node = next;
432
+ }
433
+ }
434
+
435
+ /**
436
+ * Called by the inline stream runtime when this slot's chunk arrives after
437
+ * hydration: swaps the fallback for the streamed content and claims the
438
+ * new DOM through a boundary-scoped hydration walk (trackAsync inside the
439
+ * body picks its serialized envelope up from the same chunk).
440
+ * @param {TryState} state
441
+ * @param {HTMLTemplateElement | null} template
442
+ * @param {number | undefined} [errored]
443
+ * @returns {void}
444
+ */
445
+ function activate_streamed_chunk(state, template, errored) {
446
+ if (state.b === null || is_destroyed(state.b)) {
447
+ return;
448
+ }
449
+ var id = /** @type {string} */ (state.si);
450
+ state.si = null;
451
+ if (errored) {
452
+ clear_streamed_slot(state);
453
+ route_streamed_error(state, id);
454
+ return;
455
+ }
456
+ clear_streamed_slot(state);
457
+ if (template !== null) {
458
+ /** @type {ChildNode} */ (state.sc).before(template.content);
459
+ }
460
+ var first = /** @type {ChildNode} */ (state.so).nextSibling;
461
+ if (first === null || first === state.sc) {
462
+ neutralize_slot_markers(state);
463
+ return;
464
+ }
465
+ // adopt the streamed body's own <!--[--> as the boundary anchor (the
466
+ // node the buffered-SSR hydration path would have used) and drop the
467
+ // slot wrapper comments, so the resulting DOM matches buffered SSR
468
+ // exactly like the pre-hydration swap path does
469
+ if (state.a === state.so) {
470
+ state.a = first;
471
+ }
472
+ /** @type {ChildNode} */ (state.so).remove();
473
+ /** @type {ChildNode} */ (state.sc).remove();
474
+ var previous_hydrating = hydrating;
475
+ var previous_hydrate_node = hydrate_node;
476
+ set_hydration(true, first);
477
+ hydrate_next(); // consume the streamed body's <!--[-->
478
+ try {
479
+ state.h = true;
480
+ render_resolved(state);
481
+ } finally {
482
+ set_hydration(previous_hydrating, previous_hydrate_node);
483
+ }
484
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Whether this build can hydrate server-rendered HTML. The Vite plugin's
3
+ * `ssr: false` build aliases this module to one exporting `false`, and the
4
+ * bundler then drops every hydration path in the runtime along with the
5
+ * hydration cursor the compiled components no longer reference.
6
+ */
7
+ export const HYDRATION = true;
@@ -1,14 +1,7 @@
1
1
  /** @import { AppendIntoAnchor, Block, Derived, Tracked } from '#client' */
2
2
 
3
- import {
4
- COMMENT_NODE,
5
- HYDRATION_END,
6
- HYDRATION_ERROR,
7
- HYDRATION_START,
8
- TEXT_NODE,
9
- } from '../../../constants.js';
3
+ import { HYDRATION_ERROR, TEXT_NODE } from '../../../constants.js';
10
4
  import { create_text, first_child_getter, next_sibling_getter } from './operations.js';
11
- import { active_block } from './runtime.js';
12
5
 
13
6
  export let hydrating = false;
14
7
 
@@ -23,6 +16,21 @@ export let hydrate_node = null;
23
16
  */
24
17
  export const track_hash_reference = new Map();
25
18
 
19
+ /**
20
+ * The hydration paths of the DOM runtime (see `hydrate.js`), installed by
21
+ * `hydrate()`: the runtime reaches them through this object, so a client-only
22
+ * mount never loads them.
23
+ * @type {import('./hydrate.js').HydrationRuntime | null}
24
+ */
25
+ export let H = null;
26
+
27
+ /**
28
+ * @param {import('./hydrate.js').HydrationRuntime} runtime
29
+ */
30
+ export function set_hydration_runtime(runtime) {
31
+ H = runtime;
32
+ }
33
+
26
34
  /**
27
35
  * @param {boolean} value
28
36
  */
@@ -130,53 +138,6 @@ function repair_next_sibling(next_sibling) {
130
138
  return text;
131
139
  }
132
140
 
133
- /**
134
- * The hydration path of `append`: repositions the hydration cursor instead
135
- * of inserting. Kept out of the insert path so a client-only mount never
136
- * compiles it.
137
- *
138
- * Every hydrated node, block, and component leaves the cursor on its last
139
- * DOM node, and whoever owns the next node steps past it: a parent element
140
- * with its sibling traversal, a control-flow block by reaching its end
141
- * marker, an append-into sentinel by adopting the cursor as the next
142
- * component's first node.
143
- * @param {ChildNode | AppendIntoAnchor} anchor
144
- * @param {Node} dom
145
- */
146
- export function hydrate_append(anchor, dom) {
147
- var node = /** @type {Node} */ (hydrate_node);
148
-
149
- // The cursor descended into dom's children (child()/sibling() traversal
150
- // inside a single-node template) without a compiler-emitted pop(): bring it
151
- // back up to dom before deciding where to leave it.
152
- if (node !== dom && dom.contains(node)) {
153
- node = dom;
154
- }
155
-
156
- // A child component renders into the anchor it was handed, which is its
157
- // own first node. Its content is hydrated, so leave the cursor on the
158
- // content's last node for the parent's sibling traversal.
159
- if (anchor === dom) {
160
- hydrate_node = node;
161
- return;
162
- }
163
-
164
- if (node !== dom) {
165
- // A fragment's cursor sits on its last top-level node, past the
166
- // template's first node: widen the block's end to cover the whole
167
- // fragment rather than only the node assign_nodes saw.
168
- var s = /** @type {Block} */ (active_block).s;
169
- if (s !== null) {
170
- s.end = node;
171
- }
172
- }
173
-
174
- // Step past the content: a branch lands on its block's end marker, the
175
- // root on the boundary's end marker, an append-into sentinel on the next
176
- // component's first node.
177
- hydrate_node = next_sibling_getter.call(node);
178
- }
179
-
180
141
  export function next(n = 1) {
181
142
  if (hydrating) {
182
143
  var node = hydrate_node;
@@ -194,29 +155,3 @@ export function pop(node) {
194
155
  if (!hydrating) return;
195
156
  hydrate_node = node;
196
157
  }
197
-
198
- /**
199
- * Scans forward from the current hydrate_node to find the matching HYDRATION_END
200
- * comment, handling nested blocks by tracking depth.
201
- * Should be called after hydrate_next() has consumed the opening HYDRATION_START.
202
- * Any `[`-prefixed comment opens a nested region — this includes the plain
203
- * `<!--[-->` markers as well as streaming slot markers (`<!--[?N-->`,
204
- * `<!--[!N-->`), which always pair with a `<!--]-->`.
205
- * @returns {Node} The HYDRATION_END comment node.
206
- */
207
- export function skip_to_hydration_end() {
208
- var depth = 0;
209
- var node = /** @type {Node} */ (hydrate_node);
210
- while (true) {
211
- if (node.nodeType === COMMENT_NODE) {
212
- var data = /** @type {Comment} */ (node).data;
213
- if (data === HYDRATION_END) {
214
- if (depth === 0) return node;
215
- depth -= 1;
216
- } else if (data.startsWith(HYDRATION_START)) {
217
- depth += 1;
218
- }
219
- }
220
- node = /** @type {Node} */ (next_sibling_getter.call(node));
221
- }
222
- }