octane 0.2.11 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/README.md +5 -0
  2. package/dist/behavior-root.d.ts +13 -3
  3. package/dist/behavior-root.js +28 -5
  4. package/dist/cjs/behavior-root.cjs +32 -6
  5. package/dist/cjs/class-names.cjs +49 -0
  6. package/dist/cjs/constants.cjs +9 -0
  7. package/dist/cjs/context-epoch.cjs +38 -0
  8. package/dist/cjs/css.cjs +6 -27
  9. package/dist/cjs/data-encoding.cjs +160 -0
  10. package/dist/cjs/dom-binding-handoff.cjs +93 -0
  11. package/dist/cjs/dom-binding-protocol.cjs +115 -0
  12. package/dist/cjs/dom-binding-styles.cjs +292 -0
  13. package/dist/cjs/dom-bindings.cjs +700 -0
  14. package/dist/cjs/dom-focused-move.cjs +66 -0
  15. package/dist/cjs/dom-stage.cjs +896 -0
  16. package/dist/cjs/dom-tables.cjs +4 -94
  17. package/dist/cjs/error-codes.client.generated.cjs +33 -0
  18. package/dist/cjs/error-codes.server.generated.cjs +24 -0
  19. package/dist/cjs/hydration/control-capture.cjs +244 -0
  20. package/dist/cjs/hydration/event-capture.cjs +125 -43
  21. package/dist/cjs/hydration/interaction-config.cjs +50 -2
  22. package/dist/cjs/hydration-markers.cjs +37 -0
  23. package/dist/cjs/independent-hydration-protocol.cjs +106 -0
  24. package/dist/cjs/index.cjs +9 -0
  25. package/dist/cjs/runtime.cjs +6397 -1683
  26. package/dist/cjs/runtime.server.cjs +1465 -213
  27. package/dist/cjs/server/early-signals.cjs +45 -0
  28. package/dist/cjs/server/index.cjs +47 -0
  29. package/dist/cjs/server/rpc-batch.cjs +149 -0
  30. package/dist/cjs/server/rpc-stream.cjs +146 -0
  31. package/dist/cjs/server/rpc.cjs +34 -15
  32. package/dist/cjs/server/signal-query-observation.cjs +158 -0
  33. package/dist/cjs/server/streamed-region.cjs +52 -0
  34. package/dist/cjs/server/streamed-signals.cjs +512 -0
  35. package/dist/cjs/server-call.cjs +103 -0
  36. package/dist/cjs/server-rpc-batch-client.cjs +141 -0
  37. package/dist/cjs/server-rpc-client.cjs +94 -27
  38. package/dist/cjs/server-rpc-protocol.cjs +141 -0
  39. package/dist/cjs/server-rpc-stream-client.cjs +118 -0
  40. package/dist/cjs/signals/actions.cjs +474 -0
  41. package/dist/cjs/signals/client.cjs +4 -1
  42. package/dist/cjs/signals/computations.cjs +460 -0
  43. package/dist/cjs/signals/control-binding.cjs +368 -0
  44. package/dist/cjs/signals/derived-facade.cjs +50 -0
  45. package/dist/cjs/signals/document-owner.cjs +71 -0
  46. package/dist/cjs/signals/early-values.cjs +155 -0
  47. package/dist/cjs/signals/encoding.cjs +6 -95
  48. package/dist/cjs/signals/engine.cjs +276 -12
  49. package/dist/cjs/signals/errors.cjs +18 -0
  50. package/dist/cjs/signals/facade.cjs +477 -0
  51. package/dist/cjs/signals/graph.cjs +166 -20
  52. package/dist/cjs/signals/handle-protocol.cjs +36 -0
  53. package/dist/cjs/signals/index.cjs +81 -2
  54. package/dist/cjs/signals/native-read-client.cjs +10 -0
  55. package/dist/cjs/signals/owner-context.cjs +112 -0
  56. package/dist/cjs/signals/query-attempt-observer.cjs +68 -0
  57. package/dist/cjs/signals/query-facade.cjs +72 -0
  58. package/dist/cjs/signals/read-protocol.cjs +54 -0
  59. package/dist/cjs/signals/requests.cjs +287 -14
  60. package/dist/cjs/signals/scalar-computations.cjs +76 -0
  61. package/dist/cjs/signals/server.cjs +4 -1
  62. package/dist/cjs/signals/transition-candidate.cjs +567 -0
  63. package/dist/cjs/signals/transition-state.cjs +106 -0
  64. package/dist/cjs/signals/types.cjs +50 -0
  65. package/dist/cjs/stream-protocol.cjs +3 -0
  66. package/dist/cjs/streamed-signals-protocol.cjs +159 -0
  67. package/dist/cjs/style-values.cjs +122 -0
  68. package/dist/cjs/trusted-html.cjs +30 -0
  69. package/dist/cjs/version.cjs +1 -1
  70. package/dist/class-names.d.ts +5 -0
  71. package/dist/class-names.js +25 -0
  72. package/dist/compiler/bundler.js +51 -22
  73. package/dist/compiler/compile.js +2534 -581
  74. package/dist/compiler/dom-binding-program.js +935 -0
  75. package/dist/compiler/dom-binding-request.js +57 -0
  76. package/dist/compiler/dom-bindings.js +2245 -0
  77. package/dist/compiler/hook-deps.js +759 -10
  78. package/dist/compiler/hydrate-boundaries.js +358 -15
  79. package/dist/compiler/index.d.ts +39 -2
  80. package/dist/compiler/index.js +1 -0
  81. package/dist/compiler/native-attribute-reads.js +127 -0
  82. package/dist/compiler/native-change-diagnostics.js +32 -38
  83. package/dist/compiler/native-read-diagnostics.js +69 -8
  84. package/dist/compiler/native-read-types.js +80 -34
  85. package/dist/compiler/parser.node.js +1 -1
  86. package/dist/compiler/renderer-boundaries.js +40 -0
  87. package/dist/compiler/server-context.js +118 -0
  88. package/dist/compiler/signal-attempt-reads.js +479 -0
  89. package/dist/compiler/signal-declarations.js +557 -0
  90. package/dist/compiler/signal-start-reads.js +413 -0
  91. package/dist/compiler/slot-hooks.d.ts +3 -1
  92. package/dist/compiler/slot-hooks.js +168 -34
  93. package/dist/compiler/strong-auto-memo.js +90 -0
  94. package/dist/compiler/strong-html.js +143 -0
  95. package/dist/compiler/strong-mode.js +764 -66
  96. package/dist/compiler/strong-template-policy.js +307 -0
  97. package/dist/compiler/template-ir.js +200 -0
  98. package/dist/compiler/typescript.d.ts +2 -0
  99. package/dist/compiler/typescript.js +2 -0
  100. package/dist/compiler/vite.d.ts +3 -1
  101. package/dist/compiler/vite.js +122 -4
  102. package/dist/compiler/volar.LICENSES.txt +1 -1
  103. package/dist/compiler/volar.d.ts +6 -1
  104. package/dist/compiler/volar.js +750 -1433
  105. package/dist/constants.d.ts +1 -0
  106. package/dist/constants.js +10 -0
  107. package/dist/context-epoch.d.ts +2 -0
  108. package/dist/context-epoch.js +13 -0
  109. package/dist/css.d.ts +2 -5
  110. package/dist/css.js +2 -23
  111. package/dist/data-encoding.d.ts +9 -0
  112. package/dist/data-encoding.js +134 -0
  113. package/dist/dom-binding-classes.d.ts +15 -0
  114. package/dist/dom-binding-classes.js +129 -0
  115. package/dist/dom-binding-controls.d.ts +2 -0
  116. package/dist/dom-binding-controls.js +6 -0
  117. package/dist/dom-binding-handoff.d.ts +55 -0
  118. package/dist/dom-binding-handoff.js +62 -0
  119. package/dist/dom-binding-program.d.ts +300 -0
  120. package/dist/dom-binding-program.js +1625 -0
  121. package/dist/dom-binding-projections.d.ts +15 -0
  122. package/dist/dom-binding-projections.js +187 -0
  123. package/dist/dom-binding-protocol.d.ts +13 -0
  124. package/dist/dom-binding-protocol.js +88 -0
  125. package/dist/dom-binding-signals.d.ts +21 -0
  126. package/dist/dom-binding-signals.js +109 -0
  127. package/dist/dom-binding-styles.d.ts +17 -0
  128. package/dist/dom-binding-styles.js +272 -0
  129. package/dist/dom-bindings.d.ts +89 -0
  130. package/dist/dom-bindings.js +670 -0
  131. package/dist/dom-focused-move.d.ts +6 -0
  132. package/dist/dom-focused-move.js +42 -0
  133. package/dist/dom-stage.d.ts +52 -0
  134. package/dist/dom-stage.js +872 -0
  135. package/dist/dom-tables.d.ts +1 -3
  136. package/dist/dom-tables.js +1 -91
  137. package/dist/error-codes.client.generated.d.ts +9 -0
  138. package/dist/error-codes.client.generated.js +33 -0
  139. package/dist/error-codes.server.generated.d.ts +6 -0
  140. package/dist/error-codes.server.generated.js +24 -0
  141. package/dist/hydration/control-capture.d.ts +62 -0
  142. package/dist/hydration/control-capture.js +223 -0
  143. package/dist/hydration/document-lifecycle.d.ts +23 -0
  144. package/dist/hydration/document-lifecycle.js +80 -0
  145. package/dist/hydration/event-capture.d.ts +20 -1
  146. package/dist/hydration/event-capture.js +128 -42
  147. package/dist/hydration/independent-island.d.ts +45 -0
  148. package/dist/hydration/independent-island.js +233 -0
  149. package/dist/hydration/index.d.ts +8 -1
  150. package/dist/hydration/index.js +55 -1
  151. package/dist/hydration/interaction-config.d.ts +5 -0
  152. package/dist/hydration/interaction-config.js +44 -1
  153. package/dist/hydration/stream-delivery.d.ts +32 -0
  154. package/dist/hydration/stream-delivery.js +333 -0
  155. package/dist/hydration/stream-receiver.d.ts +26 -0
  156. package/dist/hydration/stream-receiver.js +204 -0
  157. package/dist/hydration/stream-result-receiver.d.ts +70 -0
  158. package/dist/hydration/stream-result-receiver.js +246 -0
  159. package/dist/hydration/streamed-signals.d.ts +44 -0
  160. package/dist/hydration/streamed-signals.js +186 -0
  161. package/dist/hydration/types.d.ts +6 -0
  162. package/dist/hydration-markers.d.ts +7 -0
  163. package/dist/hydration-markers.js +10 -0
  164. package/dist/independent-hydration-protocol.d.ts +31 -0
  165. package/dist/independent-hydration-protocol.js +80 -0
  166. package/dist/index.d.ts +3 -0
  167. package/dist/index.js +6 -0
  168. package/dist/internal/signal-read.d.ts +1 -0
  169. package/dist/internal/signal-read.js +4 -0
  170. package/dist/jsx-runtime-strong.d.ts +33 -0
  171. package/dist/jsx-runtime.d.ts +58 -2
  172. package/dist/public-types.d.ts +15 -1
  173. package/dist/runtime.d.ts +297 -23
  174. package/dist/runtime.js +6405 -1679
  175. package/dist/runtime.server.d.ts +110 -27
  176. package/dist/runtime.server.js +1458 -213
  177. package/dist/server/early-signals.d.ts +14 -0
  178. package/dist/server/early-signals.js +34 -0
  179. package/dist/server/index.d.ts +11 -2
  180. package/dist/server/index.js +50 -1
  181. package/dist/server/rpc-batch.d.ts +17 -0
  182. package/dist/server/rpc-batch.js +129 -0
  183. package/dist/server/rpc-stream.d.ts +9 -0
  184. package/dist/server/rpc-stream.js +125 -0
  185. package/dist/server/rpc.d.ts +5 -1
  186. package/dist/server/rpc.js +37 -13
  187. package/dist/server/signal-query-observation.d.ts +3 -0
  188. package/dist/server/signal-query-observation.js +134 -0
  189. package/dist/server/streamed-region.d.ts +15 -0
  190. package/dist/server/streamed-region.js +30 -0
  191. package/dist/server/streamed-signals.d.ts +45 -0
  192. package/dist/server/streamed-signals.js +488 -0
  193. package/dist/server-call.d.ts +41 -0
  194. package/dist/server-call.js +75 -0
  195. package/dist/server-rpc-batch-client.d.ts +7 -0
  196. package/dist/server-rpc-batch-client.js +119 -0
  197. package/dist/server-rpc-client.d.ts +3 -1
  198. package/dist/server-rpc-client.js +99 -27
  199. package/dist/server-rpc-protocol.d.ts +47 -0
  200. package/dist/server-rpc-protocol.js +109 -0
  201. package/dist/server-rpc-stream-client.d.ts +5 -0
  202. package/dist/server-rpc-stream-client.js +98 -0
  203. package/dist/signals/actions.d.ts +12 -0
  204. package/dist/signals/actions.js +466 -0
  205. package/dist/signals/client.d.ts +2 -0
  206. package/dist/signals/client.js +1 -0
  207. package/dist/signals/computations.d.ts +37 -0
  208. package/dist/signals/computations.js +455 -0
  209. package/dist/signals/control-binding.d.ts +31 -0
  210. package/dist/signals/control-binding.js +353 -0
  211. package/dist/signals/derived-facade.d.ts +3 -0
  212. package/dist/signals/derived-facade.js +25 -0
  213. package/dist/signals/document-owner.d.ts +10 -0
  214. package/dist/signals/document-owner.js +43 -0
  215. package/dist/signals/early-values.d.ts +24 -0
  216. package/dist/signals/early-values.js +124 -0
  217. package/dist/signals/encoding.d.ts +1 -3
  218. package/dist/signals/encoding.js +3 -93
  219. package/dist/signals/engine.d.ts +53 -4
  220. package/dist/signals/engine.js +275 -16
  221. package/dist/signals/errors.d.ts +7 -0
  222. package/dist/signals/errors.js +16 -0
  223. package/dist/signals/facade.d.ts +74 -0
  224. package/dist/signals/facade.js +452 -0
  225. package/dist/signals/graph.d.ts +52 -6
  226. package/dist/signals/graph.js +174 -19
  227. package/dist/signals/handle-protocol.d.ts +4 -0
  228. package/dist/signals/handle-protocol.js +11 -0
  229. package/dist/signals/index.d.ts +12 -3
  230. package/dist/signals/index.js +71 -2
  231. package/dist/signals/native-read-client.d.ts +3 -0
  232. package/dist/signals/native-read-client.js +10 -0
  233. package/dist/signals/owner-context.d.ts +22 -0
  234. package/dist/signals/owner-context.js +77 -0
  235. package/dist/signals/query-attempt-observer.d.ts +49 -0
  236. package/dist/signals/query-attempt-observer.js +41 -0
  237. package/dist/signals/query-facade.d.ts +3 -0
  238. package/dist/signals/query-facade.js +49 -0
  239. package/dist/signals/read-protocol.d.ts +37 -2
  240. package/dist/signals/read-protocol.js +44 -0
  241. package/dist/signals/requests.d.ts +38 -5
  242. package/dist/signals/requests.js +298 -15
  243. package/dist/signals/scalar-computations.d.ts +2 -0
  244. package/dist/signals/scalar-computations.js +60 -0
  245. package/dist/signals/server.d.ts +2 -0
  246. package/dist/signals/server.js +1 -0
  247. package/dist/signals/transition-candidate.d.ts +71 -0
  248. package/dist/signals/transition-candidate.js +557 -0
  249. package/dist/signals/transition-state.d.ts +51 -0
  250. package/dist/signals/transition-state.js +70 -0
  251. package/dist/signals/types.d.ts +95 -5
  252. package/dist/signals/types.js +20 -0
  253. package/dist/stream-protocol.d.ts +0 -5
  254. package/dist/stream-protocol.js +3 -0
  255. package/dist/streamed-signals-protocol.d.ts +60 -0
  256. package/dist/streamed-signals-protocol.js +130 -0
  257. package/dist/style-values.d.ts +3 -0
  258. package/dist/style-values.js +96 -0
  259. package/dist/trusted-html.d.ts +17 -0
  260. package/dist/trusted-html.js +6 -0
  261. package/dist/universal-core.d.ts +6 -0
  262. package/dist/universal-core.js +214 -202
  263. package/dist/version.js +1 -1
  264. package/package.json +48 -5
