@abide/abide 0.28.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 (562) hide show
  1. package/CHANGELOG.md +607 -0
  2. package/LICENSE +21 -0
  3. package/README.md +154 -0
  4. package/bin/abide.ts +212 -0
  5. package/package.json +155 -0
  6. package/src/abideLsp.ts +211 -0
  7. package/src/abideModules.d.ts +8 -0
  8. package/src/abideResolverPlugin.ts +923 -0
  9. package/src/appEntry.ts +151 -0
  10. package/src/assets/app.html +12 -0
  11. package/src/build.ts +143 -0
  12. package/src/buildCli.ts +127 -0
  13. package/src/buildDisconnected.ts +118 -0
  14. package/src/bundleApp.ts +147 -0
  15. package/src/bundleDisconnectedEntry.ts +14 -0
  16. package/src/checkAbide.ts +77 -0
  17. package/src/cliEntry.ts +25 -0
  18. package/src/clientBuildPlugins.ts +33 -0
  19. package/src/clientEntry.ts +17 -0
  20. package/src/compile.ts +63 -0
  21. package/src/controlServerWorker.ts +426 -0
  22. package/src/devEntry.ts +250 -0
  23. package/src/discoveryEntry.ts +81 -0
  24. package/src/lib/bundle/BundleMenu.ts +12 -0
  25. package/src/lib/bundle/BundleMenuItem.ts +25 -0
  26. package/src/lib/bundle/BundleWindow.ts +37 -0
  27. package/src/lib/bundle/WEBVIEW_BUILD_REVISION.ts +9 -0
  28. package/src/lib/bundle/WEBVIEW_VERSION.ts +7 -0
  29. package/src/lib/bundle/bindConnectedFlag.ts +29 -0
  30. package/src/lib/bundle/bindRequestNavigate.ts +34 -0
  31. package/src/lib/bundle/buildWebviewLib.ts +111 -0
  32. package/src/lib/bundle/bundled.ts +35 -0
  33. package/src/lib/bundle/disconnected.abide +236 -0
  34. package/src/lib/bundle/disconnected.css +9 -0
  35. package/src/lib/bundle/ensureWebviewLib.ts +20 -0
  36. package/src/lib/bundle/exitWithParent.ts +28 -0
  37. package/src/lib/bundle/infoPlist.ts +46 -0
  38. package/src/lib/bundle/installDownloads.ts +24 -0
  39. package/src/lib/bundle/installMacMenu.ts +39 -0
  40. package/src/lib/bundle/listenLocalControlServer.ts +19 -0
  41. package/src/lib/bundle/native/abideMenu.mm +422 -0
  42. package/src/lib/bundle/native/webview.h +4557 -0
  43. package/src/lib/bundle/onMenu.ts +42 -0
  44. package/src/lib/bundle/openWebview.ts +104 -0
  45. package/src/lib/bundle/pngToIcns.ts +47 -0
  46. package/src/lib/bundle/probeAbideServer.ts +57 -0
  47. package/src/lib/bundle/resolveServerBinary.ts +12 -0
  48. package/src/lib/bundle/resolveWebviewLib.ts +53 -0
  49. package/src/lib/bundle/serverBinaryFilename.ts +8 -0
  50. package/src/lib/bundle/signMacApp.ts +37 -0
  51. package/src/lib/bundle/spawnEmbeddedServer.ts +64 -0
  52. package/src/lib/bundle/stableLocalPort.ts +19 -0
  53. package/src/lib/bundle/waitForServer.ts +23 -0
  54. package/src/lib/bundle/webviewCachePath.ts +23 -0
  55. package/src/lib/bundle/webviewLibName.ts +11 -0
  56. package/src/lib/cli/connectToServer.ts +23 -0
  57. package/src/lib/cli/createClient.ts +108 -0
  58. package/src/lib/cli/dispatchCommand.ts +71 -0
  59. package/src/lib/cli/loadEnvFromBinaryDir.ts +15 -0
  60. package/src/lib/cli/parseArgvForRpc.ts +100 -0
  61. package/src/lib/cli/printHelp.ts +119 -0
  62. package/src/lib/cli/printSessionHelp.ts +27 -0
  63. package/src/lib/cli/printSessionStatus.ts +21 -0
  64. package/src/lib/cli/printTrimmed.ts +8 -0
  65. package/src/lib/cli/printValue.ts +10 -0
  66. package/src/lib/cli/resolveCliTarget.ts +48 -0
  67. package/src/lib/cli/runCli.ts +176 -0
  68. package/src/lib/cli/runSession.ts +108 -0
  69. package/src/lib/cli/startLocalInstance.ts +14 -0
  70. package/src/lib/cli/tokenizeLine.ts +51 -0
  71. package/src/lib/cli/types/CliManifest.ts +9 -0
  72. package/src/lib/cli/types/CliManifestEntry.ts +17 -0
  73. package/src/lib/cli/types/CliTarget.ts +13 -0
  74. package/src/lib/mcp/annotationsForMethod.ts +29 -0
  75. package/src/lib/mcp/createMcpResourceServer.ts +102 -0
  76. package/src/lib/mcp/createMcpServer.ts +48 -0
  77. package/src/lib/mcp/dispatchMcpRequest.ts +138 -0
  78. package/src/lib/mcp/mcpResourceServerSlot.ts +18 -0
  79. package/src/lib/mcp/mcpSurface.ts +295 -0
  80. package/src/lib/mcp/toolResultFromResponse.ts +66 -0
  81. package/src/lib/mcp/types/JsonRpcRequest.ts +12 -0
  82. package/src/lib/mcp/types/JsonRpcResponse.ts +20 -0
  83. package/src/lib/mcp/types/McpResourceContents.ts +10 -0
  84. package/src/lib/mcp/types/McpResourceDescriptor.ts +6 -0
  85. package/src/lib/mcp/types/McpResourceServer.ts +12 -0
  86. package/src/lib/mcp/types/McpServer.ts +9 -0
  87. package/src/lib/mcp/types/McpServerOptions.ts +16 -0
  88. package/src/lib/server/AppModule.ts +47 -0
  89. package/src/lib/server/DELETE.ts +10 -0
  90. package/src/lib/server/GET.ts +10 -0
  91. package/src/lib/server/HEAD.ts +10 -0
  92. package/src/lib/server/PATCH.ts +10 -0
  93. package/src/lib/server/POST.ts +10 -0
  94. package/src/lib/server/PUT.ts +10 -0
  95. package/src/lib/server/agent.ts +86 -0
  96. package/src/lib/server/appDataDir.ts +16 -0
  97. package/src/lib/server/cli/buildEnvContent.ts +19 -0
  98. package/src/lib/server/cli/createTarGz.ts +77 -0
  99. package/src/lib/server/cli/handleCliDownload.ts +150 -0
  100. package/src/lib/server/cli/handleCliInstall.ts +37 -0
  101. package/src/lib/server/cli/installScript.ts +31 -0
  102. package/src/lib/server/cli/maxSourceMtime.ts +26 -0
  103. package/src/lib/server/cookies.ts +30 -0
  104. package/src/lib/server/env.ts +51 -0
  105. package/src/lib/server/error.ts +73 -0
  106. package/src/lib/server/json.ts +42 -0
  107. package/src/lib/server/jsonl.ts +47 -0
  108. package/src/lib/server/prompts/definePrompt.ts +21 -0
  109. package/src/lib/server/prompts/promptRegistry.ts +9 -0
  110. package/src/lib/server/prompts/registerPrompt.ts +6 -0
  111. package/src/lib/server/prompts/renderPromptTemplate.ts +17 -0
  112. package/src/lib/server/prompts/types/Prompt.ts +13 -0
  113. package/src/lib/server/prompts/types/PromptOptions.ts +12 -0
  114. package/src/lib/server/prompts/types/PromptRegistryEntry.ts +13 -0
  115. package/src/lib/server/prompts/types/PromptRoutes.ts +10 -0
  116. package/src/lib/server/reachable.ts +45 -0
  117. package/src/lib/server/redirect.ts +43 -0
  118. package/src/lib/server/request.ts +19 -0
  119. package/src/lib/server/rpc/defineVerb.ts +210 -0
  120. package/src/lib/server/rpc/dispatchVerbInProcess.ts +46 -0
  121. package/src/lib/server/rpc/findVerbByCommandName.ts +18 -0
  122. package/src/lib/server/rpc/parseArgs.ts +127 -0
  123. package/src/lib/server/rpc/readBodyWithinLimit.ts +44 -0
  124. package/src/lib/server/rpc/registerVerb.ts +6 -0
  125. package/src/lib/server/rpc/runWithVerbTimeout.ts +49 -0
  126. package/src/lib/server/rpc/types/RemoteHandler.ts +27 -0
  127. package/src/lib/server/rpc/types/RemoteRoutes.ts +13 -0
  128. package/src/lib/server/rpc/types/TypedResponse.ts +18 -0
  129. package/src/lib/server/rpc/types/VerbHelper.ts +87 -0
  130. package/src/lib/server/rpc/types/VerbRegistryEntry.ts +35 -0
  131. package/src/lib/server/rpc/unprocessed.ts +14 -0
  132. package/src/lib/server/rpc/verbRegistry.ts +11 -0
  133. package/src/lib/server/runtime/DEFAULT_PORT.ts +6 -0
  134. package/src/lib/server/runtime/DEV_READY_MESSAGE.ts +6 -0
  135. package/src/lib/server/runtime/DEV_REBUILD_MESSAGE.ts +4 -0
  136. package/src/lib/server/runtime/DEV_RELOAD_CLIENT_SCRIPT.ts +107 -0
  137. package/src/lib/server/runtime/SSR_SWAP_SCRIPT.ts +16 -0
  138. package/src/lib/server/runtime/acceptsGzip.ts +24 -0
  139. package/src/lib/server/runtime/buildCacheSnapshot.ts +61 -0
  140. package/src/lib/server/runtime/buildHealthPayload.ts +34 -0
  141. package/src/lib/server/runtime/buildInspectorSurface.ts +37 -0
  142. package/src/lib/server/runtime/buildOpenApiSpec.ts +106 -0
  143. package/src/lib/server/runtime/cacheControlForAsset.ts +22 -0
  144. package/src/lib/server/runtime/containsTraversal.ts +37 -0
  145. package/src/lib/server/runtime/createAppAssetServer.ts +76 -0
  146. package/src/lib/server/runtime/createAssetHeaderCache.ts +31 -0
  147. package/src/lib/server/runtime/createPublicAssetServer.ts +67 -0
  148. package/src/lib/server/runtime/createReachable.ts +109 -0
  149. package/src/lib/server/runtime/createRouteDispatcher.ts +127 -0
  150. package/src/lib/server/runtime/createServer.ts +674 -0
  151. package/src/lib/server/runtime/createUiPageRenderer.ts +181 -0
  152. package/src/lib/server/runtime/crossOriginForbidden.ts +17 -0
  153. package/src/lib/server/runtime/crossOriginGate.ts +29 -0
  154. package/src/lib/server/runtime/devClientFingerprint.ts +117 -0
  155. package/src/lib/server/runtime/devHotModuleResponse.ts +40 -0
  156. package/src/lib/server/runtime/devReloadResponse.ts +41 -0
  157. package/src/lib/server/runtime/disableIdleTimeoutForStream.ts +27 -0
  158. package/src/lib/server/runtime/envSchemaStore.ts +15 -0
  159. package/src/lib/server/runtime/findOpenPort.ts +21 -0
  160. package/src/lib/server/runtime/getActiveServer.ts +6 -0
  161. package/src/lib/server/runtime/globToPathSet.ts +29 -0
  162. package/src/lib/server/runtime/gzipResponse.ts +46 -0
  163. package/src/lib/server/runtime/inProcessServer.ts +20 -0
  164. package/src/lib/server/runtime/internalErrorResponse.ts +25 -0
  165. package/src/lib/server/runtime/isCrossOriginRequest.ts +23 -0
  166. package/src/lib/server/runtime/listenOnOpenPort.ts +36 -0
  167. package/src/lib/server/runtime/logExposedSurfaces.ts +156 -0
  168. package/src/lib/server/runtime/maybeMountInspector.ts +97 -0
  169. package/src/lib/server/runtime/mimeForExtension.ts +14 -0
  170. package/src/lib/server/runtime/pageUrlFromStore.ts +15 -0
  171. package/src/lib/server/runtime/parseIdleTimeout.ts +10 -0
  172. package/src/lib/server/runtime/parsePort.ts +11 -0
  173. package/src/lib/server/runtime/registryManifests.ts +66 -0
  174. package/src/lib/server/runtime/requestContext.ts +5 -0
  175. package/src/lib/server/runtime/resolvePageSnapshot.ts +25 -0
  176. package/src/lib/server/runtime/respondWithEmbeddedAsset.ts +18 -0
  177. package/src/lib/server/runtime/runWithRequestScope.ts +150 -0
  178. package/src/lib/server/runtime/safeJsonForScript.ts +17 -0
  179. package/src/lib/server/runtime/serializeCacheSnapshot.ts +45 -0
  180. package/src/lib/server/runtime/serverSlot.ts +13 -0
  181. package/src/lib/server/runtime/setActiveServer.ts +6 -0
  182. package/src/lib/server/runtime/snapshotEntryFromCache.ts +83 -0
  183. package/src/lib/server/runtime/streamCacheResolutions.ts +37 -0
  184. package/src/lib/server/runtime/streamFromIterator.ts +86 -0
  185. package/src/lib/server/runtime/types/Assets.ts +6 -0
  186. package/src/lib/server/runtime/types/DevReloadStamp.ts +18 -0
  187. package/src/lib/server/runtime/types/InspectorCacheEntry.ts +24 -0
  188. package/src/lib/server/runtime/types/InspectorCacheSnapshot.ts +11 -0
  189. package/src/lib/server/runtime/types/InspectorContext.ts +30 -0
  190. package/src/lib/server/runtime/types/InspectorSocket.ts +17 -0
  191. package/src/lib/server/runtime/types/InspectorSurface.ts +13 -0
  192. package/src/lib/server/runtime/types/InspectorVerb.ts +27 -0
  193. package/src/lib/server/runtime/types/RequestStore.ts +55 -0
  194. package/src/lib/server/runtime/warnUnguardedMcp.ts +32 -0
  195. package/src/lib/server/runtime/withResponseDefaults.ts +24 -0
  196. package/src/lib/server/server.ts +33 -0
  197. package/src/lib/server/socket.ts +32 -0
  198. package/src/lib/server/sockets/createSocketDispatcher.ts +337 -0
  199. package/src/lib/server/sockets/defineSocket.ts +179 -0
  200. package/src/lib/server/sockets/lookupSocket.ts +6 -0
  201. package/src/lib/server/sockets/registerSocket.ts +6 -0
  202. package/src/lib/server/sockets/socketOperations.ts +36 -0
  203. package/src/lib/server/sockets/socketRegistry.ts +9 -0
  204. package/src/lib/server/sockets/types/Socket.ts +23 -0
  205. package/src/lib/server/sockets/types/SocketClientFrame.ts +19 -0
  206. package/src/lib/server/sockets/types/SocketOperation.ts +22 -0
  207. package/src/lib/server/sockets/types/SocketOptions.ts +26 -0
  208. package/src/lib/server/sockets/types/SocketRegistryEntry.ts +19 -0
  209. package/src/lib/server/sockets/types/SocketRoutes.ts +10 -0
  210. package/src/lib/server/sockets/types/SocketServerFrame.ts +24 -0
  211. package/src/lib/server/sse.ts +54 -0
  212. package/src/lib/shared/ABIDE_PACKAGE_NAME.ts +7 -0
  213. package/src/lib/shared/ABIDE_VERSION.ts +9 -0
  214. package/src/lib/shared/CACHE_CONTROL_VALUES.ts +16 -0
  215. package/src/lib/shared/CACHE_WRAPPED.ts +8 -0
  216. package/src/lib/shared/CLI_PATH.ts +7 -0
  217. package/src/lib/shared/DEV_HOT_PREFIX.ts +7 -0
  218. package/src/lib/shared/DEV_RELOAD_PATH.ts +6 -0
  219. package/src/lib/shared/HEALTH_PATH.ts +7 -0
  220. package/src/lib/shared/HttpError.ts +20 -0
  221. package/src/lib/shared/IDENTITY_PATH.ts +6 -0
  222. package/src/lib/shared/INSPECTOR_PATH.ts +7 -0
  223. package/src/lib/shared/NAV_HEADER.ts +8 -0
  224. package/src/lib/shared/OFFLINE_HEADER.ts +8 -0
  225. package/src/lib/shared/REMOTE_FUNCTION.ts +8 -0
  226. package/src/lib/shared/REPLAYABLE_METHODS.ts +12 -0
  227. package/src/lib/shared/SOCKETS_PATH.ts +7 -0
  228. package/src/lib/shared/STREAMING_CONTENT_TYPES.ts +11 -0
  229. package/src/lib/shared/SocketDisconnectedError.ts +13 -0
  230. package/src/lib/shared/TEXT_PLAIN.ts +7 -0
  231. package/src/lib/shared/abideImportName.ts +44 -0
  232. package/src/lib/shared/abideLog.ts +38 -0
  233. package/src/lib/shared/activeCacheStore.ts +20 -0
  234. package/src/lib/shared/activePage.ts +25 -0
  235. package/src/lib/shared/appDataDir.ts +34 -0
  236. package/src/lib/shared/appNameSlot.ts +10 -0
  237. package/src/lib/shared/basePath.ts +10 -0
  238. package/src/lib/shared/basePathFromAppUrl.ts +20 -0
  239. package/src/lib/shared/baseSlot.ts +14 -0
  240. package/src/lib/shared/binaryDirEnvPath.ts +12 -0
  241. package/src/lib/shared/browserClientFlags.ts +10 -0
  242. package/src/lib/shared/buildRpcProxy.ts +39 -0
  243. package/src/lib/shared/buildRpcRequest.ts +70 -0
  244. package/src/lib/shared/buildSocketOverChannel.ts +58 -0
  245. package/src/lib/shared/bundleLayout.ts +36 -0
  246. package/src/lib/shared/cache.ts +951 -0
  247. package/src/lib/shared/cacheEntryFromSnapshot.ts +59 -0
  248. package/src/lib/shared/cacheStoreSlot.ts +16 -0
  249. package/src/lib/shared/cacheStores.ts +10 -0
  250. package/src/lib/shared/canonicalJson.ts +63 -0
  251. package/src/lib/shared/carriesBodyArgs.ts +13 -0
  252. package/src/lib/shared/clearLastConnection.ts +7 -0
  253. package/src/lib/shared/commandNameForUrl.ts +17 -0
  254. package/src/lib/shared/createCacheStore.ts +104 -0
  255. package/src/lib/shared/createChannelLog.ts +122 -0
  256. package/src/lib/shared/createLifecycleChannel.ts +56 -0
  257. package/src/lib/shared/createLivenessWatch.ts +118 -0
  258. package/src/lib/shared/createPushIterator.ts +127 -0
  259. package/src/lib/shared/createRemoteFunction.ts +122 -0
  260. package/src/lib/shared/createSubscriber.ts +55 -0
  261. package/src/lib/shared/createTraceContext.ts +21 -0
  262. package/src/lib/shared/dataDirEnvPath.ts +12 -0
  263. package/src/lib/shared/decodeResponse.ts +47 -0
  264. package/src/lib/shared/detectTarget.ts +27 -0
  265. package/src/lib/shared/detectVerbMethod.ts +17 -0
  266. package/src/lib/shared/emitLogRecord.ts +190 -0
  267. package/src/lib/shared/exeSuffix.ts +9 -0
  268. package/src/lib/shared/exitOnBuildFailure.ts +17 -0
  269. package/src/lib/shared/extraForwardHeaders.ts +16 -0
  270. package/src/lib/shared/fileStem.ts +9 -0
  271. package/src/lib/shared/findExportCallSite.ts +476 -0
  272. package/src/lib/shared/formatTraceparent.ts +6 -0
  273. package/src/lib/shared/forwardHeaders.ts +44 -0
  274. package/src/lib/shared/getRemoteMeta.ts +5 -0
  275. package/src/lib/shared/globalCacheStore.ts +15 -0
  276. package/src/lib/shared/globalCacheStoreSlot.ts +14 -0
  277. package/src/lib/shared/health.ts +179 -0
  278. package/src/lib/shared/healthReadSlot.ts +11 -0
  279. package/src/lib/shared/healthSeedSlot.ts +12 -0
  280. package/src/lib/shared/html.ts +38 -0
  281. package/src/lib/shared/importNamesToStrip.ts +13 -0
  282. package/src/lib/shared/invalidateEvent.ts +11 -0
  283. package/src/lib/shared/invalidateTripwire.ts +40 -0
  284. package/src/lib/shared/isAbideHealthPayload.ts +11 -0
  285. package/src/lib/shared/isCompileTarget.ts +15 -0
  286. package/src/lib/shared/isDebugEnabled.ts +26 -0
  287. package/src/lib/shared/isDebugNegated.ts +19 -0
  288. package/src/lib/shared/isModuleNotFound.ts +16 -0
  289. package/src/lib/shared/isReadOnlyMethod.ts +14 -0
  290. package/src/lib/shared/isReplayableMethod.ts +7 -0
  291. package/src/lib/shared/isStreamingResponse.ts +11 -0
  292. package/src/lib/shared/isSubscribable.ts +15 -0
  293. package/src/lib/shared/jsonSchemaForPromptArguments.ts +29 -0
  294. package/src/lib/shared/jsonSchemaForSchema.ts +39 -0
  295. package/src/lib/shared/jsonlErrorFrame.ts +24 -0
  296. package/src/lib/shared/keyForRemoteCall.ts +29 -0
  297. package/src/lib/shared/keyMatchesPrefix.ts +9 -0
  298. package/src/lib/shared/lastConnectionPath.ts +7 -0
  299. package/src/lib/shared/layoutChainForRoute.ts +22 -0
  300. package/src/lib/shared/loadEnvFile.ts +17 -0
  301. package/src/lib/shared/loadEnvFromDataDir.ts +14 -0
  302. package/src/lib/shared/log.ts +24 -0
  303. package/src/lib/shared/logClosingRecord.ts +28 -0
  304. package/src/lib/shared/logTapSlot.ts +13 -0
  305. package/src/lib/shared/manifestModule.ts +39 -0
  306. package/src/lib/shared/matchesDebugPattern.ts +16 -0
  307. package/src/lib/shared/memoizeByKey.ts +32 -0
  308. package/src/lib/shared/normalizeTarget.ts +10 -0
  309. package/src/lib/shared/online.ts +51 -0
  310. package/src/lib/shared/page.ts +30 -0
  311. package/src/lib/shared/pageSlot.ts +17 -0
  312. package/src/lib/shared/pageUrlForFile.ts +14 -0
  313. package/src/lib/shared/parseBoundedEnvInt.ts +20 -0
  314. package/src/lib/shared/parseDebugPatterns.ts +21 -0
  315. package/src/lib/shared/parseEnv.ts +30 -0
  316. package/src/lib/shared/parsePromptMarkdown.ts +35 -0
  317. package/src/lib/shared/parseRouteSegments.ts +22 -0
  318. package/src/lib/shared/parseTraceparent.ts +26 -0
  319. package/src/lib/shared/pending.ts +30 -0
  320. package/src/lib/shared/prepareRpcModule.ts +59 -0
  321. package/src/lib/shared/prepareSocketModule.ts +49 -0
  322. package/src/lib/shared/probeRegistries.ts +68 -0
  323. package/src/lib/shared/producerKey.ts +32 -0
  324. package/src/lib/shared/programNameForPackage.ts +14 -0
  325. package/src/lib/shared/promptNameForFile.ts +10 -0
  326. package/src/lib/shared/queryStringFromArgs.ts +27 -0
  327. package/src/lib/shared/randomHexId.ts +14 -0
  328. package/src/lib/shared/readEnvFile.ts +15 -0
  329. package/src/lib/shared/readLastConnection.ts +18 -0
  330. package/src/lib/shared/readPackageJson.ts +9 -0
  331. package/src/lib/shared/recordRemoteMeta.ts +5 -0
  332. package/src/lib/shared/refreshing.ts +31 -0
  333. package/src/lib/shared/remoteMetaStore.ts +16 -0
  334. package/src/lib/shared/requestScopeSlot.ts +15 -0
  335. package/src/lib/shared/resolveClientFlags.ts +20 -0
  336. package/src/lib/shared/responseErrorText.ts +9 -0
  337. package/src/lib/shared/rpcTimeoutSlot.ts +9 -0
  338. package/src/lib/shared/rpcUrlForFile.ts +19 -0
  339. package/src/lib/shared/runningAsStandaloneBinary.ts +13 -0
  340. package/src/lib/shared/selectorMatcher.ts +68 -0
  341. package/src/lib/shared/selectorPrefix.ts +39 -0
  342. package/src/lib/shared/serializeEnv.ts +18 -0
  343. package/src/lib/shared/setAppName.ts +5 -0
  344. package/src/lib/shared/setBaseResolver.ts +6 -0
  345. package/src/lib/shared/setCacheStoreResolver.ts +6 -0
  346. package/src/lib/shared/setGlobalCacheStoreResolver.ts +6 -0
  347. package/src/lib/shared/setPageResolver.ts +7 -0
  348. package/src/lib/shared/setRequestScopeResolver.ts +6 -0
  349. package/src/lib/shared/snippet.ts +25 -0
  350. package/src/lib/shared/socketNameForFile.ts +11 -0
  351. package/src/lib/shared/socketTapSlot.ts +12 -0
  352. package/src/lib/shared/sseErrorFrame.ts +29 -0
  353. package/src/lib/shared/streamResponse.ts +169 -0
  354. package/src/lib/shared/stripImport.ts +27 -0
  355. package/src/lib/shared/subscribableFromResponse.ts +51 -0
  356. package/src/lib/shared/tailProbeSlot.ts +16 -0
  357. package/src/lib/shared/toBunRoutePattern.ts +28 -0
  358. package/src/lib/shared/toScopeSet.ts +4 -0
  359. package/src/lib/shared/trace.ts +16 -0
  360. package/src/lib/shared/types/CacheEntry.ts +84 -0
  361. package/src/lib/shared/types/CacheInvalidation.ts +9 -0
  362. package/src/lib/shared/types/CacheOnContext.ts +25 -0
  363. package/src/lib/shared/types/CacheOptions.ts +39 -0
  364. package/src/lib/shared/types/CacheSelector.ts +17 -0
  365. package/src/lib/shared/types/CacheSnapshot.ts +16 -0
  366. package/src/lib/shared/types/CacheSnapshotEntry.ts +17 -0
  367. package/src/lib/shared/types/CacheStats.ts +13 -0
  368. package/src/lib/shared/types/CacheStore.ts +39 -0
  369. package/src/lib/shared/types/ChannelLog.ts +13 -0
  370. package/src/lib/shared/types/ClientFlags.ts +11 -0
  371. package/src/lib/shared/types/CompileTarget.ts +6 -0
  372. package/src/lib/shared/types/FrameworkLog.ts +13 -0
  373. package/src/lib/shared/types/HttpVerb.ts +1 -0
  374. package/src/lib/shared/types/LastConnection.ts +9 -0
  375. package/src/lib/shared/types/Log.ts +13 -0
  376. package/src/lib/shared/types/LogRecord.ts +42 -0
  377. package/src/lib/shared/types/LogVoice.ts +7 -0
  378. package/src/lib/shared/types/PageSnapshot.ts +14 -0
  379. package/src/lib/shared/types/PromptArgument.ts +12 -0
  380. package/src/lib/shared/types/RawRemoteFunction.ts +14 -0
  381. package/src/lib/shared/types/RemoteCallable.ts +12 -0
  382. package/src/lib/shared/types/RemoteFunction.ts +47 -0
  383. package/src/lib/shared/types/ReplayableMethod.ts +7 -0
  384. package/src/lib/shared/types/RequestScopeInfo.ts +16 -0
  385. package/src/lib/shared/types/RpcInvoker.ts +6 -0
  386. package/src/lib/shared/types/SocketChannel.ts +17 -0
  387. package/src/lib/shared/types/SocketSubCallbacks.ts +13 -0
  388. package/src/lib/shared/types/StandardSchemaV1.ts +56 -0
  389. package/src/lib/shared/types/StreamedResolution.ts +10 -0
  390. package/src/lib/shared/types/Subscribable.ts +26 -0
  391. package/src/lib/shared/types/TailHooks.ts +12 -0
  392. package/src/lib/shared/types/TailOptions.ts +10 -0
  393. package/src/lib/shared/types/TraceContext.ts +17 -0
  394. package/src/lib/shared/url.ts +118 -0
  395. package/src/lib/shared/withBase.ts +11 -0
  396. package/src/lib/shared/withBaseUrl.ts +17 -0
  397. package/src/lib/shared/withJsonSchema.ts +21 -0
  398. package/src/lib/shared/writeDts.ts +12 -0
  399. package/src/lib/shared/writeHealthDts.ts +36 -0
  400. package/src/lib/shared/writeLastConnection.ts +13 -0
  401. package/src/lib/shared/writePublicAssetsDts.ts +31 -0
  402. package/src/lib/shared/writeRoutesDts.ts +73 -0
  403. package/src/lib/shared/writeRpcDts.ts +49 -0
  404. package/src/lib/shared/writeTestRpcDts.ts +45 -0
  405. package/src/lib/shared/writeTestSocketsDts.ts +34 -0
  406. package/src/lib/test/assertAgentFrameConformance.ts +73 -0
  407. package/src/lib/test/createScriptedSurface.ts +45 -0
  408. package/src/lib/test/createTestApp.ts +203 -0
  409. package/src/lib/test/createTestSocketChannel.ts +142 -0
  410. package/src/lib/ui/README.md +86 -0
  411. package/src/lib/ui/compile/SSR_ESCAPE.ts +25 -0
  412. package/src/lib/ui/compile/UI_RUNTIME_IMPORTS.ts +36 -0
  413. package/src/lib/ui/compile/VOID_TAGS.ts +21 -0
  414. package/src/lib/ui/compile/abideUiPlugin.ts +65 -0
  415. package/src/lib/ui/compile/analyzeComponent.ts +117 -0
  416. package/src/lib/ui/compile/assetModulesFile.ts +32 -0
  417. package/src/lib/ui/compile/branchElements.ts +50 -0
  418. package/src/lib/ui/compile/collectAbideDiagnostics.ts +59 -0
  419. package/src/lib/ui/compile/compileComponent.ts +20 -0
  420. package/src/lib/ui/compile/compileModule.ts +116 -0
  421. package/src/lib/ui/compile/compileSSR.ts +36 -0
  422. package/src/lib/ui/compile/compileShadow.ts +352 -0
  423. package/src/lib/ui/compile/createShadowLanguageService.ts +197 -0
  424. package/src/lib/ui/compile/createShadowProgram.ts +96 -0
  425. package/src/lib/ui/compile/decodeHtmlEntities.ts +49 -0
  426. package/src/lib/ui/compile/desugarSignals.ts +133 -0
  427. package/src/lib/ui/compile/escapeHtml.ts +15 -0
  428. package/src/lib/ui/compile/generateBuild.ts +638 -0
  429. package/src/lib/ui/compile/generateSSR.ts +380 -0
  430. package/src/lib/ui/compile/groupBindParts.ts +28 -0
  431. package/src/lib/ui/compile/hoistCells.ts +120 -0
  432. package/src/lib/ui/compile/loadShadowTsConfig.ts +31 -0
  433. package/src/lib/ui/compile/lowerDocAccess.ts +202 -0
  434. package/src/lib/ui/compile/nearestProjectRoot.ts +16 -0
  435. package/src/lib/ui/compile/parseTemplate.ts +396 -0
  436. package/src/lib/ui/compile/partitionSlots.ts +36 -0
  437. package/src/lib/ui/compile/prepareNestedScript.ts +42 -0
  438. package/src/lib/ui/compile/remapShadowDiagnostic.ts +30 -0
  439. package/src/lib/ui/compile/renameSignalRefs.ts +85 -0
  440. package/src/lib/ui/compile/resolveAbideImports.ts +29 -0
  441. package/src/lib/ui/compile/scopeCss.ts +115 -0
  442. package/src/lib/ui/compile/shadowNaming.ts +11 -0
  443. package/src/lib/ui/compile/sourceToShadowOffset.ts +24 -0
  444. package/src/lib/ui/compile/staticAttrValue.ts +13 -0
  445. package/src/lib/ui/compile/stripEffects.ts +32 -0
  446. package/src/lib/ui/compile/types/AbideDiagnostic.ts +14 -0
  447. package/src/lib/ui/compile/types/AnalyzedComponent.ts +25 -0
  448. package/src/lib/ui/compile/types/CompiledShadow.ts +15 -0
  449. package/src/lib/ui/compile/types/TemplateAttr.ts +16 -0
  450. package/src/lib/ui/compile/types/TemplateNode.ts +78 -0
  451. package/src/lib/ui/compile/types/TextPart.ts +8 -0
  452. package/src/lib/ui/derived.ts +28 -0
  453. package/src/lib/ui/doc.ts +15 -0
  454. package/src/lib/ui/dom/appendSnippet.ts +34 -0
  455. package/src/lib/ui/dom/appendStatic.ts +27 -0
  456. package/src/lib/ui/dom/appendText.ts +114 -0
  457. package/src/lib/ui/dom/applyResolved.ts +72 -0
  458. package/src/lib/ui/dom/attach.ts +20 -0
  459. package/src/lib/ui/dom/attr.ts +19 -0
  460. package/src/lib/ui/dom/awaitBlock.ts +224 -0
  461. package/src/lib/ui/dom/cloneStatic.ts +52 -0
  462. package/src/lib/ui/dom/each.ts +115 -0
  463. package/src/lib/ui/dom/eachAsync.ts +153 -0
  464. package/src/lib/ui/dom/hydrate.ts +35 -0
  465. package/src/lib/ui/dom/mount.ts +29 -0
  466. package/src/lib/ui/dom/mountChild.ts +33 -0
  467. package/src/lib/ui/dom/on.ts +15 -0
  468. package/src/lib/ui/dom/openChild.ts +22 -0
  469. package/src/lib/ui/dom/openRoot.ts +20 -0
  470. package/src/lib/ui/dom/switchBlock.ts +75 -0
  471. package/src/lib/ui/dom/text.ts +20 -0
  472. package/src/lib/ui/dom/tryBlock.ts +112 -0
  473. package/src/lib/ui/dom/types/EachRow.ts +3 -0
  474. package/src/lib/ui/dom/types/SwitchCase.ts +6 -0
  475. package/src/lib/ui/dom/when.ts +73 -0
  476. package/src/lib/ui/effect.ts +16 -0
  477. package/src/lib/ui/installHotBridge.ts +73 -0
  478. package/src/lib/ui/matchRoute.ts +89 -0
  479. package/src/lib/ui/navigate.ts +17 -0
  480. package/src/lib/ui/probeNavigation.ts +33 -0
  481. package/src/lib/ui/remoteProxy.ts +97 -0
  482. package/src/lib/ui/renderChain.ts +50 -0
  483. package/src/lib/ui/renderToStream.ts +104 -0
  484. package/src/lib/ui/router.ts +286 -0
  485. package/src/lib/ui/runtime/OUTLET_TAG.ts +8 -0
  486. package/src/lib/ui/runtime/OWNER.ts +8 -0
  487. package/src/lib/ui/runtime/REACTIVE_CONTEXT.ts +14 -0
  488. package/src/lib/ui/runtime/RENDER.ts +23 -0
  489. package/src/lib/ui/runtime/RESUME.ts +16 -0
  490. package/src/lib/ui/runtime/applyPatchToTree.ts +41 -0
  491. package/src/lib/ui/runtime/claimChild.ts +10 -0
  492. package/src/lib/ui/runtime/clientPage.ts +16 -0
  493. package/src/lib/ui/runtime/createComputedNode.ts +16 -0
  494. package/src/lib/ui/runtime/createDoc.ts +177 -0
  495. package/src/lib/ui/runtime/createEffectNode.ts +58 -0
  496. package/src/lib/ui/runtime/createSignalNode.ts +16 -0
  497. package/src/lib/ui/runtime/detachLink.ts +21 -0
  498. package/src/lib/ui/runtime/endTracking.ts +24 -0
  499. package/src/lib/ui/runtime/enterRenderPass.ts +12 -0
  500. package/src/lib/ui/runtime/exitRenderPass.ts +7 -0
  501. package/src/lib/ui/runtime/firstOutlet.ts +22 -0
  502. package/src/lib/ui/runtime/flushEffects.ts +17 -0
  503. package/src/lib/ui/runtime/hotInstances.ts +10 -0
  504. package/src/lib/ui/runtime/hotReloadEnabled.ts +8 -0
  505. package/src/lib/ui/runtime/hotReplace.ts +25 -0
  506. package/src/lib/ui/runtime/nextBlockId.ts +11 -0
  507. package/src/lib/ui/runtime/pathExists.ts +23 -0
  508. package/src/lib/ui/runtime/readNode.ts +17 -0
  509. package/src/lib/ui/runtime/registerHotInstance.ts +23 -0
  510. package/src/lib/ui/runtime/runNode.ts +28 -0
  511. package/src/lib/ui/runtime/runtimePath.ts +9 -0
  512. package/src/lib/ui/runtime/scope.ts +24 -0
  513. package/src/lib/ui/runtime/toTeardown.ts +26 -0
  514. package/src/lib/ui/runtime/track.ts +58 -0
  515. package/src/lib/ui/runtime/trigger.ts +44 -0
  516. package/src/lib/ui/runtime/types/Cell.ts +5 -0
  517. package/src/lib/ui/runtime/types/Derived.ts +3 -0
  518. package/src/lib/ui/runtime/types/Doc.ts +19 -0
  519. package/src/lib/ui/runtime/types/EffectResult.ts +10 -0
  520. package/src/lib/ui/runtime/types/HotInstance.ts +14 -0
  521. package/src/lib/ui/runtime/types/NavVerdict.ts +9 -0
  522. package/src/lib/ui/runtime/types/Patch.ts +11 -0
  523. package/src/lib/ui/runtime/types/ReactiveLink.ts +21 -0
  524. package/src/lib/ui/runtime/types/ReactiveNode.ts +25 -0
  525. package/src/lib/ui/runtime/types/Route.ts +8 -0
  526. package/src/lib/ui/runtime/types/RouteLoader.ts +7 -0
  527. package/src/lib/ui/runtime/types/SsrRender.ts +22 -0
  528. package/src/lib/ui/runtime/types/State.ts +3 -0
  529. package/src/lib/ui/runtime/types/Teardown.ts +5 -0
  530. package/src/lib/ui/runtime/types/UiComponent.ts +16 -0
  531. package/src/lib/ui/runtime/types/UiProps.ts +15 -0
  532. package/src/lib/ui/runtime/unlinkDeps.ts +20 -0
  533. package/src/lib/ui/runtime/untrack.ts +20 -0
  534. package/src/lib/ui/runtime/valueAtPath.ts +18 -0
  535. package/src/lib/ui/runtime/writeNode.ts +16 -0
  536. package/src/lib/ui/socketChannel.ts +227 -0
  537. package/src/lib/ui/socketProxy.ts +25 -0
  538. package/src/lib/ui/startClient.ts +58 -0
  539. package/src/lib/ui/state.ts +25 -0
  540. package/src/lib/ui/tail.ts +324 -0
  541. package/src/lib/ui/types/Layouts.ts +9 -0
  542. package/src/lib/ui/types/Pages.ts +8 -0
  543. package/src/preload.ts +19 -0
  544. package/src/scaffold.ts +153 -0
  545. package/src/serverBuildPlugins.ts +19 -0
  546. package/src/serverEntry.ts +95 -0
  547. package/template/bunfig.toml +4 -0
  548. package/template/package.json +18 -0
  549. package/template/src/app.ts +28 -0
  550. package/template/src/bundle/icon.png +0 -0
  551. package/template/src/cli/banner.txt +3 -0
  552. package/template/src/cli/footer.txt +1 -0
  553. package/template/src/server/config.ts +17 -0
  554. package/template/src/server/rpc/getHello.ts +36 -0
  555. package/template/src/ui/Layout.abide +19 -0
  556. package/template/src/ui/app.css +21 -0
  557. package/template/src/ui/app.html +24 -0
  558. package/template/src/ui/pages/about/page.abide +9 -0
  559. package/template/src/ui/pages/page.abide +22 -0
  560. package/template/test/app.test.ts +30 -0
  561. package/template/tsconfig.json +18 -0
  562. package/tsconfig.app.json +17 -0
