@abide/abide 0.43.0 → 0.44.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 +293 -219
- package/CHANGELOG.md +46 -0
- package/README.md +191 -67
- package/package.json +2 -2
- package/src/abideLsp.ts +8 -4
- package/src/abideResolverPlugin.ts +11 -1
- package/src/build.ts +9 -0
- package/src/buildDisconnected.ts +2 -0
- package/src/devEntry.ts +1 -0
- package/src/lib/bundle/probeAbideServer.ts +1 -1
- package/src/lib/cli/parseArgvForRpc.ts +4 -2
- package/src/lib/cli/types/CliManifest.ts +6 -4
- package/src/lib/mcp/annotationsForMethod.ts +1 -1
- package/src/lib/mcp/toolResultFromResponse.ts +1 -1
- package/src/lib/mcp/types/JsonRpcRequest.ts +3 -3
- package/src/lib/server/AppModule.ts +1 -1
- package/src/lib/server/cli/handleCliDownload.ts +7 -5
- package/src/lib/server/cli/installScript.ts +3 -3
- package/src/lib/server/prompts/promptRegistry.ts +1 -1
- package/src/lib/server/prompts/types/Prompt.ts +2 -1
- package/src/lib/server/rpc/dispatchRpcInProcess.ts +2 -2
- package/src/lib/server/rpc/types/RpcHelper.ts +1 -1
- package/src/lib/server/runtime/createPublicAssetServer.ts +2 -2
- package/src/lib/server/runtime/createRouteDispatcher.ts +1 -1
- package/src/lib/server/runtime/createServer.ts +21 -0
- package/src/lib/server/runtime/createUiPageRenderer.ts +7 -11
- package/src/lib/server/runtime/crossOriginForbidden.ts +2 -2
- package/src/lib/server/runtime/crossOriginGate.ts +1 -1
- package/src/lib/server/runtime/devHotModuleResponse.ts +2 -2
- package/src/lib/server/runtime/disableIdleTimeoutForStream.ts +1 -1
- package/src/lib/server/runtime/logExposedSurfaces.ts +3 -4
- package/src/lib/server/runtime/serializeCacheSnapshot.ts +3 -8
- package/src/lib/server/runtime/snapshotEntryFromCache.ts +10 -7
- package/src/lib/server/runtime/streamFromIterator.ts +2 -2
- package/src/lib/server/runtime/types/InspectorRpc.ts +2 -2
- package/src/lib/server/socket.ts +1 -1
- package/src/lib/server/sockets/createSocketDispatcher.ts +2 -2
- package/src/lib/server/sockets/socketRegistry.ts +2 -2
- package/src/lib/server/sockets/types/SocketClientFrame.ts +3 -3
- package/src/lib/shared/CACHE_WRAPPED.ts +3 -2
- package/src/lib/shared/REMOTE_FUNCTION.ts +1 -1
- package/src/lib/shared/STREAMING_CONTENT_TYPES.ts +3 -2
- package/src/lib/shared/bodyValueForKind.ts +35 -0
- package/src/lib/shared/cache.ts +1 -1
- package/src/lib/shared/cacheEntryFromSnapshot.ts +23 -18
- package/src/lib/shared/createPushIterator.ts +1 -1
- package/src/lib/shared/decodeResponse.ts +11 -8
- package/src/lib/shared/hasReplayableRequest.ts +17 -0
- package/src/lib/shared/html.ts +7 -26
- package/src/lib/shared/manifestModule.ts +2 -2
- package/src/lib/shared/online.ts +1 -1
- package/src/lib/shared/outboxProbeSlot.ts +1 -1
- package/src/lib/shared/pageUrlForFile.ts +1 -1
- package/src/lib/shared/routeParamsShape.ts +20 -0
- package/src/lib/shared/snapshotShippable.ts +22 -0
- package/src/lib/shared/types/CacheEntry.ts +1 -1
- package/src/lib/shared/types/CacheInvalidation.ts +3 -3
- package/src/lib/shared/types/ClientFlags.ts +5 -3
- package/src/lib/shared/types/LastConnection.ts +1 -1
- package/src/lib/shared/url.ts +4 -1
- package/src/lib/shared/withBase.ts +1 -2
- package/src/lib/shared/writeDts.ts +2 -2
- package/src/lib/shared/writeRoutesDts.ts +3 -31
- package/src/lib/test/createTestSocketChannel.ts +3 -3
- package/src/lib/ui/COMPONENT_WRAPPER_PREFIX.ts +1 -1
- package/src/lib/ui/compile/ABIDE_SEMANTIC_TOKENS_LEGEND.ts +40 -6
- package/src/lib/ui/compile/REACTIVE_CALLEES.ts +1 -1
- package/src/lib/ui/compile/UI_RUNTIME_IMPORTS.ts +49 -37
- package/src/lib/ui/compile/abideUiPlugin.ts +1 -1
- package/src/lib/ui/compile/assertRuntimeHelpersBound.ts +3 -1
- package/src/lib/ui/compile/awaitPlan.ts +14 -2
- package/src/lib/ui/compile/catchBinding.ts +8 -0
- package/src/lib/ui/compile/classStyleMergePlan.ts +108 -0
- package/src/lib/ui/compile/collectAbideDiagnostics.ts +11 -0
- package/src/lib/ui/compile/compileComponent.ts +4 -4
- package/src/lib/ui/compile/compileModule.ts +20 -6
- package/src/lib/ui/compile/compileSSR.ts +12 -10
- package/src/lib/ui/compile/compileShadow.ts +107 -16
- package/src/lib/ui/compile/composeProps.ts +3 -3
- package/src/lib/ui/compile/createShadowLanguageService.ts +30 -2
- package/src/lib/ui/compile/createShadowProgram.ts +2 -1
- package/src/lib/ui/compile/createShadowScope.ts +42 -0
- package/src/lib/ui/compile/decodeHtmlEntities.ts +4 -0
- package/src/lib/ui/compile/desugarSignals.ts +12 -7
- package/src/lib/ui/compile/eachPlan.ts +61 -0
- package/src/lib/ui/compile/elementPlan.ts +55 -0
- package/src/lib/ui/compile/encodeSemanticTokens.ts +24 -1
- package/src/lib/ui/compile/generateBuild.ts +150 -127
- package/src/lib/ui/compile/generateSSR.ts +112 -73
- package/src/lib/ui/compile/ifPlan.ts +7 -1
- package/src/lib/ui/compile/interpolatedTemplateLiteral.ts +25 -0
- package/src/lib/ui/compile/isPlainIdentifier.ts +7 -0
- package/src/lib/ui/compile/isTextLeaf.ts +8 -7
- package/src/lib/ui/compile/lowerContext.ts +36 -46
- package/src/lib/ui/compile/lowerDocAccess.ts +2 -2
- package/src/lib/ui/compile/lowerScript.ts +1 -1
- package/src/lib/ui/compile/markupTokens.ts +313 -0
- package/src/lib/ui/compile/pagePropsType.ts +23 -0
- package/src/lib/ui/compile/parseTemplate.ts +131 -61
- package/src/lib/ui/compile/reactiveBinding.ts +47 -0
- package/src/lib/ui/compile/renameSignalRefs.ts +44 -10
- package/src/lib/ui/compile/skeletonable.ts +5 -5
- package/src/lib/ui/compile/snippetPlan.ts +28 -0
- package/src/lib/ui/compile/spreadExcludedNames.ts +4 -4
- package/src/lib/ui/compile/structuralBlockTokens.ts +3 -4
- package/src/lib/ui/compile/switchPlan.ts +7 -1
- package/src/lib/ui/compile/tryPlan.ts +8 -1
- package/src/lib/ui/compile/types/AnalyzedComponent.ts +2 -2
- package/src/lib/ui/compile/types/Binding.ts +24 -0
- package/src/lib/ui/compile/types/CompiledShadow.ts +13 -1
- package/src/lib/ui/compile/types/ElementPlan.ts +43 -0
- package/src/lib/ui/compile/types/ShadowKind.ts +9 -0
- package/src/lib/ui/compile/types/ShadowScope.ts +19 -0
- package/src/lib/ui/compile/types/TemplateAttr.ts +7 -0
- package/src/lib/ui/compile/types/TemplateNode.ts +8 -8
- package/src/lib/ui/compile/withBindings.ts +45 -0
- package/src/lib/ui/createScope.ts +2 -2
- package/src/lib/ui/dom/MATHML_NAMESPACE.ts +2 -2
- package/src/lib/ui/dom/SVG_NAMESPACE.ts +3 -2
- package/src/lib/ui/dom/appendText.ts +1 -1
- package/src/lib/ui/dom/applyResolved.ts +1 -1
- package/src/lib/ui/dom/buildDetachedRange.ts +4 -3
- package/src/lib/ui/dom/cloneStatic.ts +3 -2
- package/src/lib/ui/dom/each.ts +26 -7
- package/src/lib/ui/dom/foreignWrapperTag.ts +2 -2
- package/src/lib/ui/dom/mountChild.ts +8 -1
- package/src/lib/ui/dom/readCall.ts +6 -4
- package/src/lib/ui/dom/scopeLabel.ts +3 -3
- package/src/lib/ui/dom/switchBlock.ts +3 -1
- package/src/lib/ui/dom/types/EachRow.ts +4 -0
- package/src/lib/ui/dom/types/SkeletonHoles.ts +4 -2
- package/src/lib/ui/history.ts +1 -2
- package/src/lib/ui/html.ts +28 -0
- package/src/lib/ui/installHotBridge.ts +0 -2
- package/src/lib/ui/renderChain.ts +16 -3
- package/src/lib/ui/router.ts +66 -15
- package/src/lib/ui/rpcOutbox/createOutboxQueue.ts +1 -1
- package/src/lib/ui/runtime/CHILD_PRESENT.ts +8 -0
- package/src/lib/ui/runtime/OUTLET_MARKER.ts +2 -2
- package/src/lib/ui/runtime/RANGE_MARKER.ts +1 -1
- package/src/lib/ui/runtime/REACTIVE_CONTEXT.ts +9 -3
- package/src/lib/ui/runtime/captureModelDoc.ts +1 -1
- package/src/lib/ui/runtime/createDoc.ts +5 -1
- package/src/lib/ui/runtime/createEffectNode.ts +5 -5
- package/src/lib/ui/runtime/flushEffects.ts +22 -9
- package/src/lib/ui/runtime/historyEntries.ts +1 -1
- package/src/lib/ui/runtime/track.ts +4 -2
- package/src/lib/ui/runtime/trigger.ts +34 -20
- package/src/lib/ui/runtime/types/Route.ts +2 -2
- package/src/lib/ui/runtime/types/UiComponent.ts +3 -2
- package/src/lib/ui/runtime/types/UiProps.ts +9 -12
- package/src/lib/ui/runtime/walkPath.ts +15 -3
- package/src/lib/ui/startClient.ts +41 -14
- package/src/lib/ui/state.ts +3 -3
- package/src/lib/ui/types/Scope.ts +3 -3
- package/src/serverBuildPlugins.ts +11 -5
- package/src/zodCjsPlugin.ts +36 -0
- package/template/.zed/settings.json +7 -1
- package/template/package.json +3 -0
- package/template/src/ui/pages/layout.abide +3 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# abide
|
|
2
2
|
|
|
3
|
+
## 0.44.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 24444a8: add zod→CommonJS shim plugin for bun ESM-cycle bug ([`0424b20`](https://github.com/briancray/abide/commit/0424b20151f4d1a98d7b022bbacbbb974d469b47))
|
|
8
|
+
- 24444a8: {children()} replaces the <slot> element ([`0bdfbe5`](https://github.com/briancray/abide/commit/0bdfbe5c3efd621492cdef09b745f9262c5be937))
|
|
9
|
+
- 24444a8: type page params via props(); declare children in the shadow ([`2e58768`](https://github.com/briancray/abide/commit/2e58768cfbfb5a2be2aec48c77482e7bf5ee1b8d))
|
|
10
|
+
- 24444a8: syntactic markup token classifier and zed grammar tokens ([`5cdef1f`](https://github.com/briancray/abide/commit/5cdef1f81762d9c1b8c63a418499335c6524b0a5))
|
|
11
|
+
- 24444a8: {#snippet} block replaces <template name> declarations ([`620c2c3`](https://github.com/briancray/abide/commit/620c2c3ba7d8b797ccb770664db47468e4265131))
|
|
12
|
+
- 24444a8: wire {#if children} lowering; migrate snippet/slot test fixtures ([`861b30b`](https://github.com/briancray/abide/commit/861b30be19deb83b5749b8bb2ca8dd526b29b1b3))
|
|
13
|
+
- 24444a8: page/layout params as reactive props() thunks; layout {#if children} ([`991cea7`](https://github.com/briancray/abide/commit/991cea79a08b09508285769a35494b03111b5113))
|
|
14
|
+
- 24444a8: attribute and prop value interpolation ([`ae0a3da`](https://github.com/briancray/abide/commit/ae0a3daa13411d6de71917efde4cb76c57c855c7))
|
|
15
|
+
- 24444a8: {#if children} lowers children to $props.$children ([`f749f47`](https://github.com/briancray/abide/commit/f749f47836cdf69ccbc51d7b7fb9fafa7d7189a4))
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 24444a8: effect queue Set -> double-buffered array ([`03c6d09`](https://github.com/briancray/abide/commit/03c6d09334559a2a24c3c953cbf57e5f231ea9c6))
|
|
20
|
+
- 24444a8: prune each reconcile by generation stamp, not a per-pass Set ([`1b48eed`](https://github.com/briancray/abide/commit/1b48eedc9b1657946321cad8c9843930b0bec5d0))
|
|
21
|
+
- 24444a8: accumulated working-tree changes ([`1df2999`](https://github.com/briancray/abide/commit/1df2999b3f4b381334d365b1ff2df53711ad6b50))
|
|
22
|
+
- 24444a8: Breaking: reserve $$ injected namespace, relocate html to abide/ui/html ([`1ef8c2a`](https://github.com/briancray/abide/commit/1ef8c2a047cfaf086df1676d498cdcd2bcbe45d0))
|
|
23
|
+
- 24444a8: shadow block value-params on both back-ends ([`25f719a`](https://github.com/briancray/abide/commit/25f719a17c69aee71e2bc7884080231c35ef6578))
|
|
24
|
+
- 24444a8: shared element-emission plan across build/SSR backends ([`2a6cec5`](https://github.com/briancray/abide/commit/2a6cec5361051c1da021dba50ce40a656106e5a7))
|
|
25
|
+
- 24444a8: typed auto-popping shadow scope for compile lowering ([`2fd04a0`](https://github.com/briancray/abide/commit/2fd04a0ed8dc5453461efa0af920d046549a8877))
|
|
26
|
+
- 24444a8: dedup deref-scope push/pop into withScoped ([`3552fff`](https://github.com/briancray/abide/commit/3552fffd2dc2e69708b8268b42609c4e971eb932))
|
|
27
|
+
- 24444a8: lower await {:finally} outside the then/catch value-param shadow ([`4b33813`](https://github.com/briancray/abide/commit/4b33813433fc42455c6b069da1eb118d71b9af1b))
|
|
28
|
+
- 24444a8: iterate mark down single-subscriber chains ([`4ca3fd4`](https://github.com/briancray/abide/commit/4ca3fd419d58667eb074dd033afc2e29b10f56cd))
|
|
29
|
+
- 24444a8: unify warm-seed shippability + decode symmetry ([`5675e37`](https://github.com/briancray/abide/commit/5675e37ec240ab785e3e83eed7b2723f6dcce090))
|
|
30
|
+
- 24444a8: accumulated feat/arch-deepening working-tree changes ([`60cef30`](https://github.com/briancray/abide/commit/60cef30c2405db94ded7e708abddf2c18b4db555))
|
|
31
|
+
- 24444a8: clear typecheck and lint errors in the arch-deepening compile/dom backlog ([`782fb42`](https://github.com/briancray/abide/commit/782fb42769e495addd57904ccd1fb0148f81f9bb))
|
|
32
|
+
- 24444a8: add eachPlan + snippetPlan, route structure through plans (phase 1) ([`8cfffcc`](https://github.com/briancray/abide/commit/8cfffcc958b63b62da51e670f8f8f4c64a3ca5e5))
|
|
33
|
+
- 24444a8: {children()}/{#snippet}/props() route params ([`8f1dc89`](https://github.com/briancray/abide/commit/8f1dc89bfbf052c07082b939e893c9aee65aeea9))
|
|
34
|
+
- 24444a8: single-source bindings via plans + withBindings, exhaustive dispatch (phase 2) ([`9228e30`](https://github.com/briancray/abide/commit/9228e30d4ba16c3ef1bc14b7d243b9628bde1b59))
|
|
35
|
+
- 24444a8: resolve each key to its row once per reconcile ([`ce3e160`](https://github.com/briancray/abide/commit/ce3e160c8837ec5df4cf5cf625c1db50402defde))
|
|
36
|
+
- 24444a8: reorganize kitchen-sink nav and refresh README/scaffold ([`e31ba15`](https://github.com/briancray/abide/commit/e31ba159d9cc1db88cdebb96f40ff8d5c89b7e0f))
|
|
37
|
+
- 24444a8: scope the children slot reader through the signal transformer ([`e4a901d`](https://github.com/briancray/abide/commit/e4a901da9858f3b307363f98c97c3e72c3569640))
|
|
38
|
+
- 24444a8: faster structural descend via no-alloc walkPath + suffix walk ([`ef14dac`](https://github.com/briancray/abide/commit/ef14dace7c4eb870fe9b0487d4111ecfe635831c))
|
|
39
|
+
- 24444a8: elementPlan over skeletonContext, share emission decisions (phase 3) ([`f75703e`](https://github.com/briancray/abide/commit/f75703e0a276c37ce1fbbfde6b4c4b6064d551b8))
|
|
40
|
+
- 24444a8: effect is not ambient — it is a scope primitive ([`f8942ed`](https://github.com/briancray/abide/commit/f8942ed675d6d6493b3d53bd1cc4e991d1d1b7dd))
|
|
41
|
+
|
|
42
|
+
## 0.43.1
|
|
43
|
+
|
|
44
|
+
### Patch Changes
|
|
45
|
+
|
|
46
|
+
- 943402b: restore reload scroll flash-free via native restoration ([`876b99c`](https://github.com/briancray/abide/commit/876b99cd6e285b6a41afe87ca053cf0631099c03))
|
|
47
|
+
- ed96096: abide check: quote hyphenated component prop keys (`aria-label`, `data-*`) so the props shim parses, and treat `on*` callbacks as ordinary declared props (not DOM passthrough) so a passed required `onsave`/`oncancel` no longer reads as missing while an undeclared handler is still caught
|
|
48
|
+
|
|
3
49
|
## 0.43.0
|
|
4
50
|
|
|
5
51
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,29 +1,38 @@
|
|
|
1
1
|
# abide
|
|
2
2
|
|
|
3
|
-
**One typed declaration fans out to
|
|
3
|
+
**One typed declaration fans out to HTTP, a CLI, an MCP tool, and an OpenAPI
|
|
4
|
+
operation — and the same callable runs on the server and in the browser.**
|
|
4
5
|
|
|
5
|
-
abide is
|
|
6
|
+
abide is an isomorphic, multimodal HTTP framework for a single Bun runtime: you
|
|
7
|
+
declare a typed RPC once and it becomes a browser fetch, an in-process SSR call,
|
|
8
|
+
an MCP tool, a CLI subcommand, and an OpenAPI operation; the bundler swaps the
|
|
9
|
+
runtime per side so the same name behaves the same on both. Built for humans
|
|
10
|
+
*and* machines.
|
|
6
11
|
|
|
7
|
-
- One direct dependency (TypeScript).
|
|
12
|
+
- One direct dependency (TypeScript). One runtime (Bun ≥ 1.3).
|
|
13
|
+
- `.abide` single-file components render on the server and hydrate in place.
|
|
8
14
|
|
|
9
15
|
## Quick start
|
|
10
16
|
|
|
11
17
|
```sh
|
|
12
|
-
bunx abide scaffold my-app # scaffolds
|
|
18
|
+
bunx abide scaffold my-app # scaffolds, installs, and starts the dev server
|
|
13
19
|
```
|
|
14
20
|
|
|
15
|
-
Or
|
|
21
|
+
Or clone the kitchen-sink example:
|
|
16
22
|
|
|
17
23
|
```sh
|
|
18
|
-
git clone
|
|
24
|
+
git clone https://github.com/briancray/abide
|
|
19
25
|
cd abide/examples/kitchen-sink
|
|
20
26
|
bun install
|
|
21
|
-
bun dev
|
|
27
|
+
bun run dev
|
|
22
28
|
```
|
|
23
29
|
|
|
24
30
|
## RPCs
|
|
25
31
|
|
|
26
|
-
An RPC is one export
|
|
32
|
+
An RPC is one export under `src/server/rpc/`. The file path is the URL; the
|
|
33
|
+
export's schema validates the args and projects the MCP tool, the CLI flags, and
|
|
34
|
+
the OpenAPI operation. The schema contract is Standard Schema — pass a zod,
|
|
35
|
+
valibot, or arktype schema directly, unadapted.
|
|
27
36
|
|
|
28
37
|
```ts
|
|
29
38
|
// src/server/rpc/getMessages.ts
|
|
@@ -31,97 +40,212 @@ import { GET } from '@abide/abide/server/GET'
|
|
|
31
40
|
import { json } from '@abide/abide/server/json'
|
|
32
41
|
import { z } from 'zod'
|
|
33
42
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
43
|
+
export const getMessages = GET(
|
|
44
|
+
async ({ channel }) => json(await db.recentMessages(channel)),
|
|
45
|
+
{ inputSchema: z.object({ channel: z.coerce.string() }) },
|
|
46
|
+
)
|
|
37
47
|
```
|
|
38
48
|
|
|
39
|
-
|
|
49
|
+
One declaration, every surface:
|
|
40
50
|
|
|
41
51
|
```text
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
export const getMessages = GET(fn, { inputSchema })
|
|
53
|
+
│
|
|
54
|
+
┌───────────────┬─────────────┼─────────────┬───────────────┐
|
|
55
|
+
▼ ▼ ▼ ▼ ▼
|
|
56
|
+
SSR call browser fetch MCP tool CLI command OpenAPI op
|
|
57
|
+
cache(fn)() typed proxy (read-only) getMessages … /openapi.json
|
|
58
|
+
(in-process) (swapped fn())
|
|
48
59
|
```
|
|
49
60
|
|
|
50
|
-
|
|
61
|
+
A schema unlocks the CLI for any method and auto-exposes read-only methods
|
|
62
|
+
(`GET`/`HEAD`) as MCP tools; a mutating method (`POST`/`PUT`/`PATCH`/`DELETE`)
|
|
63
|
+
never auto-exposes to MCP — it needs an explicit `clients: { mcp: true }`.
|
|
64
|
+
Consume the RPC four ways: `cache(getMessages)({ channel })` in-process during
|
|
65
|
+
SSR, the swapped `fetch` proxy in the browser, `getMessages.raw(args)` for the
|
|
66
|
+
underlying `Response`, and `getMessages.stream(args)` for a frame iterable.
|
|
51
67
|
|
|
52
|
-
> Query args travel as strings —
|
|
68
|
+
> Query args travel as strings — validate with `z.coerce.*`. A per-RPC
|
|
69
|
+
> `timeout` (504 on every surface) is distinct from the client-side
|
|
70
|
+
> `ABIDE_CLIENT_TIMEOUT`.
|
|
53
71
|
|
|
54
72
|
## Sockets
|
|
55
73
|
|
|
56
|
-
A socket is one broadcast topic per file under `src/server/sockets/`. A
|
|
74
|
+
A socket is one broadcast topic per file under `src/server/sockets/`. A
|
|
75
|
+
`Socket<T>` is an isomorphic `AsyncIterable<T>` — `for await (const m of chat)`
|
|
76
|
+
is the live stream — and every socket multiplexes onto one WebSocket at
|
|
77
|
+
`/__abide/sockets`.
|
|
57
78
|
|
|
58
79
|
```ts
|
|
59
80
|
// src/server/sockets/chat.ts
|
|
60
81
|
import { socket } from '@abide/abide/server/socket'
|
|
61
82
|
import { z } from 'zod'
|
|
62
83
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
84
|
+
export const chat = socket({
|
|
85
|
+
schema: z.object({ id: z.string(), author: z.string(), text: z.string() }),
|
|
86
|
+
tail: 50, // retain the last 50 frames for replay
|
|
87
|
+
ttl: 60_000, // evict retained frames older than 60s
|
|
88
|
+
})
|
|
68
89
|
```
|
|
69
90
|
|
|
70
|
-
Each socket also has an HTTP face at `/__abide/sockets/<name>`: `GET` returns the
|
|
91
|
+
Each socket also has an HTTP face at `/__abide/sockets/<name>`: `GET` returns the
|
|
92
|
+
retained tail, `POST` publishes a frame (gated by `clientPublish`).
|
|
71
93
|
|
|
72
94
|
## Components
|
|
73
95
|
|
|
74
|
-
A
|
|
96
|
+
A `.abide` component renders on the server and hydrates in the browser. The page
|
|
97
|
+
below imports the RPC and the socket above and exercises the whole template
|
|
98
|
+
grammar. Reactive state is reached through `scope()` — the documented default is
|
|
99
|
+
to destructure it once at the top of the `<script>` and call the primitives bare.
|
|
75
100
|
|
|
76
101
|
```html
|
|
77
102
|
<script>
|
|
78
|
-
import { cache } from '@abide/abide/shared/cache'
|
|
79
|
-
import { tail } from '@abide/abide/ui/tail'
|
|
80
|
-
import {
|
|
81
|
-
import {
|
|
82
|
-
import {
|
|
83
|
-
import
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
import { cache } from '@abide/abide/shared/cache'
|
|
104
|
+
import { tail } from '@abide/abide/ui/tail'
|
|
105
|
+
import { html } from '@abide/abide/ui/html'
|
|
106
|
+
import { getMessages } from '$server/rpc/getMessages'
|
|
107
|
+
import { sendMessage } from '$server/rpc/sendMessage'
|
|
108
|
+
import { chat } from '$server/sockets/chat'
|
|
109
|
+
import Card from '$ui/Card.abide'
|
|
110
|
+
import Message from '$ui/Message.abide'
|
|
111
|
+
import Risky from '$ui/Risky.abide'
|
|
112
|
+
|
|
113
|
+
// props() is the ambient prop reader — no import; destructure with defaults + rest
|
|
114
|
+
const { channel = 'general', ...rest } = props()
|
|
115
|
+
|
|
116
|
+
// destructure-once: reach every reactive primitive through scope(), then call bare
|
|
117
|
+
const { state, computed, linked, effect } = scope()
|
|
118
|
+
|
|
119
|
+
let draft = state('')
|
|
120
|
+
let count = state(0)
|
|
121
|
+
let muted = state(false)
|
|
122
|
+
let topic = state('all')
|
|
123
|
+
const doubled = computed(() => count * 2)
|
|
124
|
+
const banner = linked(() => `# ${channel}`)
|
|
125
|
+
|
|
126
|
+
// live reads off the §3 socket: latest frame, plus a window of the last 20
|
|
127
|
+
const latest = tail(chat)
|
|
128
|
+
const recent = tail(chat, { last: 20 })
|
|
129
|
+
|
|
130
|
+
// effect runs client-only (stripped from SSR)
|
|
131
|
+
effect(() => {
|
|
132
|
+
document.title = `${channel} (${count})`
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// an event handler calling a mutating RPC
|
|
136
|
+
async function send() {
|
|
137
|
+
await sendMessage({ channel, text: draft })
|
|
96
138
|
draft = ''
|
|
97
|
-
|
|
98
|
-
|
|
139
|
+
count = count + 1
|
|
140
|
+
}
|
|
99
141
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
142
|
+
// the derived two-way binding's accessors
|
|
143
|
+
const get = () => count
|
|
144
|
+
const set = (value) => (count = Number(value))
|
|
103
145
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
<button disabled={!ready()}>Send</button>
|
|
108
|
-
</form>
|
|
109
|
-
|
|
110
|
-
{#if live()}<p class="muted">latest: {live().text}</p>{/if}
|
|
146
|
+
// an attachment: runs against the element at mount
|
|
147
|
+
const focus = (node) => node.focus()
|
|
148
|
+
</script>
|
|
111
149
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
{
|
|
150
|
+
<main {...rest}>
|
|
151
|
+
<h1 class:muted={muted} style:opacity={muted ? 0.5 : 1}>{banner}</h1>
|
|
152
|
+
<p>seen {count} — doubled {doubled}</p>
|
|
153
|
+
<p>{html`<em>latest:</em> ${latest?.text ?? '—'}`}</p>
|
|
154
|
+
|
|
155
|
+
<form onsubmit={send}>
|
|
156
|
+
<input bind:value={draft} attach={focus} placeholder="message" />
|
|
157
|
+
<label><input type="checkbox" bind:checked={muted} /> mute</label>
|
|
158
|
+
<label><input type="radio" bind:group={topic} value="all" /> all</label>
|
|
159
|
+
<label><input type="radio" bind:group={topic} value="mine" /> mine</label>
|
|
160
|
+
<input type="range" min="0" max="50" bind:value={{ get, set }} />
|
|
161
|
+
<button>send</button>
|
|
162
|
+
</form>
|
|
163
|
+
|
|
164
|
+
{#snippet row(message)}
|
|
165
|
+
<li>{html`<strong>${message.author}</strong>`}: {message.text}</li>
|
|
166
|
+
{/snippet}
|
|
167
|
+
|
|
168
|
+
{#if recent.length === 0}
|
|
169
|
+
<p>No messages yet.</p>
|
|
170
|
+
{:else if muted}
|
|
171
|
+
<p>Muted — {recent.length} hidden.</p>
|
|
172
|
+
<script>
|
|
173
|
+
// a nested script scoped to this branch — its own scope(), no imports
|
|
174
|
+
const { computed } = scope()
|
|
175
|
+
const note = computed(() => `${recent.length} while muted`)
|
|
176
|
+
</script>
|
|
177
|
+
<small>{note}</small>
|
|
178
|
+
<style>
|
|
179
|
+
small { color: gray; }
|
|
180
|
+
</style>
|
|
181
|
+
{:else}
|
|
115
182
|
<ul>
|
|
116
|
-
|
|
183
|
+
{#for message, i of recent by message.id}
|
|
184
|
+
<Card title={`#${i}`}>{row(message)}</Card>
|
|
185
|
+
{/for}
|
|
117
186
|
</ul>
|
|
118
|
-
{
|
|
119
|
-
|
|
120
|
-
|
|
187
|
+
{/if}
|
|
188
|
+
|
|
189
|
+
<h2>filter</h2>
|
|
190
|
+
{#switch topic}
|
|
191
|
+
{:case 'all'}<p>showing everything</p>
|
|
192
|
+
{:case 'mine'}<p>showing mine</p>
|
|
193
|
+
{:default}<p>unknown filter</p>
|
|
194
|
+
{/switch}
|
|
195
|
+
|
|
196
|
+
<h2>history</h2>
|
|
197
|
+
{#await cache(getMessages)({ channel })}
|
|
198
|
+
<p>loading…</p>
|
|
199
|
+
{:then list}
|
|
200
|
+
<ul>
|
|
201
|
+
{#for entry of list by entry.id}
|
|
202
|
+
<Message {...entry} />
|
|
203
|
+
{/for}
|
|
204
|
+
</ul>
|
|
205
|
+
{:catch error}
|
|
206
|
+
<p>failed: {error.message}</p>
|
|
207
|
+
{:finally}
|
|
208
|
+
<hr />
|
|
209
|
+
{/await}
|
|
210
|
+
|
|
211
|
+
<h2>live</h2>
|
|
212
|
+
<ul>
|
|
213
|
+
{#for await frame of chat}
|
|
214
|
+
<li>{frame.text}</li>
|
|
215
|
+
{/for}
|
|
216
|
+
</ul>
|
|
217
|
+
|
|
218
|
+
{#try}
|
|
219
|
+
<Risky />
|
|
220
|
+
{:catch error}
|
|
221
|
+
<p>widget crashed: {error.message}</p>
|
|
222
|
+
{:finally}
|
|
223
|
+
<span>boundary settled</span>
|
|
224
|
+
{/try}
|
|
225
|
+
</main>
|
|
226
|
+
|
|
227
|
+
<style>
|
|
228
|
+
main { font-family: system-ui; }
|
|
229
|
+
.muted { text-decoration: line-through; }
|
|
230
|
+
</style>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
A capitalised tag is a child component; the content nested inside it renders
|
|
234
|
+
where the child calls `{children()}` (the `<slot>` element was removed — there
|
|
235
|
+
are no named slots). `{#if children}…{:else}…{/if}` is the fallback form:
|
|
236
|
+
|
|
237
|
+
```html
|
|
238
|
+
<script>
|
|
239
|
+
const { title = 'Card' } = props()
|
|
240
|
+
</script>
|
|
241
|
+
|
|
242
|
+
<section class="card">
|
|
243
|
+
<h3>{title}</h3>
|
|
244
|
+
{#if children}{children()}{:else}<p>empty</p>{/if}
|
|
245
|
+
</section>
|
|
121
246
|
|
|
122
247
|
<style>
|
|
123
|
-
|
|
124
|
-
.error { color: #b91c1c; }
|
|
248
|
+
.card { border: 1px solid #ddd; }
|
|
125
249
|
</style>
|
|
126
250
|
```
|
|
127
251
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abide/abide",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Isomorphic multimodal HTTP framework built for humans and machines in a single Bun runtime",
|
|
@@ -63,7 +63,6 @@
|
|
|
63
63
|
"./shared/refreshing": "./src/lib/shared/refreshing.ts",
|
|
64
64
|
"./shared/HttpError": "./src/lib/shared/HttpError.ts",
|
|
65
65
|
"./shared/ValidationErrorData": "./src/lib/shared/types/ValidationErrorData.ts",
|
|
66
|
-
"./shared/html": "./src/lib/shared/html.ts",
|
|
67
66
|
"./shared/snippet": "./src/lib/shared/snippet.ts",
|
|
68
67
|
"./shared/withJsonSchema": "./src/lib/shared/withJsonSchema.ts",
|
|
69
68
|
"./shared/health": "./src/lib/shared/health.ts",
|
|
@@ -73,6 +72,7 @@
|
|
|
73
72
|
"./shared/trace": "./src/lib/shared/trace.ts",
|
|
74
73
|
"./shared/url": "./src/lib/shared/url.ts",
|
|
75
74
|
"./shared/createSubscriber": "./src/lib/shared/createSubscriber.ts",
|
|
75
|
+
"./ui/html": "./src/lib/ui/html.ts",
|
|
76
76
|
"./ui/effect": "./src/lib/ui/effect.ts",
|
|
77
77
|
"./ui/scope": "./src/lib/ui/scope.ts",
|
|
78
78
|
"./ui/enterScope": "./src/lib/ui/enterScope.ts",
|
package/src/abideLsp.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
} from './lib/ui/compile/createShadowLanguageService.ts'
|
|
8
8
|
import { createShadowLanguageService } from './lib/ui/compile/createShadowLanguageService.ts'
|
|
9
9
|
import { encodeSemanticTokens } from './lib/ui/compile/encodeSemanticTokens.ts'
|
|
10
|
+
import { markupTokens } from './lib/ui/compile/markupTokens.ts'
|
|
10
11
|
import { nearestProjectRoot } from './lib/ui/compile/nearestProjectRoot.ts'
|
|
11
12
|
import { offsetToPosition } from './lib/ui/compile/offsetToPosition.ts'
|
|
12
13
|
import { structuralBlockTokens } from './lib/ui/compile/structuralBlockTokens.ts'
|
|
@@ -24,10 +25,12 @@ nearest tsconfig, so files in a monorepo opened at its root are checked against
|
|
|
24
25
|
their own project — matching `abide check` run from that package.
|
|
25
26
|
*/
|
|
26
27
|
/*
|
|
27
|
-
The semantic-tokens `data` array for one component: the
|
|
28
|
-
merged with the shadow's type-aware expression
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
The semantic-tokens `data` array for one component: the HTML markup structure and
|
|
29
|
+
the structural `{#…}` framing merged with the shadow's type-aware expression
|
|
30
|
+
tokens, encoded to the LSP wire format. The markup tokens make the LSP own the
|
|
31
|
+
element/attribute coloring too, so a tree-sitter parse desynced by an `attr={expr}`
|
|
32
|
+
value can't bleed miscoloring below it. Never throws — on any internal failure it
|
|
33
|
+
yields an empty stream so the editor falls back to tree-sitter highlighting.
|
|
31
34
|
*/
|
|
32
35
|
export function componentSemanticTokens(
|
|
33
36
|
service: ShadowLanguageService,
|
|
@@ -36,6 +39,7 @@ export function componentSemanticTokens(
|
|
|
36
39
|
): number[] {
|
|
37
40
|
try {
|
|
38
41
|
const tokens = [
|
|
42
|
+
...markupTokens(text),
|
|
39
43
|
...structuralBlockTokens(text),
|
|
40
44
|
...service.semanticClassifications(abidePath),
|
|
41
45
|
]
|
|
@@ -84,12 +84,22 @@ Bun plugin that wires every virtual import abide produces at build time:
|
|
|
84
84
|
- `abide:rpc` — { rpcUrl: () => import(rpc-module) } HTTP-method manifest
|
|
85
85
|
- `abide:sockets` — { socketName: () => import(socket-module) } socket manifest
|
|
86
86
|
- `abide:pages` — { pageUrl: () => import(page.abide) } manifest
|
|
87
|
+
- `abide:layouts` — { layoutUrl: () => import(layout.abide) } layout manifest
|
|
87
88
|
- `abide:prompts` — { promptName: () => import(prompt-module) } manifest
|
|
88
|
-
- `abide:app` — { init?, handle?, handleError? } from src/app.ts
|
|
89
|
+
- `abide:app` — { init?, handle?, handleError?, health?, forwardHeaders? } from src/app.ts
|
|
90
|
+
- `abide:config` — re-exports src/server/config.ts for boot-time env validation
|
|
89
91
|
- `abide:assets` — gzip-compressed chunk bytes embedded for standalone compile
|
|
90
92
|
- `abide:public-assets` — gzip-embedded src/ui/public files
|
|
91
93
|
- `abide:mcp-resources` — gzip-embedded src/mcp/resources files
|
|
94
|
+
- `abide:mcp` — generated MCP server (createMcpServer)
|
|
92
95
|
- `abide:shell` — app.html content (custom or default)
|
|
96
|
+
- `abide:app-info` — { name, version } from package.json for OpenAPI info
|
|
97
|
+
- `abide:cli-manifest` — baked per-rpc manifest for the CLI binary
|
|
98
|
+
- `abide:cli-name` — program name from package.json
|
|
99
|
+
- `abide:cli-chrome` — banner/footer text from src/cli/
|
|
100
|
+
- `abide:bundle-window` — optional bundle window config
|
|
101
|
+
- `abide:bundle-disconnected` — baked connect-screen HTML
|
|
102
|
+
- `abide:bundle-disconnected-component` — connect-screen abide-ui component
|
|
93
103
|
|
|
94
104
|
Also rewrites modules under src/server/rpc and src/server/sockets:
|
|
95
105
|
- src/server/rpc/<file>.ts: each HTTP-method export is bound to a runtime
|
package/src/build.ts
CHANGED
|
@@ -40,12 +40,14 @@ export async function build({
|
|
|
40
40
|
compress = true,
|
|
41
41
|
clean = true,
|
|
42
42
|
exitOnFailure = true,
|
|
43
|
+
dev = false,
|
|
43
44
|
}: {
|
|
44
45
|
cwd?: string
|
|
45
46
|
minify?: boolean
|
|
46
47
|
compress?: boolean
|
|
47
48
|
clean?: boolean
|
|
48
49
|
exitOnFailure?: boolean
|
|
50
|
+
dev?: boolean
|
|
49
51
|
} = {}): Promise<boolean> {
|
|
50
52
|
const distDir = `${cwd}/dist`
|
|
51
53
|
const outDir = `${distDir}/_app`
|
|
@@ -84,6 +86,13 @@ export async function build({
|
|
|
84
86
|
chunk: '[name]-[hash].[ext]',
|
|
85
87
|
asset: '[name].[ext]',
|
|
86
88
|
},
|
|
89
|
+
/* Build-time flag the client reads to fold away dev-only machinery: production
|
|
90
|
+
(`dev: false`) defines it false so the hot-reload subtree — mountChild's
|
|
91
|
+
record path, hotReplace, captureModelDoc — dead-code-eliminates instead of
|
|
92
|
+
shipping behind a runtime flag the minifier can't prove. Dev defines it true
|
|
93
|
+
to keep HMR. Under `bun test` no define applies; the source falls back to true
|
|
94
|
+
so `hotReloadEnabled` alone governs (see startClient/mountChild). */
|
|
95
|
+
define: { __ABIDE_DEV__: dev ? 'true' : 'false' },
|
|
87
96
|
plugins,
|
|
88
97
|
})
|
|
89
98
|
|
package/src/buildDisconnected.ts
CHANGED
|
@@ -51,6 +51,8 @@ export async function buildDisconnected({
|
|
|
51
51
|
entrypoints: [ENTRY, CSS_ENTRY],
|
|
52
52
|
target: 'browser',
|
|
53
53
|
minify: true,
|
|
54
|
+
// Connect screen ships in production bundles only — fold dev-only machinery out.
|
|
55
|
+
define: { __ABIDE_DEV__: 'false' },
|
|
54
56
|
plugins,
|
|
55
57
|
})
|
|
56
58
|
exitOnBuildFailure(result)
|
package/src/devEntry.ts
CHANGED
|
@@ -10,7 +10,7 @@ Confirms a URL points at a abide server before the launcher navigates the app
|
|
|
10
10
|
window there, by fetching its unauthenticated health endpoint. Returns the
|
|
11
11
|
server's identity on success, or undefined when nothing abide answers — a network
|
|
12
12
|
error, the wrong port, or a non-abide page (a bare 403/404, a different app, a
|
|
13
|
-
captive portal's 200 — hence the `abide: true` body check, never response.ok
|
|
13
|
+
captive portal's 200 — hence the `abide: true` (or version string) body check, never response.ok
|
|
14
14
|
alone). The endpoint bypasses the app's own middleware, so an auth-guarded abide
|
|
15
15
|
app still verifies here even though its pages would later redirect to a login.
|
|
16
16
|
Probes HEALTH_PATH first, falling back to the IDENTITY_PATH alias so a newer
|
|
@@ -9,8 +9,10 @@ on the manifest entry (when present) drives flag typing:
|
|
|
9
9
|
|
|
10
10
|
For complex shapes (nested objects, unions, anyOf) the CLI exposes
|
|
11
11
|
`--json <stringified-args>` as an escape hatch that supplies the whole
|
|
12
|
-
args bag verbatim. Stdin: if a JSON object arrives piped in, it
|
|
13
|
-
as the full args bag
|
|
12
|
+
args bag verbatim. Stdin: if a JSON object arrives piped in with no argv flags, it is used
|
|
13
|
+
as the full args bag. Stdin and flags are mutually exclusive — stdin is
|
|
14
|
+
skipped when argv is non-empty to avoid hanging on a pipe that never
|
|
15
|
+
sends EOF.
|
|
14
16
|
|
|
15
17
|
Unrecognised flags throw — early loud feedback is more useful than
|
|
16
18
|
silent drops.
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { CliManifestEntry } from './CliManifestEntry.ts'
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
|
-
Map from
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
Map from command name (URL-derived via commandNameForUrl, e.g. "getReport"
|
|
5
|
+
or "users-list") to its manifest entry. Built by the bundler from
|
|
6
|
+
rpcRegistry and socketRegistry; entries are emitted for rpcs and sockets
|
|
7
|
+
with `clients.cli: true`. Sockets produce `<base>-tail` (and `-publish`
|
|
8
|
+
when `allowClientPublish` is set). The CLI binary and any programmatic
|
|
9
|
+
createClient caller read this to dispatch calls.
|
|
8
10
|
*/
|
|
9
11
|
export type CliManifest = Record<string, CliManifestEntry>
|
|
@@ -2,7 +2,7 @@ import type { HttpMethod } from '../shared/types/HttpMethod.ts'
|
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
4
|
Maps an HTTP method to MCP tool annotations so a model can tell a read from
|
|
5
|
-
a write before calling. Abide derives these from the
|
|
5
|
+
a write before calling. Abide derives these from the HTTP method the RPC was
|
|
6
6
|
declared with rather than asking the author to repeat the intent:
|
|
7
7
|
- GET / HEAD → read-only, non-destructive
|
|
8
8
|
- POST → creates; not idempotent, not (necessarily) destructive
|
|
@@ -15,7 +15,7 @@ function asText(value: unknown): string {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/*
|
|
18
|
-
Turns an
|
|
18
|
+
Turns an RPC Response into an MCP `tools/call` result. Always
|
|
19
19
|
carries a `text` content block for backward compatibility; adds
|
|
20
20
|
`structuredContent` (an object, per the MCP spec) so models that
|
|
21
21
|
understand structured output get the typed value instead of a stringified
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
2
|
JSON-RPC 2.0 request frame as MCP delivers it over Streamable HTTP. The
|
|
3
|
-
`id` is absent for notifications
|
|
4
|
-
|
|
5
|
-
"resources/read".
|
|
3
|
+
`id` is absent for notifications; they are dispatched for their side effect
|
|
4
|
+
and acknowledged with a 202 (JSON-RPC forbids replying with an envelope).
|
|
5
|
+
`method` is a string like "tools/list" or "resources/read".
|
|
6
6
|
*/
|
|
7
7
|
export type JsonRpcRequest = {
|
|
8
8
|
jsonrpc: '2.0'
|
|
@@ -10,7 +10,7 @@ WebSockets are not exposed here — abide's only native WebSocket
|
|
|
10
10
|
surface is the sockets hub (see `abide/server/socket`), multiplexed onto a
|
|
11
11
|
single framework-owned connection per client at `/__abide/sockets`.
|
|
12
12
|
Inside request scopes, the live Bun.Server is reachable via the
|
|
13
|
-
exported `server()` function from `abide/server`; `init` receives it
|
|
13
|
+
exported `server()` function from `abide/server/server`; `init` receives it
|
|
14
14
|
explicitly because it runs outside a request.
|
|
15
15
|
*/
|
|
16
16
|
// @documentation plumbing
|
|
@@ -92,12 +92,14 @@ async function computeBinary(
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
/*
|
|
95
|
-
Handles GET /__abide/cli/<platform> — streams a gzipped tarball
|
|
96
|
-
|
|
97
|
-
ABIDE_APP_URL (and ABIDE_APP_TOKEN if the inbound request was
|
|
95
|
+
Handles GET /__abide/cli/<platform> — streams a gzipped tarball containing
|
|
96
|
+
the platform-specific thin binary, the sibling server binary, and a `.env`
|
|
97
|
+
carrying ABIDE_APP_URL (and ABIDE_APP_TOKEN if the inbound request was
|
|
98
|
+
authenticated).
|
|
98
99
|
|
|
99
|
-
Thin binaries live at `dist/cli-thin/<platform>/<programName>`
|
|
100
|
-
|
|
100
|
+
Thin binaries live at `dist/cli-thin/<platform>/<programName>` (produced
|
|
101
|
+
lazily by `buildCli` on first request). The `.env` baking `ABIDE_APP_URL`
|
|
102
|
+
is generated at download time, not build time. Missing platforms produce
|
|
101
103
|
404 — the install script reports it, doesn't try to fall back.
|
|
102
104
|
*/
|
|
103
105
|
export async function handleCliDownload(
|
|
@@ -7,9 +7,9 @@ platform-specific tarball and extracts it into `$ABIDE_INSTALL_DIR`
|
|
|
7
7
|
(default `~/.local/bin`). The tarball already contains the `.env` next
|
|
8
8
|
to the binary — no separate config write step in the script.
|
|
9
9
|
|
|
10
|
-
The script is rendered server-side so
|
|
11
|
-
|
|
12
|
-
basic shell hygiene.
|
|
10
|
+
The script is rendered server-side so the request origin is baked into the
|
|
11
|
+
`URL` variable at generation time and the embedded curl URL needs no escaping
|
|
12
|
+
or quoting beyond basic shell hygiene.
|
|
13
13
|
*/
|
|
14
14
|
export function installScript(appUrl: string, programName: string): string {
|
|
15
15
|
return `#!/usr/bin/env sh
|