@abide/abide 0.123.2 → 0.124.0

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 (150) hide show
  1. package/ABIDE.md +8 -5
  2. package/CHANGELOG.md +58 -0
  3. package/bin/abide.ts +36 -65
  4. package/docs/REGISTRY.md +45 -12
  5. package/docs/RULEBOOK.md +24 -14
  6. package/docs/abide.md +999 -459
  7. package/package.json +1 -1
  8. package/src/compiler/ARRAY_MUTATORS.ts +20 -0
  9. package/src/compiler/Diagnostics.ts +198 -0
  10. package/src/compiler/KeptChecker.ts +97 -0
  11. package/src/compiler/LoweredFile.ts +609 -0
  12. package/src/compiler/Lowering.ts +18 -1
  13. package/src/compiler/PositionedRefusal.ts +1 -1
  14. package/src/compiler/SHARED_NAMES.ts +2 -0
  15. package/src/compiler/ShadowHost.ts +670 -0
  16. package/src/compiler/ShadowMap.ts +1 -1
  17. package/src/compiler/TypeSession.ts +76 -1743
  18. package/src/compiler/appLayout.ts +28 -20
  19. package/src/compiler/appLints.ts +109 -0
  20. package/src/compiler/argsDefaultsIn.ts +1 -1
  21. package/src/compiler/checkApp.ts +64 -68
  22. package/src/compiler/checkedShadow.ts +2 -2
  23. package/src/compiler/classifyRead.ts +16 -1
  24. package/src/compiler/compileApp.ts +102 -71
  25. package/src/compiler/declaredExports.ts +46 -21
  26. package/src/compiler/diagnoseSources.ts +232 -0
  27. package/src/compiler/emitClient.ts +1 -1
  28. package/src/compiler/formatAbide.ts +7 -8
  29. package/src/compiler/handlersUnder.ts +32 -63
  30. package/src/compiler/lineOf.ts +0 -19
  31. package/src/compiler/matchersOf.ts +3 -3
  32. package/src/compiler/mountsOf.ts +3 -3
  33. package/src/compiler/reactiveReads.ts +235 -0
  34. package/src/compiler/reactiveTypes.ts +13 -0
  35. package/src/compiler/readSources.ts +16 -18
  36. package/src/compiler/readsIn.ts +181 -82
  37. package/src/compiler/routesDeclaration.ts +46 -0
  38. package/src/compiler/scaffold.ts +7 -2
  39. package/src/compiler/serveLanguage.ts +46 -74
  40. package/src/compiler/sharedModuleWrites.ts +1 -1
  41. package/src/compiler/splitImports.ts +2 -2
  42. package/src/compiler/templateWarnings.ts +1 -2
  43. package/src/compiler/trackingWarnings.ts +1 -1
  44. package/src/server/CLIENT_BUILD.ts +4 -32
  45. package/src/server/DesktopSession.ts +213 -0
  46. package/src/server/Followers.ts +399 -0
  47. package/src/server/MODULE_QUERIES.ts +6 -2
  48. package/src/server/PageRender.ts +201 -0
  49. package/src/server/RESUME_MILLISECONDS.ts +2 -0
  50. package/src/server/abideModules.ts +7 -7
  51. package/src/server/answerFailure.ts +3 -2
  52. package/src/server/answerRequest.ts +16 -369
  53. package/src/server/answerRpc.ts +48 -302
  54. package/src/server/answerSocket.ts +41 -490
  55. package/src/server/appBuild.ts +377 -0
  56. package/src/server/appKit.ts +1 -1
  57. package/src/server/appPlugins.ts +15 -17
  58. package/src/server/appTree.ts +6 -5
  59. package/src/server/argsContract.ts +209 -0
  60. package/src/server/bridgeRelay.ts +153 -65
  61. package/src/server/claudeCode.ts +30 -127
  62. package/src/server/config.ts +6 -7
  63. package/src/server/createApp.ts +38 -66
  64. package/src/server/csp.ts +1 -1
  65. package/src/server/deferredBuilds.ts +3 -16
  66. package/src/server/devWorker.ts +11 -15
  67. package/src/server/faceOf.ts +1 -1
  68. package/src/server/generatedSurfaces.ts +2 -1
  69. package/src/server/handlerFileMount.ts +40 -0
  70. package/src/server/index.ts +3 -3
  71. package/src/server/installServer.ts +5 -9
  72. package/src/server/invokeHandler.ts +230 -0
  73. package/src/server/mountHandlers.ts +184 -0
  74. package/src/server/openDesktopWindow.ts +308 -0
  75. package/src/server/packageDirectory.ts +14 -0
  76. package/src/server/preload.ts +21 -2
  77. package/src/server/principal.ts +5 -4
  78. package/src/server/remote.ts +2 -2
  79. package/src/server/render.ts +31 -59
  80. package/src/server/requestScope.ts +5 -36
  81. package/src/server/runCompiled.ts +1 -1
  82. package/src/server/runDesktop.ts +20 -448
  83. package/src/server/seedBuffer.ts +12 -12
  84. package/src/server/serveDev.ts +24 -58
  85. package/src/server/servedApp.ts +390 -0
  86. package/src/server/shell.ts +1 -1
  87. package/src/server/signInChanged.ts +20 -0
  88. package/src/server/surfaceOf.ts +3 -2
  89. package/src/server/versionOf.ts +7 -16
  90. package/src/shared/RPC_SERVER.ts +27 -31
  91. package/src/shared/Schema.ts +1 -2
  92. package/src/shared/applyPatch.ts +1 -1
  93. package/src/shared/index.ts +1 -1
  94. package/src/shared/{note.ts → issueReport.ts} +22 -0
  95. package/src/shared/loadCall.ts +66 -0
  96. package/src/shared/muxFrames.ts +1 -1
  97. package/src/shared/reactive/Keyed.ts +24 -16
  98. package/src/shared/reactive/Reactive.ts +37 -991
  99. package/src/shared/reactive/argsContract.ts +131 -4
  100. package/src/shared/reactive/byOf.ts +2 -5
  101. package/src/shared/reactive/callLoad.ts +8 -14
  102. package/src/shared/reactive/cellShape.ts +734 -0
  103. package/src/shared/reactive/index.ts +12 -23
  104. package/src/shared/reactive/pairReactive.ts +5 -3
  105. package/src/shared/reactive/patchLog.ts +79 -0
  106. package/src/shared/reactive/patchMarks.ts +34 -0
  107. package/src/shared/reactive/producer.ts +121 -0
  108. package/src/shared/reactive/recordWrites.ts +11 -14
  109. package/src/shared/reactive/scoped.ts +3 -2
  110. package/src/shared/reactive/selections.ts +209 -0
  111. package/src/shared/reactive/share.ts +4 -3
  112. package/src/shared/reactive/watch.ts +3 -4
  113. package/src/shared/rpc.ts +20 -24
  114. package/src/shared/validateJson.ts +1 -2
  115. package/src/shared/writePath.ts +29 -0
  116. package/src/ui/ArmRegion.ts +10 -4
  117. package/src/ui/Level.ts +11 -20
  118. package/src/ui/LevelChain.ts +272 -0
  119. package/src/ui/Router.ts +106 -313
  120. package/src/ui/Scope.ts +17 -3
  121. package/src/ui/TryRegion.ts +22 -23
  122. package/src/ui/bindSpread.ts +2 -4
  123. package/src/ui/listenForRoutes.ts +3 -10
  124. package/src/ui/outboxQueue.ts +23 -11
  125. package/src/ui/outcomeOf.ts +120 -0
  126. package/src/ui/reconcile.ts +4 -6
  127. package/src/ui/routing.ts +2 -1
  128. package/src/ui/rows.ts +2 -2
  129. package/src/ui/setAttribute.ts +12 -3
  130. package/src/ui/socketWire.ts +28 -13
  131. package/src/ui/wire.ts +9 -10
  132. package/src/compiler/Finding.ts +0 -2
  133. package/src/compiler/Refusals.ts +0 -65
  134. package/src/compiler/formatDiagnosis.ts +0 -20
  135. package/src/server/appDirectories.ts +0 -9
  136. package/src/server/argsFor.ts +0 -39
  137. package/src/server/buildDirectory.ts +0 -10
  138. package/src/server/coerceArgs.ts +0 -109
  139. package/src/server/derivedArgs.ts +0 -26
  140. package/src/server/runBuild.ts +0 -24
  141. package/src/server/serveBuild.ts +0 -144
  142. package/src/server/testBuild.ts +0 -220
  143. package/src/shared/LOAD_OFFLINE.ts +0 -15
  144. package/src/shared/LOAD_SIGNAL.ts +0 -10
  145. package/src/shared/issuesOf.ts +0 -18
  146. package/src/shared/reactive/ENTRY_LIVES.ts +0 -7
  147. package/src/shared/reactive/FOLLOWED.ts +0 -8
  148. package/src/shared/reactive/PATCHES.ts +0 -11
  149. package/src/shared/reactive/PATCH_SINKS.ts +0 -26
  150. package/src/shared/reactive/canonicalKey.ts +0 -95
