@abide/abide 0.42.0 → 0.43.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.
- package/AGENTS.md +234 -300
- package/CHANGELOG.md +34 -0
- package/README.md +50 -93
- package/package.json +3 -2
- package/src/abideResolverPlugin.ts +104 -14
- package/src/buildCli.ts +1 -1
- package/src/discoveryEntry.ts +3 -3
- package/src/lib/bundle/BundleMenuItem.ts +1 -1
- package/src/lib/cli/createClient.ts +12 -12
- package/src/lib/cli/dispatchCommand.ts +1 -1
- package/src/lib/cli/printSessionStatus.ts +1 -1
- package/src/lib/cli/resolveCliTarget.ts +1 -1
- package/src/lib/cli/runCli.ts +1 -1
- package/src/lib/cli/types/CliManifest.ts +1 -1
- package/src/lib/cli/types/CliManifestEntry.ts +2 -2
- package/src/lib/mcp/annotationsForMethod.ts +5 -5
- package/src/lib/mcp/createMcpServer.ts +3 -3
- package/src/lib/mcp/mcpSurface.ts +14 -14
- package/src/lib/mcp/types/McpServerOptions.ts +1 -1
- package/src/lib/server/DELETE.ts +4 -4
- package/src/lib/server/GET.ts +4 -4
- package/src/lib/server/HEAD.ts +4 -4
- package/src/lib/server/PATCH.ts +4 -4
- package/src/lib/server/POST.ts +4 -4
- package/src/lib/server/PUT.ts +4 -4
- package/src/lib/server/agent.ts +4 -4
- package/src/lib/server/env.ts +1 -1
- package/src/lib/server/error.ts +49 -7
- package/src/lib/server/json.ts +1 -1
- package/src/lib/server/rpc/buildErrorConstructors.ts +19 -0
- package/src/lib/server/rpc/{defineVerb.ts → defineRpc.ts} +52 -34
- package/src/lib/server/rpc/{dispatchVerbInProcess.ts → dispatchRpcInProcess.ts} +3 -3
- package/src/lib/server/rpc/fieldErrorsFromIssues.ts +23 -0
- package/src/lib/server/rpc/{findVerbByCommandName.ts → findRpcByCommandName.ts} +5 -5
- package/src/lib/server/rpc/parseArgs.ts +6 -6
- package/src/lib/server/rpc/readBodyWithinLimit.ts +2 -2
- package/src/lib/server/rpc/registerRpc.ts +6 -0
- package/src/lib/server/rpc/{verbRegistry.ts → rpcRegistry.ts} +4 -4
- package/src/lib/server/rpc/{runWithVerbTimeout.ts → runWithRpcTimeout.ts} +4 -4
- package/src/lib/server/rpc/types/RemoteHandler.ts +9 -3
- package/src/lib/server/rpc/types/{VerbHelper.ts → RpcHelper.ts} +57 -23
- package/src/lib/server/rpc/types/{VerbRegistryEntry.ts → RpcRegistryEntry.ts} +3 -3
- package/src/lib/server/rpc/types/TypedResponse.ts +2 -2
- package/src/lib/server/rpc/unprocessed.ts +6 -7
- package/src/lib/server/rpc/validationError.ts +17 -0
- package/src/lib/server/runtime/buildInspectorSurface.ts +7 -7
- package/src/lib/server/runtime/buildOpenApiSpec.ts +6 -6
- package/src/lib/server/runtime/createRouteDispatcher.ts +7 -7
- package/src/lib/server/runtime/createServer.ts +4 -4
- package/src/lib/server/runtime/crossOriginForbidden.ts +1 -1
- package/src/lib/server/runtime/crossOriginGate.ts +4 -4
- package/src/lib/server/runtime/logExposedSurfaces.ts +4 -4
- package/src/lib/server/runtime/registryManifests.ts +2 -2
- package/src/lib/server/runtime/types/InspectorCacheEntry.ts +1 -1
- package/src/lib/server/runtime/types/InspectorRpc.ts +27 -0
- package/src/lib/server/runtime/types/InspectorSurface.ts +4 -4
- package/src/lib/server/runtime/types/RequestStore.ts +1 -1
- package/src/lib/server/runtime/warnUnguardedMcp.ts +2 -2
- package/src/lib/server/sockets/createSocketDispatcher.ts +15 -14
- package/src/lib/server/sockets/types/SocketOperation.ts +2 -2
- package/src/lib/shared/HttpError.ts +15 -1
- package/src/lib/shared/UNREACHABLE_STATUSES.ts +13 -0
- package/src/lib/shared/buildRpcRequest.ts +5 -5
- package/src/lib/shared/cache.ts +50 -168
- package/src/lib/shared/carriesBodyArgs.ts +4 -4
- package/src/lib/shared/createCacheStore.ts +12 -0
- package/src/lib/shared/createRemoteFunction.ts +11 -6
- package/src/lib/shared/decodeResponse.ts +2 -2
- package/src/lib/shared/detectRpcMethod.ts +17 -0
- package/src/lib/shared/emitLogRecord.ts +3 -3
- package/src/lib/shared/extraForwardHeaders.ts +1 -1
- package/src/lib/shared/findExportCallSite.ts +30 -273
- package/src/lib/shared/forwardHeaders.ts +2 -2
- package/src/lib/shared/httpErrorFor.ts +26 -0
- package/src/lib/shared/isAsciiWhitespace.ts +5 -0
- package/src/lib/shared/isIdentPart.ts +9 -0
- package/src/lib/shared/isIdentStart.ts +8 -0
- package/src/lib/shared/isReadOnlyMethod.ts +4 -4
- package/src/lib/shared/keyForRemoteCall.ts +4 -4
- package/src/lib/shared/log.ts +1 -1
- package/src/lib/shared/outboxProbeSlot.ts +20 -0
- package/src/lib/shared/pending.ts +4 -1
- package/src/lib/shared/prepareRpcModule.ts +96 -14
- package/src/lib/shared/probeRegistries.ts +17 -4
- package/src/lib/shared/queryStringFromArgs.ts +1 -1
- package/src/lib/shared/remoteMetaStore.ts +2 -2
- package/src/lib/shared/resolveClientFlags.ts +1 -1
- package/src/lib/shared/skipNonCode.ts +230 -0
- package/src/lib/shared/streamResponse.ts +9 -6
- package/src/lib/shared/stripImport.ts +3 -3
- package/src/lib/shared/types/CacheEntry.ts +2 -4
- package/src/lib/shared/types/CacheOnContext.ts +1 -11
- package/src/lib/shared/types/CacheStore.ts +13 -7
- package/src/lib/shared/types/ClientFlags.ts +1 -1
- package/src/lib/shared/types/ErrorConstructors.ts +17 -0
- package/src/lib/shared/types/ErrorDescriptor.ts +10 -0
- package/src/lib/shared/types/ErrorSpec.ts +11 -0
- package/src/lib/shared/types/HttpMethod.ts +1 -0
- package/src/lib/shared/types/Outbox.ts +9 -0
- package/src/lib/shared/types/OutboxEntry.ts +27 -0
- package/src/lib/shared/types/RawRemoteFunction.ts +2 -2
- package/src/lib/shared/types/RemoteCallable.ts +2 -2
- package/src/lib/shared/types/RemoteFunction.ts +21 -6
- package/src/lib/shared/types/RequestScopeInfo.ts +1 -1
- package/src/lib/shared/types/RpcErrorGuard.ts +40 -0
- package/src/lib/shared/types/RpcInvoker.ts +1 -1
- package/src/lib/shared/types/StandardSchemaV1.ts +1 -1
- package/src/lib/shared/types/ValidationErrorData.ts +20 -0
- package/src/lib/shared/url.ts +3 -3
- package/src/lib/shared/writeRpcDts.ts +7 -7
- package/src/lib/shared/writeTestRpcDts.ts +3 -3
- package/src/lib/test/createTestApp.ts +10 -10
- package/src/lib/ui/compile/awaitPlan.ts +48 -0
- package/src/lib/ui/compile/compileShadow.ts +75 -21
- package/src/lib/ui/compile/desugarSignals.ts +42 -6
- package/src/lib/ui/compile/generateBuild.ts +43 -60
- package/src/lib/ui/compile/generateSSR.ts +84 -54
- package/src/lib/ui/compile/ifPlan.ts +30 -0
- package/src/lib/ui/compile/parseTemplate.ts +41 -11
- package/src/lib/ui/compile/stripEffects.ts +17 -9
- package/src/lib/ui/compile/switchPlan.ts +22 -0
- package/src/lib/ui/compile/tryPlan.ts +29 -0
- package/src/lib/ui/compile/types/TemplateAttr.ts +8 -2
- package/src/lib/ui/compile/types/TemplateNode.ts +6 -2
- package/src/lib/ui/createScope.ts +20 -2
- package/src/lib/ui/dom/disposeRange.ts +6 -10
- package/src/lib/ui/dom/hydrate.ts +2 -5
- package/src/lib/ui/dom/mount.ts +1 -2
- package/src/lib/ui/dom/withScope.ts +6 -9
- package/src/lib/ui/effect.ts +4 -2
- package/src/lib/ui/navigate.ts +40 -13
- package/src/lib/ui/outbox.ts +30 -110
- package/src/lib/ui/remoteProxy.ts +160 -10
- package/src/lib/ui/router.ts +3 -3
- package/src/lib/ui/rpcOutbox/createOutboxQueue.ts +281 -0
- package/src/lib/ui/rpcOutbox/outboxRegistry.ts +69 -0
- package/src/lib/ui/socketChannel.ts +7 -1
- package/src/lib/ui/types/Scope.ts +20 -5
- package/template/CLAUDE.md +1 -1
- package/template/src/server/rpc/getHello.ts +3 -3
- package/template/test/app.test.ts +2 -2
- package/src/lib/server/rpc/registerVerb.ts +0 -6
- package/src/lib/server/runtime/types/InspectorVerb.ts +0 -27
- package/src/lib/shared/detectVerbMethod.ts +0 -17
- package/src/lib/shared/types/HttpVerb.ts +0 -1
- package/src/lib/ui/types/Outbox.ts +0 -14
package/AGENTS.md
CHANGED
|
@@ -1,410 +1,344 @@
|
|
|
1
1
|
# AGENTS.md — abide complete surface map
|
|
2
2
|
|
|
3
|
-
> The exhaustive index of abide's public surface: every `exports` key appears
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
>
|
|
9
|
-
> **No barrels.** Every public name has its own module path —
|
|
10
|
-
> `@abide/abide/server/GET`, `@abide/abide/shared/cache`, `@abide/abide/ui/scope`. The namespace
|
|
11
|
-
> marks the side a name runs on: `@abide/abide/server/*` is server-only,
|
|
12
|
-
> `@abide/abide/ui/*` is client-only, `@abide/abide/shared/*` is isomorphic (same callable,
|
|
13
|
-
> same behaviour on both sides — the bundler swaps the runtime). There is no
|
|
14
|
-
> umbrella `index.ts`, so importing one name never drags in side-effecting
|
|
15
|
-
> siblings.
|
|
16
|
-
>
|
|
17
|
-
> Package `@abide/abide`, runtime Bun ≥ 1.3.0, one direct dependency
|
|
18
|
-
> (`typescript`); `tailwindcss` + `bun-plugin-tailwind` are optional peers.
|
|
19
|
-
> Import specifiers below are `package.json` `exports` keys, not file paths —
|
|
20
|
-
> `@abide/abide/server/GET` resolves to `src/lib/server/GET.ts`.
|
|
3
|
+
> The exhaustive index of abide's public surface: every `exports` key appears once, grouped by namespace, with its import specifier and a one-line spec. This is the whole-API read; the README is the curated 3-primitive intro. CONTEXT.md is the glossary, `docs/adr/` the rationale.
|
|
4
|
+
|
|
5
|
+
**No barrels.** Every public name has its own module path (`abide/server/GET`, `abide/shared/cache`, `abide/ui/scope`) — there is no umbrella `index.ts`, so importing one name never drags side-effecting siblings into the bundle. The namespace marks the side a name runs on: `abide/server/*` is server-only, `abide/ui/*` is client-only, `abide/shared/*` is isomorphic (same callable, same behaviour on both sides; the bundler swaps the runtime). The bullets below name each export by its import specifier in the `abide/…` shorthand (the published package is `@abide/abide`, so `abide/server/GET` imports from `@abide/abide/server/GET`) — these are import specifiers, not source file paths.
|
|
6
|
+
|
|
7
|
+
Package `@abide/abide`. Runtime: Bun ≥ 1.3.0. One direct dependency (TypeScript); `tailwindcss` + `bun-plugin-tailwind` are optional peers for styling.
|
|
21
8
|
|
|
22
9
|
## The premise
|
|
23
10
|
|
|
24
|
-
One typed
|
|
11
|
+
One typed RPC declaration fans out to every surface:
|
|
25
12
|
|
|
26
13
|
```text
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
SSR call
|
|
32
|
-
cache(fn)()
|
|
33
|
-
proxy
|
|
14
|
+
export const getMessages = GET(fn, { inputSchema })
|
|
15
|
+
│
|
|
16
|
+
┌────────────┬────────────┬────────────┬────────────┐
|
|
17
|
+
▼ ▼ ▼ ▼ ▼
|
|
18
|
+
SSR call browser MCP tool CLI cmd OpenAPI
|
|
19
|
+
cache(fn)() fetch proxy (read-only) abide cli /openapi.json
|
|
34
20
|
```
|
|
35
21
|
|
|
36
|
-
|
|
37
|
-
(`GET` / `HEAD`); a mutating verb never auto-exposes to MCP — it opts in with
|
|
38
|
-
`clients: { mcp: true }`. The same gating applies to sockets: a schema flips
|
|
39
|
-
the MCP/CLI read faces on.
|
|
22
|
+
The Standard Schema is the gate: an `inputSchema` unlocks the CLI subcommand and, for read-only methods (GET/HEAD), the MCP tool automatically. A mutating method (POST/PUT/PATCH/DELETE) never auto-exposes to MCP — it opts in with `clients: { mcp: true }`.
|
|
40
23
|
|
|
41
24
|
## File-based conventions
|
|
42
25
|
|
|
43
|
-
The bundler reads these paths
|
|
44
|
-
|
|
45
|
-
| Path
|
|
46
|
-
|
|
|
47
|
-
| `src/server/rpc/<name>.ts`
|
|
48
|
-
| `src/server/sockets/<name>.ts`
|
|
49
|
-
| `src/
|
|
50
|
-
| `src/
|
|
51
|
-
| `src/
|
|
52
|
-
| `src/
|
|
53
|
-
| `src/
|
|
54
|
-
| `src/
|
|
55
|
-
| `src
|
|
56
|
-
| `
|
|
57
|
-
| `
|
|
58
|
-
| `src/.abide/*.d.ts` | Generated types written each build — `routes`, `rpc`, `sockets`, `health`, `publicAssets`, and test surfaces. |
|
|
59
|
-
| `dist/_app/` | Client bundle output (hashed chunks; prod adds precompressed `.gz` siblings). |
|
|
26
|
+
The bundler reads these paths; the path is the identity.
|
|
27
|
+
|
|
28
|
+
| Path | Meaning |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `src/server/rpc/<name>.ts` | one RPC export; URL is `/rpc/<name>` |
|
|
31
|
+
| `src/server/sockets/<name>.ts` | one socket export; socket identity is `<name>` |
|
|
32
|
+
| `src/mcp/prompts/<name>.md` | one MCP prompt; identity is `<name>` (front-matter + `{{arg}}` body) |
|
|
33
|
+
| `src/server/config.ts` | the `env(schema)` config, read at boot |
|
|
34
|
+
| `src/app.ts` | optional `AppModule` hooks (`init`, `handle`, `handleError`) |
|
|
35
|
+
| `src/bundle/window.ts` | optional `BundleWindow` default export (desktop bundle) |
|
|
36
|
+
| `src/ui/pages/**/page.abide` | a page; the directory is the route, `[id]` a dynamic segment, `[...rest]` a catch-all |
|
|
37
|
+
| `src/ui/pages/**/layout.abide` | a layout wrapping every page below it via its `<slot/>` outlet |
|
|
38
|
+
| `src/.abide/*.d.ts` | generated type surfaces (RPC routes, health fields, test client) |
|
|
39
|
+
| `public/` | static assets served as-is |
|
|
40
|
+
| `dist/_app/` | the built client bundle (`abide build`) |
|
|
60
41
|
|
|
61
42
|
## CLI
|
|
62
43
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
abide dev
|
|
66
|
-
abide
|
|
67
|
-
abide
|
|
68
|
-
abide
|
|
69
|
-
abide
|
|
70
|
-
abide
|
|
71
|
-
abide
|
|
72
|
-
abide
|
|
73
|
-
abide
|
|
74
|
-
abide
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
(`[test] preload = ["@abide/abide/preload"]`) so `.abide` modules resolve.
|
|
44
|
+
| Command | Does |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `abide scaffold <name>` | scaffold a project, install it, start dev (`--no-install` / `--no-dev` to skip) |
|
|
47
|
+
| `abide dev` | build + run with hot reload |
|
|
48
|
+
| `abide build` | build the client into `dist/_app/` |
|
|
49
|
+
| `abide check` | type-check `.abide` templates + props |
|
|
50
|
+
| `abide start` | run the production server against `dist/` |
|
|
51
|
+
| `abide run <file> [args…]` | run a script under the abide preload (same runtime as the server) |
|
|
52
|
+
| `abide compile [--target] [--out]` | build a standalone server executable |
|
|
53
|
+
| `abide cli [--target] [--out] [--platforms]` | build the CLI binary (a thin remote client that ships the server beside it) |
|
|
54
|
+
| `abide bundle` | build a movable, self-contained desktop app bundle for this platform |
|
|
55
|
+
| `abide lsp` | the `.abide` language server (editor integration) |
|
|
56
|
+
| `abide init-agent` | write/refresh a CLAUDE.md pointer to this surface map (non-scaffolded projects) |
|
|
57
|
+
|
|
58
|
+
For tests, add `preload = ["@abide/abide/preload"]` under `[test]` in `bunfig.toml` and use `bun test`.
|
|
79
59
|
|
|
80
60
|
## Authoring contracts
|
|
81
61
|
|
|
82
|
-
**RPC
|
|
83
|
-
`
|
|
84
|
-
|
|
85
|
-
`
|
|
86
|
-
|
|
87
|
-
raw `Response`. `opts`: `inputSchema` (validates args, infers the type, gates
|
|
88
|
-
CLI + read-MCP), `outputSchema` (documents the 200 body for OpenAPI/MCP),
|
|
89
|
-
`filesSchema` (multipart File parts), `clients: { browser, mcp, cli }` (explicit
|
|
90
|
-
surface targeting; explicit wins over schema auto-flip), `crossOrigin` (exempt
|
|
91
|
-
a mutating verb from the same-origin gate), `maxBodySize` (per-verb 413
|
|
92
|
-
ceiling), `timeout` (handler deadline in ms; 504 on every surface). Query args
|
|
93
|
-
arrive as strings — use `z.coerce.*`. Consume four ways: `cache(verb)(args)`
|
|
94
|
-
in-process, the swapped browser `fetch`, `verb.raw(args)` for the `Response`,
|
|
95
|
-
`verb.stream(args)` to iterate a streaming body.
|
|
96
|
-
|
|
97
|
-
**Socket** — `export const <name> = socket({ schema?, tail?, ttl?,
|
|
98
|
-
clientPublish?, clients? })`. `tail` retains the last N frames for late joiners
|
|
99
|
-
and the read faces; `ttl` lazily evicts frames older than N ms; `clientPublish`
|
|
100
|
-
(default off) gates browser publishes; `schema` validates publishes
|
|
101
|
-
synchronously and flips MCP/CLI on. Isomorphic `AsyncIterable<T>`: bare
|
|
102
|
-
iteration is the live stream, `.tail(count?)` seeds from retention,
|
|
103
|
-
`.publish(msg)` fans out in-process + over the multiplexed ws.
|
|
104
|
-
|
|
105
|
-
**Page / layout** — a `[id]` folder segment becomes `page.params.id`. A layout's
|
|
106
|
-
`<slot/>` is the outlet the next layer fills. Read `page` (route, params, url,
|
|
107
|
-
navigating) and call `navigate(path)` for SPA transitions.
|
|
108
|
-
|
|
109
|
-
**App / config** — `src/app.ts` default-exports an `AppModule`; `src/server/config.ts`
|
|
110
|
-
runs `env(schema)` at boot.
|
|
111
|
-
|
|
112
|
-
**Isomorphism move** — wrap an SSR read in `cache(fn)()` so the value serializes
|
|
113
|
-
into the document and the client hydrates warm instead of refetching.
|
|
62
|
+
- **RPC** — `export const <name> = METHOD(handler, opts?)` in `src/server/rpc/<name>.ts`. The handler receives the parsed args (`InferOutput<inputSchema>`, or the raw `Args` when schemaless), reads request state via `request()` / `cookies()`, and returns `json` / `jsonl` / `sse` / `error` / `redirect` / a raw `Response`. `opts`: `inputSchema`, `outputSchema`, `filesSchema` (multipart upload), `errors`, `clients: { browser, mcp, cli }`, `crossOrigin` (CSRF exemption), `maxBodySize` (413 past it), `timeout` (504, every surface), `outbox` (durable mutating delivery). Query args (GET/DELETE/HEAD) arrive as strings — use `z.coerce.*`. Consume four ways: `cache(fn)()` in-process, the swapped `fetch` proxy in the browser, `fn.raw(args)` (untouched `Response`), `fn.stream(args)` (frame stream). A non-2xx throws `HttpError`; `fn.isError(err, name)` type-guards it against the rpc's own `errors` (plus `'validation'` / `'queued'`), narrowing `.kind` and the matching `.data`.
|
|
63
|
+
- **Socket** — `export const <name> = socket(opts)` in `src/server/sockets/<name>.ts`. A `Socket<T>` is an `AsyncIterable<T>`: bare iteration is the live stream; `<name>.tail(count?)` seeds from the retained tail; `<name>.publish(m)` is isomorphic. `opts`: `schema` (validates publishes, infers `T`, flips MCP/CLI faces on), `tail` (retained frame count), `ttl` (lazy age eviction), `clientPublish` (allow browser publishes), `clients`.
|
|
64
|
+
- **Page / layout** — `.abide` files under `src/ui/pages/`. A `[id]` segment lands on `page.params.id`; a layout's `<slot/>` is the outlet the child fills; read the route via `page`, navigate via `url` / `navigate`.
|
|
65
|
+
- **app.ts / config.ts** — `app.ts` exports optional `AppModule` hooks (`init` → cleanup, `handle` middleware, `handleError`); `config.ts` exports `env(schema)`, validated synchronously at boot.
|
|
66
|
+
- **Isomorphism move** — read through `cache()` during SSR so the value bakes into the HTML and the matching `{#await}` adopts the server DOM warm on hydration (no refetch).
|
|
114
67
|
|
|
115
68
|
## .abide template grammar
|
|
116
69
|
|
|
117
|
-
A component file
|
|
118
|
-
reactive declarations) + optional `<template name="…">` snippet definitions +
|
|
119
|
-
markup + an optional component-scoped `<style>`. Ambient in-scope names need no
|
|
120
|
-
import: `scope`, `props` / `prop`, `effect`, `html`, `snippet`.
|
|
70
|
+
A component is one `.abide` file: valid HTML with an optional `<script lang="ts">`, `{expr}` bindings, `{#…}` control-flow blocks, `<template name>` snippets, capitalised component tags, and a component-scoped `<style>`. The browser's parser is the tree-builder, so SVG/MathML and foreign content work. Ambient in every component (no import): `scope`, `props`, `effect`; `html` and `snippet` are the templating brands.
|
|
121
71
|
|
|
122
|
-
**Reactive state**
|
|
72
|
+
**Reactive state** — reached through `scope()` (destructure `const { state, computed, linked } = scope()` once, or call `scope().state(…)` directly). A bare `state` / `computed` / `linked` with no `scope()` in view is a compile error.
|
|
123
73
|
|
|
124
|
-
| Form
|
|
125
|
-
|
|
|
126
|
-
| `scope().state(
|
|
127
|
-
| `scope().
|
|
128
|
-
| `scope().
|
|
129
|
-
| `effect(fn)`
|
|
130
|
-
| `props()`
|
|
74
|
+
| Form | Is |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| `scope().state(value, transform?)` | a writable cell — read/reassigned as a plain variable; optional `transform(next, prev)` coerces every write |
|
|
77
|
+
| `scope().linked(fn, transform?)` | a writable local draft seeded from upstream — reseeds when the source changes, edits stay local |
|
|
78
|
+
| `scope().computed(fn)` | a read-only derived value — re-runs when a cell it reads changes |
|
|
79
|
+
| `scope().effect(fn)` | a client-only side effect (stripped from SSR); return a function to clean up |
|
|
80
|
+
| `props()` | destructure component props (`const { name = fallback, ...rest } = props()`), each a reactive read |
|
|
81
|
+
|
|
82
|
+
A two-way binding over derived state is an accessor at the bind site (`bind:value={{ get, set }}`), not a writable primitive.
|
|
131
83
|
|
|
132
84
|
**Bindings**
|
|
133
85
|
|
|
134
|
-
|
|
|
135
|
-
|
|
|
136
|
-
| `{expr}`
|
|
137
|
-
| `name={expr}`
|
|
138
|
-
| `on<event>={fn}`
|
|
139
|
-
| `bind:value={x}`
|
|
140
|
-
| `bind:
|
|
141
|
-
| `
|
|
142
|
-
| `bind:value={{ get, set }}` | Writable computed at the binding site. |
|
|
143
|
-
| `{...expr}` | Spread keys as attributes (elements) or props (components). |
|
|
144
|
-
| `attach={fn}` | Build-time element attachment with optional teardown. |
|
|
145
|
-
|
|
146
|
-
**Control flow** — `{#…}` blocks (each head reads as the JS clause it lowers to):
|
|
147
|
-
|
|
148
|
-
| Form | Meaning |
|
|
149
|
-
| ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
150
|
-
| `{#if c}` / `{:else if c}` / `{:else}` / `{/if}` | Conditional, source-order, re-evaluated reactively. |
|
|
151
|
-
| `{#for x of list}` / `{#for x, i of list by x.id}` / `{/for}` | Keyed list (`for…of`); `, i` index reactive; `by` key reconciles rows in place; key defaults to item. |
|
|
152
|
-
| `{#for await x of asyncIter by x.id}` … `{:catch e}` / `{/for}` | Async keyed list (`for await…of`); rows append as the iterator yields. |
|
|
153
|
-
| `{#await p}` / `{:then v}` / `{:catch e}` / `{:finally}` / `{/await}` | Promise branches; pending content (before `{:then}`) streams. |
|
|
154
|
-
| `{#await p then v}` / `{/await}` | Blocking: no pending, resolved inline (SSR settles before the first flush). |
|
|
155
|
-
| `{#switch s}` / `{:case v}` / `{:default}` / `{/switch}` | First strict (`===`) match wins. |
|
|
156
|
-
| `{#try}` / `{:catch e}` / `{:finally}` / `{/try}` | Synchronous render error boundary. |
|
|
157
|
-
|
|
158
|
-
**Reusable markup** — `<template>`:
|
|
159
|
-
|
|
160
|
-
| Form | Meaning |
|
|
161
|
-
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
162
|
-
| `<template name="row" args={item}>` … `{row(item)}` | Named template (snippet) definition + call. A `<template>` with a control-flow attribute (`if`/`each`/…) is a compile error — use the `{#…}` block. |
|
|
163
|
-
|
|
164
|
-
**Components & slots** — a capitalised tag (`<Card title={x}>`) mounts a child;
|
|
165
|
-
attributes become props, children fill the child's `<slot>` (with fallback when
|
|
166
|
-
empty). `<style>` is scoped to the component and its children. Component files
|
|
167
|
-
end in `.abide`. A block's binding names (`{:then v}`, `{#for x of …}`) lexically
|
|
168
|
-
shadow same-named component state inside the block.
|
|
169
|
-
|
|
170
|
-
## Server surface — abide/server/\* (server-only)
|
|
171
|
-
|
|
172
|
-
### RPC — @documentation rpc
|
|
173
|
-
|
|
174
|
-
- `@abide/abide/server/GET` — declare a `GET` verb; args from the query string. Schema auto-exposes CLI + read-MCP.
|
|
175
|
-
- `@abide/abide/server/POST` — declare a `POST` verb; args from JSON/form/multipart body (body wins on collision).
|
|
176
|
-
- `@abide/abide/server/PUT` — declare a `PUT` verb (body args; mutating).
|
|
177
|
-
- `@abide/abide/server/PATCH` — declare a `PATCH` verb (body args; mutating).
|
|
178
|
-
- `@abide/abide/server/DELETE` — declare a `DELETE` verb (query args; mutating).
|
|
179
|
-
- `@abide/abide/server/HEAD` — declare a `HEAD` verb (query args; read-only, headers-only response).
|
|
180
|
-
|
|
181
|
-
### Response — @documentation response
|
|
182
|
-
|
|
183
|
-
- `@abide/abide/server/json` — `json(data, init?)`: JSON `TypedResponse` (`Cache-Control: no-store`); `undefined` → 204.
|
|
184
|
-
- `@abide/abide/server/jsonl` — `jsonl(asyncIterable, init?)`: JSONL stream, one value per line; errors emit a `{"$error"}` final line.
|
|
185
|
-
- `@abide/abide/server/sse` — `sse(asyncIterable, init?)`: Server-Sent Events with 15s keepalive comments; errors as an `error` event.
|
|
186
|
-
- `@abide/abide/server/error` — `error(status, message?, init?)`: plain-text error `TypedResponse<never>` (narrows out of the success union).
|
|
187
|
-
- `@abide/abide/server/redirect` — `redirect(url, status=302, init?)`: redirect accepting relative URLs; `TypedResponse<never>`.
|
|
86
|
+
| Syntax | Binds |
|
|
87
|
+
| --- | --- |
|
|
88
|
+
| `{expr}` | reactive text / snippet / `html` interpolation (escaped unless `html`-branded) |
|
|
89
|
+
| `name={expr}` | reactive attribute (`false`/`null`/`undefined` removes it) |
|
|
90
|
+
| `on<event>={fn}` | event listener (`onclick`, `onsubmit`, …) |
|
|
91
|
+
| `bind:value={x}` / `bind:checked={x}` / `bind:group={x}` | two-way form binding |
|
|
92
|
+
| `bind:value={{ get, set }}` | two-way binding over derived state |
|
|
93
|
+
| `{...expr}` | spread props (component) or attributes (element) |
|
|
188
94
|
|
|
189
|
-
|
|
95
|
+
**Control flow** — mustache blocks (`{#…}` open, `{:…}` branch, `{/…}` close):
|
|
190
96
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
97
|
+
| Block | Form |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| if | `{#if cond}` … `{:elseif cond}` … `{:else}` … `{/if}` |
|
|
100
|
+
| for | `{#for item of list by key}` … `{/for}` (`item, i of list`; `{#for await x of source …}` over an AsyncIterable) |
|
|
101
|
+
| await | `{#await promise}` pending `{:then value}` … `{:catch error}` … `{/await}` (inline `{#await p then v}`) |
|
|
102
|
+
| switch | `{#switch subject}` `{:case value}` … `{:default}` … `{/switch}` |
|
|
103
|
+
| try | `{#try}` … `{:catch error}` … `{:finally}` … `{/try}` |
|
|
104
|
+
| snippet | `<template name="row" args={{ msg }}>…</template>`, called as `{row({ msg })}` |
|
|
194
105
|
|
|
195
|
-
|
|
106
|
+
**Components & slots** — a capitalised tag (`<Avatar name={…} />`) mounts a child `.abide` component as a marker-bounded range (no wrapper element); its children fill the child's `<slot>`. `<style>` is component-scoped.
|
|
107
|
+
|
|
108
|
+
## Server surface — abide/server/*
|
|
196
109
|
|
|
197
|
-
|
|
110
|
+
### RPC helpers — @documentation rpc
|
|
111
|
+
|
|
112
|
+
- `abide/server/GET` — declare a read RPC; the bundler rewrites it to a server `defineRpc` or a client `remoteProxy`. Calling it directly throws.
|
|
113
|
+
- `abide/server/POST` — declare a creating mutating RPC (carries the durable `outbox` overloads).
|
|
114
|
+
- `abide/server/PUT` — declare a replacing mutating RPC.
|
|
115
|
+
- `abide/server/PATCH` — declare a partial-update mutating RPC.
|
|
116
|
+
- `abide/server/DELETE` — declare a deleting mutating RPC.
|
|
117
|
+
- `abide/server/HEAD` — declare a metadata-only read RPC.
|
|
198
118
|
|
|
199
119
|
### Sockets — @documentation sockets
|
|
200
120
|
|
|
201
|
-
-
|
|
121
|
+
- `abide/server/socket` — declare a broadcast `Socket<T>` in `src/server/sockets/<name>.ts`; opts (`schema`, `tail`, `ttl`, `clientPublish`, `clients`) live on the server, the client proxy discards them.
|
|
202
122
|
|
|
203
|
-
###
|
|
123
|
+
### Responses — @documentation response
|
|
124
|
+
|
|
125
|
+
- `abide/server/json` — JSON `Response` with `Cache-Control: no-store` default; `json(undefined)` emits a 204 that round-trips back to `undefined`. Brands `T` so the RPC infers `Return`.
|
|
126
|
+
- `abide/server/jsonl` — wrap an `AsyncIterable<Frame>` as a JSON Lines (`application/jsonl`) streaming response; cancellation flows into the generator's `return()`, errors become a final `{"$error":…}` line.
|
|
127
|
+
- `abide/server/sse` — wrap an `AsyncIterable<Frame>` as Server-Sent Events (`text/event-stream`) with a 15s keepalive; errors become an `event: error` frame.
|
|
128
|
+
- `abide/server/error` — return a non-2xx wire error (`TypedResponse<never>`); the caller's `await fn(args)` throws `HttpError`, so it never pollutes the inferred success `Return`.
|
|
129
|
+
- `abide/server/redirect` — return a 3xx redirect (`TypedResponse<never>`), same inference-neutral shape as `error`.
|
|
130
|
+
|
|
131
|
+
### Request scope — @documentation request-scope
|
|
132
|
+
|
|
133
|
+
- `abide/server/request` — the inbound `Request` for the current SSR/RPC pass (AsyncLocalStorage); throws outside a request scope.
|
|
134
|
+
- `abide/server/cookies` — the request's `Bun.CookieMap`; reads parse the inbound header, writes flush as `Set-Cookie` on return. Lazy; throws outside a scope.
|
|
135
|
+
- `abide/server/server` — the active `Bun.serve` instance; returns a no-op in-process server under a scope without a booted server (CLI/MCP/test), throws before init outside any scope.
|
|
136
|
+
|
|
137
|
+
### Configuration — @documentation configuration
|
|
204
138
|
|
|
205
|
-
-
|
|
139
|
+
- `abide/server/env` — validate `Bun.env` against a Standard Schema at boot and return the typed config; reports every issue at once on failure, registers the schema for the bundle setup form.
|
|
206
140
|
|
|
207
141
|
### Observability — @documentation observability
|
|
208
142
|
|
|
209
|
-
-
|
|
143
|
+
- `abide/server/reachable` — server-only outbound reachability: `await reachable(host)` HEADs the origin, caches the verdict, and background-polls every TTL so later calls resolve instantly.
|
|
144
|
+
|
|
145
|
+
### Bundle data — @documentation bundle
|
|
146
|
+
|
|
147
|
+
- `abide/server/appDataDir` — the running desktop bundle's per-user data dir, keyed by the program name; cwd-independent, pure.
|
|
148
|
+
|
|
149
|
+
### Agent — @documentation agent
|
|
150
|
+
|
|
151
|
+
- `abide/server/agent` — run a provider engine against the app's own MCP surface (`agent(engine, messages)`) and yield a neutral `AgentFrame` stream; the handler frames it with `jsonl()`/`sse()`. Exports `NeutralMessage` / `AgentFrame` / `AgentEngine`.
|
|
210
152
|
|
|
211
153
|
### Plumbing — @documentation plumbing
|
|
212
154
|
|
|
213
|
-
-
|
|
214
|
-
-
|
|
215
|
-
-
|
|
216
|
-
-
|
|
155
|
+
- `abide/server/AppModule` — the optional `src/app.ts` hook shape (`init` → cleanup, single-middleware `handle`, `handleError`).
|
|
156
|
+
- `abide/server/InspectorContext` — the capability bundle core injects into `@abide/inspector` when `ABIDE_ENABLE_INSPECTOR=true`, so the inspector stays a pure consumer.
|
|
157
|
+
- `abide/server/rpc/defineRpc` — server-side RPC construction from method + URL + handler; the bundler's server-target rewrite emits it. Records the synthesized Request for `cache()`.
|
|
158
|
+
- `abide/server/sockets/defineSocket` — server-side socket construction; the bundler's server-target rewrite binds the file-path name into real fan-out over `server.publish`.
|
|
159
|
+
- `abide/server/prompts/definePrompt` — register an MCP prompt from a name + options; the resolver plugin emits it per `src/mcp/prompts/<name>.md`.
|
|
160
|
+
- `abide/server/prompts/renderPromptTemplate` — substitute `{{name}}` placeholders in a prompt body (missing args collapse to empty).
|
|
217
161
|
|
|
218
|
-
## Isomorphic surface — abide/shared
|
|
162
|
+
## Isomorphic surface — abide/shared/*
|
|
219
163
|
|
|
220
|
-
###
|
|
164
|
+
### Responses — @documentation response
|
|
221
165
|
|
|
222
|
-
-
|
|
166
|
+
- `abide/shared/HttpError` — thrown by remote-function calls on a non-2xx response; carries the raw `Response` (status/`statusText`/headers/body) plus the typed-error layer parsed off a `{ $abideError, data }` body: `.kind` (the declared error name, `'validation'`, or the framework-reserved `'queued'`) and `.data` (`unknown` — narrow yourself; `ValidationErrorData` for `'validation'`). Both undefined for a plain `error(status, text)`.
|
|
167
|
+
- `abide/shared/ValidationErrorData` — the `data` a `kind: 'validation'` HttpError (422) carries: `{ issues, fields }` — the raw Standard Schema issue list plus the form-friendly field → first-message map.
|
|
223
168
|
|
|
224
|
-
###
|
|
169
|
+
### Schema projection — @documentation rpc
|
|
225
170
|
|
|
226
|
-
-
|
|
227
|
-
- `@abide/abide/shared/snippet` — `snippet(payload)`: brand a snippet payload (client DOM builder / server HTML string) so `{expr}` mounts it.
|
|
171
|
+
- `abide/shared/withJsonSchema` — attach a `toJSONSchema()` projection to a Standard Schema whose library lacks one, feeding OpenAPI / MCP / CLI / the setup form.
|
|
228
172
|
|
|
229
|
-
###
|
|
173
|
+
### Templating — @documentation templating
|
|
230
174
|
|
|
231
|
-
-
|
|
175
|
+
- `abide/shared/html` — a `` html`…` `` tag marking trusted raw markup that a `{expr}` inserts verbatim (registered-Symbol brand, survives bundle copies).
|
|
176
|
+
- `abide/shared/snippet` — the `Snippet<Payload>` brand a `<template name>` carries: a DOM builder on the client, pre-rendered HTML on the server.
|
|
232
177
|
|
|
233
|
-
###
|
|
178
|
+
### Cache — @documentation cache
|
|
234
179
|
|
|
235
|
-
-
|
|
180
|
+
- `abide/shared/cache` — curry a call against a store: `cache(fn, options?)` returns an invoker that coalesces in-flight calls and retains by `ttl` (undefined = forever, 0 = dedupe-only). Reactive (subscribes the reading scope), isomorphic, `options.global` for the process store. `cache.invalidate` / `cache.on` address entries by selector.
|
|
236
181
|
|
|
237
182
|
### Page — @documentation page
|
|
238
183
|
|
|
239
|
-
-
|
|
184
|
+
- `abide/shared/page` — the reactive page proxy (matched route, decoded `params`, browser-space `url`, `navigating`); isomorphic, re-runs readers on navigation.
|
|
240
185
|
|
|
241
|
-
###
|
|
186
|
+
### Probes — @documentation probes
|
|
242
187
|
|
|
243
|
-
-
|
|
188
|
+
- `abide/shared/pending` — reactive "no value yet" probe over the cache + tail registries; selector grammar `pending(fn)` / `pending(fn, args)` / `pending({ tags })` / `pending(subscribable)`. Counts undelivered durable-outbox entries.
|
|
189
|
+
- `abide/shared/refreshing` — reactive "holding a value while a fresher source is in flight" probe; same selector grammar.
|
|
190
|
+
- `abide/shared/online` — the client/server-reported connectivity boolean (the inbound counterpart to `reachable`).
|
|
244
191
|
|
|
245
|
-
###
|
|
192
|
+
### URL — @documentation url
|
|
246
193
|
|
|
247
|
-
-
|
|
248
|
-
- `@abide/abide/shared/refreshing` — `refreshing(selector?, args?)`: reactive — a value held while fresh data is in flight (SWR refetch / reconnect with retained value).
|
|
249
|
-
- `@abide/abide/shared/online` — `online()`: reactive connectivity (client `navigator.onLine`; server reads the caller's reported state); reports, never acts.
|
|
194
|
+
- `abide/shared/url` — typed URL builder: `url('/rpc/search', { q })` types args against the generated `RpcRoutes`, falling through to page/asset paths; base-correct.
|
|
250
195
|
|
|
251
196
|
### Observability — @documentation observability
|
|
252
197
|
|
|
253
|
-
-
|
|
254
|
-
-
|
|
255
|
-
-
|
|
198
|
+
- `abide/shared/health` — reactive backend health (`reachable` + the app `health()` hook's fields), polled from `/__abide/health` only while a tracking scope reads it; constant `{ reachable: true }` on the server.
|
|
199
|
+
- `abide/shared/log` — the unified logger: `log`/`warn`/`error`/`trace` on the app's always-on channel, `log.channel(name)` on a DEBUG-gated channel; tsv default or JSON per line (`ABIDE_LOG_FORMAT=json`). Carries request-scope context.
|
|
200
|
+
- `abide/shared/trace` — the current request's W3C `traceparent`, isomorphic (ALS on the server, `__SSR__` stamp in the browser); undefined outside a scope.
|
|
256
201
|
|
|
257
202
|
### Plumbing — @documentation plumbing
|
|
258
203
|
|
|
259
|
-
-
|
|
204
|
+
- `abide/shared/createSubscriber` — abide-ui-native open-on-first-read / close-on-last-reader subscriber over abide's own signal core (the lifecycle `cache`/`tail`/`health` reuse).
|
|
260
205
|
|
|
261
|
-
## UI surface — abide/ui
|
|
206
|
+
## UI surface — abide/ui/* (client-only)
|
|
262
207
|
|
|
263
208
|
### Reactive state — @documentation reactive-state
|
|
264
209
|
|
|
265
|
-
-
|
|
210
|
+
- `abide/ui/scope` — resolve a lexical scope: `scope()` is the current one (compiler-established per level), `scope('/')` the tree root; the returned value is passable to children/helpers.
|
|
266
211
|
|
|
267
|
-
###
|
|
212
|
+
### Streaming — @documentation tail
|
|
268
213
|
|
|
269
|
-
-
|
|
214
|
+
- `abide/ui/tail` — reactive consumer for a `Subscribable<T>` (a `Socket<T>` or `fn.stream(args)`): bare form is latest-wins (`T | undefined`), `{ last: n }` is a live window (`T[]`); reconnect keeps the value and flags `refreshing`. No-op on the server. `tail.error` / `tail.status` address the same entry.
|
|
270
215
|
|
|
271
|
-
###
|
|
216
|
+
### Navigation — @documentation navigate
|
|
272
217
|
|
|
273
|
-
-
|
|
218
|
+
- `abide/ui/navigate` — programmatic SPA navigation typed off the page routes; `NavigateOptions` carries `replace` / `keepScroll`. Delegates path-building to `url`.
|
|
274
219
|
|
|
275
|
-
###
|
|
220
|
+
### Outbox — @documentation ui
|
|
276
221
|
|
|
277
|
-
-
|
|
278
|
-
|
|
279
|
-
### UI — @documentation ui
|
|
280
|
-
|
|
281
|
-
- `@abide/abide/ui/outbox` — `outbox({ key, send, store, online, onDrop })`: durable FIFO mutation queue for local-first writes; drains while online, retries on reconnect, at-least-once.
|
|
222
|
+
- `abide/ui/outbox` — the global reactive view of every durable-RPC outbox: a flat list of undelivered entries tagged with their `rpc`, `outbox.retry()` to drain all queues. A single RPC's slice is `rpc.outbox`. Empty on the server. Exports `GlobalOutboxEntry`.
|
|
282
223
|
|
|
283
224
|
### Plumbing — @documentation plumbing
|
|
284
225
|
|
|
285
|
-
-
|
|
286
|
-
-
|
|
287
|
-
-
|
|
288
|
-
-
|
|
289
|
-
-
|
|
290
|
-
-
|
|
291
|
-
-
|
|
292
|
-
-
|
|
293
|
-
-
|
|
294
|
-
-
|
|
295
|
-
-
|
|
296
|
-
-
|
|
297
|
-
-
|
|
298
|
-
-
|
|
299
|
-
-
|
|
300
|
-
-
|
|
301
|
-
-
|
|
302
|
-
-
|
|
303
|
-
-
|
|
304
|
-
-
|
|
305
|
-
-
|
|
306
|
-
-
|
|
307
|
-
-
|
|
308
|
-
-
|
|
309
|
-
-
|
|
310
|
-
-
|
|
311
|
-
-
|
|
312
|
-
-
|
|
313
|
-
-
|
|
314
|
-
-
|
|
315
|
-
-
|
|
316
|
-
-
|
|
317
|
-
-
|
|
318
|
-
-
|
|
319
|
-
-
|
|
320
|
-
-
|
|
321
|
-
-
|
|
322
|
-
-
|
|
323
|
-
-
|
|
226
|
+
- `abide/ui/effect` — abide's reaction primitive: run `fn` now, re-run on dep change, optional (async) teardown; returns a dispose. The runtime target the compiler emits for `scope().effect`.
|
|
227
|
+
- `abide/ui/enterScope` — open a fresh lexical scope for an SSR render, returning the previous to restore.
|
|
228
|
+
- `abide/ui/exitScope` — restore the scope `enterScope` saved.
|
|
229
|
+
- `abide/ui/remoteProxy` — the client-side RPC substitute the bundler emits per export: fetches, decodes by Content-Type, throws `HttpError`; a durable (`outbox`) RPC parks an unreachable request for replay as a side-effect. Exports `DurableOptions`.
|
|
230
|
+
- `abide/ui/socketProxy` — the client-side socket substitute: subscribe/publish over the multiplexed ws channel, same `Socket` shape as the server.
|
|
231
|
+
- `abide/ui/startClient` — the official client entry: read `__SSR__`, seed the warm cache store, install the mount base, start the router.
|
|
232
|
+
- `abide/ui/router` — the History-API client router: match the path, import the page chunk + its layout chain, mount the chain into nested `<slot/>` outlets.
|
|
233
|
+
- `abide/ui/renderToStream` — out-of-order SSR streaming: shell first, then one `<abide-resolve>` fragment per streaming `{#await}` as it settles.
|
|
234
|
+
- `abide/ui/runtime/escapeKey` — escape one object key into a JSON-Pointer token (`~0`/`~1`) so a key with `/` or `~` survives a `/`-joined path.
|
|
235
|
+
- `abide/ui/runtime/nextBlockId` — the next block id in the current render pass (document order), so page and child ids don't collide.
|
|
236
|
+
- `abide/ui/runtime/enterRenderPass` — mark entry into a render/mount; the outermost resets the block-id counter.
|
|
237
|
+
- `abide/ui/runtime/exitRenderPass` — mark exit from a render/mount, unwinding the depth.
|
|
238
|
+
- `abide/ui/dom/mount` — mount a top-level page/layout into a host element under an ownership scope; returns a disposer.
|
|
239
|
+
- `abide/ui/dom/mountChild` — mount a child component as a marker-bounded range (no wrapper); hot path keeps the range for in-place HMR re-fill.
|
|
240
|
+
- `abide/ui/dom/mountSlot` — mount a component's `<slot>` content as a marker range (parent `$children` or fallback); renders once.
|
|
241
|
+
- `abide/ui/dom/outlet` — a layout's `<slot/>` outlet as an empty comment boundary the router fills with the next chain layer.
|
|
242
|
+
- `abide/ui/dom/mergeProps` — compose a child's props from ordered layers (explicit thunks, spreads, the `$children` slot), last layer wins per key.
|
|
243
|
+
- `abide/ui/dom/spreadProps` — wrap a `{...source}` props layer so each key resolves to a live value thunk; the source thunk re-reads reactively.
|
|
244
|
+
- `abide/ui/dom/restProps` — the unconsumed props of a `const { a, ...rest } = props()` as a live object (thunks unwrapped; plain page params returned as-is).
|
|
245
|
+
- `abide/ui/dom/spreadAttrs` — spread an object's keys onto a native element (`<div {...rest}>`): keys enumerated once, each value live; `on*` keys attach as listeners.
|
|
246
|
+
- `abide/ui/dom/attr` — bind one element attribute to `read()` (boolean present/absent, else stringified); one effect per attribute.
|
|
247
|
+
- `abide/ui/dom/on` — attach an event listener scoped to the owning component (the `onclick={…}` runtime target), pinned to its `scope()`.
|
|
248
|
+
- `abide/ui/dom/attach` — run a node-lifetime attachment at build time with optional teardown (the dual of `on`); may be async.
|
|
249
|
+
- `abide/ui/dom/text` — a text node tracking `read()` via one effect (plain text, `String()`-coerced).
|
|
250
|
+
- `abide/ui/dom/appendText` — a reactive `{expr}` interpolation (escaped text, snippet, or `html`); claims and splits merged SSR text on hydrate.
|
|
251
|
+
- `abide/ui/dom/appendTextAt` — a reactive `{expr}` mounted at a skeleton anchor, for text interleaved with element siblings.
|
|
252
|
+
- `abide/ui/dom/appendStatic` — a static (non-reactive) text node, claimed/split from SSR text on hydrate.
|
|
253
|
+
- `abide/ui/dom/appendSnippet` — a `{snippet(args)}` interpolation mounted in a marker-bounded range; reactive in its args.
|
|
254
|
+
- `abide/ui/dom/cloneStatic` — append a fully-static subtree from a compiler skeleton string (byte-identical to SSR markup).
|
|
255
|
+
- `abide/ui/dom/skeleton` — realize a compiled skeleton under a parent and return its element holes (pre-order) + anchor holes (document order); the parser is the tree-builder, so foreign content lands namespaced.
|
|
256
|
+
- `abide/ui/dom/anchorCursor` — position a skeleton-anchored control-flow block or slot relative to its `<!--a-->` marker.
|
|
257
|
+
- `abide/ui/dom/readCall` — a guarded method call on a reactive-doc read, so a nullish throw names the authored scope path instead of the desugared call.
|
|
258
|
+
- `abide/ui/dom/hydrate` — adopt server-rendered DOM: run `build` with a claim cursor so dom helpers take existing nodes; returns a disposer.
|
|
259
|
+
- `abide/ui/dom/each` — the keyed `{#for … by key}` runtime: each row a marker-bounded range reconciled by key.
|
|
260
|
+
- `abide/ui/dom/eachAsync` — the async `{#for await … by key}` runtime over an `AsyncIterable`; SSR renders no rows.
|
|
261
|
+
- `abide/ui/dom/when` — the `{#if}` (+ `{:else}`) runtime: a branch range swapped on a truthy↔falsy flip.
|
|
262
|
+
- `abide/ui/dom/awaitBlock` — the `{#await}` runtime: pending → resolved/error branch on settle, each a range.
|
|
263
|
+
- `abide/ui/dom/tryBlock` — the `{#try}` runtime: a synchronous error boundary; build throw → `{:catch}` branch, no catch re-throws.
|
|
264
|
+
- `abide/ui/dom/switchBlock` — the `{#switch}` runtime: first `===`-matching case (or default), each a range.
|
|
265
|
+
- `abide/ui/dom/applyResolved` — bundle-side consumer of an SSR stream chunk (streaming SPA nav, socket-delivered SSR): seed cache partitions and swap await boundaries.
|
|
324
266
|
|
|
325
267
|
## Build / tooling
|
|
326
268
|
|
|
327
269
|
### Building — @documentation building
|
|
328
270
|
|
|
329
|
-
-
|
|
330
|
-
-
|
|
271
|
+
- `abide/build` — build the client bundle into `dist/_app` (Bun.build + the `.abide` loader, virtual-module resolver, optional Tailwind; `compress` writes `.gz` siblings).
|
|
272
|
+
- `abide/compile` — produce a standalone Bun server executable (runs `build` first to embed assets); returns the binary path.
|
|
331
273
|
|
|
332
274
|
### Plumbing — @documentation plumbing
|
|
333
275
|
|
|
334
|
-
-
|
|
335
|
-
-
|
|
336
|
-
-
|
|
337
|
-
-
|
|
276
|
+
- `abide/preload` — the Bun preload entry that installs the `.abide` loader + resolver for `abide run` and `bun test`.
|
|
277
|
+
- `abide/resolver-plugin` — the Bun plugin wiring every build-time virtual import (`abide:rpc` / `abide:sockets` / `abide:pages` / `abide:prompts` / `abide:app` …).
|
|
278
|
+
- `abide/ui-plugin` — the Bun plugin that compiles each `.abide` single-file component (and `layout.abide`) to its ES module.
|
|
279
|
+
- `abide/tsconfig` — the shareable base `tsconfig` (`tsconfig.app.json`) projects extend.
|
|
338
280
|
|
|
339
|
-
## Desktop bundle
|
|
281
|
+
## Desktop bundle — abide/bundle/*
|
|
340
282
|
|
|
341
283
|
### Bundle — @documentation bundle
|
|
342
284
|
|
|
343
|
-
-
|
|
344
|
-
-
|
|
345
|
-
-
|
|
346
|
-
-
|
|
347
|
-
-
|
|
348
|
-
- `@abide/abide/bundle/bundled` — `bundled()`: true when running inside the abide desktop bundle.
|
|
285
|
+
- `abide/bundle/BundleWindow` — the optional `src/bundle/window.ts` default-export shape (title, size, menus); baked into the launcher.
|
|
286
|
+
- `abide/bundle/BundleMenu` — a top-level menu inserted into the macOS menu bar (`label` + `items`).
|
|
287
|
+
- `abide/bundle/BundleMenuItem` — one menu entry: a divider or a clickable item that dispatches an `abide:menu` CustomEvent into the page.
|
|
288
|
+
- `abide/bundle/onMenu` — subscribe to bundle menu clicks (catch-all or per-name), returning an unsubscribe.
|
|
289
|
+
- `abide/bundle/bundled` — `true` when the code runs inside the abide desktop bundle; isomorphic, detected per side.
|
|
349
290
|
|
|
350
|
-
## MCP
|
|
291
|
+
## MCP — abide/mcp/*
|
|
351
292
|
|
|
352
293
|
### MCP — @documentation mcp
|
|
353
294
|
|
|
354
|
-
-
|
|
355
|
-
|
|
356
|
-
### Prompts — @documentation plumbing
|
|
357
|
-
|
|
358
|
-
- `@abide/abide/server/prompts/definePrompt` — `definePrompt(name, opts)`: build a `Prompt` from an `src/mcp/prompts/*.md` file (the bundler emits the call).
|
|
359
|
-
- `@abide/abide/server/prompts/renderPromptTemplate` — `renderPromptTemplate(template, args)`: substitute `{{name}}` placeholders (missing → empty string).
|
|
295
|
+
- `abide/mcp/createMcpServer` — construct the MCP server bound to the project's RPC registry; its `handle(request)` backs `/__abide/mcp`. Framework-internal (the `abide:mcp` virtual default-constructs it).
|
|
360
296
|
|
|
361
|
-
## Testing
|
|
297
|
+
## Testing — abide/test/*
|
|
362
298
|
|
|
363
299
|
### Testing — @documentation testing
|
|
364
300
|
|
|
365
|
-
-
|
|
301
|
+
- `abide/test/createTestApp` — an in-process test app exposing `app.rpc.<rpc>` / `app.sockets.<name>` typed against the project's generated surface (no network, no imports).
|
|
366
302
|
|
|
367
303
|
### Plumbing — @documentation plumbing
|
|
368
304
|
|
|
369
|
-
-
|
|
370
|
-
-
|
|
305
|
+
- `abide/test/createScriptedSurface` — a scripted `AgentSurface` for engine tests: declarative tool stubs in, an MCP surface out, every `call` recorded.
|
|
306
|
+
- `abide/test/assertAgentFrameConformance` — collect an engine's frame stream and assert the neutral `AgentFrame` contract (one terminal `done`, every `tool_use` answered, …).
|
|
371
307
|
|
|
372
308
|
## Generated machine surfaces
|
|
373
309
|
|
|
374
310
|
Runtime routes the framework serves:
|
|
375
311
|
|
|
376
|
-
| Route
|
|
377
|
-
|
|
|
378
|
-
| `/openapi.json`
|
|
379
|
-
| `/__abide/mcp`
|
|
380
|
-
| `/__abide/health`
|
|
381
|
-
| `/__abide/sockets`
|
|
382
|
-
| `/__abide/cli`
|
|
383
|
-
| `/__abide/
|
|
384
|
-
| `/__abide/
|
|
385
|
-
| `/__abide/
|
|
312
|
+
| Route | Serves |
|
|
313
|
+
| --- | --- |
|
|
314
|
+
| `/openapi.json` | the OpenAPI document projected from every RPC schema |
|
|
315
|
+
| `/__abide/mcp` | the MCP endpoint (tools/prompts from the RPC + prompt registries) |
|
|
316
|
+
| `/__abide/health` | the health payload (`reachable` + the app `health()` hook's fields) |
|
|
317
|
+
| `/__abide/sockets` | the multiplexed WebSocket hub (and `/__abide/sockets/<name>` HTTP face) |
|
|
318
|
+
| `/__abide/cli` | the CLI manifest the `abide cli` binary reads |
|
|
319
|
+
| `/__abide/identity` | the server identity the bundle/CLI client probes |
|
|
320
|
+
| `/__abide/inspector` | the inspector surface (when `ABIDE_ENABLE_INSPECTOR=true`) |
|
|
321
|
+
| `/__abide/hot` | the dev hot-reload channel |
|
|
386
322
|
|
|
387
323
|
## Environment variables
|
|
388
324
|
|
|
389
|
-
| Variable
|
|
390
|
-
|
|
|
391
|
-
| `PORT`
|
|
392
|
-
| `APP_URL`
|
|
393
|
-
| `ABIDE_APP_URL`
|
|
394
|
-
| `ABIDE_APP_TOKEN`
|
|
395
|
-
| `ABIDE_CLIENT_TIMEOUT`
|
|
396
|
-
| `ABIDE_MAX_REQUEST_BODY_SIZE` |
|
|
397
|
-
| `ABIDE_IDLE_TIMEOUT`
|
|
398
|
-
| `
|
|
399
|
-
| `ABIDE_REACHABLE_TTL`
|
|
400
|
-
| `
|
|
401
|
-
| `ABIDE_LOG_FORMAT`
|
|
402
|
-
| `DEBUG`
|
|
403
|
-
| `ABIDE_ENABLE_INSPECTOR`
|
|
404
|
-
| `ABIDE_INSPECT`
|
|
325
|
+
| Variable | Effect |
|
|
326
|
+
| --- | --- |
|
|
327
|
+
| `PORT` | server listen port (unset → abide scans from a default) |
|
|
328
|
+
| `APP_URL` | public origin; its pathname becomes the app's mount base (sub-path hosting) |
|
|
329
|
+
| `ABIDE_APP_URL` | runtime URL of the server the bundle/CLI client connects to |
|
|
330
|
+
| `ABIDE_APP_TOKEN` | bearer token the bundle/CLI client sends to an authenticated remote server |
|
|
331
|
+
| `ABIDE_CLIENT_TIMEOUT` | client-side per-call fetch timeout (ms); a breach surfaces as a 504 `HttpError` |
|
|
332
|
+
| `ABIDE_MAX_REQUEST_BODY_SIZE` | default inbound request-body byte cap (a per-RPC `maxBodySize` overrides) |
|
|
333
|
+
| `ABIDE_IDLE_TIMEOUT` | Bun per-connection idle timeout (seconds) |
|
|
334
|
+
| `ABIDE_DATA_DIR` | override the per-user app data dir on every platform (used as-is) |
|
|
335
|
+
| `ABIDE_REACHABLE_TTL` | `reachable()` poll cadence / freshness window (ms) |
|
|
336
|
+
| `ABIDE_REACHABLE_TIMEOUT` | `reachable()` per-HEAD probe bound (ms) |
|
|
337
|
+
| `ABIDE_LOG_FORMAT` | `json` switches the logger from tsv to one JSON object per line |
|
|
338
|
+
| `DEBUG` | enable DEBUG-gated diagnostic log channels (npm-debug conventions, e.g. `abide`, `abide:*`) |
|
|
339
|
+
| `ABIDE_ENABLE_INSPECTOR` | inject the `InspectorContext` into `@abide/inspector` (exposes all traffic; trusted use only) |
|
|
340
|
+
| `ABIDE_INSPECT` | enable the desktop bundle's right-click → Inspect web-inspector (off in release bundles) |
|
|
405
341
|
|
|
406
342
|
---
|
|
407
343
|
|
|
408
|
-
This map mirrors `package.json
|
|
409
|
-
run `bun run packages/abide/scripts/readmeSurfaces.ts` and update the matching
|
|
410
|
-
bullet here.
|
|
344
|
+
This map mirrors the `exports` map in `package.json`. After adding or renaming an export, run `bun run packages/abide/scripts/readmeSurfaces.ts` and update the matching section here.
|