@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
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * What an `Rpc` asks of the server it runs on, as slots the server fills.
3
3
  *
4
- * Filled by `#server/installServer.ts`, and `raw` by `bootApp`: the request a rung is handed (16.11),
5
- * the app a `raw` call is answered by in process (16.42), and where a call reports the value it
6
- * reached, so a page's render can leave it for the browser's own call (41.13). A leaf, for
4
+ * Filled by `#server/installServer.ts`, `raw` by `bootApp` and `following` by each app's followers:
5
+ * the request a rung is handed (16.11), the app a `raw` call is answered by in process (16.42), where
6
+ * a call reports the value it reached, so a page's render can leave it for the browser's own call
7
+ * (41.13), and who a trigger reaches (18.3). A leaf, for
7
8
  * `CURRENT_ROUTER`'s reason: the isomorphic `Rpc` reads these and a browser bundle must not reach
8
9
  * what fills them.
9
10
  */
@@ -18,33 +19,30 @@ export const RPC_SERVER: {
18
19
  */
19
20
  timeout: () => number | undefined
20
21
  /**
21
- * A trigger on an `Rpc`, sent to every browser following what its pattern names.
22
+ * Every app's followers while anyone follows (`#server/Followers.ts`), which a trigger reaches.
22
23
  *
23
- * 7.10, 7.18.
24
+ * Empty in a browser, where a trigger is the copy's own.
24
25
  */
25
- broadcast:
26
- | ((
27
- rpc: object,
28
- member: 'invalidate' | 'refresh',
29
- pattern: unknown,
30
- ) => void)
31
- | null
32
- /**
33
- * A free trigger, sent to every followed copy carrying one of `tags`, or to every one where
34
- * `tags` is `null`.
35
- *
36
- * 13.15.
37
- */
38
- swept:
39
- | ((member: 'invalidate' | 'refresh', tags: string[] | null) => void)
40
- | null
41
- /**
42
- * The `global` entry an answer came from, and the key it is filed under (`GLOBAL_GETS`).
43
- *
44
- * 18.8 — so a follower subscribed before it existed, or fed from one since evicted, is fed
45
- * from this one.
46
- */
47
- served: ((rpc: object, serving: unknown, key: string) => void) | null
26
+ following: Set<{
27
+ /** A trigger on an `Rpc`, sent to every browser following what its pattern names. 7.10, 7.18. */
28
+ broadcast(
29
+ rpc: object,
30
+ member: 'invalidate' | 'refresh',
31
+ pattern: unknown,
32
+ ): void
33
+ /**
34
+ * A free trigger, sent to every followed copy carrying one of `tags`, or to every one where
35
+ * `tags` is `null`. 13.15.
36
+ */
37
+ sweep(member: 'invalidate' | 'refresh', tags: string[] | null): void
38
+ /**
39
+ * The `global` entry an answer came from, and the key it is filed under (`GLOBAL_GETS`).
40
+ *
41
+ * 18.8 — so a follower subscribed before it existed, or fed from one since evicted, is
42
+ * fed from this one.
43
+ */
44
+ served(rpc: object, serving: unknown, key: string): void
45
+ }>
48
46
  /**
49
47
  * How long a handler's own body took inside its rungs.
50
48
  *
@@ -60,8 +58,6 @@ export const RPC_SERVER: {
60
58
  raw: null,
61
59
  reached: null,
62
60
  timeout: () => undefined,
63
- broadcast: null,
64
- swept: null,
65
- served: null,
61
+ following: new Set(),
66
62
  handled: null,
67
63
  }
@@ -11,9 +11,8 @@
11
11
  // 19.6 IS THE OTHER HALF: coercion belongs to the pipeline and is never asked of a schema.
12
12
  // Together they are what lets 19.3 be enforced at all — see `runSchema`.
13
13
 
14
+ import { issuesOf, note } from './issueReport.ts'
14
15
  import type { Issues } from './Issues.ts'
15
- import { issuesOf } from './issuesOf.ts'
16
- import { note } from './note.ts'
17
16
  import { isThenable } from './reactive/isThenable.ts'
18
17
  import { untracked } from './reactive/tracking.ts'
19
18
 
@@ -6,7 +6,7 @@
6
6
  // patch records passes, so the check costs a browser replaying its server nothing, and an op naming
7
7
  // `__proto__` or a member off the prototype chain is refused at 400 rather than reached. A `test` that fails is 409, the patch's precondition rather than its form.
8
8
  import { putOwn } from './putOwn.ts'
9
- import type { PatchOp } from './reactive/PATCH_SINKS.ts'
9
+ import type { PatchOp } from './reactive/patchLog.ts'
10
10
  import { structural } from './reactive/structural.ts'
11
11
  import { refuse } from './refuse.ts'
12
12
 
@@ -119,4 +119,4 @@ export {
119
119
  url,
120
120
  } from './url.ts'
121
121
  export { validateJson } from './validateJson.ts'
122
- export { writePath } from './writePath.ts'
122
+ export { mutatePath, writePath } from './writePath.ts'
@@ -1,3 +1,6 @@
1
+ // AN ISSUES RECORD — what a refusal found, keyed by path (`Issues`, 15.8): filled one issue at a time
2
+ // by `note`, and handed out by `issuesOf` in the shape the value refused calls for.
3
+
1
4
  import { putOwn } from './putOwn.ts'
2
5
 
3
6
  /**
@@ -22,3 +25,22 @@ export function note(
22
25
  if (Object.hasOwn(found, path)) (found[path] as string[]).push(said)
23
26
  else putOwn(found, path, [said])
24
27
  }
28
+
29
+ /**
30
+ * Issues in the shape `Issues<T>` gives them for the value refused: by path for an object or an
31
+ * array, the bare list for anything else.
32
+ *
33
+ * DECIDED BY THE VALUE, because the value is all the runtime holds — `T` is erased. A scalar has
34
+ * no path to key by, so every issue about one stands on `''`, and handing back `{ '': [...] }`
35
+ * there is the wrapper `Issues<T>` says a reader never unwraps: `error().data[0]` read `undefined`.
36
+ */
37
+ export function issuesOf(
38
+ found: Record<string, string[]>,
39
+ value: unknown,
40
+ ): Record<string, string[]> | string[] {
41
+ if (typeof value === 'object' && value !== null) return found
42
+ const listed: string[] = []
43
+ for (const path in found)
44
+ for (const said of found[path] as string[]) listed.push(said)
45
+ return listed
46
+ }
@@ -0,0 +1,66 @@
1
+ // THE CALL STARTING A LOAD, while it starts (16.49, 16.81, 46.7). `callLoad` opens it around the
2
+ // synchronous reach and closes it after, and a transport's body — the browser's wire — reads it as
3
+ // it starts: the core runs a body's first step inside the reach, so the call is still open there
4
+ // and closed by the time anything the body awaits comes back.
5
+ //
6
+ // THE ORDER IS THE INTERFACE. A body asks once, with `startingLoadCall`, and is handed what the call
7
+ // carried rather than the live record, so a read made after an await cannot see a closed call — it
8
+ // holds what it was handed. The writer's three verbs are the only way the record moves.
9
+ //
10
+ // A module of its own because `callLoad` (shared) opens it and the wire (ui) reads it.
11
+
12
+ const STARTING: {
13
+ signal: AbortSignal | undefined
14
+ offline: ((args: unknown) => unknown) | undefined
15
+ /**
16
+ * Where the body that queues the call asks for the value the call reached, filled once the reach
17
+ * returns: what the delivered answer lands in (46.7).
18
+ */
19
+ standing: { value: unknown } | undefined
20
+ } = { signal: undefined, offline: undefined, standing: undefined }
21
+
22
+ /**
23
+ * Opens the call starting a load: the load's own abort `signal` (16.49) and the call's `offline`
24
+ * (16.81), for the body the reach runs.
25
+ */
26
+ export function beginLoadCall(
27
+ signal: AbortSignal | undefined,
28
+ offline: ((args: unknown) => unknown) | undefined,
29
+ ): void {
30
+ STARTING.signal = signal
31
+ STARTING.offline = offline
32
+ }
33
+
34
+ /** Hands what the reach returned to a body that queued the call (46.7), where one asked. */
35
+ export function reachedInLoadCall(reached: unknown): void {
36
+ const standing = STARTING.standing
37
+ if (standing !== undefined) standing.value = reached
38
+ }
39
+
40
+ /** Closes the call: a body started after this reads no signal, no `offline` and no stand. */
41
+ export function endLoadCall(): void {
42
+ STARTING.signal = undefined
43
+ STARTING.offline = undefined
44
+ STARTING.standing = undefined
45
+ }
46
+
47
+ /**
48
+ * What the call starting this load carries, read by the body before anything awaits — both
49
+ * `undefined` for a load no call started (a refresh, a reload).
50
+ */
51
+ export function startingLoadCall(): {
52
+ signal: AbortSignal | undefined
53
+ offline: ((args: unknown) => unknown) | undefined
54
+ } {
55
+ return { signal: STARTING.signal, offline: STARTING.offline }
56
+ }
57
+
58
+ /**
59
+ * Where the value the call reaches will land, for a body that queues the call (46.7) — filled by
60
+ * `reachedInLoadCall` once the reach returns.
61
+ */
62
+ export function standForLoadCall(): { value: unknown } {
63
+ const standing = { value: undefined }
64
+ STARTING.standing = standing
65
+ return standing
66
+ }
@@ -3,7 +3,7 @@
3
3
  // `patch` an event stream writes as events (18.20), multiplexed by `id`.
4
4
 
5
5
  import type { Problem } from './Failed.ts'
6
- import type { PatchOp } from './reactive/PATCH_SINKS.ts'
6
+ import type { PatchOp } from './reactive/patchLog.ts'
7
7
 
8
8
  /**
9
9
  * What a browser sends over the mux: a subscription, naming the version it holds (18.9), or its end.
@@ -11,13 +11,13 @@ import { checkArgs } from '../refuse.ts'
11
11
  import type { Schema } from '../Schema.ts'
12
12
  import {
13
13
  ARGS_GATE,
14
+ canonicalKey,
14
15
  type Gated,
15
16
  normalized,
16
17
  PARAMETER_DEFAULTS,
17
18
  } from './argsContract.ts'
18
- import { canonicalKey } from './canonicalKey.ts'
19
19
  import { CELL } from './CELL.ts'
20
- import { ENTRY_LIVES } from './ENTRY_LIVES.ts'
20
+ import { type Callable, type Cell, refuseBothCaps } from './cellShape.ts'
21
21
  import { armTimer } from './Expiry.ts'
22
22
  import { KEYED_BRAND } from './KEYED_BRAND.ts'
23
23
  import { matchesPattern } from './matchesPattern.ts'
@@ -28,14 +28,13 @@ import {
28
28
  createReactive,
29
29
  failedTransiently,
30
30
  isStreamBody,
31
- leaveSelections,
32
31
  type Reactive,
33
32
  type ReactiveOptions,
34
- refuseBothCaps,
35
33
  signalMoved,
36
34
  startDeferred,
37
35
  unwatchStore,
38
36
  } from './Reactive.ts'
37
+ import { leaveSelections } from './selections.ts'
39
38
  import {
40
39
  detach,
41
40
  detachProbes,
@@ -43,7 +42,6 @@ import {
43
42
  newSubscriber,
44
43
  newTracked,
45
44
  type Subscriber,
46
- type Tracked,
47
45
  TRACKING,
48
46
  trackProbe,
49
47
  } from './tracking.ts'
@@ -89,7 +87,7 @@ export function isKeyed(
89
87
  * The args are the entry's body argument and its cell already holds them for every run.
90
88
  */
91
89
  function argsOf(entry: unknown): unknown {
92
- return (entry as { [CELL]: { args: unknown } })[CELL].args
90
+ return (entry as Callable)[CELL].args
93
91
  }
94
92
 
95
93
  // One entry of `Lifetime.followed`, which is in recency order: what an eviction needs beside when
@@ -97,11 +95,25 @@ function argsOf(entry: unknown): unknown {
97
95
  type Follower = {
98
96
  at: number
99
97
  ms: number
100
- cell: Tracked & { servable: boolean; loading: boolean }
98
+ cell: Cell
101
99
  reader: Subscriber
102
100
  evict: () => void
103
101
  }
104
102
 
103
+ /**
104
+ * Each followed entry's `Follower`, by its cell: when it last produced, and how long it lives (11.45).
105
+ */
106
+ const ENTRY_LIVES = new WeakMap<Cell, Follower>()
107
+
108
+ /**
109
+ * When the entry `cell` is stops being servable, by its `Keyed`'s `ttl` — infinity where it is no
110
+ * followed entry. What `deadlineOf` reads beside the value's own `ttl` (21.8).
111
+ */
112
+ export function entryDeadline(cell: Cell): number {
113
+ const entry = ENTRY_LIVES.get(cell)
114
+ return entry === undefined ? Number.POSITIVE_INFINITY : entry.at + entry.ms
115
+ }
116
+
105
117
  /**
106
118
  * The life of every entry of one `Keyed`, evicting each once `ttl` passes without a production.
107
119
  *
@@ -138,10 +150,10 @@ class Lifetime {
138
150
  this.timer = null
139
151
  }
140
152
 
141
- follow(key: string, entry: { [CELL]: Tracked }, evict: () => void): void {
153
+ follow(key: string, entry: Callable, evict: () => void): void {
142
154
  // 11.33: `Infinity` is the life of the scope, which no timer here can reach.
143
155
  if (this.ms === Number.POSITIVE_INFINITY) return
144
- const cell = entry[CELL] as Follower['cell']
156
+ const cell = entry[CELL]
145
157
  // A MIRROR WITH NO ADOPTER — `Subscriber.isMirror` says why.
146
158
  const reader = newSubscriber([cell], null, true)
147
159
  const follower: Follower = { at: 0, ms: this.ms, cell, reader, evict }
@@ -424,13 +436,9 @@ export function createKeyed<
424
436
  )
425
437
  entries.set(key, created)
426
438
  if (lifetime !== null)
427
- lifetime.follow(
428
- key,
429
- created as unknown as { [CELL]: Tracked },
430
- () => {
431
- release(key, created)
432
- },
433
- )
439
+ lifetime.follow(key, created as unknown as Callable, () => {
440
+ release(key, created)
441
+ })
434
442
  if (starts !== null)
435
443
  starts.reached(created, () => {
436
444
  // 5.20: superseded before it started — not held, so a later reach starts afresh.