@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,179 @@
1
+ import { canonicalJson } from './canonicalJson.ts'
2
+ import { createLivenessWatch } from './createLivenessWatch.ts'
3
+ import { createSubscriber } from './createSubscriber.ts'
4
+ import { HEALTH_PATH } from './HEALTH_PATH.ts'
5
+ import { healthReadSlot } from './healthReadSlot.ts'
6
+ import { healthSeedSlot } from './healthSeedSlot.ts'
7
+ import { isAbideHealthPayload } from './isAbideHealthPayload.ts'
8
+ import { withBase } from './withBase.ts'
9
+
10
+ /*
11
+ Augmented by the generated `src/.abide/health.d.ts` with
12
+ `{ fields: <the app health() hook's resolved return> }`, so a project's
13
+ `health()` reads type against its own hook. Unaugmented (no app.ts, or no
14
+ hook), AppHealth resolves to no fields.
15
+ */
16
+ // @readme observability
17
+ // biome-ignore lint/suspicious/noEmptyInterface: augmented by the generated health.d.ts
18
+ export interface AppHealthMap {}
19
+ export type AppHealth = AppHealthMap extends { fields: infer Fields }
20
+ ? Fields extends object
21
+ ? Fields
22
+ : Record<never, never>
23
+ : Record<never, never>
24
+
25
+ /*
26
+ What health() reports: `reachable` is the framework's transport verdict; the
27
+ rest is the last successful payload, whole — the framework identity (`abide`
28
+ carries the framework version, `name`/`version` the app's) plus the app
29
+ health() hook's fields, exactly as /__abide/health serves them. Fields
30
+ persist while unreachable (last-known state beats vanishing fields: "was
31
+ authenticated, currently unreachable" and "reachable, not authenticated"
32
+ need different UI) and are Partial because nothing has arrived before the
33
+ first poll — unless the SSR seed shipped them with the document.
34
+ */
35
+ export type HealthState = {
36
+ reachable: boolean
37
+ abide?: string
38
+ name?: string
39
+ version?: string
40
+ } & Partial<AppHealth>
41
+
42
+ const PROBE_INTERVAL_MS = 10_000
43
+ const PROBE_TIMEOUT_MS = 5_000
44
+
45
+ /* Last successful payload's app fields (framework identity keys stripped). */
46
+ let fields: Record<string, unknown> = {}
47
+ /* The watch's verdict; composed with navigator.onLine at read time. */
48
+ let backendAlive = true
49
+ let notify: (() => void) | undefined
50
+
51
+ /*
52
+ One probe: the same standard of proof as the launcher's probeAbideServer —
53
+ a `abide` key in the body, never response.ok alone, because a captive
54
+ portal answers any GET with a 200. Captures the whole payload (identity
55
+ keys included) as a side effect; a changed payload (e.g. authenticated
56
+ flipping) notifies readers even though reachability didn't transition.
57
+ */
58
+ async function probeHealth(url: string): Promise<boolean> {
59
+ try {
60
+ const response = await fetch(url, {
61
+ headers: { accept: 'application/json' },
62
+ cache: 'no-store',
63
+ signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),
64
+ })
65
+ if (!response.ok) {
66
+ return false
67
+ }
68
+ const body = (await response.json()) as Record<string, unknown>
69
+ if (!isAbideHealthPayload(body)) {
70
+ return false
71
+ }
72
+ applyFields(body)
73
+ return true
74
+ } catch {
75
+ return false
76
+ }
77
+ }
78
+
79
+ /* Swaps in a changed payload and notifies readers; identical payloads stay silent. */
80
+ function applyFields(payload: Record<string, unknown>): void {
81
+ if (canonicalJson(payload) !== canonicalJson(fields)) {
82
+ fields = payload
83
+ notify?.()
84
+ }
85
+ }
86
+
87
+ const watch = createLivenessWatch({
88
+ probe: probeHealth,
89
+ onChange(alive) {
90
+ backendAlive = alive
91
+ notify?.()
92
+ },
93
+ intervalMs: PROBE_INTERVAL_MS,
94
+ })
95
+
96
+ /*
97
+ Reader-driven lifecycle (the createSubscriber rule): the first tracking
98
+ reader starts the poll, the last one tears it down — an app that never
99
+ reads health() never sends a byte. Mirrors the socket channel's visibility
100
+ philosophy: hidden tabs hold no poll (nobody is looking at the banner),
101
+ and the visible transition probes immediately so the value is honest the
102
+ moment eyes return. The online event also probes immediately — recovery
103
+ confirmation shouldn't wait out the interval; offline needs no probe
104
+ because read-time composition with navigator.onLine reports it instantly.
105
+ */
106
+ const subscribeHealth =
107
+ typeof window === 'undefined'
108
+ ? undefined
109
+ : createSubscriber((update) => {
110
+ notify = update
111
+ const onVisibility = () => {
112
+ if (document.visibilityState === 'hidden') {
113
+ watch.stop()
114
+ return
115
+ }
116
+ watch.watch(withBase(HEALTH_PATH))
117
+ watch.probeNow()
118
+ }
119
+ const onOnline = () => {
120
+ watch.probeNow()
121
+ update()
122
+ }
123
+ const onOffline = () => update()
124
+ document.addEventListener('visibilitychange', onVisibility)
125
+ window.addEventListener('online', onOnline)
126
+ window.addEventListener('offline', onOffline)
127
+ watch.watch(withBase(HEALTH_PATH))
128
+ /*
129
+ SSR seed: a page that read health() during its server render
130
+ shipped the payload in __SSR__ (startClient parks it on the
131
+ slot). The document's arrival just proved the server
132
+ reachable, so the immediate first probe is skipped — the
133
+ watch's interval owns the next one — and the fields apply a
134
+ microtask after connect: the hydration read still matches the
135
+ server-rendered DOM (the server render carried no fields),
136
+ while the update lands before first paint. Consumed once;
137
+ later reconnects probe immediately as usual.
138
+ */
139
+ const seed = healthSeedSlot.payload
140
+ healthSeedSlot.payload = undefined
141
+ if (seed) {
142
+ queueMicrotask(() => applyFields(seed))
143
+ } else {
144
+ watch.probeNow()
145
+ }
146
+ return () => {
147
+ document.removeEventListener('visibilitychange', onVisibility)
148
+ window.removeEventListener('online', onOnline)
149
+ window.removeEventListener('offline', onOffline)
150
+ watch.stop()
151
+ notify = undefined
152
+ }
153
+ })
154
+
155
+ /*
156
+ Reactive backend-health read: `reachable` plus whatever the app's
157
+ health(request) hook reports, polled from /__abide/health only while a
158
+ tracking scope ($derived/$effect) is reading it. Like tail and cache —
159
+ and unlike the pending()/refreshing() probes — reading this opens a
160
+ resource (the poll). Constant `{ reachable: true }` on the server: the
161
+ server is its own backend. navigator.onLine composes in at read time, so
162
+ a lost network reports instantly without waiting for a probe to time out.
163
+ */
164
+ export function health(): HealthState {
165
+ /* window, not navigator: Bun defines a partial navigator with no onLine. */
166
+ if (typeof window === 'undefined') {
167
+ /*
168
+ Mark the request (when the server runtime installed a marker) so the
169
+ renderer stamps the health payload into __SSR__ — the client's seed.
170
+ The render itself stays fields-less: the hook may be async and this
171
+ read is sync, so the payload is built after the render returns.
172
+ */
173
+ healthReadSlot.mark?.()
174
+ return { reachable: true } as HealthState
175
+ }
176
+ subscribeHealth?.()
177
+ /* reachable last: it is the framework's verdict, never a hook field's to shadow. */
178
+ return { ...fields, reachable: backendAlive && navigator.onLine } as HealthState
179
+ }
@@ -0,0 +1,11 @@
1
+ /*
2
+ Server-side registration point for health()'s SSR read mark. createServer
3
+ installs a marker that flags the current request store; the renderer reads
4
+ the flag to stamp the health payload into __SSR__ only for pages that
5
+ actually read health() during their render — the same reader-driven rule as
6
+ the client poll. Browser bundles never install one, so the shared module's
7
+ call no-ops there. Mirrors requestScopeSlot.
8
+ */
9
+ export const healthReadSlot: { mark: (() => void) | undefined } = {
10
+ mark: undefined,
11
+ }
@@ -0,0 +1,12 @@
1
+ /*
2
+ One-shot handoff of the SSR-stamped health payload (__SSR__.health) from
3
+ startClient to the shared health module. startClient writes it before
4
+ hydrate; health()'s first subscriber consumes it, applying the fields
5
+ without the immediate first probe — the document's arrival just proved the
6
+ server reachable, so the first poll waits a full interval. A slot rather
7
+ than a second export on health.ts keeps the seeding one-way and the module
8
+ single-callable. Mirrors healthReadSlot, its server half.
9
+ */
10
+ export const healthSeedSlot: { payload: Record<string, unknown> | undefined } = {
11
+ payload: undefined,
12
+ }
@@ -0,0 +1,38 @@
1
+ const RAW_HTML = Symbol.for('abide.rawHtml')
2
+
3
+ /* A value marked as trusted raw markup — a `{expr}` interpolation inserts it
4
+ verbatim (not escaped) on both sides. The brand is a registered Symbol, so it
5
+ survives across module/bundle copies. */
6
+ export type RawHtml = { readonly [RAW_HTML]: string }
7
+
8
+ /*
9
+ Marks a string as trusted raw HTML so a `{expr}` interpolation inserts its nodes
10
+ instead of escaped text — the abide idiom for raw markup (no `{@html}` mustache).
11
+ Works two ways:
12
+
13
+ html(trustedString) // plain call — insert the string verbatim
14
+ html`<b>${name}</b>` // tagged — concatenate parts verbatim
15
+
16
+ Calling `html` is the explicit opt-in to raw insertion; plain `{value}` always
17
+ escapes. The tag does NOT auto-escape interpolations (it's raw by intent), so only
18
+ build markup from values you trust, or escape them yourself.
19
+ */
20
+ // @readme plumbing
21
+ export function html(strings: TemplateStringsArray | string, ...values: unknown[]): RawHtml {
22
+ if (typeof strings === 'string') {
23
+ return { [RAW_HTML]: strings }
24
+ }
25
+ let markup = strings[0] ?? ''
26
+ for (let index = 0; index < values.length; index += 1) {
27
+ markup += String(values[index]) + (strings[index + 1] ?? '')
28
+ }
29
+ return { [RAW_HTML]: markup }
30
+ }
31
+
32
+ /* The raw markup of a `html`-branded value, or undefined for anything else
33
+ (so text bindings can fast-path plain values and only branded ones go raw). */
34
+ export function rawHtmlString(value: unknown): string | undefined {
35
+ return value !== null && typeof value === 'object' && RAW_HTML in value
36
+ ? (value as RawHtml)[RAW_HTML]
37
+ : undefined
38
+ }
@@ -0,0 +1,13 @@
1
+ import { ABIDE_PACKAGE_NAME } from './ABIDE_PACKAGE_NAME.ts'
2
+
3
+ /*
4
+ The names a user may import a abide server helper under: the project's chosen
5
+ alias plus the canonical package name. The resolver strips the dead import
6
+ under both so it can't side-effect-load the server stub into the client
7
+ bundle. When the alias already is the canonical name, there's only one.
8
+ */
9
+ export function importNamesToStrip(importName: string): string[] {
10
+ return importName === ABIDE_PACKAGE_NAME
11
+ ? [ABIDE_PACKAGE_NAME]
12
+ : [importName, ABIDE_PACKAGE_NAME]
13
+ }
@@ -0,0 +1,11 @@
1
+ import type { CacheInvalidation } from './types/CacheInvalidation.ts'
2
+
3
+ /*
4
+ Constructs the cache store's 'invalidate' event from the keys an
5
+ invalidation touched. The single definition of the event name + detail
6
+ shape, so the two dispatch sites (cache.invalidate and the streamed-
7
+ resolution placeholder settle) can't drift from the cache store's listener.
8
+ */
9
+ export function invalidateEvent(keys: Iterable<string>): CustomEvent<CacheInvalidation> {
10
+ return new CustomEvent('invalidate', { detail: new Set(keys) })
11
+ }
@@ -0,0 +1,40 @@
1
+ import { abideLog } from './abideLog.ts'
2
+
3
+ /*
4
+ Same-selector invalidations within one macrotask before the warning fires. A
5
+ reactive loop spins on microtasks (lifecycle mark → effect flush →
6
+ invalidate), starving macrotasks — so the reset timer below never runs while
7
+ one is live, and legitimate repeats (socket frames, user events) arriving
8
+ across macrotasks clear the count instead.
9
+ */
10
+ const LOOP_THRESHOLD = 25
11
+
12
+ const invalidationCounts = new Map<string, number>()
13
+ let resetTimer: ReturnType<typeof setTimeout> | undefined
14
+
15
+ /*
16
+ Cycle tripwire for cache.invalidate. A synchronous re-run counter (an
17
+ effect-update-depth limit) counts synchronous re-runs, but the probes' lifecycle marks defer a microtask
18
+ (createLifecycleChannel), so a self-feeding effect — one that reads a probe or
19
+ cached value and invalidates a selector that re-wakes its own scope — spins
20
+ forever without tripping it, pinning the CPU. Many invalidations of one
21
+ selector inside a single macrotask is that signature. Warns once per episode
22
+ (the starved reset timer can't fire mid-loop, so the count only crosses the
23
+ threshold once); reporting only — invalidation proceeds.
24
+ */
25
+ export function invalidateTripwire(selectorLabel: string): void {
26
+ const count = (invalidationCounts.get(selectorLabel) ?? 0) + 1
27
+ invalidationCounts.set(selectorLabel, count)
28
+ if (resetTimer === undefined) {
29
+ resetTimer = setTimeout(() => {
30
+ resetTimer = undefined
31
+ invalidationCounts.clear()
32
+ }, 0)
33
+ resetTimer.unref?.()
34
+ }
35
+ if (count === LOOP_THRESHOLD) {
36
+ abideLog.warn(
37
+ `cache.invalidate(${selectorLabel}) fired ${LOOP_THRESHOLD}× within one task — likely a reactive loop: an effect that reads pending()/refreshing() or a cached value and invalidates a selector waking its own scope re-triggers itself across microtasks, invisible to synchronous loop detection. Find the effect invalidating ${selectorLabel}.`,
38
+ )
39
+ }
40
+ }
@@ -0,0 +1,11 @@
1
+ /*
2
+ Whether a health/identity response body identifies a abide server. The
3
+ `abide` field carries the framework version (a non-empty string) on current
4
+ servers and `true` on older ones — both accepted, so a newer prober still
5
+ recognises an older server. The body check (never response.ok alone) is the
6
+ captive-portal defense shared by every prober: a portal answers any GET with
7
+ a 200, but it doesn't answer with this.
8
+ */
9
+ export function isAbideHealthPayload(body: { abide?: unknown }): boolean {
10
+ return body.abide === true || (typeof body.abide === 'string' && body.abide !== '')
11
+ }
@@ -0,0 +1,15 @@
1
+ import type { CompileTarget } from './types/CompileTarget.ts'
2
+
3
+ /* The canonical cross-compile targets, as a runtime set for validation. */
4
+ const COMPILE_TARGETS: readonly CompileTarget[] = [
5
+ 'bun-darwin-arm64',
6
+ 'bun-darwin-x64',
7
+ 'bun-linux-arm64',
8
+ 'bun-linux-x64',
9
+ 'bun-windows-x64',
10
+ ]
11
+
12
+ /* Narrows an arbitrary string to a known CompileTarget. */
13
+ export function isCompileTarget(value: string): value is CompileTarget {
14
+ return (COMPILE_TARGETS as readonly string[]).includes(value)
15
+ }
@@ -0,0 +1,26 @@
1
+ import { isDebugNegated } from './isDebugNegated.ts'
2
+ import { matchesDebugPattern } from './matchesDebugPattern.ts'
3
+ import { parseDebugPatterns } from './parseDebugPatterns.ts'
4
+
5
+ /*
6
+ Whether a DEBUG-gated channel is enabled, npm-debug conventions:
7
+ DEBUG="abide" → enables "abide"
8
+ DEBUG="abide:*" → enables "abide" and "abide:anything"
9
+ DEBUG="*" → enables everything
10
+ DEBUG="a,abide" → comma-separated list
11
+ DEBUG="abide:*,-abide:cache" → negation: exclusions win over inclusions
12
+ Always-on channels don't consult this — they check isDebugNegated only.
13
+ The default is guarded: this runs in the browser bundle, where `process`
14
+ doesn't exist.
15
+ */
16
+ export function isDebugEnabled(
17
+ name: string,
18
+ env: string | undefined = typeof process === 'undefined' ? undefined : process.env.DEBUG,
19
+ ): boolean {
20
+ if (isDebugNegated(name, env)) {
21
+ return false
22
+ }
23
+ return parseDebugPatterns(env)
24
+ .filter((pattern) => !pattern.startsWith('-'))
25
+ .some((pattern) => matchesDebugPattern(name, pattern))
26
+ }
@@ -0,0 +1,19 @@
1
+ import { matchesDebugPattern } from './matchesDebugPattern.ts'
2
+ import { parseDebugPatterns } from './parseDebugPatterns.ts'
3
+
4
+ /*
5
+ Whether a `-` pattern in DEBUG explicitly shuts a channel off — the off
6
+ switch for the always-on channels (the app's name, 'abide'): DEBUG="-abide"
7
+ silences framework lines including the per-request closing records,
8
+ DEBUG="-myapp" the app's own. Silencing a channel silences all its levels —
9
+ levels never gate, in either direction. The default is guarded: this runs in
10
+ the browser bundle, where `process` doesn't exist.
11
+ */
12
+ export function isDebugNegated(
13
+ name: string,
14
+ env: string | undefined = typeof process === 'undefined' ? undefined : process.env.DEBUG,
15
+ ): boolean {
16
+ return parseDebugPatterns(env)
17
+ .filter((pattern) => pattern.startsWith('-'))
18
+ .some((pattern) => matchesDebugPattern(name, pattern.slice(1)))
19
+ }
@@ -0,0 +1,16 @@
1
+ /*
2
+ True when an error from a dynamic `import(...)` is a module-resolution
3
+ failure (the package isn't installed) rather than an error thrown while
4
+ the module's own code ran. Lets optional-peer loads swallow "not installed"
5
+ while letting a genuine load-time failure surface. Bun surfaces the former
6
+ as a ResolveMessage / ERR_MODULE_NOT_FOUND; the message check is the
7
+ cross-runtime fallback.
8
+ */
9
+ export function isModuleNotFound(error: unknown): boolean {
10
+ const code = (error as { code?: string })?.code
11
+ if (code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') {
12
+ return true
13
+ }
14
+ const message = error instanceof Error ? error.message : String(error)
15
+ return /cannot find (module|package)|failed to resolve/i.test(message)
16
+ }
@@ -0,0 +1,14 @@
1
+ import type { HttpVerb } from './types/HttpVerb.ts'
2
+
3
+ /*
4
+ Read-only (safe) HTTP methods — they don't mutate server state. Abide
5
+ uses this to decide which verbs auto-expose to MCP: reads flip MCP on
6
+ when a schema is present, mutations require an explicit `clients.mcp`
7
+ opt-in so a model can't delete/overwrite data just because the handler
8
+ carries a schema. Also feeds the MCP tool `readOnlyHint` annotation.
9
+ */
10
+ const READ_ONLY_METHODS = new Set<HttpVerb>(['GET', 'HEAD'])
11
+
12
+ export function isReadOnlyMethod(method: HttpVerb): boolean {
13
+ return READ_ONLY_METHODS.has(method)
14
+ }
@@ -0,0 +1,7 @@
1
+ import { REPLAYABLE_METHODS } from './REPLAYABLE_METHODS.ts'
2
+ import type { ReplayableMethod } from './types/ReplayableMethod.ts'
3
+
4
+ /* Narrowing gate over REPLAYABLE_METHODS so callers get the typed method without a cast. */
5
+ export function isReplayableMethod(method: string): method is ReplayableMethod {
6
+ return REPLAYABLE_METHODS.has(method)
7
+ }
@@ -0,0 +1,11 @@
1
+ import { STREAMING_CONTENT_TYPES } from './STREAMING_CONTENT_TYPES.ts'
2
+
3
+ /*
4
+ Whether a Response carries a streaming body (SSE / JSONL / NDJSON) by its
5
+ Content-Type, so callers drain it frame-by-frame instead of buffering.
6
+ Shared by the CLI print path and the MCP tool dispatcher.
7
+ */
8
+ export function isStreamingResponse(response: Response): boolean {
9
+ const contentType = (response.headers.get('content-type') ?? '').toLowerCase()
10
+ return STREAMING_CONTENT_TYPES.some((type) => contentType.startsWith(type))
11
+ }
@@ -0,0 +1,15 @@
1
+ import type { Subscribable } from './types/Subscribable.ts'
2
+
3
+ /*
4
+ A Subscribable is a named AsyncIterable — distinguishes a stream argument from
5
+ the other probe selector shapes (callables and `{ scope }` objects, neither of
6
+ which carries Symbol.asyncIterator).
7
+ */
8
+ export function isSubscribable(value: unknown): value is Subscribable<unknown> {
9
+ return (
10
+ typeof value === 'object' &&
11
+ value !== null &&
12
+ Symbol.asyncIterator in value &&
13
+ 'name' in value
14
+ )
15
+ }
@@ -0,0 +1,29 @@
1
+ import type { PromptArgument } from './types/PromptArgument.ts'
2
+
3
+ /*
4
+ Turns a markdown prompt's frontmatter `arguments` list into the JSON
5
+ Schema the MCP dispatcher advertises in `prompts/list` (top-level string
6
+ properties + a `required` array). Prompt arguments are always strings —
7
+ MCP fills them from model output — so every property is `{ type: 'string' }`.
8
+ Returns undefined for an argument-less prompt so the generated module
9
+ omits the field entirely.
10
+ */
11
+ export function jsonSchemaForPromptArguments(
12
+ args: PromptArgument[],
13
+ ): Record<string, unknown> | undefined {
14
+ if (args.length === 0) {
15
+ return undefined
16
+ }
17
+ const properties = Object.fromEntries(
18
+ args.map((arg) => [
19
+ arg.name,
20
+ { type: 'string', ...(arg.description ? { description: arg.description } : {}) },
21
+ ]),
22
+ )
23
+ const required = args.filter((arg) => arg.required).map((arg) => arg.name)
24
+ return {
25
+ type: 'object',
26
+ properties,
27
+ ...(required.length > 0 ? { required } : {}),
28
+ }
29
+ }
@@ -0,0 +1,39 @@
1
+ import type { StandardSchemaV1 } from './types/StandardSchemaV1.ts'
2
+
3
+ const OPAQUE = { type: 'object', additionalProperties: true } as const
4
+
5
+ /*
6
+ Resolves a JSON Schema for an MCP tool's `inputSchema`, an OpenAPI body, a CLI
7
+ flag set, or the bundle setup form. Probes the schema's own projection:
8
+
9
+ 1. `schema.toJsonSchema()` (Arktype 2+)
10
+ 2. `schema.toJSONSchema()` (Zod 4, Effect Schema, or a withJsonSchema wrap)
11
+ 3. Opaque object — the surface still works, the consumer just gets no shape hint
12
+
13
+ A projection that exists but throws (e.g. Zod 4 can't render `z.custom()`)
14
+ degrades to the same opaque fallback rather than escaping — one un-serializable
15
+ schema must not take down the whole list its caller is building (an MCP
16
+ tools/list, an OpenAPI doc). Wrap with withJsonSchema to supply a shape.
17
+
18
+ Schemas whose library exposes neither carry one via withJsonSchema. Returns a
19
+ fresh object each call; callers can mutate (e.g. add a description) without
20
+ aliasing the schema's own.
21
+ */
22
+ export function jsonSchemaForSchema(schema: StandardSchemaV1 | undefined): Record<string, unknown> {
23
+ if (!schema) {
24
+ return { ...OPAQUE }
25
+ }
26
+ const candidate = schema as unknown as {
27
+ toJsonSchema?: () => Record<string, unknown>
28
+ toJSONSchema?: () => Record<string, unknown>
29
+ }
30
+ const project = candidate.toJsonSchema ?? candidate.toJSONSchema
31
+ if (typeof project !== 'function') {
32
+ return { ...OPAQUE }
33
+ }
34
+ try {
35
+ return { ...project.call(candidate) }
36
+ } catch {
37
+ return { ...OPAQUE }
38
+ }
39
+ }
@@ -0,0 +1,24 @@
1
+ /*
2
+ The in-band error sentinel for a JSONL/NDJSON stream: when a handler's
3
+ generator throws, `jsonl()` emits a final `{"$error":"<message>"}` line,
4
+ and `streamResponse` re-throws it on the consumer side. Encoder and decoder
5
+ live together here so the sentinel field has one definition and can't drift
6
+ between the two ends of the wire.
7
+ */
8
+ export const jsonlErrorFrame = {
9
+ // Error line for a thrown message, including the trailing newline.
10
+ encode(message: string): string {
11
+ return `${JSON.stringify({ $error: message })}\n`
12
+ },
13
+ // The message carried by a parsed line, or undefined when it isn't the error sentinel.
14
+ decode(parsed: unknown): string | undefined {
15
+ if (
16
+ parsed &&
17
+ typeof parsed === 'object' &&
18
+ typeof (parsed as { $error?: unknown }).$error === 'string'
19
+ ) {
20
+ return (parsed as { $error: string }).$error
21
+ }
22
+ return undefined
23
+ },
24
+ }
@@ -0,0 +1,29 @@
1
+ import { canonicalJson } from './canonicalJson.ts'
2
+ import { carriesBodyArgs } from './carriesBodyArgs.ts'
3
+ import { queryStringFromArgs } from './queryStringFromArgs.ts'
4
+ import type { HttpVerb } from './types/HttpVerb.ts'
5
+
6
+ /*
7
+ Derives a cache key from a verb-defined remote function and its args. The
8
+ prefix is `${method} ${url}` where `url` is the route template. GET/DELETE/HEAD
9
+ serialise args onto the URL as `?key=value` (sorted, via queryStringFromArgs —
10
+ the same encoder buildRpcRequest builds its query with, so the key and the
11
+ synthesized Request can't disagree); POST/PUT/PATCH join args after a space as
12
+ canonical JSON. The verb split mirrors buildRpcRequest exactly.
13
+ */
14
+ export function keyForRemoteCall(method: HttpVerb, url: string, args: unknown): string {
15
+ const prefix = `${method} ${url}`
16
+ if (!carriesBodyArgs(method)) {
17
+ if (args && typeof args === 'object' && !Array.isArray(args)) {
18
+ const search = queryStringFromArgs(args as Record<string, unknown>, true)
19
+ if (search.length > 0) {
20
+ return `${prefix}?${search}`
21
+ }
22
+ }
23
+ return prefix
24
+ }
25
+ if (args === undefined) {
26
+ return prefix
27
+ }
28
+ return `${prefix} ${canonicalJson(args)}`
29
+ }
@@ -0,0 +1,9 @@
1
+ /*
2
+ The selector-prefix grammar shared by selectorMatcher and the cache store's
3
+ scoped lifecycle marks: a prefix owns its exact key plus arg-bearing
4
+ extensions — `?` (GET/DELETE query args) or ` ` (canonical-json body /
5
+ producer args) — so `GET /a` never matches `GET /ab`.
6
+ */
7
+ export function keyMatchesPrefix(key: string, prefix: string): boolean {
8
+ return key === prefix || key.startsWith(`${prefix}?`) || key.startsWith(`${prefix} `)
9
+ }
@@ -0,0 +1,7 @@
1
+ import { join } from 'node:path'
2
+ import { appDataDir } from './appDataDir.ts'
3
+
4
+ // Path to the per-program last-connection record, beside the data-dir `.env`.
5
+ export function lastConnectionPath(programName: string): string {
6
+ return join(appDataDir(programName), 'last-connection.json')
7
+ }
@@ -0,0 +1,22 @@
1
+ /*
2
+ The ordered layout chain that wraps a page route: every directory prefix that
3
+ holds a `layout.abide` and is an ancestor of (or equal to) the route, outermost
4
+ first. `layoutKeys` are directory URLs (a layout's URL is its folder path, via
5
+ pageUrlForFile). `/` matches every route; a deeper prefix matches when the route
6
+ equals it or descends into it. Dynamic segments compare literally (`/media/[id]`)
7
+ since both keys and routes carry the same `[name]` form. Pure — both the SSR
8
+ renderer and the client router resolve a page's chain from the same function so
9
+ they nest identically.
10
+ */
11
+ export function layoutChainForRoute(routeUrl: string, layoutKeys: Iterable<string>): string[] {
12
+ const route = routeUrl === '/' ? '' : routeUrl.replace(/^\//, '')
13
+ const applies: string[] = []
14
+ for (const key of layoutKeys) {
15
+ const dir = key === '/' ? '' : key.replace(/^\//, '')
16
+ if (dir === '' || route === dir || route.startsWith(`${dir}/`)) {
17
+ applies.push(key)
18
+ }
19
+ }
20
+ /* Outermost first: a shorter prefix is an ancestor of a longer one. */
21
+ return applies.sort((first, second) => first.length - second.length)
22
+ }
@@ -0,0 +1,17 @@
1
+ import { readEnvFile } from './readEnvFile.ts'
2
+
3
+ /*
4
+ Reads a `.env` at `path` and merges each declared var into `process.env`
5
+ only when not already set. Fill-when-unset is the precedence rule the whole
6
+ env stack relies on: layers loaded earlier (shell/ambient, Bun's CWD `.env`)
7
+ win, and later callers back-fill only what's still missing. So a value's
8
+ source is invisible to the app — it reads one flat `process.env` (Bun.env is
9
+ the same object). Missing file is a no-op.
10
+ */
11
+ export async function loadEnvFile(path: string): Promise<void> {
12
+ for (const [key, value] of Object.entries(await readEnvFile(path))) {
13
+ if (process.env[key] === undefined) {
14
+ process.env[key] = value
15
+ }
16
+ }
17
+ }