@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
@@ -0,0 +1,36 @@
1
+ import { reviveWireField } from './reviveWireField.ts'
2
+ import type { OutputWirePlan } from './types/OutputWirePlan.ts'
3
+
4
+ /*
5
+ The type-directed wire DECODE step for a rpc success response (ADR-0029 output path) — the
6
+ response-side sibling of parseArgs' input revival. The server encoded a handler's structured
7
+ return into honest JSON (`wireJsonReplacer`): a `Set` → array, a `Map` → `[K,V]` entries, a
8
+ `bigint` → digit string, a `Date` → ISO string. A wire array is ambiguous (a real `T[]` vs an
9
+ encoded `Set<T>`), so the abide client revives from the DECLARED kind the warm server program baked
10
+ onto the stub (`OutputWirePlan`), applied to a DECODED response body here. Only the fields named in
11
+ the plan are touched; a genuine array / scalar the plan omits is left as-is.
12
+
13
+ Mutates the decoded body in place — the value is call-private (a fresh JSON.parse result or a
14
+ freshly cloned warm value), never shared. Fail-open at every branch: no plan, a non-object body, or
15
+ an unrevivable field value keeps the honest-JSON form so a type/runtime mismatch degrades visibly
16
+ rather than throwing. Top-level fields only; a structured value nested deeper is not descended into
17
+ (deferred, ADR-0029).
18
+ */
19
+ export function reviveWireOutput(value: unknown, plan: OutputWirePlan | undefined): unknown {
20
+ if (plan === undefined) {
21
+ return value
22
+ }
23
+ /* Only a plain object carries the named fields; a top-level array/scalar/null has none. */
24
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
25
+ return value
26
+ }
27
+ const record = value as Record<string, unknown>
28
+ for (const key in plan) {
29
+ const fieldPlan = plan[key]
30
+ if (fieldPlan === undefined || !(key in record)) {
31
+ continue
32
+ }
33
+ record[key] = reviveWireField(record[key], fieldPlan)
34
+ }
35
+ return value
36
+ }
@@ -0,0 +1,25 @@
1
+ import { createRpcServerProgram, type RpcServerProgram } from './createRpcServerProgram.ts'
2
+
3
+ /*
4
+ Warm per-root accessor for the rpc server program (ADR-0025 D1), mirroring the UI shadow's
5
+ `interpolationClassifierForRoot`: the first rpc transform in a root builds the `ts.Program`,
6
+ every later transform (streaming/method query) reuses it. Fails open in two layers — a
7
+ program that can't build stores `undefined` so the root is not retried and every query falls
8
+ back to the char-scan (each query method also catches per-query throws). The cache lives
9
+ in the resolver plugin's `setup` closure, so it persists across a whole build and is dropped
10
+ between plugin instances.
11
+ */
12
+ export function rpcServerForRoot(
13
+ cache: Map<string, RpcServerProgram | undefined>,
14
+ cwd: string,
15
+ rpcDir: string,
16
+ ): RpcServerProgram | undefined {
17
+ if (!cache.has(cwd)) {
18
+ try {
19
+ cache.set(cwd, createRpcServerProgram(cwd, rpcDir))
20
+ } catch {
21
+ cache.set(cwd, undefined)
22
+ }
23
+ }
24
+ return cache.get(cwd)
25
+ }
@@ -0,0 +1,25 @@
1
+ import { existsSync } from 'node:fs'
2
+ import { Glob } from 'bun'
3
+ import { fileName } from './fileName.ts'
4
+ import type { PagesScan } from './types/PagesScan.ts'
5
+
6
+ /*
7
+ Walks src/ui/pages once and classifies each `.abide` leaf by filename: a
8
+ `page.abide` is a route (its URL is the folder path), a `layout.abide` is a
9
+ layout that wraps every page at or below its folder (keyed by the same folder
10
+ URL). Any other `.abide` file (a shared component) is ignored here — free to
11
+ live anywhere and be imported relatively. Shared by the resolver plugin's
12
+ pages/layouts manifests and generateDeclarations' routes.d.ts so the two never
13
+ diverge on what counts as a route.
14
+ */
15
+ export async function scanPages(pagesDir: string): Promise<PagesScan> {
16
+ if (!existsSync(pagesDir)) {
17
+ return { pageFiles: [], layoutFiles: [] }
18
+ }
19
+ const allFiles = await Array.fromAsync(new Glob('**/*.abide').scan({ cwd: pagesDir }))
20
+ const leafIs = (name: string) => (file: string) => fileName(file) === name
21
+ return {
22
+ pageFiles: allFiles.filter(leafIs('page.abide')),
23
+ layoutFiles: allFiles.filter(leafIs('layout.abide')),
24
+ }
25
+ }
@@ -1,14 +1,15 @@
1
- import { hasReplayableRequest } from './hasReplayableRequest.ts'
1
+ import { hasSeedableRequest } from './hasSeedableRequest.ts'
2
2
  import type { CacheEntry } from './types/CacheEntry.ts'
