@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,86 @@
1
+ # abide-ui
2
+
3
+ A from-scratch, single-file UI framework for abide — reactive, with `<script>` +
4
+ template + `<style>` in one `.abide` file. Signal surface, document
5
+ substrate, server-rendered and streamed, with true DOM adoption.
6
+
7
+ abide-ui is the framework's UI runtime: `createUiPageRenderer` renders and streams
8
+ every page, and `.abide` files are the only component format.
9
+
10
+ ## A component
11
+
12
+ ```html
13
+ <script>
14
+ import Layout from './Layout.abide'
15
+ let count = state(0) // signal
16
+ let items = state([])
17
+ let total = derived(() => items.length) // computed
18
+ function add() { items.push('item ' + (total + 1)) }
19
+ </script>
20
+
21
+ <Layout title="home">
22
+ <button onclick={() => count += 1}>count: {count}</button>
23
+ <button onclick={add}>add ({total})</button>
24
+ <template if={total}>
25
+ <ul>
26
+ <template each={items} as="it" key="it"><li>{it}</li></template>
27
+ </ul>
28
+ <template else><p>empty</p></template>
29
+ </template>
30
+ </Layout>
31
+
32
+ <style>
33
+ button { cursor: pointer } /* scoped to this component */
34
+ </style>
35
+ ```
36
+
37
+ ## Idioms
38
+
39
+ - **Signals are the surface**: `state(v)`, `derived(fn)`, `effect(fn)`, `prop(name)`.
40
+ You write plain assignment (`count += 1`, `items.push(x)`); the compiler lowers
41
+ it. Templates auto-read (`{count}`); ordering and cross-references compose.
42
+ - **Everything dynamic lives in `{ }`** — `{expr}` text, `name={expr}`,
43
+ `onclick={fn}`, `bind:value={path}`.
44
+ - **Control flow is native `<template>`** (valid HTML, no mustache DSL):
45
+ `<template if>`/`<template else>`, `<template each as key>`,
46
+ `<template await>`/`then`/`catch`, `<template switch>`/`case`/`default`.
47
+ - **Components** are capitalised tags (`<Layout title="…">`); children fill the
48
+ child's `<slot>`. Props are reactive (passed as thunks).
49
+ - **Scoped styles**: a `<style>` block is scoped per component via a
50
+ `[data-b-<hash>]` attribute.
51
+
52
+ ## Substrate (why it's fast)
53
+
54
+ State is one mutable document addressed by path; every change is a patch over a
55
+ path. The compiler turns `model.a[i].b` into a path read and `model.x = y` into a
56
+ patch, hoisting static paths to a `cell` resolved once. Reactivity is shape-only
57
+ (a deep field edit wakes only that field, not the list above it). On the
58
+ write-path microbench this runs ~20× faster than a deep-proxy signal baseline.
59
+
60
+ ## SSR + streaming + hydration
61
+
62
+ - `compileSSR` renders to an HTML string (byte-identical to the client DOM).
63
+ - `renderToStream` streams: pending shell first, then resolved `<template await>`
64
+ fragments out of order as their promises settle; `applyResolved` swaps them in.
65
+ - `hydrate` adopts the server DOM in place (no re-render) for static-structure
66
+ components — claims existing nodes, splits merged text, wires effects/listeners.
67
+
68
+ ## Pipeline
69
+
70
+ ```
71
+ .abide → analyzeComponent (split script/style/template, desugar signals → doc,
72
+ lower data access, scope CSS)
73
+ → generateBuild (client: openChild/appendText/attr/on/each/when/…)
74
+ → generateSSR (server: HTML-string back-end, await markers)
75
+ → hoistCells (static paths → cells)
76
+ → compileModule (ES module: default mount + render() for SSR)
77
+ ```
78
+
79
+ `compile/abideUiPlugin.ts` is the Bun loader for `.abide` files.
80
+
81
+ ## Known gaps
82
+
83
+ - Hydration adopts static structure only; control-flow blocks (if/each/await/
84
+ switch) and child components fall back to `mount` (re-render).
85
+ - `compileModule` emits `abide/ui/*` specifiers (a published consumer needs
86
+ `abide/ui/*` or `abideImportName`).
@@ -0,0 +1,25 @@
1
+ /*
2
+ Source text for the `$esc` / `$attr` / `$text` / `$snip` helpers injected into
3
+ every SSR render body. `$esc` escapes the five HTML-significant characters. `$attr`
4
+ renders a dynamic `{expr}` attribute with the same present/absent semantics the
5
+ client `attr` binding uses: false/null/undefined drops it, true emits the bare
6
+ attribute, anything else emits `name="escaped"`. `$snip` brands a snippet's
7
+ rendered string. `$text` is what `{expr}` interpolations push: a snippet call's
8
+ value is emitted raw between `<!--abide:snippet-->` markers (the client runs its
9
+ builder there to claim the nodes); a `html\`…\`` value raw between `<!--abide:html-->`
10
+ markers; anything else is escaped. The brands are registered Symbols so they match
11
+ across bundles. Emitted inline (not imported) so the generated render module is
12
+ self-contained.
13
+ */
14
+ export const SSR_ESCAPE =
15
+ 'const $esc = (v) => String(v).replace(/[&<>"\']/g, (c) => ' +
16
+ "({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[c]);\n" +
17
+ 'const $attr = (n, v) => (v === false || v === null || v === undefined) ? "" ' +
18
+ ': v === true ? (" " + n) : (" " + n + \'="\' + $esc(v) + \'"\');\n' +
19
+ "const $RAW = Symbol.for('abide.rawHtml');\n" +
20
+ "const $SNIP = Symbol.for('abide.snippet');\n" +
21
+ 'const $snip = (s) => ({ [$SNIP]: s });\n' +
22
+ 'const $text = (v) => (v !== null && typeof v === "object" && $SNIP in v) ' +
23
+ "? ('<!--abide:snippet-->' + v[$SNIP] + '<!--/abide:snippet-->') " +
24
+ ': (v !== null && typeof v === "object" && $RAW in v) ' +
25
+ "? ('<!--abide:html-->' + v[$RAW] + '<!--/abide:html-->') : $esc(v);"
@@ -0,0 +1,36 @@
1
+ /*
2
+ The abide-ui runtime names every compiled component module depends on, each
3
+ paired with its package subpath (after the package name). One source of truth so
4
+ three things can't drift: the normal module's import block (`compileModule`), the
5
+ hot module's `window.__abide` destructure (dev component HMR), and the dev bridge
6
+ that populates `window.__abide`. Order is the emit order.
7
+ */
8
+ export const UI_RUNTIME_IMPORTS: { name: string; specifier: string }[] = [
9
+ { name: 'html', specifier: 'shared/html' },
10
+ { name: 'snippet', specifier: 'shared/snippet' },
11
+ { name: 'doc', specifier: 'ui/doc' },
12
+ { name: 'state', specifier: 'ui/state' },
13
+ { name: 'derived', specifier: 'ui/derived' },
14
+ { name: 'effect', specifier: 'ui/effect' },
15
+ { name: 'mount', specifier: 'ui/dom/mount' },
16
+ { name: 'openChild', specifier: 'ui/dom/openChild' },
17
+ { name: 'openRoot', specifier: 'ui/dom/openRoot' },
18
+ { name: 'appendText', specifier: 'ui/dom/appendText' },
19
+ { name: 'appendSnippet', specifier: 'ui/dom/appendSnippet' },
20
+ { name: 'appendStatic', specifier: 'ui/dom/appendStatic' },
21
+ { name: 'cloneStatic', specifier: 'ui/dom/cloneStatic' },
22
+ { name: 'attr', specifier: 'ui/dom/attr' },
23
+ { name: 'on', specifier: 'ui/dom/on' },
24
+ { name: 'attach', specifier: 'ui/dom/attach' },
25
+ { name: 'each', specifier: 'ui/dom/each' },
26
+ { name: 'eachAsync', specifier: 'ui/dom/eachAsync' },
27
+ { name: 'when', specifier: 'ui/dom/when' },
28
+ { name: 'awaitBlock', specifier: 'ui/dom/awaitBlock' },
29
+ { name: 'tryBlock', specifier: 'ui/dom/tryBlock' },
30
+ { name: 'switchBlock', specifier: 'ui/dom/switchBlock' },
31
+ { name: 'mountChild', specifier: 'ui/dom/mountChild' },
32
+ { name: 'hydrate', specifier: 'ui/dom/hydrate' },
33
+ { name: 'nextBlockId', specifier: 'ui/runtime/nextBlockId' },
34
+ { name: 'enterRenderPass', specifier: 'ui/runtime/enterRenderPass' },
35
+ { name: 'exitRenderPass', specifier: 'ui/runtime/exitRenderPass' },
36
+ ]
@@ -0,0 +1,21 @@
1
+ /*
2
+ HTML void elements — they have no closing tag and no children. Shared by the SSR
3
+ generator and the static-clone skeleton generator so both emit `<img>` not
4
+ `<img></img>`, keeping server markup and the client clone template identical.
5
+ */
6
+ export const VOID_TAGS: ReadonlySet<string> = new Set([
7
+ 'area',
8
+ 'base',
9
+ 'br',
10
+ 'col',
11
+ 'embed',
12
+ 'hr',
13
+ 'img',
14
+ 'input',
15
+ 'link',
16
+ 'meta',
17
+ 'param',
18
+ 'source',
19
+ 'track',
20
+ 'wbr',
21
+ ])
@@ -0,0 +1,65 @@
1
+ import { relative } from 'node:path'
2
+ import type { BunPlugin } from 'bun'
3
+ import { analyzeComponent } from './analyzeComponent.ts'
4
+ import { compileModule } from './compileModule.ts'
5
+ import { nearestProjectRoot } from './nearestProjectRoot.ts'
6
+
7
+ /*
8
+ Bun plugin that loads `.abide` single-file components: compiles each to the ES
9
+ module `compileModule` emits, so they import and mount like any other module. The
10
+ only UI loader in the dev/build/preload pipeline; the emitted module's
11
+ `abide/ui/*` imports resolve through the package exports.
12
+
13
+ A `layout.abide` compiles as a layout: its `<slot/>` lowers to the router's page
14
+ outlet (`<abide-outlet>`) rather than a passed-children slot — the file's role is
15
+ its name, so the loader flags it from the path stem.
16
+
17
+ The emitted module embeds the component's `<script>` and `{expr}` bodies verbatim,
18
+ so it carries the author's TypeScript (a typed `prop`, an annotated handler). The
19
+ `ts` loader strips those annotations — the generated runtime code is valid TS too —
20
+ keeping `.abide` scripts the TypeScript that `abide check` type-checks them as.
21
+
22
+ A component's scoped `<style>`(s) are bundled, not inlined: in the BROWSER build the
23
+ module imports a virtual `abide-style:` CSS module holding every block's scoped CSS
24
+ concatenated, so Bun folds it into the entry stylesheet (`client.css`, already linked
25
+ by the shell). Server builds (target `bun`) omit the import — SSR styling comes from
26
+ that same linked sheet, so a page renders styled before the client bundle loads, with
27
+ no inlined `<style>`. The elements still carry their `data-a-…` scope attributes
28
+ either way (one per `<style>` covering them — see `analyzeComponent`).
29
+ */
30
+ // @readme plumbing
31
+ export const abideUiPlugin: BunPlugin = {
32
+ name: 'abide-ui',
33
+ setup(build) {
34
+ const toBrowser = build.config?.target === 'browser'
35
+ /* Scoped CSS keyed by its virtual specifier, filled as each `.abide` loads and
36
+ read back when Bun resolves the matching `abide-style:` import (browser only). */
37
+ const cssByVirtual = new Map<string, string>()
38
+
39
+ build.onLoad({ filter: /\.abide$/ }, async (args) => {
40
+ const source = await Bun.file(args.path).text()
41
+ const moduleId = relative(nearestProjectRoot(args.path, process.cwd()), args.path)
42
+ const isLayout = (args.path.split('/').pop() ?? '') === 'layout.abide'
43
+ const code = compileModule(source, { isLayout, moduleId })
44
+ /* Browser build with `<style>`(s): concatenate every scoped block's CSS and
45
+ pull it into the bundle via one virtual import, keyed by `moduleId` so the
46
+ registry id and the CSS id agree. */
47
+ const styles = toBrowser ? analyzeComponent(source, moduleId).styles : []
48
+ if (styles.length === 0) {
49
+ return { contents: code, loader: 'ts' }
50
+ }
51
+ const virtual = `abide-style:${moduleId}`
52
+ cssByVirtual.set(virtual, styles.map((style) => style.css).join('\n'))
53
+ return { contents: `import ${JSON.stringify(virtual)}\n${code}`, loader: 'ts' }
54
+ })
55
+
56
+ build.onResolve({ filter: /^abide-style:/ }, (args) => ({
57
+ path: args.path,
58
+ namespace: 'abide-style',
59
+ }))
60
+ build.onLoad({ filter: /.*/, namespace: 'abide-style' }, (args) => ({
61
+ contents: cssByVirtual.get(args.path) ?? '',
62
+ loader: 'css',
63
+ }))
64
+ },
65
+ }
@@ -0,0 +1,117 @@
1
+ import { desugarSignals } from './desugarSignals.ts'
2
+ import { lowerDocAccess } from './lowerDocAccess.ts'
3
+ import { parseTemplate } from './parseTemplate.ts'
4
+ import { scopeCss } from './scopeCss.ts'
5
+ import type { AnalyzedComponent } from './types/AnalyzedComponent.ts'
6
+ import type { TemplateNode } from './types/TemplateNode.ts'
7
+
8
+ /*
9
+ The shared compile front-end: splits the leading `<script>` off the template,
10
+ desugars the signal surface to the doc form, lowers the script's data access, and
11
+ parses the template (which keeps each `<style>` as an in-place node). Each `<style>`
12
+ is scoped to its own attribute (`data-a-<hash>`); `annotateScopes` stamps that
13
+ attribute onto every element in the style's sibling subtree, so a top-level
14
+ `<style>` covers the whole component while a nested one covers only the branch it
15
+ sits in. Both client and SSR back-ends read the per-element `scopes`, so the targets
16
+ always agree.
17
+
18
+ `scopeSeed` (the component's stable module id, supplied by the loader) seeds each
19
+ hash — combined with the style's source-order index — so the attribute tracks
20
+ component+position identity, not CSS text: an edit to a `<style>` keeps the same
21
+ `data-a-…`, so the live elements still match and the CSS can hot-swap in place.
22
+ Absent (direct compile calls / tests) it falls back to hashing the style body.
23
+ */
24
+ export function analyzeComponent(source: string, scopeSeed?: string): AnalyzedComponent {
25
+ /* Only the LEADING `<script>` is the component script; scripts nested in the
26
+ template (scoped reactive blocks) survive into the parsed nodes. The `<style>`
27
+ is left in the template for the parser to extract structurally (below), so a
28
+ `<style>` quoted inside an expression is never mistaken for the component's. */
29
+ const scriptMatch = source.match(/^\s*<script[^>]*>([\s\S]*?)<\/script>/)
30
+ const scriptBody = (scriptMatch?.[1] ?? '').trim()
31
+ const template = source.replace(/^\s*<script[^>]*>[\s\S]*?<\/script>/, '').trim()
32
+
33
+ const { code: desugared, stateNames, derivedNames } = desugarSignals(scriptBody)
34
+ const lowered = desugared.trim() === '' ? '' : lowerDocAccess(desugared, 'model')
35
+ /* Hoist top-level import statements (e.g. child components) out of the script
36
+ so the module wrapper can place them at module scope — they can't live
37
+ inside the mount callback / render function. */
38
+ const imports: string[] = []
39
+ const script = lowered
40
+ .replace(/^[ \t]*import\s[^\n]*$/gm, (line) => {
41
+ imports.push(line.trim())
42
+ return ''
43
+ })
44
+ .replace(/\n{2,}/g, '\n')
45
+ .trim()
46
+ /* The parser keeps each `<style>` as an in-place node (one inside an expression
47
+ is text, never a node). `annotateScopes` mutates the tree — assigning each
48
+ style its scope attribute and stamping covered elements — and returns the
49
+ scoped CSS per block for the bundler. */
50
+ const { nodes } = parseTemplate(template)
51
+ const styles = annotateScopes(nodes, [], scopeSeed, { count: 0 })
52
+ return {
53
+ script,
54
+ imports: imports.join('\n'),
55
+ stateNames,
56
+ derivedNames,
57
+ nodes,
58
+ styles,
59
+ /* Hydration adopts every block in place — including `await`, which resumes
60
+ from the streamed value in the resume manifest (see `runtime/RESUME`). */
61
+ hydratable: true,
62
+ }
63
+ }
64
+
65
+ /* The children of a control-flow / element / component node, or undefined for a
66
+ leaf (text/script/style). Every children-bearing kind carries `children`. */
67
+ function childrenOf(node: TemplateNode): TemplateNode[] | undefined {
68
+ return 'children' in node ? node.children : undefined
69
+ }
70
+
71
+ /*
72
+ Walks `nodes` in source order, scoping each `<style>` to its sibling subtree: a
73
+ style among a sibling list covers every element in that list AND every descendant
74
+ (so its attribute reaches the whole branch it sits in, like the nested-`<script>`
75
+ rule). `inherited` is the scope attributes already active from ancestors; this
76
+ level adds its own styles' attributes, stamps the resulting set onto each element
77
+ here, and recurses with it. `index.count` is the running source-order ordinal that
78
+ (with `scopeSeed`) keeps each attribute stable across CSS edits. Returns the scoped
79
+ CSS for every non-empty style, in source order, for the bundler to concatenate.
80
+ */
81
+ function annotateScopes(
82
+ nodes: TemplateNode[],
83
+ inherited: string[],
84
+ scopeSeed: string | undefined,
85
+ index: { count: number },
86
+ ): { attribute: string; css: string }[] {
87
+ const collected: { attribute: string; css: string }[] = []
88
+ /* This sibling list's own style attributes — active for every element here. */
89
+ const here = [...inherited]
90
+ for (const node of nodes) {
91
+ if (node.kind === 'style' && node.css.trim() !== '') {
92
+ const attribute = `data-a-${hashString(`${scopeSeed ?? node.css}#${index.count}`)}`
93
+ index.count += 1
94
+ collected.push({ attribute, css: scopeCss(node.css, attribute) })
95
+ here.push(attribute)
96
+ }
97
+ }
98
+ for (const node of nodes) {
99
+ if (node.kind === 'element') {
100
+ node.scopes = here
101
+ }
102
+ const children = childrenOf(node)
103
+ if (children !== undefined) {
104
+ collected.push(...annotateScopes(children, here, scopeSeed, index))
105
+ }
106
+ }
107
+ return collected
108
+ }
109
+
110
+ /* Small stable hash (djb2 → base36) for a per-style scope attribute. */
111
+ function hashString(value: string): string {
112
+ let hash = 5381
113
+ for (let index = 0; index < value.length; index += 1) {
114
+ hash = (hash * 33) ^ value.charCodeAt(index)
115
+ }
116
+ return (hash >>> 0).toString(36)
117
+ }
@@ -0,0 +1,32 @@
1
+ import { resolve } from 'node:path'
2
+
3
+ /*
4
+ A single virtual ambient-declaration file injected into the shadow world so the
5
+ type-checker resolves bundler-handled asset imports instead of erroring "cannot
6
+ find module". Bun bundles a stylesheet import for its side effect and resolves a
7
+ static asset to its URL string; these declarations mirror that. One shared file
8
+ (not a per-component preamble) keeps the wildcard module patterns declared once,
9
+ which TypeScript requires. Used by both the check Program and the LSP service so
10
+ the editor and CLI agree.
11
+ */
12
+ export function assetModulesFile(cwd: string): { path: string; content: string } {
13
+ return {
14
+ path: resolve(cwd, '__abide_assets__.d.ts'),
15
+ content: [
16
+ "declare module '*.css' {}",
17
+ "declare module '*.scss' {}",
18
+ "declare module '*.sass' {}",
19
+ "declare module '*.less' {}",
20
+ "declare module '*.svg' { const src: string; export default src }",
21
+ "declare module '*.png' { const src: string; export default src }",
22
+ "declare module '*.jpg' { const src: string; export default src }",
23
+ "declare module '*.jpeg' { const src: string; export default src }",
24
+ "declare module '*.gif' { const src: string; export default src }",
25
+ "declare module '*.webp' { const src: string; export default src }",
26
+ "declare module '*.avif' { const src: string; export default src }",
27
+ "declare module '*.woff' { const src: string; export default src }",
28
+ "declare module '*.woff2' { const src: string; export default src }",
29
+ '',
30
+ ].join('\n'),
31
+ }
32
+ }
@@ -0,0 +1,50 @@
1
+ import type { TemplateNode } from './types/TemplateNode.ts'
2
+
3
+ /*
4
+ The element roots of a control-flow branch (`if`/`else`/`switch case`/`await
5
+ then|catch`). A branch may hold one or MORE top-level elements — each becomes a
6
+ root the block tracks as a range. Whitespace-only text between/around them is
7
+ dropped (so SSR and the client build agree on the node set, keeping hydration
8
+ aligned). Any other top-level content — meaningful text, a component, or a nested
9
+ control-flow `<template>` — must be wrapped in an element; it throws a clear error
10
+ rather than silently dropping (full fragment roots are a separate feature).
11
+
12
+ Both back-ends call this, so the server HTML and the client build contain exactly
13
+ the same roots in the same order.
14
+ */
15
+ type ElementNode = Extract<TemplateNode, { kind: 'element' }>
16
+
17
+ export function branchElements(
18
+ children: TemplateNode[],
19
+ context: string,
20
+ allowEmpty = false,
21
+ ): ElementNode[] {
22
+ const elements: ElementNode[] = []
23
+ for (const child of children) {
24
+ if (child.kind === 'element') {
25
+ elements.push(child)
26
+ continue
27
+ }
28
+ /* Whitespace-only text is layout noise between roots — drop it. */
29
+ if (child.kind === 'text' && isWhitespaceOnly(child)) {
30
+ continue
31
+ }
32
+ /* A scoped `<script>` is emitted as code by the back-end, not a root; a
33
+ `<style>` is bundled CSS (its scope already stamped on the roots). */
34
+ if (child.kind === 'script' || child.kind === 'style') {
35
+ continue
36
+ }
37
+ throw new Error(
38
+ `[abide] ${context} content must be element(s); wrap text / components / nested <template> in an element`,
39
+ )
40
+ }
41
+ if (elements.length === 0 && !allowEmpty) {
42
+ throw new Error(`[abide] ${context} must contain at least one element`)
43
+ }
44
+ return elements
45
+ }
46
+
47
+ /* A text node whose parts are all whitespace literals (no interpolation). */
48
+ function isWhitespaceOnly(node: Extract<TemplateNode, { kind: 'text' }>): boolean {
49
+ return node.parts.every((part) => part.kind === 'static' && part.value.trim() === '')
50
+ }
@@ -0,0 +1,59 @@
1
+ import ts from 'typescript'
2
+ import type { ShadowProgram } from './createShadowProgram.ts'
3
+ import { remapShadowDiagnostic } from './remapShadowDiagnostic.ts'
4
+ import type { AbideDiagnostic } from './types/AbideDiagnostic.ts'
5
+
6
+ /*
7
+ Runs the shadow program's type-checker over every `.abide` shadow and relocates
8
+ each diagnostic onto its source component. Only diagnostics that fall inside a
9
+ mapped expression survive (remapShadowDiagnostic drops shadow-internal noise);
10
+ a template that failed to parse contributes a single error at the file head.
11
+ Shared by `abide check` (one-shot render) and the LSP (per-file publish).
12
+ */
13
+ export function collectAbideDiagnostics(shadow: ShadowProgram): AbideDiagnostic[] {
14
+ const { program, shadows, parseErrors, abidePaths } = shadow
15
+ const diagnostics: AbideDiagnostic[] = []
16
+ for (const abidePath of abidePaths) {
17
+ const parseError = parseErrors.get(abidePath)
18
+ if (parseError !== undefined) {
19
+ diagnostics.push({
20
+ file: abidePath,
21
+ start: 0,
22
+ length: 0,
23
+ message: parseError,
24
+ category: ts.DiagnosticCategory.Error,
25
+ })
26
+ continue
27
+ }
28
+ const sourceFile = program.getSourceFile(`${abidePath}.ts`)
29
+ const mappings = shadows.get(abidePath)?.mappings
30
+ if (sourceFile === undefined || mappings === undefined) {
31
+ continue
32
+ }
33
+ const raw = [
34
+ ...program.getSyntacticDiagnostics(sourceFile),
35
+ ...program.getSemanticDiagnostics(sourceFile),
36
+ ]
37
+ for (const diagnostic of raw) {
38
+ if (diagnostic.start === undefined) {
39
+ continue
40
+ }
41
+ const located = remapShadowDiagnostic(
42
+ mappings,
43
+ diagnostic.start,
44
+ diagnostic.length ?? 0,
45
+ )
46
+ if (located === undefined) {
47
+ continue
48
+ }
49
+ diagnostics.push({
50
+ file: abidePath,
51
+ start: located.start,
52
+ length: located.length,
53
+ message: ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'),
54
+ category: diagnostic.category,
55
+ })
56
+ }
57
+ }
58
+ return diagnostics
59
+ }
@@ -0,0 +1,20 @@
1
+ import { analyzeComponent } from './analyzeComponent.ts'
2
+ import { generateBuild } from './generateBuild.ts'
3
+ import { hoistCells } from './hoistCells.ts'
4
+
5
+ /*
6
+ Compiles a single-file abide component into the body of a client build function.
7
+ Runs the shared front-end (`analyzeComponent`), generates the DOM build from the
8
+ template, and hoists static paths to cells. The returned body runs against a
9
+ `host` element with `doc`/`state`/`derived`/`effect` and the dom bindings in
10
+ scope and defines `model` itself. `compileModule` wraps it (and the SSR body) into
11
+ a real module; tests wrap it with `new Function`.
12
+ */
13
+ export function compileComponent(source: string, isLayout = false, scopeSeed?: string): string {
14
+ const { script, stateNames, derivedNames, nodes } = analyzeComponent(source, scopeSeed)
15
+ const build = generateBuild(nodes, 'host', stateNames, derivedNames, isLayout)
16
+ /* The scoped CSS is bundled into the entry stylesheet (see `abideUiPlugin`), not
17
+ injected at runtime; the build only needs the `data-a-…` scope attributes on
18
+ elements, which `generateBuild` reads from each node's annotated `scopes`. */
19
+ return `${script}\n${hoistCells(build, 'model')}`
20
+ }
@@ -0,0 +1,116 @@
1
+ import { ABIDE_PACKAGE_NAME } from '../../shared/ABIDE_PACKAGE_NAME.ts'
2
+ import { analyzeComponent } from './analyzeComponent.ts'
3
+ import { compileComponent } from './compileComponent.ts'
4
+ import { compileSSR } from './compileSSR.ts'
5
+ import { UI_RUNTIME_IMPORTS } from './UI_RUNTIME_IMPORTS.ts'
6
+
7
+ /*
8
+ Wraps a component into a complete ES module with two entry points:
9
+
10
+ - default `component(host, $props)` — mounts the client build, returns the
11
+ disposer (`import Counter from './Counter.abide'; const stop = Counter(host)`);
12
+ - `render($props)` — server-renders to `{ html, state, awaits }` for SSR.
13
+
14
+ `render` is also attached to the default export (`component.render`) so a parent
15
+ can server-render a child it imported by its default name. Both entry points share
16
+ the lowered script and template (via the shared front-end), so client and server
17
+ always agree. The `abide/ui/*` imports resolve through the package exports. This is
18
+ what the `.abide` bundler loader emits.
19
+ */
20
+ export function compileModule(
21
+ source: string,
22
+ options: { isLayout?: boolean; moduleId?: string; hot?: boolean } = {},
23
+ ): string {
24
+ const isLayout = options.isLayout ?? false
25
+ /* Component-authored imports (e.g. child components) hoisted to module scope. */
26
+ const analyzed = analyzeComponent(source)
27
+ const userImports = analyzed.imports
28
+ const body = indent(compileComponent(source, isLayout, options.moduleId))
29
+
30
+ /* Hot module (dev component HMR): the same client build, but its runtime comes
31
+ from the live bundle via `window.__abide` — so it shares the one reactive graph
32
+ and instance registry, not fresh copies — and on load it hands the new factory
33
+ to `hotReplace`, which disposes + re-runs every live instance in place. No SSR /
34
+ hydrate / export: it is imported only to replace, never mounted fresh. Supports
35
+ leaf components today; one importing children falls back to a reload (the dev
36
+ layer decides what to hot-swap). */
37
+ if (options.hot) {
38
+ const names = UI_RUNTIME_IMPORTS.map((entry) => entry.name).join(', ')
39
+ const id = JSON.stringify(options.moduleId)
40
+ return `const { ${names}, hotReplace } = window.__abide
41
+ ${userImports}
42
+ function component(host, $props) {
43
+ return mount(host, (host) => {
44
+ ${body}
45
+ })
46
+ }
47
+ component.__abideId = ${id}
48
+ if (!hotReplace(${id}, component)) location.reload()
49
+ `
50
+ }
51
+
52
+ const ssrBody = indent(compileSSR(source, isLayout, options.moduleId))
53
+ /* Per-component dead-import elimination: emit only the runtime names this module
54
+ actually references. A component that uses no `each`/`await`/`html` shouldn't
55
+ drag those modules into its chunk. The package isn't globally side-effect-free
56
+ (the dev/runtime entries register globals), so a bundler can't tree-shake the
57
+ unused imports for us — but the generated code is the one place that knows
58
+ exactly which names it emitted, so it filters here. A name absent from the body
59
+ is unreferenced; erring toward inclusion (a stray match in user script) only
60
+ keeps a harmless unused import, never drops a needed one. */
61
+ const moduleBody = `export default function component(host, $props) {
62
+ return mount(host, (host) => {
63
+ ${body}
64
+ })
65
+ }
66
+
67
+ /* Adopt the server-rendered DOM in place instead of rebuilding it. */
68
+ export function hydrateInto(host, $props) {
69
+ return hydrate(host, (host) => {
70
+ ${body}
71
+ })
72
+ }
73
+
74
+ export function render($props) {
75
+ ${ssrBody}
76
+ }
77
+
78
+ component.render = render
79
+ component.hydrate = hydrateInto
80
+ component.hydratable = ${analyzed.hydratable}
81
+ ${options.moduleId === undefined ? '' : `component.__abideId = ${JSON.stringify(options.moduleId)}\n`}`
82
+ /* Scope each name to the surface that genuinely references it. The SSR body
83
+ carries fixed boilerplate ($attr/$text helpers, `<!--abide:html-->` markers,
84
+ the `{ html, state, awaits }` return shape) whose substrings would falsely
85
+ match value/DOM imports — so client helpers are matched against the client
86
+ build, render-pass helpers against the SSR body, and the two wrapper calls
87
+ (mount/hydrate) are always present. */
88
+ const clientSurface = `${userImports}\n${body}`
89
+ const isReferenced = (entry: { name: string; specifier: string }): boolean => {
90
+ if (entry.name === 'mount' || entry.name === 'hydrate') {
91
+ return true
92
+ }
93
+ /* Render-pass helpers are emitted by both back-ends (e.g. client and server
94
+ await/try blocks both call nextBlockId); their names are distinctive enough
95
+ that scanning both surfaces adds no false match. */
96
+ const surface = entry.specifier.startsWith('ui/runtime/')
97
+ ? `${clientSurface}\n${ssrBody}`
98
+ : clientSurface
99
+ return new RegExp(`\\b${entry.name}\\b`).test(surface)
100
+ }
101
+ const importBlock = UI_RUNTIME_IMPORTS.filter(isReferenced)
102
+ .map((entry) => `import { ${entry.name} } from '${ABIDE_PACKAGE_NAME}/${entry.specifier}'`)
103
+ .join('\n')
104
+ return `${importBlock}
105
+ ${userImports}
106
+
107
+ ${moduleBody}`
108
+ }
109
+
110
+ /* Indents a body block for embedding inside a wrapper function. */
111
+ function indent(body: string): string {
112
+ return body
113
+ .split('\n')
114
+ .map((line) => (line === '' ? line : ` ${line}`))
115
+ .join('\n')
116
+ }