@@ -0,0 +1,734 @@
1
+ // A VALUE'S RECORD, AND THE ONE PLACE ITS SHAPE IS DECLARED. `Cell` and the sub-records it holds
2
+ // (`Cap`, `Persisted`, `Stream`, `Adoption`) live here rather than in `Reactive.ts` so a sibling
3
+ // that reaches a value's record — `Keyed`, `watch`, `byOf`, the selection index, the producer port —
4
+ // names the real type instead of re-declaring the few fields it reads.
5
+ //
6
+ // NO RUNTIME EDGE BACK TO THE CORE. `Reactive.ts` imports this, and a module reaching this ahead
7
+ // of the core would otherwise enter the cycle `index.ts` names. That is why `notify` — a cell's
8
+ // wake, which is a run of the graph — is put on the prototype by `Reactive.ts` (see `run` there)
9
+ // rather than declared as a method here: the instance shape is the constructor's, and a prototype
10
+ // slot is not part of it.
11
+
12
+ import type { Schema } from '../Schema.ts'
13
+ import { CELL } from './CELL.ts'
14
+ import { type Expiry, expiryFor } from './Expiry.ts'
15
+ import { MUTATION } from './MUTATION.ts'
16
+ import type { Identity, Reactive, ReactiveOptions, Store } from './Reactive.ts'
17
+ import { currentScope, type Scope } from './scoping.ts'
18
+ import { CLEAN, type Subscriber, type Tracked } from './tracking.ts'
19
+
20
+ /** The standing adoption: what is adopted, and the way to stop mirroring it. */
21
+ export type Adoption = { source: Cell; stop: () => void }
22
+
23
+ /**
24
+ * The window a `throttle` or a `debounce` holds open, allocated only where one is declared.
25
+ *
26
+ * THE WINDOW A `throttle` OR A `debounce` HOLDS OPEN (RULEBOOK 5.8). One field on the
27
+ * cell rather than one per window field, allocated only where a value declared one — the
28
+ * shape `adoption` already uses, and for the same reason.
29
+ *
30
+ * WHAT A WINDOW CAPS IS THE WAKE, NEVER THE PRODUCTION (5.9). Every write still mints and
31
+ * the ordinal moves. What waits is the value a READER sees and the cascade that tells it so,
32
+ * which is the whole of 5.8's "how often a value changes for a reader".
33
+ *
34
+ * WHAT IT COSTS EVERY VALUE THAT NEVER CAPS: one field load and one branch on the write
35
+ * path, plus `serve` as a frame rather than five stores inline. Measured at 0.99x -> 1.08x
36
+ * against the hand-written arm on the since-removed `publish into a capped ring` case, consistent across three
37
+ * runs over a 0.7% floor — about 1.3 ns on a 14.7 ns op. Moving the comparison target
38
+ * behind the gate did not recover it, so it is the frame and the branch rather than a
39
+ * wasted load. Inlining `serve` into the uncapped arm would buy it back for a second copy
40
+ * of the reader-visible transition, and this file has already paid for one of those: the
41
+ * trade is stated rather than taken, 1.3 ns being nowhere near perception.
42
+ */
43
+ export type Cap = {
44
+ /**
45
+ * True for a throttle, which lets the leading change through; false for a debounce.
46
+ *
47
+ * 5.12 against 5.13, and the only difference between the two mechanisms: a throttle
48
+ * lets the leading change through and holds what follows, a debounce holds everything
49
+ * until the changes stop.
50
+ */
51
+ leading: boolean
52
+ ms: number
53
+ timer: ReturnType<typeof setTimeout> | null
54
+ /**
55
+ * The production the window is holding back, while `holding` is set.
56
+ *
57
+ * The production the window is holding back. `holding` is a field rather than a test
58
+ * against `held`, because `undefined` is a value an app can write and so cannot carry
59
+ * the absence.
60
+ */
61
+ held: unknown
62
+ holding: boolean
63
+ /**
64
+ * The last production minted, which the identity gate compares against.
65
+ *
66
+ * WHAT THE IDENTITY GATE COMPARES AGAINST. On every uncapped value that is `cell.value`
67
+ * and the two are one thing; a window moves the last production MINTED apart from the
68
+ * last one RELEASED, and comparing against the released one would collapse a production
69
+ * 5.9 forbids dropping — A, B, A inside one window is three productions, and only the
70
+ * third's own predecessor makes it a repeat.
71
+ */
72
+ minted: unknown
73
+ /**
74
+ * Whether the window is holding back a body run.
75
+ *
76
+ * A BODY RUN THE WINDOW IS HOLDING BACK (5.11), against `holding`'s production. The two
77
+ * are separate flags because they can stand together: a stream has a body AND tells its
78
+ * chunks through the window (5.17), so one close can owe a run and a telling at once.
79
+ */
80
+ owed: boolean
81
+ /**
82
+ * Whether the window is holding back a refresh, started when it closes.
83
+ *
84
+ * 5.24 — A RELOAD THE WINDOW IS HOLDING BACK: a refresh made inside it, started when it closes.
85
+ * Started there rather than owed like a run, because 7.11 reloads whether or not anything reads
86
+ * and an owed run waits for a read to pull it.
87
+ */
88
+ reloading: boolean
89
+ }
90
+
91
+ /**
92
+ * A value's store and the state of its writes, allocated only where a `store` was declared.
93
+ *
94
+ * A VALUE'S STORE AND WHAT ITS WRITES ARE DOING, allocated only where a `store` was declared.
95
+ *
96
+ * 8.10: ONE WRITE IN FLIGHT AND ONE PENDING. A production arriving while a write is out replaces
97
+ * the pending value rather than queueing behind it: a slow store handed every intermediate is doing
98
+ * work nobody can observe, and a queue is how it grows without bound behind a fast writer.
99
+ */
100
+ export type Persisted = {
101
+ store: Store<unknown>
102
+ /** The value's own `ttl`, taken once, and infinity where it declares none (8.13). */
103
+ ttl: number
104
+ /**
105
+ * Set while a restore mints its production, so what was just read is not written back (8.8).
106
+ */
107
+ restoring: boolean
108
+ writing: boolean
109
+ pending: boolean
110
+ /**
111
+ * The newest value handed to the store and not yet confirmed.
112
+ *
113
+ * THE NEWEST VALUE THE APP HAS HANDED THE STORE, standing until the store confirms it. It is
114
+ * what `pending` sends next, and what 8.18 serves a re-read in place of calling `get`.
115
+ */
116
+ unconfirmed: unknown
117
+ /** What stops the store's `watch`, where it has one (8.21). */
118
+ unwatch: (() => void) | null
119
+ }
120
+
121
+ /**
122
+ * A streaming producer's own state; `null` on every value whose body is not an async generator.
123
+ *
124
+ * A STREAMING PRODUCER'S OWN STATE (9.1, 9.2, 9.6), and `null` on every value whose body is
125
+ * not an async generator — the shape `cap` and `adoption` already use.
126
+ *
127
+ * THE ACCUMULATION IS PUSHED INTO AND MATERIALIZED ON THE READ. A chunk is one push and one
128
+ * cascade; the copy a reader is handed is taken by the read that follows, so a hundred
129
+ * chunks between two reads are one copy rather than a hundred (9.2). The copy is FRESH per
130
+ * chunk count and has to be: a reader holding an earlier snapshot still holds what it read,
131
+ * and a value derived from this one compares by reference — the live buffer handed out would
132
+ * be collapsed at every derived identity gate after the first chunk.
133
+ *
134
+ * WHAT THAT COSTS WHERE A READ FOLLOWS EVERY CHUNK is a copy of the accumulation per read,
135
+ * and a reader woken per chunk made that a copy per chunk: twenty thousand chunks landing in
136
+ * one task took 61 ms against 1.9 ms for the hand-written arm. 9.9 is what bounds it — the
137
+ * wake is held to one per task, which is the unit a browser paints between, so the reads it
138
+ * drops were never visible. A reader that reads per chunk on its own, unwoken, is still a
139
+ * copy per read.
140
+ */
141
+ export type Stream = {
142
+ /**
143
+ * The accumulation of the run being served — and the same array as `ring`, so a cursor
144
+ * walks the chunks this holds rather than a second copy of them.
145
+ */
146
+ chunks: unknown[]
147
+ /** The accumulation's version: moves on every release, patch and new run. */
148
+ version: number
149
+ /**
150
+ * Which accumulation `value` stands for, as a `version` rather than a chunk count.
151
+ *
152
+ * A version rather than a chunk count because a patch changes the accumulation without
153
+ * changing its length (9.13), and a write stands at the version it was made at until the
154
+ * accumulation moves past it (9.11). -1 where nothing has been materialized.
155
+ */
156
+ materializedAt: number
157
+ /**
158
+ * Whether `value` is a write rather than a materialization.
159
+ *
160
+ * WHETHER `value` IS A WRITE rather than a materialization, while `materializedAt` stands. A value
161
+ * forwarding this stream serves the write the way it would have served a production (11.59).
162
+ */
163
+ written: boolean
164
+ /**
165
+ * How many chunks a reader has been told of.
166
+ *
167
+ * HOW MANY CHUNKS A READER HAS BEEN TOLD OF. Every chunk as it lands, without a cap; with one,
168
+ * only what the window has released (5.18) — the rest are in `chunks` for a cursor (5.10) and
169
+ * out of what a read materializes until the release.
170
+ */
171
+ visible: number
172
+ /** The run in flight, told to return when a newer run supersedes it. */
173
+ iterator: AsyncIterator<unknown> | null
174
+ /**
175
+ * Which run is current; only a new run moves it.
176
+ *
177
+ * WHICH RUN IS CURRENT, and only a new run moves it. Apart from `generation`, which every
178
+ * write moves so that a load it overtook lands nowhere — a write over a stream stands beside
179
+ * the stream (9.11) rather than superseding it, and sharing the counter stopped the stream.
180
+ */
181
+ run: number
182
+ /**
183
+ * Whether a wake is already held for this task, so the next chunk only pushes.
184
+ *
185
+ * 9.9: chunks have landed that the readers have not been told about, and the value is
186
+ * already in `WAKING` — so the next chunk in this task pushes and does nothing else.
187
+ */
188
+ waking: boolean
189
+ /**
190
+ * A probe moved under the held wake — the first chunk making the value ready, or one
191
+ * clearing a standing error — and the wake owes it to the guards as well.
192
+ */
193
+ probesOwed: boolean
194
+ /**
195
+ * The stream this one forwards, and `null` on a value that produces its own.
196
+ *
197
+ * THE STREAM THIS ONE FORWARDS (11.15), and `null` on a value that produces its own. A
198
+ * value adopting a stream IS that stream to a cursor, a guard and an await, so it holds
199
+ * the adopted value's buffer and ring rather than copies — and this is what stops a
200
+ * trigger on it starting its body as though the body were the generator.
201
+ */
202
+ source: Cell | null
203
+ /**
204
+ * How far the forwarding value's ordinals run ahead of the adopted value's, fixed when
205
+ * the forwarding begins so the adopter's cursor positions go on from its own.
206
+ */
207
+ ordinalOffset: number
208
+ /**
209
+ * Whether what is served is a run that closed.
210
+ *
211
+ * WHETHER WHAT IS SERVED IS A RUN THAT CLOSED, which is the only accumulation a deadline
212
+ * reaches (6.10). A run in flight has minted nothing, so `expiry.at` says nothing about it —
213
+ * without this the standing arm reads `at` as 0 and drops the value on its first read.
214
+ */
215
+ closed: boolean
216
+ }
217
+
218
+ export function newStream(source: Cell | null): Stream {
219
+ return {
220
+ chunks: EMPTY_RING,
221
+ version: 0,
222
+ visible: 0,
223
+ materializedAt: -1,
224
+ written: false,
225
+ iterator: null,
226
+ run: 0,
227
+ waking: false,
228
+ probesOwed: false,
229
+ source,
230
+ ordinalOffset: 0,
231
+ closed: false,
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Every value that is not streaming shares this as its `ring`. The field stays monomorphically an
237
+ * Array — CLAUDE.md's shape rule — and only a stream's own chunk buffer is ever pushed to. Frozen so
238
+ * that if anything ever does push here, it says so rather than corrupting every other value at once.
239
+ */
240
+ export const EMPTY_RING = Object.freeze([]) as unknown as unknown[]
241
+
242
+ /**
243
+ * What an `invalidate` leaves behind: nothing owed, a look above, or a reload.
244
+ *
245
+ * WHAT AN INVALIDATE LEAVES BEHIND, and it is a debt rather than a mark. The mark walk's states
246
+ * are the wrong tool: a node marked `CHECK` or `DIRTY` without its effects queued is one a later
247
+ * write's walk stops at — `state >= wanted` — and the effects below it are never woken for a
248
+ * change that really happened. So nothing in the graph's state moves; the invalidated value OWES
249
+ * A RELOAD, the values built from it OWE A LOOK ABOVE, and none of them is directly servable, so
250
+ * the read that reaches any of them goes a frame in and settles the debt first (7.12, 7.13).
251
+ */
252
+ export const OWES_NOTHING: number = 0
253
+ export const OWES_ABOVE: number = 1
254
+ export const OWES_RELOAD: number = 2
255
+
256
+ /**
257
+ * A value's internal state record, apart from the callable an app holds.
258
+ *
259
+ * THE INTERNAL FACE, AND A SECOND OBJECT. With the fields on the callable itself, every
260
+ * one was a property added to a FUNCTION at construction, and that was most of what a
261
+ * value cost to make: moving them here took `construct a value` from 123 ns to 87 under
262
+ * JSC and from 101 to 83 under V8, and a derived value's construction, a chain and a
263
+ * layered DAG 7-13% with it. Nothing measured moved the other way. The callable captures
264
+ * its record, so a read is one context load — the hand-written arm's one captured
265
+ * variable — and a member reaches the record through `CELL`, one load ahead of what it
266
+ * did before.
267
+ *
268
+ * THE FIELD COUNT SITS ON A VM BOUNDARY AND IT IS NOT A LEVER. Both engines give an
269
+ * object a fixed inline slot budget and spill the rest to an out-of-line store, and this
270
+ * record is over it — so the count moves numbers that have nothing to do with the work.
271
+ * Two independent measurements say the same thing from opposite ends. Taking `Cell` to
272
+ * 38 is worth ~11% of `construct a value` and ~6-9% of the derived case, and it does not
273
+ * matter HOW the four go: a consolidation into one record and four fields simply deleted
274
+ * buy the same number, so the consolidation is not what pays. Going the other way,
275
+ * 42 -> 46, is FREE — above the budget the out-of-line store already exists. And dropping
276
+ * ONE field moved chain 20 and both layered DAGs +4.2% under V8 while moving nothing
277
+ * under JSC; adding a DEAD boolean back put all three within 0.6%, which is the proof it
278
+ * was layout and not work — that same dead boolean then cost the probe walk 6-7%.
279
+ *
280
+ * Above the budget is not free under JSC, though: three fields more (the dead-reader
281
+ * counts and `probeCursor`) moved `construct a value` and the derived case +6-8% there,
282
+ * and three UNUSED fields on the old record moved them the same — layout, not work.
283
+ *
284
+ * So the boundary is worth KNOWING and not worth engineering around. A field costs a few
285
+ * ns of construction; getting under costs a structural change that the next field added here
286
+ * silently undoes, and it re-rolls in a different direction for every row. If
287
+ * construction ever needs that 11%, shed fields — do not build machinery to shed them.
288
+ * And when a V8-only move of this size shows up on a graph row, the first thing to check
289
+ * is whether the field count changed.
290
+ */
291
+ export class Cell {
292
+ /**
293
+ * Who reads this value, on the value edge.
294
+ *
295
+ * ARRAYS, not sets. The mark walk walks this per write and a set's iterator
296
+ * allocates. A disposed reader is left in place and counted rather than found — see
297
+ * `dropFrom` in `tracking.ts` — so a walk over this skips `!alive`.
298
+ */
299
+ declare readers: Subscriber[]
300
+ declare deadReaders: number
301
+ /**
302
+ * Who asked about this value's PROBES — a different edge from `readers`, and see
303
+ * `markProbes` for what that buys.
304
+ */
305
+ declare probeReaders: Subscriber[]
306
+ declare deadProbeReaders: number
307
+ declare sources: Cell[]
308
+ /**
309
+ * The values whose PROBES this body asked about — a `Cell` is a `Subscriber`, so it
310
+ * carries the reader half of the probe edge as well as the source half.
311
+ */
312
+ declare probeSources: Cell[]
313
+ declare probeCursor: number
314
+ declare cursor: number
315
+ /** See `Subscriber.seen`. */
316
+ declare seen: Set<Cell> | null
317
+ declare seenThrough: number
318
+ declare scanningFrom: number
319
+ declare label: string
320
+ declare body: ((args: unknown) => unknown) | null
321
+ declare args: unknown
322
+ declare value: unknown
323
+ declare landed: boolean
324
+ /**
325
+ * Whether a read may answer with `value`.
326
+ *
327
+ * WHETHER A READ MAY ANSWER WITH `value`. Implies `landed`, and is false over a landed value
328
+ * a trigger, an abort or an adoption has stopped serving — which is the state `landed`
329
+ * alone cannot say.
330
+ */
331
+ declare servable: boolean
332
+ /**
333
+ * Whether a read can return `value` straight, without going a frame in.
334
+ *
335
+ * `state === CLEAN && servable` — the whole of "this read can return the field",
336
+ * maintained rather than recomputed. A read is the hottest path in the design and it
337
+ * was three loads and three branches to decide.
338
+ *
339
+ * THE INVARIANT IS ONE-DIRECTIONAL and that is what makes it safe to maintain by
340
+ * hand: `true` is written only where all three are known to hold, and every
341
+ * transition that can break one of them writes `false`. So a site that forgets to
342
+ * set it true costs a frame on the reads that follow and cannot serve a wrong value,
343
+ * which is the opposite of how a maintained flag usually fails.
344
+ */
345
+ declare direct: boolean
346
+ declare loading: boolean
347
+ declare failure: unknown
348
+ /**
349
+ * The compiled `identity` comparator.
350
+ *
351
+ * `null` IS the default — see `comparatorFor`.
352
+ */
353
+ declare identityFn: ((next: unknown, previous: unknown) => boolean) | null
354
+ /**
355
+ * The comparator this value DECLARED, which `identityFn` returns to when an adoption ends.
356
+ *
357
+ * 11.17 inherits the adopted value's `identity` only where the outer declared none, and only
358
+ * for as long as it adopts: kept on `identityFn` alone, the inherited comparator outlived the
359
+ * adoption and gated the outer's own productions — `flag() ? inner : count()` with `inner`
360
+ * keyed on `.id` read every number as the same `undefined` and never woke again.
361
+ */
362
+ declare declaredIdentityFn:
363
+ ((next: unknown, previous: unknown) => boolean) | null
364
+ declare transform: ((value: unknown) => unknown) | null
365
+ /**
366
+ * `null` on every value that declares no `schema`, which keeps the gate off the write
367
+ * path of everything that did not ask for one.
368
+ */
369
+ declare schema: Schema<unknown> | null
370
+ /**
371
+ * A streaming producer's chunk buffer, for a cursor to walk (2.6); `EMPTY_RING` on every
372
+ * other value.
373
+ */
374
+ declare ring: unknown[]
375
+ /**
376
+ * The ordinal before `ring[0]`, so `ring[index]` carries ordinal `ringBase + index + 1` and a
377
+ * cursor finds its place from the ordinal it holds.
378
+ */
379
+ declare ringBase: number
380
+ /**
381
+ * `null` on every value that declares no `ttl`, and on every value 6.2 makes it inert
382
+ * for. Its presence is also what holds `direct` false — see `serve`.
383
+ */
384
+ declare expiry: Expiry | null
385
+ declare ordinal: number
386
+ declare generation: number
387
+ declare alive: boolean
388
+ declare isEffect: boolean
389
+ declare isMirror: boolean
390
+ declare adopter: Tracked | null
391
+ /**
392
+ * The mark: `CLEAN`, `CHECK` or `DIRTY`.
393
+ *
394
+ * `CLEAN`, `CHECK` or `DIRTY` — see `tracking.ts`. Stamped on every transitive
395
+ * reader BEFORE anything runs, so a body that reaches a source which has not caught
396
+ * up yet pulls it forward; `running` is what stops a body already on the stack being
397
+ * re-entered.
398
+ *
399
+ * ONE RUN PER NODE PER WRITE is the contract, and the state carries it without a
400
+ * cascade counter: a node that has run is `CLEAN`, and only a source PRODUCING can
401
+ * mark it again — which a source it already read cannot do, because reading it is
402
+ * what resolved it.
403
+ */
404
+ declare state: number
405
+ declare running: boolean
406
+ /**
407
+ * Whether the last run aborted on a value that had not landed.
408
+ *
409
+ * 2.13: A RUN THAT ABORTED ON A VALUE THAT HAD NOT LANDED, and is owed the rest of itself
410
+ * when that value arrives. Push-pull leaves a marked body for the read that wants it, and
411
+ * that is right for a body which RAN — this one did not, so nothing downstream can pull it:
412
+ * a reader guarding on `ready()` asks the probe edge and never the value, and the guard would
413
+ * answer false for as long as nobody read through it.
414
+ */
415
+ declare aborted: boolean
416
+ /**
417
+ * The value this one adopted, or `null`.
418
+ *
419
+ * WHAT THIS VALUE'S BODY HANDED BACK, where it handed back another `Reactive`
420
+ * (11.12). `null` on every value that is not adopting, which is nearly all of them —
421
+ * one field rather than two, and the record is allocated only where there is one.
422
+ */
423
+ declare adoption: Adoption | null
424
+ /**
425
+ * `null` on every value declaring neither `throttle` nor `debounce`, which is nearly
426
+ * all of them.
427
+ */
428
+ declare cap: Cap | null
429
+ /**
430
+ * `null` on every value declaring no `tags`, which keeps `markProbes` from looking up a
431
+ * selection signal for any of them.
432
+ */
433
+ declare tags: string[] | null
434
+ /** Whether `declare` built this value for a mutation, which a sweep invalidates (13.16). */
435
+ declare mutation: boolean
436
+ /**
437
+ * Whether what is held was written here since the producer last produced (3.10).
438
+ *
439
+ * Only ever true on a value with a body: a value with no producer has nothing to be out of
440
+ * step with (3.12). Moved by `writtenHere` and `producedAgain` alone, each owning its probe move.
441
+ */
442
+ declare local: boolean
443
+ /** `null` on every value declaring no `store`, which is what keeps `serve` from persisting. */
444
+ declare store: Persisted | null
445
+ /**
446
+ * The declared `by`.
447
+ *
448
+ * 5.22 — held as declared rather than as a function, so the property name is still there to send.
449
+ */
450
+ declare by: string | ((element: unknown) => unknown) | null
451
+ /** The probe pass this cell was last visited in. See `walkBusy` and `walkReady`. */
452
+ declare probePass: number
453
+ /**
454
+ * `OWES_NOTHING`, `OWES_ABOVE` or `OWES_RELOAD` — what an `invalidate` left for the next read
455
+ * to do. See `invalidateOne`.
456
+ */
457
+ declare owes: number
458
+ /** The value this record is the state of — what `NotLanded` names as its source. */
459
+ declare callable: Reactive<unknown> | null
460
+ /** `null` on every value whose body is not an async generator, which is nearly all. */
461
+ declare stream: Stream | null
462
+ /**
463
+ * Whether a read may ever take the field straight, fixed at construction.
464
+ *
465
+ * WHETHER A READ MAY EVER TAKE THE FIELD STRAIGHT, fixed at construction: no expiry to
466
+ * check and no accumulation to materialize. `setDirect` reads this one field where it
467
+ * would otherwise read one per mechanism that needs the read to go a frame in.
468
+ */
469
+ declare plain: boolean
470
+ /**
471
+ * Whether a settled write goes straight to `produce`, past no gate.
472
+ *
473
+ * NOTHING STANDS BETWEEN A SETTLED WRITE AND `produce`: no `schema`, no `transform`, and no
474
+ * stream whose writes stand apart from its chunks (9.11, 9.12). One field where the write and
475
+ * the recompute each tested two, maintained where a forwarded stream comes and goes.
476
+ */
477
+ declare bareWrite: boolean
478
+ /**
479
+ * Whether a gated write can take `SIMPLE_PROTOTYPE`'s short path.
480
+ *
481
+ * EVERYTHING A GATED WRITE WOULD OTHERWISE ASK, IN ONE FIELD: no cap holding the
482
+ * production back, no expiry, no store to persist through, no
483
+ * declared `identity`, and `bareWrite`'s own three. A value carrying none of them has a
484
+ * `produce` -> `serve` -> `cascade` that reduces to three stores and a mark — which is
485
+ * what `SIMPLE_PROTOTYPE.set` spells out rather than calls.
486
+ *
487
+ * IT SELECTS A PROTOTYPE AND IS NOT READ ON THE WRITE PATH. See `SIMPLE_PROTOTYPE`.
488
+ *
489
+ * MAINTAINED, NOT FIXED: three of the fields under it move after construction —
490
+ * `bareWrite` and `plain` where a forwarded stream comes and goes, `identityFn` where an
491
+ * adoption takes the inner value's. `simpleShape` is called at each of those.
492
+ */
493
+ declare simple: boolean
494
+ /**
495
+ * The scope this value was built in, and so the one its body runs under.
496
+ *
497
+ * 11.32 — THE SCOPE THIS VALUE WAS BUILT IN, and so the one its body runs under. `undefined` in a
498
+ * browser, and on a server for a value built outside any request.
499
+ */
500
+ declare scope: Scope | undefined
501
+ /**
502
+ * Whether this value is one for the whole process, in every scope.
503
+ *
504
+ * 11.34, 13.13 — one value for the process, and so inside every scope a selection is made in. An
505
+ * entry of a `global` keyed value is one too, whichever request first reached it.
506
+ */
507
+ declare global: boolean
508
+ /**
509
+ * The one weak handle every selection index holds this value by, or `null` where none does.
510
+ *
511
+ * 13.1 AND 13.6: a value filed for the bare sweep or carrying `tags` is findable by one, and
512
+ * every index holds the same handle, so an eviction drops it from all of them at once.
513
+ */
514
+ declare ref: WeakRef<Cell> | null
515
+ /**
516
+ * Whether this value is filed for the bare selection — once, where it first becomes a load.
517
+ *
518
+ * See `fileProducer`. Not cleared by an eviction: dropping `ref` is what takes an evicted entry
519
+ * out, and this staying set is what keeps its next load from filing it again.
520
+ */
521
+ declare filed: boolean
522
+ /**
523
+ * Whether what this value was built in has stopped — the setup or the request that owned it.
524
+ *
525
+ * 12.14. Set by `orphan`; the value lets go of its sources once nothing
526
+ * reads it (`releaseOrphan`), which may be at once or when the last reader outside its owner leaves.
527
+ */
528
+ declare orphaned: boolean
529
+ /** A cell's wake, which is a run of the graph: on the prototype, from `Reactive.ts` — see above. */
530
+ declare notify: () => void
531
+
532
+ constructor(
533
+ label: string,
534
+ body: ((args: unknown) => unknown) | null,
535
+ args: unknown,
536
+ options: ReactiveOptions<unknown, unknown, never> | undefined,
537
+ streaming: boolean,
538
+ ) {
539
+ // Every field, in one order, `undefined` included.
540
+ this.readers = []
541
+ this.deadReaders = 0
542
+ this.probeReaders = []
543
+ this.deadProbeReaders = 0
544
+ this.sources = []
545
+ this.probeSources = []
546
+ this.probeCursor = 0
547
+ this.cursor = 0
548
+ this.seen = null
549
+ this.seenThrough = 0
550
+ this.scanningFrom = -1
551
+ this.label = label
552
+ this.body = body
553
+ this.args = args
554
+ this.value = undefined
555
+ this.landed = false
556
+ this.servable = false
557
+ this.direct = false
558
+ this.loading = false
559
+ this.failure = undefined
560
+ this.identityFn = comparatorFor(
561
+ options?.identity as Identity<unknown> | undefined,
562
+ )
563
+ this.declaredIdentityFn = this.identityFn
564
+ this.transform = (options?.transform ?? null) as
565
+ ((value: unknown) => unknown) | null
566
+ this.schema = (options?.schema ?? null) as Schema<unknown> | null
567
+ this.ring = EMPTY_RING
568
+ this.ringBase = 0
569
+ // 6.2 DECIDED ONCE, here rather than per production: a body is what makes a value a
570
+ // producer, and a plain state is the one this must not reach. See `expiryFor`.
571
+ this.expiry = expiryFor(
572
+ options?.ttl,
573
+ // A store is a producer too (8.2): there is somewhere to get the value back from, so
574
+ // `ttl` on a value holding one drops rather than being inert.
575
+ body !== null || options?.store !== undefined,
576
+ )
577
+ this.ordinal = 0
578
+ this.generation = 0
579
+ this.alive = true
580
+ this.state = CLEAN
581
+ this.running = false
582
+ this.aborted = false
583
+ this.adoption = null
584
+ this.cap = capFor(label, options?.throttle, options?.debounce)
585
+ const tags = options?.tags
586
+ this.tags =
587
+ tags === undefined
588
+ ? null
589
+ : typeof tags === 'function'
590
+ ? tags(args as never)
591
+ : tags
592
+ this.mutation =
593
+ (options as { [MUTATION]?: true } | undefined)?.[MUTATION] === true
594
+ this.local = false
595
+ const store = options?.store
596
+ this.store =
597
+ store === undefined
598
+ ? null
599
+ : {
600
+ store: (typeof store === 'function'
601
+ ? store(args as never)
602
+ : store) as Store<unknown>,
603
+ ttl: options?.ttl ?? Number.POSITIVE_INFINITY,
604
+ restoring: false,
605
+ writing: false,
606
+ pending: false,
607
+ unconfirmed: undefined,
608
+ unwatch: null,
609
+ }
610
+ this.by = (options?.by ?? null) as
611
+ string | ((element: unknown) => unknown) | null
612
+ this.probePass = 0
613
+ this.owes = OWES_NOTHING
614
+ this.isEffect = false
615
+ this.isMirror = false
616
+ this.adopter = null
617
+ this.callable = null
618
+ this.stream = streaming ? newStream(null) : null
619
+ this.plain = this.expiry === null && this.stream === null
620
+ this.bareWrite =
621
+ this.schema === null && this.transform === null && !streaming
622
+ this.simple = false
623
+ this.scope = currentScope()
624
+ this.global = options?.global === true
625
+ this.ref = null
626
+ this.filed = false
627
+ this.orphaned = false
628
+ simpleShape(this)
629
+ }
630
+ }
631
+
632
+ /** What a member's `this` is, and the one way from the value an app holds to its record. */
633
+ export type Callable = { [CELL]: Cell }
634
+
635
+ /**
636
+ * Throws where a value declares both `throttle` and `debounce`.
637
+ *
638
+ * 5.14 is a BUILD error and there is no build yet, so it lands at construction — the
639
+ * earliest moment that exists, and the one the app still has a stack for. Naming the value
640
+ * is the clause's own requirement; without it a page declaring both on one of forty values
641
+ * says only that something did. One statement for both producers of a window: a value's
642
+ * (5.8) and a keyed value's, which caps starts rather than wakes (5.19).
643
+ */
644
+ export function refuseBothCaps(
645
+ label: string,
646
+ throttle: number | undefined,
647
+ debounce: number | undefined,
648
+ ): void {
649
+ if (throttle !== undefined && debounce !== undefined)
650
+ throw new Error(
651
+ `${label} declares both throttle and debounce. A value is capped one way or the other.`,
652
+ )
653
+ }
654
+
655
+ export function capFor(
656
+ label: string,
657
+ throttle: number | undefined,
658
+ debounce: number | undefined,
659
+ ): Cap | null {
660
+ refuseBothCaps(label, throttle, debounce)
661
+ const ms = throttle ?? debounce
662
+ if (ms === undefined) return null
663
+ return {
664
+ leading: throttle !== undefined,
665
+ ms,
666
+ timer: null,
667
+ held: undefined,
668
+ holding: false,
669
+ minted: undefined,
670
+ owed: false,
671
+ reloading: false,
672
+ }
673
+ }
674
+
675
+ /**
676
+ * Compiles `identity` into a comparator, or `null` for the default `Object.is`.
677
+ *
678
+ * THE DEFAULT IS THE REFERENCE, and `structural` is exported for an app to pass.
679
+ *
680
+ * THE CASE FOR A STRUCTURAL DEFAULT IS REAL: a reload that fetched an equal
681
+ * payload builds a FRESH object, so a reference compare never fires and every reader
682
+ * wakes on a value that did not change. What decides it against that is the cost on
683
+ * the shape an app actually holds — a compare walks the whole value on EVERY write,
684
+ * where the wake it avoids is paid only when the payload really is equal. A grid of
685
+ * rows re-assembled per recompute pays the deep walk every time and collapses never.
686
+ *
687
+ * So the framework takes the cheap, predictable default — `===` is what JavaScript
688
+ * means by "the same value" — and the app names `identity: structural` on the values
689
+ * where re-materialization is the common case. 5.5's "not equal wherever it cannot
690
+ * decide" is unchanged; it is just no longer the default reading.
691
+ *
692
+ * `identity` is discriminated by ARITY (5.3), once, at construction — not per compare.
693
+ *
694
+ * NULL IS THE DEFAULT, not a function that implements it. `produce` compares against
695
+ * `null` and calls `Object.is` directly, which takes an INDIRECT call off the write path:
696
+ * the site is polymorphic across the default, a projection closure and whatever an app
697
+ * passed, so it is not one an engine can speculate through. The saving is the indirection
698
+ * rather than the comparison — `Object.is` is itself the fastest spelling of it.
699
+ */
700
+ export function comparatorFor(
701
+ identity: Identity<unknown> | undefined,
702
+ ): ((next: unknown, previous: unknown) => boolean) | null {
703
+ if (identity === undefined) return null
704
+ if (identity.length >= 2)
705
+ return identity as (next: unknown, previous: unknown) => boolean
706
+ const project = identity as (value: unknown) => unknown
707
+ return (next, previous) => project(next) === project(previous)
708
+ }
709
+
710
+ /**
711
+ * Recomputes `simple` and re-seats the callable on the matching prototype.
712
+ *
713
+ * `simple` IN ONE PLACE. A second copy of this conjunction is the drift that would let one of the
714
+ * sites go on reading `true` after the field under it moved — and what the short write would then
715
+ * skip is a cap, a ring or a declared `identity`, silently. The prototype that goes with it is
716
+ * `seat`'s, taken where the transition that moved a field under it ends.
717
+ */
718
+ export function simpleShape(cell: Cell): void {
719
+ cell.simple =
720
+ cell.bareWrite &&
721
+ // `plain` carries `expiry === null` and `stream === null` already.
722
+ cell.plain &&
723
+ cell.cap === null &&
724
+ cell.store === null &&
725
+ cell.identityFn === null
726
+ }
727
+
728
+ /**
729
+ * The record `value` keeps its state on, for a reader outside the core: `value` is a `Reactive`, and
730
+ * this is the one cast from what an app holds to the record, rather than one per reader.
731
+ */
732
+ export function cellOf(value: unknown): Cell {
733
+ return (value as Callable)[CELL]
734
+ }