@abide/abide 0.41.1 → 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.
Files changed (167) hide show
  1. package/AGENTS.md +234 -294
  2. package/CHANGELOG.md +82 -0
  3. package/README.md +51 -95
  4. package/package.json +3 -2
  5. package/src/abideLsp.ts +46 -8
  6. package/src/abideResolverPlugin.ts +107 -19
  7. package/src/buildCli.ts +1 -1
  8. package/src/discoveryEntry.ts +3 -3
  9. package/src/lib/bundle/BundleMenuItem.ts +1 -1
  10. package/src/lib/cli/createClient.ts +12 -12
  11. package/src/lib/cli/dispatchCommand.ts +1 -1
  12. package/src/lib/cli/printSessionStatus.ts +1 -1
  13. package/src/lib/cli/resolveCliTarget.ts +1 -1
  14. package/src/lib/cli/runCli.ts +1 -1
  15. package/src/lib/cli/types/CliManifest.ts +1 -1
  16. package/src/lib/cli/types/CliManifestEntry.ts +2 -2
  17. package/src/lib/mcp/annotationsForMethod.ts +5 -5
  18. package/src/lib/mcp/createMcpServer.ts +3 -3
  19. package/src/lib/mcp/mcpSurface.ts +14 -14
  20. package/src/lib/mcp/types/McpServerOptions.ts +1 -1
  21. package/src/lib/server/DELETE.ts +4 -4
  22. package/src/lib/server/GET.ts +4 -4
  23. package/src/lib/server/HEAD.ts +4 -4
  24. package/src/lib/server/PATCH.ts +4 -4
  25. package/src/lib/server/POST.ts +4 -4
  26. package/src/lib/server/PUT.ts +4 -4
  27. package/src/lib/server/agent.ts +4 -4
  28. package/src/lib/server/env.ts +1 -1
  29. package/src/lib/server/error.ts +49 -7
  30. package/src/lib/server/json.ts +1 -1
  31. package/src/lib/server/rpc/buildErrorConstructors.ts +19 -0
  32. package/src/lib/server/rpc/{defineVerb.ts → defineRpc.ts} +52 -34
  33. package/src/lib/server/rpc/{dispatchVerbInProcess.ts → dispatchRpcInProcess.ts} +3 -3
  34. package/src/lib/server/rpc/fieldErrorsFromIssues.ts +23 -0
  35. package/src/lib/server/rpc/{findVerbByCommandName.ts → findRpcByCommandName.ts} +5 -5
  36. package/src/lib/server/rpc/parseArgs.ts +6 -6
  37. package/src/lib/server/rpc/readBodyWithinLimit.ts +2 -2
  38. package/src/lib/server/rpc/registerRpc.ts +6 -0
  39. package/src/lib/server/rpc/{verbRegistry.ts → rpcRegistry.ts} +4 -4
  40. package/src/lib/server/rpc/{runWithVerbTimeout.ts → runWithRpcTimeout.ts} +4 -4
  41. package/src/lib/server/rpc/types/RemoteHandler.ts +9 -3
  42. package/src/lib/server/rpc/types/{VerbHelper.ts → RpcHelper.ts} +57 -23
  43. package/src/lib/server/rpc/types/{VerbRegistryEntry.ts → RpcRegistryEntry.ts} +3 -3
  44. package/src/lib/server/rpc/types/TypedResponse.ts +2 -2
  45. package/src/lib/server/rpc/unprocessed.ts +6 -7
  46. package/src/lib/server/rpc/validationError.ts +17 -0
  47. package/src/lib/server/runtime/buildInspectorSurface.ts +7 -7
  48. package/src/lib/server/runtime/buildOpenApiSpec.ts +6 -6
  49. package/src/lib/server/runtime/createRouteDispatcher.ts +7 -7
  50. package/src/lib/server/runtime/createServer.ts +4 -4
  51. package/src/lib/server/runtime/crossOriginForbidden.ts +1 -1
  52. package/src/lib/server/runtime/crossOriginGate.ts +4 -4
  53. package/src/lib/server/runtime/devClientFingerprint.ts +2 -1
  54. package/src/lib/server/runtime/logExposedSurfaces.ts +4 -4
  55. package/src/lib/server/runtime/registryManifests.ts +2 -2
  56. package/src/lib/server/runtime/types/InspectorCacheEntry.ts +1 -1
  57. package/src/lib/server/runtime/types/InspectorRpc.ts +27 -0
  58. package/src/lib/server/runtime/types/InspectorSurface.ts +4 -4
  59. package/src/lib/server/runtime/types/RequestStore.ts +1 -1
  60. package/src/lib/server/runtime/warnUnguardedMcp.ts +2 -2
  61. package/src/lib/server/sockets/createSocketDispatcher.ts +15 -14
  62. package/src/lib/server/sockets/types/SocketOperation.ts +2 -2
  63. package/src/lib/shared/HttpError.ts +15 -1
  64. package/src/lib/shared/UNREACHABLE_STATUSES.ts +13 -0
  65. package/src/lib/shared/buildRpcRequest.ts +5 -5
  66. package/src/lib/shared/cache.ts +50 -168
  67. package/src/lib/shared/carriesBodyArgs.ts +4 -4
  68. package/src/lib/shared/createCacheStore.ts +12 -0
  69. package/src/lib/shared/createRemoteFunction.ts +11 -6
  70. package/src/lib/shared/decodeResponse.ts +2 -2
  71. package/src/lib/shared/detectRpcMethod.ts +17 -0
  72. package/src/lib/shared/emitLogRecord.ts +3 -3
  73. package/src/lib/shared/escapeRegex.ts +9 -0
  74. package/src/lib/shared/extraForwardHeaders.ts +1 -1
  75. package/src/lib/shared/fileName.ts +9 -0
  76. package/src/lib/shared/fileStem.ts +3 -1
  77. package/src/lib/shared/findExportCallSite.ts +30 -273
  78. package/src/lib/shared/forwardHeaders.ts +2 -2
  79. package/src/lib/shared/httpErrorFor.ts +26 -0
  80. package/src/lib/shared/isAsciiWhitespace.ts +5 -0
  81. package/src/lib/shared/isIdentPart.ts +9 -0
  82. package/src/lib/shared/isIdentStart.ts +8 -0
  83. package/src/lib/shared/isReadOnlyMethod.ts +4 -4
  84. package/src/lib/shared/keyForRemoteCall.ts +4 -4
  85. package/src/lib/shared/log.ts +1 -1
  86. package/src/lib/shared/outboxProbeSlot.ts +20 -0
  87. package/src/lib/shared/pending.ts +4 -1
  88. package/src/lib/shared/prepareRpcModule.ts +96 -14
  89. package/src/lib/shared/probeRegistries.ts +17 -4
  90. package/src/lib/shared/programNameForPackage.ts +3 -1
  91. package/src/lib/shared/queryStringFromArgs.ts +1 -1
  92. package/src/lib/shared/remoteMetaStore.ts +2 -2
  93. package/src/lib/shared/resolveClientFlags.ts +1 -1
  94. package/src/lib/shared/skipNonCode.ts +230 -0
  95. package/src/lib/shared/streamResponse.ts +9 -6
  96. package/src/lib/shared/stripImport.ts +6 -4
  97. package/src/lib/shared/types/CacheEntry.ts +2 -4
  98. package/src/lib/shared/types/CacheOnContext.ts +1 -11
  99. package/src/lib/shared/types/CacheStore.ts +13 -7
  100. package/src/lib/shared/types/ClientFlags.ts +1 -1
  101. package/src/lib/shared/types/ErrorConstructors.ts +17 -0
  102. package/src/lib/shared/types/ErrorDescriptor.ts +10 -0
  103. package/src/lib/shared/types/ErrorSpec.ts +11 -0
  104. package/src/lib/shared/types/HttpMethod.ts +1 -0
  105. package/src/lib/shared/types/Outbox.ts +9 -0
  106. package/src/lib/shared/types/OutboxEntry.ts +27 -0
  107. package/src/lib/shared/types/RawRemoteFunction.ts +2 -2
  108. package/src/lib/shared/types/RemoteCallable.ts +2 -2
  109. package/src/lib/shared/types/RemoteFunction.ts +21 -6
  110. package/src/lib/shared/types/RequestScopeInfo.ts +1 -1
  111. package/src/lib/shared/types/RpcErrorGuard.ts +40 -0
  112. package/src/lib/shared/types/RpcInvoker.ts +1 -1
  113. package/src/lib/shared/types/StandardSchemaV1.ts +1 -1
  114. package/src/lib/shared/types/ValidationErrorData.ts +20 -0
  115. package/src/lib/shared/url.ts +3 -3
  116. package/src/lib/shared/writeRpcDts.ts +7 -7
  117. package/src/lib/shared/writeTestRpcDts.ts +3 -3
  118. package/src/lib/test/createTestApp.ts +10 -10
  119. package/src/lib/ui/compile/ABIDE_SEMANTIC_TOKENS_LEGEND.ts +45 -0
  120. package/src/lib/ui/compile/abideUiPlugin.ts +2 -1
  121. package/src/lib/ui/compile/awaitPlan.ts +48 -0
  122. package/src/lib/ui/compile/compileShadow.ts +117 -31
  123. package/src/lib/ui/compile/createShadowLanguageService.ts +48 -0
  124. package/src/lib/ui/compile/desugarSignals.ts +42 -6
  125. package/src/lib/ui/compile/encodeSemanticTokens.ts +37 -0
  126. package/src/lib/ui/compile/generateBuild.ts +45 -62
  127. package/src/lib/ui/compile/generateSSR.ts +90 -60
  128. package/src/lib/ui/compile/ifPlan.ts +30 -0
  129. package/src/lib/ui/compile/makeVarNamer.ts +10 -0
  130. package/src/lib/ui/compile/offsetToPosition.ts +9 -0
  131. package/src/lib/ui/compile/parseTemplate.ts +565 -115
  132. package/src/lib/ui/compile/stripEffects.ts +17 -9
  133. package/src/lib/ui/compile/structuralBlockTokens.ts +101 -0
  134. package/src/lib/ui/compile/switchPlan.ts +22 -0
  135. package/src/lib/ui/compile/tryPlan.ts +29 -0
  136. package/src/lib/ui/compile/types/SemanticToken.ts +11 -0
  137. package/src/lib/ui/compile/types/TemplateAttr.ts +8 -2
  138. package/src/lib/ui/compile/types/TemplateNode.ts +15 -2
  139. package/src/lib/ui/createScope.ts +20 -2
  140. package/src/lib/ui/dom/appendText.ts +1 -5
  141. package/src/lib/ui/dom/applyResolved.ts +1 -5
  142. package/src/lib/ui/dom/disposeRange.ts +6 -10
  143. package/src/lib/ui/dom/hydrate.ts +2 -5
  144. package/src/lib/ui/dom/isComment.ts +6 -0
  145. package/src/lib/ui/dom/mount.ts +1 -2
  146. package/src/lib/ui/dom/withScope.ts +6 -9
  147. package/src/lib/ui/effect.ts +4 -2
  148. package/src/lib/ui/navigate.ts +40 -13
  149. package/src/lib/ui/outbox.ts +30 -110
  150. package/src/lib/ui/remoteProxy.ts +160 -10
  151. package/src/lib/ui/router.ts +3 -3
  152. package/src/lib/ui/rpcOutbox/createOutboxQueue.ts +281 -0
  153. package/src/lib/ui/rpcOutbox/outboxRegistry.ts +69 -0
  154. package/src/lib/ui/runtime/createDoc.ts +3 -3
  155. package/src/lib/ui/runtime/pathSegments.ts +10 -0
  156. package/src/lib/ui/socketChannel.ts +7 -1
  157. package/src/lib/ui/types/Scope.ts +20 -5
  158. package/template/.zed/settings.json +4 -0
  159. package/template/CLAUDE.md +1 -1
  160. package/template/src/server/rpc/getHello.ts +3 -3
  161. package/template/src/ui/pages/page.abide +4 -4
  162. package/template/test/app.test.ts +2 -2
  163. package/src/lib/server/rpc/registerVerb.ts +0 -6
  164. package/src/lib/server/runtime/types/InspectorVerb.ts +0 -27
  165. package/src/lib/shared/detectVerbMethod.ts +0 -17
  166. package/src/lib/shared/types/HttpVerb.ts +0 -1
  167. package/src/lib/ui/types/Outbox.ts +0 -14
