octane 0.2.12 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/README.md +5 -0
  2. package/dist/behavior-root.d.ts +13 -3
  3. package/dist/behavior-root.js +28 -5
  4. package/dist/cjs/behavior-root.cjs +32 -6
  5. package/dist/cjs/class-names.cjs +49 -0
  6. package/dist/cjs/constants.cjs +9 -0
  7. package/dist/cjs/css.cjs +6 -27
  8. package/dist/cjs/data-encoding.cjs +160 -0
  9. package/dist/cjs/dom-binding-handoff.cjs +93 -0
  10. package/dist/cjs/dom-binding-protocol.cjs +115 -0
  11. package/dist/cjs/dom-binding-styles.cjs +292 -0
  12. package/dist/cjs/dom-bindings.cjs +700 -0
  13. package/dist/cjs/dom-focused-move.cjs +66 -0
  14. package/dist/cjs/dom-tables.cjs +4 -94
  15. package/dist/cjs/error-codes.client.generated.cjs +33 -0
  16. package/dist/cjs/error-codes.server.generated.cjs +19 -0
  17. package/dist/cjs/hydration/control-capture.cjs +244 -0
  18. package/dist/cjs/hydration/event-capture.cjs +125 -43
  19. package/dist/cjs/hydration/interaction-config.cjs +50 -2
  20. package/dist/cjs/hydration-markers.cjs +37 -0
  21. package/dist/cjs/independent-hydration-protocol.cjs +106 -0
  22. package/dist/cjs/index.cjs +6 -0
  23. package/dist/cjs/runtime.cjs +2791 -215
  24. package/dist/cjs/runtime.server.cjs +716 -76
  25. package/dist/cjs/server/early-signals.cjs +45 -0
  26. package/dist/cjs/server/index.cjs +44 -0
  27. package/dist/cjs/server/rpc-batch.cjs +149 -0
  28. package/dist/cjs/server/rpc-stream.cjs +146 -0
  29. package/dist/cjs/server/rpc.cjs +34 -15
  30. package/dist/cjs/server/signal-query-observation.cjs +158 -0
  31. package/dist/cjs/server/streamed-region.cjs +52 -0
  32. package/dist/cjs/server/streamed-signals.cjs +512 -0
  33. package/dist/cjs/server-call.cjs +103 -0
  34. package/dist/cjs/server-rpc-batch-client.cjs +141 -0
  35. package/dist/cjs/server-rpc-client.cjs +94 -27
  36. package/dist/cjs/server-rpc-protocol.cjs +141 -0
  37. package/dist/cjs/server-rpc-stream-client.cjs +118 -0
  38. package/dist/cjs/signals/actions.cjs +474 -0
  39. package/dist/cjs/signals/client.cjs +4 -1
  40. package/dist/cjs/signals/computations.cjs +460 -0
  41. package/dist/cjs/signals/control-binding.cjs +368 -0
  42. package/dist/cjs/signals/derived-facade.cjs +50 -0
  43. package/dist/cjs/signals/document-owner.cjs +71 -0
  44. package/dist/cjs/signals/early-values.cjs +155 -0
  45. package/dist/cjs/signals/encoding.cjs +6 -95
  46. package/dist/cjs/signals/engine.cjs +276 -12
  47. package/dist/cjs/signals/errors.cjs +18 -0
  48. package/dist/cjs/signals/facade.cjs +477 -0
  49. package/dist/cjs/signals/graph.cjs +163 -20
  50. package/dist/cjs/signals/handle-protocol.cjs +36 -0
  51. package/dist/cjs/signals/index.cjs +81 -2
  52. package/dist/cjs/signals/native-read-client.cjs +10 -0
  53. package/dist/cjs/signals/owner-context.cjs +112 -0
  54. package/dist/cjs/signals/query-attempt-observer.cjs +68 -0
  55. package/dist/cjs/signals/query-facade.cjs +72 -0
  56. package/dist/cjs/signals/read-protocol.cjs +32 -0
  57. package/dist/cjs/signals/requests.cjs +287 -14
  58. package/dist/cjs/signals/scalar-computations.cjs +76 -0
  59. package/dist/cjs/signals/server.cjs +4 -1
  60. package/dist/cjs/signals/transition-candidate.cjs +567 -0
  61. package/dist/cjs/signals/transition-state.cjs +106 -0
  62. package/dist/cjs/signals/types.cjs +50 -0
  63. package/dist/cjs/stream-protocol.cjs +3 -0
  64. package/dist/cjs/streamed-signals-protocol.cjs +159 -0
  65. package/dist/cjs/style-values.cjs +122 -0
  66. package/dist/cjs/version.cjs +1 -1
  67. package/dist/class-names.d.ts +5 -0
  68. package/dist/class-names.js +25 -0
  69. package/dist/compiler/bundler.js +34 -6
  70. package/dist/compiler/compile.js +2234 -559
  71. package/dist/compiler/dom-binding-program.js +935 -0
  72. package/dist/compiler/dom-binding-request.js +57 -0
  73. package/dist/compiler/dom-bindings.js +2245 -0
  74. package/dist/compiler/hook-deps.js +26 -0
  75. package/dist/compiler/hydrate-boundaries.js +358 -15
  76. package/dist/compiler/index.d.ts +38 -1
  77. package/dist/compiler/index.js +1 -0
  78. package/dist/compiler/native-attribute-reads.js +127 -0
  79. package/dist/compiler/native-read-diagnostics.js +48 -9
  80. package/dist/compiler/native-read-types.js +55 -32
  81. package/dist/compiler/server-context.js +118 -0
  82. package/dist/compiler/signal-attempt-reads.js +479 -0
  83. package/dist/compiler/signal-declarations.js +557 -0
  84. package/dist/compiler/signal-start-reads.js +413 -0
  85. package/dist/compiler/slot-hooks.js +57 -10
  86. package/dist/compiler/template-ir.js +200 -0
  87. package/dist/compiler/typescript.d.ts +2 -0
  88. package/dist/compiler/typescript.js +2 -0
  89. package/dist/compiler/vite.d.ts +3 -1
  90. package/dist/compiler/vite.js +122 -4
  91. package/dist/compiler/volar.d.ts +6 -1
  92. package/dist/compiler/volar.js +674 -143
  93. package/dist/constants.d.ts +1 -0
  94. package/dist/constants.js +10 -0
  95. package/dist/css.d.ts +2 -5
  96. package/dist/css.js +2 -23
  97. package/dist/data-encoding.d.ts +9 -0
  98. package/dist/data-encoding.js +134 -0
  99. package/dist/dom-binding-classes.d.ts +15 -0
  100. package/dist/dom-binding-classes.js +129 -0
  101. package/dist/dom-binding-controls.d.ts +2 -0
  102. package/dist/dom-binding-controls.js +6 -0
  103. package/dist/dom-binding-handoff.d.ts +55 -0
  104. package/dist/dom-binding-handoff.js +62 -0
  105. package/dist/dom-binding-program.d.ts +300 -0
  106. package/dist/dom-binding-program.js +1625 -0
  107. package/dist/dom-binding-projections.d.ts +15 -0
  108. package/dist/dom-binding-projections.js +187 -0
  109. package/dist/dom-binding-protocol.d.ts +13 -0
  110. package/dist/dom-binding-protocol.js +88 -0
  111. package/dist/dom-binding-signals.d.ts +21 -0
  112. package/dist/dom-binding-signals.js +109 -0
  113. package/dist/dom-binding-styles.d.ts +17 -0
  114. package/dist/dom-binding-styles.js +272 -0
  115. package/dist/dom-bindings.d.ts +89 -0
  116. package/dist/dom-bindings.js +670 -0
  117. package/dist/dom-focused-move.d.ts +6 -0
  118. package/dist/dom-focused-move.js +42 -0
  119. package/dist/dom-tables.d.ts +1 -3
  120. package/dist/dom-tables.js +1 -91
  121. package/dist/error-codes.client.generated.d.ts +9 -0
  122. package/dist/error-codes.client.generated.js +33 -0
  123. package/dist/error-codes.server.generated.d.ts +5 -0
  124. package/dist/error-codes.server.generated.js +19 -0
  125. package/dist/hydration/control-capture.d.ts +62 -0
  126. package/dist/hydration/control-capture.js +223 -0
  127. package/dist/hydration/document-lifecycle.d.ts +23 -0
  128. package/dist/hydration/document-lifecycle.js +80 -0
  129. package/dist/hydration/event-capture.d.ts +20 -1
  130. package/dist/hydration/event-capture.js +128 -42
  131. package/dist/hydration/independent-island.d.ts +45 -0
  132. package/dist/hydration/independent-island.js +233 -0
  133. package/dist/hydration/index.d.ts +8 -1
  134. package/dist/hydration/index.js +55 -1
  135. package/dist/hydration/interaction-config.d.ts +5 -0
  136. package/dist/hydration/interaction-config.js +44 -1
  137. package/dist/hydration/stream-delivery.d.ts +32 -0
  138. package/dist/hydration/stream-delivery.js +333 -0
  139. package/dist/hydration/stream-receiver.d.ts +26 -0
  140. package/dist/hydration/stream-receiver.js +204 -0
  141. package/dist/hydration/stream-result-receiver.d.ts +70 -0
  142. package/dist/hydration/stream-result-receiver.js +246 -0
  143. package/dist/hydration/streamed-signals.d.ts +44 -0
  144. package/dist/hydration/streamed-signals.js +186 -0
  145. package/dist/hydration/types.d.ts +6 -0
  146. package/dist/hydration-markers.d.ts +7 -0
  147. package/dist/hydration-markers.js +10 -0
  148. package/dist/independent-hydration-protocol.d.ts +31 -0
  149. package/dist/independent-hydration-protocol.js +80 -0
  150. package/dist/index.d.ts +2 -0
  151. package/dist/index.js +4 -0
  152. package/dist/internal/signal-read.d.ts +1 -0
  153. package/dist/internal/signal-read.js +4 -0
  154. package/dist/jsx-runtime.d.ts +45 -6
  155. package/dist/public-types.d.ts +15 -1
  156. package/dist/runtime.d.ts +259 -21
  157. package/dist/runtime.js +2812 -220
  158. package/dist/runtime.server.d.ts +86 -6
  159. package/dist/runtime.server.js +712 -76
  160. package/dist/server/early-signals.d.ts +14 -0
  161. package/dist/server/early-signals.js +34 -0
  162. package/dist/server/index.d.ts +10 -2
  163. package/dist/server/index.js +48 -1
  164. package/dist/server/rpc-batch.d.ts +17 -0
  165. package/dist/server/rpc-batch.js +129 -0
  166. package/dist/server/rpc-stream.d.ts +9 -0
  167. package/dist/server/rpc-stream.js +125 -0
  168. package/dist/server/rpc.d.ts +5 -1
  169. package/dist/server/rpc.js +37 -13
  170. package/dist/server/signal-query-observation.d.ts +3 -0
  171. package/dist/server/signal-query-observation.js +134 -0
  172. package/dist/server/streamed-region.d.ts +15 -0
  173. package/dist/server/streamed-region.js +30 -0
  174. package/dist/server/streamed-signals.d.ts +45 -0
  175. package/dist/server/streamed-signals.js +488 -0
  176. package/dist/server-call.d.ts +41 -0
  177. package/dist/server-call.js +75 -0
  178. package/dist/server-rpc-batch-client.d.ts +7 -0
  179. package/dist/server-rpc-batch-client.js +119 -0
  180. package/dist/server-rpc-client.d.ts +3 -1
  181. package/dist/server-rpc-client.js +99 -27
  182. package/dist/server-rpc-protocol.d.ts +47 -0
  183. package/dist/server-rpc-protocol.js +109 -0
  184. package/dist/server-rpc-stream-client.d.ts +5 -0
  185. package/dist/server-rpc-stream-client.js +98 -0
  186. package/dist/signals/actions.d.ts +12 -0
  187. package/dist/signals/actions.js +466 -0
  188. package/dist/signals/client.d.ts +2 -0
  189. package/dist/signals/client.js +1 -0
  190. package/dist/signals/computations.d.ts +37 -0
  191. package/dist/signals/computations.js +455 -0
  192. package/dist/signals/control-binding.d.ts +31 -0
  193. package/dist/signals/control-binding.js +353 -0
  194. package/dist/signals/derived-facade.d.ts +3 -0
  195. package/dist/signals/derived-facade.js +25 -0
  196. package/dist/signals/document-owner.d.ts +10 -0
  197. package/dist/signals/document-owner.js +43 -0
  198. package/dist/signals/early-values.d.ts +24 -0
  199. package/dist/signals/early-values.js +124 -0
  200. package/dist/signals/encoding.d.ts +1 -3
  201. package/dist/signals/encoding.js +3 -93
  202. package/dist/signals/engine.d.ts +53 -4
  203. package/dist/signals/engine.js +275 -16
  204. package/dist/signals/errors.d.ts +7 -0
  205. package/dist/signals/errors.js +16 -0
  206. package/dist/signals/facade.d.ts +74 -0
  207. package/dist/signals/facade.js +452 -0
  208. package/dist/signals/graph.d.ts +50 -5
  209. package/dist/signals/graph.js +170 -19
  210. package/dist/signals/handle-protocol.d.ts +4 -0
  211. package/dist/signals/handle-protocol.js +11 -0
  212. package/dist/signals/index.d.ts +12 -3
  213. package/dist/signals/index.js +71 -2
  214. package/dist/signals/native-read-client.d.ts +3 -0
  215. package/dist/signals/native-read-client.js +10 -0
  216. package/dist/signals/owner-context.d.ts +22 -0
  217. package/dist/signals/owner-context.js +77 -0
  218. package/dist/signals/query-attempt-observer.d.ts +49 -0
  219. package/dist/signals/query-attempt-observer.js +41 -0
  220. package/dist/signals/query-facade.d.ts +3 -0
  221. package/dist/signals/query-facade.js +49 -0
  222. package/dist/signals/read-protocol.d.ts +32 -3
  223. package/dist/signals/read-protocol.js +26 -0
  224. package/dist/signals/requests.d.ts +38 -5
  225. package/dist/signals/requests.js +298 -15
  226. package/dist/signals/scalar-computations.d.ts +2 -0
  227. package/dist/signals/scalar-computations.js +60 -0
  228. package/dist/signals/server.d.ts +2 -0
  229. package/dist/signals/server.js +1 -0
  230. package/dist/signals/transition-candidate.d.ts +71 -0
  231. package/dist/signals/transition-candidate.js +557 -0
  232. package/dist/signals/transition-state.d.ts +51 -0
  233. package/dist/signals/transition-state.js +70 -0
  234. package/dist/signals/types.d.ts +95 -5
  235. package/dist/signals/types.js +20 -0
  236. package/dist/stream-protocol.d.ts +0 -5
  237. package/dist/stream-protocol.js +3 -0
  238. package/dist/streamed-signals-protocol.d.ts +60 -0
  239. package/dist/streamed-signals-protocol.js +130 -0
  240. package/dist/style-values.d.ts +3 -0
  241. package/dist/style-values.js +96 -0
  242. package/dist/version.js +1 -1
  243. package/package.json +37 -1
