@abide/abide 0.48.0 → 0.50.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 (360) hide show
  1. package/AGENTS.md +85 -59
  2. package/CHANGELOG.md +216 -0
  3. package/README.md +21 -10
  4. package/package.json +15 -4
  5. package/src/abideLsp.ts +5 -6
  6. package/src/abideResolverPlugin.ts +197 -169
  7. package/src/build.ts +79 -56
  8. package/src/buildCli.ts +3 -5
  9. package/src/buildDisconnected.ts +2 -5
  10. package/src/bundleApp.ts +2 -3
  11. package/src/checkAbide.ts +12 -2
  12. package/src/compile.ts +2 -4
  13. package/src/devEntry.ts +113 -28
  14. package/src/discoveryEntry.ts +3 -2
  15. package/src/lib/bundle/disconnected.abide +69 -73
  16. package/src/lib/bundle/infoPlist.ts +13 -7
  17. package/src/lib/bundle/installDownloads.ts +13 -3
  18. package/src/lib/bundle/installMacMenu.ts +13 -3
  19. package/src/lib/bundle/spawnEmbeddedServer.ts +13 -4
  20. package/src/lib/bundle/waitForServer.ts +6 -1
  21. package/src/lib/cli/parseArgvForRpc.ts +36 -9
  22. package/src/lib/cli/tokenizeArgvFlags.ts +4 -2
  23. package/src/lib/mcp/createMcpResourceServer.ts +13 -2
  24. package/src/lib/mcp/mcpTools.ts +15 -6
  25. package/src/lib/mcp/toolResultFromResponse.ts +40 -12
  26. package/src/lib/server/error.ts +6 -6
  27. package/src/lib/server/json.ts +17 -3
  28. package/src/lib/server/rpc/defineRpc.ts +58 -24
  29. package/src/lib/server/rpc/parseArgs.ts +113 -14
  30. package/src/lib/server/rpc/resolveRpcJsonSchema.ts +28 -0
  31. package/src/lib/server/rpc/runWithRpcTimeout.ts +12 -1
  32. package/src/lib/server/rpc/types/RpcHelper.ts +75 -105
  33. package/src/lib/server/rpc/types/RpcRegistryEntry.ts +24 -9
  34. package/src/lib/server/rpc/validationError.ts +1 -1
  35. package/src/lib/server/runtime/DEV_RELOAD_CLIENT_SCRIPT.ts +0 -15
  36. package/src/lib/server/runtime/buildCacheSnapshot.ts +10 -9
  37. package/src/lib/server/runtime/buildInspectorSurface.ts +6 -4
  38. package/src/lib/server/runtime/buildOpenApiSpec.ts +55 -11
  39. package/src/lib/server/runtime/buildPreloadManifest.ts +12 -10
  40. package/src/lib/server/runtime/createAppAssetServer.ts +18 -15
  41. package/src/lib/server/runtime/createAppRouteResolver.ts +145 -0
  42. package/src/lib/server/runtime/createPlumbingRouter.ts +212 -0
  43. package/src/lib/server/runtime/createRouteDispatcher.ts +4 -10
  44. package/src/lib/server/runtime/createServer.ts +120 -324
  45. package/src/lib/server/runtime/createUiPageRenderer.ts +137 -26
  46. package/src/lib/server/runtime/devClientFingerprint.ts +19 -34
  47. package/src/lib/server/runtime/finalizeResponse.ts +11 -1
  48. package/src/lib/server/runtime/installAmbientScopeStore.ts +30 -9
  49. package/src/lib/server/runtime/logExposedSurfaces.ts +8 -7
  50. package/src/lib/server/runtime/pathStore.ts +15 -0
  51. package/src/lib/server/runtime/registryManifests.ts +1 -1
  52. package/src/lib/server/runtime/renderCellBarrierStore.ts +15 -0
  53. package/src/lib/server/runtime/runWithRequestScope.ts +3 -0
  54. package/src/lib/server/runtime/serializeCacheSnapshot.ts +6 -4
  55. package/src/lib/server/runtime/snapshotEntryFromCache.ts +24 -16
  56. package/src/lib/server/runtime/streamCacheResolutions.ts +14 -7
  57. package/src/lib/server/runtime/streamFromIterator.ts +30 -2
  58. package/src/lib/server/runtime/textResponse.ts +23 -0
  59. package/src/lib/server/runtime/types/DevReloadStamp.ts +6 -10
  60. package/src/lib/server/runtime/types/InspectorCacheEntry.ts +1 -1
  61. package/src/lib/server/runtime/types/RequestStore.ts +27 -0
  62. package/src/lib/server/runtime/warnUnguardedMcp.ts +15 -5
  63. package/src/lib/server/sockets/createSocketDispatcher.ts +9 -11
  64. package/src/lib/server/sockets/defineSocket.ts +5 -4
  65. package/src/lib/server/sse.ts +5 -1
  66. package/src/lib/shared/ASYNC_CELL.ts +5 -0
  67. package/src/lib/shared/DEV_REBUILD_PATH.ts +6 -0
  68. package/src/lib/shared/HTTP_METHODS.ts +6 -0
  69. package/src/lib/shared/HttpError.ts +1 -5
  70. package/src/lib/shared/MCP_PATH.ts +6 -0
  71. package/src/lib/shared/PROXIED_SERVER_SUBDIRS.ts +15 -0
  72. package/src/lib/shared/REF_JSON_TAGS.ts +13 -1
  73. package/src/lib/shared/RPC_SHIM_GLOBALS.ts +9 -0
  74. package/src/lib/shared/activeCacheStore.ts +1 -0
  75. package/src/lib/shared/activePage.ts +1 -0
  76. package/src/lib/shared/buildArtifact.ts +20 -0
  77. package/src/lib/shared/buildRpcRequest.ts +6 -2
  78. package/src/lib/shared/buildSocketOverChannel.ts +4 -3
  79. package/src/lib/shared/bundleGraphFromMetafile.ts +68 -0
  80. package/src/lib/shared/cache.ts +156 -131
  81. package/src/lib/shared/canonicalJson.ts +24 -1
  82. package/src/lib/shared/changeAffectsClient.ts +12 -7
  83. package/src/lib/shared/createCacheStore.ts +31 -8
  84. package/src/lib/shared/createChannelLog.ts +24 -0
  85. package/src/lib/shared/createLifecycleChannel.ts +7 -1
  86. package/src/lib/shared/createReachable.ts +47 -78
  87. package/src/lib/shared/createRemoteFunction.ts +52 -30
  88. package/src/lib/shared/createRpcServerProgram.ts +820 -0
  89. package/src/lib/shared/decodeRefJson.ts +4 -4
  90. package/src/lib/shared/decodeResponse.ts +2 -2
  91. package/src/lib/shared/decodeWireBody.ts +35 -0
  92. package/src/lib/shared/detectRpcMethod.ts +8 -1
  93. package/src/lib/shared/done.ts +8 -2
  94. package/src/lib/shared/encodeRefJson.ts +4 -4
  95. package/src/lib/shared/encodeWireBody.ts +18 -0
  96. package/src/lib/shared/exitOnBuildFailure.ts +4 -3
  97. package/src/lib/{server/rpc → shared}/fieldErrorsFromIssues.ts +5 -1
  98. package/src/lib/shared/generateDeclarations.ts +72 -0
  99. package/src/lib/shared/hasSeedableRequest.ts +25 -0
  100. package/src/lib/shared/hydrationWindow.ts +53 -0
  101. package/src/lib/shared/isAsyncCell.ts +11 -0
  102. package/src/lib/shared/isAsyncIterable.ts +8 -0
  103. package/src/lib/shared/isSubscribable.ts +3 -3
  104. package/src/lib/shared/isThenable.ts +9 -0
  105. package/src/lib/shared/jsonSchemaForType.ts +258 -0
  106. package/src/lib/shared/lenientDecode.ts +15 -0
  107. package/src/lib/shared/loadProjectTsConfig.ts +28 -0
  108. package/src/lib/shared/markFrameworkSourcesIgnored.ts +1 -1
  109. package/src/lib/shared/matchRoute.ts +4 -14
  110. package/src/lib/shared/parseEnv.ts +17 -6
  111. package/src/lib/shared/peek.ts +14 -0
  112. package/src/lib/shared/pending.ts +9 -6
  113. package/src/lib/shared/pendingAsyncCellsSlot.ts +13 -0
  114. package/src/lib/shared/prepareRpcModule.ts +91 -93
  115. package/src/lib/shared/prepareSocketModule.ts +3 -2
  116. package/src/lib/shared/probeRegistries.ts +5 -18
  117. package/src/lib/shared/reachable.ts +7 -10
  118. package/src/lib/shared/refresh.ts +12 -2
  119. package/src/lib/shared/refreshing.ts +8 -2
  120. package/src/lib/shared/resolvedCellsSlot.ts +13 -0
  121. package/src/lib/shared/reviveWireField.ts +49 -0
  122. package/src/lib/shared/reviveWireOutput.ts +36 -0
  123. package/src/lib/shared/rpcServerForRoot.ts +25 -0
  124. package/src/lib/shared/scanPages.ts +25 -0
  125. package/src/lib/shared/serializeEnv.ts +18 -6
  126. package/src/lib/shared/snapshotShippable.ts +8 -7
  127. package/src/lib/shared/snippet.ts +11 -6
  128. package/src/lib/shared/streamedCellsSlot.ts +14 -0
  129. package/src/lib/shared/subscribableFromResponse.ts +4 -4
  130. package/src/lib/shared/subscribableProbes.ts +1 -1
  131. package/src/lib/shared/tailProbeSlot.ts +1 -1
  132. package/src/lib/shared/types/AsyncComputed.ts +20 -0
  133. package/src/lib/shared/types/AsyncState.ts +13 -0
  134. package/src/lib/shared/types/CacheEntry.ts +7 -7
  135. package/src/lib/shared/types/CacheOptions.ts +23 -37
  136. package/src/lib/shared/types/CachePolicy.ts +25 -0
  137. package/src/lib/shared/types/CacheSnapshotEntry.ts +6 -5
  138. package/src/lib/shared/types/ErrorJsonSchemas.ts +8 -0
  139. package/src/lib/shared/types/HttpMethod.ts +3 -1
  140. package/src/lib/shared/types/InputCoercion.ts +17 -0
  141. package/src/lib/shared/types/{Subscribable.ts → NamedAsyncIterable.ts} +1 -1
  142. package/src/lib/shared/types/OutputWirePlan.ts +17 -0
  143. package/src/lib/shared/types/PagesScan.ts +7 -0
  144. package/src/lib/shared/types/PendingAsyncCells.ts +10 -0
  145. package/src/lib/shared/types/RawRemoteFunction.ts +6 -0
  146. package/src/lib/shared/types/RemoteCallable.ts +8 -7
  147. package/src/lib/shared/types/RemoteFunction.ts +16 -15
  148. package/src/lib/shared/types/ResolvedCells.ts +11 -0
  149. package/src/lib/shared/types/ReturnBody.ts +15 -0
  150. package/src/lib/shared/types/RpcBuildStamps.ts +23 -0
  151. package/src/lib/shared/types/RpcErrorGuard.ts +3 -8
  152. package/src/lib/shared/types/Socket.ts +4 -4
  153. package/src/lib/shared/types/SsrPayload.ts +5 -1
  154. package/src/lib/shared/types/StreamPolicy.ts +11 -0
  155. package/src/lib/shared/types/StreamedCells.ts +19 -0
  156. package/src/lib/shared/types/StreamedResolution.ts +24 -6
  157. package/src/lib/shared/types/TailHooks.ts +1 -1
  158. package/src/lib/shared/types/WireKind.ts +11 -0
  159. package/src/lib/shared/url.ts +5 -0
  160. package/src/lib/shared/validationHttpError.ts +33 -0
  161. package/src/lib/shared/warmSeedKey.ts +16 -0
  162. package/src/lib/shared/wireJsonReplacer.ts +30 -0
  163. package/src/lib/shared/writeRpcDts.ts +11 -1
  164. package/src/lib/shared/writeTestSocketsDts.ts +1 -1
  165. package/src/lib/test/createTestApp.ts +19 -1
  166. package/src/lib/ui/README.md +1 -1
  167. package/src/lib/ui/activePendingCells.ts +14 -0
  168. package/src/lib/ui/compile/BLOCK_KEYWORDS.ts +21 -0
  169. package/src/lib/ui/compile/SSR_ESCAPE.ts +4 -1
  170. package/src/lib/ui/compile/UI_RUNTIME_IMPORTS.ts +35 -7
  171. package/src/lib/ui/compile/abideUiPlugin.ts +19 -2
  172. package/src/lib/ui/compile/analyzeComponent.ts +89 -6
  173. package/src/lib/ui/compile/assignmentTargetNames.ts +54 -0
  174. package/src/lib/ui/compile/asyncInterpolationFields.ts +152 -0
  175. package/src/lib/ui/compile/asyncValuePositionError.ts +21 -0
  176. package/src/lib/ui/compile/asyncValuePositionInterpolations.ts +64 -0
  177. package/src/lib/ui/compile/attrLiftPosition.ts +18 -0
  178. package/src/lib/ui/compile/bindListenEvent.ts +5 -6
  179. package/src/lib/ui/compile/cachedSourceFile.ts +40 -0
  180. package/src/lib/ui/compile/catchBinding.ts +7 -5
  181. package/src/lib/ui/compile/classifyInterpolationType.ts +46 -0
  182. package/src/lib/ui/compile/collectAbideDiagnostics.ts +96 -0
  183. package/src/lib/ui/compile/compileComponent.ts +19 -3
  184. package/src/lib/ui/compile/compileModule.ts +27 -58
  185. package/src/lib/ui/compile/compileSSR.ts +52 -13
  186. package/src/lib/ui/compile/compileShadow.ts +265 -42
  187. package/src/lib/ui/compile/composeProps.ts +15 -4
  188. package/src/lib/ui/compile/createShadowLanguageService.ts +116 -68
  189. package/src/lib/ui/compile/createShadowProgram.ts +35 -6
  190. package/src/lib/ui/compile/declaredNames.ts +36 -0
  191. package/src/lib/ui/compile/desugarSignals.ts +419 -37
  192. package/src/lib/ui/compile/expressionIsPrefixEvaluable.ts +19 -0
  193. package/src/lib/ui/compile/generateBuild.ts +74 -17
  194. package/src/lib/ui/compile/generateSSR.ts +286 -75
  195. package/src/lib/ui/compile/hoistableAwaits.ts +193 -0
  196. package/src/lib/ui/compile/hoistableChildRenders.ts +112 -0
  197. package/src/lib/ui/compile/interpolatedTemplateLiteral.ts +3 -1
  198. package/src/lib/ui/compile/interpolationClassifierForRoot.ts +37 -0
  199. package/src/lib/ui/compile/isSpuriousAsyncReadDiagnostic.ts +174 -0
  200. package/src/lib/ui/compile/isWhitespaceText.ts +10 -2
  201. package/src/lib/ui/compile/liftAsyncSubExpressions.ts +166 -0
  202. package/src/lib/ui/compile/lowerAsyncInterpolations.ts +92 -0
  203. package/src/lib/ui/compile/lowerContext.ts +10 -0
  204. package/src/lib/ui/compile/lowerDocAccess.ts +51 -10
  205. package/src/lib/ui/compile/lowerScript.ts +40 -4
  206. package/src/lib/ui/compile/nodeAtShadowOffset.ts +28 -0
  207. package/src/lib/ui/compile/parseTemplate.ts +18 -1090
  208. package/src/lib/ui/compile/parseTemplateRecovering.ts +1385 -0
  209. package/src/lib/ui/compile/referencedIdentifiers.ts +35 -0
  210. package/src/lib/ui/compile/renameSignalRefs.ts +26 -40
  211. package/src/lib/ui/compile/resolveReactiveExport.ts +4 -7
  212. package/src/lib/ui/compile/scopeCss.ts +27 -4
  213. package/src/lib/ui/compile/seedTypeClassifierForRoot.ts +65 -0
  214. package/src/lib/ui/compile/shadowInterpolationClassifier.ts +47 -0
  215. package/src/lib/ui/compile/sourceFileOptionsSignature.ts +20 -0
  216. package/src/lib/ui/compile/structuralHeadTokens.ts +107 -0
  217. package/src/lib/ui/compile/templateSemanticTokens.ts +21 -0
  218. package/src/lib/ui/compile/templateStartOffset.ts +15 -0
  219. package/src/lib/ui/compile/tryPlan.ts +4 -3
  220. package/src/lib/ui/compile/types/AnalyzedComponent.ts +4 -0
  221. package/src/lib/ui/compile/types/AsyncInterpolationField.ts +19 -0
  222. package/src/lib/ui/compile/types/InterpolationClassifier.ts +12 -0
  223. package/src/lib/ui/compile/types/InterpolationKind.ts +7 -0
  224. package/src/lib/ui/compile/types/ParseDiagnostic.ts +8 -0
  225. package/src/lib/ui/compile/types/SeedTypeClassifier.ts +15 -0
  226. package/src/lib/ui/compile/types/TemplateNode.ts +36 -4
  227. package/src/lib/ui/compile/types/ValuePositionInterpolation.ts +13 -0
  228. package/src/lib/ui/compile/writtenTemplateNames.ts +84 -0
  229. package/src/lib/ui/computed.ts +28 -1
  230. package/src/lib/ui/createScope.ts +35 -68
  231. package/src/lib/ui/dom/anchoredBranch.ts +142 -0
  232. package/src/lib/ui/dom/appendText.ts +8 -3
  233. package/src/lib/ui/dom/awaitBlock.ts +62 -75
  234. package/src/lib/ui/dom/bindProp.ts +22 -0
  235. package/src/lib/ui/dom/bindableProp.ts +47 -0
  236. package/src/lib/ui/dom/cellPending.ts +24 -0
  237. package/src/lib/ui/dom/discardBoundary.ts +24 -6
  238. package/src/lib/ui/dom/disposeRange.ts +2 -1
  239. package/src/lib/ui/dom/each.ts +41 -12
  240. package/src/lib/ui/dom/eachAsync.ts +39 -3
  241. package/src/lib/ui/dom/fillBefore.ts +6 -7
  242. package/src/lib/ui/dom/fillBoundary.ts +2 -3
  243. package/src/lib/ui/dom/fillRange.ts +4 -4
  244. package/src/lib/ui/dom/hydrate.ts +6 -12
  245. package/src/lib/ui/dom/isComment.ts +1 -1
  246. package/src/lib/ui/dom/matchingRangeClose.ts +29 -0
  247. package/src/lib/ui/dom/mergeProps.ts +1 -1
  248. package/src/lib/ui/dom/mount.ts +1 -2
  249. package/src/lib/ui/dom/mountChild.ts +9 -40
  250. package/src/lib/ui/dom/mountRange.ts +2 -3
  251. package/src/lib/ui/dom/mountSlot.ts +1 -1
  252. package/src/lib/ui/dom/mountStreamedChild.ts +84 -0
  253. package/src/lib/ui/dom/mountSwappableRange.ts +46 -4
  254. package/src/lib/ui/dom/mutateDocContainer.ts +65 -0
  255. package/src/lib/ui/dom/on.ts +2 -2
  256. package/src/lib/ui/dom/readCell.ts +40 -0
  257. package/src/lib/ui/dom/restProps.ts +2 -2
  258. package/src/lib/ui/dom/spreadProps.ts +3 -4
  259. package/src/lib/ui/dom/switchBlock.ts +30 -7
  260. package/src/lib/ui/dom/tryBlock.ts +233 -70
  261. package/src/lib/ui/dom/types/SwitchCase.ts +5 -1
  262. package/src/lib/ui/dom/when.ts +12 -2
  263. package/src/lib/ui/dom/withScope.ts +9 -2
  264. package/src/lib/ui/finalizeStreamedChildren.ts +89 -0
  265. package/src/lib/ui/flight.ts +56 -0
  266. package/src/lib/ui/html.ts +12 -1
  267. package/src/lib/ui/isolateCellBarrier.ts +17 -0
  268. package/src/lib/ui/linked.ts +48 -2
  269. package/src/lib/ui/props.ts +17 -0
  270. package/src/lib/ui/remoteProxy.ts +84 -159
  271. package/src/lib/ui/renderChain.ts +53 -13
  272. package/src/lib/ui/renderToStream.ts +22 -18
  273. package/src/lib/ui/resumeSeedScript.ts +1 -1
  274. package/src/lib/ui/router.ts +86 -53
  275. package/src/lib/ui/runtime/AsyncCellError.ts +20 -0
  276. package/src/lib/ui/runtime/CELL_SEED.ts +14 -0
  277. package/src/lib/ui/runtime/CHILD_PRESENT.ts +2 -2
  278. package/src/lib/ui/runtime/CURRENT_BOUNDARY.ts +11 -0
  279. package/src/lib/ui/runtime/CURRENT_PATH.ts +29 -0
  280. package/src/lib/ui/runtime/RENDER.ts +10 -7
  281. package/src/lib/ui/runtime/RESUME.ts +4 -4
  282. package/src/lib/ui/runtime/STREAMED_CELLS.ts +57 -0
  283. package/src/lib/ui/runtime/ambientPathBacking.ts +32 -0
  284. package/src/lib/ui/runtime/applyPatchToTree.ts +17 -4
  285. package/src/lib/ui/runtime/blockId.ts +31 -0
  286. package/src/lib/ui/runtime/boundaryFor.ts +11 -0
  287. package/src/lib/ui/runtime/cellBarrierBacking.ts +30 -0
  288. package/src/lib/ui/runtime/createAsyncCell.ts +300 -0
  289. package/src/lib/ui/runtime/createDoc.ts +31 -54
  290. package/src/lib/ui/runtime/createEffectNode.ts +9 -0
  291. package/src/lib/ui/runtime/enterRenderPass.ts +5 -4
  292. package/src/lib/ui/runtime/flushEffects.ts +33 -1
  293. package/src/lib/ui/runtime/isAsyncFunction.ts +14 -0
  294. package/src/lib/ui/runtime/nextBlockId.ts +8 -7
  295. package/src/lib/ui/runtime/renderPath.ts +16 -0
  296. package/src/lib/ui/runtime/scope.ts +11 -0
  297. package/src/lib/ui/runtime/toTeardown.ts +10 -3
  298. package/src/lib/ui/runtime/types/Boundary.ts +9 -0
  299. package/src/lib/ui/runtime/types/RenderContext.ts +9 -7
  300. package/src/lib/ui/runtime/types/SsrRender.ts +9 -2
  301. package/src/lib/ui/runtime/types/UiComponent.ts +1 -5
  302. package/src/lib/ui/runtime/types/UiProps.ts +6 -5
  303. package/src/lib/ui/runtime/withOptionalPath.ts +8 -0
  304. package/src/lib/ui/runtime/withPath.ts +16 -0
  305. package/src/lib/ui/runtime/withPathFrom.ts +20 -0
  306. package/src/lib/ui/runtime/withoutHydration.ts +22 -0
  307. package/src/lib/ui/seedStreamedResolution.ts +31 -6
  308. package/src/lib/ui/settleAsyncCells.ts +24 -0
  309. package/src/lib/ui/socketProxy.ts +1 -1
  310. package/src/lib/ui/startClient.ts +16 -31
  311. package/src/lib/ui/state.ts +9 -3
  312. package/src/lib/ui/trackedComputed.ts +68 -0
  313. package/src/lib/ui/types/Scope.ts +8 -24
  314. package/src/lib/ui/watch.ts +3 -3
  315. package/src/serverEntry.ts +14 -0
  316. package/template/src/server/rpc/getHello.ts +15 -13
  317. package/template/test/app.test.ts +1 -1
  318. package/src/lib/server/runtime/devHotModuleResponse.ts +0 -41
  319. package/src/lib/shared/DEV_HOT_PREFIX.ts +0 -7
  320. package/src/lib/shared/UNREACHABLE_STATUSES.ts +0 -13
  321. package/src/lib/shared/hasReplayableRequest.ts +0 -17
  322. package/src/lib/shared/hydratingSlot.ts +0 -12
  323. package/src/lib/shared/outboxProbeSlot.ts +0 -20
  324. package/src/lib/shared/types/Outbox.ts +0 -9
  325. package/src/lib/shared/types/OutboxEntry.ts +0 -27
  326. package/src/lib/shared/types/SmartReadOptions.ts +0 -36
  327. package/src/lib/shared/wakeHydrationPeeks.ts +0 -20
  328. package/src/lib/ui/COMPONENT_WRAPPER_PREFIX.ts +0 -5
  329. package/src/lib/ui/compile/REACTIVE_CALLEES.ts +0 -11
  330. package/src/lib/ui/compile/assertRuntimeHelpersBound.ts +0 -80
  331. package/src/lib/ui/compile/markupTokens.ts +0 -313
  332. package/src/lib/ui/compile/structuralBlockTokens.ts +0 -100
  333. package/src/lib/ui/dom/applyResolved.ts +0 -87
  334. package/src/lib/ui/dom/scopeLabel.ts +0 -21
  335. package/src/lib/ui/dom/text.ts +0 -20
  336. package/src/lib/ui/history.ts +0 -101
  337. package/src/lib/ui/installHotBridge.ts +0 -93
  338. package/src/lib/ui/installInspectorBridge.ts +0 -140
  339. package/src/lib/ui/outbox.ts +0 -35
  340. package/src/lib/ui/persist.ts +0 -115
  341. package/src/lib/ui/rpcOutbox/createOutboxQueue.ts +0 -281
  342. package/src/lib/ui/rpcOutbox/outboxRegistry.ts +0 -69
  343. package/src/lib/ui/runtime/PATCH_BUS.ts +0 -28
  344. package/src/lib/ui/runtime/captureModelDoc.ts +0 -28
  345. package/src/lib/ui/runtime/hotInstances.ts +0 -10
  346. package/src/lib/ui/runtime/hotReloadEnabled.ts +0 -8
  347. package/src/lib/ui/runtime/hotReplace.ts +0 -38
  348. package/src/lib/ui/runtime/liveScopes.ts +0 -15
  349. package/src/lib/ui/runtime/localStoragePersistence.ts +0 -47
  350. package/src/lib/ui/runtime/registerHotInstance.ts +0 -23
  351. package/src/lib/ui/runtime/seedModelDoc.ts +0 -26
  352. package/src/lib/ui/runtime/types/HotInstance.ts +0 -22
  353. package/src/lib/ui/runtime/types/PatchEvent.ts +0 -16
  354. package/src/lib/ui/seedResolved.ts +0 -28
  355. package/src/lib/ui/sync.ts +0 -48
  356. package/src/lib/ui/types/History.ts +0 -14
  357. package/src/lib/ui/types/PersistHandle.ts +0 -11
  358. package/src/lib/ui/types/PersistenceStore.ts +0 -12
  359. package/src/lib/ui/types/ResolvedFrame.ts +0 -15
  360. package/src/lib/ui/types/SyncTransport.ts +0 -13