@@ -0,0 +1,380 @@
1
+ import { OUTLET_TAG } from '../runtime/OUTLET_TAG.ts'
2
+ import { branchElements } from './branchElements.ts'
3
+ import { escapeHtml } from './escapeHtml.ts'
4
+ import { groupBindParts } from './groupBindParts.ts'
5
+ import { lowerDocAccess } from './lowerDocAccess.ts'
6
+ import { partitionSlots } from './partitionSlots.ts'
7
+ import { nestedBindingNames } from './prepareNestedScript.ts'
8
+ import { renameSignalRefs } from './renameSignalRefs.ts'
9
+ import { staticAttrValue } from './staticAttrValue.ts'
10
+ import { stripEffects } from './stripEffects.ts'
11
+ import type { TemplateNode } from './types/TemplateNode.ts'
12
+ import { VOID_TAGS } from './VOID_TAGS.ts'
13
+
14
+ /*
15
+ Server code generator: turns the parsed template into statements that push HTML
16
+ fragments onto an output array, reading the document synchronously (no DOM, no
17
+ listeners). Same expression lowering as the client back-end, so server and client
18
+ render the same markup. Dynamic values go through `$esc`; `if` is a plain `if`,
19
+ `each` a `for…of`.
20
+
21
+ An `await` block emits boundary comments (`<!--abide:await:N-->…<!--/abide:await:N-->`)
22
+ and registers the promise plus its resolved/error string-renderers on `$awaits`. A
23
+ streaming block (no `then` on the tag) puts its pending branch between the markers;
24
+ `renderToStream` flushes each resolved fragment out of order — the await-block-streams
25
+ half of the cache rule. A blocking block (`then` on the tag) emits an empty boundary
26
+ and flags the entry, so `renderToStream` settles it before the first flush.
27
+ */
28
+ export function generateSSR(
29
+ nodes: TemplateNode[],
30
+ stateNames: ReadonlySet<string>,
31
+ derivedNames: ReadonlySet<string>,
32
+ isLayout = false,
33
+ ): string {
34
+ /* Compile-time counter for unique temp var names (runtime block ids, child render
35
+ results) — block ids themselves are allocated at runtime via nextBlockId(). */
36
+ let varCounter = 0
37
+ const nextVar = (prefix: string): string => `${prefix}${varCounter++}`
38
+
39
+ /* Branch-scoped nested-script bindings, deref'd to `.value` (see generateBuild). */
40
+ const localDerived = new Set<string>()
41
+ const derefScope = (): ReadonlySet<string> =>
42
+ localDerived.size === 0 ? derivedNames : new Set([...derivedNames, ...localDerived])
43
+
44
+ function lowerExpression(code: string): string {
45
+ return lowerDocAccess(renameSignalRefs(code, stateNames, derefScope()), 'model')
46
+ .trim()
47
+ .replace(/;$/, '')
48
+ }
49
+
50
+ /* Lowers a scoped-script body for SSR: rename refs, lower doc access, then strip
51
+ effects (client-only lifecycle that emits no HTML). */
52
+ function lowerScript(code: string): string {
53
+ return stripEffects(
54
+ lowerDocAccess(renameSignalRefs(code, stateNames, derefScope()), 'model').trim(),
55
+ )
56
+ }
57
+
58
+ function push(target: string, literal: string): string {
59
+ return `${target}.push(${JSON.stringify(literal)});\n`
60
+ }
61
+
62
+ function generateInto(children: TemplateNode[], target: string): string {
63
+ return children.map((child) => generate(child, target)).join('')
64
+ }
65
+
66
+ /* A control-flow branch's body: run its nested `<script>`s (lowered, in scope)
67
+ first, then push the element markup — so SSR re-seeds the same local signals
68
+ the client build does, keeping hydration aligned. */
69
+ function branchInto(children: TemplateNode[], context: string, target: string): string {
70
+ const added: string[] = []
71
+ for (const child of children) {
72
+ if (child.kind === 'script') {
73
+ for (const name of nestedBindingNames(child.code)) {
74
+ if (!localDerived.has(name)) {
75
+ localDerived.add(name)
76
+ added.push(name)
77
+ }
78
+ }
79
+ }
80
+ }
81
+ const scriptCode = children
82
+ .filter(
83
+ (child): child is Extract<TemplateNode, { kind: 'script' }> =>
84
+ child.kind === 'script',
85
+ )
86
+ .map((child) => `${lowerScript(child.code)}\n`)
87
+ .join('')
88
+ const markup = generateInto(branchElements(children, context, true), target)
89
+ for (const name of added) {
90
+ localDerived.delete(name)
91
+ }
92
+ return scriptCode + markup
93
+ }
94
+
95
+ function generate(node: TemplateNode, target: string): string {
96
+ if (node.kind === 'text') {
97
+ return node.parts
98
+ .map((part) => {
99
+ if (part.kind === 'static') {
100
+ return part.value.trim() === '' ? '' : push(target, escapeHtml(part.value))
101
+ }
102
+ return `${target}.push($text(${lowerExpression(part.code)}));\n`
103
+ })
104
+ .join('')
105
+ }
106
+ if (node.kind === 'if') {
107
+ const elseBranch = node.children.find((child) => child.kind === 'case')
108
+ const thenChildren = node.children.filter((child) => child.kind !== 'case')
109
+ let code = `if (${lowerExpression(node.condition)}) {\n${branchInto(thenChildren, '<template if>', target)}}`
110
+ if (elseBranch !== undefined && elseBranch.kind === 'case') {
111
+ code += ` else {\n${branchInto(elseBranch.children, '<template else>', target)}}`
112
+ }
113
+ return `${code}\n`
114
+ }
115
+ if (node.kind === 'switch') {
116
+ const cases = node.children.filter(
117
+ (child): child is Extract<TemplateNode, { kind: 'case' }> => child.kind === 'case',
118
+ )
119
+ let code = `{ const $s = (${lowerExpression(node.subject)});\n`
120
+ let started = false
121
+ for (const branch of cases) {
122
+ if (branch.match !== undefined) {
123
+ code += `${started ? 'else ' : ''}if ($s === (${lowerExpression(branch.match)})) {\n${branchInto(branch.children, '<template case>', target)}}\n`
124
+ started = true
125
+ }
126
+ }
127
+ const fallback = cases.find((branch) => branch.match === undefined)
128
+ if (fallback !== undefined) {
129
+ code += `${started ? 'else ' : ''}{\n${branchInto(fallback.children, '<template case>', target)}}\n`
130
+ }
131
+ return `${code}}\n`
132
+ }
133
+ if (node.kind === 'case') {
134
+ return ''
135
+ }
136
+ if (node.kind === 'snippet') {
137
+ /* A hoisted function returning the snippet's `$snip`-branded HTML string;
138
+ `{name(args)}` pushes it via `$text`, which wraps it in markers. */
139
+ const body = generateInto(node.children, '$o')
140
+ return `function ${node.name}(${node.params ?? ''}) {\nconst $o = [];\n${body}return $snip($o.join(''));\n}\n`
141
+ }
142
+ if (node.kind === 'script') {
143
+ /* A scoped reactive block: re-seed its local signals (lowered, in scope)
144
+ so SSR renders the same values the client build will. */
145
+ return `${lowerScript(node.code)}\n`
146
+ }
147
+ /* A `<style>` emits no markup — its scope attribute is already on the elements
148
+ it covers (above) and its CSS is bundled, not inlined. */
149
+ if (node.kind === 'style') {
150
+ return ''
151
+ }
152
+ if (node.kind === 'each') {
153
+ /* Async each (`await`) is drained on the client — render no rows on the
154
+ server (an infinite stream would hang SSR); the client inserts its anchor
155
+ before the next sibling during hydration, like an empty sync each. */
156
+ if (node.async) {
157
+ return ''
158
+ }
159
+ return `for (const ${node.as} of (${lowerExpression(node.items)})) {\n${branchInto(node.children, '<template each>', target)}}\n`
160
+ }
161
+ if (node.kind === 'await') {
162
+ return generateAwait(node, target)
163
+ }
164
+ if (node.kind === 'try') {
165
+ return generateTry(node, target)
166
+ }
167
+ if (node.kind === 'branch') {
168
+ return ''
169
+ }
170
+ if (node.kind === 'component') {
171
+ /* Server-render the child via its `render` and inline the HTML inside
172
+ the same wrapper the client mounts into, so SSR and client agree.
173
+ Props pass as thunks; slot content passes as a string-returning
174
+ `$children` the child invokes from its <slot>. */
175
+ const tag = node.name.toLowerCase()
176
+ const parts = node.props.map(
177
+ (prop) => `${JSON.stringify(prop.name)}: () => (${lowerExpression(prop.code)})`,
178
+ )
179
+ const groups = partitionSlots(node.children)
180
+ const slotCode = generateInto(groups.default, '$slot')
181
+ if (slotCode.trim() !== '') {
182
+ parts.push(
183
+ `"$children": () => { const $slot = []; ${slotCode}return $slot.join(''); }`,
184
+ )
185
+ }
186
+ if (groups.named.length > 0) {
187
+ const entries = groups.named
188
+ .map((group) => {
189
+ const code = generateInto(group.nodes, '$slot')
190
+ return `${JSON.stringify(group.name)}: () => { const $slot = []; ${code}return $slot.join(''); }`
191
+ })
192
+ .join(', ')
193
+ parts.push(`"$slots": { ${entries} }`)
194
+ }
195
+ /* Render the child and MERGE its await blocks into this page's `$awaits`
196
+ so they join the page's SSR stream — their markers carry render-pass
197
+ block ids (nextBlockId), unique across page + children, so the streamed
198
+ fragments resolve into the right boundaries. ($awaits is captured from
199
+ the enclosing render body, including from branch closures.) */
200
+ const result = nextVar('$child')
201
+ return (
202
+ push(target, `<${tag}>`) +
203
+ `const ${result} = ${node.name}.render({ ${parts.join(', ')} });\n` +
204
+ `${target}.push(${result}.html);\n` +
205
+ `for (const $a of ${result}.awaits) { $awaits.push($a); }\n` +
206
+ push(target, `</${tag}>`)
207
+ )
208
+ }
209
+ if (node.kind === 'element' && node.tag === 'slot') {
210
+ /* A layout's unnamed `<slot/>` is the router's page outlet: emit an empty
211
+ placeholder the chain composer folds the child layer's html into. */
212
+ if (isLayout && staticAttrValue(node, 'name') === undefined) {
213
+ return push(target, `<${OUTLET_TAG}></${OUTLET_TAG}>`)
214
+ }
215
+ return generateSlot(node, target)
216
+ }
217
+ let code = push(target, `<${node.tag}`)
218
+ /* Every `<style>` active at this element (own siblings + ancestors) — same set
219
+ the client stamps, so server and client markup carry identical attributes. */
220
+ for (const scope of node.scopes ?? []) {
221
+ code += push(target, ` ${scope}=""`)
222
+ }
223
+ for (const attr of node.attrs) {
224
+ if (attr.kind === 'static') {
225
+ /* Escape the literal value so a `"`/`&`/`<` in it can't break out of
226
+ the attribute or inject markup (the client uses setAttribute, which
227
+ needs no escaping — escaping here keeps SSR and client in sync). */
228
+ code += push(target, ` ${attr.name}="${escapeHtml(attr.value)}"`)
229
+ } else if (attr.kind === 'expression') {
230
+ /* present/absent semantics matching the client `attr` binding:
231
+ false/null/undefined drops it, true emits the bare attribute. */
232
+ code += `${target}.push($attr(${JSON.stringify(attr.name)}, ${lowerExpression(attr.code)}));\n`
233
+ } else if (attr.kind === 'bind' && attr.property === 'group') {
234
+ /* Render the checked state as a boolean attribute: present when the
235
+ path holds (radio) or contains (checkbox) this control's value. */
236
+ const { valueCode, isRadio } = groupBindParts(node)
237
+ const present = isRadio
238
+ ? `(${lowerExpression(attr.code)}) === (${lowerExpression(valueCode)})`
239
+ : `(${lowerExpression(attr.code)}).includes(${lowerExpression(valueCode)})`
240
+ code += `${target}.push((${present}) ? ' checked' : '');\n`
241
+ } else if (attr.kind === 'bind' && attr.property === 'checked') {
242
+ /* A boolean property — its mere presence means checked, so emit the
243
+ attribute only when truthy (a string `checked="false"` still checks). */
244
+ code += `${target}.push((${lowerExpression(attr.code)}) ? ' checked' : '');\n`
245
+ } else if (attr.kind === 'bind') {
246
+ code += `${target}.push(${JSON.stringify(` ${attr.property}="`)} + $esc(${lowerExpression(attr.code)}) + '"');\n`
247
+ }
248
+ }
249
+ code += push(target, '>')
250
+ if (!VOID_TAGS.has(node.tag)) {
251
+ /* A `<script>` child scopes its bindings to this element's subtree. */
252
+ const added: string[] = []
253
+ for (const child of node.children) {
254
+ if (child.kind === 'script') {
255
+ for (const name of nestedBindingNames(child.code)) {
256
+ if (!localDerived.has(name)) {
257
+ localDerived.add(name)
258
+ added.push(name)
259
+ }
260
+ }
261
+ }
262
+ }
263
+ code += generateInto(node.children, target)
264
+ for (const name of added) {
265
+ localDerived.delete(name)
266
+ }
267
+ code += push(target, `</${node.tag}>`)
268
+ }
269
+ return code
270
+ }
271
+
272
+ /* A `<slot>` outlet: emit the parent-provided content for this slot (default
273
+ via `$children`, named via `$slots[name]`), falling back to the slot's own
274
+ children when none was supplied. */
275
+ function generateSlot(
276
+ node: Extract<TemplateNode, { kind: 'element' }>,
277
+ target: string,
278
+ ): string {
279
+ const name = staticAttrValue(node, 'name')
280
+ const guard =
281
+ name === undefined
282
+ ? '$props && $props.$children'
283
+ : `$props && $props.$slots && $props.$slots[${JSON.stringify(name)}]`
284
+ const provided =
285
+ name === undefined ? '$props.$children' : `$props.$slots[${JSON.stringify(name)}]`
286
+ const fallback = generateInto(node.children, target)
287
+ if (fallback.trim() === '') {
288
+ return `if (${guard}) { ${target}.push(${provided}()); }\n`
289
+ }
290
+ return `if (${guard}) { ${target}.push(${provided}()); } else {\n${fallback}}\n`
291
+ }
292
+
293
+ /* Boundary markers + a `$awaits` registration carrying the promise and
294
+ string-renderers for the resolved/error branches. Streaming emits the pending
295
+ branch between the markers (flushed now, value streamed later); blocking emits
296
+ an empty boundary — its resolved branch is the children bound to `node.as` — and
297
+ flags the entry so `renderToStream` settles it before the first flush. */
298
+ function generateAwait(node: Extract<TemplateNode, { kind: 'await' }>, target: string): string {
299
+ const branchOf = (which: 'then' | 'catch' | 'finally') =>
300
+ node.children.find(
301
+ (child): child is Extract<TemplateNode, { kind: 'branch' }> =>
302
+ child.kind === 'branch' && child.branch === which,
303
+ )
304
+ const catchBranch = branchOf('catch')
305
+ const finallyChildren = branchOf('finally')?.children ?? []
306
+ /* Resolved branch + its bound value: the children directly when blocking, the
307
+ `then` child when streaming. Pending (streaming only) is the non-branch
308
+ children. */
309
+ const thenBranch = branchOf('then')
310
+ const resolvedChildren = node.blocking
311
+ ? node.children.filter((child) => child.kind !== 'branch')
312
+ : (thenBranch?.children ?? [])
313
+ const resolvedAs = node.blocking ? node.as : thenBranch?.as
314
+ const pending = node.blocking
315
+ ? []
316
+ : node.children.filter((child) => child.kind !== 'branch')
317
+ /* Runtime block id (shared with the client + child components in this pass). */
318
+ const id = nextVar('$aid')
319
+ let code = `const ${id} = nextBlockId();\n`
320
+ code += `${target}.push("<!--abide:await:" + ${id} + "-->");\n`
321
+ code += branchInto(pending, '<template await> pending', target)
322
+ code += `${target}.push("<!--/abide:await:" + ${id} + "-->");\n`
323
+ /* The settled closures append `finally` after the outcome markup, matching the
324
+ client's concatenated node range so hydration aligns. */
325
+ const settled = (binding: string, children: TemplateNode[], context: string) =>
326
+ `(${binding}) => { const $o = []; ${branchInto(children, context, '$o')}${branchInto(finallyChildren, '<template finally>', '$o')}return $o.join(''); }`
327
+ /* Neither catch nor finally → omit `catch` so a rejection surfaces to the
328
+ stream/error path (renderToStream re-throws) instead of rendering an empty
329
+ branch. A finally-only block keeps a catch closure that renders just finally. */
330
+ const catchProp =
331
+ catchBranch === undefined && finallyChildren.length === 0
332
+ ? ''
333
+ : `catch: ${settled(catchBranch?.as ?? '_error', catchBranch?.children ?? [], '<template catch>')} `
334
+ code +=
335
+ `$awaits.push({ id: ${id}, ` +
336
+ (node.blocking ? 'blocking: true, ' : '') +
337
+ `promise: () => (${lowerExpression(node.promise)}), ` +
338
+ `then: ${settled(resolvedAs ?? '_value', resolvedChildren, node.blocking ? '<template await then>' : '<template then>')}, ` +
339
+ `${catchProp}});\n`
340
+ return code
341
+ }
342
+
343
+ /* A sync error boundary: push the guarded markup (++ finally) inside a real
344
+ try/catch; on a throw, truncate the output back to the boundary start and push
345
+ the catch markup (++ finally) instead — so even mid-stream a render throw
346
+ becomes catch markup, not a broken response. No catch re-throws (propagates to
347
+ an enclosing boundary / the 500 / the stream). Boundary comments let hydration
348
+ discard the server content if the client adoption fails. */
349
+ function generateTry(node: Extract<TemplateNode, { kind: 'try' }>, target: string): string {
350
+ const branchOf = (which: 'catch' | 'finally') =>
351
+ node.children.find(
352
+ (child): child is Extract<TemplateNode, { kind: 'branch' }> =>
353
+ child.kind === 'branch' && child.branch === which,
354
+ )
355
+ const catchBranch = branchOf('catch')
356
+ const finallyChildren = branchOf('finally')?.children ?? []
357
+ const guarded = node.children.filter((child) => child.kind !== 'branch')
358
+ const errName = catchBranch?.as ?? '_error'
359
+ const id = nextVar('$tid')
360
+ const mark = nextVar('$trim')
361
+ let code = `const ${id} = nextBlockId();\n`
362
+ code += `${target}.push("<!--abide:try:" + ${id} + "-->");\n`
363
+ code += `const ${mark} = ${target}.length;\n`
364
+ code += `try {\n`
365
+ code += branchInto(guarded, '<template try>', target)
366
+ code += branchInto(finallyChildren, '<template finally>', target)
367
+ code += `} catch (${errName}) {\n${target}.length = ${mark};\n`
368
+ if (catchBranch !== undefined) {
369
+ code += branchInto(catchBranch.children, '<template catch>', target)
370
+ code += branchInto(finallyChildren, '<template finally>', target)
371
+ } else {
372
+ code += `throw ${errName};\n`
373
+ }
374
+ code += `}\n`
375
+ code += `${target}.push("<!--/abide:try:" + ${id} + "-->");\n`
376
+ return code
377
+ }
378
+
379
+ return generateInto(nodes, '$out')
380
+ }
@@ -0,0 +1,28 @@
1
+ import { staticAttrValue } from './staticAttrValue.ts'
2
+ import type { TemplateNode } from './types/TemplateNode.ts'
3
+
4
+ /*
5
+ The pieces a `bind:group` needs from its own element: `valueCode` is the JS source
6
+ of the control's `value` (a string literal for static `value="x"`, the expression
7
+ for `value={expr}`); `isRadio` selects single-value (radio) vs array-membership
8
+ (checkbox) semantics. Throws on the two cases the binding can't mean anything for —
9
+ a missing `value`, or a `type` not statically `radio`/`checkbox` (the semantics are
10
+ chosen at compile time, so the type can't be dynamic).
11
+ */
12
+ export function groupBindParts(node: Extract<TemplateNode, { kind: 'element' }>): {
13
+ valueCode: string
14
+ isRadio: boolean
15
+ } {
16
+ const value = node.attrs.find(
17
+ (attr) => (attr.kind === 'static' || attr.kind === 'expression') && attr.name === 'value',
18
+ )
19
+ if (value === undefined || (value.kind !== 'static' && value.kind !== 'expression')) {
20
+ throw new Error('bind:group requires a `value` attribute on the same element')
21
+ }
22
+ const valueCode = value.kind === 'static' ? JSON.stringify(value.value) : value.code
23
+ const type = staticAttrValue(node, 'type')
24
+ if (type !== 'radio' && type !== 'checkbox') {
25
+ throw new Error('bind:group requires a static type="radio" or type="checkbox"')
26
+ }
27
+ return { valueCode, isRadio: type === 'radio' }
28
+ }
@@ -0,0 +1,120 @@
1
+ import ts from 'typescript'
2
+
3
+ /*
4
+ The perf pass that follows `lowerDocAccess`. Within a render scope, a static path
5
+ is read and written many times; resolving it to a node + parent + key on every
6
+ access (what `read`/`replace` do) is the path-string floor the bench measured.
7
+ This hoists each distinct static path to a `cell` bound once at the top of the
8
+ scope and rewrites accesses to the string-free `get`/`set` — the form that runs
9
+ ~20x faster than re-resolving:
10
+
11
+ model.read("count") → _cell0.get()
12
+ model.replace("count", v) → _cell0.set(v)
13
+ // with, prepended once: const _cell0 = model.cell("count")
14
+
15
+ The input is a render-scope body where `docName` is already in scope (the cell
16
+ decls are prepended to it, so the doc must exist first). Dynamic-path accesses
17
+ (`read(`a/${i}`)`) and structural ops (`add`/`remove`) are left untouched — a
18
+ cell binds one fixed scalar leaf.
19
+ */
20
+ export function hoistCells(code: string, docName: string): string {
21
+ const source = ts.createSourceFile('component.ts', code, ts.ScriptTarget.Latest, true)
22
+ const cellIdForPath = new Map<string, string>()
23
+
24
+ /* Pass 1: assign a cell id to each distinct static read/replace path. */
25
+ const collect = (node: ts.Node): void => {
26
+ const path = staticDocPath(node, docName, 'read') ?? staticDocPath(node, docName, 'replace')
27
+ if (path !== undefined && !cellIdForPath.has(path)) {
28
+ cellIdForPath.set(path, `_cell${cellIdForPath.size}`)
29
+ }
30
+ ts.forEachChild(node, collect)
31
+ }
32
+ collect(source)
33
+ if (cellIdForPath.size === 0) {
34
+ return code
35
+ }
36
+
37
+ const result = ts.transform(source, [hoistTransformer(docName, cellIdForPath)])
38
+ const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
39
+ const output = printer.printFile(result.transformed[0] as ts.SourceFile)
40
+ result.dispose()
41
+ return output
42
+ }
43
+
44
+ /* Returns the literal path of a `docName.method("literal", …)` call, else undefined. */
45
+ function staticDocPath(node: ts.Node, docName: string, method: string): string | undefined {
46
+ if (
47
+ ts.isCallExpression(node) &&
48
+ ts.isPropertyAccessExpression(node.expression) &&
49
+ ts.isIdentifier(node.expression.expression) &&
50
+ node.expression.expression.text === docName &&
51
+ node.expression.name.text === method
52
+ ) {
53
+ const first = node.arguments[0]
54
+ if (first !== undefined && ts.isStringLiteral(first)) {
55
+ return first.text
56
+ }
57
+ }
58
+ return undefined
59
+ }
60
+
61
+ function hoistTransformer(
62
+ docName: string,
63
+ cellIdForPath: Map<string, string>,
64
+ ): ts.TransformerFactory<ts.SourceFile> {
65
+ return (context) => (root) => {
66
+ function visit(node: ts.Node): ts.Node {
67
+ const readPath = staticDocPath(node, docName, 'read')
68
+ if (readPath !== undefined) {
69
+ return cellCall(cellIdForPath.get(readPath) as string, 'get', [])
70
+ }
71
+ const replacePath = staticDocPath(node, docName, 'replace')
72
+ if (replacePath !== undefined) {
73
+ const value = (node as ts.CallExpression).arguments[1]
74
+ return cellCall(cellIdForPath.get(replacePath) as string, 'set', [
75
+ ts.visitNode(value, visit) as ts.Expression,
76
+ ])
77
+ }
78
+ return ts.visitEachChild(node, visit, context)
79
+ }
80
+ const visited = ts.visitNode(root, visit) as ts.SourceFile
81
+ const declarations = [...cellIdForPath].map(([path, id]) =>
82
+ cellDeclaration(docName, id, path),
83
+ )
84
+ return ts.factory.updateSourceFile(visited, [...declarations, ...visited.statements])
85
+ }
86
+ }
87
+
88
+ /* Builds `cellId.method(...args)`. */
89
+ function cellCall(cellId: string, method: string, args: ts.Expression[]): ts.CallExpression {
90
+ return ts.factory.createCallExpression(
91
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(cellId), method),
92
+ undefined,
93
+ args,
94
+ )
95
+ }
96
+
97
+ /* Builds `const cellId = docName.cell("path")`. */
98
+ function cellDeclaration(docName: string, cellId: string, path: string): ts.VariableStatement {
99
+ return ts.factory.createVariableStatement(
100
+ undefined,
101
+ ts.factory.createVariableDeclarationList(
102
+ [
103
+ ts.factory.createVariableDeclaration(
104
+ cellId,
105
+ undefined,
106
+ undefined,
107
+ ts.factory.createCallExpression(
108
+ ts.factory.createPropertyAccessExpression(
109
+ ts.factory.createIdentifier(docName),
110
+ 'cell',
111
+ ),
112
+ undefined,
113
+ [ts.factory.createStringLiteral(path)],
114
+ ),
115
+ ),
116
+ ],
117
+ ts.NodeFlags.Const,
118
+ ),
119
+ )
120
+ }
@@ -0,0 +1,31 @@
1
+ import ts from 'typescript'
2
+
3
+ /*
4
+ Loads the project's tsconfig (for lib/paths/baseUrl/strictness — the shadows must
5
+ type-check against the same world the app does), then forces the overrides the
6
+ shadow needs: `noUnusedLocals`/`noUnusedParameters` off because the shadow
7
+ legitimately declares scope bindings a template may not read, and `noEmit`/
8
+ `skipLibCheck` because it only ever type-checks. Falls back to permissive defaults
9
+ when no tsconfig is found. Shared by the check Program and the LSP LanguageService.
10
+ */
11
+ export function loadShadowTsConfig(cwd: string): ts.ParsedCommandLine {
12
+ const configPath = ts.findConfigFile(cwd, ts.sys.fileExists, 'tsconfig.json')
13
+ const base = configPath
14
+ ? ts.parseJsonConfigFileContent(
15
+ ts.readConfigFile(configPath, ts.sys.readFile).config,
16
+ ts.sys,
17
+ cwd,
18
+ )
19
+ : { options: {}, fileNames: [], errors: [] }
20
+ return {
21
+ ...base,
22
+ options: {
23
+ ...base.options,
24
+ noEmit: true,
25
+ skipLibCheck: true,
26
+ noUnusedLocals: false,
27
+ noUnusedParameters: false,
28
+ allowUnreachableCode: true,
29
+ },
30
+ }
31
+ }