3
3
 
4
4
  /*
5
5
  The one store-filter predicate selecting which cache entries are candidates for a
6
- warm snapshot: settled AND carrying a replayable (GET-only) wire request, so it
7
- can ship without re-firing a write or losing a body. Every selection site
8
- (serializeCacheSnapshot, the renderer's render-return and streaming-drain filters)
9
- calls this instead of re-spelling the guard, so they cannot drift.
6
+ warm snapshot: settled AND carrying a seedable wire request (any method), so an
7
+ inline call hydrates warm on the client instead of re-firing after render. Every
8
+ selection site (serializeCacheSnapshot, the renderer's render-return and
9
+ streaming-drain filters) calls this instead of re-spelling the guard, so they
10
+ cannot drift.
10
11
 
11
- Composed from `hasReplayableRequest` — the request half snapshotEntryFromCache
12
+ Composed from `hasSeedableRequest` — the request half snapshotEntryFromCache
12
13
  also gates on. snapshotEntryFromCache itself uses ONLY the request half (not
13
14
  `settled`): the streaming-drain path hands it still-pending entries and awaits
14
15
  them, so it can't require `settled` up front.
@@ -18,5 +19,5 @@ awaiting its body. The async response-level half (non-streaming + warmable kind)
18
19
  lives in snapshotEntryFromCache, reading the resolved Response.
19
20
  */
20
21
  export function snapshotShippable(entry: CacheEntry): boolean {
21
- return entry.settled === true && hasReplayableRequest(entry)
22
+ return entry.settled === true && hasSeedableRequest(entry)
22
23
  }
@@ -0,0 +1,14 @@
1
+ import { createResolverSlot } from './createResolverSlot.ts'
2
+ import type { StreamedCells } from './types/StreamedCells.ts'
3
+
4
+ /*
5
+ The active streamed-cells slot — mirrors `resolvedCellsSlot`/`pendingAsyncCellsSlot`. The server
6
+ entry installs an ALS-backed resolver (a fresh list per request, so concurrent SSR renders never
7
+ mix their streamed values); with no resolver a single fallback list is created lazily so isolated
8
+ tests work without booting the runtime. `createAsyncCell` pushes a `{ key, promise }` when a
9
+ STREAMING cell constructs server-side; the page renderer drains it during the stream, awaiting each
10
+ promise and streaming an `__abideResolve({ cellKey, value })` chunk (ADR-0035).
11
+ */
12
+ export const streamedCellsSlot = createResolverSlot<StreamedCells>(() => ({
13
+ entries: [],
14
+ }))
@@ -1,19 +1,19 @@
1
1
  import { streamResponse } from './streamResponse.ts'
2
- import type { Subscribable } from './types/Subscribable.ts'
2
+ import type { NamedAsyncIterable } from './types/NamedAsyncIterable.ts'
3
3
 
4
4
  /*
5
- Builds the Subscribable returned by `fn.stream(args)`. The carried
5
+ Builds the NamedAsyncIterable returned by `fn.stream(args)`. The carried
6
6
  `name` is the cache-style key for (method, url, args) so tail()
7
7
  dedupes multiple readers of identical args into one underlying
8
8
  fetch. The fetch is deferred until the first iterator pull so
9
- constructing the Subscribable (which happens on every $derived
9
+ constructing the NamedAsyncIterable (which happens on every $derived
10
10
  re-evaluation) doesn't open a connection — tail()'s registry
11
11
  short-circuits the second instance before it iterates.
12
12
  */