@@ -1,21 +1,21 @@
1
1
  import type { CacheEntry } from '../../shared/types/CacheEntry.ts'
2
2
  import type { CacheSnapshotEntry } from '../../shared/types/CacheSnapshotEntry.ts'
3
3
  import type { CacheStore } from '../../shared/types/CacheStore.ts'
4
- import type { StreamedResolution } from '../../shared/types/StreamedResolution.ts'
4
+ import type { CacheResolution } from '../../shared/types/StreamedResolution.ts'
5
5
  import { snapshotEntryFromCache } from './snapshotEntryFromCache.ts'
6
6
 
7
7
  /*
8
8
  Drains the pending ({#await}) cache entries in resolution order — whichever
9
9
  fetch lands next is yielded next, so a slow entry never blocks a fast one
10
- behind it. Yields exactly one StreamedResolution per entry: the snapshot when
10
+ behind it. Yields exactly one CacheResolution per entry: the snapshot when
11
11
  serialization succeeds, or a `{ key, miss }` marker when the body can't ship so
12
12
  the client placeholder re-fetches instead of hanging on a deferred that never
13
- settles.
13
+ settles. (Never the cell arm of StreamedResolution — that is emitted separately.)
14
14
  */
15
15
  export async function* streamCacheResolutions(
16
16
  store: CacheStore,
17
17
  pending: CacheEntry[],
18
- ): AsyncIterable<StreamedResolution> {
18
+ ): AsyncIterable<CacheResolution> {
19
19
  /*
20
20
  Tag each pending serialization with its key so the loop can drop exactly
21
21
  the one that just settled. Deleting inside the `.then` instead would race
@@ -29,9 +29,16 @@ export async function* streamCacheResolutions(
29
29
  snapshotEntryFromCache(store, entry).then((snapshot) => ({ key: entry.key, snapshot })),
30
30
  )
31
31
  }
32
+ /*
33
+ Drain in settle order. A pending BARE read (ADR-0024 auto-streaming) is bounded by its OWN
34
+ endpoint `timeout` — which 504s the in-process handler during SSR, settling the entry into an
35
+ error that snapshots as a `{ key, miss }` (the client refetches on hydrate). So there is no
36
+ separate SSR-stream deadline (ADR-0024 option a): a read with a declared timeout self-settles;
37
+ a read that declares none is unbounded — the author bounds it with a `timeout`.
38
+ */
32
39
  while (inflight.size > 0) {
33
- const { key, snapshot } = await Promise.race(inflight.values())
34
- inflight.delete(key)
35
- yield snapshot ?? { key, miss: true }
40
+ const settled = await Promise.race(inflight.values())
41
+ inflight.delete(settled.key)
42
+ yield settled.snapshot ?? { key: settled.key, miss: true }
36
43
  }
37
44
  }
