@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,114 @@
1
+ import { rawHtmlString } from '../../shared/html.ts'
2
+ import { snippetPayload } from '../../shared/snippet.ts'
3
+ import { effect } from '../effect.ts'
4
+ import { claimChild } from '../runtime/claimChild.ts'
5
+ import { RENDER } from '../runtime/RENDER.ts'
6
+ import { appendSnippet } from './appendSnippet.ts'
7
+
8
+ const CLOSE = '/abide:html'
9
+
10
+ /*
11
+ A reactive `{expr}` interpolation under `parent`. A plain value is an escaped text
12
+ node: created and appended (create), or the server-rendered text node claimed
13
+ (hydrate) and bound. Adjacent SSR text merges into one node, so on hydrate the
14
+ claimed node is split at the current value's length — deterministic, because
15
+ `read()` returns the same value the server rendered.
16
+
17
+ A value branded by `html\`…\`` (see abide/shared/html) inserts raw markup instead:
18
+ its parsed nodes go between an anchor (create), or the server-rendered nodes
19
+ between `<!--abide:html-->`/`<!--/abide:html-->` markers are adopted (hydrate), and
20
+ a change re-parses and swaps. A binding is text or raw for its lifetime (decided by
21
+ its first value), so plain text — the common case — stays a cheap single node.
22
+ */
23
+ // @readme plumbing
24
+ export function appendText(parent: Node, read: () => unknown, splitAlways = false): void {
25
+ /* A snippet call (`{row(args)}`) mounts its builder; a `html\`\`` value inserts
26
+ raw markup; everything else is escaped text — decided by the first value. */
27
+ if (typeof snippetPayload(read()) === 'function') {
28
+ appendSnippet(parent, read)
29
+ return
30
+ }
31
+ if (rawHtmlString(read()) !== undefined) {
32
+ appendRawHtml(parent, read)
33
+ return
34
+ }
35
+ const hydration = RENDER.hydration
36
+ if (hydration !== undefined) {
37
+ const node = claimChild(hydration, parent) as unknown as Text
38
+ const value = String(read())
39
+ /* Peel this binding's text off the merged SSR node. A non-final binding in a
40
+ run (`splitAlways`) splits even when it consumes the whole node, leaving an
41
+ empty node for the next binding — otherwise an interpolation that renders to
42
+ empty string (or whose followers do) has no node and the next claim grabs the
43
+ wrong sibling. The final binding keeps `<` so it doesn't leave a stray node a
44
+ following element would claim. */
45
+ if (
46
+ node !== null &&
47
+ (splitAlways ? value.length <= node.data.length : value.length < node.data.length)
48
+ ) {
49
+ node.splitText(value.length)
50
+ }
51
+ hydration.next.set(parent, node === null ? null : node.nextSibling)
52
+ effect(() => {
53
+ node.data = String(read())
54
+ })
55
+ return
56
+ }
57
+ const node = document.createTextNode('')
58
+ parent.appendChild(node)
59
+ effect(() => {
60
+ node.data = String(read())
61
+ })
62
+ }
63
+
64
+ /* Raw-markup interpolation: parse the branded string into nodes behind an anchor,
65
+ re-parsing on change; on hydrate adopt the server markup between its markers. */
66
+ function appendRawHtml(parent: Node, read: () => unknown): void {
67
+ const hydration = RENDER.hydration
68
+ const markup = (): string => rawHtmlString(read()) ?? ''
69
+ const anchor = document.createTextNode('')
70
+ let nodes: Node[] = []
71
+
72
+ const set = (value: string): void => {
73
+ for (const node of nodes) {
74
+ parent.removeChild(node)
75
+ }
76
+ const holder = document.createElement('div')
77
+ holder.innerHTML = value
78
+ nodes = [...holder.childNodes]
79
+ for (const node of nodes) {
80
+ parent.insertBefore(node, anchor)
81
+ }
82
+ }
83
+
84
+ if (hydration !== undefined) {
85
+ const open = claimChild(hydration, parent)
86
+ let node: Node | null = open === null ? null : open.nextSibling
87
+ while (node !== null && !isComment(node, CLOSE)) {
88
+ nodes.push(node)
89
+ node = node.nextSibling
90
+ }
91
+ hydration.next.set(parent, node === null ? null : node.nextSibling)
92
+ parent.insertBefore(anchor, node)
93
+ let first = true
94
+ effect(() => {
95
+ const value = markup()
96
+ if (first) {
97
+ first = false // adopt the server markup as-is
98
+ return
99
+ }
100
+ set(value)
101
+ })
102
+ return
103
+ }
104
+
105
+ parent.appendChild(anchor)
106
+ effect(() => {
107
+ set(markup())
108
+ })
109
+ }
110
+
111
+ /* A comment node carrying exactly `data`. */
112
+ function isComment(node: Node, data: string): boolean {
113
+ return (node as { data?: string }).data === data && node.childNodes.length === 0
114
+ }
@@ -0,0 +1,72 @@
1
+ import { RESUME } from '../runtime/RESUME.ts'
2
+
3
+ /*
4
+ Client consumer of an SSR stream fragment. Parses a streamed
5
+ `<abide-resolve data-id="ID" data-resume="…">…</abide-resolve>` frame, registers
6
+ its serialized value in the resume manifest (for later hydration), finds the
7
+ matching `<!--abide:await:ID-->…<!--/abide:await:ID-->` boundary in `root`, removes
8
+ the pending nodes between the markers, and inserts the resolved content in their
9
+ place. The pending shell painted instantly; this swaps in each value as it
10
+ arrives — completing the out-of-order streaming loop on the client.
11
+ */
12
+ // @readme plumbing
13
+ export function applyResolved(root: Element, frame: string): void {
14
+ const holder = document.createElement('div')
15
+ holder.innerHTML = frame
16
+ const resolved = holder.firstChild as Element | null
17
+ if (resolved === null || resolved.getAttribute === undefined) {
18
+ return
19
+ }
20
+ const id = resolved.getAttribute('data-id')
21
+ if (id === null) {
22
+ return
23
+ }
24
+ /* Record the resolved value so a later hydrate adopts this branch (no re-fetch). */
25
+ const resume = resolved.getAttribute('data-resume')
26
+ if (resume !== null) {
27
+ try {
28
+ RESUME[Number(id)] = JSON.parse(resume)
29
+ } catch {
30
+ /* malformed payload — leave unregistered, hydration re-runs the promise */
31
+ }
32
+ }
33
+ const open = `abide:await:${id}`
34
+ const close = `/abide:await:${id}`
35
+ const boundary = findBoundary(root, open)
36
+ if (boundary === undefined) {
37
+ return
38
+ }
39
+ const { parent, start } = boundary
40
+ /* Remove the pending nodes between the markers (exclusive of the markers). */
41
+ let node = start.nextSibling
42
+ while (node !== null && !isComment(node, close)) {
43
+ const next = node.nextSibling
44
+ parent.removeChild(node)
45
+ node = next
46
+ }
47
+ /* Insert resolved content after the open marker. */
48
+ let anchor = start.nextSibling
49
+ for (const child of [...resolved.childNodes]) {
50
+ parent.insertBefore(child, anchor)
51
+ anchor = child.nextSibling
52
+ }
53
+ }
54
+
55
+ /* A comment node carrying exactly `data`. */
56
+ function isComment(node: Node, data: string): boolean {
57
+ return (node as { data?: string }).data === data && node.childNodes.length === 0
58
+ }
59
+
60
+ /* Depth-first search for the parent + open-marker comment of a boundary. */
61
+ function findBoundary(node: Node, open: string): { parent: Node; start: Node } | undefined {
62
+ for (const child of [...node.childNodes]) {
63
+ if (isComment(child, open)) {
64
+ return { parent: node, start: child }
65
+ }
66
+ const nested = findBoundary(child, open)
67
+ if (nested !== undefined) {
68
+ return nested
69
+ }
70
+ }
71
+ return undefined
72
+ }
@@ -0,0 +1,20 @@
1
+ import { OWNER } from '../runtime/OWNER.ts'
2
+ import { toTeardown } from '../runtime/toTeardown.ts'
3
+ import type { EffectResult } from '../runtime/types/EffectResult.ts'
4
+
5
+ /*
6
+ Runs an attachment against an element at build time and registers its optional
7
+ teardown with the current ownership scope, so it detaches when the component
8
+ disposes. The dual of `on`: where `on` owns a listener, `attach` owns whatever
9
+ the attachment sets up. Node-lifetime, not reactive — for param reactivity put an
10
+ `effect` inside the attachment and return its dispose. The attachment may be
11
+ async; its teardown then runs once the promise settles. Runtime target for an
12
+ `attach={…}` binding.
13
+ */
14
+ // @readme plumbing
15
+ export function attach(element: Element, attachment: (node: Element) => EffectResult): void {
16
+ const teardown = toTeardown(attachment(element))
17
+ if (teardown !== undefined && OWNER.current !== undefined) {
18
+ OWNER.current.push(teardown)
19
+ }
20
+ }
@@ -0,0 +1,19 @@
1
+ import { effect } from '../effect.ts'
2
+
3
+ /*
4
+ Binds an element attribute to `read()`. A boolean true sets the bare attribute,
5
+ and false/null/undefined removes it (the standard present/absent semantics);
6
+ anything else is stringified. One effect per bound attribute, so only the
7
+ changed attribute touches the DOM.
8
+ */
9
+ // @readme plumbing
10
+ export function attr(element: Element, name: string, read: () => unknown): void {
11
+ effect(() => {
12
+ const value = read()
13
+ if (value === false || value === null || value === undefined) {
14
+ element.removeAttribute(name)
15
+ } else {
16
+ element.setAttribute(name, value === true ? '' : String(value))
17
+ }
18
+ })
19
+ }
@@ -0,0 +1,224 @@
1
+ import { effect } from '../effect.ts'
2
+ import { claimChild } from '../runtime/claimChild.ts'
3
+ import { RENDER } from '../runtime/RENDER.ts'
4
+ import { RESUME } from '../runtime/RESUME.ts'
5
+ import { scope } from '../runtime/scope.ts'
6
+
7
+ /*
8
+ Async binding — the runtime for `<template await>`. Renders the pending branch,
9
+ then swaps to the resolved branch (with the value) or the error branch on settle.
10
+ Each branch is a RANGE of element roots, tracked as a node array so a multi-root
11
+ branch inserts/removes as a unit.
12
+
13
+ The read runs inside a abide-ui `effect`, so it's reactive: `abide/shared/cache`'s
14
+ store subscribes the key it reads to this effect (createSubscriber is abide-ui-
15
+ native), so `cache.invalidate()` of that key re-runs the block — pending, then the
16
+ fresh value swaps in. A read that touches no reactive source runs exactly once.
17
+
18
+ Hydration adopts in place, by precedence:
19
+ 1. a streamed resume value (`RESUME[id]`) → adopt the resolved branch the stream
20
+ swapped in, no read (the promise never runs — a plain producer resume);
21
+ 2. a warm-sync read (a non-thenable result) → adopt the SSR branch with it;
22
+ 3. otherwise (genuinely pending) → discard the SSR boundary and run fresh.
23
+ After the first (adopting) run, later invalidations swap content before an anchor
24
+ parked just before the close marker.
25
+ */
26
+ // @readme plumbing
27
+ export function awaitBlock(
28
+ parent: Node,
29
+ id: number,
30
+ promiseThunk: () => unknown,
31
+ renderPending: ((parent: Node) => Node[]) | undefined,
32
+ renderThen: (parent: Node, value: unknown) => Node[],
33
+ /* Absent when the block has no catch branch — a rejection then surfaces (re-throws
34
+ to the unhandled-rejection path) instead of rendering an empty branch. */
35
+ renderCatch: ((parent: Node, error: unknown) => Node[]) | undefined,
36
+ ): void {
37
+ const hydration = RENDER.hydration
38
+ let active: { nodes: Node[]; dispose: () => void } | undefined
39
+ let anchor: Node | undefined
40
+ let first = true
41
+ /* Bumped each run so a prior run's in-flight promise can't clobber a newer one. */
42
+ let generation = 0
43
+
44
+ const detach = (): void => {
45
+ if (active !== undefined) {
46
+ active.dispose()
47
+ for (const node of active.nodes) {
48
+ parent.removeChild(node)
49
+ }
50
+ active = undefined
51
+ }
52
+ }
53
+
54
+ /* Replace the current content with a freshly-built range, before the anchor. */
55
+ const place = (build: (parent: Node) => Node[]): void => {
56
+ detach()
57
+ let nodes: Node[] = []
58
+ const dispose = scope(() => {
59
+ nodes = build(parent)
60
+ })
61
+ active = { nodes, dispose }
62
+ for (const node of nodes) {
63
+ parent.insertBefore(node, anchor ?? null)
64
+ }
65
+ }
66
+
67
+ /* Render a settled-or-pending result into the current generation. */
68
+ const render = (result: unknown): void => {
69
+ const gen = generation
70
+ if (!isThenable(result)) {
71
+ place((host) => renderThen(host, result)) // warm-sync → resolved now, no flash
72
+ return
73
+ }
74
+ if (renderPending !== undefined) {
75
+ place((host) => renderPending(host))
76
+ } else {
77
+ detach()
78
+ }
79
+ result.then(
80
+ (value) => {
81
+ if (gen === generation) {
82
+ place((host) => renderThen(host, value))
83
+ }
84
+ },
85
+ (error) => {
86
+ if (gen !== generation) {
87
+ return
88
+ }
89
+ /* No catch branch → surface the rejection instead of an empty branch. */
90
+ if (renderCatch === undefined) {
91
+ throw error
92
+ }
93
+ place((host) => renderCatch(host, error))
94
+ },
95
+ )
96
+ }
97
+
98
+ /* Adopt an SSR-resolved branch in place (its roots claim the existing nodes),
99
+ then park an anchor just before the close marker for later swaps. */
100
+ const adopt = (open: Node | null, build: (parent: Node) => Node[]): void => {
101
+ const cursor = hydration as NonNullable<typeof hydration>
102
+ cursor.next.set(parent, open?.nextSibling ?? null)
103
+ let nodes: Node[] = []
104
+ const dispose = scope(() => {
105
+ nodes = build(parent)
106
+ })
107
+ const close = claimChild(cursor, parent)
108
+ cursor.next.set(parent, close?.nextSibling ?? null)
109
+ anchor = document.createTextNode('')
110
+ parent.insertBefore(anchor, close)
111
+ active = { nodes, dispose }
112
+ }
113
+
114
+ /* Discard the SSR boundary and (re)build the block from the live promise, fresh
115
+ (hydration off) — the recovery path when adoption can't use the server markup. */
116
+ const rebuildCold = (open: Node | null): void => {
117
+ detach()
118
+ discardBoundary(
119
+ parent,
120
+ open,
121
+ `/abide:await:${id}`,
122
+ hydration as NonNullable<typeof hydration>,
123
+ )
124
+ anchor = document.createTextNode('')
125
+ parent.appendChild(anchor)
126
+ const previous = RENDER.hydration
127
+ RENDER.hydration = undefined
128
+ try {
129
+ render(promiseThunk())
130
+ } finally {
131
+ RENDER.hydration = previous
132
+ }
133
+ }
134
+
135
+ /* The first run when hydrating: adopt by precedence (resume / warm-sync), else
136
+ discard the boundary and mount fresh. Adoption is guarded: a resume value that
137
+ didn't round-trip (e.g. a non-serializable Response) throws while building the
138
+ branch — fall back to the live promise, which reads the properly-reconstructed
139
+ warm cache (or re-fetches) instead of crashing hydration. */
140
+ const firstHydrate = (result: unknown): void => {
141
+ const cursor = hydration as NonNullable<typeof hydration>
142
+ const open = claimChild(cursor, parent)
143
+ const entry = RESUME[id]
144
+ if (entry !== undefined) {
145
+ let build: (host: Node) => Node[]
146
+ if (entry.ok) {
147
+ build = (host) => renderThen(host, entry.value)
148
+ } else if (renderCatch !== undefined) {
149
+ build = (host) => renderCatch(host, entry.error)
150
+ } else {
151
+ /* A resumed rejection with no catch branch surfaces (mirrors the cold
152
+ path); in practice the server 500s such a block, so none resumes. */
153
+ throw entry.error
154
+ }
155
+ try {
156
+ adopt(open, build)
157
+ } catch {
158
+ rebuildCold(open)
159
+ }
160
+ return
161
+ }
162
+ if (!isThenable(result)) {
163
+ try {
164
+ adopt(open, (host) => renderThen(host, result))
165
+ } catch {
166
+ rebuildCold(open)
167
+ }
168
+ return
169
+ }
170
+ discardBoundary(parent, open, `/abide:await:${id}`, cursor)
171
+ anchor = document.createTextNode('')
172
+ parent.appendChild(anchor)
173
+ render(result)
174
+ }
175
+
176
+ effect(() => {
177
+ generation += 1
178
+ /* Read the promise EVERY run, including the first hydrate run, so the block
179
+ subscribes to its reactive source (a cache key). A cache-remote read is warm
180
+ on resume — it serves the snapshot without a network round-trip, so adoption
181
+ stays no-flash AND a later cache.invalidate re-runs the block. Without this
182
+ read a resume-adopted block has no deps and invalidate is a no-op. */
183
+ const result = promiseThunk()
184
+ if (first) {
185
+ first = false
186
+ if (hydration !== undefined) {
187
+ firstHydrate(result)
188
+ return
189
+ }
190
+ anchor = document.createTextNode('')
191
+ parent.appendChild(anchor)
192
+ }
193
+ render(result)
194
+ })
195
+ }
196
+
197
+ /* Whether a value is Promise-like (the cold path); a non-thenable is warm-sync. */
198
+ function isThenable(value: unknown): value is Promise<unknown> {
199
+ return value !== null && typeof (value as { then?: unknown })?.then === 'function'
200
+ }
201
+
202
+ /* Remove the SSR boundary — open marker through close marker (inclusive) — and
203
+ park the hydration cursor on the node after it, so a fresh run replaces it
204
+ without duplicating the server's pending shell. */
205
+ function discardBoundary(
206
+ parent: Node,
207
+ open: Node | null,
208
+ closeData: string,
209
+ hydration: NonNullable<(typeof RENDER)['hydration']>,
210
+ ): void {
211
+ let node = open
212
+ let after: Node | null = null
213
+ while (node !== null) {
214
+ const next = node.nextSibling
215
+ const isClose = (node as { data?: string }).data === closeData
216
+ parent.removeChild(node)
217
+ if (isClose) {
218
+ after = next
219
+ break
220
+ }
221
+ node = next
222
+ }
223
+ hydration.next.set(parent, after)
224
+ }
@@ -0,0 +1,52 @@
1
+ import { claimChild } from '../runtime/claimChild.ts'
2
+ import { RENDER } from '../runtime/RENDER.ts'
3
+
4
+ /*
5
+ Parsed-once `<template>` per unique static-skeleton string, reused across every
6
+ mount. A `<template>` (not a detached `<div>`) so table/select content parses by
7
+ the real content model, exactly as the browser parsed the server markup.
8
+ */
9
+ const TEMPLATES = new Map<string, HTMLTemplateElement>()
10
+
11
+ function templateFor(html: string): HTMLTemplateElement {
12
+ let template = TEMPLATES.get(html)
13
+ if (template === undefined) {
14
+ template = document.createElement('template')
15
+ template.innerHTML = html
16
+ TEMPLATES.set(html, template)
17
+ }
18
+ return template
19
+ }
20
+
21
+ /*
22
+ Appends a fully-static subtree (one or more top-level nodes) under `parent` — what
23
+ the compiler emits in place of the imperative `openChild`/`setAttribute`/
24
+ `appendStatic` chain when an element subtree carries no bindings, control flow, or
25
+ listeners. The skeleton string is generated by the same rules as the SSR back-end,
26
+ so it is byte-identical to the server markup.
27
+
28
+ Create mode: clone the cached template once per mount — a single deep clone (native
29
+ in the browser) instead of N create/append calls. Hydrate mode: nothing is built;
30
+ the server already rendered this exact markup, so it only advances the parent's
31
+ claim cursor past the run's top-level nodes (nothing inside binds, so none need
32
+ claiming individually). The node count comes from the parsed template, which has
33
+ the same top-level node count as the server markup.
34
+ */
35
+ // @readme plumbing
36
+ export function cloneStatic(parent: Node, html: string): void {
37
+ const template = templateFor(html)
38
+ const hydration = RENDER.hydration
39
+ if (hydration !== undefined) {
40
+ let node = claimChild(hydration, parent)
41
+ let remaining = template.content.childNodes.length
42
+ while (remaining > 0 && node !== null) {
43
+ node = node.nextSibling
44
+ remaining -= 1
45
+ }
46
+ hydration.next.set(parent, node)
47
+ return
48
+ }
49
+ for (const child of template.content.childNodes) {
50
+ parent.appendChild(child.cloneNode(true))
51
+ }
52
+ }
@@ -0,0 +1,115 @@
1
+ import { effect } from '../effect.ts'
2
+ import { claimChild } from '../runtime/claimChild.ts'
3
+ import { OWNER } from '../runtime/OWNER.ts'
4
+ import { RENDER } from '../runtime/RENDER.ts'
5
+ import { scope } from '../runtime/scope.ts'
6
+ import type { EachRow } from './types/EachRow.ts'
7
+
8
+ /*
9
+ Keyed list binding — the runtime for `<template each key=>`. Rows live in their own
10
+ region, bounded by a trailing anchor so positioning is relative to the each itself,
11
+ never `parent.firstChild` — a sibling before the each (e.g. a static nav link) must
12
+ not be treated as the first row. An effect tracks `items()` and reconciles by key:
13
+ a new key renders a row in its own ownership scope (so the row's bindings dispose
14
+ when it leaves), and a departed key disposes and is removed. Keying by identity
15
+ (not index) lets a row keep its node and inner effects across a reorder.
16
+
17
+ Placement walks the desired list *backwards* from the trailing anchor, holding a
18
+ cursor at the node each row should precede; a row already sitting there is left
19
+ untouched, so a stable list does zero DOM moves and an append does exactly one —
20
+ only out-of-place rows are re-inserted (`insertBefore` on an in-place node would
21
+ otherwise remove-then-reinsert it, O(rows) moves per change). Departed rows are
22
+ pruned *before* placement so their nodes can't shift the cursor's sibling checks.
23
+
24
+ On hydrate the SSR rows are already in place and in order: claim each one where it
25
+ sits (no reordering), park the anchor after them, and skip the first reconcile.
26
+ */
27
+ // @readme plumbing
28
+ export function each<T>(
29
+ parent: Node,
30
+ items: () => Iterable<T>,
31
+ keyOf: (item: T) => string,
32
+ render: (parent: Node, item: T) => Node,
33
+ ): void {
34
+ const rows = new Map<string, EachRow>()
35
+
36
+ /* Build one row in its own scope (render claims on hydrate, creates otherwise). */
37
+ const buildRow = (item: T): EachRow => {
38
+ let node: Node | undefined
39
+ const dispose = scope(() => {
40
+ node = render(parent, item)
41
+ })
42
+ return { node: node as Node, dispose }
43
+ }
44
+
45
+ const hydration = RENDER.hydration
46
+ let anchor: Node
47
+ /* When hydrating, the first effect run must NOT reconcile — the rows it would
48
+ build are already adopted in place below. */
49
+ let adopting = false
50
+ if (hydration !== undefined) {
51
+ for (const item of items()) {
52
+ rows.set(keyOf(item), buildRow(item)) // claims the SSR row where it sits
53
+ }
54
+ anchor = document.createTextNode('')
55
+ parent.insertBefore(anchor, claimChild(hydration, parent))
56
+ adopting = true
57
+ } else {
58
+ anchor = document.createTextNode('')
59
+ parent.appendChild(anchor)
60
+ }
61
+
62
+ effect(() => {
63
+ /* Read (subscribe) every run, including the adopting one. Materialize a
64
+ non-array iterable to an array so a generator yields fresh each run and the
65
+ list can be safely traversed once for placement, once for pruning. */
66
+ const source = items()
67
+ if (adopting) {
68
+ adopting = false // rows already adopted in document order; nothing to move
69
+ return
70
+ }
71
+ const list = Array.isArray(source) ? source : [...source]
72
+ const keys = list.map(keyOf)
73
+ const present = new Set(keys)
74
+ /* Prune departed rows first so their nodes don't sit between survivors and
75
+ throw off the in-place sibling checks below. */
76
+ for (const [key, row] of rows) {
77
+ if (!present.has(key)) {
78
+ row.dispose()
79
+ parent.removeChild(row.node)
80
+ rows.delete(key)
81
+ }
82
+ }
83
+ /* Walk backwards from the anchor: `cursor` is the node the current row must
84
+ precede. A row already there keeps its place; only an out-of-order (or
85
+ freshly built) row is moved. Placement never touches preceding siblings. */
86
+ let cursor: Node = anchor
87
+ for (let index = list.length - 1; index >= 0; index -= 1) {
88
+ const key = keys[index] as string
89
+ let row = rows.get(key)
90
+ if (row === undefined) {
91
+ row = buildRow(list[index] as T)
92
+ rows.set(key, row)
93
+ }
94
+ if (row.node.nextSibling !== cursor) {
95
+ parent.insertBefore(row.node, cursor)
96
+ }
97
+ cursor = row.node
98
+ }
99
+ })
100
+
101
+ /* Dispose every row still live when the enclosing scope tears down. The effect's
102
+ own disposer only unsubscribes it from `items()`; it never reaches the per-row
103
+ ownership scopes, which are pruned only on the departed-key path above. Without
104
+ this, a row whose binding subscribes to a longer-lived signal (a module store,
105
+ the cache, `page`) stays in that signal's observers after the list unmounts. The
106
+ host's DOM is cleared by `mount`, so disposal need not remove the nodes. */
107
+ if (OWNER.current !== undefined) {
108
+ OWNER.current.push(() => {
109
+ for (const row of rows.values()) {
110
+ row.dispose()
111
+ }
112
+ rows.clear()
113
+ })
114
+ }
115
+ }