@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,100 +0,0 @@
1
- import type { SemanticToken } from './types/SemanticToken.ts'
2
-
3
- /*
4
- Lexical highlighting for `{#…}`/`{:…}`/`{/…}` control-flow framing — the part the
5
- HTML grammar sees only as text and the shadow program lowers away. A pure scan of
6
- raw source (independent of a successful parse, so it survives mid-edit), it emits
7
- an `operator` token for the `{`+sigil opener and a `keyword` token for the block
8
- word, plus the `of`/`by` connectors inside a `{#for …}` head. Expression interiors
9
- and bare `{expr}` interpolations are NOT touched here — those are the shadow's job.
10
- A keyword allowlist after the sigil prevents matching arbitrary `{:foo}` text.
11
- Longest phrases first so `for await` beats `for` and `else if` beats `else`.
12
- */
13
- const BLOCK_KEYWORDS = [
14
- 'for await',
15
- 'else if',
16
- 'if',
17
- 'for',
18
- 'await',
19
- 'switch',
20
- 'case',
21
- 'default',
22
- 'try',
23
- 'catch',
24
- 'finally',
25
- 'then',
26
- 'else',
27
- ]
28
-
29
- const BLOCK_HEAD = new RegExp(`\\{([#:/])\\s*(${BLOCK_KEYWORDS.join('|')})\\b`, 'g')
30
-
31
- export function structuralBlockTokens(source: string): SemanticToken[] {
32
- const tokens: SemanticToken[] = []
33
- for (const match of source.matchAll(BLOCK_HEAD)) {
34
- const braceStart = match.index
35
- const sigil = match[1]
36
- const keyword = match[2]
37
- if (keyword === undefined) {
38
- continue
39
- }
40
- const keywordStart = braceStart + match[0].length - keyword.length
41
- tokens.push({ start: braceStart, length: 2, type: 'operator', modifiers: [] })
42
- tokens.push({ start: keywordStart, length: keyword.length, type: 'keyword', modifiers: [] })
43
- /* A `{#for …}` head carries abide-only connectors `of`/`by` that the shadow
44
- lowers away (`of`) or never emits (`by`), so color them here. */
45
- if (sigil === '#' && (keyword === 'for' || keyword === 'for await')) {
46
- tokens.push(...forHeadConnectors(source, keywordStart + keyword.length))
47
- }
48
- }
49
- return tokens
50
- }
51
-
52
- /*
53
- Scans a `{#for …}` head from `from` to its closing `}`, emitting `keyword` tokens
54
- for the `of`/`by` connectors at brace depth 0 — skipping any `of`/`by` nested in a
55
- destructure, call, or string so an identifier or object key is never miscolored.
56
- */
57
- function forHeadConnectors(source: string, from: number): SemanticToken[] {
58
- const tokens: SemanticToken[] = []
59
- let depth = 0
60
- let cursor = from
61
- while (cursor < source.length) {
62
- const char = source.charAt(cursor)
63
- if (char === '"' || char === "'" || char === '`') {
64
- cursor += 1
65
- while (cursor < source.length && source.charAt(cursor) !== char) {
66
- if (source.charAt(cursor) === '\\') {
67
- cursor += 1
68
- }
69
- cursor += 1
70
- }
71
- } else if (char === '{' || char === '(' || char === '[') {
72
- depth += 1
73
- } else if (char === ')' || char === ']') {
74
- depth -= 1
75
- } else if (char === '}') {
76
- if (depth === 0) {
77
- break
78
- }
79
- depth -= 1
80
- } else if (depth === 0 && (char === 'o' || char === 'b')) {
81
- const word = source.startsWith('of', cursor)
82
- ? 'of'
83
- : source.startsWith('by', cursor)
84
- ? 'by'
85
- : undefined
86
- const isWordBoundary = (offset: number): boolean => /\s/.test(source.charAt(offset))
87
- if (
88
- word !== undefined &&
89
- isWordBoundary(cursor - 1) &&
90
- isWordBoundary(cursor + word.length)
91
- ) {
92
- tokens.push({ start: cursor, length: word.length, type: 'keyword', modifiers: [] })
93
- cursor += word.length
94
- continue
95
- }
96
- }
97
- cursor += 1
98
- }
99
- return tokens
100
- }
@@ -1,87 +0,0 @@
1
- import { seedResolved } from '../seedResolved.ts'
2
- import { isComment } from './isComment.ts'
3
-
4
- /*
5
- Bundle-side consumer of an SSR stream chunk, the counterpart of the doc stream's inline
6
- vanilla scripts (`SSR_SWAP_SCRIPT`'s `__abideSwap` and `CACHE_RESOLVE_SCRIPT`'s `__abideResolve`) for a stream the
7
- running bundle consumes itself — streaming SPA navigation, socket-delivered SSR. It routes
8
- the two chunk kinds the stream interleaves:
9
-
10
- - `<abide-cache>{StreamedResolution}</abide-cache>` → seed the streamed cache partition.
11
- A script set via innerHTML never runs, so the cache channel rides a data frame here
12
- (not the doc stream's `<script>__abideResolve(…)</script>`); seeding it keeps the
13
- pending {#await} read warm instead of cold-missing to the network.
14
- - `<abide-resolve data-id="ID"><script type="application/json">…</script>…</abide-resolve>`
15
- → register the value in the resume manifest (for hydration), find the matching
16
- `<!--abide:await:ID-->…<!--/abide:await:ID-->` boundary in `root`, remove the pending
17
- nodes between the markers, and insert the resolved content in their place.
18
-
19
- The pending shell painted instantly; this swaps in each value as it arrives — completing
20
- the out-of-order streaming loop on the client.
21
- */
22
- // @documentation plumbing
23
- export function applyResolved(root: Element, frame: string): void {
24
- const holder = document.createElement('div')
25
- holder.innerHTML = frame
26
- const resolved = holder.firstChild as Element | null
27
- if (resolved === null || resolved.getAttribute === undefined) {
28
- return
29
- }
30
- /* A cache-seed frame warms the streamed cache partition — paired with the DOM swap so a
31
- bundle-consumed stream can't adopt a resolved branch while dropping its cache key. */
32
- if (resolved.nodeName === 'ABIDE-CACHE') {
33
- try {
34
- seedResolved({ kind: 'cache', resolution: JSON.parse(resolved.textContent ?? 'null') })
35
- } catch {
36
- /* malformed payload — leave unseeded; the read falls back to a live fetch */
37
- }
38
- return
39
- }
40
- const id = resolved.getAttribute('data-id')
41
- if (id === null) {
42
- return
43
- }
44
- /* The resolved value rides in a leading <script type=application/json> as ref-json
45
- text; store it raw and remove the node so only the resolved markup moves into the
46
- boundary. Decoding is deferred to the read in `awaitBlock` (which has the codec);
47
- recording it lets a later hydrate adopt this branch (no re-fetch). */
48
- const payload = resolved.firstChild as Element | null
49
- if (payload !== null && payload.nodeName === 'SCRIPT') {
50
- seedResolved({ kind: 'resume', id: Number(id), resume: payload.textContent ?? '' })
51
- payload.remove()
52
- }
53
- const open = `abide:await:${id}`
54
- const close = `/abide:await:${id}`
55
- const boundary = findBoundary(root, open)
56
- if (boundary === undefined) {
57
- return
58
- }
59
- const { parent, start } = boundary
60
- /* Remove the pending nodes between the markers (exclusive of the markers). */
61
- let node = start.nextSibling
62
- while (node !== null && !isComment(node, close)) {
63
- const next = node.nextSibling
64
- parent.removeChild(node)
65
- node = next
66
- }
67
- /* Insert resolved content after the open marker. */
68
- let anchor = start.nextSibling
69
- for (const child of [...resolved.childNodes]) {
70
- parent.insertBefore(child, anchor)
71
- anchor = child.nextSibling
72
- }
73
- }
74
-
75
- /* Depth-first search for the parent + open-marker comment of a boundary. */
76
- function findBoundary(node: Node, open: string): { parent: Node; start: Node } | undefined {
77
- for (const child of [...node.childNodes]) {
78
- if (isComment(child, open)) {
79
- return { parent: node, start: child }
80
- }
81
- const nested = findBoundary(child, open)
82
- if (nested !== undefined) {
83
- return nested
84
- }
85
- }
86
- return undefined
87
- }
@@ -1,21 +0,0 @@
1
- /*
2
- The human-readable name for the scope the direct-mount entry (`mount`/`hydrate`)
3
- establishes, derived from its host element's tag. The router instead fills layers into
4
- marker boundaries with no host element, so it passes each layer's route key as an
5
- explicit label (`fillBoundary`); a nested child likewise passes its component name (see
6
- `mountRange`). The `abide-` prefix strip turns a framework host tag like `abide-resolve`
7
- into `resolve`; any other host yields its lowercased tag. Feeds the inspector's
8
- Reactive tab a readable scope name; computed and stored in all builds (only the
9
- inspector surface is dev-only). Returns undefined when there's no element to name from.
10
- */
11
- import { COMPONENT_WRAPPER_PREFIX } from '../COMPONENT_WRAPPER_PREFIX.ts'
12
-
13
- export function scopeLabel(host: Element): string | undefined {
14
- const tag = host.tagName?.toLowerCase()
15
- if (tag === undefined) {
16
- return undefined
17
- }
18
- return tag.startsWith(COMPONENT_WRAPPER_PREFIX)
19
- ? tag.slice(COMPONENT_WRAPPER_PREFIX.length)
20
- : tag
21
- }
@@ -1,20 +0,0 @@
1
- import { effect } from '../effect.ts'
2
-
3
- /*
4
- A text node whose content tracks `read()`. The effect captures whatever reactive
5
- cells `read` touches, so the node — and only this node — re-renders when they
6
- change: one text node, one effect — fine-grained granularity.
7
-
8
- Plain-text only — `read()` is coerced with String(). For a `{expr}` interpolation
9
- that may yield an `html\`…\`` or snippet value the compiler emits `appendText`,
10
- which branches on the branded value and inserts raw markup; `text` cannot host
11
- multiple nodes and would stringify such a value to `[object Object]`.
12
- */
13
- // @documentation plumbing
14
- export function text(read: () => unknown): Text {
15
- const node = document.createTextNode('')
16
- effect(() => {
17
- node.data = String(read())
18
- })
19
- return node
20
- }
@@ -1,101 +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 { History } from './types/History.ts'
5
-
6
- /*
7
- Undo/redo for a document. Subscribes the `PATCH_BUS`, filters to this `doc`, and
8
- journals each applied patch's `inverse` into a bounded stack — O(size of the
9
- change) per step, never a tree snapshot. `undo`/`redo` replay inverses through
10
- `doc.apply`; the patches that replay itself emits are routed into a `sink` so a
11
- replay never opens a fresh entry nor clears the opposite stack (it instead fills
12
- it, keeping the move reversible). A genuine new edit clears the redo stack.
13
- `transaction(fn)` groups every patch `fn` emits into one entry. `limit` caps
14
- depth — the oldest entry drops. Inert (but harmless) on the server.
15
- */
16
- // @documentation plumbing
17
- export function history(doc: Doc, { limit = 100 }: { limit?: number } = {}): History {
18
- const undoStack: Patch[][] = []
19
- const redoStack: Patch[][] = []
20
- /* When set, captured inverses accumulate here instead of opening a new undo entry
21
- — held by an in-progress transaction and by an undo/redo replay. */
22
- let sink: Patch[] | undefined
23
-
24
- /* Push one finished entry, evicting the oldest past `limit`. */
25
- const push = (stack: Patch[][], entry: Patch[]): void => {
26
- stack.push(entry)
27
- if (stack.length > limit) {
28
- stack.shift()
29
- }
30
- }
31
-
32
- const unsubscribe = PATCH_BUS.subscribe((event) => {
33
- if (event.doc !== doc || event.inverse === undefined) {
34
- return
35
- }
36
- if (sink !== undefined) {
37
- sink.push(event.inverse)
38
- return
39
- }
40
- push(undoStack, [event.inverse])
41
- redoStack.length = 0
42
- })
43
-
44
- /* Apply an entry's inverses in reverse application order (LIFO), capturing the
45
- inverses they emit — the original forward patches — onto `target`, so the move
46
- is itself reversible and lands on the opposite stack. */
47
- const replay = (entry: Patch[], target: Patch[][]): void => {
48
- const captured: Patch[] = []
49
- sink = captured
50
- try {
51
- for (let index = entry.length - 1; index >= 0; index -= 1) {
52
- doc.apply(entry[index] as Patch)
53
- }
54
- } finally {
55
- sink = undefined
56
- }
57
- if (captured.length > 0) {
58
- push(target, captured)
59
- }
60
- }
61
-
62
- return {
63
- undo: () => {
64
- const entry = undoStack.pop()
65
- if (entry !== undefined) {
66
- replay(entry, redoStack)
67
- }
68
- },
69
- redo: () => {
70
- const entry = redoStack.pop()
71
- if (entry !== undefined) {
72
- replay(entry, undoStack)
73
- }
74
- },
75
- canUndo: () => undoStack.length > 0,
76
- canRedo: () => redoStack.length > 0,
77
- transaction: (run: () => void) => {
78
- /* A nested transaction folds into the one already collecting. */
79
- if (sink !== undefined) {
80
- run()
81
- return
82
- }
83
- const entry: Patch[] = []
84
- sink = entry
85
- try {
86
- run()
87
- } finally {
88
- sink = undefined
89
- }
90
- if (entry.length > 0) {
91
- push(undoStack, entry)
92
- redoStack.length = 0
93
- }
94
- },
95
- dispose: () => {
96
- unsubscribe()
97
- undoStack.length = 0
98
- redoStack.length = 0
99
- },
100
- }
101
- }
@@ -1,93 +0,0 @@
1
- import { snippet } from '../shared/snippet.ts'
2
- import { anchorCursor } from './dom/anchorCursor.ts'
3
- import { appendSnippet } from './dom/appendSnippet.ts'
4
- import { appendStatic } from './dom/appendStatic.ts'
5
- import { appendText } from './dom/appendText.ts'
6
- import { appendTextAt } from './dom/appendTextAt.ts'
7
- import { attach } from './dom/attach.ts'
8
- import { attr } from './dom/attr.ts'
9
- import { awaitBlock } from './dom/awaitBlock.ts'
10
- import { bindSelectValue } from './dom/bindSelectValue.ts'
11
- import { cloneStatic } from './dom/cloneStatic.ts'
12
- import { each } from './dom/each.ts'
13
- import { eachAsync } from './dom/eachAsync.ts'
14
- import { hydrate } from './dom/hydrate.ts'
15
- import { mergeProps } from './dom/mergeProps.ts'
16
- import { mount } from './dom/mount.ts'
17
- import { mountChild } from './dom/mountChild.ts'
18
- import { mountSlot } from './dom/mountSlot.ts'
19
- import { on } from './dom/on.ts'
20
- import { outlet } from './dom/outlet.ts'
21
- import { readCall } from './dom/readCall.ts'
22
- import { restProps } from './dom/restProps.ts'
23
- import { skeleton } from './dom/skeleton.ts'
24
- import { spreadAttrs } from './dom/spreadAttrs.ts'
25
- import { spreadProps } from './dom/spreadProps.ts'
26
- import { switchBlock } from './dom/switchBlock.ts'
27
- import { tryBlock } from './dom/tryBlock.ts'
28
- import { when } from './dom/when.ts'
29
- import { effect } from './effect.ts'
30
- import { enterScope } from './enterScope.ts'
31
- import { exitScope } from './exitScope.ts'
32
- import { enterRenderPass } from './runtime/enterRenderPass.ts'
33
- import { escapeKey } from './runtime/escapeKey.ts'
34
- import { exitRenderPass } from './runtime/exitRenderPass.ts'
35
- import { hotReloadEnabled } from './runtime/hotReloadEnabled.ts'
36
- import { hotReplace } from './runtime/hotReplace.ts'
37
- import { nextBlockId } from './runtime/nextBlockId.ts'
38
- import { scope } from './scope.ts'
39
- import { watch } from './watch.ts'
40
-
41
- /*
42
- Dev-only: exposes the abide-ui runtime plus `hotReplace` on `window.__abide`, and
43
- flips on `hotReloadEnabled` so `mountChild` records every instance it mounts. A
44
- hot module (the dev server's standalone recompile of one edited `.abide`) reads
45
- its runtime from this object instead of importing fresh copies — so it shares the
46
- one reactive graph and instance registry — then calls `hotReplace` to swap every
47
- live instance in place. The keys mirror `UI_RUNTIME_IMPORTS` (+ `hotReplace`); a
48
- test guards that pairing. `startClient` calls this when the server marks the page
49
- dev (the live-reload script sets `window.__abideDev`).
50
- */
51
- export function installHotBridge(): void {
52
- ;(globalThis as { __abide?: Record<string, unknown> }).__abide = {
53
- snippet,
54
- scope,
55
- enterScope,
56
- exitScope,
57
- effect,
58
- watch,
59
- mount,
60
- appendText,
61
- appendTextAt,
62
- appendSnippet,
63
- appendStatic,
64
- cloneStatic,
65
- skeleton,
66
- anchorCursor,
67
- attr,
68
- on,
69
- attach,
70
- bindSelectValue,
71
- each,
72
- eachAsync,
73
- when,
74
- awaitBlock,
75
- tryBlock,
76
- switchBlock,
77
- mountSlot,
78
- outlet,
79
- mountChild,
80
- mergeProps,
81
- spreadProps,
82
- restProps,
83
- spreadAttrs,
84
- readCall,
85
- hydrate,
86
- escapeKey,
87
- nextBlockId,
88
- enterRenderPass,
89
- exitRenderPass,
90
- hotReplace,
91
- }
92
- hotReloadEnabled.current = true
93
- }
@@ -1,140 +0,0 @@
1
- import { effect } from './effect.ts'
2
- import { clientPage } from './runtime/clientPage.ts'
3
- import { historyEntries } from './runtime/historyEntries.ts'
4
- import { liveScopes } from './runtime/liveScopes.ts'
5
- import { PATCH_BUS } from './runtime/PATCH_BUS.ts'
6
- import { runtimePath } from './runtime/runtimePath.ts'
7
-
8
- /* Same-origin cross-tab channel the inspector page listens on. The app tab
9
- publishes scope + router state; the inspector subscribes. Web-standard, so no
10
- server route or buffer is involved — core publishes, the package consumes. */
11
- const CHANNEL = 'abide:inspector'
12
-
13
- /* Coalesce a burst of patches into one snapshot — the post is the cost, the read is cheap. */
14
- const SNAPSHOT_DEBOUNCE_MS = 60
15
-
16
- /* JSON round-trip to strip anything structured-clone can't carry (functions,
17
- class instances, DOM nodes) before postMessage, degrading to undefined rather
18
- than throwing into the channel. */
19
- function cloneable(value: unknown): unknown {
20
- try {
21
- return JSON.parse(JSON.stringify(value))
22
- } catch {
23
- return undefined
24
- }
25
- }
26
-
27
- /* The live scope forest as a flat list — the inspector rebuilds the tree from
28
- each node's `parent` id (the Scope surface exposes no children accessor). */
29
- function scopeNodes(): Array<{
30
- id: string
31
- label: string | undefined
32
- parent: string | undefined
33
- state: unknown
34
- recorded: boolean
35
- }> {
36
- return Array.from(liveScopes.scopes, (scope) => ({
37
- id: scope.id,
38
- label: scope.label,
39
- parent: scope.parent?.id,
40
- state: cloneable(scope.snapshot()),
41
- recorded: scope.canUndo() || scope.canRedo(),
42
- }))
43
- }
44
-
45
- /* Router state off the existing reactive holders — read, not subscribed, here;
46
- the nav effect drives re-reads. */
47
- function routerState() {
48
- const page = clientPage.value
49
- return {
50
- path: runtimePath.value,
51
- route: page.route,
52
- /* `page.params` is a reactive Proxy — structuredClone (postMessage) can't carry
53
- a Proxy and throws, dropping every router frame. Spread to a plain object. */
54
- params: { ...page.params },
55
- navigating: page.navigating,
56
- url: page.url.href,
57
- entry: historyEntries.current,
58
- }
59
- }
60
-
61
- /*
62
- Installs the client→inspector bridge: a BroadcastChannel the inspector page reads
63
- to render its Reactive + Router tabs. Gated by `__abideInspect` (server-injected
64
- only when the inspector is enabled) and called from startClient before the router
65
- builds any scope — so registration is armed before the first scope exists. A
66
- no-op where BroadcastChannel is absent (SSR, old runtimes). Mirrors
67
- installHotBridge: dev instrumentation, not public surface.
68
- */
69
- export function installInspectorBridge(): void {
70
- /* No BroadcastChannel means no consumer for the scope registry — bail before
71
- arming `liveScopes.enabled`, so createScope never pays scope tracking for a
72
- set nothing reads. */
73
- if (typeof BroadcastChannel === 'undefined') {
74
- return
75
- }
76
- liveScopes.enabled = true
77
- const channel = new BroadcastChannel(CHANNEL)
78
- const tab = typeof crypto !== 'undefined' ? crypto.randomUUID() : String(performance.now())
79
- const post = (message: object) => {
80
- try {
81
- channel.postMessage({ tab, ...message })
82
- } catch {
83
- /* A non-cloneable slipped through despite the JSON pass — drop the frame
84
- rather than throw into a patch/nav handler. */
85
- }
86
- }
87
-
88
- const announce = () =>
89
- post({
90
- kind: 'announce',
91
- url: typeof location !== 'undefined' ? location.href : '',
92
- app: typeof document !== 'undefined' ? document.title : '',
93
- })
94
- const sendSnapshot = () =>
95
- post({ kind: 'snapshot', scopes: scopeNodes(), router: routerState() })
96
-
97
- let snapshotTimer: ReturnType<typeof setTimeout> | undefined
98
- const scheduleSnapshot = () => {
99
- clearTimeout(snapshotTimer)
100
- snapshotTimer = setTimeout(sendSnapshot, SNAPSHOT_DEBOUNCE_MS)
101
- }
102
-
103
- /* Inspector handshakes: `hello` (it just opened — everyone re-announce + push)
104
- and `request` (it wants a fresh snapshot of this tab). */
105
- channel.onmessage = (event) => {
106
- const message = event.data as { kind?: string; tab?: string }
107
- if (message.kind === 'hello') {
108
- announce()
109
- sendSnapshot()
110
- } else if (message.kind === 'request' && message.tab === tab) {
111
- sendSnapshot()
112
- }
113
- }
114
-
115
- /* Every doc mutation flows through PATCH_BUS; forward the patch as a live
116
- mutation event and re-snapshot (debounced) so values stay current. */
117
- PATCH_BUS.subscribe((patchEvent) => {
118
- post({ kind: 'patch', op: patchEvent.patch.op, path: patchEvent.patch.path })
119
- scheduleSnapshot()
120
- })
121
-
122
- /* Reading the page + path States tracks them, so this re-runs on navigation. */
123
- effect(() => {
124
- clientPage.value
125
- runtimePath.value
126
- post({ kind: 'nav', router: routerState() })
127
- })
128
-
129
- if (typeof addEventListener === 'function') {
130
- addEventListener('pagehide', () => {
131
- post({ kind: 'bye' })
132
- channel.close()
133
- })
134
- }
135
-
136
- announce()
137
- /* First snapshot once the router has built the initial scope tree (this runs
138
- before router()). */
139
- setTimeout(sendSnapshot, 0)
140
- }
@@ -1,35 +0,0 @@
1
- import type { OutboxEntry } from '../shared/types/OutboxEntry.ts'
2
- import type { RemoteFunction } from '../shared/types/RemoteFunction.ts'
3
- import { outboxRegistry } from './rpcOutbox/outboxRegistry.ts'
4
-
5
- /* One entry in the global outbox, tagged with the RPC it belongs to. */
6
- export type GlobalOutboxEntry = OutboxEntry<unknown> & { rpc: RemoteFunction<unknown, unknown> }
7
-
8
- /* The global outbox: callable for the flat entry list, awaitable `retry()` to drain every
9
- queue (resolves when every replay settles). */
10
- export type GlobalOutbox = (() => GlobalOutboxEntry[]) & { retry: () => Promise<void> }
11
-
12
- function list(): GlobalOutboxEntry[] {
13
- return outboxRegistry.all().flatMap(({ rpc, queue }) =>
14
- queue.entries().map((entry) => ({
15
- ...entry,
16
- rpc: rpc as RemoteFunction<unknown, unknown>,
17
- })),
18
- )
19
- }
20
-
21
- /*
22
- The global, reactive view of every durable RPC's outbox — a flat list of undelivered
23
- entries across all `outbox` rpcs, each tagged with its `rpc`. Reactive: reading it in a
24
- template/effect subscribes to each registered queue, so it updates as writes park, drain,
25
- fail, or cancel. Use it for an app-wide "N unsynced" badge or a sync panel; cancel a
26
- pending write through `entry.controller.abort()`, retry one through `entry.retry()`, or
27
- drain everything through `outbox.retry()`. A single rpc's slice is `rpc.outbox`. Server-
28
- side there are no client queues, so it returns an empty list.
29
- */
30
- // @documentation ui
31
- export const outbox: GlobalOutbox = Object.assign(list, {
32
- async retry(): Promise<void> {
33
- await Promise.all(outboxRegistry.all().map(({ queue }) => queue.retry()))
34
- },
35
- })