octane 0.2.2 → 0.2.3

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 (50) hide show
  1. package/dist/cjs/compatibility.cjs +35 -0
  2. package/dist/cjs/component-flags.cjs +8 -1
  3. package/dist/cjs/dom-tables.cjs +2 -0
  4. package/dist/cjs/error-codes.client.generated.cjs +15 -2
  5. package/dist/cjs/error-codes.server.generated.cjs +5 -0
  6. package/dist/cjs/event-names.cjs +39 -0
  7. package/dist/cjs/index.cjs +13 -0
  8. package/dist/cjs/runtime.cjs +1223 -332
  9. package/dist/cjs/runtime.server.cjs +362 -120
  10. package/dist/cjs/server/index.cjs +22 -0
  11. package/dist/cjs/version.cjs +1 -1
  12. package/dist/compatibility.d.ts +7 -0
  13. package/dist/compatibility.js +10 -0
  14. package/dist/compiler/bundler.js +13 -30
  15. package/dist/compiler/compile-renderer-boundaries.js +1 -0
  16. package/dist/compiler/compile-universal.js +3 -0
  17. package/dist/compiler/compile.js +619 -99
  18. package/dist/compiler/hook-deps.js +100 -3
  19. package/dist/compiler/hook-names.js +1 -0
  20. package/dist/compiler/manual-hooks.js +171 -0
  21. package/dist/compiler/plain-hook-memo.js +54 -5
  22. package/dist/compiler/slot-hooks.d.ts +43 -0
  23. package/dist/compiler/slot-hooks.js +154 -35
  24. package/dist/component-flags.d.ts +1 -1
  25. package/dist/component-flags.js +8 -1
  26. package/dist/dom-tables.js +2 -0
  27. package/dist/error-codes.client.generated.d.ts +3 -1
  28. package/dist/error-codes.client.generated.js +15 -2
  29. package/dist/error-codes.server.generated.d.ts +1 -0
  30. package/dist/error-codes.server.generated.js +5 -0
  31. package/dist/event-names.d.ts +1 -0
  32. package/dist/event-names.js +15 -0
  33. package/dist/html-tree-validation.d.ts +17 -34
  34. package/dist/index.d.ts +3 -1
  35. package/dist/index.js +12 -1
  36. package/dist/jsx-runtime.d.ts +6 -1
  37. package/dist/public-types.d.ts +188 -0
  38. package/dist/public-types.js +0 -0
  39. package/dist/runtime.d.ts +109 -66
  40. package/dist/runtime.js +1220 -332
  41. package/dist/runtime.server.d.ts +39 -14
  42. package/dist/runtime.server.js +356 -120
  43. package/dist/server/index.d.ts +4 -2
  44. package/dist/server/index.js +19 -0
  45. package/dist/static/index.d.ts +2 -1
  46. package/dist/static/index.js +3 -1
  47. package/dist/universal-core.d.ts +8 -1
  48. package/dist/universal-core.js +95 -9
  49. package/dist/version.js +1 -1
  50. package/package.json +2 -1
@@ -5,15 +5,16 @@
5
5
  // byte-for-byte. Production bundlers may additionally select the separate
6
6
  // whole-AST memo path, which preserves TypeScript and supplies a source map.
7
7
  //
8
- // This pass parses the module (for byte offsets), finds ONLY octane BASE hook
9
- // calls, and splices a trailing compiler slot into each — every other byte (all the
10
- // TS the printer can't handle) passes through verbatim. It does NOT wrap custom
11
- // hooks in `withSlot` (that's done by the `.tsrx`/`.tsx` CALLER, and wrapping a
12
- // hand-written binding that already forwards a slot would double-slot it). In
8
+ // This pass parses the module (for byte offsets), slots Octane base hooks and
9
+ // gives imported custom hooks their own withSlot boundary. Imported aliases can
10
+ // point directly at a base hook, so the enclosing component's boundary alone
11
+ // cannot distinguish their call sites. Local helpers retain their authored slot
12
+ // policy; explicitly manual modules opt out of all injected slots. In
13
13
  // production it reserves a collision-free runtime range because these arbitrary
14
14
  // helpers can execute in a Scope alongside code from any other source module.
15
15
 
16
16
  import { parseModule } from '@tsrx/core';
17
+ import { parseModule as parseFallbackModule } from '#octane/compiler-parser';
17
18
  import { HOOK_NAMES, hookSlotHash } from './compile.js';
18
19
  import { NATIVE_SIGNAL_HOOK_NAMES } from './hook-names.js';
19
20
  import { METHOD_DEP_IMPORT, annotateHookCalls } from './hook-deps.js';
@@ -21,6 +22,7 @@ import { inlinePlainHookMemos } from './plain-hook-memo.js';
21
22
  import { assertStrongMode } from './strong-mode.js';
22
23
  import { assertNativeReadDiagnostics, assertNativeReadOptions } from './native-read-diagnostics.js';
23
24
  import { nativeReadActivationIndex } from './native-read-codegen.js';
25
+ import { findManualHookProviders, manualHookWrapperParameters } from './manual-hooks.js';
24
26
 