@@ -1,3 +1,11 @@
1
+ import {
2
+ activeCandidate,
3
+ candidateWriteCount,
4
+ deferCandidateInvalidation,
5
+ recordCandidateUrgentWrite,
6
+ registerCandidateGraph,
7
+ withoutSignalCandidate
8
+ } from "./transition-state.js";
1
9
  import {
2
10
  createReactiveSystem
3
11
  } from "alien-signals/system";
@@ -5,16 +13,27 @@ import {
5
13
  ScopeDisposedError,
6
14
  SignalCycleError,
7
15
  SignalFrameError,
16
+ SignalIdleError,
8
17
  SignalWriteError
9
18
  } from "./errors.js";
10
19
  import {
11
20
  NativeAdoptionMiss,
21
+ NATIVE_DOM_VALUE,
22
+ getNativeCandidate,
23
+ forwardNativeTransitionConsumer,
12
24
  getNativeReadObserver,
13
25
  getNativeAdoptionResolver,
14
26
  isNativeWriteGuarded,
15
27
  reportNativeRead,
16
28
  setNativeReadObserver
17
29
  } from "./read-protocol.js";
30
+ import {
31
+ SIGNAL_BINDING_READ,
32
+ SIGNAL_BINDING_SUBSCRIBE,
33
+ SIGNAL_BINDING_IDENTITY,
34
+ SIGNAL_HANDLE
35
+ } from "./types.js";
36
+ import { CandidateUnsupportedError } from "./transition-state.js";
18
37
  const ReactiveFlags = {
19
38
  None: 0,
20
39
  Mutable: 1,
@@ -53,7 +72,15 @@ const graph = createReactiveSystem({
53
72
  node.flags |= ReactiveFlags.Dirty;
54
73
  }
55
74
  node.owner.trace("invalidate", node);
56
- if (node.kind === "async") queued.add(node);
75
+ if (node.invalidateAttempt) {
76
+ if (deferCandidateInvalidation) {
77
+ const invalidate = node.invalidateAttempt;
78
+ queued.add(() => {
79
+ if (node.invalidateAttempt === invalidate) invalidate();
80
+ });
81
+ } else node.invalidateAttempt();
82
+ queued.add(node);
83
+ } else if (node.kind === "async") queued.add(node);
57
84
  } else {
58
85
  queued.add(node);
59
86
  }
@@ -94,6 +121,9 @@ function untrack(run) {
94
121
  setNativeReadObserver(previousObserver);
95
122
  }
96
123
  }
