octane 0.3.1 → 0.3.2

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 (45) hide show
  1. package/dist/cjs/constants.cjs +18 -25
  2. package/dist/cjs/css.cjs +6 -0
  3. package/dist/cjs/dom-binding-protocol.cjs +37 -14
  4. package/dist/cjs/hydration/control-capture.cjs +12 -4
  5. package/dist/cjs/hydration/event-capture.cjs +6 -7
  6. package/dist/cjs/hydration-markers.cjs +40 -2
  7. package/dist/cjs/runtime-tags.cjs +55 -0
  8. package/dist/cjs/runtime.cjs +136 -113
  9. package/dist/cjs/runtime.server.cjs +34 -41
  10. package/dist/cjs/server/streamed-signals.cjs +7 -4
  11. package/dist/cjs/signals/control-binding.cjs +2 -1
  12. package/dist/cjs/stream-protocol.cjs +9 -8
  13. package/dist/cjs/version.cjs +1 -1
  14. package/dist/compiler/compile.js +70 -17
  15. package/dist/compiler/dom-bindings.js +5 -0
  16. package/dist/constants.d.ts +7 -18
  17. package/dist/constants.js +11 -9
  18. package/dist/css.d.ts +7 -0
  19. package/dist/css.js +4 -0
  20. package/dist/dom-binding-program.js +12 -5
  21. package/dist/dom-binding-protocol.d.ts +14 -1
  22. package/dist/dom-binding-protocol.js +40 -14
  23. package/dist/hydration/control-capture.d.ts +2 -0
  24. package/dist/hydration/control-capture.js +18 -5
  25. package/dist/hydration/event-capture.js +1 -2
  26. package/dist/hydration/independent-island.js +5 -5
  27. package/dist/hydration-markers.d.ts +30 -0
  28. package/dist/hydration-markers.js +27 -1
  29. package/dist/react/index.js +1 -1
  30. package/dist/react/react-compat-shared.js +5 -3
  31. package/dist/react/shared.d.ts +1 -3
  32. package/dist/react/shared.js +1 -1
  33. package/dist/runtime-tags.d.ts +34 -0
  34. package/dist/runtime-tags.js +22 -0
  35. package/dist/runtime.d.ts +5 -14
  36. package/dist/runtime.js +116 -71
  37. package/dist/runtime.server.d.ts +2 -3
  38. package/dist/runtime.server.js +25 -17
  39. package/dist/server/streamed-signals.js +7 -4
  40. package/dist/signals/control-binding.js +4 -2
  41. package/dist/stream-protocol.js +20 -9
  42. package/dist/universal-core.js +8 -4
  43. package/dist/universal-native.js +1 -1
  44. package/dist/version.js +1 -1
  45. package/package.json +3 -3
@@ -196,6 +196,8 @@ var import_trusted_html = require("./trusted-html.cjs");
196
196
  var import_read_protocol = require("./signals/read-protocol.cjs");
197
197
  var import_hook_slot_cache = require("./hook-slot-cache.cjs");
198
198
  var import_dom_binding_protocol = require("./dom-binding-protocol.cjs");
199
+ var import_hydration_markers = require("./hydration-markers.cjs");
200
+ var import_runtime_tags = require("./runtime-tags.cjs");
199
201
  var import_constants = require("./constants.cjs");
200
202
  var import_independent_hydration_protocol = require("./independent-hydration-protocol.cjs");
201
203
  var import_has_own = require("./has-own.cjs");
@@ -546,10 +548,8 @@ function ssrNestingText(value) {
546
548
  }
547
549
  const NOOP = () => {
548
550
  };
549
- const ELEMENT_TAG = /* @__PURE__ */ Symbol.for("octane.element");
550
- const PORTAL_TAG = /* @__PURE__ */ Symbol.for("octane.portal");
551
- const Fragment = /* @__PURE__ */ Symbol.for("octane.Fragment");
552
- const Activity = /* @__PURE__ */ Symbol.for("octane.Activity");
551
+ const Fragment = import_runtime_tags.FRAGMENT_TAG;
552
+ const Activity = import_runtime_tags.ACTIVITY_TAG;
553
553
  const SCOPED_ELEMENT_PROPS = /* @__PURE__ */ new WeakSet();
554
554
  const SCOPED_CHILDREN_RESOLVER = /* @__PURE__ */ Symbol("octane.scopedChildrenResolver");
555
555
  const SCOPED_VALUE_RESOLVER = /* @__PURE__ */ Symbol("octane.scopedValueResolver");
@@ -750,7 +750,7 @@ function nativeCreateScopedValue(readElement) {
750
750
  return scopedValueDescriptor(createNativeServerScopedResolver(readElement));
751
751
  }