25
27
  function importsNativeRenderer(ast) {
26
28
  return ast.body.some(
@@ -42,6 +44,7 @@ function octaneHookLocals(ast, nativeReads = false) {
42
44
  const locals = new Map();
43
45
  let importsHook = false;
44
46
  let hasOctaneImport = false;
47
+ let importsCustomHook = false;
45
48
  for (const node of ast.body || []) {
46
49
  if (
47
50
  (node.type === 'ExportNamedDeclaration' || node.type === 'ExportAllDeclaration') &&
@@ -51,6 +54,15 @@ function octaneHookLocals(ast, nativeReads = false) {
51
54
  continue;
52
55
  }
53
56
  if (node.type !== 'ImportDeclaration') continue;
57
+ if (node.importKind === 'type') continue;
58
+ for (const sp of node.specifiers || []) {
59
+ if (
60
+ sp.importKind !== 'type' &&
61
+ (/^use[A-Z]/.test(sp.imported?.name ?? '') || /^use[A-Z]/.test(sp.local?.name ?? ''))
62
+ ) {
63
+ importsCustomHook = true;
64
+ }
65
+ }
54
66
  const native =
55
67
  nativeReads &&
56
68
  (node.source?.value === 'octane/signals/client' ||
@@ -76,7 +88,11 @@ function octaneHookLocals(ast, nativeReads = false) {
76
88
  importsHook = true;
77
89
  }
78
90
  }
79
- return { locals, importsHook, hasOctaneImport };
91
+ return {
92
+ locals,
93
+ importsHook: importsHook || (hasOctaneImport && importsCustomHook),
94
+ hasOctaneImport,
95
+ };
80
96
  }
81
97
 
82
98
  // Find only the disposable top-level root shape used by production entries:
@@ -158,7 +174,7 @@ function collectVoidRootCandidates(ast) {
158
174
  export function findVoidRootImports(source, id) {
159
175
  let ast;
160
176
  try {
161
- ast = parseModule(source, id);
177
+ ast = parseHookSource(source, id).ast;
162
178
  } catch {
163
179
  return [];
164
180
  }
@@ -236,7 +252,7 @@ export function findVoidComponentImports(source, id) {
236
252
  ast = source;
237
253
  } else {
238
254
  try {
239
- ast = parseModule(source, id);
255
+ ast = parseHookSource(source, id).ast;
240
256
  } catch {
241
257
  return [];
242
258
  }
@@ -737,6 +753,19 @@ function collectStateGetterCalls(ast) {
737
753
  return calls;
738
754
  }
739
755
 
756
+ function collectStateGetterEdit(node, imported, st) {
757
+ if (!st.getterCalls.has(node) || !STATE_GETTER_HELPERS[imported]) return;
758
+ let helper = st.getterHelpers.get(imported);
759
+ if (helper === undefined) {
760
+ const base = `_$${STATE_GETTER_HELPERS[imported]}`;
761
+ helper = base;
762
+ let suffix = 0;
763
+ while (st.source.includes(helper)) helper = `${base}$${++suffix}`;
764
+ st.getterHelpers.set(imported, helper);
765
+ }
766
+ st.edits.push({ pos: node.callee.start, end: node.callee.end, text: helper });
767
+ }
768
+
740
769
  // DFS in SOURCE ORDER, allocating a hook's slot id BEFORE descending into its args
741
770
  // — identical pre-order to rewriteHookCalls, so a base hook nested as an argument
742
771
  // (e.g. in a deps array) gets its own stable id. Collects insertion edits + the
@@ -954,6 +983,20 @@ function collectParallelUseEdits(ast, st) {
954
983
  scan(ast.body, hookOwner(null, 'module'));
955
984
  }
956
985
 
986
+ // Locate the call delimiter after the callee/type arguments without consuming
987
+ // comments or TypeScript syntax. Parenthesized identifier callees are valid too.
988
+ function callOpenParen(node, source) {
989
+ let pos = node.typeArguments?.end ?? node.callee.end;
990
+ while (pos < node.end) {
991
+ if (/\s/.test(source[pos]) || source[pos] === ')') pos++;
992
+ else if (source.startsWith('/*', pos)) pos = source.indexOf('*/', pos + 2) + 2;
993
+ else if (source.startsWith('//', pos)) {
994
+ while (pos < node.end && source[pos] !== '\n' && source[pos] !== '\r') pos++;
995
+ } else return source[pos] === '(' ? pos : -1;
996
+ }
997
+ return -1;
998
+ }
999
+
957
1000
  function walk(node, owner, st) {
958
1001
  if (!node || typeof node !== 'object') return;
959
1002
  if (Array.isArray(node)) {
@@ -976,10 +1019,24 @@ function walk(node, owner, st) {
976
1019
  node.type === 'FunctionDeclaration' && node.id ? hookOwner(node, node.id.name) : owner;
977
1020
 
978
1021
  if (node.type === 'CallExpression') {
1022
+ if (!st.manualSlots && node._octaneCustomHookCall) {
1023
+ const open = callOpenParen(node, st.source);
1024
+ if (open !== -1) {
1025
+ const sym = allocHookSymbol(st, owner, node.callee.name, node._octaneCustomHookCall, node);
1026
+ const helper = requireParallelHelper(st, 'withSlot');
1027
+ // The path stack supplies identity without changing the authored
1028
+ // argument list. An alias may point at a foreign hook whose omitted
1029
+ // parameter has a default, rather than at Octane's trailing-slot ABI.
1030
+ st.edits.push({ pos: node.start, text: `${helper}(${sym}, ` });
1031
+ st.edits.push({ pos: open, end: open + 1, text: node.arguments.length ? ', ' : '' });
1032
+ }
1033
+ }
979
1034
  const imported =
980
1035
  node._octaneImportedHook ??
981
1036
  (st.nativeReads ? node._octaneHookRuntimeImportedHook : undefined);
1037
+ collectStateGetterEdit(node, imported, st);
982
1038
  if (
1039
+ !st.manualSlots &&
983
1040
  imported &&
984
1041
  (HOOK_NAMES.has(imported) || (st.nativeReads && NATIVE_SIGNAL_HOOK_NAMES.has(imported)))
985
1042
  ) {
@@ -996,7 +1053,17 @@ function walk(node, owner, st) {
996
1053
  text: requireParallelHelper(st, 'nativePuMemo'),
997
1054
  });
998
1055
  }
999
- if (inferred !== undefined) {
1056
+ if (
1057
+ (imported === 'useState' || imported === 'useRef') &&
1058
+ node.arguments.some((arg) => arg.type === 'SpreadElement')
1059
+ ) {
1060
+ const open = callOpenParen(node, st.source);
1061
+ if (open !== -1) {
1062
+ const helper = requireParallelHelper(st, 'withSlot');
1063
+ st.edits.push({ pos: node.start, text: `${helper}(${sym}, ` });
1064
+ st.edits.push({ pos: open, end: open + 1, text: ', ' });
1065
+ }
1066
+ } else if (inferred !== undefined) {
1000
1067
  // The dependency callback is already the final user argument. Insert
1001
1068
  // both the generated array and slot in one edit so equal-position edit
1002
1069
  // ordering cannot reverse them. Dependency nodes retain original source
@@ -1016,11 +1083,11 @@ function walk(node, owner, st) {
1016
1083
  text: `, [${deps}], ${sym}`,
1017
1084
  });
1018
1085
  } else if (node.arguments.length === 0) {
1019
- // `useId()` → `useId(_h$N)`. Symbols remain self-identifying when
1020
- // optional user arguments are omitted.
1086
+ // State/ref initializers may themselves be Symbols. Reserve their
1087
+ // authored position even when empty; other hooks keep their ABI.
1021
1088
  st.edits.push({
1022
1089
  pos: node.end - 1,
1023
- text: sym,
1090
+ text: imported === 'useState' || imported === 'useRef' ? `undefined, ${sym}` : sym,
1024
1091
  });
1025
1092
  } else {
1026
1093
  // `useState(0)` → `useState(0, _h$N)` — insert AFTER the last arg's end so
@@ -1030,17 +1097,6 @@ function walk(node, owner, st) {
1030
1097
  text: ', ' + sym,
1031
1098
  });
1032
1099
  }
1033
- if (st.getterCalls.has(node) && STATE_GETTER_HELPERS[imported]) {
1034
- let helper = st.getterHelpers.get(imported);
1035
- if (helper === undefined) {
1036
- const base = `_$${STATE_GETTER_HELPERS[imported]}`;
1037
- helper = base;
1038
- let suffix = 0;
1039
- while (st.source.includes(helper)) helper = `${base}$${++suffix}`;
1040
- st.getterHelpers.set(imported, helper);
1041
- }
1042
- st.edits.push({ pos: node.callee.start, end: node.callee.end, text: helper });
1043
- }
1044
1100
  }
1045
1101
  }
1046
1102
 
@@ -1051,8 +1107,59 @@ function walk(node, owner, st) {
1051
1107
  }
1052
1108
  }
1053
1109
 
1110
+ function collectManualHookEdits(ast, providers, st) {
1111
+ function visit(node) {
1112
+ if (!node || typeof node !== 'object') return;
1113
+ if (Array.isArray(node)) {
1114
+ for (const item of node) visit(item);
1115
+ return;
1116
+ }
1117
+ if (providers.has(node)) {
1118
+ if (node.type === 'FunctionDeclaration') {
1119
+ const helper = requireParallelHelper(st, 'invokeManualHook');
1120
+ const implementation = allocSlotName(st, `_$manual_${node.id.name}`);
1121
+ const params = manualHookWrapperParameters(node)
1122
+ .map((param) => param.name)
1123
+ .join(', ');
1124
+ st.edits.push({
1125
+ pos: node.start,
1126
+ text: `function ${node.id.name}(${params}) { return ${helper}(${implementation}, this, arguments); } `,
1127
+ });
1128
+ st.edits.push({ pos: node.id.start, end: node.id.end, text: implementation });
1129
+ } else {
1130
+ const helper = requireParallelHelper(st, 'manualHook');
1131
+ st.edits.push({ pos: node.start, text: `/* @__PURE__ */ ${helper}(` });
1132
+ st.edits.push({ pos: node.end, text: `, ${JSON.stringify(providers.get(node))})` });
1133
+ }
1134
+ }
1135
+ for (const key in node) {
1136
+ if (key === 'loc' || key === 'metadata' || key === 'parent' || key.startsWith('_octane'))
1137
+ continue;
1138
+ const value = node[key];
1139
+ if (value && typeof value === 'object') visit(value);
1140
+ }
1141
+ }
1142
+ visit(ast);
1143
+ }
1144
+
1145
+ function parseHookSource(source, id) {
1146
+ try {
1147
+ return { ast: parseModule(source, id), canPrint: true };
1148
+ } catch (error) {
1149
+ if (!(error instanceof SyntaxError)) throw error;
1150
+ // Some binding signatures (const generics in function types) need the
1151
+ // native parser. Its object-TS dialect retains types and source offsets,
1152
+ // but drops type parentheses required by the Program printer. Keep that
1153
+ // AST on the surgical path so every authored type stays byte-for-byte.
1154
+ return {
1155
+ ast: parseFallbackModule(source, `${id.split(/[?#]/, 1)[0]}.object.ts`),
1156
+ canPrint: false,
1157
+ };
1158
+ }
1159
+ }
1160
+
1054
1161
  /**
1055
- * Inject per-call-site hook slots into octane BASE hook calls in a plain
1162
+ * Inject per-call-site hook slots into Octane base and imported/aliased hook calls in a plain
1056
1163
  * `.ts`/`.js` module. Returns `null` (pass through unchanged) when the module
1057
1164
  * imports no octane base hook or calls none.
1058
1165
  *
@@ -1064,8 +1171,8 @@ function walk(node, owner, st) {
1064
1171
  * runtime-ranged Symbols. Profiling retains short described Symbols because
1065
1172
  * hook metadata is keyed by Symbol identity.
1066
1173
  * `inlineHookMemo: true` enables the production-client whole-AST memo path;
1067
- * the default remains surgical. `manualSlots: true` permits only that memo
1068
- * rewrite and never injects or changes the module's authored slot policy.
1174
+ * the default remains surgical. `manualSlots: true` permits memo and observed
1175
+ * getter rewrites without injecting or changing the authored slot policy.
1069
1176
  * @returns {{ code: string, map: any } | null}
1070
1177
  */
1071
1178
  export function slotHooks(source, id, options) {
@@ -1077,21 +1184,29 @@ export function slotHooks(source, id, options) {
1077
1184
  );
1078
1185
  }
1079
1186
  let ast;
1187
+ let canPrint;
1080
1188
  try {
1081
- ast = parseModule(source, id);
1189
+ ({ ast, canPrint } = parseHookSource(source, id));
1082
1190
  } catch {
1083
1191
  return null; // let the normal pipeline surface the parse error
1084
1192
  }
1085
1193
  assertStrongMode(ast, source, id, options);
1086
1194
  assertNativeReadDiagnostics(ast, source, id, options);
1087
1195
  const importInfo = octaneHookLocals(ast, options?.nativeReads === true);
1196
+ const manualProviders = options?.manualSlots ? findManualHookProviders(ast) : new Map();
1088
1197
  const nativeReadActivation = options?.nativeReads === true && importsNativeRenderer(ast);
1089
1198
  const canSpecializeRoot =
1199
+ !options?.manualSlots &&
1090
1200
  !options?.hmr &&
1091
1201
  !options?.profile &&
1092
1202
  typeof options?.isVoidComponentImport === 'function' &&
1093
1203
  importInfo.hasOctaneImport;
1094
- if (!importInfo.importsHook && !canSpecializeRoot && !nativeReadActivation) {
1204
+ if (
1205
+ !importInfo.importsHook &&
1206
+ !canSpecializeRoot &&
1207
+ !nativeReadActivation &&
1208
+ !manualProviders.size
1209
+ ) {
1095
1210
  return null;
1096
1211
  }
1097
1212
  // The parsed tree is never mutated: annotateHookCalls returns a COW-rebuilt
@@ -1114,6 +1229,7 @@ export function slotHooks(source, id, options) {
1114
1229
  }
1115
1230
  const getterCalls = importInfo.importsHook ? collectStateGetterCalls(ast) : new WeakSet();
1116
1231
  if (
1232
+ canPrint &&
1117
1233
  options?.inlineHookMemo === true &&
1118
1234
  environment === 'client' &&
1119
1235
  !options?.hmr &&
@@ -1137,9 +1253,8 @@ export function slotHooks(source, id, options) {
1137
1253
  });
1138
1254
  if (inlined !== null) return inlined;
1139
1255
  }
1140
- if (options?.manualSlots === true && !nativeReadActivation) return null;
1141
-
1142
1256
  const st = {
1257
+ manualSlots: options?.manualSlots === true,
1143
1258
  nativeReads: options?.nativeReads === true,
1144
1259
  locals: importInfo.locals,
1145
1260
  source,
@@ -1163,10 +1278,13 @@ export function slotHooks(source, id, options) {
1163
1278
  voidRootName: null,
1164
1279
  };
1165
1280
  if (!st.hmr && !st.profile) st.slotBaseName = allocSlotName(st, '_hs$');
1166
- if (importInfo.importsHook && options?.manualSlots !== true) {
1167
- collectParallelUseEdits(ast, st);
1281
+ if (importInfo.importsHook) {
1282
+ if (!st.manualSlots) collectParallelUseEdits(ast, st);
1168
1283
  for (const node of ast.body || []) walk(node, hookOwner(null, 'module'), st);
1169
1284
  }
1285
+ if (manualProviders.size) {
1286
+ collectManualHookEdits(ast, findManualHookProviders(ast), st);
1287
+ }
1170
1288
  if (canSpecializeRoot) {
1171
1289
  collectVoidRootEdits(ast, st, options.isVoidComponentImport);
1172
1290
  }
@@ -1210,9 +1328,10 @@ export function slotHooks(source, id, options) {
1210
1328
  const otherHelperImports = [...otherHelpers]
1211
1329
  .map(([request, specifiers]) => `import { ${specifiers.join(', ')} } from '${request}';\n`)
1212
1330
  .join('');
1213
- const profileImport = st.profile
1214
- ? "import { __profileHook as _$__profileHook } from 'octane/profiling';\n"
1215
- : '';
1331
+ const profileImport =
1332
+ st.profile && !st.manualSlots
1333
+ ? "import { __profileHook as _$__profileHook } from 'octane/profiling';\n"
1334
+ : '';
1216
1335
  const slotBase =
1217
1336
  !st.hmr && !st.profile && st.nextId > 0
1218
1337
  ? `const ${st.slotBaseName} = /* @__PURE__ */ ${st.hookSlotsName}(${st.nextId});\n`
@@ -1,6 +1,6 @@
1
1
  /** The component owns a load-bearing runtime/SSR boundary range. */
2
2
  export declare const COMPONENT_FLAG_BOUNDARY: number;
3
3
  /** Attach an immutable capability bitmask without retaining concrete component identities. */
4
- export declare function markComponentFlags<T extends Function>(component: T, flags: number, name: string): T;
4
+ export declare function markComponentFlags<T extends Function>(component: T, flags: number, name: string, kind?: symbol): T;
5
5
  /** Test compiler/runtime capability bits on a component from any Octane runtime copy. */
6
6
  export declare function hasComponentFlags(component: unknown, flags: number): boolean;
@@ -1,9 +1,16 @@
1
1
  import { hasOwnProp } from "./has-own.js";
2
2
  const OCTANE_COMPONENT_FLAGS = /* @__PURE__ */ Symbol.for("octane.flags.component");
3
3
  const COMPONENT_FLAG_BOUNDARY = 1 << 0;
4
- function markComponentFlags(component, flags, name) {
4
+ function markComponentFlags(component, flags, name, kind) {
5
5
  Object.defineProperty(component, OCTANE_COMPONENT_FLAGS, { value: flags });
6
6
  Object.defineProperty(component, "name", { value: name, configurable: true });
7
+ if (kind !== void 0) {
8
+ Object.defineProperty(component, kind, {
9
+ get() {
10
+ return this === component;
11
+ }
12
+ });
13
+ }
7
14
  return component;
8
15
  }
9
16
  function hasComponentFlags(component, flags) {
@@ -398,6 +398,7 @@ for (const base of [
398
398
  "opacity",
399
399
  "order",
400
400
  "orphans",
401
+ "scale",
401
402
  "tabSize",
402
403
  "widows",
403
404
  "zIndex",
@@ -428,6 +429,7 @@ function cssStyleValue(name, value) {
428
429
  return typeof value === "string" ? value.trim() : "" + value;
429
430
  }
430
431
  function hyphenateStyleName(name) {
432
+ if (name === "cssFloat") return "float";
431
433
  if (name.charCodeAt(0) === 45) return name;
432
434
  let hasUpper = false;
433
435
  for (let i = 0; i < name.length; i++) {
@@ -26,7 +26,6 @@ type ClientErrorArguments = {
26
26
  25: [];
27
27
  26: [unknown];
28
28
  27: [];
29
- 28: [];
30
29
  29: [];
31
30
  46: [unknown, unknown];
32
31
  49: [];
@@ -38,6 +37,9 @@ type ClientErrorArguments = {
38
37
  55: [];
39
38
  56: [];
40
39
  58: [];
40
+ 61: [];
41
+ 62: [];
42
+ 63: [];
41
43
  };
42
44
  export declare function formatClientError<Code extends keyof ClientErrorArguments>(code: Code, ...args: ClientErrorArguments[Code]): string;
43
45
  export {};
@@ -129,8 +129,6 @@ function formatClientError(code, ...args) {
129
129
  "A hosted foreign-context request escaped its renderer-region owner; the owning bridge is gone or declined it.",
130
130
  args
131
131
  );
132
- case 28:
133
- return formatDevErrorMessage("Target container is not a DOM element.", args);
134
132
  case 29:
135
133
  return formatDevErrorMessage("Cannot update an unmounted root.", args);
136
134
  case 46:
@@ -177,6 +175,21 @@ function formatClientError(code, ...args) {
177
175
  );
178
176
  case 58:
179
177
  return formatDevErrorMessage("Unsupported native-read compiler/runtime version.", args);
178
+ case 61:
179
+ return formatDevErrorMessage(
180
+ "Hydration mismatch: the server-rendered text differed from the client; the text was updated to the client value.",
181
+ args
182
+ );
183
+ case 62:
184
+ return formatDevErrorMessage(
185
+ "Hydration mismatch: the server rendered extra children in a text element; the stale children were discarded.",
186
+ args
187
+ );
188
+ case 63:
189
+ return formatDevErrorMessage(
190
+ "Target container is not a DOM element. Pass an Element, Document, or DocumentFragment. If document.body is null after document hydration, update the existing document root or render a document shell containing <body>.",
191
+ args
192
+ );
180
193
  default:
181
194
  return formatUnknownDevErrorMessage(code);
182
195
  }
@@ -30,6 +30,7 @@ type ServerErrorArguments = {
30
30
  57: [];
31
31
  58: [];
32
32
  59: [unknown];
33
+ 60: [];
33
34
  };
34
35
  export declare function formatServerError<Code extends keyof ServerErrorArguments>(code: Code, ...args: ServerErrorArguments[Code]): string;
35
36
  export {};
@@ -125,6 +125,11 @@ function formatServerError(code, ...args) {
125
125
  return formatDevErrorMessage("Unsupported native-read compiler/runtime version.", args);
126
126
  case 59:
127
127
  return formatDevErrorMessage("%s requires an active server component.", args);
128
+ case 60:
129
+ return formatDevErrorMessage(
130
+ "A component suspended without a Suspense boundary during synchronous server rendering. Use prerender() or a streaming renderer to await it.",
131
+ args
132
+ );
128
133
  default:
129
134
  return formatUnknownDevErrorMessage(code);
130
135
  }
@@ -0,0 +1 @@
1
+ export function isDelegatedEventProp(name: string): boolean;
@@ -0,0 +1,15 @@
1
+ const names = "Abort AnimationEnd AnimationIteration AnimationStart AuxClick BeforeInput BeforeToggle Blur Cancel CanPlay CanPlayThrough Change Click Close CompositionEnd CompositionStart CompositionUpdate ContextMenu Copy Cut DoubleClick Drag DragEnd DragEnter DragExit DragLeave DragOver DragStart Drop DurationChange Emptied Encrypted Ended Error Focus GotPointerCapture Input Invalid KeyDown KeyPress KeyUp Load LoadedData LoadedMetadata LoadStart LostPointerCapture MouseDown MouseEnter MouseLeave MouseMove MouseOut MouseOver MouseUp Paste Pause Play Playing PointerCancel PointerDown PointerEnter PointerLeave PointerMove PointerOut PointerOver PointerUp Progress RateChange Reset Resize Scroll ScrollEnd Seeked Seeking Select Stalled Submit Suspend TimeUpdate Toggle TouchCancel TouchEnd TouchMove TouchStart TransitionCancel TransitionEnd TransitionRun TransitionStart VolumeChange Waiting Wheel";
2
+ let delegatedEventProps;
3
+ function isDelegatedEventProp(name) {
4
+ if (delegatedEventProps === void 0) {
5
+ delegatedEventProps = /* @__PURE__ */ new Set();
6
+ for (const event of names.split(" ")) {
7
+ delegatedEventProps.add("on" + event);
8
+ delegatedEventProps.add("on" + event + "Capture");
9
+ }
10
+ }
11
+ return delegatedEventProps.has(name);
12
+ }
13
+ export {
14
+ isDelegatedEventProp
15
+ };
@@ -1,34 +1,17 @@
1
- /**
2
- * HTML parser-repair rules used by DEV client and SSR nesting diagnostics.
3
- *
4
- * This is intentionally narrower than the full HTML content model: it only
5
- * lists placements the browser repairs while parsing serialized HTML, because
6
- * those repairs can change the DOM before hydration. Adapted from Svelte's
7
- * html-tree-validation module, which Ripple also uses.
8
- *
9
- * Copyright (c) 2016-2025 Svelte Contributors
10
- *
11
- * Permission is hereby granted, free of charge, to any person obtaining a copy
12
- * of this software and associated documentation files (the "Software"), to deal
13
- * in the Software without restriction, including without limitation the rights
14
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
- * copies of the Software, and to permit persons to whom the Software is
16
- * furnished to do so, subject to the following conditions:
17
- *
18
- * The above copyright notice and this permission notice shall be included in
19
- * all copies or substantial portions of the Software.
20
- *
21
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
- * SOFTWARE.
28
- */
29
- /** Return a diagnostic when `childTag` causes an ancestor to be repaired. */
30
- export declare function invalidHtmlNestingWithAncestor(childTag: string, ancestors: string[], childLocation?: string, ancestorLocation?: string): string | null;
31
- /** Return a diagnostic when `childTag` causes its direct parent to be repaired. */
32
- export declare function invalidHtmlNestingWithParent(childTag: string, parentTag: string, childLocation?: string, parentLocation?: string): string | null;
33
- /** Return a diagnostic when visible or whitespace text cannot remain under its parent. */
34
- export declare function invalidHtmlTextNesting(text: string, parentTag: string, parentLocation?: string): string | null;
1
+ export declare function invalidHtmlNestingWithAncestor(
2
+ childTag: string,
3
+ ancestors: string[],
4
+ childLocation?: string,
5
+ ancestorLocation?: string,
6
+ ): string | null;
7
+ export declare function invalidHtmlNestingWithParent(
8
+ childTag: string,
9
+ parentTag: string,
10
+ childLocation?: string,
11
+ parentLocation?: string,
12
+ ): string | null;
13
+ export declare function invalidHtmlTextNesting(
14
+ text: string,
15
+ parentTag: string,
16
+ parentLocation?: string,
17
+ ): string | null;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  export { version } from './version.js';
2
+ export type * from './public-types.js';
3
+ export { StrictMode, unstable_batchedUpdates } from './compatibility.js';
2
4
  export { initializeHydrationEventCapture } from './hydration/event-capture.js';
3
5
  export { attachBehaviorRoot } from './behavior-root.js';
4
6
  export type * from './behavior-root.js';
5
7
  export { createSubSlot, subSlot, type SubSlot, type SlotlessSubSlot, type SubSlotOptions, } from './sub-slot.js';
6
- export { createRoot, hydrateRoot, flushSync, act, type Root, type RootOptions, useState, useLinkedState, type LinkedStatePrevious, type LinkedStateOptions, useReducer, useEffect, useLayoutEffect, useInsertionEffect, useMemo, useCallback, useRef, useId, useImperativeHandle, useEffectEvent, useSyncExternalStore, useDeferredValue, useTransition, useActionState, useFormStatus, useOptimistic, useDebugValue, type FormStatus, startTransition, requestFormReset, memo, lazy, preload, preinit, preloadModule, preinitModule, preconnect, prefetchDNS, createContext, use, useContext, type Context, type ForeignHostContext, Suspense, ErrorBoundary, Hydrate, Activity, Activity as unstable_Activity, ViewTransition, addTransitionType, ViewTransition as unstable_ViewTransition, addTransitionType as unstable_addTransitionType, ViewTransitionPseudoElement, type ViewTransitionProps, type ViewTransitionInstance, Fragment, createPortal, type PortalDescriptor, createElement, cloneElement, isValidElement, isChildrenBlock, Children, type ElementDescriptor, type ComponentBody, type OctaneNode, TsrxErrorBoundary, __useStateWithGetter, __useLinkedStateWithGetter, __useReducerWithGetter, __createVoidRoot, bindRendererRegionOwner, EXTERNAL_HYDRATION_PROMISE, HYDRATION_RANGE_BOUNDARY, createHostContextRequest, __vtSeen, template, clone, drainFrag, bag0, bag1, bag2, bag3, bag4, bag5, bag6, bag7, bag8, bag9, bag10, bag11, bag12, bag13, bag14, bag15, bag16, bagOf, evt0, evt0u, evt1, evt1u, evt2, evt2u, evtN, evtNu, setEventHandler, devEventListener, devHtmlNesting, htext, htextSwap, child, sibling, setText, setScriptText, setHTML, setDangerouslySetInnerHTML, setDangerouslySetInnerHTMLSources, markDangerouslySetInnerHTMLChildren, setAttribute, setStringData, setBooleanAttribute, setAriaAttribute, setClassName, setClassAttr, normalizeClass, setStyle, setStyleProperty, setSpread, snapshotSpread, setHostPropSources, queueNativeChangeDiagnostic, queueFormAuthoringDiagnostic, markNativeChangeDiagnosticStatic, setFormAction, setValue, setFormControlSources, setChecked, setCheckedCheckable, setSelectValue, setDefaultValue, setDefaultValueUncontrolled, setDefaultChecked, setAutoFocus, attachRef, queueRefAttach, queueRefDetach, replaceRef, queueOwnRefDetach, injectStyle, headBlock, stylesheetResource, styleResource, scriptResource, namespaceHead, namespaceHeadElement, delegateEvents, delegateCaptureEvents, fastForBlock, fastKeyedForBlock, fastMapSlot, forBlock, keyedForBlock, mapSlot, ifBlock, errorBlock, tryBlock, switchBlock, activityBlock, componentSlot, componentSlotVoid, componentSlotLite, compilerCacheArray, compilerCacheImmutableArrayFilter, compilerCacheMappedArray, compilerCacheContext, compilerOwnsContextProvider, markSingleRoot, markSingleRoot as __s, markChildrenBlock, descriptorChildren, createScopedValue, createScopedElement, childSlot, positionalChildren, textSlot, textHole, childTextHole, hostComponent, renderBlock, portal, hookSlots, withSlot, useBatch, seedOrCreate, warmMemo, warmChild, puMiss, puTake0, puTake1, puTake2, puTake3, puTake4, puPub, provideContext, mountFragmentRef, FragmentInstance, hmr, HMR, hasPendingWork, type Scope, type Block, drainPassiveEffects, setIsOctaneActEnvironment, resetFloatResourceState, setTransitionFallbackTimeout, getTransitionFallbackTimeout, } from './runtime.js';
8
+ export { createRoot, hydrateRoot, flushSync, act, type Root, type RootContainer, type RootOptions, useState, useLinkedState, type LinkedStatePrevious, type LinkedStateOptions, useReducer, useEffect, useLayoutEffect, useInsertionEffect, useMemo, useCallback, useRef, useId, useImperativeHandle, useEffectEvent, useSyncExternalStore, useDeferredValue, useTransition, useActionState, useActionState as useFormState, useFormStatus, useOptimistic, useDebugValue, type FormStatus, startTransition, requestFormReset, memo, lazy, preload, preinit, preloadModule, preinitModule, preconnect, prefetchDNS, createContext, use, useContext, type Context, type ForeignHostContext, Suspense, ErrorBoundary, Hydrate, Activity, Activity as unstable_Activity, ViewTransition, addTransitionType, ViewTransition as unstable_ViewTransition, addTransitionType as unstable_addTransitionType, ViewTransitionPseudoElement, type ViewTransitionProps, type ViewTransitionInstance, Fragment, createPortal, type PortalDescriptor, createElement, cloneElement, isValidElement, isChildrenBlock, descriptorChildren, Children, type ElementDescriptor, type ComponentBody, type OctaneNode, TsrxErrorBoundary, __useStateWithGetter, __useLinkedStateWithGetter, __useReducerWithGetter, __createVoidRoot, bindRendererRegionOwner, EXTERNAL_HYDRATION_PROMISE, HYDRATION_RANGE_BOUNDARY, createHostContextRequest, __vtSeen, template, clone, drainFrag, bag0, bag1, bag2, bag3, bag4, bag5, bag6, bag7, bag8, bag9, bag10, bag11, bag12, bag13, bag14, bag15, bag16, bagOf, evt0, evt0u, evt1, evt1u, evt2, evt2u, evtN, evtNu, setEventHandler, devEventListener, devHtmlNesting, htext, htextSwap, child, sibling, setText, setScriptText, setHTML, setDangerouslySetInnerHTML, setDangerouslySetInnerHTMLSources, markDangerouslySetInnerHTMLChildren, setAttribute, setStringData, setBooleanAttribute, setAriaAttribute, setClassName, setClassAttr, normalizeClass, setStyle, setStyleProperty, setSpread, snapshotSpread, setHostPropSources, queueNativeChangeDiagnostic, queueFormAuthoringDiagnostic, markNativeChangeDiagnosticStatic, setFormAction, setValue, setFormControlSources, setChecked, setCheckedCheckable, setSelectValue, setDefaultValue, setDefaultValueUncontrolled, setDefaultChecked, setAutoFocus, attachRef, queueRefAttach, queueRefDetach, replaceRef, queueOwnRefDetach, injectStyle, headBlock, stylesheetResource, styleResource, scriptResource, namespaceHead, namespaceHeadElement, delegateEvents, delegateCaptureEvents, fastForBlock, fastKeyedForBlock, fastMapSlot, forBlock, keyedForBlock, mapSlot, ifBlock, errorBlock, tryBlock, switchBlock, activityBlock, componentSlot, componentSlotVoid, componentSlotLite, compilerCacheArray, compilerCacheImmutableArrayFilter, compilerCacheMappedArray, compilerCacheContext, compilerOwnsContextProvider, markSingleRoot, markWarm, markSingleRoot as __s, markChildrenBlock, createScopedValue, createScopedElement, childSlot, positionalChildren, textSlot, textHole, childTextHole, hostComponent, renderBlock, portal, hookSlots, withSlot, manualHook, invokeManualHook, useBatch, seedOrCreate, warmMemo, warmChild, puMiss, puTake0, puTake1, puTake2, puTake3, puTake4, puPub, provideContext, mountFragmentRef, FragmentInstance, hmr, HMR, hasPendingWork, type Scope, type Block, drainPassiveEffects, setIsOctaneActEnvironment, resetFloatResourceState, setTransitionFallbackTimeout, getTransitionFallbackTimeout, } from './runtime.js';
7
9
  export type { HydrateOptions, HydrateProps, HydrateWhen, HydrationInteractionEvent, HydrationInteractionEvents, HydrationPrefetchContext, HydrationPrefetchFunction, HydrationPrefetchStrategy, HydrationPrefetchWaitReason, HydrationStrategy, HydrationWhen, } from './hydration/types.js';
8
10
  export { __serverRpc } from './server-rpc-client.js';
9
11
  export { __methodDep } from './method-dep.js';
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { version } from "./version.js";
2
+ import { StrictMode, unstable_batchedUpdates } from "./compatibility.js";
2
3
  import { initializeHydrationEventCapture } from "./hydration/event-capture.js";
3
4
  import { attachBehaviorRoot } from "./behavior-root.js";
4
5
  import {
@@ -26,6 +27,7 @@ import {
26
27
  useDeferredValue,
27
28
  useTransition,
28
29
  useActionState,
30
+ useActionState as useActionState2,
29
31
  useFormStatus,
30
32
  useOptimistic,
31
33
  useDebugValue,
@@ -58,6 +60,7 @@ import {
58
60
  cloneElement,
59
61
  isValidElement,
60
62
  isChildrenBlock,
63
+ descriptorChildren,
61
64
  Children,
62
65
  TsrxErrorBoundary,
63
66
  __useStateWithGetter,
@@ -170,9 +173,9 @@ import {
170
173
  compilerCacheContext,
171
174
  compilerOwnsContextProvider,
172
175
  markSingleRoot,
176
+ markWarm,
173
177
  markSingleRoot as markSingleRoot2,
174
178
  markChildrenBlock,
175
- descriptorChildren,
176
179
  createScopedValue,
177
180
  createScopedElement,
178
181
  childSlot,
@@ -185,6 +188,8 @@ import {
185
188
  portal,
186
189
  hookSlots,
187
190
  withSlot,
191
+ manualHook,
192
+ invokeManualHook,
188
193
  useBatch,
189
194
  seedOrCreate,
190
195
  warmMemo,
@@ -220,6 +225,7 @@ export {
220
225
  HMR,
221
226
  HYDRATION_RANGE_BOUNDARY,
222
227
  Hydrate,
228
+ StrictMode,
223
229
  Suspense,
224
230
  TsrxErrorBoundary,
225
231
  ViewTransition,
@@ -310,15 +316,18 @@ export {
310
316
  ifBlock,
311
317
  initializeHydrationEventCapture,
312
318
  injectStyle,
319
+ invokeManualHook,
313
320
  isChildrenBlock,
314
321
  isValidElement,
315
322
  keyedForBlock,
316
323
  lazy,
324
+ manualHook,
317
325
  mapSlot,
318
326
  markChildrenBlock,
319
327
  markDangerouslySetInnerHTMLChildren,
320
328
  markNativeChangeDiagnosticStatic,
321
329
  markSingleRoot,
330
+ markWarm,
322
331
  memo,
323
332
  mountFragmentRef,
324
333
  namespaceHead,
@@ -393,6 +402,7 @@ export {
393
402
  Activity2 as unstable_Activity,
394
403
  ViewTransition2 as unstable_ViewTransition,
395
404
  addTransitionType2 as unstable_addTransitionType,
405
+ unstable_batchedUpdates,
396
406
  use,
397
407
  useActionState,
398
408
  useBatch,
@@ -402,6 +412,7 @@ export {
402
412
  useDeferredValue,
403
413
  useEffect,
404
414
  useEffectEvent,
415
+ useActionState2 as useFormState,
405
416
  useFormStatus,
406
417
  useId,
407
418
  useImperativeHandle,