13
13
  export function subscribableFromResponse<T>(
14
14
  name: string,
15
15
  fetchResponse: () => Promise<Response>,
16
- ): Subscribable<T> {
16
+ ): NamedAsyncIterable<T> {
17
17
  return {
18
18
  name,
19
19
  [Symbol.asyncIterator]() {
@@ -29,7 +29,7 @@ re-derive by scanning.
29
29
  const lifecycle = createLifecycleChannel()
30
30
 
31
31
  /*
32
- Installs the prober the shared probes call for a Subscribable (probeRegistries →
32
+ Installs the prober the shared probes call for a NamedAsyncIterable (probeRegistries →
33
33
  tailProbeSlot). Register-on-consume: an entry exists only while something is
34
34
  consuming the stream, exactly as a cache entry exists only while a call is
35
35
  retained. A name with no entry reads as "no value yet" (pending) without opening
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  Internal slot the browser tail() registry registers its prober into, so the
3
- shared probes (pending / refreshing) can answer for Subscribables without
3
+ shared probes (pending / refreshing) can answer for NamedAsyncIterables without
4
4
  shared/ importing browser/. The prober taps the registry's lifecycle channel
5
5
  (reactive inside $derived / $effect) and reports one stream by source name —
6
6
  spanning its latest-wins and window entries — or, with no name, whether any
@@ -0,0 +1,20 @@
1
+ import type { ASYNC_CELL } from '../ASYNC_CELL.ts'
2
+
3
+ /*
4
+ A read-only async cell — what `computed(await …)` / `computed(getStream())` produce.
5
+ It *tracks* an async source (a promise it unwrapped, or a NamedAsyncIterable whose
6
+ frames it follows) rather than holding a value. Unlike sync `Computed<T>` it has NO
7
+ `.value`; it is read through the probe family, always method-form — `peek()` (the
8
+ retained value or latest frame, or `undefined`), `pending()` (no value yet),
9
+ `refreshing()` (a value held while a fresher source is in flight), `error()` (the
10
+ last rejection), `refresh()` (re-invoke the source). The standalone probes route
11
+ here too: `peek(cell)` ≡ `cell.peek()`. Branded so those probes recognise it.
12
+ */
13
+ export interface AsyncComputed<T> {
14
+ readonly [ASYNC_CELL]: true
15
+ peek(): T | undefined
16
+ pending(): boolean
17
+ refreshing(): boolean
18
+ error(): unknown
19
+ refresh(): void
20
+ }
@@ -0,0 +1,13 @@
1
+ import type { AsyncComputed } from './AsyncComputed.ts'
2
+
3
+ /*
4
+ A writable async cell — what `linked(await …)` / `linked(getStream())` produce. Same
5
+ probe surface as `AsyncComputed<T>` plus `set(value)`, following the normal `linked`
6
+ write rule: a local write latches until the next *reseed* (a dependency change that
7
+ produces a new source). An arriving frame or a settling promise updates the value only
8
+ while unwritten, so a high-frequency stream never clobbers an in-progress edit; a
9
+ reseed clears the write and snaps the cell back to the live source.
10
+ */
11
+ export interface AsyncState<T> extends AsyncComputed<T> {
12
+ set(value: T): void
13
+ }
@@ -37,20 +37,20 @@ into `__SSR__`; ones still pending were consumed via `{#await}` (render emitted
37
37
  the pending branch without blocking) and stream a resolve chunk instead.
38
38
 
39
39
  `refreshing` flips true while this entry is reloading data it already held —
40
- either an `swr` refetch (stale value still visible) or the default
40
+ either a keep-stale refetch (stale value still visible) or the default
41
41
  drop-then-reload (the prior entry was invalidated and dropped, this is its
42
42
  replacement read). It backs refreshing(), distinguishing a reload from a
43
43
  first-ever load; cleared when the read settles.
44
44
 
45
- `invalidation` holds the entry's `swr` policy: the refetch thunk (the call
45
+ `invalidation` holds the entry's refetch policy: the refetch thunk (the call
46
46
  captured with its args) plus its optional throttle/debounce window and runtime
47
47
  timer state, so invalidate() keeps the stale value and revalidates this key —
48
48
  rate-limited by the window — instead of dropping the entry. Set at registration
49
- when the creating read declared `swr`, or attached by a later read declaring it
50
- on an entry that lacks it (hydrated snapshot entries always start without one)
51
- first wins. An armed `timer` is cleared if the entry is evicted, so a dead key
52
- never refetches. Wrap-time validation guarantees `swr` never coexists with
53
- ttl: 0 and never sits on a non-replayable remote method.
49
+ for a smart retained read (SWR unconditional for a replayable read ADR-0020) or
50
+ a producer declaring a throttle/debounce window, or attached by a later read on an
51
+ entry that lacks it (hydrated snapshot entries always start without one) first
52
+ wins. An armed `timer` is cleared if the entry is evicted, so a dead key never
53
+ refetches.
54
54
  */
55
55
  export type CacheEntry = {
56
56
  key: string
@@ -1,14 +1,17 @@
1
1
  /*
2
- Options for cache(). The key is always auto-derived (method+url+args for a remote
3
- function, producer-reference+args for a plain producer): hoist a producer to a
4
- stable reference to share its entry across calls. `ttl` is the
5
- milliseconds-past-resolve that the entry stays live: 0 = dedupe only (entry
6
- dropped once the promise settles the mutation idiom: in-flight coalescing and
7
- pending() visibility, nothing retained), any other number = TTL. Omitted = forever
8
- for a producer and for a remote call on the client; a remote call on the SERVER
9
- with neither `ttl` nor `swr` stated defaults to 0 (coalesce-only — the request is
10
- the atomic unit, nothing is retained past it; pair with `shared` + an explicit
11
- `ttl` to memoise across requests).
2
+ Options for the explicit `cache(producer, args, options?)` call over a plain
3
+ producer, and the value-shape of an endpoint's `cache` policy (CachePolicy adds
4
+ only the arg-derived `tags` function form on top). A remote rpc has no options
5
+ argument any more its policy lives on the definition (ADR-0020); this type is
6
+ the producer's only policy home. The key is always auto-derived
7
+ (producer-reference+args): hoist a producer to a stable reference to share its
8
+ entry across calls.
9
+
10
+ `ttl` is the milliseconds-past-resolve the entry stays live: 0 = dedupe only
11
+ (entry dropped once the promise settles — in-flight coalescing and pending()
12
+ visibility, nothing retained), any other number = TTL. Omitted = forever for a
13
+ producer.
14
+
12
15
  `tags` is an array of free-form labels grouping unrelated calls so one
13
16
  `cache.invalidate({ tags })` drops every entry sharing any of them — list
14
17
  multiple when a call belongs to multiple invalidation groups. A unique tag (e.g.
@@ -17,39 +20,22 @@ a uuid) shared by a set of calls gives them their own private invalidation group
17
20
  `shared` opts the entry into the process-level store instead of the default
18
21
  request-scoped one (server) — a store that outlives every request. It selects
19
22
  the store only; it does NOT retain (pair it with `ttl` to memoise across
20
- requests). The shared store is keyed by method+url+args, never by user, so do
21
- not put per-user data in it — it would be served to other users. Omit `shared`
22
- for per-request data. Write only `shared: true`; there is no `false` form. On
23
- the client there is a single tab store, so the flag is a no-op there.
24
-
25
- `swr` is stale-while-revalidate: it changes what a `cache.invalidate` hit does
26
- to this key. Without it, an invalidate drops the entry and the next read shows
27
- `pending()`. With it, the entry is kept and refetched in the background — the
28
- existing (stale) value stays visible and `refreshing()` reports the in-flight
29
- reload — so the reader never blanks. It governs only the refetch-after-invalidate;
30
- the first fetch and arg-change fetches stay immediate regardless.
31
-
32
- `swr: true` refetches immediately on every invalidate. An optional window
33
- coalesces a burst (e.g. a socket spraying `cache.invalidate`) into far fewer
34
- calls: `swr: { throttle: N }` refetches on the leading edge then at most once
35
- per N ms while invalidations keep arriving; `swr: { debounce: N }` refetches
36
- only after N ms of quiet. `swr` declares the call safe to re-run unprompted:
37
- cache() throws at wrap time on throttle+debounce set at once, on ttl: 0 (nothing
38
- retained, nothing to revalidate), and on a non-replayable remote method
39
- (replaying a write is a state change disguised as a refresh). Producers are
40
- uncheckable — set `swr` only on a producer that is a pure read.
23
+ requests). The shared store is keyed by producer-reference+args, never by user,
24
+ so do not put per-user data in it — it would be served to other users. Omit
25
+ `shared` for per-request data. Write only `shared: true`; there is no `false`
26
+ form. On the client there is a single tab store, so the flag is a no-op there.
41
27
 
42
- `throttle`/`debounce` are root rate-limit windows for the refetch clock. For the
43
- smart bare call where SWR is unconditional for replayable reads, so there is no
44
- `swr` toggle to hang a window off they cap how often a background revalidation
45
- fires (leading-edge-then-coalesce, or fire-after-quiet respectively). They pair
46
- with the same wrap-time guard as the `swr` window: set one, not both.
28
+ `throttle`/`debounce` arm the keep-stale-and-revalidate refetch clock for a
29
+ producer: with one set, a `cache.invalidate` hit keeps the stale value visible
30
+ and coalesces a background refetch (leading-edge-then-coalesce, or
31
+ fire-after-quiet respectively) instead of dropping the entry. Set one, not both.
32
+ SWR is otherwise unconditional for replayable remote reads; there is no `swr`
33
+ toggle.
47
34
  */
48
35
  export type CacheOptions = {
49
36
  ttl?: number
50
37
  tags?: string[]
51
38
  shared?: boolean
52
- swr?: boolean | { throttle?: number; debounce?: number }
53
39
  throttle?: number
54
40
  debounce?: number
55
41
  }
@@ -0,0 +1,25 @@
1
+ /*
2
+ Endpoint cache policy, declared once on the rpc definition (ADR-0020). Same value
3
+ shape as the producer-side `CacheOptions` (`ttl` / `tags` / `throttle` / `debounce`
4
+ / `shared`, no `swr` — SWR is unconditional for replayable reads), except `tags`
5
+ also accepts an arg-derived function so the group can vary by call. That makes the
6
+ type generic over the rpc's `Args`: `(args) => ['rates:' + args.base]` is typed
7
+ against the endpoint's own argument shape.
8
+
9
+ - `ttl` — retention/staleness in ms. Default Infinity: the entry is retained for its
10
+ store's lifetime — the request on the server (a non-shared read dies with the request,
11
+ regardless of ttl), the tab on the client (until invalidate/refresh). An explicit ttl
12
+ is a hard expiry on the server, a staleness deadline (SWR) on the client.
13
+ - `tags` — static invalidation-group labels, or a function of the call's args.
14
+ - `throttle` / `debounce` — the background refetch clock (set one, not both).
15
+ - `shared` — opt the entry into the process-level store (never per-user data — the store
16
+ is keyed by method+url+args, not by user). With the default Infinity ttl this memoises
17
+ across requests; an explicit ttl bounds it. A client no-op (one tab store).
18
+ */
19
+ export type CachePolicy<Args> = {
20
+ ttl?: number
21
+ tags?: string[] | ((args: Args) => string[])
22
+ throttle?: number
23
+ debounce?: number
24
+ shared?: boolean
25
+ }
@@ -1,15 +1,16 @@
1
- import type { ReplayableMethod } from './ReplayableMethod.ts'
1
+ import type { HttpMethod } from './HttpMethod.ts'
2
2
 
3
3
  /*
4
4
  Wire format for a single cached response shipped from SSR to client hydration.
5
- Only replayable entries (see REPLAYABLE_METHODS) with a textual Content-Type
6
- are emitted writes must not re-fire from a snapshot, and binary bodies don't
7
- survive a JSON round-trip.
5
+ Any entry called inline during render (any method) with a textual Content-Type is
6
+ emitted, so the client hydrates warm instead of re-firing the call after render;
7
+ binary bodies don't survive a JSON round-trip. The seeded value is read warm once
8
+ — it is never auto-replayed (that stays GET-only, see REPLAYABLE_METHODS).
8
9
  */
9
10
  export type CacheSnapshotEntry = {
10
11
  key: string
11
12
  url: string
12
- method: ReplayableMethod
13
+ method: HttpMethod
13
14
  status: number
14
15
  statusText: string
15
16
  headers: Array<[string, string]>
@@ -0,0 +1,8 @@
1
+ /*
2
+ Status-keyed map of a handler's typed-error data schemas (ADR-0030), baked at build time from the
3
+ handler's `error.typed(name, status, schema?)` return branches. Each key is an HTTP status, each
4
+ value the error's `data` type projected to JSON Schema (multiple errors sharing a status combine
5
+ under `anyOf`; a nullary error with no data contributes a bare `{}`). Feeds the OpenAPI
6
+ `responses[status]` surface — the error-branch sibling of the success `outputJsonSchema`.
7
+ */
8
+ export type ErrorJsonSchemas = Record<number, Record<string, unknown>>
@@ -1 +1,3 @@
1
- export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD'
1
+ import type { HTTP_METHODS } from '../HTTP_METHODS.ts'
2
+
3
+ export type HttpMethod = (typeof HTTP_METHODS)[number]
@@ -0,0 +1,17 @@
1
+ import type { WireKind } from './WireKind.ts'
2
+
3
+ /*
4
+ The build-time wire codec plan for a rpc's input args, keyed by field name (ADR-0028 for the
5
+ scalar `number`/`boolean` kinds, generalized by ADR-0029 to the structured `date`/`bigint`/`set`/
6
+ `map` kinds). A GET/form request delivers every field as a string, and a non-abide JSON client
7
+ sends a `Date` as an ISO string / a `Set` as an array, so parseArgs uses this plan to revive each
8
+ declared field into the typed value the input schema expects — before validation, on the exact
9
+ fields the author declared. String and other-typed fields are never listed, so a value that merely
10
+ looks numeric (an id, a zip code, `'1.0'`) stays a string. The plan is derived by the warm server
11
+ program from the real type graph and stamped into the server `defineRpc` call; a field is absent
12
+ when its type is anything but a recognized WireKind (or an array / optional thereof), so the codec
13
+ is precise and fail-open — no plan ⇒ today's string-through behavior. The abide client's own
14
+ POST/PUT/PATCH body already round-trips these kinds via ref-json; the plan covers the query-string
15
+ and non-abide-client paths where ref-json isn't in play.
16
+ */
17
+ export type InputCoercion = Record<string, WireKind>
@@ -20,7 +20,7 @@ HTTP/SSE read face); one-shot rpc streams omit it. Implementers must signal
20
20
  `hooks.replayed` in-band once the seed portion is delivered (even when
21
21
  empty) so a seeded reader can commit its window atomically; see TailHooks.
22
22
  */
23
- export interface Subscribable<T> extends AsyncIterable<T> {
23
+ export interface NamedAsyncIterable<T> extends AsyncIterable<T> {
24
24
  readonly name: string
25
25
  tail?(count: number, hooks?: TailHooks): AsyncIterable<T>
26
26
  }
@@ -0,0 +1,17 @@
1
+ import type { WireKind } from './WireKind.ts'
2
+
3
+ /*
4
+ The build-time wire codec plan for a rpc's success RESPONSE body, keyed by top-level field name
5
+ (ADR-0029 output path — the response-side sibling of `InputCoercion`). The server serializes a
6
+ handler's structured return through a value-directed replacer (`wireJsonReplacer`), so a `Set`
7
+ crosses as a JSON array, a `Map` as an `[K,V]` entries array, and a `bigint` as a digit string —
8
+ honest JSON a non-abide client still reads. But a wire array is ambiguous (a real `T[]` vs an
9
+ encoded `Set<T>`), so an abide client needs the DECLARED kind to revive: this plan carries only the
10
+ structured kinds (`date`/`bigint`/`set`/`map`) the client proxy revives from a decoded response body.
11
+ It is resolved by the warm server program from the handler's success-body type and baked onto the
12
+ CLIENT `remoteProxy` stub (next to the live `schemas`, ADR-0022 D2). A field absent from the plan (a
13
+ genuine array, a scalar, a `number`/`boolean` JSON already carries) is left untouched. Fail-open —
14
+ no plan / an unrevivable value keeps the honest-JSON form, never a throw. Top-level fields only in
15
+ this increment; a structured value nested inside another value is not descended into.
16
+ */
17
+ export type OutputWirePlan = Record<string, WireKind>
@@ -0,0 +1,7 @@
1
+ /* The classification scanPages returns for src/ui/pages: route leaves
2
+ (page.abide) and layout leaves (layout.abide), each an array of paths
3
+ relative to the pages dir. */
4
+ export type PagesScan = {
5
+ pageFiles: string[]
6
+ layoutFiles: string[]
7
+ }
@@ -0,0 +1,10 @@
1
+ /*
2
+ The per-request list of in-flight async-cell promises registered during an SSR
3
+ render. `createAsyncCell` pushes each settling promise here (server-side only);
4
+ `settleAsyncCells` drains and awaits them between a component's cell declarations
5
+ and its template, so the resolved values bake into the first-pass HTML (ADR-0019
6
+ Tier-2) instead of the template peeking `undefined`.
7
+ */
8
+ export type PendingAsyncCells = {
9
+ promises: Promise<unknown>[]
10
+ }
@@ -1,5 +1,7 @@
1
+ import type { CachePolicy } from './CachePolicy.ts'
1
2
  import type { HttpMethod } from './HttpMethod.ts'
2
3
  import type { RemoteCallable } from './RemoteCallable.ts'
4
+ import type { StreamPolicy } from './StreamPolicy.ts'
3
5
 
4
6
  /*
5
7
  Bare-response remote function — same call shape as RemoteFunction but
@@ -11,4 +13,8 @@ implement custom error handling can opt out of the decode.
11
13
  export type RawRemoteFunction<Args> = RemoteCallable<Args, Response> & {
12
14
  readonly method: HttpMethod
13
15
  readonly url: string
16
+ /* Endpoint cache/stream policy (ADR-0020), stamped on this variant too so readThrough can
17
+ read it whether the caller passed `fn` or `fn.raw`. Same value as the decoded sibling's. */
18
+ readonly cache?: CachePolicy<Args>
19
+ readonly stream?: StreamPolicy
14
20
  }
@@ -1,5 +1,5 @@
1
+ import type { NamedAsyncIterable } from './NamedAsyncIterable.ts'
1
2
  import type { RpcOptions } from './RpcOptions.ts'
2
- import type { Subscribable } from './Subscribable.ts'
3
3
 
4
4
  /*
5
5
  Call signature shared by RemoteFunction and RawRemoteFunction. The base
@@ -10,24 +10,25 @@ optional-arg signature lets call sites write `fn()` instead of
10
10
  stays callable while `Args` is still generic (cache() invokes producers
11
11
  before `Args` resolves). FormData is the multipart upload escape hatch —
12
12
  see RemoteFunction. The trailing `Opts` differs by variant: the smart bare
13
- call (RemoteFunction) carries cache/stream options (SmartReadOptions), while
14
- `.raw` (RawRemoteFunction) carries per-call transport options (RpcOptions:
13
+ call (RemoteFunction) takes no second argument at all (`Opts = never` — all
14
+ cache/stream policy lives on the rpc definition per ADR-0020), while `.raw`
15
+ (RawRemoteFunction) carries per-call transport options (RpcOptions:
15
16
  signal/keepalive/priority/cache/headers). The server ignores either, so the
16
17
  callable stays isomorphic.
17
18
 
18
19
  A streaming `Resolved` (an `AsyncIterable<Frame>`, branded by jsonl()/sse()) makes
19
- the bare call return a `Subscribable<Frame>` synchronously — the iterable IS the
20
+ the bare call return a `NamedAsyncIterable<Frame>` synchronously — the iterable IS the
20
21
  value, consumed by `for await` or `state(fn(args))`, no `.stream()`. Every other
21
22
  `Resolved` stays `Promise<Resolved>`. `await`-ing a streaming call is a compile
22
- error (a Subscribable is not awaitable), which replaces the old runtime guard.
23
+ error (a NamedAsyncIterable is not awaitable), which replaces the old runtime guard.
23
24
  */
24
25
  /* `[Resolved] extends [never]` first: a handler that only ever returns error() resolves to
25
26
  `never`, and `never extends AsyncIterable` is vacuously true — without this guard its call
26
- would mistype as a Subscribable. A real streaming rpc's `Resolved` is `AsyncIterable<Frame>`. */
27
+ would mistype as a NamedAsyncIterable. A real streaming rpc's `Resolved` is `AsyncIterable<Frame>`. */
27
28
  type CallResult<Resolved> = [Resolved] extends [never]
28
29
  ? Promise<Resolved>
29
30
  : Resolved extends AsyncIterable<infer Frame>
30
- ? Subscribable<Frame>
31
+ ? NamedAsyncIterable<Frame>
31
32
  : Promise<Resolved>
32
33
 
33
34
  export type RemoteCallable<Args, Resolved, Opts = RpcOptions> = ((
@@ -1,12 +1,12 @@
1
+ import type { CachePolicy } from './CachePolicy.ts'
1
2
  import type { ClientFlags } from './ClientFlags.ts'
2
3
  import type { ErrorSpec } from './ErrorSpec.ts'
3
4
  import type { HttpMethod } from './HttpMethod.ts'
4
- import type { Outbox } from './Outbox.ts'
5
5
  import type { RawRemoteFunction } from './RawRemoteFunction.ts'
6
6
  import type { RemoteCallable } from './RemoteCallable.ts'
7
7
  import type { RpcError } from './RpcError.ts'
8
8
  import type { RpcErrorGuard } from './RpcErrorGuard.ts'
9
- import type { SmartReadOptions } from './SmartReadOptions.ts'
9
+ import type { StreamPolicy } from './StreamPolicy.ts'
10
10
 
11
11
  /*
12
12
  Remote function reference produced by GET/POST/... inside an `$rpc/**`
@@ -21,7 +21,7 @@ method, same url, same args, no decode. Pass `fn.raw` to cache() to
21
21
  memoise raw Responses against the same cache key as `fn` (both share one
22
22
  stored entry — the decode just happens on the way out for callers of
23
23
  `fn`). A streaming handler (jsonl()/sse()) makes the bare call return a
24
- `Subscribable<Frame>` directly (the iterable IS the value) — consume it with
24
+ `NamedAsyncIterable<Frame>` directly (the iterable IS the value) — consume it with
25
25
  `for await (… of fn(args))` or `state(fn(args))`; there is no `.stream()`, and
26
26
  `await`-ing a streaming call is a compile error. For sustained broadcast /
27
27
  pub-sub use the `abide/server/socket` primitive — HTTP rpc isn't the place for
@@ -44,23 +44,29 @@ export type RemoteFunction<
44
44
  Args,
45
45
  Return,
46
46
  Errors extends ErrorSpec = Record<never, never>,
47
- Durable extends boolean = false,
48
- > = RemoteCallable<Args, Return, SmartReadOptions> & {
47
+ > = RemoteCallable<Args, Return, never> & {
49
48
  readonly method: HttpMethod
50
49
  readonly url: string
51
50
  readonly clients: ClientFlags
52
51
  readonly crossOrigin?: boolean
52
+ /* Endpoint cache/stream policy declared on the rpc definition (ADR-0020), stamped
53
+ here so the smart read (readThrough) reads it as the bottom policy layer. Ships to
54
+ the client too — it governs client cache behaviour and is behaviour, not secrets
55
+ (`shared` is a client no-op). Absent on a plainly-defined rpc (method defaults only). */
56
+ readonly cache?: CachePolicy<Args>
57
+ readonly stream?: StreamPolicy
53
58
  readonly raw: RawRemoteFunction<Args>
54
59
  fetch(request: Request): Promise<Response>
55
60
  /* Type-guard a caught error against this rpc's declared `errors` (plus the framework
56
- `'validation'` / `'queued'`): narrows `.kind` and, for a known kind, `.data` — the
57
- per-rpc replacement for a global guard, since the error name → data type mapping
58
- lives in the rpc's own spec. */
61
+ `'validation'`): narrows `.kind` and, for a known kind, `.data` — the per-rpc
62
+ replacement for a global guard, since the error name → data type mapping lives in
63
+ the rpc's own spec. */
59
64
  readonly isError: RpcErrorGuard<Errors>
60
65
  /* Pre-bound selector sugar: `fn.pending(args?)` ≡ `pending(fn, args?)`, and likewise for
61
66
  refreshing / refresh / peek — the rpc is the leading selector, bound in. The argument is
62
67
  this rpc's typed `Args` (the by-args refinement); tags / cross-cutting selection stay on
63
- the globals. The bare call `fn(args, opts)` IS the cached read (was `fn.cache`), and
68
+ the globals. The bare call `fn(args)` IS the cached read (was `fn.cache`) — all cache
69
+ policy lives on the definition, so there is no second options argument, and
64
70
  `refresh(args?)` refetches keeping the stale value visible (was `invalidate`, which
65
71
  dropped). `peek(args?)` reads the retained value synchronously (a streaming rpc peeks its
66
72
  latest frame). `patch` is fetch-only, so it is omitted for a streaming rpc (a stream isn't
@@ -93,9 +99,4 @@ export type RemoteFunction<
93
99
  : {
94
100
  patch(args: Args | undefined, updater: (current: Return) => Return): void
95
101
  patch(updater: (current: Return) => Return): void
96
- }) /* `outbox` presence follows the `outbox: true` opt: the mutating helper threads `Durable`
97
- into the return type so a DURABLE rpc's `.outbox` is the required queue face (no optional
98
- chain). A non-durable rpc keeps it optional — assignable to a durable one everywhere a
99
- bare `RemoteFunction<Args, Return>` slot (cache selectors, registries) is expected, since
100
- required→optional widens cleanly and no call site had to learn the `Durable` bit. */ &
101
- (Durable extends true ? { readonly outbox: Outbox<Args> } : { readonly outbox?: Outbox<Args> })
102
+ })
@@ -0,0 +1,11 @@
1
+ /*
2
+ The per-request list of async-cell values that RESOLVED during an SSR render, each keyed by the
3
+ cell's serialization-stable render-path id (`${scope.id}:${index}`). `createAsyncCell` pushes an
4
+ entry when its seed settles server-side; the page renderer stamps them into `__SSR__.cells`
5
+ (ref-json-encoded) so the client hydrates the cell WARM — reading the value instead of re-running
6
+ the seed (no refetch, no pending flash). The sibling of `PendingAsyncCells` (the barrier's
7
+ in-flight list); this one holds settled VALUES, read at render-return rather than awaited.
8
+ */
9
+ export type ResolvedCells = {
10
+ entries: { key: string; value: unknown }[]
11
+ }
@@ -0,0 +1,15 @@
1
+ /*
2
+ The build-time success-body descriptor for an rpc, derived from the handler's return type by the
3
+ warm server program (ADR-0030). Mirrors `RpcHelper`'s `SuccessBody<R>` projection: the handler's
4
+ `Awaited<ReturnType>` union has its `TypedError` branches dropped, and each success
5
+ `TypedResponse<Body>` contributes its `Body`. `type` is that body rendered as a TS type string
6
+ (the union of the surviving branches). For a streaming endpoint (`jsonl()`/`sse()` →
7
+ `TypedResponse<AsyncIterable<Frame>>`) `streaming` is true and `type` is the per-FRAME type — the
8
+ AsyncIterable element — so a consumer describes one streamed item rather than the iterable itself.
9
+ The query fails open to undefined (no handler/body resolvable), matching every other server-program
10
+ query.
11
+ */
12
+ export type ReturnBody = {
13
+ type: string
14
+ streaming: boolean
15
+ }