@@ -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,17 +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,
12
21
  NATIVE_DOM_VALUE,
22
+ getNativeCandidate,
23
+ forwardNativeTransitionConsumer,
13
24
  getNativeReadObserver,
14
25
  getNativeAdoptionResolver,
15
26
  isNativeWriteGuarded,
16
27
  reportNativeRead,
17
28
  setNativeReadObserver
18
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";
19
37
  const ReactiveFlags = {
20
38
  None: 0,
21
39
  Mutable: 1,
@@ -54,7 +72,15 @@ const graph = createReactiveSystem({
54
72
  node.flags |= ReactiveFlags.Dirty;
55
73
  }
56
74
  node.owner.trace("invalidate", node);
57
- 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);
58
84
  } else {
59
85
  queued.add(node);
60
86
  }
@@ -95,6 +121,9 @@ function untrack(run) {
95
121
  setNativeReadObserver(previousObserver);
96
122
  }
97
123
  }
124
+ function untrackCommitted(run) {
125
+ return withoutSignalCandidate(() => untrack(run));
126
+ }
98
127
  function startSignalBatch() {
99
128
  batchDepth++;
100
129
  }
@@ -172,6 +201,16 @@ function pendingState(waiting, connection = "none", requestKey, resolveWaiting)
172
201
  ...resolveWaiting ? { resolveWaiting } : {}
