@solidjs/signals 2.0.0-rc.15 → 2.0.0-rc.16

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 (89) hide show
  1. package/dist/dev-shared.js +785 -367
  2. package/dist/dev.attribution.js +75 -52
  3. package/dist/dev.js +1120 -567
  4. package/dist/observe/affects-marks.js +86 -0
  5. package/dist/observe/affects.js +22 -73
  6. package/dist/observe/boundaries.js +191 -189
  7. package/dist/observe/core/async.js +175 -131
  8. package/dist/observe/core/attribution-queries.js +1 -1
  9. package/dist/observe/core/attribution.js +176 -159
  10. package/dist/observe/core/constants.js +17 -3
  11. package/dist/observe/core/context.js +3 -3
  12. package/dist/observe/core/core.js +503 -363
  13. package/dist/observe/core/dev.js +66 -38
  14. package/dist/observe/core/effect.js +48 -48
  15. package/dist/observe/core/error.js +5 -3
  16. package/dist/observe/core/external.js +5 -6
  17. package/dist/observe/core/graph.js +57 -43
  18. package/dist/observe/core/heap.js +33 -33
  19. package/dist/observe/core/identities.js +62 -0
  20. package/dist/observe/core/lanes.js +226 -259
  21. package/dist/observe/core/owner.js +62 -50
  22. package/dist/observe/core/scheduler.js +319 -171
  23. package/dist/observe/core/truth.js +45 -0
  24. package/dist/observe/core/verdict.js +88 -50
  25. package/dist/observe/deferred.js +184 -0
  26. package/dist/observe/index.js +7 -1
  27. package/dist/observe/map.js +345 -260
  28. package/dist/observe/reveal.js +76 -76
  29. package/dist/observe/signals.js +41 -30
  30. package/dist/observe/store/affects.js +6 -6
  31. package/dist/observe/store/edges.js +39 -0
  32. package/dist/observe/store/optimistic.js +41 -36
  33. package/dist/observe/store/projection.js +68 -55
  34. package/dist/observe/store/store.js +157 -104
  35. package/dist/prod/affects-marks.js +86 -0
  36. package/dist/prod/affects.js +23 -72
  37. package/dist/prod/boundaries.js +155 -153
  38. package/dist/prod/core/async.js +171 -127
  39. package/dist/prod/core/constants.js +17 -3
  40. package/dist/prod/core/context.js +3 -3
  41. package/dist/prod/core/core.js +478 -342
  42. package/dist/prod/core/effect.js +68 -68
  43. package/dist/prod/core/error.js +5 -3
  44. package/dist/prod/core/external.js +5 -6
  45. package/dist/prod/core/graph.js +57 -43
  46. package/dist/prod/core/heap.js +38 -38
  47. package/dist/prod/core/identities.js +62 -0
  48. package/dist/prod/core/lanes.js +217 -250
  49. package/dist/prod/core/owner.js +62 -51
  50. package/dist/prod/core/scheduler.js +310 -162
  51. package/dist/prod/core/truth.js +45 -0
  52. package/dist/prod/core/verdict.js +87 -49
  53. package/dist/prod/deferred.js +182 -0
  54. package/dist/prod/index.js +7 -1
  55. package/dist/prod/map.js +360 -275
  56. package/dist/prod/reveal.js +76 -76
  57. package/dist/prod/signals.js +41 -30
  58. package/dist/prod/store/affects.js +6 -6
  59. package/dist/prod/store/edges.js +39 -0
  60. package/dist/prod/store/optimistic.js +37 -33
  61. package/dist/prod/store/projection.js +25 -19
  62. package/dist/prod/store/store.js +142 -96
  63. package/dist/types/affects-marks.d.ts +14 -0
  64. package/dist/types/boundaries.d.ts +1 -1
  65. package/dist/types/core/async.d.ts +10 -0
  66. package/dist/types/core/constants.d.ts +13 -1
  67. package/dist/types/core/core.d.ts +44 -2
  68. package/dist/types/core/dev.d.ts +43 -13
  69. package/dist/types/core/graph.d.ts +11 -0
  70. package/dist/types/core/identities.d.ts +17 -0
  71. package/dist/types/core/index.d.ts +2 -1
  72. package/dist/types/core/lanes.d.ts +2 -14
  73. package/dist/types/core/owner.d.ts +5 -3
  74. package/dist/types/core/scheduler.d.ts +47 -28
  75. package/dist/types/core/truth.d.ts +16 -0
  76. package/dist/types/core/types.d.ts +21 -0
  77. package/dist/types/core/verdict.d.ts +32 -0
  78. package/dist/types/deferred.d.ts +28 -0
  79. package/dist/types/index.d.ts +6 -0
  80. package/dist/types/map.d.ts +2 -2
  81. package/dist/types/signals.d.ts +28 -7
  82. package/dist/types/store/edges.d.ts +9 -0
  83. package/dist/types/store/index.d.ts +10 -3
  84. package/dist/types/store/optimistic.d.ts +3 -2
  85. package/dist/types/store/projection.d.ts +4 -3
  86. package/dist/types/store/store.d.ts +1 -1
  87. package/dist/types/store/target.d.ts +16 -8
  88. package/dist/types/store/types.d.ts +14 -0
  89. package/package.json +1 -1
