@abide/abide 0.124.1 → 0.125.1

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 (74) hide show
  1. package/ABIDE.md +4 -0
  2. package/CHANGELOG.md +50 -0
  3. package/bin/abide.ts +3 -2
  4. package/docs/REGISTRY.md +67 -40
  5. package/docs/RULEBOOK.md +206 -18
  6. package/docs/abide.md +393 -67
  7. package/package.json +1 -1
  8. package/src/compiler/appMap.ts +14 -1
  9. package/src/compiler/compileApp.ts +1 -0
  10. package/src/compiler/declaredExports.ts +41 -0
  11. package/src/compiler/handlersUnder.ts +1 -0
  12. package/src/compiler/hookCalls.ts +1 -0
  13. package/src/compiler/projectShadow.ts +52 -2
  14. package/src/compiler/readsIn.ts +39 -34
  15. package/src/server/PageRender.ts +7 -8
  16. package/src/server/abideModules.ts +22 -9
  17. package/src/server/addressed.ts +14 -0
  18. package/src/server/answerRequest.ts +115 -52
  19. package/src/server/answerSocket.ts +6 -5
  20. package/src/server/answerWorker.ts +34 -23
  21. package/src/server/assistant.ts +141 -35
  22. package/src/server/banner.ts +9 -5
  23. package/src/server/bridgeRelay.ts +3 -3
  24. package/src/server/callerOf.ts +5 -0
  25. package/src/server/claudeCode.ts +20 -11
  26. package/src/server/commands.ts +14 -7
  27. package/src/server/createApp.ts +65 -12
  28. package/src/server/devWorker.ts +18 -16
  29. package/src/server/faceOf.ts +3 -1
  30. package/src/server/generatedSurfaces.ts +6 -5
  31. package/src/server/handlerFileMount.ts +2 -0
  32. package/src/server/hooks.ts +54 -8
  33. package/src/server/index.ts +21 -4
  34. package/src/server/invokeHandler.ts +1 -1
  35. package/src/server/mountHandlers.ts +9 -7
  36. package/src/server/principal.ts +3 -2
  37. package/src/server/render.ts +11 -2
  38. package/src/server/requestScope.ts +61 -1
  39. package/src/server/responseRelay.ts +9 -3
  40. package/src/server/serveDev.ts +18 -3
  41. package/src/server/sqliteStore.ts +65 -0
  42. package/src/server/testMount.ts +1 -0
  43. package/src/shared/AssistantEvent.ts +40 -0
  44. package/src/shared/BrowserHooks.ts +73 -0
  45. package/src/shared/CURRENT_ROUTER.ts +3 -1
  46. package/src/shared/Issues.ts +11 -3
  47. package/src/shared/Middleware.ts +14 -7
  48. package/src/shared/UNEXPECTED.ts +1 -1
  49. package/src/shared/answerOf.ts +9 -4
  50. package/src/shared/imagePiece.ts +85 -0
  51. package/src/shared/index.ts +17 -0
  52. package/src/shared/isServer.ts +15 -0
  53. package/src/shared/navigate.ts +10 -3
  54. package/src/shared/onError.ts +51 -0
  55. package/src/shared/onRefusal.ts +47 -0
  56. package/src/shared/online.ts +5 -1
  57. package/src/shared/reactive/Keyed.ts +12 -1
  58. package/src/shared/reactive/Reactive.ts +53 -25
  59. package/src/shared/reactive/cellShape.ts +4 -3
  60. package/src/shared/reactive/poll.ts +49 -0
  61. package/src/shared/reactive/scoped.ts +10 -1
  62. package/src/shared/reactive/scoping.ts +14 -0
  63. package/src/shared/reactive/watch.ts +19 -8
  64. package/src/shared/resultsOf.ts +23 -0
  65. package/src/shared/route.ts +18 -4
  66. package/src/shared/rpc.ts +125 -30
  67. package/src/shared/seededDocument.ts +5 -6
  68. package/src/shared/storedValue.ts +32 -0
  69. package/src/shared/webStore.ts +54 -0
  70. package/src/ui/Router.ts +42 -9
  71. package/src/ui/outboxQueue.ts +1 -1
  72. package/src/ui/wire.ts +4 -4
  73. package/src/shared/KEEP_OPENED.ts +0 -7
  74. /package/src/{server → shared}/IMAGE_TYPES.ts +0 -0
package/ABIDE.md CHANGED
@@ -29,12 +29,16 @@ affected code saying what it did, and tell the user.
29
29
  calls it. Every component has a test that `mount`s it and counts the work an
30
30
  interaction did with `measure`, both from `@abide/harness/abide` (RULEBOOK 38.119, 43.23) — a
31
31
  test that only reads the text back passes against a component doing ten times the work.
32
+ A prop the test moves is handed as a getter — `Label({ get label() { return source() } })` —
33
+ and is read through it on every read (RULEBOOK 38.134); any other prop is the value it was given.
32
34
  A test waits on a value landing — `await` the handler call, or the `Reactive` the component
33
35
  reads, which is thenable (RULEBOOK 1.4) — never on `Bun.sleep` or a timer. Break the code once and
34
36
  watch a new test fail; a test that has never failed has not been shown to test anything.
35
37
  Called outside a request, a `GET` keeps its answer for the whole test process: a test that changes
36
38
  the data behind one calls its `invalidate()` in `beforeEach`. A handler that reads `config()` or
37
39
  `principal` runs inside `app.run(…)` of `await createApp()`, where the app's `onConfig` has run.
40
+ A request sent as someone is `app.fetch(request, { principal, caller })` (RULEBOOK 42.20, 42.21),
41
+ never a hand-written `abide-principal` or `abide-caller` cookie.
38
42
  `mount` sets no route, so a page stays thin: it reads the route and hands what it needs to a
39
43
  component in `lib/`, and the test mounts that component.
40
44
  - `bun run bench` — runs `harness-bench`: every `*.bench.ts` under `src/`, kept beside the code it
package/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # @abide/abide
2
2
 