173
202
  };
174
203
  }
204
+ function idleState() {
205
+ return {
206
+ snapshot: {
207
+ status: "idle",
208
+ refreshing: false,
209
+ connection: "none",
210
+ complete: false
211
+ }
212
+ };
213
+ }
175
214
  function sameOwners(a, b) {
176
215
  if (a.owners === b.owners) return true;
177
216
  if ((a.owners?.size ?? 0) !== (b.owners?.size ?? 0)) return false;
@@ -271,6 +310,9 @@ class ScopedNode {
271
310
  owner;
272
311
  key;
273
312
  kind;
313
+ get [SIGNAL_HANDLE]() {
314
+ return true;
315
+ }
274
316
  deps;
275
317
  depsTail;
276
318
  subs;
@@ -279,6 +321,7 @@ class ScopedNode {
279
321
  revision = 0;
280
322
  state;
281
323
  compute;
324
+ invalidateAttempt;
282
325
  last;
283
326
  lastState;
284
327
  hasLast = false;
@@ -292,7 +335,24 @@ class ScopedNode {
292
335
  throw new TypeError("Only an async signal can be retried.");
293
336
  }
294
337
  get() {
295
- 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 };
296
356
  }
297
357
  [NATIVE_DOM_VALUE]() {
298
358
  return this.get();
@@ -301,12 +361,23 @@ class ScopedNode {
301
361
  assertAlive(this.owner);
302
362
  assertWritable();
303
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
+ }
304
369
  signalBatch(() => {
305
- const previous = strictValue(refreshNode(this));
370
+ const previous = strictValue(refreshNode(this), this.key);
306
371
  const next = typeof value === "function" ? untrack(() => pure(() => value(previous))) : value;
307
- if (Object.is(previous, next)) return;
308
- publishNode(this, readyState(next));
309
- 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
+ }
310
381
  });
311
382
  }
312
383
  latest(fallback) {
@@ -356,8 +427,21 @@ function inspectNativeNode(node, read) {
356
427
  dependencies
357
428
  };
358
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
+ }
359
441
  function readNode(node, read = "value") {
360
442
  assertAlive(node.owner);
443
+ const candidate = activeCandidate;
444
+ if (candidate) node = candidate.resolve(node);
361
445
  const historical = historicalReader?.(node, read);
362
446
  if (historical) return historical;
363
447
  if (!historicalReader && node.owner.seedable) {
@@ -369,27 +453,35 @@ function readNode(node, read = "value") {
369
453
  if (activeNode) graph.link(node, activeNode, trackingCycle);
370
454
  if (getNativeReadObserver()) {
371
455
  const field = read === "value" ? "nativeSource" : read === "latest" ? "nativeLatestSource" : "nativeSnapshotSource";
372
- const source = node[field] ??= {
373
- getVersion: () => node.revision,
374
- subscribe: (notify) => {
375
- assertAlive(node.owner);
376
- return attachObserver(node, notify, true);
377
- },
378
- serialize: (revision) => node.revision === revision ? node.owner.serializeRead(node, read) : void 0,
379
- inspect: () => inspectNativeNode(node, read)
380
- };
381
- 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
+ );
382
461
  }
383
462
  if (observed.owners) for (const owner of observed.owners) assertAlive(owner);
384
463
  if (activeNode) recordOwners(node, observed);
385
464
  return observed;
386
465
  }
387
- function strictValue(state) {
466
+ function strictValue(state, key = "idle") {
388
467
  const snapshot = state.snapshot;
389
468
  if (snapshot.status === "ready") return snapshot.value;
390
469
  if (snapshot.status === "error") throw snapshot.error;
470
+ if (snapshot.status === "idle") throw new SignalIdleError(key);
391
471
  throw state.waiting;
392
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
+ }
393
485
  function refreshNode(node) {
394
486
  assertAlive(node.owner);
395
487
  if (node.evaluating) throw new SignalCycleError(node.key);
@@ -432,7 +524,7 @@ function evaluate(node) {
432
524
  let next;
433
525
  let owners;
434
526
  try {
435
- next = node.compute();
527
+ next = node.compute(node);
436
528
  } catch (error) {
437
529
  if (isThenable(error)) {
438
530
  const wakeup = node.wakeup ??= createWakeup();
@@ -501,9 +593,17 @@ function invalidateNode(node) {
501
593
  function derivedState(node, read) {
502
594
  const value = pure(read);
503
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) {
504
599
  let refreshing = false;
505
600
  let complete = true;
506
601
  let connection = "none";
602
+ if (activity) {
603
+ refreshing = activity.refreshing;
604
+ complete = activity.complete;
605
+ connection = activity.connection;
606
+ }
507
607
  for (let link = node.deps; link && node.depsTail; link = link.nextDep) {
508
608
  const dependency = link.dep.state?.snapshot;
509
609
  if (dependency) {
@@ -516,6 +616,18 @@ function derivedState(node, read) {
516
616
  }
517
617
  if (link === node.depsTail) break;
518
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
+ }
519
631
  return readyState(value, { refreshing, complete, connection });
520
632
  }
521
633
  class SignalObserver {
@@ -539,6 +651,10 @@ function attachObserver(node, notify, native, state) {
539
651
  node.owner.observers.add(observer);
540
652
  return () => stopObserver(observer);
541
653
  }
654
+ function subscribeNode(node, notify) {
655
+ const state = untrack(() => refreshNode(node));
656
+ return attachObserver(node, notify, true, state);
657
+ }
542
658
  function runObserver(observer) {
543
659
  const node = observer.node;
544
660
  if (!node || !observer.flags) return;
@@ -578,6 +694,7 @@ function retireGraph(owner, nodes) {
578
694
  node.state = errorState(retirementError);
579
695
  releaseRetention(node);
580
696
  node.compute = void 0;
697
+ node.invalidateAttempt = void 0;
581
698
  if (node.kind === "async") node.retry = ScopedNode.prototype.retry;
582
699
  if (node.subs) {
583
700
  graph.propagate(node.subs, executionDepth !== 0);
@@ -591,14 +708,45 @@ function retireGraph(owner, nodes) {
591
708
  retirementError = previousError;
592
709
  }
593
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
+ });
594
738
  export {
739
+ CandidateUnsupportedError,
595
740
  ScopedNode,
596
741
  SignalObserver,
597
742
  assertAlive,
598
743
  assertWritable,
744
+ attachObserver,
599
745
  derivedState,
746
+ derivedValueState,
600
747
  endSignalBatch,
601
748
  errorState,
749
+ idleState,
602
750
  inspectNativeNode,
603
751
  invalidateNode,
604
752
  isThenable,
@@ -606,6 +754,7 @@ export {
606
754
  publishNode,
607
755
  pure,
608
756
  readNode,
757
+ readSignalBinding,
609
758
  readyState,
610
759
  refreshNode,
611
760
  releaseRetention,
@@ -616,5 +765,7 @@ export {
616
765
  startSignalBatch,
617
766
  stopObserver,
618
767
  strictValue,
619
- untrack
768
+ subscribeNode,
769
+ untrack,
770
+ untrackCommitted
620
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;