@@ -1,25 +1,25 @@
1
1
  import {
2
- bv as OBSERVE,
3
- bF as setAttributionHooks,
4
- bG as liveRootOwners,
2
+ bN as OBSERVE,
3
+ bY as setAttributionHooks,
4
+ bZ as liveRootOwners,
5
5
  N as NOT_PENDING,
6
- ap as emitDiagnostic,
7
- bH as ownerPath,
8
- aD as reportDiagnostic,
9
- bI as isSuppressed,
10
- bJ as blockersOf,
11
- bK as CONFIG_PLUMBING,
12
- bL as anyExcluded,
13
- bM as isExcluded,
14
- bN as CONFIG_WIDE,
15
- a as CONFIG_OVERRIDE,
6
+ as as emitDiagnostic,
7
+ b_ as ownerPath,
8
+ aJ as reportDiagnostic,
9
+ b$ as isSuppressed,
10
+ c0 as blockersOf,
11
+ c1 as CONFIG_PLUMBING,
12
+ c2 as anyExcluded,
13
+ c3 as isExcluded,
14
+ c4 as CONFIG_WIDE,
15
+ c as CONFIG_OVERRIDE,
16
16
  C as CONFIG_GUESS,
17
17
  G as GlobalQueue,
18
- b as CONFIG_VERDICT,
19
- bO as GRAPH_SIZE_WARN_AT,
20
- bP as noteFanOut,
21
- bQ as CONFIG_SUPERSEDES,
22
- aV as $REFRESH
18
+ f as CONFIG_VERDICT,
19
+ c5 as GRAPH_SIZE_WARN_AT,
20
+ c6 as noteFanOut,
21
+ c7 as CONFIG_SUPERSEDES,
22
+ b0 as $REFRESH
23
23
  } from "./dev-shared.js";
24
24
 
25
25
  /** A fallback shown for less than this is a flash: feedback for a wait too short to need it. */
