@abide/abide 0.49.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 (325) hide show
  1. package/AGENTS.md +70 -52
  2. package/CHANGELOG.md +177 -0
  3. package/README.md +12 -7
  4. package/package.json +14 -5
  5. package/src/abideLsp.ts +5 -6
  6. package/src/abideResolverPlugin.ts +197 -169
  7. package/src/build.ts +79 -56
  8. package/src/buildDisconnected.ts +0 -2
  9. package/src/checkAbide.ts +12 -2
  10. package/src/devEntry.ts +113 -28
  11. package/src/discoveryEntry.ts +3 -2
  12. package/src/lib/bundle/disconnected.abide +69 -73
  13. package/src/lib/bundle/infoPlist.ts +13 -7
  14. package/src/lib/bundle/spawnEmbeddedServer.ts +13 -4
  15. package/src/lib/bundle/waitForServer.ts +6 -1
  16. package/src/lib/mcp/mcpTools.ts +15 -6
  17. package/src/lib/server/error.ts +6 -6
  18. package/src/lib/server/json.ts +17 -3
  19. package/src/lib/server/rpc/defineRpc.ts +58 -24
  20. package/src/lib/server/rpc/parseArgs.ts +98 -13
  21. package/src/lib/server/rpc/resolveRpcJsonSchema.ts +28 -0
  22. package/src/lib/server/rpc/types/RpcHelper.ts +75 -105
  23. package/src/lib/server/rpc/types/RpcRegistryEntry.ts +24 -9
  24. package/src/lib/server/rpc/validationError.ts +1 -1
  25. package/src/lib/server/runtime/DEV_RELOAD_CLIENT_SCRIPT.ts +0 -15
  26. package/src/lib/server/runtime/buildCacheSnapshot.ts +10 -9
  27. package/src/lib/server/runtime/buildInspectorSurface.ts +6 -4
  28. package/src/lib/server/runtime/buildOpenApiSpec.ts +55 -11
  29. package/src/lib/server/runtime/buildPreloadManifest.ts +12 -10
  30. package/src/lib/server/runtime/createAppAssetServer.ts +18 -15
  31. package/src/lib/server/runtime/createAppRouteResolver.ts +145 -0
  32. package/src/lib/server/runtime/createPlumbingRouter.ts +212 -0
  33. package/src/lib/server/runtime/createRouteDispatcher.ts +4 -10
  34. package/src/lib/server/runtime/createServer.ts +120 -324
  35. package/src/lib/server/runtime/createUiPageRenderer.ts +137 -26
  36. package/src/lib/server/runtime/devClientFingerprint.ts +19 -34
  37. package/src/lib/server/runtime/installAmbientScopeStore.ts +30 -9
  38. package/src/lib/server/runtime/logExposedSurfaces.ts +8 -7
  39. package/src/lib/server/runtime/pathStore.ts +15 -0
  40. package/src/lib/server/runtime/registryManifests.ts +1 -1
  41. package/src/lib/server/runtime/renderCellBarrierStore.ts +15 -0
  42. package/src/lib/server/runtime/runWithRequestScope.ts +3 -0
  43. package/src/lib/server/runtime/serializeCacheSnapshot.ts +6 -4
  44. package/src/lib/server/runtime/snapshotEntryFromCache.ts +14 -14
  45. package/src/lib/server/runtime/streamCacheResolutions.ts +14 -7
  46. package/src/lib/server/runtime/streamFromIterator.ts +30 -2
  47. package/src/lib/server/runtime/textResponse.ts +23 -0
  48. package/src/lib/server/runtime/types/DevReloadStamp.ts +6 -10
  49. package/src/lib/server/runtime/types/InspectorCacheEntry.ts +1 -1
  50. package/src/lib/server/runtime/types/RequestStore.ts +27 -0
  51. package/src/lib/server/runtime/warnUnguardedMcp.ts +15 -5
  52. package/src/lib/server/sockets/createSocketDispatcher.ts +9 -11
  53. package/src/lib/server/sockets/defineSocket.ts +5 -4
  54. package/src/lib/server/sse.ts +5 -1
  55. package/src/lib/shared/ASYNC_CELL.ts +5 -0
  56. package/src/lib/shared/DEV_REBUILD_PATH.ts +6 -0
  57. package/src/lib/shared/HTTP_METHODS.ts +6 -0
  58. package/src/lib/shared/HttpError.ts +1 -5
  59. package/src/lib/shared/MCP_PATH.ts +6 -0
  60. package/src/lib/shared/PROXIED_SERVER_SUBDIRS.ts +15 -0
  61. package/src/lib/shared/REF_JSON_TAGS.ts +13 -1
  62. package/src/lib/shared/RPC_SHIM_GLOBALS.ts +9 -0
  63. package/src/lib/shared/activeCacheStore.ts +1 -0
  64. package/src/lib/shared/activePage.ts +1 -0
  65. package/src/lib/shared/buildArtifact.ts +4 -1
  66. package/src/lib/shared/buildSocketOverChannel.ts +4 -3
  67. package/src/lib/shared/bundleGraphFromMetafile.ts +68 -0
  68. package/src/lib/shared/cache.ts +156 -131
  69. package/src/lib/shared/changeAffectsClient.ts +12 -7
  70. package/src/lib/shared/createCacheStore.ts +31 -8
  71. package/src/lib/shared/createLifecycleChannel.ts +7 -1
  72. package/src/lib/shared/createReachable.ts +47 -78
  73. package/src/lib/shared/createRemoteFunction.ts +52 -30
  74. package/src/lib/shared/createRpcServerProgram.ts +820 -0
  75. package/src/lib/shared/decodeRefJson.ts +4 -4
  76. package/src/lib/shared/decodeResponse.ts +2 -2
  77. package/src/lib/shared/decodeWireBody.ts +35 -0
  78. package/src/lib/shared/detectRpcMethod.ts +8 -1
  79. package/src/lib/shared/done.ts +8 -2
  80. package/src/lib/shared/encodeRefJson.ts +4 -4
  81. package/src/lib/shared/encodeWireBody.ts +18 -0
  82. package/src/lib/{server/rpc → shared}/fieldErrorsFromIssues.ts +5 -1
  83. package/src/lib/shared/generateDeclarations.ts +72 -0
  84. package/src/lib/shared/hasSeedableRequest.ts +25 -0
  85. package/src/lib/shared/hydrationWindow.ts +53 -0
  86. package/src/lib/shared/isAsyncCell.ts +11 -0
  87. package/src/lib/shared/isAsyncIterable.ts +8 -0
  88. package/src/lib/shared/isSubscribable.ts +3 -3
  89. package/src/lib/shared/isThenable.ts +9 -0
  90. package/src/lib/shared/jsonSchemaForType.ts +258 -0
  91. package/src/lib/shared/lenientDecode.ts +15 -0
  92. package/src/lib/shared/loadProjectTsConfig.ts +28 -0
  93. package/src/lib/shared/markFrameworkSourcesIgnored.ts +1 -1
  94. package/src/lib/shared/matchRoute.ts +4 -14
  95. package/src/lib/shared/peek.ts +14 -0
  96. package/src/lib/shared/pending.ts +9 -6
  97. package/src/lib/shared/pendingAsyncCellsSlot.ts +13 -0
  98. package/src/lib/shared/prepareRpcModule.ts +91 -93
  99. package/src/lib/shared/prepareSocketModule.ts +3 -2
  100. package/src/lib/shared/probeRegistries.ts +5 -18
  101. package/src/lib/shared/reachable.ts +7 -10
  102. package/src/lib/shared/refresh.ts +12 -2
  103. package/src/lib/shared/refreshing.ts +8 -2
  104. package/src/lib/shared/resolvedCellsSlot.ts +13 -0
  105. package/src/lib/shared/reviveWireField.ts +49 -0
  106. package/src/lib/shared/reviveWireOutput.ts +36 -0
  107. package/src/lib/shared/rpcServerForRoot.ts +25 -0
  108. package/src/lib/shared/scanPages.ts +25 -0
  109. package/src/lib/shared/snapshotShippable.ts +8 -7
  110. package/src/lib/shared/streamedCellsSlot.ts +14 -0
  111. package/src/lib/shared/subscribableFromResponse.ts +4 -4
  112. package/src/lib/shared/subscribableProbes.ts +1 -1
  113. package/src/lib/shared/tailProbeSlot.ts +1 -1
  114. package/src/lib/shared/types/AsyncComputed.ts +20 -0
  115. package/src/lib/shared/types/AsyncState.ts +13 -0
  116. package/src/lib/shared/types/CacheEntry.ts +7 -7
  117. package/src/lib/shared/types/CacheOptions.ts +23 -37
  118. package/src/lib/shared/types/CachePolicy.ts +25 -0
  119. package/src/lib/shared/types/CacheSnapshotEntry.ts +6 -5
  120. package/src/lib/shared/types/ErrorJsonSchemas.ts +8 -0
  121. package/src/lib/shared/types/HttpMethod.ts +3 -1
  122. package/src/lib/shared/types/InputCoercion.ts +17 -0
  123. package/src/lib/shared/types/{Subscribable.ts → NamedAsyncIterable.ts} +1 -1
  124. package/src/lib/shared/types/OutputWirePlan.ts +17 -0
  125. package/src/lib/shared/types/PagesScan.ts +7 -0
  126. package/src/lib/shared/types/PendingAsyncCells.ts +10 -0
  127. package/src/lib/shared/types/RawRemoteFunction.ts +6 -0
  128. package/src/lib/shared/types/RemoteCallable.ts +8 -7
  129. package/src/lib/shared/types/RemoteFunction.ts +16 -15
  130. package/src/lib/shared/types/ResolvedCells.ts +11 -0
  131. package/src/lib/shared/types/ReturnBody.ts +15 -0
  132. package/src/lib/shared/types/RpcBuildStamps.ts +23 -0
  133. package/src/lib/shared/types/RpcErrorGuard.ts +3 -8
  134. package/src/lib/shared/types/Socket.ts +4 -4
  135. package/src/lib/shared/types/SsrPayload.ts +5 -1
  136. package/src/lib/shared/types/StreamPolicy.ts +11 -0
  137. package/src/lib/shared/types/StreamedCells.ts +19 -0
  138. package/src/lib/shared/types/StreamedResolution.ts +24 -6
  139. package/src/lib/shared/types/TailHooks.ts +1 -1
  140. package/src/lib/shared/types/WireKind.ts +11 -0
  141. package/src/lib/shared/validationHttpError.ts +33 -0
  142. package/src/lib/shared/warmSeedKey.ts +16 -0
  143. package/src/lib/shared/wireJsonReplacer.ts +30 -0
  144. package/src/lib/shared/writeRpcDts.ts +11 -1
  145. package/src/lib/shared/writeTestSocketsDts.ts +1 -1
  146. package/src/lib/test/createTestApp.ts +19 -1
  147. package/src/lib/ui/README.md +1 -1
  148. package/src/lib/ui/activePendingCells.ts +14 -0
  149. package/src/lib/ui/compile/BLOCK_KEYWORDS.ts +21 -0
  150. package/src/lib/ui/compile/SSR_ESCAPE.ts +4 -1
  151. package/src/lib/ui/compile/UI_RUNTIME_IMPORTS.ts +35 -8
  152. package/src/lib/ui/compile/abideUiPlugin.ts +19 -2
  153. package/src/lib/ui/compile/analyzeComponent.ts +89 -6
  154. package/src/lib/ui/compile/assignmentTargetNames.ts +54 -0
  155. package/src/lib/ui/compile/asyncInterpolationFields.ts +152 -0
  156. package/src/lib/ui/compile/asyncValuePositionError.ts +21 -0
  157. package/src/lib/ui/compile/asyncValuePositionInterpolations.ts +64 -0
  158. package/src/lib/ui/compile/attrLiftPosition.ts +18 -0
  159. package/src/lib/ui/compile/cachedSourceFile.ts +40 -0
  160. package/src/lib/ui/compile/catchBinding.ts +7 -5
  161. package/src/lib/ui/compile/classifyInterpolationType.ts +46 -0
  162. package/src/lib/ui/compile/collectAbideDiagnostics.ts +96 -0
  163. package/src/lib/ui/compile/compileComponent.ts +19 -3
  164. package/src/lib/ui/compile/compileModule.ts +27 -58
  165. package/src/lib/ui/compile/compileSSR.ts +51 -12
  166. package/src/lib/ui/compile/compileShadow.ts +145 -18
  167. package/src/lib/ui/compile/composeProps.ts +12 -2
  168. package/src/lib/ui/compile/createShadowLanguageService.ts +116 -68
  169. package/src/lib/ui/compile/createShadowProgram.ts +35 -6
  170. package/src/lib/ui/compile/declaredNames.ts +36 -0
  171. package/src/lib/ui/compile/desugarSignals.ts +418 -36
  172. package/src/lib/ui/compile/expressionIsPrefixEvaluable.ts +19 -0
  173. package/src/lib/ui/compile/generateBuild.ts +52 -9
  174. package/src/lib/ui/compile/generateSSR.ts +242 -43
  175. package/src/lib/ui/compile/hoistableAwaits.ts +193 -0
  176. package/src/lib/ui/compile/hoistableChildRenders.ts +112 -0
  177. package/src/lib/ui/compile/interpolatedTemplateLiteral.ts +3 -1
  178. package/src/lib/ui/compile/interpolationClassifierForRoot.ts +37 -0
  179. package/src/lib/ui/compile/isSpuriousAsyncReadDiagnostic.ts +174 -0
  180. package/src/lib/ui/compile/liftAsyncSubExpressions.ts +166 -0
  181. package/src/lib/ui/compile/lowerAsyncInterpolations.ts +92 -0
  182. package/src/lib/ui/compile/lowerContext.ts +10 -0
  183. package/src/lib/ui/compile/lowerDocAccess.ts +26 -23
  184. package/src/lib/ui/compile/lowerScript.ts +40 -4
  185. package/src/lib/ui/compile/nodeAtShadowOffset.ts +28 -0
  186. package/src/lib/ui/compile/parseTemplate.ts +18 -1092
  187. package/src/lib/ui/compile/parseTemplateRecovering.ts +1385 -0
  188. package/src/lib/ui/compile/referencedIdentifiers.ts +35 -0
  189. package/src/lib/ui/compile/renameSignalRefs.ts +21 -22
  190. package/src/lib/ui/compile/seedTypeClassifierForRoot.ts +65 -0
  191. package/src/lib/ui/compile/shadowInterpolationClassifier.ts +47 -0
  192. package/src/lib/ui/compile/sourceFileOptionsSignature.ts +20 -0
  193. package/src/lib/ui/compile/structuralHeadTokens.ts +107 -0
  194. package/src/lib/ui/compile/templateSemanticTokens.ts +21 -0
  195. package/src/lib/ui/compile/templateStartOffset.ts +15 -0
  196. package/src/lib/ui/compile/tryPlan.ts +4 -3
  197. package/src/lib/ui/compile/types/AnalyzedComponent.ts +4 -0
  198. package/src/lib/ui/compile/types/AsyncInterpolationField.ts +19 -0
  199. package/src/lib/ui/compile/types/InterpolationClassifier.ts +12 -0
  200. package/src/lib/ui/compile/types/InterpolationKind.ts +7 -0
  201. package/src/lib/ui/compile/types/ParseDiagnostic.ts +8 -0
  202. package/src/lib/ui/compile/types/SeedTypeClassifier.ts +15 -0
  203. package/src/lib/ui/compile/types/TemplateNode.ts +36 -4
  204. package/src/lib/ui/compile/types/ValuePositionInterpolation.ts +13 -0
  205. package/src/lib/ui/compile/writtenTemplateNames.ts +84 -0
  206. package/src/lib/ui/computed.ts +28 -1
  207. package/src/lib/ui/createScope.ts +35 -68
  208. package/src/lib/ui/dom/anchoredBranch.ts +142 -0
  209. package/src/lib/ui/dom/appendText.ts +8 -3
  210. package/src/lib/ui/dom/awaitBlock.ts +43 -94
  211. package/src/lib/ui/dom/bindProp.ts +22 -0
  212. package/src/lib/ui/dom/bindableProp.ts +47 -0
  213. package/src/lib/ui/dom/cellPending.ts +24 -0
  214. package/src/lib/ui/dom/disposeRange.ts +2 -1
  215. package/src/lib/ui/dom/each.ts +26 -4
  216. package/src/lib/ui/dom/eachAsync.ts +39 -3
  217. package/src/lib/ui/dom/fillBoundary.ts +2 -3
  218. package/src/lib/ui/dom/fillRange.ts +4 -4
  219. package/src/lib/ui/dom/hydrate.ts +6 -12
  220. package/src/lib/ui/dom/isComment.ts +1 -1
  221. package/src/lib/ui/dom/matchingRangeClose.ts +29 -0
  222. package/src/lib/ui/dom/mount.ts +1 -2
  223. package/src/lib/ui/dom/mountChild.ts +9 -40
  224. package/src/lib/ui/dom/mountRange.ts +2 -3
  225. package/src/lib/ui/dom/mountStreamedChild.ts +84 -0
  226. package/src/lib/ui/dom/mountSwappableRange.ts +46 -4
  227. package/src/lib/ui/dom/mutateDocContainer.ts +65 -0
  228. package/src/lib/ui/dom/on.ts +2 -2
  229. package/src/lib/ui/dom/readCell.ts +40 -0
  230. package/src/lib/ui/dom/switchBlock.ts +30 -7
  231. package/src/lib/ui/dom/tryBlock.ts +230 -66
  232. package/src/lib/ui/dom/types/SwitchCase.ts +5 -1
  233. package/src/lib/ui/dom/when.ts +12 -2
  234. package/src/lib/ui/dom/withScope.ts +2 -2
  235. package/src/lib/ui/finalizeStreamedChildren.ts +89 -0
  236. package/src/lib/ui/flight.ts +56 -0
  237. package/src/lib/ui/html.ts +12 -1
  238. package/src/lib/ui/isolateCellBarrier.ts +17 -0
  239. package/src/lib/ui/linked.ts +48 -2
  240. package/src/lib/ui/remoteProxy.ts +84 -159
  241. package/src/lib/ui/renderChain.ts +49 -13
  242. package/src/lib/ui/renderToStream.ts +22 -18
  243. package/src/lib/ui/resumeSeedScript.ts +1 -1
  244. package/src/lib/ui/router.ts +63 -36
  245. package/src/lib/ui/runtime/AsyncCellError.ts +20 -0
  246. package/src/lib/ui/runtime/CELL_SEED.ts +14 -0
  247. package/src/lib/ui/runtime/CURRENT_BOUNDARY.ts +11 -0
  248. package/src/lib/ui/runtime/CURRENT_PATH.ts +29 -0
  249. package/src/lib/ui/runtime/RENDER.ts +10 -7
  250. package/src/lib/ui/runtime/RESUME.ts +4 -4
  251. package/src/lib/ui/runtime/STREAMED_CELLS.ts +57 -0
  252. package/src/lib/ui/runtime/ambientPathBacking.ts +32 -0
  253. package/src/lib/ui/runtime/applyPatchToTree.ts +1 -1
  254. package/src/lib/ui/runtime/blockId.ts +31 -0
  255. package/src/lib/ui/runtime/boundaryFor.ts +11 -0
  256. package/src/lib/ui/runtime/cellBarrierBacking.ts +30 -0
  257. package/src/lib/ui/runtime/createAsyncCell.ts +300 -0
  258. package/src/lib/ui/runtime/createDoc.ts +3 -42
  259. package/src/lib/ui/runtime/createEffectNode.ts +9 -0
  260. package/src/lib/ui/runtime/enterRenderPass.ts +5 -4
  261. package/src/lib/ui/runtime/flushEffects.ts +16 -6
  262. package/src/lib/ui/runtime/isAsyncFunction.ts +14 -0
  263. package/src/lib/ui/runtime/nextBlockId.ts +8 -7
  264. package/src/lib/ui/runtime/renderPath.ts +16 -0
  265. package/src/lib/ui/runtime/types/Boundary.ts +9 -0
  266. package/src/lib/ui/runtime/types/RenderContext.ts +9 -7
  267. package/src/lib/ui/runtime/types/SsrRender.ts +9 -2
  268. package/src/lib/ui/runtime/types/UiComponent.ts +1 -5
  269. package/src/lib/ui/runtime/withOptionalPath.ts +8 -0
  270. package/src/lib/ui/runtime/withPath.ts +16 -0
  271. package/src/lib/ui/runtime/withPathFrom.ts +20 -0
  272. package/src/lib/ui/seedStreamedResolution.ts +31 -6
  273. package/src/lib/ui/settleAsyncCells.ts +24 -0
  274. package/src/lib/ui/socketProxy.ts +1 -1
  275. package/src/lib/ui/startClient.ts +16 -31
  276. package/src/lib/ui/trackedComputed.ts +68 -0
  277. package/src/lib/ui/types/Scope.ts +8 -24
  278. package/src/lib/ui/watch.ts +3 -3
  279. package/src/serverEntry.ts +14 -0
  280. package/template/src/server/rpc/getHello.ts +15 -13
  281. package/template/test/app.test.ts +1 -1
  282. package/src/lib/server/runtime/devHotModuleResponse.ts +0 -41
  283. package/src/lib/shared/DEV_HOT_PREFIX.ts +0 -7
  284. package/src/lib/shared/UNREACHABLE_STATUSES.ts +0 -13
  285. package/src/lib/shared/hasReplayableRequest.ts +0 -17
  286. package/src/lib/shared/hydratingSlot.ts +0 -12
  287. package/src/lib/shared/outboxProbeSlot.ts +0 -20
  288. package/src/lib/shared/types/Outbox.ts +0 -9
  289. package/src/lib/shared/types/OutboxEntry.ts +0 -27
  290. package/src/lib/shared/types/SmartReadOptions.ts +0 -36
  291. package/src/lib/shared/wakeHydrationPeeks.ts +0 -20
  292. package/src/lib/ui/COMPONENT_WRAPPER_PREFIX.ts +0 -5
  293. package/src/lib/ui/compile/REACTIVE_CALLEES.ts +0 -11
  294. package/src/lib/ui/compile/assertRuntimeHelpersBound.ts +0 -80
  295. package/src/lib/ui/compile/markupTokens.ts +0 -313
  296. package/src/lib/ui/compile/structuralBlockTokens.ts +0 -100
  297. package/src/lib/ui/dom/applyResolved.ts +0 -87
  298. package/src/lib/ui/dom/mutateDocArray.ts +0 -38
  299. package/src/lib/ui/dom/scopeLabel.ts +0 -21
  300. package/src/lib/ui/dom/text.ts +0 -20
  301. package/src/lib/ui/history.ts +0 -108
  302. package/src/lib/ui/installHotBridge.ts +0 -95
  303. package/src/lib/ui/installInspectorBridge.ts +0 -140
  304. package/src/lib/ui/outbox.ts +0 -35
  305. package/src/lib/ui/persist.ts +0 -115
  306. package/src/lib/ui/rpcOutbox/createOutboxQueue.ts +0 -281
  307. package/src/lib/ui/rpcOutbox/outboxRegistry.ts +0 -69
  308. package/src/lib/ui/runtime/PATCH_BUS.ts +0 -28
  309. package/src/lib/ui/runtime/captureModelDoc.ts +0 -43
  310. package/src/lib/ui/runtime/hotInstances.ts +0 -10
  311. package/src/lib/ui/runtime/hotReloadEnabled.ts +0 -8
  312. package/src/lib/ui/runtime/hotReplace.ts +0 -38
  313. package/src/lib/ui/runtime/liveScopes.ts +0 -15
  314. package/src/lib/ui/runtime/localStoragePersistence.ts +0 -47
  315. package/src/lib/ui/runtime/registerHotInstance.ts +0 -23
  316. package/src/lib/ui/runtime/seedModelDoc.ts +0 -26
  317. package/src/lib/ui/runtime/types/HotInstance.ts +0 -22
  318. package/src/lib/ui/runtime/types/PatchEvent.ts +0 -16
  319. package/src/lib/ui/seedResolved.ts +0 -28
  320. package/src/lib/ui/sync.ts +0 -48
  321. package/src/lib/ui/types/History.ts +0 -14
  322. package/src/lib/ui/types/PersistHandle.ts +0 -11
  323. package/src/lib/ui/types/PersistenceStore.ts +0 -12
  324. package/src/lib/ui/types/ResolvedFrame.ts +0 -15
  325. package/src/lib/ui/types/SyncTransport.ts +0 -13
