@abide/abide 0.43.1 → 0.44.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +293 -219
- package/CHANGELOG.md +63 -0
- package/README.md +191 -67
- package/package.json +2 -2
- package/src/abideLsp.ts +8 -4
- package/src/abideResolverPlugin.ts +17 -2
- package/src/build.ts +9 -0
- package/src/buildDisconnected.ts +2 -0
- package/src/devEntry.ts +44 -9
- package/src/lib/bundle/probeAbideServer.ts +1 -1
- package/src/lib/cli/parseArgvForRpc.ts +25 -26
- package/src/lib/cli/runCli.ts +9 -24
- package/src/lib/cli/tokenizeArgvFlags.ts +84 -0
- 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/defineRpc.ts +9 -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 +50 -12
- 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 +3 -3
- package/src/lib/server/runtime/disableIdleTimeoutForStream.ts +1 -1
- package/src/lib/server/runtime/gzipResponse.ts +14 -16
- package/src/lib/server/runtime/logExposedSurfaces.ts +3 -4
- package/src/lib/server/runtime/runWithRequestScope.ts +4 -1
- 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/runtime/types/RequestStore.ts +16 -0
- package/src/lib/server/runtime/withResponseDefaults.ts +8 -3
- package/src/lib/server/socket.ts +1 -1
- package/src/lib/server/sockets/createSocketDispatcher.ts +2 -2
- package/src/lib/server/sockets/defineSocket.ts +5 -1
- 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/RPC_ARGS_TYPE.ts +7 -0
- package/src/lib/shared/STREAMING_CONTENT_TYPES.ts +3 -2
- package/src/lib/shared/activeCacheStore.ts +5 -14
- package/src/lib/shared/activePage.ts +5 -19
- package/src/lib/shared/augmentModule.ts +18 -0
- package/src/lib/shared/basePath.ts +6 -5
- package/src/lib/shared/baseResolver.ts +10 -0
- package/src/lib/shared/baseSlot.ts +6 -12
- package/src/lib/shared/bodyValueForKind.ts +35 -0
- package/src/lib/shared/cache.ts +22 -2
- package/src/lib/shared/cacheEntryFromSnapshot.ts +23 -18
- package/src/lib/shared/cacheStoreResolver.ts +12 -0
- package/src/lib/shared/cacheStoreSlot.ts +5 -13
- package/src/lib/shared/changeAffectsClient.ts +35 -0
- package/src/lib/shared/createPushIterator.ts +1 -1
- package/src/lib/shared/createResolverSlot.ts +37 -0
- package/src/lib/shared/debugGate.ts +90 -0
- package/src/lib/shared/decodeResponse.ts +11 -8
- package/src/lib/shared/emitLogRecord.ts +18 -4
- package/src/lib/shared/globalCacheStoreResolver.ts +12 -0
- package/src/lib/shared/globalCacheStoreSlot.ts +6 -11
- package/src/lib/shared/hasReplayableRequest.ts +17 -0
- package/src/lib/shared/html.ts +7 -26
- package/src/lib/shared/isDebugEnabled.ts +3 -10
- package/src/lib/shared/isDebugNegated.ts +4 -6
- 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/pageResolver.ts +16 -0
- package/src/lib/shared/pageSlot.ts +5 -14
- package/src/lib/shared/pageUrlForFile.ts +1 -1
- package/src/lib/shared/requestScopeResolver.ts +12 -0
- package/src/lib/shared/requestScopeSlot.ts +7 -12
- package/src/lib/shared/responseBodyKind.ts +35 -0
- package/src/lib/shared/routeParamsShape.ts +20 -0
- package/src/lib/shared/setBaseResolver.ts +2 -4
- package/src/lib/shared/setCacheStoreResolver.ts +3 -5
- package/src/lib/shared/setGlobalCacheStoreResolver.ts +3 -5
- package/src/lib/shared/setPageResolver.ts +2 -5
- package/src/lib/shared/setRequestScopeResolver.ts +3 -5
- 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/DebugGate.ts +10 -0
- package/src/lib/shared/types/LastConnection.ts +1 -1
- package/src/lib/shared/types/ResolverSlot.ts +10 -0
- package/src/lib/shared/url.ts +4 -1
- package/src/lib/shared/withBase.ts +1 -2
- package/src/lib/shared/writeDts.ts +10 -3
- package/src/lib/shared/writePublicAssetsDts.ts +5 -9
- package/src/lib/shared/writeRoutesDts.ts +14 -46
- package/src/lib/shared/writeRpcDts.ts +13 -12
- package/src/lib/shared/writeTestRpcDts.ts +11 -11
- package/src/lib/shared/writeTestSocketsDts.ts +9 -9
- 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 +10 -8
- package/src/lib/ui/compile/assertRuntimeHelpersBound.ts +27 -13
- 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 +56 -21
- package/src/lib/ui/compile/compileSSR.ts +12 -10
- package/src/lib/ui/compile/compileShadow.ts +163 -12
- package/src/lib/ui/compile/composeProps.ts +3 -3
- package/src/lib/ui/compile/createShadowLanguageService.ts +58 -4
- 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 +156 -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 +135 -62
- 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 +9 -9
- 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/mountSwappableRange.ts +79 -0
- package/src/lib/ui/dom/readCall.ts +6 -4
- package/src/lib/ui/dom/scopeLabel.ts +3 -3
- package/src/lib/ui/dom/skeleton.ts +10 -1
- package/src/lib/ui/dom/switchBlock.ts +17 -63
- package/src/lib/ui/dom/types/EachRow.ts +4 -0
- package/src/lib/ui/dom/types/SkeletonHoles.ts +4 -2
- package/src/lib/ui/dom/when.ts +11 -64
- 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 +24 -3
- 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 +107 -13
- 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 +51 -0
- package/template/.zed/settings.json +7 -1
- package/template/package.json +3 -0
- package/template/src/ui/pages/layout.abide +3 -5
- package/src/lib/shared/matchesDebugPattern.ts +0 -16
- package/src/lib/shared/parseDebugPatterns.ts +0 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,68 @@
|
|
|
1
1
|
# abide
|
|
2
2
|
|
|
3
|
+
## 0.44.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 767b415: 02-zod-plugin-memo ([`0e00b21`](https://github.com/briancray/abide/commit/0e00b217f99352a7d3def4841172c5bff287bc5c))
|
|
8
|
+
- 767b415: 06-wakeSubtree-prefix-index ([`23ab920`](https://github.com/briancray/abide/commit/23ab9202fd0cb41e01811e78b76eac2843c9cf8f))
|
|
9
|
+
- 767b415: 09-when-via-switch ([`48f8d50`](https://github.com/briancray/abide/commit/48f8d5063cf74060004ad38691f584abcff0cab2))
|
|
10
|
+
- 767b415: 08-dts-codegen ([`5170542`](https://github.com/briancray/abide/commit/51705426e55a700140cc7bc38f7e21f30759fce3))
|
|
11
|
+
- 767b415: 03-socket-publish-gate ([`56fae49`](https://github.com/briancray/abide/commit/56fae49bf393fdfb3aa35cecc618a39443354ce4))
|
|
12
|
+
- 767b415: 10-cli-tokenizer ([`5e305c1`](https://github.com/briancray/abide/commit/5e305c154efd5f77d0a57e78831b72a30b4d9155))
|
|
13
|
+
- 767b415: 14-resolver-slot-factory-JUDGMENT ([`6e00809`](https://github.com/briancray/abide/commit/6e00809c343e24599d54b2304a50a9cecd90619f))
|
|
14
|
+
- 767b415: catch top-level await in a .abide <script> during abide check ([`76ff64e`](https://github.com/briancray/abide/commit/76ff64e9fb9ffed108ae2fde53f2ded2bf3a0abe))
|
|
15
|
+
- 767b415: 12-warm-clone-PARTIAL ([`8e58e0b`](https://github.com/briancray/abide/commit/8e58e0b2c1891174cc809797f949f01619529b89))
|
|
16
|
+
- 767b415: 05-compiler-double-pass ([`9216dae`](https://github.com/briancray/abide/commit/9216dae4c26e27fce49f39b116bd8b1dcf1dd226))
|
|
17
|
+
- 767b415: 04-lsp-shadow-cache ([`9f9f5fc`](https://github.com/briancray/abide/commit/9f9f5fc84792204259d591fa4aff261b2a19c46d))
|
|
18
|
+
- 767b415: 13-dev-rebuild-scoping-JUDGMENT ([`b5a1d49`](https://github.com/briancray/abide/commit/b5a1d49e6607a8fcf37efe03e9fe6f6b2c31ea45))
|
|
19
|
+
- 767b415: gate skeleton fragment-staging on a connected parent ([`c9380ee`](https://github.com/briancray/abide/commit/c9380eebdd9f6773ccffd446665b1acbc78b1123))
|
|
20
|
+
- 767b415: 07-debug-gate ([`c96466e`](https://github.com/briancray/abide/commit/c96466e73ea1f521d728b11aac44262530c3b09c))
|
|
21
|
+
- 767b415: rename paint's escape var to avoid shadowing the global ([`caf1322`](https://github.com/briancray/abide/commit/caf1322adc6598bc6ea32e0ba9047ba768b6f5e1))
|
|
22
|
+
- 767b415: reflow generateBuild attr-kind union to biome's multiline form ([`f9b3669`](https://github.com/briancray/abide/commit/f9b36690e4add2c955abb8f0127a9af9d513be53))
|
|
23
|
+
- 767b415: 01-bugs-B1-B2 ([`fa8659d`](https://github.com/briancray/abide/commit/fa8659d276265c0fbb4f7ca0740fc74702f00168))
|
|
24
|
+
- 767b415: address code-review findings ([`fb02df5`](https://github.com/briancray/abide/commit/fb02df58c924d7206fce35874cc80309949c9e59))
|
|
25
|
+
- 767b415: 11-server-log-micro ([`fb689bc`](https://github.com/briancray/abide/commit/fb689bc05bee9ba127ddf206e925e3a9e04841fd))
|
|
26
|
+
|
|
27
|
+
## 0.44.0
|
|
28
|
+
|
|
29
|
+
### Minor Changes
|
|
30
|
+
|
|
31
|
+
- 24444a8: add zod→CommonJS shim plugin for bun ESM-cycle bug ([`0424b20`](https://github.com/briancray/abide/commit/0424b20151f4d1a98d7b022bbacbbb974d469b47))
|
|
32
|
+
- 24444a8: {children()} replaces the <slot> element ([`0bdfbe5`](https://github.com/briancray/abide/commit/0bdfbe5c3efd621492cdef09b745f9262c5be937))
|
|
33
|
+
- 24444a8: type page params via props(); declare children in the shadow ([`2e58768`](https://github.com/briancray/abide/commit/2e58768cfbfb5a2be2aec48c77482e7bf5ee1b8d))
|
|
34
|
+
- 24444a8: syntactic markup token classifier and zed grammar tokens ([`5cdef1f`](https://github.com/briancray/abide/commit/5cdef1f81762d9c1b8c63a418499335c6524b0a5))
|
|
35
|
+
- 24444a8: {#snippet} block replaces <template name> declarations ([`620c2c3`](https://github.com/briancray/abide/commit/620c2c3ba7d8b797ccb770664db47468e4265131))
|
|
36
|
+
- 24444a8: wire {#if children} lowering; migrate snippet/slot test fixtures ([`861b30b`](https://github.com/briancray/abide/commit/861b30be19deb83b5749b8bb2ca8dd526b29b1b3))
|
|
37
|
+
- 24444a8: page/layout params as reactive props() thunks; layout {#if children} ([`991cea7`](https://github.com/briancray/abide/commit/991cea79a08b09508285769a35494b03111b5113))
|
|
38
|
+
- 24444a8: attribute and prop value interpolation ([`ae0a3da`](https://github.com/briancray/abide/commit/ae0a3daa13411d6de71917efde4cb76c57c855c7))
|
|
39
|
+
- 24444a8: {#if children} lowers children to $props.$children ([`f749f47`](https://github.com/briancray/abide/commit/f749f47836cdf69ccbc51d7b7fb9fafa7d7189a4))
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- 24444a8: effect queue Set -> double-buffered array ([`03c6d09`](https://github.com/briancray/abide/commit/03c6d09334559a2a24c3c953cbf57e5f231ea9c6))
|
|
44
|
+
- 24444a8: prune each reconcile by generation stamp, not a per-pass Set ([`1b48eed`](https://github.com/briancray/abide/commit/1b48eedc9b1657946321cad8c9843930b0bec5d0))
|
|
45
|
+
- 24444a8: accumulated working-tree changes ([`1df2999`](https://github.com/briancray/abide/commit/1df2999b3f4b381334d365b1ff2df53711ad6b50))
|
|
46
|
+
- 24444a8: Breaking: reserve $$ injected namespace, relocate html to abide/ui/html ([`1ef8c2a`](https://github.com/briancray/abide/commit/1ef8c2a047cfaf086df1676d498cdcd2bcbe45d0))
|
|
47
|
+
- 24444a8: shadow block value-params on both back-ends ([`25f719a`](https://github.com/briancray/abide/commit/25f719a17c69aee71e2bc7884080231c35ef6578))
|
|
48
|
+
- 24444a8: shared element-emission plan across build/SSR backends ([`2a6cec5`](https://github.com/briancray/abide/commit/2a6cec5361051c1da021dba50ce40a656106e5a7))
|
|
49
|
+
- 24444a8: typed auto-popping shadow scope for compile lowering ([`2fd04a0`](https://github.com/briancray/abide/commit/2fd04a0ed8dc5453461efa0af920d046549a8877))
|
|
50
|
+
- 24444a8: dedup deref-scope push/pop into withScoped ([`3552fff`](https://github.com/briancray/abide/commit/3552fffd2dc2e69708b8268b42609c4e971eb932))
|
|
51
|
+
- 24444a8: lower await {:finally} outside the then/catch value-param shadow ([`4b33813`](https://github.com/briancray/abide/commit/4b33813433fc42455c6b069da1eb118d71b9af1b))
|
|
52
|
+
- 24444a8: iterate mark down single-subscriber chains ([`4ca3fd4`](https://github.com/briancray/abide/commit/4ca3fd419d58667eb074dd033afc2e29b10f56cd))
|
|
53
|
+
- 24444a8: unify warm-seed shippability + decode symmetry ([`5675e37`](https://github.com/briancray/abide/commit/5675e37ec240ab785e3e83eed7b2723f6dcce090))
|
|
54
|
+
- 24444a8: accumulated feat/arch-deepening working-tree changes ([`60cef30`](https://github.com/briancray/abide/commit/60cef30c2405db94ded7e708abddf2c18b4db555))
|
|
55
|
+
- 24444a8: clear typecheck and lint errors in the arch-deepening compile/dom backlog ([`782fb42`](https://github.com/briancray/abide/commit/782fb42769e495addd57904ccd1fb0148f81f9bb))
|
|
56
|
+
- 24444a8: add eachPlan + snippetPlan, route structure through plans (phase 1) ([`8cfffcc`](https://github.com/briancray/abide/commit/8cfffcc958b63b62da51e670f8f8f4c64a3ca5e5))
|
|
57
|
+
- 24444a8: {children()}/{#snippet}/props() route params ([`8f1dc89`](https://github.com/briancray/abide/commit/8f1dc89bfbf052c07082b939e893c9aee65aeea9))
|
|
58
|
+
- 24444a8: single-source bindings via plans + withBindings, exhaustive dispatch (phase 2) ([`9228e30`](https://github.com/briancray/abide/commit/9228e30d4ba16c3ef1bc14b7d243b9628bde1b59))
|
|
59
|
+
- 24444a8: resolve each key to its row once per reconcile ([`ce3e160`](https://github.com/briancray/abide/commit/ce3e160c8837ec5df4cf5cf625c1db50402defde))
|
|
60
|
+
- 24444a8: reorganize kitchen-sink nav and refresh README/scaffold ([`e31ba15`](https://github.com/briancray/abide/commit/e31ba159d9cc1db88cdebb96f40ff8d5c89b7e0f))
|
|
61
|
+
- 24444a8: scope the children slot reader through the signal transformer ([`e4a901d`](https://github.com/briancray/abide/commit/e4a901da9858f3b307363f98c97c3e72c3569640))
|
|
62
|
+
- 24444a8: faster structural descend via no-alloc walkPath + suffix walk ([`ef14dac`](https://github.com/briancray/abide/commit/ef14dace7c4eb870fe9b0487d4111ecfe635831c))
|
|
63
|
+
- 24444a8: elementPlan over skeletonContext, share emission decisions (phase 3) ([`f75703e`](https://github.com/briancray/abide/commit/f75703e0a276c37ce1fbbfde6b4c4b6064d551b8))
|
|
64
|
+
- 24444a8: effect is not ambient — it is a scope primitive ([`f8942ed`](https://github.com/briancray/abide/commit/f8942ed675d6d6493b3d53bd1cc4e991d1d1b7dd))
|
|
65
|
+
|
|
3
66
|
## 0.43.1
|
|
4
67
|
|
|
5
68
|
### Patch 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.1",
|
|
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
|
|
@@ -247,10 +257,15 @@ export function abideResolverPlugin({
|
|
|
247
257
|
return {
|
|
248
258
|
name: 'abide-resolver',
|
|
249
259
|
setup(build) {
|
|
250
|
-
/* Fresh edge graph each build (dev watch reuses the
|
|
260
|
+
/* Fresh edge graph + resolution cache each build (dev watch reuses the
|
|
261
|
+
plugin instance). The resolution cache memoises (path → resolved file)
|
|
262
|
+
within a build; clearing it per build keeps the memo but stops a stale
|
|
263
|
+
miss — a path resolved before its file existed — surviving into the next
|
|
264
|
+
build, so a freshly-created file resolves instead of staying "not found".
|
|
251
265
|
onStart is build-time only — absent in the runtime/preload plugin context. */
|
|
252
266
|
build.onStart?.(() => {
|
|
253
267
|
importerOf.clear()
|
|
268
|
+
resolveExtensionCache.clear()
|
|
254
269
|
})
|
|
255
270
|
|
|
256
271
|
/*
|
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
|
@@ -6,6 +6,7 @@ import { DEV_READY_MESSAGE } from './lib/server/runtime/DEV_READY_MESSAGE.ts'
|
|
|
6
6
|
import { DEV_REBUILD_MESSAGE } from './lib/server/runtime/DEV_REBUILD_MESSAGE.ts'
|
|
7
7
|
import { findOpenPort } from './lib/server/runtime/findOpenPort.ts'
|
|
8
8
|
import { abideLog } from './lib/shared/abideLog.ts'
|
|
9
|
+
import { changeAffectsClient } from './lib/shared/changeAffectsClient.ts'
|
|
9
10
|
|
|
10
11
|
/*
|
|
11
12
|
Dev orchestrator. Replaces `bun --watch` (which only watches the import graph,
|
|
@@ -63,6 +64,7 @@ const buildOptions = {
|
|
|
63
64
|
compress: false,
|
|
64
65
|
clean: false,
|
|
65
66
|
exitOnFailure: false,
|
|
67
|
+
dev: true,
|
|
66
68
|
} as const
|
|
67
69
|
|
|
68
70
|
// The worker currently meant to be serving; undefined while crashed or replaced.
|
|
@@ -173,30 +175,51 @@ async function replaceServer(port: number): Promise<void> {
|
|
|
173
175
|
|
|
174
176
|
let building = false
|
|
175
177
|
let queued = false
|
|
178
|
+
// True once any change collapsed into the queued run needs the client rebuilt;
|
|
179
|
+
// a client-affecting change can never be downgraded to a server-only restart.
|
|
180
|
+
let queuedNeedsClient = false
|
|
176
181
|
|
|
177
182
|
/*
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
+
Apply a change: rebuild the client (unless `skipClientBuild` — a server/MCP-only
|
|
184
|
+
change leaves the client bundle byte-identical), then on success swap in a fresh
|
|
185
|
+
server child. The worker restart always runs: SSR renders through Bun's module
|
|
186
|
+
cache, so a new process is the only reliable way to reflect any source edit,
|
|
187
|
+
client-affecting or not.
|
|
188
|
+
|
|
189
|
+
Serialized: a change arriving mid-build sets `queued` so exactly one more run
|
|
190
|
+
follows, collapsing further changes in between; `queuedNeedsClient` records
|
|
191
|
+
whether any of them needs the client, so the collapsed run never skips a client
|
|
192
|
+
rebuild a queued change required. A failed build leaves the current child
|
|
193
|
+
untouched — the error is logged and the last-good server keeps serving.
|
|
183
194
|
*/
|
|
184
|
-
async function rebuild(port: number): Promise<void> {
|
|
195
|
+
async function rebuild(port: number, skipClientBuild = false): Promise<void> {
|
|
185
196
|
if (building) {
|
|
186
197
|
queued = true
|
|
198
|
+
queuedNeedsClient ||= !skipClientBuild
|
|
187
199
|
return
|
|
188
200
|
}
|
|
189
201
|
building = true
|
|
190
202
|
try {
|
|
191
|
-
const succeeded = await build(buildOptions)
|
|
203
|
+
const succeeded = skipClientBuild ? true : await build(buildOptions)
|
|
192
204
|
if (succeeded) {
|
|
193
205
|
await replaceServer(port)
|
|
194
206
|
}
|
|
207
|
+
/* A server/MCP-only change reuses the existing client bundle. That's correct for
|
|
208
|
+
an rpc/socket handler BODY edit, but changing an rpc's method, its export name,
|
|
209
|
+
or `outbox: true` changes the client proxy stub too — the stale bundle then
|
|
210
|
+
calls with the old shape (e.g. a 405). Flag the skip so that case isn't silent. */
|
|
211
|
+
if (skipClientBuild) {
|
|
212
|
+
abideLog.info(
|
|
213
|
+
'server-only change — kept the existing client bundle; if you changed an rpc method, export name, or outbox, save a client file (or restart dev) for a full rebuild',
|
|
214
|
+
)
|
|
215
|
+
}
|
|
195
216
|
} finally {
|
|
196
217
|
building = false
|
|
197
218
|
if (queued) {
|
|
198
219
|
queued = false
|
|
199
|
-
|
|
220
|
+
const needsClient = queuedNeedsClient
|
|
221
|
+
queuedNeedsClient = false
|
|
222
|
+
void rebuild(port, !needsClient)
|
|
200
223
|
}
|
|
201
224
|
}
|
|
202
225
|
}
|
|
@@ -222,14 +245,26 @@ an agent editing the app's own source — isn't yanked mid-run by a save.
|
|
|
222
245
|
const manualRebuild = Bun.env.ABIDE_DEV_NO_WATCH === '1'
|
|
223
246
|
|
|
224
247
|
let debounce: ReturnType<typeof setTimeout> | undefined
|
|
248
|
+
/*
|
|
249
|
+
True only while every change collapsed into the pending debounce is server/MCP-
|
|
250
|
+
only; one client-affecting change in the burst flips it false (latches until the
|
|
251
|
+
debounce fires), so a multi-file save that touches the client never skips the
|
|
252
|
+
client rebuild.
|
|
253
|
+
*/
|
|
254
|
+
let pendingSkipClientBuild = true
|
|
225
255
|
const watcher = manualRebuild
|
|
226
256
|
? undefined
|
|
227
257
|
: watch(SOURCE_DIR, { recursive: true }, (_event, filename) => {
|
|
228
258
|
if (!filename || isGenerated(filename)) {
|
|
229
259
|
return
|
|
230
260
|
}
|
|
261
|
+
pendingSkipClientBuild &&= !changeAffectsClient(filename)
|
|
231
262
|
clearTimeout(debounce)
|
|
232
|
-
debounce = setTimeout(() =>
|
|
263
|
+
debounce = setTimeout(() => {
|
|
264
|
+
const skipClientBuild = pendingSkipClientBuild
|
|
265
|
+
pendingSkipClientBuild = true
|
|
266
|
+
void rebuild(port, skipClientBuild)
|
|
267
|
+
}, REBUILD_DEBOUNCE_MS)
|
|
233
268
|
})
|
|
234
269
|
if (manualRebuild) {
|
|
235
270
|
abideLog.info(
|