3
+ ## 0.125.1
4
+
5
+ ### Patch Changes
6
+
7
+ - one late-read writer for a handler's address, a named handler rung, resultsOf reads Rpc's own members — 16.88 ([`b74dc3a`](https://github.com/briancray/abide/commit/b74dc3a99385125ad76d5180e8ad9479cb4798b5))
8
+ - b9e4187: Rung helpers, `resultsOf` and a handler's address, from updating an app to 0.125 — 16.86, 16.88, 44.51
9
+
10
+ - `resultsOf` takes any handler, whatever its args (it refused every handler with a parameter).
11
+ - A rung list a helper builds (`middleware: rungs()`, `[...rungs()]`) carries its `Middleware`s' named refusals onto the `Rpc`, as an inline list does.
12
+ - A generic rung helper takes its `Args` from the handler it is listed on again.
13
+ - A handler file's `rpc.address` is its route as soon as the file loads, so a `bun test` importing it matches it with no app booted.
14
+
15
+ MIGRATION from 0.124: a rung's `next` is typed `(ctx?: RpcContext<Args>) => Promise<…>`, so a rung written for any handler whose `next` takes a ctx with `args: () => unknown` no longer fits a handler with typed args — it could hand that handler args of the wrong shape. Type the helper over the handler's `Args` (`<Args>(…) => ((next: (ctx?: { request: Request; args: () => Args }) => Promise<unknown>, ctx: { request: Request; args: () => Args }) => unknown)[]`), or write the rung as a `Middleware`. A mismatch is now reported against `middleware` rather than as the handler not being assignable to `never`.
16
+
17
+ ## 0.125.0
18
+
19
+ ### Minor Changes
20
+
21
+ - e948e8e: `App.fetch` takes a `principal` and a `caller`, and `App.run` a `caller`, each answered as over the request's cookies with no cookie written — 42.20, 42.21
22
+ - 74eacfc: an assistant's `tool` and `result` events carry the handler they called (`{ method, address }`, as its `Rpc` reads them) and a result the value it answered, read off the app's own surface whichever provider ran the conversation — `resultsOf(events, handler)` is every successful call's value, typed as the handler's; a `Provider` now yields `ProviderEvent`s naming each tool as its `Toolbox` lists it; `AssistantMessage`, `AssistantContent` and `AssistantEvent` are exported from `@abide/abide` for the browser; `imagePiece(file)` and `imageFiles(dataTransfer)` turn a pasted, dropped or picked image into a turn's image piece, drawn down to 1568px — 44.48-44.55
23
+ - 1eaf716: `assistant` takes a `signal` in its options: aborting it ends the conversation at once, refused `aborted` at 499, even while the provider is stuck in an await — the same end a client leaving now gets — 44.57
24
+ - fd731a2: a `BridgeStatus` and `claudeCode.bridgeCommand()` carry `install`, the command that installs the bridge app the pairing link opens at the release the pairing command runs, so a page no longer parses the release out of `command` — 44.56
25
+ - c5ea214: `onError` from `@abide/abide`, called in a layout's or a page's `<script>`, hears in the browser what nothing caught — an uncaught throw, an unhandled rejection such as a call's refusal no handler caught, and an effect's throw — once each, nearest component first, for as long as the component stands — 37.16, 37.17, 37.18
26
+ - 17fdafe: `onRefusal` from `@abide/abide`, called in a layout's or a page's `<script>`, is handed in the browser every refusal a call over http is answered with — the handler's, a proxy's 401, the 503 for no answer, and one an `outbox` send gets — with the call's method and URL, once each, nearest component first, for as long as the component stands; the value still refuses — 37.22-37.27
27
+ - b436c3e: `abide dev`, `abide start`, the shell's app and a compiled executable's `start` take `--hostname` and listen on that interface alone — every interface where none is named, and the banner then lists no network address — 38.136; and `requestIP()` answers where the request being served came from, the same under `start`, `dev` and `App.listen`, or `'in-process'` for one no listener received — 22.12, 22.13
28
+ - c49316f: `isServer()` answers which side the running work is on — true inside a request, an `App.run` or a `render` even with a DOM preloaded, so an in-process test takes the server branch; an effect's throw no longer fails a server render beside that DOM, and `online` is true there — 22.11, 12.7, 23.8
29
+ - 02f34f7: a `middleware` rung is handed `ctx.lane` — the `Lane` that answers its request: a page, a handler, a public file, `openapi`, `mcp`, `bridge`, the socket upgrade, or the rest of `/__abide` — so a gate need not spell out abide's own addresses, and is handed the request below the mount — 37.19, 37.20
30
+ - 801345f: `poll` — a reactive option that refreshes the value every `poll` milliseconds, skipping a tick while it is busy and stopping with the value's owner or its `Keyed` (RULEBOOK 7.20 through 7.25)
31
+ - 3ffb8c0: `route.index` is the entry's place in the history the app's router wrote, and `navigate(by)` steps the history and settles once the step has arrived — 23.28, 23.29, 30.38, 30.39
32
+ - 380be01: `abide routes` names the rungs each handler's `middleware` declares, as written, and `--json` carries them as `middleware` on every route — `null` where the options are not written inline — 38.135
33
+ - 226e6a7: a refusal a rung names is on its `Rpc`'s failures and narrows by name, and `Middleware` takes the refusals it may answer with as a third parameter — 16.8, 16.86
34
+ - cbcd422: `webStore` (from `@abide/abide`) and `sqliteStore` (from `@abide/abide/server`) — shipped `Store`s for Web Storage, following other tabs' writes and inert on a server, and for a `bun:sqlite` table; both keep the value's `ttl` beside it and run an optional `schema` over what they read (RULEBOOK 8.22 through 8.28)
35
+
36
+ ### Patch Changes
37
+
38
+ - 6f2742a: a handler whose parameter carries no annotation takes its `Args` from the `args` its options declare, now stated and gated — 16.87
39
+ - eb201fb: one spelling each for a server's stops, a refused call and a present member; endedBy races a fresh abort per step ([`47dffbf`](https://github.com/briancray/abide/commit/47dffbf3563895200aabed1fc4d7a65aa6764fe0))
40
+ - eb201fb: a render outside every request is torn down as a request is, and so is mount's server pass — 12.5, 38.119 ([`a7a2ada`](https://github.com/briancray/abide/commit/a7a2ada76a61df4f6632542b01083383d6218910))
41
+ - eb201fb: renumber clauses 22.11-12, 37.16-17, 38.134-135 to follow those merged beside them ([`d4ca7c5`](https://github.com/briancray/abide/commit/d4ca7c57ec2deb91eef08c6182729d561da5e8c6))
42
+ - eb201fb: a navigation the worker forwards is the page that hydrates — chromium sends it navigate with its destination empty — 41.29, 45.25 ([`f94c1bd`](https://github.com/briancray/abide/commit/f94c1bd4cfd9a416036bd8d918ce109f07642b66))
43
+ - 5d05e0e: `onError` from `@abide/abide` throws where it could never file — a `<script server>`, a server module, a module's top level, a later callback — naming `@abide/abide/server`'s, rather than doing nothing (RULEBOOK 37.21).
44
+ - 693c7f3: `abide check` holds an element's `bind:` to what the element writes back — a numeric input's `number | undefined`, a text field's string, a `<select>`'s strings, a boolean for `checked` and `open`, files for `files` — and a `type` written as an expression to the union of them — 32.78
45
+ - 20bb20a: a handler's value, and any `reactive` a module declares, built on a server where it is first reached, is no longer owned by the render or the component setup that reached it first — so it is not released when that one ends, and the next read neither runs its body again nor restarts its stream. A request's own instance is still that request's — 12.17
46
+ - d3b0202: `Issues<typeof handler>` is the issues of what the handler is called with, so a form's refusal state names the handler rather than `Parameters<typeof handler>[0]` — 19.26
47
+ - ce73c75: a prop handed to a component bound for `mount` as a getter is read through it on every read — 38.134
48
+ - e93eaf6: A mutator on a `Reactive` list typed with `undefined` or `null` — `drafts?.push(d)`, or `drafts.push(d)` once narrowed — is a write that wakes its readers, as on a list typed without them — 31.9
49
+ - 92f7c58: the offline worker asks the network for a navigation as that navigation, so a sign-in proxy redirects it rather than answering a fetch 401, and drops a saved copy the network answers over with a redirect or a 4xx — 45.25, 45.26
50
+ - 26ebcb7: a stream whose owner stopped and whose last reader left is started again by the next read, rather than staying stopped — a `{#for}` row or `{#if}` arm that comes back, or a streamed `GET` shared by a reader that left; and `mount` tears its server pass down as `render` does — 12.14, 12.16
51
+ - f215b78: a store miss that falls back to the initial value no longer writes it back through `set`, so a server render no longer overwrites a browser's store with the default — 8.8
52
+
3
53
  ## 0.124.1
4
54
 
5
55
  ### Patch Changes
package/bin/abide.ts CHANGED
@@ -821,14 +821,15 @@ async function lsp({ values }: Given): Promise<number> {
821
821
  */
822
822
  async function dev(
823
823
  { root }: AppDirectories,
824
- { values: { port } }: Given,
824
+ { values: { port, hostname } }: Given,
825
825
  ): Promise<undefined> {
826
826
  process.env.NODE_ENV ??= 'development'
827
827
  const server = await serveDev({
828
828
  root,
829
829
  port: port === undefined ? undefined : Number(port),
830
+ hostname,
830
831
  })
831
- console.log(banner('abide', 'dev', packageUnder(root), server))
832
+ console.log(banner('abide', 'dev', packageUnder(root), server, hostname))
832
833
  return undefined
833
834
  }
834
835
 
package/docs/REGISTRY.md CHANGED
@@ -62,8 +62,8 @@ Accepted, Failures>` is the inner value's own `Accepted`. Then `Failures`, then
62
62
  | `Shaped` | `unknown` | What a `transform` hands back: the value to store, or a refusal. | 4.6, 4.9 |
63
63
  | `Produced` | `unknown` | What a production carries, where that differs from what is stored. | 1.2, 9.3 |
64
64
  | `Args` | `Record<string, JsonValue> \| undefined` | The key of a keyed value. | 9.4, 11.24, 11.25, 11.26, 11.27, 11.29, 11.31, 11.64, 19.15 |
65
- | `reactive` | `<Computed, Shaped = Awaited<Computed>, Gate = Schema<Awaited<Computed>>>(body: () => Computed, options?: Omit<ReactiveOptions<Awaited<NoInfer<Computed>>, Kept<Shaped>, never>, 'schema'> & { transform?: (value: Awaited<NoInfer<Computed>>) => Shaped; schema?: Gate & Schema<Awaited<NoInfer<Computed>>> }) => Reactive<Kept<Shaped>, Awaited<Computed>, AdoptedFailures<Computed> \| Refused<Shaped> \| Gated<Gate, Awaited<Computed>>, AdoptedProduced<Computed, Kept<Shaped>>>` | The unkeyed body overload. | 3.9, 11.1, 11.3, 11.5, 11.7, 11.8, 11.9, 11.10, 11.11, 11.12, 11.13, 11.14, 11.15, 11.16, 11.17, 11.18, 11.19, 11.20, 11.21, 11.22, 11.32, 11.33, 11.50, 11.51, 11.52, 11.53, 11.54, 11.57, 11.58, 41.6, 11.62, 11.63, 11.65, 11.66, 12.14, 19.24 |
66
- | `reactive` | `<Chunk, Shaped = Chunk[], Gate = Schema<Chunk[]>>(body: () => AsyncGenerator<Chunk> \| Promise<AsyncGenerator<Chunk>>, options?: Omit<ReactiveOptions<Chunk[], Kept<Shaped>, never>, 'schema'> & { transform?: (value: Chunk[]) => Shaped; schema?: Gate & Schema<Chunk[]> }) => Reactive<Kept<Shaped>, Chunk[], Refused<Shaped> \| Gated<Gate, Chunk[]>, Chunk>` | The streaming body overload. | 3.7, 3.8, 4.8, 9.1, 9.2, 9.6, 9.7, 9.8, 9.9 |
65
+ | `reactive` | `<Computed, Shaped = Awaited<Computed>, Gate = Schema<Awaited<Computed>>>(body: () => Computed, options?: Omit<ReactiveOptions<Awaited<NoInfer<Computed>>, Kept<Shaped>, never>, 'schema'> & { transform?: (value: Awaited<NoInfer<Computed>>) => Shaped; schema?: Gate & Schema<Awaited<NoInfer<Computed>>> }) => Reactive<Kept<Shaped>, Awaited<Computed>, AdoptedFailures<Computed> \| Refused<Shaped> \| Gated<Gate, Awaited<Computed>>, AdoptedProduced<Computed, Kept<Shaped>>>` | The unkeyed body overload. | 3.9, 11.1, 11.3, 11.5, 11.7, 11.8, 11.9, 11.10, 11.11, 11.12, 11.13, 11.14, 11.15, 11.16, 11.17, 11.18, 11.19, 11.20, 11.21, 11.22, 11.32, 11.33, 11.50, 11.51, 11.52, 11.53, 11.54, 11.57, 11.58, 41.6, 11.62, 11.63, 11.65, 11.66, 12.14, 12.17, 19.24 |
66
+ | `reactive` | `<Chunk, Shaped = Chunk[], Gate = Schema<Chunk[]>>(body: () => AsyncGenerator<Chunk> \| Promise<AsyncGenerator<Chunk>>, options?: Omit<ReactiveOptions<Chunk[], Kept<Shaped>, never>, 'schema'> & { transform?: (value: Chunk[]) => Shaped; schema?: Gate & Schema<Chunk[]> }) => Reactive<Kept<Shaped>, Chunk[], Refused<Shaped> \| Gated<Gate, Chunk[]>, Chunk>` | The streaming body overload. | 3.7, 3.8, 4.8, 9.1, 9.2, 9.6, 9.7, 9.8, 9.9, 12.14, 12.17, 12.16 |
67
67
  | `reactive` | `<Chunk, Args, Shaped = Chunk[], Gate = Schema<Chunk[]>, ArgsGate = Schema<Args>>(body: (args: Args) => AsyncGenerator<Chunk> \| Promise<AsyncGenerator<Chunk>>, options?: Omit<ReactiveOptions<Chunk[], Kept<Shaped>, never, Args>, 'schema' \| 'args'> & { transform?: (value: Chunk[]) => Shaped; schema?: Gate & Schema<Chunk[]>; args?: ArgsGate & Schema<Args> }) => Keyed<Kept<Shaped>, Args, Chunk[], Refused<Shaped> \| Gated<Gate, Chunk[]> \| Gated<ArgsGate, Args>, Chunk>` | The keyed streaming body overload. | 9.6, 9.9 |
68
68
  | `reactive` | `<Chunk, Args, Shaped = Chunk[], Gate = Schema<Chunk[]>, ArgsGate = Schema<Args \| undefined>>(body: (args?: Args) => AsyncGenerator<Chunk> \| Promise<AsyncGenerator<Chunk>>, options?: Omit<ReactiveOptions<Chunk[], Kept<Shaped>, never, Args \| undefined>, 'schema' \| 'args'> & { transform?: (value: Chunk[]) => Shaped; schema?: Gate & Schema<Chunk[]>; args?: ArgsGate & Schema<Args \| undefined> }) => Keyed<Kept<Shaped>, Args \| undefined, Chunk[], Refused<Shaped> \| Gated<Gate, Chunk[]> \| Gated<ArgsGate, Args \| undefined>, Chunk>` | The keyed streaming overload for a body whose parameter is optional. | 11.2 |
69
69
  | `reactive` | `<Computed, Args, Shaped = Awaited<Computed>, Gate = Schema<Awaited<Computed>>, ArgsGate = Schema<Args>>(body: (args: Args) => Computed, options?: Omit<ReactiveOptions<Awaited<NoInfer<Computed>>, Kept<Shaped>, never, Args>, 'schema' \| 'args'> & { transform?: (value: Awaited<NoInfer<Computed>>) => Shaped; schema?: Gate & Schema<Awaited<NoInfer<Computed>>>; args?: ArgsGate & Schema<Args> }) => Keyed<Kept<Shaped>, Args, Awaited<Computed>, AdoptedFailures<Computed> \| Refused<Shaped> \| Gated<Gate, Awaited<Computed>> \| Gated<ArgsGate, Args>, AdoptedProduced<Computed, Kept<Shaped>>>` | The keyed body overload. | 11.2, 11.3, 11.4, 11.6, 11.7, 11.23, 11.55, 11.62, 19.24 |
@@ -73,6 +73,8 @@ Accepted, Failures>` is the inner value's own `Accepted`. Then `Failures`, then
73
73
  | `reactive` | `<Accepted>() => Reactive<Kept<Accepted>, Accepted, Refused<Accepted>>` | The empty overload, for a value nothing has written yet. | 4.14 |
74
74
  | `Transformer` | `<Accepted, Stored, Failures = never>(value: Accepted) => Stored \| Failures` | The shape of a `transform`. | 4.6, 4.7, 4.8 |
75
75
  | `Store` | `{ get: () => Stored \| undefined \| Promise<Stored \| undefined>; set: (value: Stored, retention: { ttl: number }) => void \| Promise<void>; watch?: (changed: () => void) => () => void }` | Where a value lives when this process does not. | 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 8.10, 8.11, 8.12, 8.13, 8.14, 8.15, 8.16, 8.17, 8.18, 8.19, 8.20, 8.21 |
76
+ | `webStore` | `<Stored>(key: string, options?: { area?: 'local' \| 'session'; schema?: Schema<Stored> }) => Store<Stored>` | A `Store` kept in the browser's Web Storage. | 8.22, 8.23, 8.24, 8.26, 8.27, 8.28 |
77
+ | `sqliteStore` | `<Stored>(database: Database \| string, key: string, options?: { table?: string; schema?: Schema<Stored> }) => Store<Stored>` | A `Store` kept in a `bun:sqlite` table, from `@abide/abide/server`. | 8.25, 8.26, 8.27, 8.28 |
76
78
  | `Shared` | `interface Shared {}` | The app's declaration-merged registry of shared keys. | 10.3 |
77
79
  | `reactive.share` | `<Key extends string, Value>(key: Key, create: () => Reactive<Value>) => Key extends keyof Shared ? Reactive<Shared[Key]> : Reactive<Value>` | Get-or-create a reactive value in the component's scope by key. | 10.1, 10.2, 10.4, 10.5, 10.6, 10.7 |
78
80
 
@@ -98,6 +100,7 @@ type Gated<Gate, Accepted> = [Schema<Accepted>] extends [Gate] ? never : Failed<
98
100
  | `structural` | `(next: unknown, previous: unknown) => boolean` | The by-value comparator an app declares on `identity`. | 5.4, 5.5, 18.4 |
99
101
  | `by` | `(keyof Element & string) \| ((element: Element) => unknown)`, over the `Element` a `Stored` array holds | What tells one element of the value from another. | 5.22, 18.4, 18.15, 32.32 |
100
102
  | `ttl` | `number` | The life of a production, or of a keyed entry. | 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 6.10, 11.6, 11.35, 11.45, 11.48, 11.49, 11.69 |
103
+ | `poll` | `number` | How often the value refreshes itself, in milliseconds. | 7.20, 7.21, 7.22, 7.23, 7.24, 7.25 |
101
104
  | `args` | `Schema<Args>` | The gate on a keyed value's args. | 9.4, 11.28, 11.30, 11.40, 11.41, 11.56, 11.60, 11.68, 11.72 |
102
105
  | `global` | `boolean` | Opts out of the default scope into one cache shared by every caller in the process. | 11.34, 11.35, 11.36, 11.37, 11.38, 11.39, 11.53, 11.67 |
103
106
  | `tags` | `string[] \| ((args: Args) => string[])` | What a `Selection` matches on. | 11.43, 11.44, 18.4, 18.15 |
@@ -222,16 +225,16 @@ type Gated<Gate, Accepted> = [Schema<Accepted>] extends [Gate] ? never : Failed<
222
225
  | `Value` | `unknown` | What the addressed `Reactive` holds. | 16.3, 16.30 |
223
226
  | `Produced` | `unknown` | What it yields, per the unit rule. | 1.2, 16.3 |
224
227
  | `Args` | `Record<string, JsonValue> \| undefined` | The arguments, in the body on a mutation and in the URL on a `GET` or `DELETE`. | 11.24, 16.18, 19.15 |
225
- | `Middleware` | `Middleware<Answer = never, Extra extends object = object> = <Given extends { request: Request } & Extra, Result>(next: (ctx?: Given) => Promise<Result>, ctx: Given) => Result \| Answer \| Failed<string, unknown> \| Promise<Result \| Answer \| Failed<string, unknown>>` | One rung, written once for every lane whose context carries `Extra`. | 16.14, 16.15, 16.16, 16.21, 37.14, 37.15 |
226
- | `GET` | `<Stored, Accepted, Failures, Produced>(handler: Reactive<Stored, Accepted, Failures, Produced>, options?: RpcOptions<undefined>) => Rpc<Stored, undefined, Failures, Produced>` | Declares a read any surface may call. | 16.1, 16.2, 16.5, 16.6, 16.30, 16.31, 16.32, 16.68, 16.76, 16.34, 16.35, 16.36, 16.37, 16.39, 16.44, 16.45, 16.46, 16.47, 16.75, 16.50, 16.51, 16.52, 16.64, 18.1, 18.3, 18.6, 18.8, 18.10, 18.12, 18.21, 18.24, 18.27 |
227
- | `GET` | `<Stored, Args, Accepted, Failures, Produced>(handler: Keyed<Stored, Args, Accepted, Failures, Produced>, options?: RpcOptions<Args>) => Rpc<Stored, Args, Failures, Produced>` | The keyed overload, for a `Keyed` given an address. | 11.2, 16.1, 16.3, 16.6 |
228
- | `GET` | `<Chunk, Shaped = Chunk[], Gate = Schema<Chunk[]>>(handler: () => AsyncGenerator<Chunk> \| Promise<AsyncGenerator<Chunk>>, options?: Shaping<Chunk[], Shaped, never, Gate> & RpcOptions<undefined>) => Rpc<Kept<Shaped>, undefined, Refusals<Shaped, Gate, Chunk[]>, Chunk>` | The streaming overload, whose options build the value it becomes beside its address. | 16.1, 16.6, 16.7, 16.44, 16.45, 16.46, 16.47 |
229
- | `GET` | `<Chunk, Args, Shaped = Chunk[], Gate = Schema<Chunk[]>, ArgsGate = Schema<Args>>(handler: (args: Args) => AsyncGenerator<Chunk> \| Promise<AsyncGenerator<Chunk>>, options?: Shaping<Chunk[], Shaped, Args, Gate, ArgsGate> & RpcOptions<Args>) => Rpc<Kept<Shaped>, Args, Refusals<Shaped, Gate, Chunk[], ArgsGate, Args>, Chunk>` | The keyed streaming overload. | 11.2, 16.1, 16.6, 16.7 |
230
- | `GET` | `<Chunk, Args, Shaped = Chunk[], Gate = Schema<Chunk[]>, ArgsGate = Schema<Args \| undefined>>(handler: (args?: Args) => AsyncGenerator<Chunk> \| Promise<AsyncGenerator<Chunk>>, options?: Shaping<Chunk[], Shaped, Args \| undefined, Gate, ArgsGate> & RpcOptions<Args \| undefined>) => Rpc<Kept<Shaped>, Args \| undefined, Refusals<Shaped, Gate, Chunk[], ArgsGate, Args \| undefined>, Chunk>` | The keyed streaming overload for a body whose parameter is optional. | 11.2 |
231
- | `GET` | `<Computed, Shaped = Awaited<Computed>, Gate = Schema<Awaited<Computed>>>(handler: () => Computed, options?: Shaping<Awaited<Computed>, Shaped, never, Gate> & RpcOptions<undefined>) => Rpc<Kept<Shaped>, undefined, AdoptedFailures<Computed> \| Refusals<Shaped, Gate, Awaited<Computed>>, AdoptedProduced<Computed, Kept<Shaped>>>` | The plain-function overload, whose options (`ttl`, `global`, `debounce` and the rest) build the value it becomes beside its address. | 16.1, 16.6, 16.7 |
232
- | `GET` | `<Computed, Args, Shaped = Awaited<Computed>, Gate = Schema<Awaited<Computed>>, ArgsGate = Schema<Args>>(handler: (args: Args) => Computed, options?: Shaping<Awaited<Computed>, Shaped, Args, Gate, ArgsGate> & RpcOptions<Args>) => Rpc<Kept<Shaped>, Args, AdoptedFailures<Computed> \| Refusals<Shaped, Gate, Awaited<Computed>, ArgsGate, Args>, AdoptedProduced<Computed, Kept<Shaped>>>` | The keyed plain-function overload. | 11.2, 16.1, 16.6, 16.7 |
233
- | `GET` | `<Computed, Args, Shaped = Awaited<Computed>, Gate = Schema<Awaited<Computed>>, ArgsGate = Schema<Args \| undefined>>(handler: (args?: Args) => Computed, options?: Shaping<Awaited<Computed>, Shaped, Args \| undefined, Gate, ArgsGate> & RpcOptions<Args \| undefined>) => Rpc<Kept<Shaped>, Args \| undefined, AdoptedFailures<Computed> \| Refusals<Shaped, Gate, Awaited<Computed>, ArgsGate, Args \| undefined>, AdoptedProduced<Computed, Kept<Shaped>>>` | The keyed plain-function overload for a body whose parameter is optional. | 11.2 |
234
- | `GET` | `<Accepted, Shaped = Accepted, Gate = Schema<Accepted>>(handler: Accepted \| PromiseLike<Accepted>, options?: Shaping<Accepted, Shaped, never, Gate> & RpcOptions<undefined>) => Rpc<Kept<Shaped>, undefined, Refusals<Shaped, Gate, Accepted>>` | The value overload, for what the handler owns outright, whose options build the value it becomes. | 16.1, 16.6, 16.7 |
228
+ | `Middleware` | `Middleware<Answer = never, Extra extends object = object, Refused extends Failed<string, unknown> = Failed<string, unknown>> = <Given extends { request: Request } & Extra, Result extends {} \| null \| undefined>(next: (ctx?: Given) => Promise<Result>, ctx: Given) => Result \| Answer \| Refused \| Promise<Result \| Answer \| Refused>` | One rung, written once for every lane whose context carries `Extra`. | 16.8, 16.14, 16.15, 16.16, 16.21, 16.86, 37.14, 37.15 |
229
+ | `GET` | `<Stored, Accepted, Failures, Produced, Answers extends readonly unknown[] = unknown[]>(handler: Reactive<Stored, Accepted, Failures, Produced>, options?: RpcOptions<undefined, Answers>) => Rpc<Stored, undefined, Failures \| RungRefusals<Answers>, Produced>` | Declares a read any surface may call. | 16.1, 16.2, 16.5, 16.6, 16.30, 16.31, 16.32, 16.68, 16.76, 16.34, 16.35, 16.36, 16.37, 16.39, 16.44, 16.45, 16.46, 16.47, 16.75, 16.50, 16.51, 16.52, 16.64, 12.17, 18.1, 18.3, 18.6, 18.8, 18.10, 18.12, 18.21, 18.24, 18.27 |
230
+ | `GET` | `<Stored, Args, Accepted, Failures, Produced, Answers extends readonly unknown[] = unknown[]>(handler: Keyed<Stored, Args, Accepted, Failures, Produced>, options?: RpcOptions<Args, Answers>) => Rpc<Stored, Args, Failures \| RungRefusals<Answers>, Produced>` | The keyed overload, for a `Keyed` given an address. | 11.2, 16.1, 16.3, 16.6 |
231
+ | `GET` | `<Chunk, Shaped = Chunk[], Gate = Schema<Chunk[]>, Answers extends readonly unknown[] = unknown[]>(handler: () => AsyncGenerator<Chunk> \| Promise<AsyncGenerator<Chunk>>, options?: Shaping<Chunk[], Shaped, never, Gate> & RpcOptions<undefined, Answers>) => Rpc<Kept<Shaped>, undefined, Refusals<Shaped, Gate, Chunk[]> \| RungRefusals<Answers>, Chunk>` | The streaming overload, whose options build the value it becomes beside its address. | 16.1, 16.6, 16.7, 16.44, 16.45, 16.46, 16.47 |
232
+ | `GET` | `<Chunk, Args, Shaped = Chunk[], Gate = Schema<Chunk[]>, ArgsGate = Schema<Args>, Answers extends readonly unknown[] = unknown[]>(handler: (args: Args) => AsyncGenerator<Chunk> \| Promise<AsyncGenerator<Chunk>>, options?: Shaping<Chunk[], Shaped, Args, Gate, ArgsGate> & RpcOptions<Args, Answers>) => Rpc<Kept<Shaped>, Args, Refusals<Shaped, Gate, Chunk[], ArgsGate, Args> \| RungRefusals<Answers>, Chunk>` | The keyed streaming overload. | 11.2, 16.1, 16.6, 16.7, 16.87 |
233
+ | `GET` | `<Chunk, Args, Shaped = Chunk[], Gate = Schema<Chunk[]>, ArgsGate = Schema<Args \| undefined>, Answers extends readonly unknown[] = unknown[]>(handler: (args?: Args) => AsyncGenerator<Chunk> \| Promise<AsyncGenerator<Chunk>>, options?: Shaping<Chunk[], Shaped, Args \| undefined, Gate, ArgsGate> & RpcOptions<Args \| undefined, Answers>) => Rpc<Kept<Shaped>, Args \| undefined, Refusals<Shaped, Gate, Chunk[], ArgsGate, Args \| undefined> \| RungRefusals<Answers>, Chunk>` | The keyed streaming overload for a body whose parameter is optional. | 11.2, 16.87 |
234
+ | `GET` | `<Computed, Shaped = Awaited<Computed>, Gate = Schema<Awaited<Computed>>, Answers extends readonly unknown[] = unknown[]>(handler: () => Computed, options?: Shaping<Awaited<Computed>, Shaped, never, Gate> & RpcOptions<undefined, Answers>) => Rpc<Kept<Shaped>, undefined, AdoptedFailures<Computed> \| Refusals<Shaped, Gate, Awaited<Computed>> \| RungRefusals<Answers>, AdoptedProduced<Computed, Kept<Shaped>>>` | The plain-function overload, whose options (`ttl`, `global`, `debounce` and the rest) build the value it becomes beside its address. | 16.1, 16.6, 16.7 |
235
+ | `GET` | `<Computed, Args, Shaped = Awaited<Computed>, Gate = Schema<Awaited<Computed>>, ArgsGate = Schema<Args>, Answers extends readonly unknown[] = unknown[]>(handler: (args: Args) => Computed, options?: Shaping<Awaited<Computed>, Shaped, Args, Gate, ArgsGate> & RpcOptions<Args, Answers>) => Rpc<Kept<Shaped>, Args, AdoptedFailures<Computed> \| Refusals<Shaped, Gate, Awaited<Computed>, ArgsGate, Args> \| RungRefusals<Answers>, AdoptedProduced<Computed, Kept<Shaped>>>` | The keyed plain-function overload. | 11.2, 16.1, 16.6, 16.7, 16.87 |
236
+ | `GET` | `<Computed, Args, Shaped = Awaited<Computed>, Gate = Schema<Awaited<Computed>>, ArgsGate = Schema<Args \| undefined>, Answers extends readonly unknown[] = unknown[]>(handler: (args?: Args) => Computed, options?: Shaping<Awaited<Computed>, Shaped, Args \| undefined, Gate, ArgsGate> & RpcOptions<Args \| undefined, Answers>) => Rpc<Kept<Shaped>, Args \| undefined, AdoptedFailures<Computed> \| Refusals<Shaped, Gate, Awaited<Computed>, ArgsGate, Args \| undefined> \| RungRefusals<Answers>, AdoptedProduced<Computed, Kept<Shaped>>>` | The keyed plain-function overload for a body whose parameter is optional. | 11.2, 16.87 |
237
+ | `GET` | `<Accepted, Shaped = Accepted, Gate = Schema<Accepted>, Answers extends readonly unknown[] = unknown[]>(handler: Accepted \| PromiseLike<Accepted>, options?: Shaping<Accepted, Shaped, never, Gate> & RpcOptions<undefined, Answers>) => Rpc<Kept<Shaped>, undefined, Refusals<Shaped, Gate, Accepted> \| RungRefusals<Answers>>` | The value overload, for what the handler owns outright, whose options build the value it becomes. | 16.1, 16.6, 16.7 |
235
238
  | `POST` / `PUT` / `PATCH` / `DELETE` | same as `GET` | Declares a mutation. | 16.2, 16.7, 16.32, 16.68, 16.76, 16.38, 16.53 |
236
239
  | `rpc.busy` | `(pattern?: Partial<Args>) => boolean` | `busy` narrowed to the handler's matching entries. | 13.2, 13.3, 13.12, 13.19, 46.11 |
237
240
  | `rpc.ready` | `(pattern?: Partial<Args>) => boolean` | `ready` narrowed to the handler's matching entries. | 13.11, 13.12, 13.19 |
@@ -242,11 +245,13 @@ type Gated<Gate, Accepted> = [Schema<Accepted>] extends [Gate] ? never : Failed<
242
245
  | `rpc.raw` | `(args: Args, init?: RequestInit) => Promise<Response>` | The same call handed back as the raw response. | 16.11, 16.42 |
243
246
  | `rpc.method` | `string` | The HTTP method. | 16.2 |
244
247
  | `rpc.url` | `(args?: Args) => string` | The address, resolved against the mount. | 16.9, 16.10, 30.28 |
248
+ | `rpc.address` | `string \| undefined` | Where the handler answers. | 16.88 |
245
249
  | `rpc.description` | `string \| undefined` | The human description. | 16.28 |
246
250
  | `PatchOp` | `{ op: 'add' \| 'replace' \| 'test'; path: string; value: unknown } \| { op: 'remove'; path: string } \| { op: 'move' \| 'copy'; from: string; path: string }` | One JSON Patch operation (RFC 6902), its paths JSON Pointers, as a followed `GET` is sent what an `s.patch` wrote. | 18.11, 18.13 |
247
251
 
248
252
  The aliases a call's failures and a plain handler's options are spelled through are declared
249
- rather than listed, none of them being a name an app writes. `Annotated` is the `ValidationError` of
253
+ rather than listed, none of them being a name an app writes. `RungRefusals` is what 16.86 carries,
254
+ and `Annotated` is the `ValidationError` of
250
255
  16.8, `never` wherever 19.9 derives no object's schema from `Args`:
251
256
 
252
257
  ```ts
@@ -254,6 +259,8 @@ type Annotated<Args> = 0 extends 1 & Args ? never : unknown extends Args ? never
254
259
  type Derived<Member, Whole = Member> = Member extends readonly unknown[] | ((...given: never[]) => unknown) ? never : Member extends object ? [Whole] extends [Member] ? [keyof Member] extends [never] ? [string] extends [Member] ? Failed<'ValidationError', Issues<Whole>> : never : Failed<'ValidationError', Issues<Whole>> : never : never
255
260
  type Shaping<Accepted, Shaped, Args = never, Gate = Schema<Accepted>, ArgsGate = Schema<Args>> = Omit<ReactiveOptions<Accepted, Kept<NoInfer<Shaped>>, never, Args>, 'transform' | 'schema' | 'args'> & { transform?: (value: Accepted) => Shaped; schema?: Gate & Schema<Accepted>; args?: [Args] extends [never] ? never : ArgsGate & Schema<Args> }
256
261
  type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Refused<Shaped> | Gated<Gate, Stored> | Gated<ArgsGate, Args>
262
+ type RungRefusals<Answers extends readonly unknown[]> = Answers[number] extends infer Answer ? Answer extends Failed<infer Name, unknown> ? string extends Name ? never : Answer : never : never
263
+ type Reached = { readonly [REACHED]: true }
257
264
  ```
258
265
 
259
266
  ### `RpcOptions`
@@ -261,7 +268,7 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
261
268
  | Name | Signature | Meaning | Rules |
262
269
  | --- | --- | --- | --- |
263
270
  | `description` | `string` | The human description carried onto every generated surface. | 16.28 |
264
- | `middleware` | `((next: (ctx?: { request: Request; args: () => Args }) => Promise<unknown>, ctx: { request: Request; args: () => Args }) => unknown)[]` | The rungs run per call. | 16.11, 16.12, 16.16, 16.17, 16.18, 16.19, 16.20 |
271
+ | `middleware` | `{ [At in keyof Answers]: (next: (ctx?: { request: Request; args: () => Args }) => Promise<Reached>, ctx: { request: Request; args: () => Args }) => Answers[At] \| Promise<Answers[At]> } \| readonly ((next: (ctx?: { request: Request; args: () => Args }) => Promise<Reached>, ctx: { request: Request; args: () => Args }) => unknown)[]` | The rungs run per call. | 16.8, 16.11, 16.12, 16.16, 16.17, 16.18, 16.19, 16.20, 16.86 |
265
272
  | `timeout` | `number` | How long the call may go without progress. | 16.22, 16.58, 16.59, 16.60, 16.61, 16.77 |
266
273
  | `clients` | `Clients` | Which surfaces carry this handler. | 16.37, 20.3 |
267
274
  | `crossOrigin` | `boolean \| string[]` | Whether other origins may call it, or follow it over the mux. | 16.24, 18.2, 21.19 |
@@ -296,7 +303,7 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
296
303
  | --- | --- | --- | --- |
297
304
  | `Schema<T>` | `((value: unknown) => T) \| StandardSchemaV1<T>` | The two forms a shape may be declared in. | 19.2, 19.3, 19.4, 19.6, 19.8, 19.9, 19.10, 19.18, 19.11, 19.12 |
298
305
  | `JsonValue` | `null \| boolean \| number \| string \| JsonValue[] \| { [k: string]: JsonValue }` | What an `Args` may hold. | — |
299
- | `Issues<T>` | `T extends object ? Partial<Record<Paths<T> \| '', string[]>> : string[]` | What was wrong, keyed by where. | 19.4, 19.19 |
306
+ | `Issues<T>` | `T extends Rpc<infer _Value, infer Args, infer _Failures, infer _Produced> ? Issues<Args> : T extends object ? Partial<Record<Paths<T> \| '', string[]>> : string[]` | What was wrong, keyed by where. | 19.4, 19.19, 19.26 |
300
307
  | `Paths<T>` | `string` | The dot-joined leaf paths of a type. | 19.5 |
301
308
  | `JsonSchema` | `JsonValue` | A JSON Schema document, the native form. | 19.7, 19.14 |
302
309
  | `jsonSchema` | `<T>(document: JsonSchema) => StandardSchemaV1<T>` | A JSON Schema document as a `Schema`, carrying its validator. | 19.13, 19.14, 19.23, 20.11 |
@@ -349,15 +356,19 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
349
356
 
350
357
  | Name | Signature | Meaning | Rules |
351
358
  | --- | --- | --- | --- |
352
- | `assistant` | `(messages: AssistantMessage[], provider: Provider, options?: AssistantOptions) => AsyncGenerator<AssistantEvent>` | A conversation with a model, as the events it produces. | 44.1, 44.2, 44.3, 44.4, 44.21, 44.36, 44.37, 44.39 |
359
+ | `assistant` | `(messages: AssistantMessage[], provider: Provider, options?: AssistantOptions) => AsyncGenerator<AssistantEvent>` | A conversation with a model, as the events it produces. | 44.1, 44.2, 44.3, 44.4, 44.21, 44.36, 44.37, 44.39, 44.57 |
353
360
  | `AssistantMessage` | `{ role: 'user' \| 'assistant'; content: string \| AssistantContent[] }` | One turn of the transcript a caller sends: its words, or its pieces in order. | 44.3, 44.4 |
354
361
  | `AssistantContent` | `{ type: 'text'; text: string } \| { type: 'image'; data: string; mimeType: string }` | A piece of a turn: words, or an image as base64 with its type. | 44.5, 44.35, 44.36, 44.37, 44.38, 44.39 |
355
- | `AssistantEvent` | `{ type: 'text'; text: string } \| { type: 'tool'; id: string; name: string } \| { type: 'input'; id: string; input: unknown } \| { type: 'result'; id: string; text: string; failed: boolean } \| { type: 'done'; stop: string; usage: { input: number; output: number } }` | What a conversation produces: text, a tool call as it starts, its input once written, its result, and the end. | 44.2, 44.11, 44.28 |
356
- | `AssistantOptions` | `{ mcp?: boolean; maxTurns?: number }` | What `assistant` takes beside a provider. | 44.6, 44.8, 44.11 |
357
- | `Provider` | `{ run(messages: (AssistantMessage & { content: AssistantContent[] })[], tools: Toolbox, limits: { maxTurns: number; signal: AbortSignal }): AsyncGenerator<AssistantEvent> }` | What runs a conversation. | 44.2, 44.28, 44.39 |
362
+ | `AssistantEvent` | `{ type: 'text'; text: string } \| { type: 'tool'; id: string; name: string; handler: { method: string; address: string } \| undefined } \| { type: 'input'; id: string; input: unknown } \| { type: 'result'; id: string; text: string; failed: boolean; handler: { method: string; address: string } \| undefined; value: unknown } \| { type: 'done'; stop: string; usage: { input: number; output: number } }` | What a conversation produces: text, a tool call as it starts, its input once written, its result, and the end. | 44.2, 44.11, 44.28, 44.48, 44.49 |
363
+ | `AssistantOptions` | `{ mcp?: boolean; maxTurns?: number; signal?: AbortSignal }` | What `assistant` takes beside a provider. | 44.6, 44.8, 44.11, 44.57 |
364
+ | `Provider` | `{ run(messages: (AssistantMessage & { content: AssistantContent[] })[], tools: Toolbox, limits: { maxTurns: number; signal: AbortSignal }): AsyncGenerator<ProviderEvent> }` | What runs a conversation. | 44.2, 44.28, 44.39, 44.50, 44.57 |
365
+ | `ProviderEvent` | `Exclude<AssistantEvent, { type: 'tool' \| 'result' }> \| { type: 'tool'; id: string; name: string } \| { type: 'result'; id: string; text: string; failed: boolean }` | An `AssistantEvent` as a provider yields it, before `assistant` reads the handler and the value off the app's surface. | 44.28, 44.35, 44.50 |
358
366
  | `Toolbox` | `{ list: ToolDefinition[]; call(name: string, input: unknown): Promise<ToolAnswer> }` | The app's MCP tools, called as the asker. | 44.6, 44.7, 44.35 |
359
367
  | `ToolAnswer` | `{ content: AssistantContent[]; failed: boolean }` | What a tool call answered: its pieces, and whether it failed. | 20.21, 20.22, 44.35 |
360
368
  | `ToolDefinition` | `{ name: string; description: string; inputSchema: unknown; annotations: { readOnlyHint: boolean; destructiveHint: boolean; idempotentHint: boolean }; outputSchema: unknown }` | A tool as the app's MCP surface lists it. | 20.14, 20.16, 20.19, 44.6 |
369
+ | `resultsOf` | `<Value>(events: readonly AssistantEvent[], handler: ((...args: never) => Reactive<Value, never, unknown, unknown>) & { method: string; address: string \| undefined }) => Value[]` | What a conversation's calls to one handler answered. | 44.51 |
370
+ | `imagePiece` | `(image: Blob) => Promise<{ type: 'image'; data: string; mimeType: string }>` | An image as a turn's image piece, drawn down to what a model looks at. | 44.52, 44.53, 44.54 |
371
+ | `imageFiles` | `(data: DataTransfer \| null) => File[]` | The images a paste or a drop carries that a model is shown. | 44.55 |
361
372
 
362
373
  ## `claudeApi`
363
374
 
@@ -372,9 +383,9 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
372
383
  | --- | --- | --- | --- |
373
384
  | `claudeCode` | `(config?: ClaudeCodeConfig) => Provider` | The visitor's own Claude Code, reached through the bridge paired with their browser, as a provider. | 44.5, 44.13, 44.17, 44.18, 44.19, 44.33 |
374
385
  | `ClaudeCodeConfig` | `{ model?: string; fallbackModel?: string; systemPrompt?: string; appendSystemPrompt?: string; effort?: 'low' \| 'medium' \| 'high' \| 'xhigh' \| 'max'; maxBudgetUsd?: number; betas?: string[]; disallowedTools?: string[]; tools?: string[] }` | The Claude Code options a site may set for a turn, and the built-in tools it asks the visitor for. | 44.16, 44.29 |
375
- | `claudeCode.bridgeCommand` | `(options?: { tools?: string[] }) => { command: string; link: string; expires: number }` | The command and the link that pair a bridge with this browser, granting the built-in tools it is given. | 44.14, 44.32, 44.33, 44.40 |
386
+ | `claudeCode.bridgeCommand` | `(options?: { tools?: string[] }) => { command: string; link: string; install: string; expires: number }` | The command and the link that pair a bridge with this browser, granting the built-in tools it is given, and the command that installs the app the link opens. | 44.14, 44.32, 44.33, 44.40, 44.56 |
376
387
  | `claudeCode.bridge` | `(options?: { tools?: string[] }) => AsyncGenerator<BridgeStatus>` | This browser's pairing, as it changes. | 44.20, 44.22, 44.32, 44.33, 44.34, 44.40 |
377
- | `BridgeStatus` | `{ paired: boolean; command: string \| undefined; link: string \| undefined }` | Whether a bridge is paired, and the command and the link that pair one where none is. | 44.20, 44.40 |
388
+ | `BridgeStatus` | `{ paired: boolean; command: string \| undefined; link: string \| undefined; install: string \| undefined }` | Whether a bridge is paired, and the command and the link that pair one where none is, with the command that installs the app the link opens. | 44.20, 44.40, 44.56 |
378
389
  | `/__abide/bridge` | `GET`, `POST` | Where a bridge pairs, and is relayed its turns. | 36.7, 44.14, 44.15, 44.19, 44.23, 44.26, 16.57, 16.78 |
379
390
 
380
391
  # Ambient values
@@ -392,6 +403,13 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
392
403
  | --- | --- | --- | --- |
393
404
  | `request` | `() => Request` | The request being served. | 18.16, 18.17, 18.18, 22.1 |
394
405
 
406
+ ## `requestIP`
407
+
408
+ | Name | Signature | Meaning | Rules |
409
+ | --- | --- | --- | --- |
410
+ | `requestIP` | `() => ReceivedFrom \| 'in-process'` | Where the request being served came from. | 22.1, 22.12, 22.13 |
411
+ | `ReceivedFrom` | `{ address: string; family: 'IPv4' \| 'IPv6'; port: number } \| null` | The peer a listener received a request from. | 22.12 |
412
+
395
413
  ## `response`
396
414
 
397
415
  | Name | Signature | Meaning | Rules |
@@ -406,6 +424,7 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
406
424
  | `route.params` | `Reactive<Params>` | The matched route's segments — typed by its own route in a page or a layout, and `Params` in any other file. | 23.1, 23.5, 23.9, 30.23, 31.15 |
407
425
  | `Params` | `Record<string, string \| string[]>` | What a matched route's segments are. | 23.5 |
408
426
  | `route.name` | `Reactive<string>` | The resolution path, the same under any mount path. | 23.1, 23.6, 23.14, 31.15 |
427
+ | `route.index` | `Reactive<number>` | The place of the entry the address bar stands at in the history this app's router wrote. | 23.1, 23.28, 23.29, 31.15 |
409
428
  | `route.navigating` | `Reactive<boolean>` | Whether a navigation is in flight. | 23.1, 31.15 |
410
429
 
411
430
  ## `online`
@@ -446,6 +465,12 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
446
465
  | --- | --- | --- | --- |
447
466
  | `server` | `<WebSocketData>() => Server<WebSocketData>` | The listening server. | 22.1 |
448
467
 
468
+ ## `isServer`
469
+
470
+ | Name | Signature | Meaning | Rules |
471
+ | --- | --- | --- | --- |
472
+ | `isServer` | `() => boolean` | Whether the work running is a server's. | 22.11, 12.7, 23.7, 23.8 |
473
+
449
474
  ## `health`
450
475
 
451
476
  | Name | Signature | Meaning | Rules |
@@ -544,7 +569,7 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
544
569
 
545
570
  | Name | Signature | Meaning | Rules |
546
571
  | --- | --- | --- | --- |
547
- | `navigate` | `(url?: URL \| string, options?: { replace?: boolean, keepScroll?: boolean }) => Promise<void>` | Navigates. | 30.7, 30.9, 30.10, 30.11, 30.12, 30.13, 30.14, 30.15, 30.16, 30.17, 30.18, 30.20, 30.21, 30.22, 30.23, 30.24, 30.25, 30.27, 30.29, 30.30, 30.31, 30.32, 45.12, 45.24 |
572
+ | `navigate` | `{ (by: number): Promise<void>; (url?: URL \| string, options?: { replace?: boolean, keepScroll?: boolean }): Promise<void> }` | Navigates to an address, or steps through the history. | 30.7, 30.38, 30.39, 30.9, 30.10, 30.11, 30.12, 30.13, 30.14, 30.15, 30.16, 30.17, 30.18, 30.20, 30.21, 30.22, 30.23, 30.24, 30.25, 30.27, 30.29, 30.30, 30.31, 30.32, 45.12, 45.24 |
548
573
 
549
574
  # `.abide` files
550
575
 
@@ -576,13 +601,13 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
576
601
  | `name={expr}` | A reactive attribute or property. | 32.3, 32.20, 32.23, 32.37, 32.70, 32.71 |
577
602
  | `on<event>={fn}` | A native listener on an element, and an ordinary prop on a component. | 32.4, 32.75 |
578
603
  | `name="…{expr}…"` | An interpolated quoted value. | 32.3, 32.71 |
579
- | `bind:value` | Two-way bind on an element. | 5.16, 32.5, 32.58, 32.59, 32.60, 32.61, 32.62, 32.72, 32.74, 32.75, 32.76 |
604
+ | `bind:value` | Two-way bind on an element. | 5.16, 32.5, 32.58, 32.59, 32.60, 32.61, 32.62, 32.72, 32.74, 32.75, 32.76, 32.78 |
580
605
  | `bind:prop={state}` | Hands a component prop the caller's `Reactive`, or a `{get, set}` pair, to write through. | 32.6, 33.6, 33.8, 14.18, 32.76 |
581
- | `bind:checked` | A boolean bind on an input. | 32.7, 32.72, 32.74, 32.75, 32.76 |
582
- | `bind:open` | The same, on a `<details>`. | 32.7, 32.72, 32.74, 32.75, 32.76 |
606
+ | `bind:checked` | A boolean bind on an input. | 32.7, 32.72, 32.74, 32.75, 32.76, 32.78 |
607
+ | `bind:open` | The same, on a `<details>`. | 32.7, 32.72, 32.74, 32.75, 32.76, 32.78 |
583
608
  | `bind:group` | Radio or checkbox membership. | 32.8, 32.72, 32.74, 32.75, 32.76 |
584
- | `bind:files` | A file input's files, as a list. | 32.73, 32.72, 32.74, 32.75, 32.76 |
585
- | `bind:value={{get, set}}` | Two-way bind over an explicit accessor pair, on an element or a component. | 32.5, 32.6 |
609
+ | `bind:files` | A file input's files, as a list. | 32.73, 32.72, 32.74, 32.75, 32.76, 32.78 |
610
+ | `bind:value={{get, set}}` | Two-way bind over an explicit accessor pair, on an element or a component. | 32.5, 32.6, 32.78 |
586
611
  | `bind:element={Reactive<Element> \| ((element: Element) => void \| Disposer)}` | A node reference. | 32.9, 32.38, 32.66, 32.68, 32.69 |
587
612
  | `class:name={cond}` | Toggles a class. | 32.10, 32.71 |
588
613
  | `style:prop={value}` | Sets one style property. | 32.10, 32.19, 32.71 |
@@ -645,7 +670,7 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
645
670
  | `[[name]]` | An optional segment. | 23.5, 30.4, 30.34, 30.36 |
646
671
  | `[...name]` | A rest segment, terminal. | 23.5, 30.5, 30.34, 30.36 |
647
672
  | `[name=NAME]` · `[[name=NAME]]` · `[...name=NAME]` | A dynamic segment a param file's matcher decides. | 19.1, 23.26, 23.27, 30.19, 30.35, 30.36, 30.37 |
648
- | `/__abide/**` | Every endpoint abide controls. | 20.8 |
673
+ | `/__abide/**` | Every endpoint abide controls. | 20.8, 37.19 |
649
674
 
650
675
  ## `render`
651
676
 
@@ -683,7 +708,7 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
683
708
  | `ABIDE_MAX_REQUEST_BODY_SIZE` | `number` | The default ceiling on a mutation's body. | 16.13, 16.54, 16.55, 16.78 |
684
709
  | `ABIDE_MAX_SOCKET_MESSAGE_SIZE` | `number` | The ceiling on a frame received over the socket mux, in bytes. | 18.28 |
685
710
  | `ABIDE_MAX_SOCKET_SUBSCRIPTIONS` | `number` | How many values one connection to the socket mux may follow. | 18.31, 18.32 |
686
- | `ABIDE_OFFLINE` | `boolean` | Whether the app keeps its pages and its bundle on the device, for when the network is gone. | 45.1, 45.2, 45.3, 45.4, 45.5, 45.6, 45.7, 45.8, 45.9, 45.10, 45.11, 45.12, 45.13, 45.14, 45.15, 45.16, 45.17, 45.18, 45.19, 45.20, 45.21, 45.22, 45.23, 45.24 |
711
+ | `ABIDE_OFFLINE` | `boolean` | Whether the app keeps its pages and its bundle on the device, for when the network is gone. | 45.1, 45.2, 45.3, 45.4, 45.5, 45.6, 45.7, 45.8, 45.9, 45.10, 45.11, 45.12, 45.13, 45.14, 45.15, 45.16, 45.17, 45.18, 45.19, 45.20, 45.21, 45.22, 45.23, 45.24, 45.25, 45.26 |
687
712
  | `ABIDE_STOP_TIMEOUT` | `number` | How long `App.stop` drains, in ms. | 42.17, 42.18 |
688
713
  | `ABIDE_MAX_STREAM_BUFFER_SIZE` | `number` | The cap on a stream transcript held in memory. | 36.18 |
689
714
  | `ABIDE_MAX_LOG_BUFFER_COUNT` | `number` | How many lines `log.records` is trimmed back to. | 28.1 |
@@ -724,10 +749,12 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
724
749
 
725
750
  | Name | Signature | Meaning | Rules |
726
751
  | --- | --- | --- | --- |
727
- | `middleware` | `(...rungs: ((next: (ctx?: { request: Request }) => Promise<Response>, ctx: { request: Request }) => Response \| Failed<string, unknown> \| Promise<Response \| Failed<string, unknown>>)[]) => () => void` | The per-request lane at the calling file's route. | 18.26, 37.2, 37.3, 37.13, 37.14, 37.15 |
752
+ | `middleware` | `(...rungs: ((next: (ctx?: { request: Request }) => Promise<Response>, ctx: { request: Request; lane: Lane }) => Response \| Failed<string, unknown> \| Promise<Response \| Failed<string, unknown>>)[]) => () => void` | The per-request lane at the calling file's route. | 18.26, 37.2, 37.3, 37.13, 37.14, 37.15, 37.19, 37.20 |
753
+ | `Lane` | `'page' \| 'handler' \| 'file' \| 'openapi' \| 'mcp' \| 'bridge' \| 'socket' \| 'abide'` | What answers a request a `middleware` rung is handed. | 37.19 |
728
754
  | `onStart` | `(fn: (start: () => Promise<void>) => void \| Promise<void>) => () => void` | Wraps the boot. | 37.4, 37.6, 37.13 |
729
755
  | `onStop` | `(fn: (stop: () => Promise<void>) => void \| Promise<void>) => () => void` | Mirrors it for teardown. | 37.4, 37.6, 37.13 |
730
- | `onError` | `(fn: (error: unknown) => unknown) => () => void` | Runs on an unexpected error at the calling file's route. | 37.5, 37.8, 37.13 |
756
+ | `onError` | `(fn: (error: unknown) => unknown) => () => void` | Runs on an unexpected error at the calling file's route, or in the browser below the calling component. | 37.5, 37.8, 37.13, 37.16, 37.17, 37.18, 37.21, 12.6 |
757
+ | `onRefusal` | `(fn: (refusal: Failed<string, unknown>, call: { method: 'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'; url: string }) => unknown) => () => void` | What the browser hands each refusal a call over http is answered with, below the calling component. | 37.13, 37.22, 37.23, 37.24, 37.25, 37.26, 37.27 |
731
758
  | `onConfig` | `(fn: ConfigDefaults \| null, options?: ConfigOptions) => () => void` | The app's config defaults. | 27.6, 37.7, 37.13 |
732
759
  | `onHealth` | `(report: () => unknown \| Promise<unknown>) => () => void` | The app's health reporter. | 25.2, 37.7, 37.13 |
733
760
  | `onPrincipal` | `(resolve: (claims: unknown) => unknown \| Promise<unknown>) => () => void` | Turns claims into the app's half of a principal. | 26.4, 37.7, 37.13 |
@@ -753,8 +780,8 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
753
780
  | --- | --- | --- | --- |
754
781
  | `createApp` | `() => Promise<App>` | The app built and booted, with no socket bound. | 42.1, 42.2, 42.3, 42.4, 42.16, 37.4, 37.6, 38.100 |
755
782
  | `App` | `interface App` | What a host, a test or a script holds the app as. | 42.12, 42.13 |
756
- | `App.fetch` | `(request: Request) => Promise<Response>` | The whole request path, entered in process. | 42.5, 42.6 |
757
- | `App.run` | `<Result>(fn: () => Result \| Promise<Result>, options?: { request?: Request; principal?: Record<string, unknown> }) => Promise<Result>` | One scope around a function, and nothing else. | 42.7, 42.8, 42.19, 11.38 |
783
+ | `App.fetch` | `(request: Request, options?: { principal?: Record<string, unknown>; caller?: string }) => Promise<Response>` | The whole request path, entered in process. | 42.5, 42.6, 42.20, 42.21 |
784
+ | `App.run` | `<Result>(fn: () => Result \| Promise<Result>, options?: { request?: Request; principal?: Record<string, unknown>; caller?: string }) => Promise<Result>` | One scope around a function, and nothing else. | 42.7, 42.8, 42.19, 42.21, 11.38 |
758
785
  | `App.listen` | `(options?: { port?: number; hostname?: string; unix?: string }) => Promise<void>` | The socket, bound. | 42.9, 16.23, 16.56, 18.28, 18.29, 18.30 |
759
786
  | `App.stop` | `() => Promise<void>` | The drain and the teardown. | 42.10, 42.11, 42.15, 42.17, 37.4 |
760
787
  | `App[Symbol.asyncDispose]` | `() => Promise<void>` | `App.stop`, under the name `await using` calls. | 42.14 |
@@ -763,7 +790,7 @@ type Refusals<Shaped, Gate, Stored, ArgsGate = Schema<never>, Args = never> = Re
763
790
 
764
791
  | Name | Signature | Meaning | Rules |
765
792
  | --- | --- | --- | --- |
766
- | `mount` | `(component: Component) => Promise<Mounted>` | A bound component, rendered into the document's body and hydrated there. | 38.119, 38.121 |
793
+ | `mount` | `(component: Component) => Promise<Mounted>` | A bound component, rendered into the document's body and hydrated there. | 38.119, 38.121, 38.134 |
767
794
  | `Mounted` | `{ stop(): void; [Symbol.dispose](): void }` | A component `mount` hydrated, until it is stopped. | 38.119 |
768
795
 
769
796
  # The measurement harness
@@ -787,7 +814,7 @@ rows a runner prints, and an adapter for an abide app.
787
814
 
788
815
  | Name | Meaning | Rules |
789
816
  | --- | --- | --- |
790
- | `preload = ["@abide/harness/preload"]` | The `[test]` preload that registers a DOM with the measure lane's patches installed. | 43.4, 43.28 |
817
+ | `preload = ["@abide/harness/preload"]` | The `[test]` preload that registers a DOM with the measure lane's patches installed. | 43.4, 43.28, 43.35 |
791
818
 
792
819
  ## `@abide/harness/engine` — what the browser engine did
793
820
 
@@ -884,16 +911,16 @@ rows a runner prints, and an adapter for an abide app.
884
911
  | `abide run <file> [args…]` | Runs a script under the abide runtime. | 38.2, 38.57 |
885
912
  | `abide check [dir…]` | The type-checker over a `.abide` tree. | 38.3, 38.31, 38.32, 38.33, 38.40, 38.105, 38.123 |
886
913
  | `abide format [--check] [dir…]` | The formatter over a `.abide` tree. | 38.25, 38.125, 38.126, 38.127, 38.128, 38.129 |
887
- | `abide routes [--json]` | Every address the app answers, the file answering it, what each matcher takes, and where each hook is filed. | 38.108, 38.123 |
888
- | `abide dev [--port <n>]` | Watches the project and keeps the app up. | 16.23, 16.56, 37.8, 37.9, 38.4, 38.14, 38.15, 38.16, 38.17, 38.19, 38.24, 38.25, 38.26, 38.28, 38.30, 38.35, 38.36, 38.37, 38.38, 38.41, 38.43, 38.58, 38.63, 38.64, 38.65, 38.94, 38.96, 38.97, 38.123 |
914
+ | `abide routes [--json]` | Every address the app answers, the file answering it, what each matcher takes, the rungs each handler names, and where each hook is filed. | 38.108, 38.123, 38.135 |
915
+ | `abide dev [--port <n>] [--hostname <host>]` | Watches the project and keeps the app up. | 16.23, 16.56, 37.8, 37.9, 38.4, 38.14, 38.15, 38.16, 38.17, 38.19, 38.24, 38.25, 38.26, 38.28, 38.30, 38.35, 38.36, 38.37, 38.38, 38.41, 38.43, 38.58, 38.63, 38.64, 38.65, 38.94, 38.96, 38.97, 38.123, 38.136 |
889
916
  | `abide build` | Builds the client into content-hashed chunks and a manifest. | 38.43, 38.5, 38.18, 38.25, 38.26, 38.27, 38.30, 38.66, 38.94, 38.123 |
890
- | `abide start [--port <n>]` | Boots the built app. | 37.8, 37.10, 37.11, 37.12, 38.6, 38.100, 38.20, 38.21, 38.22, 38.23, 38.25, 38.26, 38.27, 38.28, 38.29, 38.58, 38.67, 38.68, 38.95, 38.97, 38.110, 38.123 |
891
- | `abide [--url <origin>] [--port <n>]` | The interactive shell — on the built app it boots, or on the running app `--url` names. | 37.8, 37.10, 37.11, 37.12, 38.6, 38.7, 38.53, 38.54, 38.55, 38.58, 38.59, 38.60, 38.62, 38.123 |
917
+ | `abide start [--port <n>] [--hostname <host>]` | Boots the built app. | 37.8, 37.10, 37.11, 37.12, 38.6, 38.100, 38.20, 38.21, 38.22, 38.23, 38.25, 38.26, 38.27, 38.28, 38.29, 38.58, 38.67, 38.68, 38.95, 38.97, 38.110, 38.123, 38.136 |
918
+ | `abide [--url <origin>] [--port <n>] [--hostname <host>]` | The interactive shell — on the built app it boots, or on the running app `--url` names. | 37.8, 37.10, 37.11, 37.12, 38.6, 38.7, 38.53, 38.54, 38.55, 38.58, 38.59, 38.60, 38.62, 38.123, 38.136 |
892
919
  | `abide call <address> [args]` | One call to one handler. | 38.8, 38.61, 38.110 |
893
920
  | `abide openapi [--url <origin>]` | The OpenAPI document printed rather than served. | 38.9, 38.25, 38.110, 38.111, 38.123 |
894
921
  | `abide mcp [--url <origin>]` | The app's MCP server over stdio. | 38.9, 38.13, 38.25, 38.110, 38.123 |
895
922
  | `abide watch <address> [args]` | A live subscription to one of the app's followed `GET`s. | 38.69 |
896
- | `abide compile [--target] [--out] [--platforms]` | One standalone executable. | 37.8, 37.10, 37.11, 37.12, 38.10, 38.25, 38.26, 38.44, 38.45, 38.46, 38.47, 38.48, 38.49, 38.50, 38.51, 38.52, 38.56, 38.93, 38.97, 38.123 |
923
+ | `abide compile [--target] [--out] [--platforms]` | One standalone executable. | 37.8, 37.10, 37.11, 37.12, 38.10, 38.25, 38.26, 38.44, 38.45, 38.46, 38.47, 38.48, 38.49, 38.50, 38.51, 38.52, 38.56, 38.93, 38.97, 38.123, 38.136 |
897
924
  | `abide bundle [--out]` | A desktop app for the host platform, with a window on the app. | 38.10, 38.25, 38.26, 38.70, 38.71, 38.72, 38.73, 38.74, 38.75, 38.76, 38.77, 38.78, 38.79, 38.80, 38.81, 38.82, 38.83, 38.84, 38.85, 38.86, 38.87, 38.88, 38.89, 38.90, 38.91, 38.92, 38.101, 38.102, 38.123 |
898
925
  | `abide lsp` | The `.abide` language server, over stdio. | 38.11, 38.34, 38.39, 38.98, 38.116, 38.117, 38.118, 38.130 |
899
926
  | `--help` · `-h` · `abide help` | Usage, generated from the command list. | 38.12, 38.113, 38.114 |