@@ -1,69 +0,0 @@
1
- import { canonicalJson } from '../../shared/canonicalJson.ts'
2
- import { outboxProbeSlot } from '../../shared/outboxProbeSlot.ts'
3
- import type { OutboxQueue } from './createOutboxQueue.ts'
4
-
5
- /* One registered durable RPC: its url, the RemoteFunction it belongs to (tag for the
6
- global aggregate), and its live queue. */
7
- type RegisteredOutbox = { url: string; rpc: unknown; queue: OutboxQueue<unknown> }
8
-
9
- /*
10
- Client registry of every durable RPC's outbox queue, keyed by url. A durable RPC
11
- (`outbox: true`) registers on first use so the global `outbox()` aggregate can
12
- flatten every queue and `pending()` can see queued entries. App-scoped, not component-
13
- scoped — the queues outlive any mount.
14
- */
15
- const registered = new Map<string, RegisteredOutbox>()
16
-
17
- export const outboxRegistry = {
18
- register(url: string, queue: OutboxQueue<unknown>, rpc: unknown): void {
19
- registered.set(url, { url, rpc, queue })
20
- },
21
- get(url: string): OutboxQueue<unknown> | undefined {
22
- return registered.get(url)?.queue
23
- },
24
- all(): RegisteredOutbox[] {
25
- return [...registered.values()]
26
- },
27
- /* Drop every registered queue. App-scoped state outlives any mount, so tests that
28
- park writes share one process-global registry; reset() gives each its own clean
29
- slate. Only the in-memory registry is dropped — `queue.dispose()` keeps the
30
- persisted snapshot (a reload rehydrates it), so a sign-out that must abandon
31
- unsynced work has to clear persistence separately. */
32
- reset(): void {
33
- for (const { queue } of registered.values()) {
34
- queue.dispose?.()
35
- }
36
- registered.clear()
37
- },
38
- }
39
-
40
- /* The queues a pending() selector spans: a durable rpc selector carries the queue's
41
- `url`, so it narrows to that one; the bare form spans every registered queue; any
42
- other selector (producer fn, tags, subscribable) carries no url and matches none. */
43
- const queuesFor = (selector: unknown): OutboxQueue<unknown>[] => {
44
- if (selector === undefined) {
45
- return outboxRegistry.all().map(({ queue }) => queue)
46
- }
47
- const url = (selector as { url?: unknown }).url
48
- if (typeof url !== 'string') {
49
- return []
50
- }
51
- const queue = outboxRegistry.get(url)
52
- return queue === undefined ? [] : [queue]
53
- }
54
-
55
- /* Prober for the shared pending() probe (see outboxProbeSlot). A parked write has no
56
- value yet, so it counts as pending. Reads queue.entries() (doc-backed), so the probe
57
- re-runs as writes park, drain, fail, or cancel; optional args narrow to one parked
58
- call by structural compare — the double-submit guard for a form. The compare uses
59
- canonicalJson (key-sorted, the encoder keyForRemoteCall keys body args with), not
60
- JSON.stringify, so a selector's args match a parked entry regardless of key order —
61
- the same equality the cache-side selector grammar already uses. */
62
- outboxProbeSlot.probe = (selector, args): boolean => {
63
- const entries = queuesFor(selector).flatMap((queue) => queue.entries())
64
- if (args === undefined) {
65
- return entries.length > 0
66
- }
67
- const key = canonicalJson(args)
68
- return entries.some((entry) => canonicalJson(entry.args) === key)
69
- }
@@ -1,28 +0,0 @@
1
- import type { PatchEvent } from './types/PatchEvent.ts'
2
-
3
- /*
4
- Process-global tap for every document mutation. `createDoc` emits a `PatchEvent`
5
- here on each applied patch; cross-cutting consumers (undo history, persistence,
6
- sync) subscribe. One chokepoint means those features journal a single uniform
7
- stream instead of each re-deriving change detection. `active` lets the emitter
8
- skip computing an inverse — its only real cost — when nobody is listening.
9
- */
10
- const listeners = new Set<(event: PatchEvent) => void>()
11
-
12
- export const PATCH_BUS = {
13
- /* True only while at least one consumer is attached; gates inverse capture. */
14
- get active(): boolean {
15
- return listeners.size > 0
16
- },
17
- emit(event: PatchEvent): void {
18
- for (const listener of listeners) {
19
- listener(event)
20
- }
21
- },
22
- subscribe(listener: (event: PatchEvent) => void): () => void {
23
- listeners.add(listener)
24
- return () => {
25
- listeners.delete(listener)
26
- }
27
- },
28
- }
@@ -1,43 +0,0 @@
1
- import { PATCH_BUS } from './PATCH_BUS.ts'
2
- import type { Doc } from './types/Doc.ts'
3
-
4
- /* Stack of in-flight captures, innermost last. `mountChild` wraps every hot-tracked child
5
- mount in its own `captureModelDoc`, and these NEST inside a parent's build, so a single
6
- shared PATCH_BUS would let a parent's listener (subscribed first) grab a nested child's
7
- model. Assigning each patch only to the innermost active capture keeps a component's model
8
- scoped to its OWN build. */
9
- const captureStack: { model: Doc | undefined }[] = []
10
-
11
- /*
12
- Runs a component `build` and returns its result (the mount handle / disposer)
13
- alongside the component's own `model` document — the serializable `state` doc,
14
- needed so a hot swap can carry its value across (see `hotReplace`). The model is
15
- found, not threaded: a component seeds its `model` first (the desugared
16
- `const $$model = scope()` + its init `replace` patches (state slots lowered by `lowerDocAccess`) run before any child mounts or
17
- control-flow blocks), so the FIRST patch announced during THIS build (not a nested
18
- child's) names it. A component with no `state` mints no model and emits nothing first
19
- — `model` is then `undefined` and there is nothing to preserve. A nested child mount
20
- pushes its own frame, so its state-init patch names the child's model, not the parent's
21
- (the M5 stateless-parent/stateful-child fix). Used only on the hot path; the subscription
22
- is torn down with the build.
23
- */
24
- export function captureModelDoc<T>(build: () => T): {
25
- value: T
26
- model: Doc | undefined
27
- } {
28
- const frame: { model: Doc | undefined } = { model: undefined }
29
- captureStack.push(frame)
30
- const unsubscribe = PATCH_BUS.subscribe((event) => {
31
- /* Only the innermost active capture claims a patch — a nested child mounting during
32
- this build has pushed a deeper frame, so its patches don't leak up to this one. */
33
- if (captureStack[captureStack.length - 1] === frame) {
34
- frame.model ??= event.doc
35
- }
36
- })
37
- try {
38
- return { value: build(), model: frame.model }
39
- } finally {
40
- unsubscribe()
41
- captureStack.pop()
42
- }
43
- }
@@ -1,10 +0,0 @@
1
- import type { HotInstance } from './types/HotInstance.ts'
2
-
3
- /*
4
- Live component instances grouped by module id (`UiComponent.__abideId`).
5
- `mountChild` adds each instance it mounts while hot reload is active; `hotReplace`
6
- walks a module's set to swap every instance when that module is edited. The set's
7
- remove callback (filed with the mounting owner) drops an instance on unmount, so
8
- no stale record survives to be swapped into a detached host.
9
- */
10
- export const hotInstances: Map<string, Set<HotInstance>> = new Map()
@@ -1,8 +0,0 @@
1
- /*
2
- Whether abide-ui hot-module replacement is active. Off by default, so production
3
- and ordinary dev render exactly as before — `mountChild` takes the plain path.
4
- The dev client sets it true once the hot bridge is in place, switching every
5
- child mount onto the path that records its instance so an edited component can be
6
- disposed and re-run where it stands.
7
- */
8
- export const hotReloadEnabled: { current: boolean } = { current: false }
@@ -1,38 +0,0 @@
1
- import { fillRange } from '../dom/fillRange.ts'
2
- import { captureModelDoc } from './captureModelDoc.ts'
3
- import { hotInstances } from './hotInstances.ts'
4
- import { seedModelDoc } from './seedModelDoc.ts'
5
- import type { UiComponent } from './types/UiComponent.ts'
6
-
7
- /*
8
- Swaps every live instance of an edited component to its new factory. Per instance:
9
- snapshot its model, dispose the current scope and clear its DOM range (the disposer
10
- leaves the `start`/`end` markers in place), re-fill the SAME range with the new
11
- module's `build` and the same props, then re-seed the fresh model from the snapshot —
12
- so the user's in-progress `state` survives the edit (state above the boundary already
13
- survives: props are thunks re-reading the parent's live signals). The hot module
14
- calls this on load with its freshly compiled `next`. Returns whether it swapped at
15
- least one instance: false (the edited component has none mounted — e.g. a
16
- router-mounted page, or a hidden branch) tells the caller to fall back to a full
17
- reload, since nothing on screen would update.
18
- */
19
- export function hotReplace(moduleId: string, next: UiComponent): boolean {
20
- const set = hotInstances.get(moduleId)
21
- if (set === undefined || set.size === 0) {
22
- return false
23
- }
24
- for (const instance of set) {
25
- const saved = instance.model?.snapshot()
26
- instance.dispose()
27
- instance.factory = next
28
- const { value: handle, model } = captureModelDoc(() =>
29
- fillRange(instance.start, instance.end, next.build, instance.props, instance.label),
30
- )
31
- instance.dispose = handle.dispose
32
- instance.model = model
33
- if (saved !== undefined && model !== undefined) {
34
- seedModelDoc(model, saved)
35
- }
36
- }
37
- return true
38
- }
@@ -1,15 +0,0 @@
1
- import type { Scope } from '../types/Scope.ts'
2
-
3
- /*
4
- Dev-only registry of every live scope, for the inspector's Reactive tab. `scopes`
5
- stays empty and untouched unless installInspectorBridge flips `enabled` (gated by
6
- the server-injected `__abideInspect`), so production allocates and tracks nothing.
7
- createScope adds on construction and removes on dispose; the bridge reconstructs
8
- the scope forest from each entry's `id` + `parent.id` (the Scope surface exposes
9
- no children accessor, so the flat set + parent links is the traversal path). One
10
- mutable singleton object — mirrors `reactiveAbortState`, reached without a barrel.
11
- */
12
- export const liveScopes: { enabled: boolean; scopes: Set<Scope> } = {
13
- enabled: false,
14
- scopes: new Set(),
15
- }
@@ -1,47 +0,0 @@
1
- import { decodeRefJson } from '../../shared/decodeRefJson.ts'
2
- import { encodeRefJson } from '../../shared/encodeRefJson.ts'
3
- import type { PersistenceStore } from '../types/PersistenceStore.ts'
4
-
5
- /*
6
- The default `persist` backend: `localStorage` keyed by the persistence key, using
7
- the ref-json codec as the wire form (which also clones on decode, so a stored
8
- snapshot can't alias the live tree). ref-json over plain JSON because a doc
9
- snapshot can hold the types JSON silently coerces (Date), drops (undefined) or
10
- throws on (bigint, cycles, shared references) — a throw here is a swallowed save,
11
- i.e. silent persistence loss. Returns `undefined` where there is no `localStorage`
12
- — the server, or a browser with storage disabled — which `persist` reads as "stay
13
- inert". A corrupt or unreadable entry (including one written by an older JSON
14
- build) loads as `undefined` rather than throwing, so one bad write can't wedge
15
- boot; the next save rewrites it in ref-json form.
16
- */
17
- export function localStoragePersistence(): PersistenceStore | undefined {
18
- if (typeof localStorage === 'undefined') {
19
- return undefined
20
- }
21
- return {
22
- load: (key) => {
23
- const raw = localStorage.getItem(key)
24
- if (raw === null) {
25
- return undefined
26
- }
27
- try {
28
- return decodeRefJson(raw)
29
- } catch {
30
- return undefined
31
- }
32
- },
33
- save: (key, snapshot) => {
34
- /* Swallow a failed write (QuotaExceededError, storage disabled mid-session) —
35
- it fires from a debounced flush / pagehide handler with no caller to catch it,
36
- and a dropped persist must not crash the app. */
37
- try {
38
- localStorage.setItem(key, encodeRefJson(snapshot))
39
- } catch {
40
- // best-effort persistence
41
- }
42
- },
43
- remove: (key) => {
44
- localStorage.removeItem(key)
45
- },
46
- }
47
- }
@@ -1,23 +0,0 @@
1
- import { hotInstances } from './hotInstances.ts'
2
- import type { HotInstance } from './types/HotInstance.ts'
3
-
4
- /*
5
- Records a live component instance under its module id and returns a remove
6
- callback. `mountChild` files the remove with the mounting owner, so the instance
7
- leaves the registry when its parent (or branch/row) tears down — the module's set
8
- is dropped once empty, leaving no orphan keys.
9
- */
10
- export function registerHotInstance(moduleId: string, instance: HotInstance): () => void {
11
- let set = hotInstances.get(moduleId)
12
- if (set === undefined) {
13
- set = new Set()
14
- hotInstances.set(moduleId, set)
15
- }
16
- set.add(instance)
17
- return () => {
18
- set.delete(instance)
19
- if (set.size === 0) {
20
- hotInstances.delete(moduleId)
21
- }
22
- }
23
- }
@@ -1,26 +0,0 @@
1
- import type { Doc } from './types/Doc.ts'
2
-
3
- /*
4
- Loads a `saved` snapshot (from the pre-swap instance) into a freshly-built `model`,
5
- restoring the user's in-progress state across a hot swap. A shallow per-top-level-key
6
- merge, not a wholesale root replace: a key present in both is restored from `saved`;
7
- a key the edit ADDED keeps its fresh default; a key the edit REMOVED is not re-added.
8
- So editing a component's state shape still loads cleanly instead of resurrecting a
9
- stale tree. Each restored key is one patch, so only the changed slots re-render.
10
- */
11
- export function seedModelDoc(model: Doc, saved: unknown): void {
12
- const current = model.snapshot()
13
- if (
14
- saved === null ||
15
- typeof saved !== 'object' ||
16
- current === null ||
17
- typeof current !== 'object'
18
- ) {
19
- return
20
- }
21
- for (const key of Object.keys(saved)) {
22
- if (key in current) {
23
- model.replace(key, (saved as Record<string, unknown>)[key])
24
- }
25
- }
26
- }
@@ -1,22 +0,0 @@
1
- import type { Doc } from './Doc.ts'
2
- import type { UiComponent } from './UiComponent.ts'
3
-
4
- /*
5
- A live component instance the hot-reload registry tracks: the `start`/`end` markers
6
- bounding its DOM range (the wrapper-free mount, see `mountRange`), its `label` (the
7
- scope name), the factory that built it, the props (thunks re-read on a swap so the
8
- parent's live state still flows through), the disposer for its current scope + DOM,
9
- and its own `model` document (`undefined` when the component has no `state`) —
10
- snapshotted before a swap and re-seeded after, so the user's in-progress state
11
- survives the edit. A swap re-fills the SAME range and mutates `factory`/`dispose`/
12
- `model` in place (see `hotReplace`).
13
- */
14
- export type HotInstance = {
15
- start: Comment
16
- end: Comment
17
- label: string | undefined
18
- factory: UiComponent
19
- props: Parameters<UiComponent>[1]
20
- dispose: () => void
21
- model: Doc | undefined
22
- }
@@ -1,16 +0,0 @@
1
- import type { Doc } from './Doc.ts'
2
- import type { Patch } from './Patch.ts'
3
-
4
- /*
5
- A single applied change announced on the `PATCH_BUS`: the `doc` it hit (reference
6
- identity within the process — a serialization-stable id arrives with sync), the
7
- forward `patch`, and its `inverse` — the patch that exactly undoes it, or
8
- `undefined` for a no-op (e.g. removing an absent key). Consumers — undo history,
9
- persistence, sync — read this one shape; the inverse is what makes a journal
10
- reversible at O(size of the change), never a retained tree snapshot.
11
- */
12
- export type PatchEvent = {
13
- doc: Doc
14
- patch: Patch
15
- inverse: Patch | undefined
16
- }
@@ -1,28 +0,0 @@
1
- import { RESUME } from './runtime/RESUME.ts'
2
- import { seedStreamedResolution } from './seedStreamedResolution.ts'
3
- import type { ResolvedFrame } from './types/ResolvedFrame.ts'
4
-
5
- /*
6
- The single client intake seam for SSR warm-state seeding. Both warm-seed channels —
7
- the cache-snapshot channel (a settled `cache()` value, keyed by cache key) and the
8
- await-resume channel (an `await`-block resolved value, keyed by boundary id) — answer
9
- the same "ship a server-settled value so hydration doesn't re-fetch" question, but land
10
- in two distinct stores: the cache STORE (read by `cache()`) and the RESUME MANIFEST
11
- (read by `awaitBlock` on adopt). This routes a discriminated `ResolvedFrame` to the
12
- matching store so every consumer — startClient's boot drain, the live `__abideResolve`,
13
- applyResolved's stream swap — registers through ONE call instead of poking each store
14
- inline. The codecs stay split by source: the cache value is an HTTP body capped at plain
15
- JSON (it must agree with the live `decodeResponse` read), the resume value is an in-process
16
- graph carried as ref-json text and decoded lazily at the read site.
17
- */
18
- // @documentation plumbing
19
- export function seedResolved(frame: ResolvedFrame): void {
20
- if (frame.kind === 'cache') {
21
- seedStreamedResolution(frame.resolution)
22
- return
23
- }
24
- /* The resume value rides as raw ref-json text; store it unparsed so the inline
25
- stream-swap script (vanilla, runs before the bundle's codec loads) can register
26
- through this same seam. `awaitBlock` decodes it at the read. */
27
- RESUME[frame.id] = frame.resume
28
- }
@@ -1,48 +0,0 @@
1
- import { PATCH_BUS } from './runtime/PATCH_BUS.ts'
2
- import type { Doc } from './runtime/types/Doc.ts'
3
- import type { Patch } from './runtime/types/Patch.ts'
4
- import type { SyncTransport } from './types/SyncTransport.ts'
5
-
6
- /*
7
- Shares a document's state across peers in real time. Two directions over one
8
- `transport`, both riding the patch bus:
9
- - OUTBOUND: every local patch to `doc` is published (`transport.send`);
10
- - INBOUND: every peer patch is applied to `doc`.
11
- An inbound apply emits on the bus like any change, so an `applying` guard stops it
12
- being echoed straight back — the thing that would otherwise ping-pong forever. The
13
- transport itself should not deliver a sender its own patch either; together the two
14
- guards keep a write to a path from looping. Last-write-wins by arrival order;
15
- edits to *different* paths never conflict, by construction of the doc's wake. A
16
- late joiner needs a snapshot seed before live patches (a transport concern, out of
17
- this core). Returns a disposer.
18
- */
19
- // @documentation plumbing
20
- export function sync(doc: Doc, transport: SyncTransport): () => void {
21
- /* The specific inbound patches currently being applied — their own bus echo must not be
22
- re-sent. Tracked by IDENTITY (not a blanket `applying` flag): `doc.apply` emits the
23
- patch on the bus inside its batch, then flushes effects on batch exit while still
24
- synchronously inside this apply. A local effect that writes the doc in reaction emits
25
- a DIFFERENT patch during that flush — a genuine new local change peers need — which a
26
- blanket flag would wrongly suppress, diverging peers permanently. */
27
- const applyingPatches = new Set<Patch>()
28
-
29
- const unsubscribeInbound = transport.subscribe((patch) => {
30
- applyingPatches.add(patch)
31
- try {
32
- doc.apply(patch)
33
- } finally {
34
- applyingPatches.delete(patch)
35
- }
36
- })
37
-
38
- const unsubscribeBus = PATCH_BUS.subscribe((event) => {
39
- if (event.doc === doc && !applyingPatches.has(event.patch)) {
40
- transport.send(event.patch)
41
- }
42
- })
43
-
44
- return () => {
45
- unsubscribeBus()
46
- unsubscribeInbound()
47
- }
48
- }
@@ -1,14 +0,0 @@
1
- /*
2
- The undo/redo handle returned by `history(doc)`. `undo`/`redo` step the journal
3
- of inverse patches; `canUndo`/`canRedo` report availability; `transaction` groups
4
- a burst of patches into one reversible step (one user action = one undo); `dispose`
5
- detaches from the `PATCH_BUS` and drops the journal.
6
- */
7
- export type History = {
8
- undo: () => void
9
- redo: () => void
10
- canUndo: () => boolean
11
- canRedo: () => boolean
12
- transaction: (run: () => void) => void
13
- dispose: () => void
14
- }
@@ -1,11 +0,0 @@
1
- /*
2
- The handle returned by `persist(doc, key)`. `flush` writes the pending snapshot
3
- immediately (the debounced writer otherwise coalesces a burst); `clear` removes
4
- the stored snapshot; `dispose` stops persisting (unsubscribes, drops listeners).
5
- On the server or a store-less browser, every method is a no-op.
6
- */
7
- export type PersistHandle = {
8
- flush: () => void
9
- clear: () => void
10
- dispose: () => void
11
- }
@@ -1,12 +0,0 @@
1
- /*
2
- The durable backend `persist` writes a document snapshot to. Deliberately tiny
3
- and synchronous — `load` must return the saved value in time to seed the doc
4
- before first render, which a sync store (localStorage) gives for free. Inject a
5
- custom one for a different backend (a test memory store; a server data-dir store);
6
- an async backend (IndexedDB) needs an async-boot wrapper, out of this contract.
7
- */
8
- export type PersistenceStore = {
9
- load: (key: string) => unknown
10
- save: (key: string, snapshot: unknown) => void
11
- remove: (key: string) => void
12
- }
@@ -1,15 +0,0 @@
1
- import type { StreamedResolution } from '../../shared/types/StreamedResolution.ts'
2
-
3
- /*
4
- A warm-state-seed frame for the single client intake (`seedResolved`), discriminated by
5
- `kind`. Both kinds ship a server-settled value so hydration adopts without a re-fetch,
6
- but route to distinct stores:
7
- - `cache` — a `StreamedResolution` for the cache store, read by a warm `cache()` call.
8
- - `resume` — an `await`-block boundary id plus its ref-json-encoded value STRING for the
9
- RESUME manifest, decoded lazily by `awaitBlock` when it adopts the branch.
10
- The payloads stay distinct (cache snapshot vs boundary-keyed value); the unified thing is
11
- the intake seam, not the payload.
12
- */
13
- export type ResolvedFrame =
14
- | { kind: 'cache'; resolution: StreamedResolution }
15
- | { kind: 'resume'; id: number; resume: string }
@@ -1,13 +0,0 @@
1
- import type { Patch } from '../runtime/types/Patch.ts'
2
-
3
- /*
4
- The bidirectional channel `sync` rides: `send` publishes a local patch to peers,
5
- `subscribe` delivers patches from peers (returning an unsubscribe). Deliberately
6
- minimal and patch-shaped — an app adapts it to a `socket` (publish ⇒ `send`, the
7
- socket's frames ⇒ `subscribe`), and a test adapts it to an in-memory hub. A patch
8
- is already the serializable wire unit, so nothing else is needed.
9
- */
10
- export type SyncTransport = {
11
- send: (patch: Patch) => void
12
- subscribe: (onPatch: (patch: Patch) => void) => () => void
13
- }