752
752
  function scopedValueDescriptor(resolve) {
753
- const descriptor = { $$kind: ELEMENT_TAG };
753
+ const descriptor = { $$kind: import_runtime_tags.ELEMENT_TAG };
754
754
  Object.defineProperty(descriptor, SCOPED_VALUE_RESOLVER, { value: resolve });
755
755
  Object.defineProperty(descriptor, "type", SCOPED_VALUE_PROPERTIES.type);
756
756
  Object.defineProperty(descriptor, "props", SCOPED_VALUE_PROPERTIES.props);
@@ -800,7 +800,7 @@ function scopedElementDescriptor(type, copiedProps, key, children, invocationSit
800
800
  setScopedChildrenResolver(copiedProps, children);
801
801
  SCOPED_ELEMENT_PROPS.add(copiedProps);
802
802
  const descriptor = {
803
- $$kind: ELEMENT_TAG,
803
+ $$kind: import_runtime_tags.ELEMENT_TAG,
804
804
  type,
805
805
  props: copiedProps,
806
806
  key,
@@ -834,7 +834,7 @@ function createElementFromConfig(invocationSite, type, props, children) {
834
834
  (0, import_shared_value_helpers.applyElementDefaultProps)(type, p);
835
835
  kids = p.children;
836
836
  const descriptor = {
837
- $$kind: ELEMENT_TAG,
837
+ $$kind: import_runtime_tags.ELEMENT_TAG,
838
838
  type,
839
839
  props: p,
840
840
  key,
@@ -850,7 +850,7 @@ function positionalChildren(children) {
850
850
  return children;
851
851
  }
852
852
  function isElementDescriptor(v) {
853
- return v != null && v.$$kind === ELEMENT_TAG;
853
+ return v != null && v.$$kind === import_runtime_tags.ELEMENT_TAG;
854
854
  }
855
855
  function isFragmentDescriptor(value) {
856
856
  return isElementDescriptor(value) && value.type === Fragment;
@@ -862,7 +862,7 @@ function fragmentDescriptorChildren(value) {
862
862
  }
863
863
  function fragmentRefDescriptor(value) {
864
864
  return {
865
- $$kind: ELEMENT_TAG,
865
+ $$kind: import_runtime_tags.ELEMENT_TAG,
866
866
  type: renderFragmentRefDescriptor,
867
867
  props: value,
868
868
  key: value.key,
@@ -1052,7 +1052,7 @@ function cloneElement(element, config, ...children) {
1052
1052
  let descriptor;
1053
1053
  if (preserveScopedChildren) {
1054
1054
  descriptor = {
1055
- $$kind: ELEMENT_TAG,
1055
+ $$kind: import_runtime_tags.ELEMENT_TAG,
1056
1056
  type: element.type,
1057
1057
  props,
1058
1058
  key,
@@ -1066,7 +1066,7 @@ function cloneElement(element, config, ...children) {
1066
1066
  if (scopedResolver !== void 0) setScopedChildrenResolver(descriptor, scopedResolver);
1067
1067
  } else {
1068
1068
  descriptor = {
1069
- $$kind: ELEMENT_TAG,
1069
+ $$kind: import_runtime_tags.ELEMENT_TAG,
1070
1070
  type: element.type,
1071
1071
  props,
1072
1072
  key,
@@ -1085,7 +1085,7 @@ function cloneAndReplaceElementKey(element, key) {
1085
1085
  const get = Object.getOwnPropertyDescriptor(element, "children").get;
1086
1086
  const copiedGetter = get === SCOPED_VALUE_PROPERTIES.children.get ? () => get.call(element) : get;
1087
1087
  descriptor = {
1088
- $$kind: ELEMENT_TAG,
1088
+ $$kind: import_runtime_tags.ELEMENT_TAG,
1089
1089
  type: element.type,
1090
1090
  props: element.props,
1091
1091
  key,
@@ -1104,7 +1104,7 @@ function cloneAndReplaceElementKey(element, key) {
1104
1104
  }
1105
1105
  } else {
1106
1106
  descriptor = {
1107
- $$kind: ELEMENT_TAG,
1107
+ $$kind: import_runtime_tags.ELEMENT_TAG,
1108
1108
  type: element.type,
1109
1109
  props: element.props,
1110
1110
  key,
@@ -1167,7 +1167,7 @@ function mapIntoChildren(children, out, escapedPrefix, nameSoFar, callback) {
1167
1167
  children = null;
1168
1168
  type = "object";
1169
1169
  }
1170
- const isLeaf = children === null || type === "string" || type === "number" || type === "bigint" || isElementDescriptor(children) || children != null && children.$$kind === PORTAL_TAG;
1170
+ const isLeaf = children === null || type === "string" || type === "number" || type === "bigint" || isElementDescriptor(children) || children != null && children.$$kind === import_runtime_tags.PORTAL_TAG;
1171
1171
  if (isLeaf) {
1172
1172
  const child = children;
1173
1173
  let mapped = callback(child);
@@ -1266,7 +1266,7 @@ const Children = {
1266
1266
  };
1267
1267
  function createPortal(body, target, props = void 0) {
1268
1268
  const key = typeof props === "string" || typeof props === "number" ? String(props) : null;
1269
- return { $$kind: PORTAL_TAG, body, target, key, props: key === null ? props : void 0 };
1269
+ return { $$kind: import_runtime_tags.PORTAL_TAG, body, target, key, props: key === null ? props : void 0 };
1270
1270
  }
1271
1271
  const HTML_ESCAPE_RE = /[&<>]/;
1272
1272
  const SERVER_HTML = /* @__PURE__ */ Symbol.for("octane.serverHtml");
@@ -1301,7 +1301,7 @@ function ssrHtml(html) {
1301
1301
  const BINDING_HTML_ROOT = /* @__PURE__ */ Symbol.for("octane.binding.html");
1302
1302
  function ssrBindingHtml(html, id) {
1303
1303
  const output = new ServerHtml(html);
1304
- output[BINDING_HTML_ROOT] = "[b;" + id + ";root";
1304
+ output[BINDING_HTML_ROOT] = (0, import_dom_binding_protocol.bindingRootMarker)(id);
1305
1305
  return output;
1306
1306
  }
1307
1307
  function bindPresentationView(view, _id) {
@@ -1396,7 +1396,7 @@ function ssrChildValue(v, scope, includeKeyedSingle, selfMarkItem = false) {
1396
1396
  return v[SERVER_HTML];
1397
1397
  }
1398
1398
  if (v == null || v === false || v === true) return ssrBlock("");
1399
- if ((typeof v === "object" || typeof v === "function") && (v.$$kind === CONTEXT_TAG || typeof v.then === "function")) {
1399
+ if ((typeof v === "object" || typeof v === "function") && (v.$$kind === import_runtime_tags.CONTEXT_TAG || typeof v.then === "function")) {
1400
1400
  return ssrChildValue(
1401
1401
  use(v),
1402
1402
  scope,
@@ -1420,7 +1420,7 @@ function ssrChildValue(v, scope, includeKeyedSingle, selfMarkItem = false) {
1420
1420
  if (typeof v === "function")
1421
1421
  return ssrComponent(scope, v, {}, void 0, void 0, true);
1422
1422
  if (typeof v === "object") {
1423
- if (v.$$kind === ELEMENT_TAG) {
1423
+ if (v.$$kind === import_runtime_tags.ELEMENT_TAG) {
1424
1424
  const d = v;
1425
1425
  const render = () => {
1426
1426
  if (typeof d.type === "string") {
@@ -1435,7 +1435,7 @@ function ssrChildValue(v, scope, includeKeyedSingle, selfMarkItem = false) {
1435
1435
  const renderType = () => withAsyncIdentity("child-type", d.type, render);
1436
1436
  return d.key != null ? withAsyncIdentity("child-key", d.key, renderType, true) : renderType();
1437
1437
  }
1438
- if (v.$$kind === PORTAL_TAG) return ssrBlock(ssrPortal());
1438
+ if (v.$$kind === import_runtime_tags.PORTAL_TAG) return ssrBlock(ssrPortal());
1439
1439
  throw invalidChildError(v);
1440
1440
  }
1441
1441
  return ssrBlock(escapeHtml(v));
@@ -1576,14 +1576,14 @@ function ssrDeoptBlockChildren(children, scope) {
1576
1576
  }
1577
1577
  function serverDescNeedsBlocks(v) {
1578
1578
  if (v == null || typeof v !== "object") return false;
1579
- if (v.$$kind === CONTEXT_TAG || typeof v.then === "function") return true;
1579
+ if (v.$$kind === import_runtime_tags.CONTEXT_TAG || typeof v.then === "function") return true;
1580
1580
  if (Array.isArray(v)) {
1581
1581
  for (let i = 0; i < v.length; i++) if (serverDescNeedsBlocks(v[i])) return true;
1582
1582
  return false;
1583
1583
  }
1584
1584
  if (!isElementDescriptor(v) && (0, import_shared_value_helpers.childrenIterator)(v) !== null) return true;
1585
1585
  const d = v;
1586
- if (d.$$kind === ELEMENT_TAG) {
1586
+ if (d.$$kind === import_runtime_tags.ELEMENT_TAG) {
1587
1587
  if (d.type === Fragment || d.type === Activity) return true;
1588
1588
  return typeof d.type === "function" || serverDescNeedsBlocks(d.children);
1589
1589
  }
@@ -1607,7 +1607,7 @@ function serverHostHasPrimitiveChildren(children) {
1607
1607
  return children === null || typeof children !== "object" && typeof children !== "function";
1608
1608
  }
1609
1609
  function ssrDeoptItemContent(value, scope) {
1610
- if (value !== null && typeof value === "object" && value.$$kind === ELEMENT_TAG) {
1610
+ if (value !== null && typeof value === "object" && value.$$kind === import_runtime_tags.ELEMENT_TAG) {
1611
1611
  const descriptor = value;
1612
1612
  if (typeof descriptor.type === "string") {
1613
1613
  const type = descriptor.type;
@@ -1627,7 +1627,7 @@ function ssrDescriptorContent(v, scope) {
1627
1627
  for (let i = 0; i < v.length; i++) out += ssrDescriptorContent(v[i], scope);
1628
1628
  return out;
1629
1629
  }
1630
- if (typeof v === "object" && v.$$kind === ELEMENT_TAG) {
1630
+ if (typeof v === "object" && v.$$kind === import_runtime_tags.ELEMENT_TAG) {
1631
1631
  const d = v;
1632
1632
  if (typeof d.type === "string") return ssrHostElement(d.type, d.props, d.children, scope);
1633
1633
  return ssrComponentDescriptor(d, scope);
@@ -3328,7 +3328,7 @@ const Suspense = /* @__PURE__ */ (0, import_component_flags.markComponentFlags)(
3328
3328
  },
3329
3329
  import_component_flags.COMPONENT_FLAG_BOUNDARY,
3330
3330
  "Suspense",
3331
- /* @__PURE__ */ Symbol.for("octane.suspense")
3331
+ import_runtime_tags.SUSPENSE_TAG
3332
3332
  );
3333
3333
  let VT_SSR_TRY_SEQ = 0;
3334
3334
  let VT_SSR_HAS_CANDIDATES = false;
@@ -3511,11 +3511,7 @@ function vtSsrAnnotateScope(html) {
3511
3511
  true
3512
3512
  );
3513
3513
  const valid = roots === 1 && !sentinel && !text;
3514
- if (valid)
3515
- injectStyle(
3516
- "octane-view-transition-scope",
3517
- '[vt-scope="element"]{view-transition-scope:all!important}'
3518
- );
3514
+ if (valid) injectStyle(import_css.VIEW_TRANSITION_SCOPE_STYLE_ID, import_css.VIEW_TRANSITION_SCOPE_CSS);
3519
3515
  return vtSsrMapTags(
3520
3516
  html,
3521
3517
  (open) => vtSsrInject(open, [["vt-scope", valid ? "element" : "none"]]),
@@ -3707,12 +3703,11 @@ const ErrorBoundary = /* @__PURE__ */ (0, import_component_flags.markComponentFl
3707
3703
  import_component_flags.COMPONENT_FLAG_BOUNDARY,
3708
3704
  "ErrorBoundary"
3709
3705
  );
3710
- const CONTEXT_TAG = /* @__PURE__ */ Symbol.for("octane.context");
3711
3706
  function createContext(defaultValue) {
3712
3707
  const ctx = function ProviderBody(props, scope) {
3713
3708
  return ssrHtml(renderServerContextProvider(ctx, props, scope));
3714
3709
  };
3715
- ctx.$$kind = CONTEXT_TAG;
3710
+ ctx.$$kind = import_runtime_tags.CONTEXT_TAG;
3716
3711
  ctx.defaultValue = defaultValue;
3717
3712
  (0, import_context_identity.registerContext)(ctx);
3718
3713
  if (process.env.NODE_ENV !== "production") {
@@ -3747,7 +3742,7 @@ function readContext(ctx) {
3747
3742
  return ctx.defaultValue;
3748
3743
  }
3749
3744
  function useContext(ctx) {
3750
- if (ctx && ctx.$$kind === CONTEXT_TAG) return readContext(ctx);
3745
+ if (ctx && ctx.$$kind === import_runtime_tags.CONTEXT_TAG) return readContext(ctx);
3751
3746
  return readHostedForeignContext(ctx, "useContext");
3752
3747
  }
3753
3748
  const SSR_SUSPENSE = /* @__PURE__ */ Symbol("octane.ssr.suspense");
@@ -3939,7 +3934,7 @@ function use(usable, siteKey, directSite) {
3939
3934
  "Do not call use() inside a useMemo() factory. Cached factories can skip context or promise reads; call use() before useMemo() and memoize the returned value instead."
3940
3935
  );
3941
3936
  }
3942
- if (usable && usable.$$kind === CONTEXT_TAG) {
3937
+ if (usable && usable.$$kind === import_runtime_tags.CONTEXT_TAG) {
3943
3938
  recordSkippedHydrationSite(SERIAL, directSite);
3944
3939
  return readContext(usable);
3945
3940
  }
@@ -4306,18 +4301,17 @@ function warmChild(comp, props) {
4306
4301
  }
4307
4302
  }
4308
4303
  let LAZY_ID = 0;
4309
- const LAZY_COMPONENT = /* @__PURE__ */ Symbol.for("octane.lazy");
4310
4304
  function resolveLazyModule(mod) {
4311
4305
  let comp = mod;
4312
4306
  if (mod != null) {
4313
4307
  const defaultExport = mod.default;
4314
4308
  if (defaultExport !== void 0) comp = defaultExport;
4315
4309
  }
4316
- if (typeof comp !== "function" || comp[LAZY_COMPONENT] === true) {
4310
+ if (typeof comp !== "function" || comp[import_runtime_tags.LAZY_COMPONENT_TAG] === true) {
4317
4311
  throw new Error(
4318
4312
  (0, import_error_codes_server_generated.formatServerError)(
4319
4313
  10,
4320
- comp?.[LAZY_COMPONENT] === true ? "lazy component" : typeof comp
4314
+ comp?.[import_runtime_tags.LAZY_COMPONENT_TAG] === true ? "lazy component" : typeof comp
4321
4315
  )
4322
4316
  );
4323
4317
  }
@@ -4383,7 +4377,7 @@ function lazy(load) {
4383
4377
  }
4384
4378
  throw SSR_SUSPENSE;
4385
4379
  };
4386
- Object.defineProperty(lazyWrapper, LAZY_COMPONENT, {
4380
+ Object.defineProperty(lazyWrapper, import_runtime_tags.LAZY_COMPONENT_TAG, {
4387
4381
  get() {
4388
4382
  return this === lazyWrapper;
4389
4383
  }
@@ -4555,7 +4549,7 @@ function useDebugValue(_value, _format) {
4555
4549
  function requestFormReset(_form) {
4556
4550
  }
4557
4551
  function useId() {
4558
- return ":" + ID_PREFIX + "in-" + (ID_COUNTER++).toString(36) + ":";
4552
+ return (0, import_hydration_markers.formatUseId)(ID_PREFIX, ID_COUNTER++);
4559
4553
  }
4560
4554
  function throwOnServerEffectEventCall() {
4561
4555
  throw new Error((0, import_error_codes_server_generated.formatServerError)(11));
@@ -4691,10 +4685,9 @@ function startTransition(fn) {
4691
4685
  function flushSync(fn) {
4692
4686
  return fn();
4693
4687
  }
4694
- const CHILDREN_BLOCK = /* @__PURE__ */ Symbol.for("octane.childrenBlock");
4695
4688
  function markChildrenBlock(fn) {
4696
4689
  if (typeof fn === "function") {
4697
- fn[CHILDREN_BLOCK] = true;
4690
+ fn[import_runtime_tags.CHILDREN_BLOCK_TAG] = true;
4698
4691
  }
4699
4692
  return fn;
4700
4693
  }
@@ -4702,7 +4695,7 @@ function descriptorChildren(component) {
4702
4695
  return component;
4703
4696
  }
4704
4697
  function isChildrenBlock(value) {
4705
- return typeof value === "function" && value[CHILDREN_BLOCK] === true;
4698
+ return typeof value === "function" && value[import_runtime_tags.CHILDREN_BLOCK_TAG] === true;
4706
4699
  }
4707
4700
  function injectStyle(id, css, nonce) {
4708
4701
  if (CSS !== null) {
@@ -183,6 +183,9 @@ function createStreamedRendererFrameStream(frames, options = {}) {
183
183
  function escapeAttribute(value) {
184
184
  return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
185
185
  }
186
+ function byteLength(value) {
187
+ return typeof globalThis.Buffer === "function" ? globalThis.Buffer.byteLength(value, "utf8") : new TextEncoder().encode(value).byteLength;
188
+ }
186
189
  function streamedRendererFrameScript(frame, nonce) {
187
190
  const encoded = (0, import_streamed_signals_protocol.encodeStreamedRendererFrameForScript)(frame);
188
191
  return `<script ${import_stream_protocol.STREAM_SCRIPT_ATTR}${nonce === void 0 ? "" : ` nonce="${escapeAttribute(nonce)}"`}>globalThis.__octaneStreamedRenderer.receive(${encoded});</script>`;
@@ -201,7 +204,7 @@ function createSignalInjection(identity, result, options, timeoutMessage) {
201
204
  let queued = options.announceSelection ? streamedSignalSelectionScript(identity, options.nonce) : "";
202
205
  let pending = false;
203
206
  let awaitingAcceptance = false;
204
- let queuedBytes = queued === "" ? 0 : new TextEncoder().encode(queued).byteLength;
207
+ let queuedBytes = queued === "" ? 0 : byteLength(queued);
205
208
  let finished = false;
206
209
  let subscribed = false;
207
210
  let totalBytes = 0;
@@ -247,7 +250,7 @@ function createSignalInjection(identity, result, options, timeoutMessage) {
247
250
  return;
248
251
  }
249
252
  const html = streamedRendererFrameScript(next.value, options.nonce);
250
- const bytes = new TextEncoder().encode(html).byteLength;
253
+ const bytes = byteLength(html);
251
254
  if (bytes > budget.maxFrameBytes || totalBytes + bytes > budget.maxTotalBytes) {
252
255
  fail(new Error("Streamed renderer injection exceeded its byte budget."));
253
256
  return;
@@ -364,7 +367,7 @@ function createAutomaticStreamedSignalInjection(options, external) {
364
367
  for (const { identity, attempt } of selections ?? []) {
365
368
  if (attempt.signal.aborted) continue;
366
369
  const script = streamedSignalSelectionScript(identity, options.nonce);
367
- const bytes = new TextEncoder().encode(script).byteLength;
370
+ const bytes = byteLength(script);
368
371
  if (bytes > budget.maxFrameBytes || totalBytes + bytes > budget.maxTotalBytes) {
369
372
  const error = new Error("Automatic streamed signals exceeded their byte budget.");
370
373
  fail(error);
@@ -397,7 +400,7 @@ function createAutomaticStreamedSignalInjection(options, external) {
397
400
  if (child.done && (child.attempt !== void 0 || renderComplete)) cleanupChild(child);
398
401
  continue;
399
402
  }
400
- const bytes = child.attempt === void 0 ? new TextEncoder().encode(html).byteLength : child.source.queuedBytes;
403
+ const bytes = child.attempt === void 0 ? byteLength(html) : child.source.queuedBytes;
401
404
  if (bytes > budget.maxFrameBytes || totalBytes + bytes > budget.maxTotalBytes) {
402
405
  fail(new Error("Automatic streamed signals exceeded their byte budget."));
403
406
  return;
@@ -260,7 +260,8 @@ function __createBindingControls(owner = (0, import_owner_context.currentSignalO
260
260
  let snapshot;
261
261
  do {
262
262
  snapshot = (0, import_control_capture.snapshotHydrationControl)(control);
263
- if (snapshot.editRevision > 0 && (0, import_handle_protocol.isWritableSignal)(active)) write(nativeValue());
263
+ if ((0, import_handle_protocol.isWritableSignal)(active) && (snapshot.editRevision > 0 || channel === "value" && (0, import_control_capture.isRestoredHydrationTextarea)(control, read(active))))
264
+ write(nativeValue());
264
265
  if (disposed) return;
265
266
  } while (!(0, import_control_capture.consumeHydrationControl)(control, snapshot.revision));
266
267
  },
@@ -30,15 +30,16 @@ __export(stream_protocol_exports, {
30
30
  });
31
31
  module.exports = __toCommonJS(stream_protocol_exports);
32
32
  var import_dom_binding_protocol = require("./dom-binding-protocol.cjs");
33
+ var import_hydration_markers = require("./hydration-markers.cjs");
33
34
  const STREAM_BOUNDARY_ATTR = "data-oct-b";
34
35
  const SUSPENSE_SCRIPT_ATTR = "data-octane-suspense";
35
36
  const STREAM_SCRIPT_ATTR = "data-octane-stream";
36
37
  const HYDRATE_STREAM_TOKEN_ATTR = "data-octane-stream-token";
37
38
  function hydrationMarkerMultiplicity(data, open) {
38
- const marker = open ? "[" : "]";
39
+ const marker = open ? import_hydration_markers.HYDRATION_START : import_hydration_markers.HYDRATION_END;
39
40
  if (data === marker) return 1;
40
- if (open && (data === "[f0" || data === "[f1")) return 1;
41
- if (open && (data.startsWith("[b;") || data.startsWith("[f")) && (0, import_dom_binding_protocol.isBindingOpenComment)(data))
41
+ if (open && (data === import_hydration_markers.HYDRATION_FOR_EMPTY || data === import_hydration_markers.HYDRATION_FOR_ITEMS)) return 1;
42
+ if (open && (data.startsWith(import_dom_binding_protocol.BINDING_OPEN_PREFIX) || data.startsWith(import_hydration_markers.HYDRATION_FOR_PREFIX)) && (0, import_dom_binding_protocol.isBindingOpenComment)(data))
42
43
  return 1;
43
44
  if (data.length < 2 || data.charCodeAt(0) !== marker.charCodeAt(0)) return 0;
44
45
  const first = data.charCodeAt(1);
@@ -78,8 +79,8 @@ function getLeadingHydrationListRange(host) {
78
79
  let enclosingEnd = null;
79
80
  while (start !== null && start.nodeType === 8) {
80
81
  const data = start.data;
81
- const list = data === "[f0" || data === "[f1" || (data.startsWith("[f0;b;") || data.startsWith("[f1;b;")) && (0, import_dom_binding_protocol.isBindingOpenComment)(data);
82
- const wrapperMultiplicity = data === "[" ? 1 : data.charCodeAt(1) >= 49 && data.charCodeAt(1) <= 57 ? hydrationMarkerMultiplicity(data, true) : 0;
82
+ const list = data === import_hydration_markers.HYDRATION_FOR_EMPTY || data === import_hydration_markers.HYDRATION_FOR_ITEMS || (0, import_dom_binding_protocol.isForBindingOpenComment)(data);
83
+ const wrapperMultiplicity = data === import_hydration_markers.HYDRATION_START ? 1 : data.charCodeAt(1) >= 49 && data.charCodeAt(1) <= 57 ? hydrationMarkerMultiplicity(data, true) : 0;
83
84
  if (!list && wrapperMultiplicity === 0) return null;
84
85
  const end = rendererRangeClose(start);
85
86
  if (end === null || enclosingEnd !== null && (end.compareDocumentPosition(enclosingEnd) & 4) === 0)
@@ -87,12 +88,12 @@ function getLeadingHydrationListRange(host) {
87
88
  if (hydrationMarkerMultiplicity(end.data, false) !== (list ? 1 : wrapperMultiplicity))
88
89
  return null;
89
90
  if (list) {
90
- const suffix = data.slice(3);
91
+ const suffix = data.slice(import_hydration_markers.HYDRATION_FOR_EMPTY.length);
91
92
  return {
92
93
  start,
93
94
  end,
94
- emptyMarker: "[f0" + suffix,
95
- itemsMarker: "[f1" + suffix
95
+ emptyMarker: import_hydration_markers.HYDRATION_FOR_EMPTY + suffix,
96
+ itemsMarker: import_hydration_markers.HYDRATION_FOR_ITEMS + suffix
96
97
  };
97
98
  }
98
99
  enclosingEnd = end;
@@ -21,7 +21,7 @@ __export(version_exports, {
21
21
  version: () => version
22
22
  });
23
23
  module.exports = __toCommonJS(version_exports);
24
- const version = "0.3.1";
24
+ const version = "0.3.2";
25
25
  // Annotate the CommonJS export names for ESM import in node:
26
26
  0 && (module.exports = {
27
27
  version
@@ -1444,6 +1444,7 @@ const INTERNAL_CLIENT_RUNTIME_HELPERS = new Set([
1444
1444
  'bindSignalText',
1445
1445
  'bindSignalChild',
1446
1446
  'bindSignalAttribute',
1447
+ 'hydrateClaimedBindingCaches',
1447
1448
  'bindSignalValue',
1448
1449
  'bindSignalChecked',
1449
1450
  'bindSignalHostPropSources',
@@ -15590,6 +15591,8 @@ function preparePresentationHydration(body, node, ctx, hostEnd) {
15590
15591
  * bodies. `cssHash` selects the enclosing scoped-style expression fallback.
15591
15592
  */
15592
15593
  function compileFunctionBody(node, ctx, name, parentNs = 'html', cssHash = null, options = null) {
15594
+ const previousScalarBindingClaims = ctx.scalarBindingClaims;
15595
+ ctx.scalarBindingClaims = node._octaneScalarBindingClaims;
15593
15596
  const previousPresentationHydration = ctx.presentationHydration;
15594
15597
  ctx.presentationHydration = node._octanePresentationHydration;
15595
15598
  const returnedOutput = options?.returnedOutput === true;
@@ -16203,6 +16206,7 @@ function compileFunctionBody(node, ctx, name, parentNs = 'html', cssHash = null,
16203
16206
  ctx,
16204
16207
  presentationHostEnd,
16205
16208
  );
16209
+ ctx.scalarBindingClaims = previousScalarBindingClaims;
16206
16210
  ctx.presentationHydration = previousPresentationHydration;
16207
16211
  const emittedFunction = b.function_declaration(
16208
16212
  b.id(name, node.id ?? node),
@@ -23870,16 +23874,9 @@ const INTRINSIC_MUTATION_METHODS = new Set([
23870
23874
  ]);
23871
23875
 
23872
23876
  function mayWriteTextIntrinsicMember(target) {
23877
+ target = unwrapTsExpr(target);
23873
23878
  if (!target || typeof target !== 'object') return false;
23874
- if (
23875
- target.type === 'TSAsExpression' ||
23876
- target.type === 'TSTypeAssertion' ||
23877
- target.type === 'TSNonNullExpression' ||
23878
- target.type === 'ParenthesizedExpression' ||
23879
- target.type === 'AssignmentPattern'
23880
- ) {
23881
- return mayWriteTextIntrinsicMember(target.expression ?? target.left);
23882
- }
23879
+ if (target.type === 'AssignmentPattern') return mayWriteTextIntrinsicMember(target.left);
23883
23880
  if (target.type === 'MemberExpression') {
23884
23881
  return target.computed
23885
23882
  ? target.property?.type !== 'Literal' || TEXT_INTRINSICS.has(target.property.value)
@@ -23930,15 +23927,8 @@ function isPossibleIntrinsicMutator(node) {
23930
23927
  // proofs for the module. Calls still evaluate the authored callee: a replacement
23931
23928
  // may return an element rather than the built-in's primitive result.
23932
23929
  function writesGlobalTextIntrinsic(target, lexical) {
23930
+ target = unwrapTsExpr(target);
23933
23931
  if (!target || typeof target !== 'object') return false;
23934
- if (
23935
- target.type === 'TSAsExpression' ||
23936
- target.type === 'TSTypeAssertion' ||
23937
- target.type === 'TSNonNullExpression' ||
23938
- target.type === 'ParenthesizedExpression'
23939
- ) {
23940
- return writesGlobalTextIntrinsic(target.expression, lexical);
23941
- }
23942
23932
  const unbound = (node, name) => {
23943
23933
  const scope = lexical.nodeScopes.get(node);
23944
23934
  return scope !== undefined && !lexical.isBound(scope, name);
@@ -25504,6 +25494,69 @@ function planJsx(
25504
25494
  if (b.deferred) everyRenderLines.push(updateEmit);
25505
25495
  else updateLines.push(updateEmit);
25506
25496
  }
25497
+ if (ctx.scalarBindingClaims) {
25498
+ // Only opted-in scalar views can retain another writer's publication at
25499
+ // hydration. Record their existing cache fields; ordinary output is unchanged.
25500
+ const fields = [];
25501
+ for (const binding of elementBindings) {
25502
+ const key = binding.id;
25503
+ const text = binding.kind === 'textOnlyChild' || binding.kind === 'text';
25504
+ const host = text && !binding.signalDirect ? `_txt$${key}` : `_el$${key}`;
25505
+ if (text && binding.signalDirect)
25506
+ fields.push(bag.letter(`_sig$${key}`), bag.letter(host), '#text-token');
25507
+ if (binding.kind === 'nativeStyle') {
25508
+ fields.push(binding.slotIndex, bag.letter(host), 'style');
25509
+ } else if (binding.kind === 'styleProperties') {
25510
+ for (let i = 0; i < binding.properties.length; i++)
25511
+ fields.push(
25512
+ bag.letter(`_prev$${key}_${i}`),
25513
+ bag.letter(host),
25514
+ `style:${binding.properties[i].name}`,
25515
+ );
25516
+ } else if (binding.kind === 'style') {
25517
+ fields.push(bag.letter(`_sty$${key}`), bag.letter(host), 'style');
25518
+ } else if (
25519
+ text ||
25520
+ ['attr', 'stringData', 'booleanAttr', 'ariaAttr', 'class', 'styleProperty'].includes(
25521
+ binding.kind,
25522
+ )
25523
+ ) {
25524
+ const cache = binding.signalDirect && !text ? `_sig$${key}` : `_prev$${key}`;
25525
+ fields.push(
25526
+ bag.letter(cache),
25527
+ bag.letter(host),
25528
+ text
25529
+ ? '#text'
25530
+ : binding.kind === 'styleProperty'
25531
+ ? `style:${binding.name}`
25532
+ : binding.kind === 'class'
25533
+ ? 'class'
25534
+ : ATTRIBUTE_ALIASES.get(binding.name) || binding.name,
25535
+ );
25536
+ }
25537
+ }
25538
+ if (fields.length) {
25539
+ const name = `_claims$${ctx.nextHelperId++}`;
25540
+ ctx.hoistedHelpers.push(
25541
+ inheritOriginLoc(
25542
+ b.const(name, b.array(fields.map((value) => b.literal(value)))),
25543
+ planOrigin,
25544
+ ),
25545
+ );
25546
+ everyRenderLines.push(
25547
+ inheritOriginLoc(
25548
+ b.stmt(
25549
+ b.call(
25550
+ requireRuntimeForContext(ctx, 'hydrateClaimedBindingCaches'),
25551
+ b.id('__s'),
25552
+ b.id(name),
25553
+ ),
25554
+ ),
25555
+ planOrigin,
25556
+ ),
25557
+ );
25558
+ }
25559
+ }
25507
25560
  if (keyedSelection !== null && single && !noTemplate) {
25508
25561
  // Reuse the ordinary root-class write and its exact bag fields. Updating
25509
25562
  // only the DOM would leave the normal row diff's previous value stale.
@@ -2300,6 +2300,11 @@ export function prepareDomBindings(ast, source, filename, selectedExport, helper
2300
2300
  );
2301
2301
  }
2302
2302
  for (const [node, replacement] of rewritten) replacements.set(node, replacement);
2303
+ if (!plan.hostHandoff)
2304
+ replacements.set(node, {
2305
+ ...mapCow(node, rewritten),
2306
+ _octaneScalarBindingClaims: true,
2307
+ });
2303
2308
  if (plan.hostHandoff)
2304
2309
  replacements.set(node, {
2305
2310
  ...mapCow(node, rewritten),
@@ -10,16 +10,13 @@
10
10
  *
11
11
  * The server emit (runtime.server `ssrBlock` and friends) writes these markers
12
12
  * around every dynamic site, and the client `hydrateRoot` cursor scans for them
13
- * to align with the server output. This module is the shared home both import.
13
+ * to align with the server output. This module is the public home both import;
14
+ * the marker payloads and boundary attribute names themselves are declared in
15
+ * `hydration-markers.js`, which stays off the `dom-tables.js` graph so the
16
+ * pre-root capture bundle can share them, and are re-exported here unchanged.
14
17
  */
15
- /** Single-character payload of a block-open comment. */
16
- export declare const HYDRATION_START = "[";
17
- /** Single-character payload of a block-close comment. */
18
- export declare const HYDRATION_END = "]";
19
- /** @for outer-open payload: the server rendered its @empty arm. */
20
- export declare const HYDRATION_FOR_EMPTY = "[f0";
21
- /** @for outer-open payload: the server rendered one or more direct-host items. */
22
- export declare const HYDRATION_FOR_ITEMS = "[f1";
18
+ import { HYDRATION_START, HYDRATION_END, HYDRATION_FOR_EMPTY, HYDRATION_FOR_ITEMS } from './hydration-markers.js';
19
+ export { HYDRATION_START, HYDRATION_END, HYDRATION_FOR_EMPTY, HYDRATION_FOR_ITEMS };
23
20
  /** Opens a hydratable block (component output / control-flow branch). */
24
21
  export declare const BLOCK_OPEN = "<!--[-->";
25
22
  /** Closes a hydratable block. */
@@ -87,17 +84,9 @@ export declare const HYDRATION_RANGE_BOUNDARY: unique symbol;
87
84
  export declare const HYDRATE_STATIC_ID_COUNT_PREFIX = "octane-static-hydrate:";
88
85
  /** Closing comment for a wrapper-free permanent-static range. */
89
86
  export declare const HYDRATE_STATIC_END = "/octane-static-hydrate";
90
- /** Stable id of a server-rendered deferred hydration boundary. */
91
- export declare const HYDRATE_ID_ATTR = "data-octane-hydrate-id";
92
- /** Serialized strategy kind (`visible`, `idle`, `dynamic`, …). */
93
- export declare const HYDRATE_WHEN_ATTR = "data-octane-hydrate-when";
94
- /** Number of `useId()` slots consumed while rendering the deferred child. */
95
- export declare const HYDRATE_ID_COUNT_ATTR = "data-octane-hydrate-id-count";
96
87
  /** Opaque renderer stream token authenticating pending descendants owned by this boundary. */
97
88
  export { HYDRATE_STREAM_TOKEN_ATTR } from './stream-protocol.js';
98
- /** Direct-child JSON script carrying this boundary's `use()` seed slice. */
99
- export declare const HYDRATE_SEED_ATTR = "data-octane-hydrate-seed";
100
- export { INDEPENDENT_HYDRATE_MANIFEST_ATTR, HYDRATE_INDEPENDENT_ATTR, HYDRATE_INPUT_ATTR, SIGNAL_CONTROL_ATTR, } from './hydration-markers.js';
89
+ export { INDEPENDENT_HYDRATE_MANIFEST_ATTR, HYDRATE_INDEPENDENT_ATTR, HYDRATE_INPUT_ATTR, SIGNAL_CONTROL_ATTR, HYDRATE_ID_ATTR, HYDRATE_WHEN_ATTR, HYDRATE_ID_COUNT_ATTR, HYDRATE_SEED_ATTR, } from './hydration-markers.js';
101
90
  /** Sentinel <template> attribute marking a pending streamed boundary. */
102
91
  export { STREAM_BOUNDARY_ATTR } from './stream-protocol.js';
103
92
  /** Hidden segment container attribute carrying a completed boundary's content. */
package/dist/constants.js CHANGED
@@ -1,7 +1,9 @@
1
- const HYDRATION_START = "[";
2
- const HYDRATION_END = "]";
3
- const HYDRATION_FOR_EMPTY = "[f0";
4
- const HYDRATION_FOR_ITEMS = "[f1";
1
+ import {
2
+ HYDRATION_START,
3
+ HYDRATION_END,
4
+ HYDRATION_FOR_EMPTY,
5
+ HYDRATION_FOR_ITEMS
6
+ } from "./hydration-markers.js";
5
7
  const BLOCK_OPEN = `<!--${HYDRATION_START}-->`;
6
8
  const BLOCK_CLOSE = `<!--${HYDRATION_END}-->`;
7
9
  const FOR_BLOCK_OPEN_EMPTY = `<!--${HYDRATION_FOR_EMPTY}-->`;
@@ -23,16 +25,16 @@ const HYDRATION_RANGE_BOUNDARY = /* @__PURE__ */ Symbol.for(
23
25
  );
24
26
  const HYDRATE_STATIC_ID_COUNT_PREFIX = "octane-static-hydrate:";
25
27
  const HYDRATE_STATIC_END = "/octane-static-hydrate";
26
- const HYDRATE_ID_ATTR = "data-octane-hydrate-id";
27
- const HYDRATE_WHEN_ATTR = "data-octane-hydrate-when";
28
- const HYDRATE_ID_COUNT_ATTR = "data-octane-hydrate-id-count";
29
28
  import { HYDRATE_STREAM_TOKEN_ATTR } from "./stream-protocol.js";
30
- const HYDRATE_SEED_ATTR = "data-octane-hydrate-seed";
31
29
  import {
32
30
  INDEPENDENT_HYDRATE_MANIFEST_ATTR,
33
31
  HYDRATE_INDEPENDENT_ATTR,
34
32
  HYDRATE_INPUT_ATTR,
35
- SIGNAL_CONTROL_ATTR
33
+ SIGNAL_CONTROL_ATTR,
34
+ HYDRATE_ID_ATTR,
35
+ HYDRATE_WHEN_ATTR,
36
+ HYDRATE_ID_COUNT_ATTR,
37
+ HYDRATE_SEED_ATTR
36
38
  } from "./hydration-markers.js";
37
39
  import { STREAM_BOUNDARY_ATTR } from "./stream-protocol.js";
38
40
  const STREAM_SEGMENT_ATTR = "data-oct-s";
package/dist/css.d.ts CHANGED
@@ -12,3 +12,10 @@ export declare function styleName(name: string): string;
12
12
  export declare function devWarnStyleProperty(name: string, value: unknown, server: boolean): void;
13
13
  /** @internal Development-only guidance after an existing CSS coercion fails. */
14
14
  export declare function devWarnStyleCoercion(name: string, value: unknown): void;
15
+ /**
16
+ * The one stylesheet element-scoped `<ViewTransition>` needs. The client
17
+ * dedupes the injection by this id and the SSR serializer emits the same pair,
18
+ * so spelling either half twice ships the rule twice or drops it on one side.
19
+ */
20
+ export declare const VIEW_TRANSITION_SCOPE_STYLE_ID = "octane-view-transition-scope";
21
+ export declare const VIEW_TRANSITION_SCOPE_CSS = "[vt-scope=\"element\"]{view-transition-scope:all!important}";
package/dist/css.js CHANGED
@@ -67,7 +67,11 @@ function devWarnStyleCoercion(name, value) {
67
67
  `The provided \`${name}\` CSS property is an unsupported type ${valueType}. This value must be coerced to a string before using it here.`
68
68
  );
69
69
  }
70
+ const VIEW_TRANSITION_SCOPE_STYLE_ID = "octane-view-transition-scope";
71
+ const VIEW_TRANSITION_SCOPE_CSS = '[vt-scope="element"]{view-transition-scope:all!important}';
70
72
  export {
73
+ VIEW_TRANSITION_SCOPE_CSS,
74
+ VIEW_TRANSITION_SCOPE_STYLE_ID,
71
75
  devWarnStyleCoercion,
72
76
  devWarnStyleProperty,
73
77
  mergeClass,