@@ -1070,7 +1070,15 @@ function trackEffectWrite(node, record, value) {
1070
1070
  const writer = info === undefined ? 0 : devId(info.node);
1071
1071
  recordNodes.set(record, node);
1072
1072
  n._devSoleWriter = n._devSoleWriter === undefined || n._devSoleWriter === writer ? writer : null;
1073
- if (info !== undefined && value !== undefined && value === info.node._value) {
1073
+ // An apply half that takes no argument cannot be copying its compute
1074
+ // output: a match is coincidence (`createEffect(open, () =>
1075
+ // setFlipped(measure()))`).
1076
+ if (
1077
+ info !== undefined &&
1078
+ value !== undefined &&
1079
+ value === info.node._value &&
1080
+ (info.node._effectFn?.length ?? 1)
1081
+ ) {
1074
1082
  copyWrites.add(record);
1075
1083
  n._devCopyRuns = n._devCopyFrom === writer ? (n._devCopyRuns ?? 0) + 1 : 1;
1076
1084
  n._devCopyFrom = writer;
@@ -1168,7 +1176,13 @@ function checkRelayTear(victim, causes, prevCauses) {
1168
1176
  // "reset editable state from a source" shape — the tear is real, but a memo
1169
1177
  // is not the answer, so it stays advisory like any other non-derivable tear.
1170
1178
  const derivable = copy && soleWriter;
1171
- const severity = derivable || state.count >= RELAY_WARN_AT ? "warn" : "info";
1179
+ // An apply half that ignores its argument writes from outside the graph
1180
+ // (layout, time, a ref; a signal read there is STRICT_READ's): measuring,
1181
+ // so it stays advisory however often it repeats.
1182
+ const severity =
1183
+ derivable || (state.count >= RELAY_WARN_AT && (relay.node._effectFn?.length ?? 1))
1184
+ ? "warn"
1185
+ : "info";
1172
1186
  // First sighting always reports (advisory); afterwards only the escalation.
1173
1187
  if (state.count > 1 && (severity !== "warn" || state.warned)) return;
1174
1188
  // One verdict per derivable signal: the copy report (checkCopyEffect) and
@@ -1187,12 +1201,10 @@ function checkRelayTear(victim, causes, prevCauses) {
1187
1201
  `writers — editable state reset from a source. If the reset is the intent, the tear ` +
1188
1202
  `is its cost; if "${write.name}" only ever mirrors the source, drop the local copy ` +
1189
1203
  `and read the source.`
1190
- : soleWriter
1191
- ? `Nothing else writes "${write.name}" — it is derived state: make it a memo over what ` +
1192
- `the effect reads and every reader gets it in the same flush.`
1193
- : `If "${write.name}" is computed from what the effect reads, make it a memo so readers ` +
1194
- `get it in the same flush; if the write reads something outside the graph (layout, ` +
1195
- `time), the tear is the cost of measuring.`;
1204
+ : (soleWriter ? `Nothing else writes "${write.name}". ` : "") +
1205
+ `If "${write.name}" is computed from what the effect reads, make it a memo so readers ` +
1206
+ `get it in the same flush; if the write reads something outside the graph (layout, ` +
1207
+ `time), the tear is the cost of measuring.`;
1196
1208
  const message =
1197
1209
  `[EFFECT_RELAY_TEAR] ${victimKind} "${nodeName(victim)}" ran twice for one write of ` +
1198
1210
  `"${shared.name}": once in the flush where "${shared.name}" changed, and again after ` +
@@ -1363,13 +1375,11 @@ function asyncOrigin(el) {
1363
1375
  // WeakMaps: an errored/abandoned flight must not leak its node or block GC.
1364
1376
  const liveFlights = new WeakMap();
1365
1377
  const landedFlights = new WeakMap();
1366
- /**
1367
- * Flight-object identity → earliest known start. Fed by markFlight() (the
1368
- * cooperative preload/cache declaration — populated even while attribution
1369
- * is disabled, so navigation-time marks survive a later enable()) and by
1370
- * first sightings at registration.
1371
- */
1372
- const flightOrigins = new WeakMap();
1378
+ // Flight-object identity → earliest known start lives on the core's slot
1379
+ // (`OBSERVE.attribution.markFlight`/`flightOrigin`), so marks made with no
1380
+ // engine loaded — a router's preloads, `lazy()`'s import — and the server's
1381
+ // boundary check share it. Fed by markFlight() and by first sightings at
1382
+ // registration.
1373
1383
  let waterfallLog = [];
1374
1384
  /** Deepest landed-flight cause reachable through a cause list (derived links included). */
1375
1385
  function flightCauseIn(causes) {
@@ -1412,8 +1422,8 @@ function emitFlight(el, flight, endedAt, outcome) {
1412
1422
  }
1413
1423
  function trackFlightStart(el, flight) {
1414
1424
  const at = now();
1415
- const origin = flightOrigins.get(flight) ?? at;
1416
- if (origin === at) flightOrigins.set(flight, at);
1425
+ const origin = OBSERVE.attribution.flightOrigin(flight) ?? at;
1426
+ if (origin === at) OBSERVE.attribution.markFlight(flight, at);
1417
1427
  // Census: a flight still in the air when the node starts another was
1418
1428
  // superseded — its answer will be discarded.
1419
1429
  const superseded = liveFlights.get(el);
@@ -1915,8 +1925,7 @@ function checkOptimisticRevert(el, shown, truth, how) {
1915
1925
  // --- Graph growth -----------------------------------------------------------------
1916
1926
  /**
1917
1927
  * Per route: at its last `visits` compared settles, oldest first, the
1918
- * graph's size and the part of it that was already alive when that
1919
- * navigation opened.
1928
+ * graph's size and the part of it already alive as a navigation opened.
1920
1929
  */
1921
1930
  const routeCounts = new Map();
1922
1931
  /**
@@ -1924,6 +1933,12 @@ const routeCounts = new Map();
1924
1933
  * its params or query change) continues the visit and is not compared.
1925
1934
  */
1926
1935
  let visitRoute;
1936
+ /**
1937
+ * Every node met as a navigation opened, weakly, for the session: one set,
1938
+ * not one per navigation (see `trackGraph`). Never reset — a node in it was
1939
+ * alive as a navigation opened whichever window met it.
1940
+ */
1941
+ const opened = new WeakSet();
1927
1942
  /**
1928
1943
  * The live graph's size — a walk, not a counter: nothing is charged at node
1929
1944
  * creation, disposal, write or re-run; the engine asks at a navigation's
@@ -1944,7 +1959,7 @@ function graphSize() {
1944
1959
  * The walk behind `graphSize()`. Given `before` alone, it adds every node it
1945
1960
  * meets to that set: what is alive as a navigation opens. Given `before` and
1946
1961
  * `survived`, it also counts into `survived` the nodes it meets that are in
1947
- * the set, and an edge when both its ends are: what outlived the navigation.
1962
+ * the set, and an edge when both its ends are: what outlived a navigation.
1948
1963
  * Nothing is retained — the set is weak.
1949
1964
  */
1950
1965
  function walkGraph(before, survived) {
@@ -1999,12 +2014,12 @@ function walkGraph(before, survived) {
1999
2014
  }
2000
2015
  /**
2001
2016
  * openNavigation, while the growth check is on: what is alive as a
2002
- * navigation opens, for its settle to tell apart from what it created.
2017
+ * navigation opens, added to what earlier ones met, for its settle to tell
2018
+ * apart from what it created.
2003
2019
  */
2004
2020
  function snapshotGraph() {
2005
- const before = new WeakSet();
2006
- walkGraph(before);
2007
- return before;
2021
+ walkGraph(opened);
2022
+ return opened;
2008
2023
  }
2009
2024
  /**
2010
2025
  * settleNavigation: the app has finished moving to a route — count the live
@@ -2017,10 +2032,19 @@ function snapshotGraph() {
2017
2032
  *
2018
2033
  * A count taken at an arrival also holds everything the visit just created,
2019
2034
  * so a page whose correctly owned content is bigger each visit climbs too.
2020
- * What tells the two apart is what outlived the navigation: the nodes alive
2021
- * when it opened (`NavState.before`) that are still alive at its settle. A
2022
- * visit's own content is not among them; what an earlier visit left behind
2023
- * is, whatever the content does. A series reports only when both climb.
2035
+ * What tells the two apart is what outlived a navigation: the nodes alive
2036
+ * as this or any earlier navigation opened (`opened`) that are still alive
2037
+ * at this settle. A visit's own content is not among them; what an earlier
2038
+ * visit left behind is, whatever the content does. A series reports only
2039
+ * when both climb.
2040
+ *
2041
+ * The set is the session's, not this navigation's own snapshot: the walk
2042
+ * meets a long-lived source only through a page that reads it, so a
2043
+ * per-navigation snapshot holds a module-level signal (an HMR registry, a
2044
+ * global store) only when the page just left read it too, and arriving from
2045
+ * pages that share ever more with this one read as growth (#4101). Kept
2046
+ * across navigations, such a source counts at every settle once met, the
2047
+ * same each visit; only what keeps accumulating climbs.
2024
2048
  */
2025
2049
  const GRAPH_SERIES = ["owners", "computations", "signals", "edges"];
2026
2050
  function trackGraph(state) {
@@ -2088,7 +2112,7 @@ function trackGraph(state) {
2088
2112
  `(${size.roots} roots)${routes.length > 1 ? `, across visits to ${routes.join(", ")}` : ""}. Each ` +
2089
2113
  `visit left something behind that the next did not reclaim — the shape says ${shape}. Dispose ` +
2090
2114
  `what a visit creates (onCleanup, or return the disposer from onSettled) and own it under the ` +
2091
- `route's component so leaving the route tears it down.`;
2115
+ `route's component so leaving the route tears it down. A cache that never evicts grows alike.`;
2092
2116
  const data = {
2093
2117
  route,
2094
2118
  grew,
@@ -3102,11 +3126,10 @@ const attribution = {
3102
3126
  // The buffers are typed by their variable; the switch is the proof.
3103
3127
  return buffer;
3104
3128
  },
3105
- markFlight(flight, startedAt = now()) {
3106
- // Earliest wins: re-marking (a cache re-serving the same promise) must
3107
- // not move the origin later.
3108
- const existing = flightOrigins.get(flight);
3109
- if (existing === undefined || startedAt < existing) flightOrigins.set(flight, startedAt);
3129
+ markFlight(flight, startedAt) {
3130
+ // Earliest wins (the slot's rule): re-marking (a cache re-serving the
3131
+ // same promise) must not move the origin later.
3132
+ OBSERVE.attribution.markFlight(flight, startedAt);
3110
3133
  }
3111
3134
  };
3112
3135