package/CHANGELOG.md CHANGED
@@ -1,5 +1,87 @@
1
1
  # abide
2
2
 
3
+ ## 0.43.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6453cf9: repurpose the bare outbox() export to the global reactive aggregate ([`003713d`](https://github.com/briancray/abide/commit/003713dab125b3df72d6cf832ec18ea546922c79))
8
+ - 6453cf9: typed navigate params, scope-destructured primitives, precise prop diagnostics ([`0769896`](https://github.com/briancray/abide/commit/07698966147e96970c27e0278e2152a23e48b219))
9
+ - 6453cf9: OutboxEntry type + status ([`08d9b03`](https://github.com/briancray/abide/commit/08d9b036501110ab24c18258cc79364f9ac71ea8))
10
+ - 6453cf9: migrate kitchen-sink to rpc-native outbox; AGENTS.md surface ([`1b8aa3f`](https://github.com/briancray/abide/commit/1b8aa3fe631181e7798d0703eb09a0f22dba0f88))
11
+ - 6453cf9: persist request body + content-type, replay on reload ([`26c309f`](https://github.com/briancray/abide/commit/26c309f20bf573e512b74477ba2319c22218f7d9))
12
+ - 6453cf9: client registry of durable rpc queues ([`2b89c20`](https://github.com/briancray/abide/commit/2b89c20b1f1f1794f90152f46958ee760333bab5))
13
+ - 6453cf9: reject server-only imports in the client bundle with an evidence chain ([`2de1730`](https://github.com/briancray/abide/commit/2de1730872898d320c240a89b570dfaa9acace7a))
14
+ - 6453cf9: name-keyed typed errors via a handler errors ctx ([`62f75a8`](https://github.com/briancray/abide/commit/62f75a8341d61ac9cfd1e7cbeccc66ddec991643))
15
+ - 6453cf9: createOutboxQueue enqueue + reactive/persisted entries ([`88560c9`](https://github.com/briancray/abide/commit/88560c942d0f28623a68ed1315bb2341ad66a9c3))
16
+ - 6453cf9: bundler threads outbox:true into the client proxy emission ([`b279960`](https://github.com/briancray/abide/commit/b27996089f4a3c8786fcd1ade530057a34f086fc))
17
+ - 6453cf9: pending() reflects the durable queue (in-flight or queued) ([`bfa505d`](https://github.com/briancray/abide/commit/bfa505d8d5326f0464be35568ac8ae6fc4bd1901))
18
+ - 6453cf9: class: and style: directives for surgical reactive class/style writes ([`c5ee6d1`](https://github.com/briancray/abide/commit/c5ee6d13faad82ac45c6c1627c6e9435c9c59c5f))
19
+ - 6453cf9: durable return type — outbox:true overload on mutating rpc helpers ([`d916c6b`](https://github.com/briancray/abide/commit/d916c6b5b563ddc4dee07a015cde08d32e6dd750))
20
+ - 6453cf9: outbox:true rpc option, gated to mutating methods ([`e37f2a3`](https://github.com/briancray/abide/commit/e37f2a333e201ef40303dd25bafb9f0ca82dd220))
21
+ - 6453cf9: drain loop — deliver/retry/error/cancel under the entry signal ([`ec32868`](https://github.com/briancray/abide/commit/ec32868eb860b6185f21c196b18f03c7b3605ba8))
22
+ - 6453cf9: durable client invoke path + rpc.outbox face ([`f96a0c0`](https://github.com/briancray/abide/commit/f96a0c025cfda5f6daf713f4d69857854b8f3459))
23
+
24
+ ### Patch Changes
25
+
26
+ - 6453cf9: notify() forEach callback must not return a value ([`1c7f20f`](https://github.com/briancray/abide/commit/1c7f20fa5b6a24f3a5e90ab20521f7d24ba55d57))
27
+ - 6453cf9: Breaking: rename defineVerb export to defineRpc ([`29fe778`](https://github.com/briancray/abide/commit/29fe7782844e0de15c53fad711d6616cc90a27e0))
28
+ - 6453cf9: rename VERB*\* constants to RPC*\* ([`391687a`](https://github.com/briancray/abide/commit/391687a252a33ba355ba929944cd1a2cef83c1ef))
29
+ - 6453cf9: rename verb-named rpc helpers to rpc ([`4ebdd8f`](https://github.com/briancray/abide/commit/4ebdd8ff862121a48a39fbdb7b2893a14fd52022))
30
+ - 6453cf9: rename verbRegistry to rpcRegistry ([`507adf5`](https://github.com/briancray/abide/commit/507adf5d5ae3a1b66ef85fc495ba1a974a530abf))
31
+ - 6453cf9: rename Verb-named types/helpers/files to Rpc ([`8342e96`](https://github.com/briancray/abide/commit/8342e963babbddcb9a87dcc99fc2e4958dbc5750))
32
+ - 6453cf9: refresh AGENTS surface map ({#…} blocks, scaffold flags, migration error) ([`88cc4d9`](https://github.com/briancray/abide/commit/88cc4d97205bd3de74a08a6dbae3f2221f0275fe))
33
+ - 6453cf9: commit working tree — outbox, rpc errors, compile plans, cache refactor ([`c673dc7`](https://github.com/briancray/abide/commit/c673dc71522e33ad4f9b48f41ac73fa6c4f03a02))
34
+ - 6453cf9: rename HttpVerb type to HttpMethod ([`d64a59a`](https://github.com/briancray/abide/commit/d64a59a045f77c627b98dbb1b3a12b545f3d3c60))
35
+ - 6453cf9: scrub verb from comments, AGENTS.md, and inspector surface (rpc/method) ([`d9356ce`](https://github.com/briancray/abide/commit/d9356ce9eeba6b03d43ef67fc500cf697e34d39c))
36
+
37
+ ## 0.42.0
38
+
39
+ ### Minor Changes
40
+
41
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - reject stray {:…}/{/…} tokens outside a block ([`1b5d54e`](https://github.com/briancray/abide/commit/1b5d54e7798acfa7c9b15ce6b65b0c2b6a8c2c07))
42
+
43
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - parse {#switch}/{:case}/{:default} blocks to the switch AST ([`448da38`](https://github.com/briancray/abide/commit/448da3840c120ac3b15d239c090f123c25527fec))
44
+
45
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - parse {#for … of … by …} blocks to the each AST ([`7bb2ac8`](https://github.com/briancray/abide/commit/7bb2ac8f3012e3d40cfcbe8ddf277d6a8732ee93))
46
+
47
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - LSP semantic-token encoder + extract offsetToPosition ([`7daeb92`](https://github.com/briancray/abide/commit/7daeb926f045058aa452b5f539ddd75b0d8efa67))
48
+
49
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - semantic-token legend + TS-classification mapping for abide lsp ([`892f97b`](https://github.com/briancray/abide/commit/892f97bbc6dfd8af9301297276995f7060fe3f9a))
50
+
51
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - type-aware semanticClassifications on the shadow language service ([`9377dd2`](https://github.com/briancray/abide/commit/9377dd24d855cde790d960fceef00255904ee926))
52
+
53
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - block control-flow grammar formatting + shared helpers ([`b39c0a7`](https://github.com/briancray/abide/commit/b39c0a70696b031b63ef157c67360c2da0fd60b0))
54
+
55
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - zed onboarding — auto-install extension + enable semantic tokens ([`b47acc7`](https://github.com/briancray/abide/commit/b47acc7cc106956f115c70b110c29ce017a71cd0))
56
+
57
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - parse {#if}/{:else if}/{:else} blocks to the if AST ([`b662397`](https://github.com/briancray/abide/commit/b66239765bae2ec7a24d70bc7b2edbcbe400614c))
58
+
59
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - parse {#try}/{:catch}/{:finally} blocks to the try AST ([`b82c3dd`](https://github.com/briancray/abide/commit/b82c3ddaaec3db3941639df952e568f017d6c767))
60
+
61
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - Breaking: remove <template> control-flow directives in favor of {#…} blocks ([`bf5cf89`](https://github.com/briancray/abide/commit/bf5cf89813a8dcbc967e1303bd2509e18e701761))
62
+
63
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - color of/by connectors in {#for} block heads ([`c958614`](https://github.com/briancray/abide/commit/c9586147f8196e9e6301b14cdb08986b36da2751))
64
+
65
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - parse {#await} streaming + blocking blocks to the await AST ([`cfd7ff0`](https://github.com/briancray/abide/commit/cfd7ff0102b2be2ac241a6c0b1965949aa6621bf))
66
+
67
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - serve textDocument/semanticTokens/full for .abide ([`e152663`](https://github.com/briancray/abide/commit/e152663dae9e60e13d16f0edf4b0a140a99b1bfb))
68
+
69
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - structural {#…} block framing tokenizer ([`e1e85e8`](https://github.com/briancray/abide/commit/e1e85e847e9442f8c6140df5346b1d37f8cfad54))
70
+
71
+ ### Patch Changes
72
+
73
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - point block-construct loc at its primary expression (shadow source-map fidelity) ([`0fb0efa`](https://github.com/briancray/abide/commit/0fb0efab43639331c856969fdb6a7b83bd7ab604))
74
+
75
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - unify block/branch child-scan loops behind a shared helper ([`4683098`](https://github.com/briancray/abide/commit/4683098df96edd0321dc66d200372e0fbedce2e2))
76
+
77
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - document {#…} control-flow blocks in the AGENTS surface map ([`68fe96f`](https://github.com/briancray/abide/commit/68fe96f3294a228b91eef5cde37c0300673eb88a))
78
+
79
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - map {#for}/{:then}/{:catch} bindings + by-key to source so hover & semantic tokens land on them ([`e8447e8`](https://github.com/briancray/abide/commit/e8447e8d54934737b80c2f49d4f4d1b134786531))
80
+
81
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - map <template args> snippet param + await/try {:catch} bindings (+ index/catch/snippet tests) ([`f724d10`](https://github.com/briancray/abide/commit/f724d101f5baed79de2d39a1ab9598eb9d1eb818))
82
+
83
+ - [`568956c`](https://github.com/briancray/abide/commit/568956c88ff1d32ca79a2aa8a1a0ffffeb25afe3) - satisfy noUncheckedIndexedAccess in block-token + shadow paths ([`fbb6e44`](https://github.com/briancray/abide/commit/fbb6e4443932e92277fb332b639c746663c7759b))
84
+
3
85
  ## 0.41.1
4
86
 
5
87
  ### Patch Changes
package/README.md CHANGED
@@ -1,171 +1,127 @@
1
1
  # abide
2
2
 
3
- **One typed declaration fans out to HTTP, a CLI, an MCP tool, and an
4
- OpenAPI spec — the bundler swaps the runtime per side.**
3
+ **One typed declaration fans out to an HTTP endpoint, a CLI subcommand, an MCP tool, and an OpenAPI operation — and the same callable runs on the server and in the browser.**
5
4
 
6
- abide is an isomorphic framework on Bun where you write a function once and
7
- it serves every consumer: a browser fetch, an in-process SSR call, a CLI
8
- subcommand, an MCP tool, an OpenAPI operation. The same callable keeps its
9
- name and behaviour on both sides — the bundler decides whether it runs the
10
- real handler or a network proxy. Built for humans _and_ machines.
5
+ abide is a type-safe isomorphic framework on Bun and web standards. You declare an RPC, a socket, or a `.abide` component once; the bundler swaps the runtime per side (in-process on the server, a typed `fetch` proxy in the browser) so the name, the call, and the behaviour are identical wherever you import it. Built for humans *and* the machines that now read and drive software.
11
6
 
12
- - One direct dependency (`typescript`); `tailwindcss` + `bun-plugin-tailwind`
13
- are optional peers. Single runtime: Bun ≥ 1.3.0.
7
+ - One direct dependency (TypeScript). Bun is the only runtime — no Node, no separate bundler, no dev server to wire up.
14
8
 
15
9
  ## Quick start
16
10
 
17
11
  ```sh
18
- bunx abide scaffold my-app # scaffolds, installs deps, and starts dev
12
+ bunx abide scaffold my-app # scaffolds the project, installs it, and starts dev
19
13
  ```
20
14
 
21
- Or read the full feature tour in the kitchen-sink example:
15
+ Or read the runnable tour every primitive below, live:
22
16
 
23
17
  ```sh
24
- git clone https://github.com/briancray/abide
18
+ git clone git@github.com:briancray/abide.git
25
19
  cd abide/examples/kitchen-sink
26
20
  bun install
27
- bun run dev
21
+ bun dev
28
22
  ```
29
23
 
30
24
  ## RPCs
31
25
 
32
- An RPC is one export per file under `src/server/rpc/`. The file path is the
33
- URL; the export name is the verb. A Standard Schema (zod / valibot / arktype,
34
- unadapted) validates the args and projects the same shape into the MCP tool,
35
- the CLI flags, and the OpenAPI operation.
26
+ An RPC is one export per file under `src/server/rpc/`. The file path is the URL (`getMessages.ts` → `/rpc/getMessages`), and a Standard Schema (zod / valibot / arktype, unadapted) validates the args once and projects the same declaration into every surface.
36
27
 
37
28
  ```ts
38
29
  // src/server/rpc/getMessages.ts
39
30
  import { GET } from '@abide/abide/server/GET'
40
31
  import { json } from '@abide/abide/server/json'
41
32
  import { z } from 'zod'
42
- import { recent } from '../../chatState.ts'
43
33
 
44
- const inputSchema = z.object({ room: z.string(), limit: z.coerce.number().default(20) })
34
+ const inputSchema = z.object({ room: z.string() })
45
35
 
46
- export const getMessages = GET(({ room, limit }) => json(recent(room).slice(-limit)), {
47
- inputSchema,
48
- })
36
+ export const getMessages = GET(({ room }) => json(db.messages(room)), { inputSchema })
49
37
  ```
50
38
 
51
- One declaration, every surface:
39
+ That single declaration fans out:
52
40
 
53
41
  ```text
54
- getMessages = GET(fn, { inputSchema })
55
-
56
- ┌─────────────┬─────────┼──────────┬──────────────┐
57
-
58
- SSR call browser MCP tool CLI sub- OpenAPI
59
- cache(fn)() fetch (read) command operation
60
- proxy
42
+ export const getMessages = GET(fn, { inputSchema })
43
+
44
+ ┌────────────┬────────────┬────────────┬────────────┐
45
+
46
+ SSR call browser MCP tool CLI cmd OpenAPI
47
+ cache(fn)() fetch proxy (read-only) abide cli /openapi.json
61
48
  ```
62
49
 
63
- A schema unlocks the CLI for every verb and MCP for read-only verbs (`GET` /
64
- `HEAD`); a mutating verb never auto-exposes to MCP — it needs an explicit
65
- `clients: { mcp: true }`. Consume the verb four ways: `cache(getMessages)(args)`
66
- in-process (warm SSR hydration), the swapped `fetch` proxy in the browser,
67
- `getMessages.raw(args)` for the untouched `Response`, and
68
- `getMessages.stream(args)` to iterate a `jsonl`/`sse` body.
50
+ The schema is the gate: it unlocks the CLI 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 }`. Consume a call four ways: `cache(getMessages)()` in-process (warm SSR + hydration), the swapped `fetch` proxy in the browser, `getMessages.raw(args)` for the untouched `Response`, and `getMessages.stream(args)` for a frame stream.
69
51
 
70
- > Query args arrive as strings — wrap numeric/boolean fields in `z.coerce.*`.
71
- > The per-verb `timeout` (504 on every surface) is distinct from the
72
- > client-side `ABIDE_CLIENT_TIMEOUT`.
52
+ > Query args travel as strings — use `z.coerce.*` for numbers/booleans on GET/DELETE/HEAD. A per-RPC `timeout` (a 504 on every surface) is distinct from the client-wide `ABIDE_CLIENT_TIMEOUT`.
73
53
 
74
54
  ## Sockets
75
55
 
76
- A socket is one broadcast topic per file under `src/server/sockets/`. A
77
- `Socket<T>` is an isomorphic `AsyncIterable<T>`; every socket multiplexes onto
78
- one WebSocket at `/__abide/sockets`.
56
+ A socket is one broadcast topic per file under `src/server/sockets/`. A `Socket<T>` is an isomorphic `AsyncIterable<T>` — `for await (const m of chat)` is the live stream — and every socket multiplexes onto one WebSocket at `/__abide/sockets`.
79
57
 
80
58
  ```ts
81
59
  // src/server/sockets/chat.ts
82
60
  import { socket } from '@abide/abide/server/socket'
83
61
  import { z } from 'zod'
84
62
 
85
- const schema = z.object({ id: z.string(), from: z.string(), text: z.string(), at: z.number() })
63
+ const schema = z.object({ from: z.string(), text: z.string(), at: z.number() })
86
64
 
87
- // retain the last 100 frames; evict any older than an hour
65
+ // tail: retain the last 100 frames for late joiners; ttl: evict frames older than an hour.
88
66
  export const chat = socket({ schema, tail: 100, ttl: 3_600_000 })
89
67
  export type ChatMessage = z.infer<typeof schema>
90
68
  ```
91
69
 
92
- It also has an HTTP face for clients that can't speak the multiplex (the CLI
93
- and MCP): `GET /__abide/sockets/chat` returns the retained tail, and
94
- `POST /__abide/sockets/chat` publishes — gated by `clientPublish` (default off,
95
- so browsers publish through a validating verb instead).
70
+ Each socket also has an HTTP face at `/__abide/sockets/<name>`: `GET` returns the retained tail, `POST` publishes (only when the socket declares `clientPublish`). `chat.publish(m)` is isomorphic — server-side it fans out in-process and to remote subscribers; client-side it sends a validated `pub` frame.
96
71
 
97
- ## Components — the full template
72
+ ## Components
98
73
 
99
- A `.abide` component pulls the verb and the socket above into one page and
100
- exercises the template grammar. `scope`, `props`, `effect`, `html`, and
101
- `snippet` are ambient — no import needed.
74
+ A component is a `.abide` file: valid HTML with a `<script>`, `{#…}` control-flow blocks, `<template name>` snippets, `{expr}` bindings, and a component-scoped `<style>`. This page imports the RPC and socket above `cache(getMessages)` seeds the list warm at SSR, `tail(chat)` layers live frames on top after hydration.
102
75
 
103
- <!-- prettier-ignore -->
104
76
  ```html
105
77
  <script>
106
78
  import { cache } from '@abide/abide/shared/cache'
107
79
  import { tail } from '@abide/abide/ui/tail'
108
80
  import { getMessages } from '$server/rpc/getMessages.ts'
109
- import { publishChat } from '$server/rpc/publishChat.ts'
81
+ import { createMessage } from '$server/rpc/createMessage.ts'
110
82
  import { chat } from '$server/sockets/chat.ts'
111
83
  import Avatar from '$ui/Avatar.abide'
112
84
 
113
- const { room } = props()
85
+ const { room = 'lobby' } = props()
86
+ const { state, computed } = scope()
114
87
 
115
- // warm on the server, live on the client
116
- const history = scope().computed(() => cache(getMessages)({ room }))
117
- const latest = scope().computed(() => tail(chat))
88
+ let draft = state('')
89
+ let notify = state(true)
90
+ const live = computed(() => tail(chat)) // read-only derived
91
+ const ready = computed(() => draft.trim().length > 0)
118
92
 
119
- let from = scope().state('alice')
120
- let text = scope().state('')
121
- let pinned = scope().state(false)
122
- let view = scope().state('all')
123
-
124
- async function send() {
125
- await publishChat({ from, text })
126
- text = ''
93
+ async function send(event: SubmitEvent) {
94
+ event.preventDefault()
95
+ await createMessage({ room, text: draft, notify })
96
+ draft = ''
127
97
  }
128
98
  </script>
129
99
 
130
- <template name="line" args={message}>
131
- <li><Avatar name={message.from} /> <b>{message.from}</b>: {message.text}</li>
100
+ <template name="row" args={{ msg }}>
101
+ <li><Avatar name={msg.from} /> {msg.text}</li>
132
102
  </template>
133
103
 
134
104
  <form onsubmit={send}>
135
- <input bind:value={from} placeholder="name" />
136
- <input bind:value={text} placeholder="message" />
137
- <label><input type="checkbox" bind:checked={pinned} /> pin</label>
138
- <label><input type="radio" bind:group={view} value="all" /> all</label>
139
- <label><input type="radio" bind:group={view} value="mine" /> mine</label>
140
- <button disabled={!text}>send</button>
105
+ <input bind:value={draft} placeholder="message" />
106
+ <label><input type="checkbox" bind:checked={notify} /> notify</label>
107
+ <button disabled={!ready()}>Send</button>
141
108
  </form>
142
109
 
143
- <template if={latest}>
144
- <p>latest from {latest.from}</p>
145
- <template else>
146
- <p>no messages yet</p>
147
- </template>
148
-
149
- <template switch={view}>
150
- <template case="mine"><p>showing your messages</p></template>
151
- <template default><p>showing every message</p></template>
152
- </template>
110
+ {#if live()}<p class="muted">latest: {live().text}</p>{/if}
153
111
 
154
- <template await={history}>
155
- <p>loading…</p>
156
- <template then="data">
112
+ {#await cache(getMessages)({ room })}
113
+ <p>Loading…</p>
114
+ {:then messages}
157
115
  <ul>
158
- <template each={data} as="message" key="message.id" index="i">
159
- {i}. {line(message)}
160
- </template>
116
+ {#for msg of messages by msg.at}{row({ msg })}{/for}
161
117
  </ul>
162
- <template catch="reason">
163
- <p>failed: {reason.message}</p>
164
- </template>
165
- </template>
118
+ {:catch error}
119
+ <p class="error">{error.message}</p>
120
+ {/await}
166
121
 
167
122
  <style>
168
- form { display: flex; gap: 0.5rem; }
123
+ .muted { color: #64748b; }
124
+ .error { color: #b91c1c; }
169
125
  </style>
170
126
  ```
171
127
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abide/abide",
3
- "version": "0.41.1",
3
+ "version": "0.43.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",
@@ -54,7 +54,7 @@
54
54
  "./server/AppModule": "./src/lib/server/AppModule.ts",
55
55
  "./server/InspectorContext": "./src/lib/server/runtime/types/InspectorContext.ts",
56
56
  "./server/agent": "./src/lib/server/agent.ts",
57
- "./server/rpc/defineVerb": "./src/lib/server/rpc/defineVerb.ts",
57
+ "./server/rpc/defineRpc": "./src/lib/server/rpc/defineRpc.ts",
58
58
  "./server/sockets/defineSocket": "./src/lib/server/sockets/defineSocket.ts",
59
59
  "./server/prompts/definePrompt": "./src/lib/server/prompts/definePrompt.ts",
60
60
  "./ui/tail": "./src/lib/ui/tail.ts",
@@ -62,6 +62,7 @@
62
62
  "./shared/pending": "./src/lib/shared/pending.ts",
63
63
  "./shared/refreshing": "./src/lib/shared/refreshing.ts",
64
64
  "./shared/HttpError": "./src/lib/shared/HttpError.ts",
65
+ "./shared/ValidationErrorData": "./src/lib/shared/types/ValidationErrorData.ts",
65
66
  "./shared/html": "./src/lib/shared/html.ts",
66
67
  "./shared/snippet": "./src/lib/shared/snippet.ts",
67
68
  "./shared/withJsonSchema": "./src/lib/shared/withJsonSchema.ts",
package/src/abideLsp.ts CHANGED
@@ -1,11 +1,15 @@
1
1
  import { fileURLToPath, pathToFileURL } from 'node:url'
2
2
  import ts from 'typescript'
3
+ import { ABIDE_SEMANTIC_TOKENS_LEGEND } from './lib/ui/compile/ABIDE_SEMANTIC_TOKENS_LEGEND.ts'
3
4
  import type {
4
5
  ShadowLanguageService,
5
6
  ShadowQuickInfo,
6
7
  } from './lib/ui/compile/createShadowLanguageService.ts'
7
8
  import { createShadowLanguageService } from './lib/ui/compile/createShadowLanguageService.ts'
9
+ import { encodeSemanticTokens } from './lib/ui/compile/encodeSemanticTokens.ts'
8
10
  import { nearestProjectRoot } from './lib/ui/compile/nearestProjectRoot.ts'
11
+ import { offsetToPosition } from './lib/ui/compile/offsetToPosition.ts'
12
+ import { structuralBlockTokens } from './lib/ui/compile/structuralBlockTokens.ts'
9
13
  import type { AbideDiagnostic } from './lib/ui/compile/types/AbideDiagnostic.ts'
10
14
 
11
15
  /*
@@ -19,6 +23,28 @@ unsaved text as overlays. Each document routes to a shadow service for its
19
23
  nearest tsconfig, so files in a monorepo opened at its root are checked against
20
24
  their own project — matching `abide check` run from that package.
21
25
  */
26
+ /*
27
+ The semantic-tokens `data` array for one component: the structural `{#…}` framing
28
+ merged with the shadow's type-aware expression tokens, encoded to the LSP wire
29
+ format. Never throws — on any internal failure it yields an empty stream so the
30
+ editor falls back to tree-sitter highlighting.
31
+ */
32
+ export function componentSemanticTokens(
33
+ service: ShadowLanguageService,
34
+ abidePath: string,
35
+ text: string,
36
+ ): number[] {
37
+ try {
38
+ const tokens = [
39
+ ...structuralBlockTokens(text),
40
+ ...service.semanticClassifications(abidePath),
41
+ ]
42
+ return encodeSemanticTokens(text, tokens)
43
+ } catch {
44
+ return []
45
+ }
46
+ }
47
+
22
48
  export async function abideLsp({ cwd }: { cwd: string }): Promise<void> {
23
49
  const documentText = new Map<string, string>()
24
50
 
@@ -64,7 +90,14 @@ export async function abideLsp({ cwd }: { cwd: string }): Promise<void> {
64
90
  jsonrpc: '2.0',
65
91
  id: message.id,
66
92
  result: {
67
- capabilities: { textDocumentSync: 1, hoverProvider: true },
93
+ capabilities: {
94
+ textDocumentSync: 1,
95
+ hoverProvider: true,
96
+ semanticTokensProvider: {
97
+ legend: ABIDE_SEMANTIC_TOKENS_LEGEND,
98
+ full: true,
99
+ },
100
+ },
68
101
  serverInfo: { name: 'abide-lsp' },
69
102
  },
70
103
  })
@@ -115,6 +148,18 @@ export async function abideLsp({ cwd }: { cwd: string }): Promise<void> {
115
148
  })
116
149
  return
117
150
  }
151
+ case 'textDocument/semanticTokens/full': {
152
+ const { uri } = message.params.textDocument
153
+ const data = isAbide(uri)
154
+ ? componentSemanticTokens(
155
+ serviceFor(fileURLToPath(uri)),
156
+ fileURLToPath(uri),
157
+ documentText.get(fileURLToPath(uri)) ?? '',
158
+ )
159
+ : []
160
+ send({ jsonrpc: '2.0', id: message.id, result: { data } })
161
+ return
162
+ }
118
163
  case 'textDocument/didClose': {
119
164
  const { uri } = message.params.textDocument
120
165
  if (isAbide(uri)) {
@@ -194,13 +239,6 @@ function toLspHover(text: string, info: ShadowQuickInfo): object {
194
239
  }
195
240
  }
196
241
 
197
- /* An absolute offset → LSP `{ line, character }` (0-based, UTF-16 code units). */
198
- function offsetToPosition(text: string, offset: number): { line: number; character: number } {
199
- const before = text.slice(0, offset)
200
- const line = before.split('\n').length - 1
201
- return { line, character: offset - (before.lastIndexOf('\n') + 1) }
202
- }
203
-
204
242
  /* An LSP `{ line, character }` (0-based) → absolute offset in `text`. */
205
243
  function positionToOffset(text: string, position: { line: number; character: number }): number {
206
244
  const lineStart = text