124
+ function untrackCommitted(run) {
125
+ return withoutSignalCandidate(() => untrack(run));
126
+ }
97
127
  function startSignalBatch() {
98
128
  batchDepth++;
99
129
  }
@@ -171,6 +201,16 @@ function pendingState(waiting, connection = "none", requestKey, resolveWaiting)
171
201
  ...resolveWaiting ? { resolveWaiting } : {}
172
202
  };
173
203
  }
204
+ function idleState() {
205
+ return {
206
+ snapshot: {
207
+ status: "idle",
208
+ refreshing: false,
209
+ connection: "none",
210
+ complete: false
211
+ }
212
+ };
213
+ }
174
214
  function sameOwners(a, b) {
175
215
  if (a.owners === b.owners) return true;
176
216
  if ((a.owners?.size ?? 0) !== (b.owners?.size ?? 0)) return false;
@@ -270,6 +310,9 @@ class ScopedNode {
270
310
  owner;
271
311
  key;
272
312
  kind;
313
+ get [SIGNAL_HANDLE]() {
314
+ return true;
315
+ }
273
316
  deps;
274
317
  depsTail;
275
318
  subs;
@@ -278,6 +321,7 @@ class ScopedNode {
278
321
  revision = 0;
279
322
  state;
280
323
  compute;
324
+ invalidateAttempt;
281
325
  last;
282
326
  lastState;
283
327
  hasLast = false;
@@ -291,18 +335,49 @@ class ScopedNode {
291
335
  throw new TypeError("Only an async signal can be retried.");
292
336
  }
293
337
  get() {
294
- return strictValue(readNode(this));
338
+ return strictValue(readNode(this), this.key);
339
+ }
340
+ [SIGNAL_BINDING_READ]() {
341
+ return readSignalBinding(this);
342
+ }
343
+ [SIGNAL_BINDING_SUBSCRIBE](notify, onRetire) {
344
+ assertAlive(this.owner);
345
+ return attachObserver(
346
+ this,
347
+ onRetire === void 0 ? notify : forwardNativeTransitionConsumer(
348
+ notify,
349
+ () => this.owner.retired ? onRetire() : notify()
350
+ ),
351
+ true
352
+ );
353
+ }
354
+ [SIGNAL_BINDING_IDENTITY]() {
355
+ return { scope: "instance", nodeKey: this.key };
356
+ }
357
+ [NATIVE_DOM_VALUE]() {
358
+ return this.get();
295
359
  }
296
360
  set(value) {
297
361
  assertAlive(this.owner);
298
362
  assertWritable();
299
363
  if (this.kind !== "signal") throw new TypeError("Only a writable signal accepts set().");
364
+ const candidate = activeCandidate ?? getNativeCandidate();
365
+ if (candidate) {
366
+ candidate.run(() => candidate.write(this, value));
367
+ return;
368
+ }
300
369
  signalBatch(() => {
301
- const previous = strictValue(refreshNode(this));
370
+ const previous = strictValue(refreshNode(this), this.key);
302
371
  const next = typeof value === "function" ? untrack(() => pure(() => value(previous))) : value;
303
- if (Object.is(previous, next)) return;
304
- publishNode(this, readyState(next));
305
- this.owner.trace("write", this);
372
+ const releases = candidateWriteCount ? recordCandidateUrgentWrite(this, value) : void 0;
373
+ try {
374
+ if (!Object.is(previous, next)) {
375
+ publishNode(this, readyState(next));
376
+ this.owner.trace("write", this);
377
+ }
378
+ } finally {
379
+ if (releases) for (const release of releases) release();
380
+ }
306
381
  });
307
382
  }
308
383
  latest(fallback) {
@@ -352,8 +427,21 @@ function inspectNativeNode(node, read) {
352
427
  dependencies
353
428
  };
354
429
  }
430
+ function createNativeSource(node, read) {
431
+ return {
432
+ getVersion: () => activeCandidate && !activeCandidate.observes(node) ? NaN : node.revision,
433
+ subscribe: (notify) => {
434
+ assertAlive(node.owner);
435
+ return attachObserver(node, notify, true);
436
+ },
437
+ serialize: (revision) => node.revision === revision ? node.owner.serializeRead(node, read) : void 0,
438
+ inspect: () => inspectNativeNode(node, read)
439
+ };
440
+ }
355
441
  function readNode(node, read = "value") {
356
442
  assertAlive(node.owner);
443
+ const candidate = activeCandidate;
444
+ if (candidate) node = candidate.resolve(node);
357
445
  const historical = historicalReader?.(node, read);
358
446
  if (historical) return historical;
359
447
  if (!historicalReader && node.owner.seedable) {
@@ -365,27 +453,35 @@ function readNode(node, read = "value") {
365
453
  if (activeNode) graph.link(node, activeNode, trackingCycle);
366
454
  if (getNativeReadObserver()) {
367
455
  const field = read === "value" ? "nativeSource" : read === "latest" ? "nativeLatestSource" : "nativeSnapshotSource";
368
- const source = node[field] ??= {
369
- getVersion: () => node.revision,
370
- subscribe: (notify) => {
371
- assertAlive(node.owner);
372
- return attachObserver(node, notify, true);
373
- },
374
- serialize: (revision) => node.revision === revision ? node.owner.serializeRead(node, read) : void 0,
375
- inspect: () => inspectNativeNode(node, read)
376
- };
377
- reportNativeRead(source, node.revision);
456
+ const source = node[field] ??= createNativeSource(node, read);
457
+ reportNativeRead(
458
+ candidate ? candidate.nativeSource(node, read, source) : source,
459
+ node.revision
460
+ );
378
461
  }
379
462
  if (observed.owners) for (const owner of observed.owners) assertAlive(owner);
380
463
  if (activeNode) recordOwners(node, observed);
381
464
  return observed;
382
465
  }
383
- function strictValue(state) {
466
+ function strictValue(state, key = "idle") {
384
467
  const snapshot = state.snapshot;
385
468
  if (snapshot.status === "ready") return snapshot.value;
386
469
  if (snapshot.status === "error") throw snapshot.error;
470
+ if (snapshot.status === "idle") throw new SignalIdleError(key);
387
471
  throw state.waiting;
388
472
  }
473
+ function readSignalBinding(handle$) {
474
+ const resolveAdoption = getNativeAdoptionResolver();
475
+ if ((historicalReader || resolveAdoption) && handle$ instanceof ScopedNode && handle$.owner.seedable && (historicalReader || resolveAdoption?.(handle$.owner))) {
476
+ return handle$.get();
477
+ }
478
+ const observer = setNativeReadObserver(null);
479
+ try {
480
+ return handle$.get();
481
+ } finally {
482
+ setNativeReadObserver(observer);
483
+ }
484
+ }
389
485
  function refreshNode(node) {
390
486
  assertAlive(node.owner);
391
487
  if (node.evaluating) throw new SignalCycleError(node.key);
@@ -428,7 +524,7 @@ function evaluate(node) {
428
524
  let next;
429
525
  let owners;
430
526
  try {
431
- next = node.compute();
527
+ next = node.compute(node);
432
528
  } catch (error) {
433
529
  if (isThenable(error)) {
434
530
  const wakeup = node.wakeup ??= createWakeup();
@@ -497,9 +593,17 @@ function invalidateNode(node) {
497
593
  function derivedState(node, read) {
498
594
  const value = pure(read);
499
595
  if (isThenable(value)) throw new TypeError("derived$ requires a synchronous computation.");
596
+ return derivedValueState(node, value);
597
+ }
598
+ function derivedValueState(node, value, activity, additionalDependencies) {
500
599
  let refreshing = false;
501
600
  let complete = true;
502
601
  let connection = "none";
602
+ if (activity) {
603
+ refreshing = activity.refreshing;
604
+ complete = activity.complete;
605
+ connection = activity.connection;
606
+ }
503
607
  for (let link = node.deps; link && node.depsTail; link = link.nextDep) {
504
608
  const dependency = link.dep.state?.snapshot;
505
609
  if (dependency) {
@@ -512,6 +616,18 @@ function derivedState(node, read) {
512
616
  }
513
617
  if (link === node.depsTail) break;
514
618
  }
619
+ if (additionalDependencies) {
620
+ for (const node2 of additionalDependencies) {
621
+ const dependency = node2.state?.snapshot;
622
+ if (!dependency) continue;
623
+ refreshing ||= dependency.refreshing;
624
+ complete &&= dependency.complete;
625
+ if (dependency.connection === "open") connection = "open";
626
+ else if (connection !== "open" && dependency.connection === "connecting")
627
+ connection = "connecting";
628
+ else if (connection === "none" && dependency.connection === "closed") connection = "closed";
629
+ }
630
+ }
515
631
  return readyState(value, { refreshing, complete, connection });
516
632
  }
517
633
  class SignalObserver {
@@ -535,6 +651,10 @@ function attachObserver(node, notify, native, state) {
535
651
  node.owner.observers.add(observer);
536
652
  return () => stopObserver(observer);
537
653
  }
654
+ function subscribeNode(node, notify) {
655
+ const state = untrack(() => refreshNode(node));
656
+ return attachObserver(node, notify, true, state);
657
+ }
538
658
  function runObserver(observer) {
539
659
  const node = observer.node;
540
660
  if (!node || !observer.flags) return;
@@ -574,6 +694,7 @@ function retireGraph(owner, nodes) {
574
694
  node.state = errorState(retirementError);
575
695
  releaseRetention(node);
576
696
  node.compute = void 0;
697
+ node.invalidateAttempt = void 0;
577
698
  if (node.kind === "async") node.retry = ScopedNode.prototype.retry;
578
699
  if (node.subs) {
579
700
  graph.propagate(node.subs, executionDepth !== 0);
@@ -587,14 +708,45 @@ function retireGraph(owner, nodes) {
587
708
  retirementError = previousError;
588
709
  }
589
710
  }
711
+ registerCandidateGraph({
712
+ ScopedNode,
713
+ graph,
714
+ flags: ReactiveFlags,
715
+ historical: () => historicalReader !== void 0,
716
+ link: (from, to) => {
717
+ graph.link(from, to, ++trackingCycle);
718
+ },
719
+ removeQueued: (node) => {
720
+ queued.delete(node);
721
+ },
722
+ assertAlive,
723
+ strictValue,
724
+ refreshNode,
725
+ pure,
726
+ untrack,
727
+ signalBatch,
728
+ publishNode,
729
+ readyState,
730
+ commitState,
731
+ sameState,
732
+ releaseRetainedOwners,
733
+ retainOwners,
734
+ releaseRetention,
735
+ createNativeSource,
736
+ attachObserver
737
+ });
590
738
  export {
739
+ CandidateUnsupportedError,
591
740
  ScopedNode,
592
741
  SignalObserver,
593
742
  assertAlive,
594
743
  assertWritable,
744
+ attachObserver,
595
745
  derivedState,
746
+ derivedValueState,
596
747
  endSignalBatch,
597
748
  errorState,
749
+ idleState,
598
750
  inspectNativeNode,
599
751
  invalidateNode,
600
752
  isThenable,
@@ -602,6 +754,7 @@ export {
602
754
  publishNode,
603
755
  pure,
604
756
  readNode,
757
+ readSignalBinding,
605
758
  readyState,
606
759
  refreshNode,
607
760
  releaseRetention,
@@ -612,5 +765,7 @@ export {
612
765
  startSignalBatch,
613
766
  stopObserver,
614
767
  strictValue,
615
- untrack
768
+ subscribeNode,
769
+ untrack,
770
+ untrackCommitted
616
771
  };
@@ -0,0 +1,4 @@
1
+ import { type SignalHandle, type WritableSignal } from './types.js';
2
+ /** Native handle capability checks must not import the graph or create an owner. */
3
+ export declare function isSignalHandle(value: unknown): value is SignalHandle<unknown>;
4
+ export declare function isWritableSignal(value: unknown): value is WritableSignal<unknown>;
@@ -0,0 +1,11 @@
1
+ import { SIGNAL_HANDLE } from "./types.js";
2
+ function isSignalHandle(value) {
3
+ return (typeof value === "object" || typeof value === "function") && value !== null && value[SIGNAL_HANDLE] === true;
4
+ }
5
+ function isWritableSignal(value) {
6
+ return isSignalHandle(value) && value.kind === "signal" && typeof value.set === "function";
7
+ }
8
+ export {
9
+ isSignalHandle,
10
+ isWritableSignal
11
+ };
@@ -1,5 +1,14 @@
1
1
  /** Stable scoped signals. This entry does not import a renderer. */
2
2
  export { createScope } from './engine.js';
3
- export { query } from './requests.js';
4
- export { ScopeDisposedError, SignalCycleError, SignalFrameError, SignalSerializationError, SignalWriteError, } from './errors.js';
5
- export type { SIGNAL_HANDLE, QUERY_REQUEST, AdoptionFrame, ConnectionState, DerivedSignal, EncodedSignalValue, Query, QueryContext, QueryRequest, Resource, Scope, ScopeInspection, ScopeOptions, ScopeSeed, SignalHandle, SignalSeedEntry, SignalSnapshot, SignalTraceEvent, WritableSignal, } from './types.js';
3
+ export { bindSignalControl } from './control-binding.js';
4
+ export { enableSignalDocument as __enableSignalDocument } from './document-owner.js';
5
+ export { createResource, query } from './requests.js';
6
+ export { ActionUncertainError, action$, isActionUncertain, optimistic$ } from './actions.js';
7
+ export { __derivedAt, derived$ } from './derived-facade.js';
8
+ export { __queryAt, query$ } from './query-facade.js';
9
+ export { isSignalHandle, isWritableSignal } from './handle-protocol.js';
10
+ export { __derivedScalarAt, __signalAt, __startSignalReads, acceptStreamedSignalResult, attachStreamedSignalResult, bindStreamedSignalSelection, readSignalBinding, failStreamedSignalResult, signal$, } from './facade.js';
11
+ export { captureSignalOwner, currentSignalOwner, installSignalOwnerEnvironment, retireSignalOwnerIdentity, runWithSignalOwner, } from './owner-context.js';
12
+ export { ScopeDisposedError, SignalCycleError, SignalFrameError, SignalIdleError, SignalSerializationError, SignalStreamError, SignalWriteError, } from './errors.js';
13
+ export { QUERY_REQUEST, SIGNAL_BINDING_IDENTITY, SIGNAL_BINDING_READ, SIGNAL_BINDING_SUBSCRIBE, SIGNAL_HANDLE, skip, } from './types.js';
14
+ export type { AdoptionFrame, ActionOperation, ActionUncertain, ConnectionState, DerivedCompute, DerivedContext, DerivedOptions, DerivedSignal, EncodedSignalValue, Query, QueryContext, QueryLoadResult, QueryOptions, QueryRequest, QuerySignal, Resource, OptimisticOptions, OptimisticSignal, Scope, ScopeInspection, ScopeOptions, ScopeSeed, SignalHandle, SignalOptions, SignalBindingIdentity, SignalAction, SignalOwner, SignalOwnerEnvironment, SignalOwnerIdentity, SignalRendererOwnerIdentity, SignalSeedEntry, SignalSnapshot, SignalTraceEvent, WritableSignal, } from './types.js';
@@ -1,18 +1,87 @@
1
1
  import { createScope } from "./engine.js";
2
- import { query } from "./requests.js";
2
+ import { bindSignalControl } from "./control-binding.js";
3
+ import { enableSignalDocument } from "./document-owner.js";
4
+ import { createResource, query } from "./requests.js";
5
+ import { ActionUncertainError, action$, isActionUncertain, optimistic$ } from "./actions.js";
6
+ import { __derivedAt, derived$ } from "./derived-facade.js";
7
+ import { __queryAt, query$ } from "./query-facade.js";
8
+ import { isSignalHandle, isWritableSignal } from "./handle-protocol.js";
9
+ import {
10
+ __derivedScalarAt,
11
+ __signalAt,
12
+ __startSignalReads,
13
+ acceptStreamedSignalResult,
14
+ attachStreamedSignalResult,
15
+ bindStreamedSignalSelection,
16
+ readSignalBinding,
17
+ failStreamedSignalResult,
18
+ signal$
19
+ } from "./facade.js";
20
+ import {
21
+ captureSignalOwner,
22
+ currentSignalOwner,
23
+ installSignalOwnerEnvironment,
24
+ retireSignalOwnerIdentity,
25
+ runWithSignalOwner
26
+ } from "./owner-context.js";
3
27
  import {
4
28
  ScopeDisposedError,
5
29
  SignalCycleError,
6
30
  SignalFrameError,
31
+ SignalIdleError,
7
32
  SignalSerializationError,
33
+ SignalStreamError,
8
34
  SignalWriteError
9
35
  } from "./errors.js";
36
+ import {
37
+ QUERY_REQUEST,
38
+ SIGNAL_BINDING_IDENTITY,
39
+ SIGNAL_BINDING_READ,
40
+ SIGNAL_BINDING_SUBSCRIBE,
41
+ SIGNAL_HANDLE,
42
+ skip
43
+ } from "./types.js";
10
44
  export {
45
+ ActionUncertainError,
46
+ QUERY_REQUEST,
47
+ SIGNAL_BINDING_IDENTITY,
48
+ SIGNAL_BINDING_READ,
49
+ SIGNAL_BINDING_SUBSCRIBE,
50
+ SIGNAL_HANDLE,
11
51
  ScopeDisposedError,
12
52
  SignalCycleError,
13
53
  SignalFrameError,
54
+ SignalIdleError,
14
55
  SignalSerializationError,
56
+ SignalStreamError,
15
57
  SignalWriteError,
58
+ __derivedAt,
59
+ __derivedScalarAt,
60
+ enableSignalDocument as __enableSignalDocument,
61
+ __queryAt,
62
+ __signalAt,
63
+ __startSignalReads,
64
+ acceptStreamedSignalResult,
65
+ action$,
66
+ attachStreamedSignalResult,
67
+ bindSignalControl,
68
+ bindStreamedSignalSelection,
69
+ captureSignalOwner,
70
+ createResource,
16
71
  createScope,
17
- query
72
+ currentSignalOwner,
73
+ derived$,
74
+ failStreamedSignalResult,
75
+ installSignalOwnerEnvironment,
76
+ isActionUncertain,
77
+ isSignalHandle,
78
+ isWritableSignal,
79
+ optimistic$,
80
+ query,
81
+ query$,
82
+ readSignalBinding,
83
+ retireSignalOwnerIdentity,
84
+ runWithSignalOwner,
85
+ signal$,
86
+ skip
18
87
  };
@@ -4,6 +4,9 @@ interface NativeReadHost {
4
4
  capture(): object | null;
5
5
  cleanup(scope: Scope, dispose: () => void): void;
6
6
  schedule(block: Block): void;
7
+ /** Candidate admission renders this exact subscribed owner without notifying it. */
8
+ prepare?(block: Block): void;
9
+ retire?(block: Block): void;
7
10
  /** Reuse current ref manifests after a superseding root commits. */
8
11
  replayRefs(capture: object, owner: PublicationOwner): boolean;
9
12
  refDisposed(entry: object): boolean;
@@ -2,6 +2,7 @@ import {
2
2
  createNativeReadCollector,
3
3
  validateNativeReadWitness
4
4
  } from "./native-read-collector.js";
5
+ import { NATIVE_TRANSITION_CONSUMER } from "./read-protocol.js";
5
6
  import { inspectNativeReadWitness } from "./native-read-inspection.js";
6
7
  function createNativeReadDriver(host) {
7
8
  const consumers = /* @__PURE__ */ new WeakMap();
@@ -37,6 +38,7 @@ function createNativeReadDriver(host) {
37
38
  function disposeConsumer(consumer) {
38
39
  if (consumer.disposed) return;
39
40
  consumer.disposed = true;
41
+ host.retire?.(consumer.block);
40
42
  if (consumer.committed !== null) release(consumer.committed);
41
43
  consumer.committed = null;
42
44
  for (const candidate of consumer.pending) release(candidate);
@@ -59,6 +61,14 @@ function createNativeReadDriver(host) {
59
61
  };
60
62
  consumers.set(scope, consumer);
61
63
  const owned = consumer;
64
+ if (host.prepare !== void 0) {
65
+ Object.assign(owned.notify, {
66
+ [NATIVE_TRANSITION_CONSUMER]: {
67
+ active: () => !owned.disposed && !owned.block.disposed,
68
+ prepare: () => host.prepare(owned.block)
69
+ }
70
+ });
71
+ }
62
72
  host.cleanup(scope, () => disposeConsumer(owned));
63
73
  }
64
74
  return consumer;
@@ -0,0 +1,22 @@
1
+ import type { SignalOwner, SignalOwnerEnvironment } from './types.js';
2
+ declare let installedEnvironment: SignalOwnerEnvironment | undefined;
3
+ declare let synchronousOwner: SignalOwner | null;
4
+ /** @internal Live capability guards; reading them never installs a default owner. */
5
+ export { installedEnvironment as activeSignalOwnerEnvironment, synchronousOwner as activeSynchronousSignalOwner, };
6
+ /** Install a concurrency-safe owner carrier without importing the signal engine. */
7
+ export declare function installSignalOwnerEnvironment(environment: SignalOwnerEnvironment): () => void;
8
+ export declare function currentSignalOwner(): SignalOwner | null;
9
+ /** @internal Distinguish an active owner frame from the lazy document fallback. */
10
+ export declare function currentExplicitSignalOwner(): SignalOwner | null;
11
+ /** @internal Client renderer installs its lazy document owner, never a last-root owner. */
12
+ export declare function installDefaultSignalOwner(current: () => SignalOwner | null): () => void;
13
+ /** Enter an owner for a synchronous declaration, read, write, or callback. */
14
+ export declare function runWithSignalOwner<T>(owner: SignalOwner, callback: () => T): T;
15
+ /** @internal Synchronous SSR entry without retaining a callback frame per component. */
16
+ export declare function enterSynchronousSignalOwner(owner: SignalOwner): SignalOwner | null | undefined;
17
+ /** @internal Pair with a successful synchronous entry in a finally block. */
18
+ export declare function restoreSynchronousSignalOwner(previous: SignalOwner | null): void;
19
+ export declare function captureSignalOwner(owner: SignalOwner): <T>(callback: () => T) => T;
20
+ /** Retire renderer-created identity state without linking the renderer to the engine. */
21
+ export declare function retireSignalOwnerIdentity(owner: SignalOwner): void;
22
+ export declare function installSignalOwnerRetirement(retire: (owner: SignalOwner) => void): () => void;
@@ -0,0 +1,77 @@
1
+ let installedEnvironment;
2
+ let synchronousOwner = null;
3
+ let defaultOwner;
4
+ let retireOwner;
5
+ function installSignalOwnerEnvironment(environment) {
6
+ if (!environment || typeof environment.current !== "function" || typeof environment.run !== "function" || typeof environment.capture !== "function") {
7
+ throw new TypeError("A signal owner environment requires current, run, and capture.");
8
+ }
9
+ const previous = installedEnvironment;
10
+ installedEnvironment = environment;
11
+ return () => {
12
+ if (installedEnvironment === environment) installedEnvironment = previous;
13
+ };
14
+ }
15
+ function currentSignalOwner() {
16
+ if (installedEnvironment !== void 0) return installedEnvironment.current() ?? synchronousOwner;
17
+ return synchronousOwner ?? defaultOwner?.() ?? null;
18
+ }
19
+ function currentExplicitSignalOwner() {
20
+ return installedEnvironment?.current() ?? synchronousOwner;
21
+ }
22
+ function installDefaultSignalOwner(current) {
23
+ if (typeof current !== "function")
24
+ throw new TypeError("A default signal owner requires a provider.");
25
+ const previous = defaultOwner;
26
+ defaultOwner = current;
27
+ return () => {
28
+ if (defaultOwner === current) defaultOwner = previous;
29
+ };
30
+ }
31
+ function runWithSignalOwner(owner, callback) {
32
+ if (typeof callback !== "function") throw new TypeError("A signal owner callback is required.");
33
+ if (installedEnvironment) return installedEnvironment.run(owner, callback);
34
+ const previous = synchronousOwner;
35
+ synchronousOwner = owner;
36
+ try {
37
+ return callback();
38
+ } finally {
39
+ synchronousOwner = previous;
40
+ }
41
+ }
42
+ function enterSynchronousSignalOwner(owner) {
43
+ if (installedEnvironment !== void 0) return void 0;
44
+ const previous = synchronousOwner;
45
+ synchronousOwner = owner;
46
+ return previous;
47
+ }
48
+ function restoreSynchronousSignalOwner(previous) {
49
+ synchronousOwner = previous;
50
+ }
51
+ function captureSignalOwner(owner) {
52
+ return installedEnvironment?.capture(owner) ?? ((callback) => runWithSignalOwner(owner, callback));
53
+ }
54
+ function retireSignalOwnerIdentity(owner) {
55
+ retireOwner?.(owner);
56
+ }
57
+ function installSignalOwnerRetirement(retire) {
58
+ const previous = retireOwner;
59
+ retireOwner = retire;
60
+ return () => {
61
+ if (retireOwner === retire) retireOwner = previous;
62
+ };
63
+ }
64
+ export {
65
+ installedEnvironment as activeSignalOwnerEnvironment,
66
+ synchronousOwner as activeSynchronousSignalOwner,
67
+ captureSignalOwner,
68
+ currentExplicitSignalOwner,
69
+ currentSignalOwner,
70
+ enterSynchronousSignalOwner,
71
+ installDefaultSignalOwner,
72
+ installSignalOwnerEnvironment,
73
+ installSignalOwnerRetirement,
74
+ restoreSynchronousSignalOwner,
75
+ retireSignalOwnerIdentity,
76
+ runWithSignalOwner
77
+ };
@@ -0,0 +1,49 @@
1
+ import type { SignalRendererOwnerIdentity } from './types.js';
2
+ export interface ServerSignalQueryAttempt {
3
+ readonly ownerKey: string;
4
+ readonly instanceKey: string;
5
+ readonly nodeKey: string;
6
+ readonly selectionKey: string;
7
+ readonly attempt: number;
8
+ readonly kind: 'promise' | 'stream';
9
+ readonly result: unknown;
10
+ readonly signal: AbortSignal;
11
+ readonly isCurrent: () => boolean;
12
+ /** Stop retaining and backpressuring this renderer observation. */
13
+ readonly release: () => void;
14
+ }
15
+ export type ServerSignalQueryAttemptObserver = (attempt: ServerSignalQueryAttempt) => void;
16
+ export interface ServerSignalQueryAttemptObserverContext {
17
+ readonly owner: SignalRendererOwnerIdentity;
18
+ readonly observe: ServerSignalQueryAttemptObserver;
19
+ readonly createObservations: () => ServerSignalQueryAttemptObservations;
20
+ }
21
+ export interface ServerSignalQueryAttemptSource {
22
+ readonly nodeKey: string;
23
+ readonly selectionKey: string;
24
+ readonly attempt: number;
25
+ readonly kind: 'promise' | 'stream';
26
+ readonly result: unknown;
27
+ readonly isCurrent: () => boolean;
28
+ }
29
+ /** The shared request engine owns a lease, not the server's transport mirrors. */
30
+ export interface ServerSignalQueryAttemptObservations {
31
+ observe(context: ServerSignalQueryAttemptObserverContext, source: ServerSignalQueryAttemptSource): void;
32
+ publish(value: unknown): Promise<void> | undefined;
33
+ complete(): void;
34
+ fail(error: unknown): void;
35
+ retire(): void;
36
+ }
37
+ /**
38
+ * Install a synchronous renderer observation context around authored server
39
+ * signal work. The context is restored before a returned promise can suspend,
40
+ * so concurrent requests cannot inherit one another's observer.
41
+ *
42
+ * @internal
43
+ */
44
+ export declare function runWithServerSignalQueryAttemptObserver<T>(owner: SignalRendererOwnerIdentity, observe: ServerSignalQueryAttemptObserver, createObservations: () => ServerSignalQueryAttemptObservations, callback: () => T): T;
45
+ /** @internal Keep the browser/query fast path allocation-free when no server observer matches. */
46
+ export declare function serverSignalQueryAttemptObserver(scopeKey: string): ServerSignalQueryAttemptObserverContext | undefined;
47
+ export declare function hasServerSignalQueryAttemptObserver(scopeKey: string): boolean;
48
+ /** @internal Preserve observation across a pending query description, not an async context. */
49
+ export declare function captureCurrentServerSignalQueryAttemptObserver(scopeKey: string): (<T>(callback: () => T) => T) | undefined;