@@ -1,3 +1,4 @@
1
+ import { abideLog } from '../../shared/abideLog.ts'
1
2
  import { messageFromError } from '../../shared/messageFromError.ts'
2
3
 
3
4
  /*
@@ -27,6 +28,11 @@ export function streamFromIterator<T>(
27
28
  const textEncoder = new TextEncoder()
28
29
  const iterator = iterable[Symbol.asyncIterator]()
29
30
  let keepalive: ReturnType<typeof setInterval> | undefined
31
+ /* Set once the stream closes or is cancelled. A `pull` parked on `iterator.next()`
32
+ resolves AFTER a client-disconnect `cancel()` has already closed the controller;
33
+ without this guard it would touch the dead controller and throw "Controller is
34
+ already closed" — noise on every mid-frame disconnect. */
35
+ let closed = false
30
36
 
31
37
  function stopKeepalive(): void {
32
38
  if (keepalive !== undefined) {
@@ -65,20 +71,42 @@ export function streamFromIterator<T>(
65
71
  async pull(controller) {
66
72
  try {
67
73
  const next = await iterator.next()
74
+ /* Cancelled during the awaited next() — the controller is already closed,
75
+ so any close/enqueue here would throw. Nothing left to do. */
76
+ if (closed) {
77
+ return
78
+ }
68
79
  if (next.done) {
80
+ closed = true
69
81
  stopKeepalive()
70
82
  controller.close()
71
83
  return
72
84
  }
73
85
  controller.enqueue(textEncoder.encode(encoder.encodeFrame(next.value)))
74
86
  } catch (error) {
87
+ /* A throw during cancellation unwinding (the generator's `finally` rejecting
88
+ as `.return()` runs) is not a real stream error — the controller is gone. */
89
+ if (closed) {
90
+ return
91
+ }
92
+ /* Log the FULL error server-side (host/credentials/stack an operator needs) — the
93
+ unary rpc path does the same, and the jsonl/sse docs promise it. Only the
94
+ sanitized message crosses the wire in the sentinel error frame. */
95
+ abideLog.error(error)
75
96
  const message = messageFromError(error)
76
- controller.enqueue(textEncoder.encode(encoder.encodeError(message)))
97
+ closed = true
77
98
  stopKeepalive()
78
- controller.close()
99
+ try {
100
+ controller.enqueue(textEncoder.encode(encoder.encodeError(message)))
101
+ controller.close()
102
+ } catch {
103
+ /* Consumer vanished between the throw and the sentinel frame — the error
104
+ frame never lands, but the connection is already closing regardless. */
105
+ }
79
106
  }
80
107
  },
81
108
  cancel(reason) {
109
+ closed = true
82
110
  stopKeepalive()
83
111
  /*
84
112
  Route cancel into the generator's normal exit, but swallow a
@@ -0,0 +1,23 @@
1
+ import { NO_STORE } from '../../shared/CACHE_CONTROL_VALUES.ts'
2
+ import { TEXT_PLAIN } from '../../shared/TEXT_PLAIN.ts'
3
+ import { STATUS_TEXT } from './STATUS_TEXT.ts'
4
+
5
+ /*
6
+ The framework's plain-text status response — a `text/plain`, `no-store` body at
7
+ `status`, shared by the 404/405 dispatch branches, the asset servers' miss, and
8
+ the failed-upgrade reply so those literals can't drift. `body` defaults to the
9
+ status reason phrase (STATUS_TEXT, e.g. 'Not Found'), falling back to `HTTP
10
+ <status>` for an unlisted code. `extraHeaders` overlays the defaults per-key —
11
+ the 405 passes `Allow` this way. A fresh Response per call: a body is
12
+ single-use, so it can't be hoisted to a shared const.
13
+ */
14
+ export function textResponse(
15
+ status: number,
16
+ body?: string,
17
+ extraHeaders?: Record<string, string>,
18
+ ): Response {
19
+ return new Response(body ?? STATUS_TEXT[status] ?? `HTTP ${status}`, {
20
+ status,
21
+ headers: { 'Content-Type': TEXT_PLAIN, 'Cache-Control': NO_STORE, ...extraHeaders },
22
+ })
23
+ }
@@ -1,18 +1,14 @@
1
1
  /*
2
2
  The dev live-reload stamp the worker announces on the channel, split so the
3
3
  browser keeps its page across edits that don't need a reload:
4
- - `structure` fingerprints everything EXCEPT the entry stylesheet and the
5
- hot-swappable component bodies non-component source, public assets, the
6
- shell, the component-id set, and non-hot component bodies (pages, layouts,
7
- import-bearing components). Any change here reloads.
8
- - `cssHref` is the entry stylesheet's current content-hashed URL; a change
9
- here alone swaps the `<link>` in place. Undefined when no stylesheet is built.
10
- - `components` maps each hot-swappable (leaf child) component's module id to a
11
- hash of its client build (style-independent). A change here alone fetches the
12
- component's hot module and replaces its live instances — no reload.
4
+ - `structure` fingerprints every source signal a reload must react to — each
5
+ `.abide`'s client build hash (no CSS), the component-id set, non-`.abide`
6
+ source, public assets, and the shell (with the stylesheet href normalised out).
7
+ Any change here reloads.
8
+ - `cssHref` is the entry stylesheet's current content-hashed URL; a change here
9
+ alone swaps the `<link>` in place. Undefined when no stylesheet is built.
13
10
  */
14
11
  export type DevReloadStamp = {
15
12
  structure: string
16
13
  cssHref: string | undefined
17
- components: Record<string, string>
18
14
  }
@@ -19,6 +19,6 @@ export type InspectorCacheEntry = {
19
19
  tags: string[]
20
20
  /* A short JSON preview of the decoded warm value, when the entry holds one. */
21
21
  value: string | undefined
22
- /* An armed swr policy (`swr`, optionally + throttle/debounce + ms), if declared. */
22
+ /* An armed refetch policy (`refetch`, optionally + throttle/debounce + ms), if declared. */
23
23
  policy: string | undefined
24
24
  }
@@ -1,4 +1,7 @@
1
1
  import type { CacheStore } from '../../../shared/types/CacheStore.ts'
2
+ import type { PendingAsyncCells } from '../../../shared/types/PendingAsyncCells.ts'
3
+ import type { ResolvedCells } from '../../../shared/types/ResolvedCells.ts'
4
+ import type { StreamedCells } from '../../../shared/types/StreamedCells.ts'
2
5
  import type { TraceContext } from '../../../shared/types/TraceContext.ts'
3
6
  import type { Scope } from '../../../ui/types/Scope.ts'
4
7
 
@@ -14,6 +17,30 @@ export type RequestStore = {
14
17
  req: Request
15
18
  cache: CacheStore
16
19
  /*
20
+ In-flight async-cell promises registered during this request's SSR pass. The
21
+ Tier-2 barrier (`settleAsyncCells`) drains and awaits them between a
22
+ component's cell declarations and its template so resolved values bake into
23
+ the HTML. Per-request (like `cache`) so concurrent renders never share a drain.
24
+ */
25
+ pendingAsyncCells: PendingAsyncCells
26
+ /*
27
+ Async-cell values that RESOLVED during this request's SSR pass, keyed by render-path id.
28
+ `createAsyncCell.settleValue` pushes each; the page renderer stamps them into `__SSR__.cells`
29
+ (ref-json) so the client hydrates the cell warm. Sibling of `pendingAsyncCells` (the barrier's
30
+ in-flight list) — this one holds settled VALUES, read at render-return, not awaited.
31
+ */
32
+ resolvedCells: ResolvedCells
33
+ /*
34
+ STREAMING async-cell settled VALUES recorded during this request's SSR pass, keyed by render-path
35
+ id (ADR-0035). A streaming cell ships pending in the shell; the page renderer drains this after the
36
+ shell and streams an `__abideResolve({ cellKey, value })` chunk for each so the client adopts the
37
+ resolved value post-hydration. These are already-settled values (pushed by `createAsyncCell`),
38
+ never awaited here — a cell that stays pending through the request is simply not recorded and the
39
+ client cold-runs it (awaiting one would hang the response). Per-request so concurrent renders never
40
+ mix. Sibling of `resolvedCells` (the blocking partition baked into the head snapshot).
41
+ */
42
+ streamedCells: StreamedCells
43
+ /*
17
44
  W3C trace position: inbound `traceparent` continued (prefer-incoming) or a
18
45
  fresh sampled trace minted at the boundary. Read by trace()/log via the
19
46
  request-scope resolver and stamped into __SSR__ for the browser half.
@@ -1,4 +1,5 @@
1
1
  import { abideLog } from '../../shared/abideLog.ts'
2
+ import { MCP_PATH } from '../../shared/MCP_PATH.ts'
2
3
  import { rpcRegistry } from '../rpc/rpcRegistry.ts'
3
4
  import { socketRegistry } from '../sockets/socketRegistry.ts'
4
5
  import { ensureRegistriesLoaded } from './registryManifests.ts'
@@ -18,15 +19,24 @@ export async function warnUnguardedMcp(): Promise<void> {
18
19
  } catch {
19
20
  return
20
21
  }
21
- const isMcpExposed = (entry: { clients: { mcp: boolean } }): boolean => entry.clients.mcp
22
- const exposed = [...rpcRegistry.values(), ...socketRegistry.values()].filter(
23
- isMcpExposed,
24
- ).length
22
+ /* Rpc entries carry the resolved clients on `entry.remote` (ADR-0020); socket entries
23
+ keep their own `entry.clients`. Count each from its own home. */
24
+ let exposed = 0
25
+ for (const entry of rpcRegistry.values()) {
26
+ if (entry.remote.clients.mcp) {
27
+ exposed += 1
28
+ }
29
+ }
30
+ for (const entry of socketRegistry.values()) {
31
+ if (entry.clients.mcp) {
32
+ exposed += 1
33
+ }
34
+ }
25
35
  if (exposed === 0) {
26
36
  return
27
37
  }
28
38
  abideLog.warn(
29
- `MCP endpoint /__abide/mcp exposes ${exposed} declaration${exposed === 1 ? '' : 's'} ` +
39
+ `MCP endpoint ${MCP_PATH} exposes ${exposed} declaration${exposed === 1 ? '' : 's'} ` +
30
40
  'with no auth guard — add an app.handle middleware in src/app.ts to ' +
31
41
  'authenticate machine clients, or set clients.mcp: false per declaration',
32
42
  )
@@ -1,6 +1,6 @@
1
1
  import type { ServerWebSocket } from 'bun'
2
2
  import { abideLog } from '../../shared/abideLog.ts'
3
- import { decodeRefJson } from '../../shared/decodeRefJson.ts'
3
+ import { decodeWireBody } from '../../shared/decodeWireBody.ts'
4
4
  import { encodeRefJson } from '../../shared/encodeRefJson.ts'
5
5
  import { memoizeByKey } from '../../shared/memoizeByKey.ts'
6
6
  import { messageFromError } from '../../shared/messageFromError.ts'
@@ -245,7 +245,7 @@ export function createSocketDispatcher(sockets: SocketRoutes): SocketDispatcher
245
245
  the process down.
246
246
  */
247
247
  try {
248
- entry.socket.broadcast(frame.message)
248
+ entry.socket.publish(frame.message)
249
249
  } catch (publishError) {
250
250
  abideLog.error(publishError)
251
251
  }
@@ -309,7 +309,7 @@ export function createSocketDispatcher(sockets: SocketRoutes): SocketDispatcher
309
309
  }
310
310
  try {
311
311
  // publish() validates against the socket schema and throws on a bad payload.
312
- entry.socket.broadcast(message)
312
+ entry.socket.publish(message)
313
313
  } catch (publishError) {
314
314
  return error(422, messageFromError(publishError))
315
315
  }
@@ -338,14 +338,12 @@ export function createSocketDispatcher(sockets: SocketRoutes): SocketDispatcher
338
338
  const text = typeof data === 'string' ? data : textDecoder.decode(data)
339
339
  let frame: SocketClientFrame
340
340
  try {
341
- /* ref-json from abide's own client; a non-abide client sends a plain-JSON
342
- frame, which decodeRefJson rejects (a frame is always an object, never the
343
- `[rootValue, slots]` envelope) fall back to JSON.parse so raw WS clients work. */
344
- try {
345
- frame = decodeRefJson(text) as SocketClientFrame
346
- } catch {
347
- frame = JSON.parse(text) as SocketClientFrame
348
- }
341
+ /* No header rides a ws frame, so decodeWireBody sniffs: ref-json from abide's
342
+ own client, else a non-abide client's plain-JSON frame (which decodeRefJson
343
+ rejectsa frame is always an object, never the `[rootValue, slots]`
344
+ envelope — so it falls back to JSON.parse). A frame malformed under both
345
+ codecs throws here and is dropped. */
346
+ frame = decodeWireBody(text, undefined) as SocketClientFrame
349
347
  } catch {
350
348
  return
351
349
  }
@@ -24,8 +24,8 @@ is the live stream — no replay. `chat.tail(count)` opens a subscription
24
24
  seeded with the last `count` retained frames (no-arg = the whole
25
25
  retained tail, clamped to the declared `tail` size). When `ttl` is set,
26
26
  retained frames older than `ttl` ms are evicted lazily on every
27
- read/append — no timer runs in the background. `chat.broadcast(m)` is isomorphic —
28
- called server-side it both notifies in-process iterators and broadcasts
27
+ read/append — no timer runs in the background. `chat.publish(m)` is isomorphic —
28
+ called server-side it both notifies in-process iterators and fans out
29
29
  to remote subscribers; called client-side (via socketProxy) it sends a
30
30
  `pub` frame the dispatcher validates and forwards.
31
31
  */
@@ -178,8 +178,9 @@ export function defineSocket<T>(name: string, opts: SocketOptions = {}): Socket<
178
178
  const self = {
179
179
  name,
180
180
  clients,
181
- /* `broadcast` is the public fan-out; `publish` remains the internal function name. */
182
- broadcast: publish,
181
+ /* `publish` is the public fan-out (mirroring Bun's `server.publish()`); the internal
182
+ function shares the name. */
183
+ publish,
183
184
  tail: (count?: number, hooks?: TailHooks) => iterate(count ?? 'all', hooks),
184
185
  /* The latest retained frame (after ttl pruning), or undefined when none is held. */
185
186
  peek: () => {
@@ -24,6 +24,7 @@ EventSource surfaces this via its `error` listener and `tail()`
24
24
  maps it to the entry's `error` field.
25
25
  */
26
26
  import { NO_STORE } from '../shared/CACHE_CONTROL_VALUES.ts'
27
+ import { encodeWireBody } from '../shared/encodeWireBody.ts'
27
28
  import { sseErrorFrame } from '../shared/sseErrorFrame.ts'
28
29
  import type { TypedResponse } from './rpc/types/TypedResponse.ts'
29
30
  import { streamFromIterator } from './runtime/streamFromIterator.ts'
@@ -37,7 +38,10 @@ export function sse<Frame>(
37
38
  init?: ResponseInit,
38
39
  ): TypedResponse<AsyncIterable<Frame>> {
39
40
  const body = streamFromIterator(iterable, {
40
- encodeFrame: (value) => `data: ${JSON.stringify(value)}\n\n`,
41
+ /* Honest-JSON encode (same encoder as `json()`) so a frame carrying a Set/Map/bigint
42
+ crosses losslessly instead of the silent `{}` / bigint-throw plain JSON.stringify gave
43
+ — parseSse's JSON.parse reads it unchanged since the wire stays honest JSON. */
44
+ encodeFrame: (value) => `data: ${encodeWireBody(value)}\n\n`,
41
45
  encodeError: (message) => sseErrorFrame.encode(message),
42
46
  keepaliveMs: KEEPALIVE_INTERVAL_MS,
43
47
  keepalivePayload: ': keepalive\n\n',
@@ -0,0 +1,5 @@
1
+ /* Brand on an async cell's facet (`AsyncComputed`/`AsyncState`). The probe family
2
+ (`peek`/`pending`/`refreshing`/`refresh`) tests for it to route a cell to its own
3
+ methods, the way `Symbol.asyncIterator` routes a stream. A well-known symbol (not a
4
+ string key) so it never collides with a resolved value's own properties. */
5
+ export const ASYNC_CELL: unique symbol = Symbol.for('abide.asyncCell')
@@ -0,0 +1,6 @@
1
+ /*
2
+ Dev-only manual-rebuild trigger: POSTing here signals the orchestrator to rebuild +
3
+ restart. Mounted only under `abide dev`. Shared so the router mount and the launcher's
4
+ "POST … to apply" hint name the one path.
5
+ */
6
+ export const DEV_REBUILD_PATH = '/__abide/reload'
@@ -0,0 +1,6 @@
1
+ /*
2
+ The canonical RPC/HTTP verbs abide understands. One source of truth so the `HttpMethod`
3
+ type, the loader's rpc-export detection, and the compiler's helper set can't drift on which
4
+ export names are rpc entrypoints.
5
+ */
6
+ export const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD'] as const
@@ -14,11 +14,7 @@ export class HttpError extends Error {
14
14
  payload it carried — parsed off the `{ $abideError, data }` body by decodeResponse.
15
15
  `data` is typed `unknown` (a throw can't carry the rpc's per-kind type to the
16
16
  catch); narrow it yourself — for `kind: 'validation'` the shape is the exported
17
- `ValidationErrorData` (`{ issues, fields }`). Both undefined for a plain `error(status, text)`.
18
- The framework also reserves `kind: 'queued'` for a durable (`outbox: true`) call
19
- parked because the server was unreachable — `data` then holds the parked OutboxEntry,
20
- so `(error.data as OutboxEntry).settled` awaits the eventual delivered result or
21
- server refusal (the entry's own `error` carries the underlying cause). */
17
+ `ValidationErrorData` (`{ issues, fields }`). Both undefined for a plain `error(status, text)`. */
22
18
  readonly kind?: string
23
19
  readonly data?: unknown
24
20
 
@@ -0,0 +1,6 @@
1
+ /*
2
+ The MCP endpoint: inbound JSON-RPC over HTTP delegated to the app's `McpServer.handle`,
3
+ mounted only when an `mcp` is configured. Framework-internal (`/__abide/*`). Shared so the
4
+ router mount and the boot-time disclosure warning name the one path.
5
+ */
6
+ export const MCP_PATH = '/__abide/mcp'
@@ -0,0 +1,15 @@
1
+ /*
2
+ Single source of truth for the proxied/server-only split. These are the only
3
+ subdirectories under src/server/ whose modules the client bundle replaces with
4
+ proxy stubs instead of shipping their real source: src/server/rpc (each
5
+ HTTP-method handler → remoteProxy) and src/server/sockets (each socket
6
+ declaration → socketProxy). Every OTHER module under src/server/ is server-only
7
+ and must never reach the browser bundle.
8
+
9
+ Expressed as bare `src/server/`-relative segments so each caller joins them
10
+ against its own base — the resolver plugin against the absolute serverDir, the
11
+ dev orchestrator's changeAffectsClient against the `server/` string prefix —
12
+ rather than re-spelling the set. Adding a proxied directory is one edit here and
13
+ both side-classifiers move in lockstep.
14
+ */
15
+ export const PROXIED_SERVER_SUBDIRS = ['rpc', 'sockets'] as const
@@ -26,6 +26,18 @@ export const REF_JSON_TAGS = {
26
26
  BIGINT: '~g',
27
27
  // ['~u'] — undefined (and functions/symbols, folded to it).
28
28
  UNDEFINED: '~u',
29
- // ['~n', token] — the numbers JSON flattens to null: 'NaN' | 'Infinity' | '-Infinity' | '-0'.
29
+ // ['~n', token] — the numbers JSON flattens to null; the token is one of REF_JSON_NUMBER_TOKENS.
30
30
  NUMBER: '~n',
31
31
  } as const
32
+
33
+ /*
34
+ The tokens carried by a `['~n', token]` tag — the numbers JSON can't represent. Shared by
35
+ `encodeRefJson`'s `numberToken` (produces them) and `decodeRefJson`'s `decodeNumberToken`
36
+ (parses them) so the wire form can't drift between the two ends.
37
+ */
38
+ export const REF_JSON_NUMBER_TOKENS = {
39
+ NAN: 'NaN',
40
+ INFINITY: 'Infinity',
41
+ NEG_INFINITY: '-Infinity',
42
+ NEG_ZERO: '-0',
43
+ } as const
@@ -0,0 +1,9 @@
1
+ /*
2
+ The reserved global alias names the `$rpc`/`$socket` module rewrites target: the bundler's
3
+ banner binds each (`import { defineRpc as __abideDefineRpc__ }`, see abideResolverPlugin) and
4
+ the codegen emit (`prepareRpcModule` / `prepareSocketModule`) calls it. Shared so the emitted
5
+ call and the banner binding can't drift into an unbound-name ReferenceError at load.
6
+ */
7
+ export const DEFINE_RPC_GLOBAL = '__abideDefineRpc__'
8
+ export const REMOTE_PROXY_GLOBAL = '__abideRemoteProxy__'
9
+ export const DEFINE_SOCKET_GLOBAL = '__abideDefineSocket__'
@@ -7,5 +7,6 @@ lazily-created fallback when none is registered (so isolated tests work). The
7
7
  fallback creator guarantees a value, hence the non-null assertion.
8
8
  */
9
9
  export function activeCacheStore(): CacheStore {
10
+ // biome-ignore lint/style/noNonNullAssertion: the slot's lazy fallback creator always returns a store
10
11
  return cacheStoreSlot.get()!
11
12
  }
@@ -7,5 +7,6 @@ single lazily-created empty snapshot when none is registered (so isolated tests
7
7
  work). The fallback creator guarantees a value, hence the non-null assertion.
8
8
  */
9
9
  export function activePage(): PageSnapshot {
10
+ // biome-ignore lint/style/noNonNullAssertion: the slot's lazy fallback creator always returns a snapshot
10
11
  return pageSlot.get()!
11
12
  }
@@ -0,0 +1,20 @@
1
+ import type { BuildConfig, BuildOutput } from 'bun'
2
+ import { exitOnBuildFailure } from './exitOnBuildFailure.ts'
3
+
4
+ /*
5
+ Runs one Bun.build and fails the process on any diagnostic, returning the
6
+ successful output — the build-or-die pairing every one-shot build site shares
7
+ (compile, buildCli's discovery + cli, bundleApp, buildDisconnected). Keeps the
8
+ `Bun.build` + `exitOnBuildFailure` step atomic so a new build site can't ship
9
+ without the failure check. The incremental client build (build.ts) does NOT use
10
+ this: it must clean its staging dir and return `false` rather than exit, so it
11
+ keeps its own epilogue.
12
+ */
13
+ export async function buildArtifact(config: BuildConfig): Promise<BuildOutput> {
14
+ /* metafile: true so the abideResolverPlugin's onEnd reachability guard (ADR-0022 D3) can read
15
+ the post-DCE graph on a client build (buildDisconnected). Harmless extra output on the
16
+ server builds that also route through here. A caller can still override it explicitly. */
17
+ const result = await Bun.build({ metafile: true, ...config })
18
+ exitOnBuildFailure(result)
19
+ return result
20
+ }
@@ -68,8 +68,12 @@ function appendQuery(method: HttpMethod, url: string, args: unknown): string {
68
68
  if (args === undefined) {
69
69
  return url
70
70
  }
71
- if (typeof args !== 'object' || args === null || Array.isArray(args)) {
72
- const got = Array.isArray(args) ? 'array' : typeof args
71
+ const isFormData = typeof FormData !== 'undefined' && args instanceof FormData
72
+ if (typeof args !== 'object' || args === null || Array.isArray(args) || isFormData) {
73
+ /* FormData has no own enumerable keys, so `queryStringFromArgs` would silently drop
74
+ every field; a query-carrying method (GET/DELETE/HEAD) can't take a body anyway.
75
+ Fail loudly like any other non-plain-object arg. */
76
+ const got = Array.isArray(args) ? 'array' : isFormData ? 'FormData' : typeof args
73
77
  throw new Error(`[abide] ${method} ${url} args must be a plain object — got ${got}`)
74
78
  }
75
79
  const suffix = queryStringFromArgs(args as Record<string, unknown>, false)
@@ -63,9 +63,10 @@ export function buildSocketOverChannel<T>(
63
63
  const socket = {
64
64
  name,
65
65
  clients: browserClientFlags,
66
- /* `broadcast` sends a server-validated `pub` frame (the dispatcher gates it on the
67
- topic's `clientPublish`); `publish` is the internal channel-send function name. */
68
- broadcast: publish,
66
+ /* `publish` sends a server-validated `pub` frame (the dispatcher gates it on the
67
+ topic's `clientPublish`), mirroring Bun's `server.publish()`; the internal
68
+ channel-send function shares the name. */
69
+ publish,
69
70
  tail: (count?: number, hooks?: TailHooks) => iterate(count, hooks),
70
71
  /* The latest frame this client has seen, synchronously. */
71
72
  peek: () => lastFrame,
@@ -0,0 +1,68 @@
1
+ import { resolve } from 'node:path'
2
+ import type { BuildMetafile } from 'bun'
3
+
4
+ /* One surviving module in the post-DCE bundle graph: its absolute path and input source byte
5
+ size. `bytes` is the metafile's `inputs[key].bytes` — the source weight the budget diagnostic
6
+ measures (a tree-shaken module is absent from the metafile entirely, so every module here
7
+ SURVIVED into the bundle). */
8
+ type BundleGraphModule = {
9
+ path: string
10
+ bytes: number
11
+ }
12
+
13
+ /*
14
+ The post-DCE module graph reconstructed from a client build's `Bun.build` metafile — the reusable
15
+ analysis seam ADR-0031 D2 factors out. `metafile.inputs` is the DCE-accurate graph (a
16
+ textually-imported but tree-shaken module is ABSENT), so a single walk yields both the surviving
17
+ modules and their child→importer edges; consumers then judge the graph without re-walking it.
18
+ Two ride it today: the side-crossing reachability guard (a surviving server-only module is a
19
+ violation) and the bundle-budget diagnostic (a surviving input over a size budget is a warning).
20
+ The metafile carries module presence + input byte size, NOT export-level liveness — so a consumer
21
+ can judge "this module survived / is this big", not "this export is unused" (ADR-0031 D2 spike).
22
+ */
23
+ export type BundleGraph = {
24
+ /* Every module present in the post-DCE graph, keyed by absolute path. */
25
+ modules: BundleGraphModule[]
26
+ /* The import chain from a graph root down to `target`, in root→target order (absolute paths),
27
+ reconstructed from the graph's own first-wins child→importer edges — one witness, cycle-safe.
28
+ Returns `[target]` when nothing imports it (a graph root). */
29
+ importerChain(target: string): string[]
30
+ }
31
+
32
+ /*
33
+ Walks a client build's metafile once into a `BundleGraph`. `inputs` keys are relative to
34
+ `process.cwd()` while edge `path`s are absolute, so each module path is resolved against `cwd` to
35
+ match on absolute paths throughout. First edge wins for the importer map — enough to render one
36
+ witness chain, and cheap.
37
+ */
38
+ export function bundleGraphFromMetafile(metafile: BuildMetafile, cwd: string): BundleGraph {
39
+ const modules: BundleGraphModule[] = []
40
+ /* child(absolute) → its importer(absolute); first edge wins — one witness chain. */
41
+ const importerOf = new Map<string, string>()
42
+ for (const [key, input] of Object.entries(metafile.inputs)) {
43
+ const modulePath = resolve(cwd, key)
44
+ modules.push({ path: modulePath, bytes: input.bytes })
45
+ for (const edge of input.imports) {
46
+ if (!importerOf.has(edge.path)) {
47
+ importerOf.set(edge.path, modulePath)
48
+ }
49
+ }
50
+ }
51
+ return {
52
+ modules,
53
+ importerChain(target) {
54
+ const chain = [target]
55
+ const seen = new Set([target])
56
+ let cursor = target
57
+ while (importerOf.has(cursor)) {
58
+ cursor = importerOf.get(cursor) as string
59
+ if (seen.has(cursor)) {
60
+ break
61
+ }
62
+ seen.add(cursor)
63
+ chain.push(cursor)
64
+ }
65
+ return chain.reverse()
66
+ },
67
+ }
68
+ }