@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,181 @@
1
+ import { appNameSlot } from '../../shared/appNameSlot.ts'
2
+ import { SSR_CACHE_CONTROL } from '../../shared/CACHE_CONTROL_VALUES.ts'
3
+ import { formatTraceparent } from '../../shared/formatTraceparent.ts'
4
+ import { layoutChainForRoute } from '../../shared/layoutChainForRoute.ts'
5
+ import { renderChain } from '../../ui/renderChain.ts'
6
+ import { renderToStream } from '../../ui/renderToStream.ts'
7
+ import type { UiComponent } from '../../ui/runtime/types/UiComponent.ts'
8
+ import { pageUrlFromStore } from './pageUrlFromStore.ts'
9
+ import { SSR_SWAP_SCRIPT } from './SSR_SWAP_SCRIPT.ts'
10
+ import { safeJsonForScript } from './safeJsonForScript.ts'
11
+ import { serializeCacheSnapshot } from './serializeCacheSnapshot.ts'
12
+ import type { RequestStore } from './types/RequestStore.ts'
13
+
14
+ /* A abide-ui page module: its default export is the compiled component. */
15
+ type LoadPage = () => Promise<{ default: UiComponent }>
16
+
17
+ const SSR_MARKER = /<!--ssr:(head|body|state)-->/g
18
+ const BODY_MARKER = '<!--ssr:body-->'
19
+
20
+ function wantsJson(request: Request): boolean {
21
+ return (request.headers.get('accept') ?? '').includes('application/json')
22
+ }
23
+
24
+ /*
25
+ The abide-ui SSR document renderer. A matched route + params in, a finished HTML
26
+ Response out.
27
+
28
+ A page with no `await` block renders synchronously and ships buffered. A page with
29
+ await blocks STREAMS: the pending shell flushes first, then each resolved fragment
30
+ (`<abide-resolve data-resume>`) as its promise settles, swapped into its boundary
31
+ by the inline SSR_SWAP_SCRIPT — which also registers the value into the resume
32
+ manifest so client hydration adopts it without re-fetching (see abide/ui/awaitBlock).
33
+
34
+ `__SSR__` carries the route/params, mount base, trace, app name, client timeout,
35
+ and the settled cache snapshot (the client seeds its tab store from it). A route's
36
+ `layout.abide` files wrap the page outermost-first (every ancestor directory's
37
+ layout applies); the chain server-renders as one document via `renderChain`, the
38
+ page folded into each layout's `<slot/>` outlet. The client router re-resolves the
39
+ same chain and keeps shared layouts mounted across navigation.
40
+ */
41
+ export function createUiPageRenderer({
42
+ shell,
43
+ base,
44
+ clientTimeout,
45
+ pages,
46
+ layouts,
47
+ healthPayload,
48
+ }: {
49
+ shell: string
50
+ base: string
51
+ clientTimeout: number | undefined
52
+ pages: Record<string, LoadPage>
53
+ layouts: Record<string, LoadPage>
54
+ healthPayload: (request: Request) => Promise<Record<string, unknown>>
55
+ }): {
56
+ renderPage: (
57
+ routeUrl: string,
58
+ params: Record<string, string>,
59
+ store: RequestStore,
60
+ ) => Promise<Response>
61
+ renderError: (
62
+ status: number,
63
+ message: string,
64
+ store: RequestStore,
65
+ stack?: string,
66
+ ) => Promise<Response | undefined>
67
+ } {
68
+ /* Build the __SSR__ <script> the client (startClient) reads on boot. */
69
+ async function stateTag(
70
+ routeUrl: string,
71
+ params: Record<string, string>,
72
+ store: RequestStore,
73
+ ): Promise<string> {
74
+ const { inline } = await serializeCacheSnapshot(store.cache)
75
+ const health = store.healthRead ? await healthPayload(store.req) : undefined
76
+ const payload = safeJsonForScript({
77
+ route: routeUrl,
78
+ params,
79
+ cache: inline,
80
+ base: base || undefined,
81
+ trace: formatTraceparent(store.trace),
82
+ app: appNameSlot.name,
83
+ health,
84
+ clientTimeout,
85
+ })
86
+ return `<script>window.__SSR__ = ${payload};</script>`
87
+ }
88
+
89
+ async function renderPage(
90
+ routeUrl: string,
91
+ params: Record<string, string>,
92
+ store: RequestStore,
93
+ ): Promise<Response> {
94
+ store.route = routeUrl
95
+ store.params = params
96
+ /* Touch pageUrl so the page proxy resolves the browser-space URL during SSR. */
97
+ pageUrlFromStore(store)
98
+ if (wantsJson(store.req)) {
99
+ return Response.json(
100
+ { route: routeUrl, params },
101
+ { headers: { Vary: 'Accept', 'Cache-Control': SSR_CACHE_CONTROL } },
102
+ )
103
+ }
104
+ const loadPage = pages[routeUrl]
105
+ if (loadPage === undefined) {
106
+ throw new Error(`[abide] unknown route: ${routeUrl}`)
107
+ }
108
+ /* Outermost layout → … → page: load every applicable layout chunk plus the
109
+ page, then render the chain as one document (shared block-id pass). */
110
+ const chainKeys = layoutChainForRoute(routeUrl, Object.keys(layouts))
111
+ const views = await Promise.all([
112
+ ...chainKeys.map((key) => layouts[key]?.().then((module) => module.default)),
113
+ loadPage().then((module) => module.default),
114
+ ])
115
+ const ssr = renderChain(
116
+ views.filter((view): view is UiComponent => view !== undefined),
117
+ params,
118
+ )
119
+
120
+ /* No await blocks → render synchronously, ship buffered. */
121
+ if (ssr.awaits.length === 0) {
122
+ const html = shell.replace(SSR_MARKER, (_match, key: string) =>
123
+ key === 'body' ? ssr.html : key === 'state' ? '' : '',
124
+ )
125
+ const withState = html.replace(
126
+ '</body>',
127
+ `${await stateTag(routeUrl, params, store)}</body>`,
128
+ )
129
+ return new Response(withState, {
130
+ headers: {
131
+ 'Content-Type': 'text/html; charset=utf-8',
132
+ Vary: 'Accept',
133
+ 'Cache-Control': SSR_CACHE_CONTROL,
134
+ },
135
+ })
136
+ }
137
+
138
+ /* Await blocks → stream the shell, then resolved fragments as they settle.
139
+ Fill head/state but LEAVE the body marker intact — it's the split point for
140
+ streaming the page body into `#app`; consuming it here would append the body
141
+ after the whole shell (outside `#app`), breaking hydration. */
142
+ const head = `<script>${SSR_SWAP_SCRIPT}</script>${await stateTag(routeUrl, params, store)}`
143
+ const filled = shell.replace(/<!--ssr:(head|state)-->/g, (_match, key: string) =>
144
+ key === 'head' ? head : '',
145
+ )
146
+ const [before, after] = filled.split(BODY_MARKER)
147
+ const encoder = new TextEncoder()
148
+ return new Response(
149
+ new ReadableStream({
150
+ async start(controller) {
151
+ controller.enqueue(encoder.encode(before ?? ''))
152
+ let first = true
153
+ for await (const chunk of renderToStream(() => ssr)) {
154
+ controller.enqueue(
155
+ encoder.encode(
156
+ first ? chunk : `${chunk}<script>__abideSwap()</script>`,
157
+ ),
158
+ )
159
+ first = false
160
+ }
161
+ controller.enqueue(encoder.encode(after ?? ''))
162
+ controller.close()
163
+ },
164
+ }),
165
+ {
166
+ headers: {
167
+ 'Content-Type': 'text/html; charset=utf-8',
168
+ 'Cache-Control': SSR_CACHE_CONTROL,
169
+ },
170
+ },
171
+ )
172
+ }
173
+
174
+ /* Error pages are not framework-resolved in abide-ui — no error view to render,
175
+ so the caller falls back to its plain Response (404 text) or rethrows. */
176
+ async function renderError(): Promise<Response | undefined> {
177
+ return undefined
178
+ }
179
+
180
+ return { renderPage, renderError }
181
+ }
@@ -0,0 +1,17 @@
1
+ import { NO_STORE } from '../../shared/CACHE_CONTROL_VALUES.ts'
2
+ import { TEXT_PLAIN } from '../../shared/TEXT_PLAIN.ts'
3
+
4
+ /*
5
+ The framework's CSRF refusal, shared by every same-origin gate — the socket
6
+ upgrade, the socket REST publish face, the MCP endpoint, and mutating rpc
7
+ verbs — so the 403 body can't drift between surfaces. `hint` appends a
8
+ surface-specific remedy; rpc names its `crossOrigin: true` opt-out so the
9
+ first developer this 403s can self-serve.
10
+ */
11
+ export function crossOriginForbidden(hint?: string): Response {
12
+ const detail = hint ? ` ${hint}` : ''
13
+ return new Response(
14
+ `Forbidden: cross-origin browser request refused (CSRF protection).${detail}`,
15
+ { status: 403, headers: { 'Content-Type': TEXT_PLAIN, 'Cache-Control': NO_STORE } },
16
+ )
17
+ }
@@ -0,0 +1,29 @@
1
+ import { isReadOnlyMethod } from '../../shared/isReadOnlyMethod.ts'
2
+ import type { HttpVerb } from '../../shared/types/HttpVerb.ts'
3
+ import { crossOriginForbidden } from './crossOriginForbidden.ts'
4
+ import { isCrossOriginRequest } from './isCrossOriginRequest.ts'
5
+
6
+ /*
7
+ The framework's CSRF/CSWSH posture in one place: a cross-origin browser
8
+ request to a mutating framework endpoint is refused. Every endpoint that
9
+ parses bodies ignoring Content-Type (rpc verbs, socket publish, MCP JSON-RPC)
10
+ must gate here — a hostile page's text/plain form trick could otherwise
11
+ smuggle a payload in with the visitor's ambient cookies; non-browser clients
12
+ send no Origin and pass. Returns the 403 to send, or undefined to proceed.
13
+ Mount sites declare their variation: `allowReadOnly` lets GET/HEAD reads
14
+ through (rpc reads and socket tails stay open cross-origin), `optOut` honours
15
+ a verb's explicit `crossOrigin: true`, `hint` names the remedy in the 403.
16
+ */
17
+ export function crossOriginGate(
18
+ req: Request,
19
+ url: URL,
20
+ options: { allowReadOnly?: boolean; optOut?: boolean; hint?: string } = {},
21
+ ): Response | undefined {
22
+ if (options.optOut) {
23
+ return undefined
24
+ }
25
+ if (options.allowReadOnly && isReadOnlyMethod(req.method as HttpVerb)) {
26
+ return undefined
27
+ }
28
+ return isCrossOriginRequest(req, url) ? crossOriginForbidden(options.hint) : undefined
29
+ }
@@ -0,0 +1,117 @@
1
+ import { relative } from 'node:path'
2
+ import { analyzeComponent } from '../../ui/compile/analyzeComponent.ts'
3
+ import { compileComponent } from '../../ui/compile/compileComponent.ts'
4
+ import { nearestProjectRoot } from '../../ui/compile/nearestProjectRoot.ts'
5
+ import { globToPathSet } from './globToPathSet.ts'
6
+ import type { DevReloadStamp } from './types/DevReloadStamp.ts'
7
+
8
+ // The shell's entry-stylesheet link: any `/_app/*.css` href, either quote style.
9
+ const CSS_HREF = /href=(["'])([^"']*\/_app\/[^"']*\.css)\1/
10
+ // Every `/_app/<hashed-asset>` ref in the shell (the JS entry, the stylesheet) —
11
+ // content-hashed names that move on any rebuild. Normalised out of `structure` so
12
+ // a component/CSS edit (which re-hashes the bundle) doesn't read as a reload; the
13
+ // source-based signals (components, non-component hashes, cssHref) catch real changes.
14
+ const APP_ASSET = /\/_app\/[^"'\s)]*/g
15
+ // src/.abide is the build's own generated output (route d.ts) — rewritten every
16
+ // rebuild, so it must stay out of the hash or the page would always reload.
17
+ const GENERATED = /(^|\/)\.abide\//
18
+
19
+ // page.abide / layout.abide are router-mounted, not `mountChild`-tracked, so they
20
+ // can't hot-swap — they fold into `structure` (a reload) instead.
21
+ function isPageOrLayout(moduleId: string): boolean {
22
+ const file = moduleId.split('/').pop() ?? ''
23
+ return file === 'page.abide' || file === 'layout.abide'
24
+ }
25
+
26
+ /*
27
+ The dev live-reload stamp, computed once at worker boot from SOURCE (the dev
28
+ watcher only watches src/, so source is what a rebuild can reflect). Splits the
29
+ edit space so the browser keeps its page where it can:
30
+
31
+ - Each `.abide` is hashed by its client BUILD (`compileComponent`, which carries
32
+ no CSS), so a style-only edit doesn't change it. A leaf component with no
33
+ imports that isn't a page/layout is hot-swappable: its hash goes in
34
+ `components`, keyed by the same module id the loader stamps (so it matches the
35
+ registry). Every other component (page, layout, import-bearing) folds its hash
36
+ into `structure` — editing it reloads.
37
+ - `structure` also covers non-`.abide` source, public stamps, the shell (with
38
+ the stylesheet href normalised out), and the sorted component-id set (so
39
+ adding/removing a component reloads).
40
+ - `cssHref` is the entry stylesheet's current URL, read from the shell.
41
+
42
+ A compile failure (mid-edit syntax error) falls back to a raw-source hash marked
43
+ non-hot, so the worst case is a reload, never a throw at boot.
44
+ */
45
+ export async function devClientFingerprint({
46
+ srcDir,
47
+ publicDir,
48
+ shell,
49
+ projectRoot,
50
+ }: {
51
+ srcDir: string
52
+ publicDir: string
53
+ shell: string
54
+ projectRoot: string
55
+ }): Promise<DevReloadStamp> {
56
+ const srcFiles = [...(await globToPathSet(srcDir, '**/*', (file) => file, { dot: true }))]
57
+ .filter((file) => !GENERATED.test(file))
58
+ .sort()
59
+
60
+ const components: Record<string, string> = {}
61
+ const nonHotComponents: string[] = []
62
+ const componentIds: string[] = []
63
+ const otherSource: string[] = []
64
+
65
+ await Promise.all(
66
+ srcFiles.map(async (file) => {
67
+ const full = `${srcDir}/${file}`
68
+ if (!file.endsWith('.abide')) {
69
+ const bytes = await Bun.file(full)
70
+ .arrayBuffer()
71
+ .catch(() => undefined)
72
+ otherSource.push(`${file}:${bytes ? Bun.hash(bytes) : 0}`)
73
+ return
74
+ }
75
+ const source = await Bun.file(full)
76
+ .text()
77
+ .catch(() => '')
78
+ const moduleId = relative(nearestProjectRoot(full, projectRoot), full)
79
+ componentIds.push(moduleId)
80
+ let bodyHash: string
81
+ let hot = false
82
+ try {
83
+ const isLayout = moduleId.endsWith('layout.abide')
84
+ bodyHash = Bun.hash(compileComponent(source, isLayout, moduleId)).toString(36)
85
+ hot = analyzeComponent(source).imports === '' && !isPageOrLayout(moduleId)
86
+ } catch {
87
+ bodyHash = Bun.hash(source).toString(36)
88
+ }
89
+ if (hot) {
90
+ components[moduleId] = bodyHash
91
+ } else {
92
+ nonHotComponents.push(`${moduleId}:${bodyHash}`)
93
+ }
94
+ }),
95
+ )
96
+
97
+ const publicFiles = [
98
+ ...(await globToPathSet(publicDir, '**/*', (file) => file, { dot: true })),
99
+ ].sort()
100
+ const publicStamps = publicFiles.map((file) => {
101
+ const stat = Bun.file(`${publicDir}/${file}`)
102
+ return `${file}:${stat.size}:${stat.lastModified}`
103
+ })
104
+
105
+ const cssHref = shell.match(CSS_HREF)?.[2]
106
+ const structureShell = shell.replace(APP_ASSET, '/_app/HASH')
107
+ const structure = Bun.hash(
108
+ [
109
+ otherSource.sort().join('\n'),
110
+ publicStamps.join('\n'),
111
+ structureShell,
112
+ componentIds.sort().join(','),
113
+ nonHotComponents.sort().join('\n'),
114
+ ].join('\0'),
115
+ ).toString(36)
116
+ return { structure, cssHref, components }
117
+ }
@@ -0,0 +1,40 @@
1
+ import { resolve } from 'node:path'
2
+ import { NO_STORE } from '../../shared/CACHE_CONTROL_VALUES.ts'
3
+ import { compileModule } from '../../ui/compile/compileModule.ts'
4
+
5
+ // Reused across requests — strips the embedded author TypeScript to browser JS.
6
+ const TRANSPILER = new Bun.Transpiler({ loader: 'ts' })
7
+
8
+ /*
9
+ Serves one edited `.abide`'s hot module (dev component HMR). Compiles it in hot
10
+ mode — runtime sourced from `window.__abide`, self-invoking `hotReplace` — and
11
+ transpiles the embedded author TypeScript to plain JS the browser can import
12
+ directly (the normal pipeline relies on the bundler's `ts` loader for this). The
13
+ browser imports this in place of a reload; on load it swaps the component's live
14
+ instances. The id is guarded as a project-relative `.abide` under cwd; a bad or
15
+ missing file 404s so the client falls back to a reload.
16
+ */
17
+ export async function devHotModuleResponse(moduleId: string): Promise<Response> {
18
+ const root = process.cwd()
19
+ const path = resolve(root, moduleId)
20
+ if (!moduleId.endsWith('.abide') || !path.startsWith(`${root}/`)) {
21
+ return new Response('bad request', { status: 400 })
22
+ }
23
+ const source = await Bun.file(path)
24
+ .text()
25
+ .catch(() => undefined)
26
+ if (source === undefined) {
27
+ return new Response('not found', { status: 404 })
28
+ }
29
+ const code = compileModule(source, {
30
+ isLayout: moduleId.endsWith('layout.abide'),
31
+ moduleId,
32
+ hot: true,
33
+ })
34
+ return new Response(TRANSPILER.transformSync(code), {
35
+ headers: {
36
+ 'Content-Type': 'application/javascript; charset=utf-8',
37
+ 'Cache-Control': NO_STORE,
38
+ },
39
+ })
40
+ }
@@ -0,0 +1,41 @@
1
+ import { NO_STORE } from '../../shared/CACHE_CONTROL_VALUES.ts'
2
+ import type { DevReloadStamp } from './types/DevReloadStamp.ts'
3
+
4
+ // Keepalive comment cadence — keeps the idle SSE connection from being dropped.
5
+ const KEEPALIVE_INTERVAL_MS = 15000
6
+ const TEXT_ENCODER = new TextEncoder()
7
+
8
+ /*
9
+ The dev live-reload channel (`/__abide/dev`, dev only). An SSE stream carrying
10
+ one event: the worker's reload stamp (devClientFingerprint) as JSON. The
11
+ connection drops when the dev orchestrator swaps the server after a rebuild;
12
+ the browser-side client (DEV_RELOAD_CLIENT_SCRIPT) reconnects and compares — a
13
+ changed `structure` reloads, a changed `cssHref` alone swaps the stylesheet in
14
+ place, and a server-only edit (both equal) keeps the page alive. The opening
15
+ `retry: 250` shortens EventSource's reconnect backoff; a periodic comment keeps
16
+ the idle connection alive. The interval is cleared when the consumer disconnects.
17
+ */
18
+ export function devReloadResponse(stamp: DevReloadStamp): Response {
19
+ let keepalive: ReturnType<typeof setInterval>
20
+ const body = new ReadableStream<Uint8Array>({
21
+ start(controller) {
22
+ controller.enqueue(
23
+ TEXT_ENCODER.encode(`retry: 250\ndata: ${JSON.stringify(stamp)}\n\n`),
24
+ )
25
+ keepalive = setInterval(() => {
26
+ controller.enqueue(TEXT_ENCODER.encode(': keepalive\n\n'))
27
+ }, KEEPALIVE_INTERVAL_MS)
28
+ },
29
+ cancel() {
30
+ clearInterval(keepalive)
31
+ },
32
+ })
33
+ return new Response(body, {
34
+ headers: {
35
+ 'Content-Type': 'text/event-stream; charset=utf-8',
36
+ 'Cache-Control': NO_STORE,
37
+ 'X-Content-Type-Options': 'nosniff',
38
+ Connection: 'keep-alive',
39
+ },
40
+ })
41
+ }
@@ -0,0 +1,27 @@
1
+ import type { Server } from 'bun'
2
+ import { isStreamingResponse } from '../../shared/isStreamingResponse.ts'
3
+
4
+ /*
5
+ Opts a long-lived streaming response (SSE / JSONL) out of Bun's per-connection
6
+ idle timeout. Such a stream can stay quiet for longer than the 10s default
7
+ between frames, which Bun would otherwise read as an idle connection and close
8
+ mid-stream. `server.timeout(req, 0)` clears the timeout for just this in-flight
9
+ request, leaving the global default in place for ordinary traffic. Streaming is
10
+ detected by Content-Type (the shared signal the CLI/MCP drain paths use) rather
11
+ than `body instanceof ReadableStream`, since every bodied Response exposes one.
12
+
13
+ A streamed SSR page (`text/html`) is deliberately not opted out: it inherits the
14
+ configured `idleTimeout` as a bounded cap on how long it can hold the connection,
15
+ and the client re-fetches any placeholder left unresolved by a cut stream (see
16
+ flushUnresolvedPlaceholders). Non-stream responses pass through.
17
+ */
18
+ export function disableIdleTimeoutForStream(
19
+ server: Server<unknown>,
20
+ req: Request,
21
+ response: Response,
22
+ ): Response {
23
+ if (isStreamingResponse(response)) {
24
+ server.timeout(req, 0)
25
+ }
26
+ return response
27
+ }
@@ -0,0 +1,15 @@
1
+ import type { StandardSchemaV1 } from '../../shared/types/StandardSchemaV1.ts'
2
+
3
+ /*
4
+ Holds the schema handed to env() so the bundle launcher can project the
5
+ first-run setup form from it (jsonSchemaForSchema) without re-running boot
6
+ validation. `skipValidation` lets the launcher import src/server/config.ts
7
+ purely to register the schema: env() records it and returns early instead of
8
+ validating Bun.env — which the launcher has no business doing, that's the
9
+ embedded server's job at its own boot. In-process module state, so the server
10
+ child the launcher spawns gets a fresh store and validates normally.
11
+ */
12
+ export const envSchemaStore: {
13
+ schema: StandardSchemaV1 | undefined
14
+ skipValidation: boolean
15
+ } = { schema: undefined, skipValidation: false }
@@ -0,0 +1,21 @@
1
+ import { listenOnOpenPort } from './listenOnOpenPort.ts'
2
+
3
+ /*
4
+ Returns the first bindable TCP port at or above `start`, probing upward.
5
+ Used when no PORT is configured so the server lands on a predictable
6
+ 3000+ port (3000, then 3001, …) instead of a random kernel-assigned one —
7
+ running a second app just steps to the next free port. The scan policy
8
+ (range, kernel-assigned fallback) lives in listenOnOpenPort; this variant
9
+ binds a throwaway server and releases it, so like any release-then-rebind
10
+ there's a tiny race before the real listener takes the port — negligible
11
+ for a local boot.
12
+ */
13
+ export function findOpenPort(start: number): number {
14
+ const probe = listenOnOpenPort(
15
+ (port) => Bun.serve({ port, fetch: () => new Response() }),
16
+ start,
17
+ )
18
+ const bound = probe.port as number
19
+ probe.stop(true)
20
+ return bound
21
+ }
@@ -0,0 +1,6 @@
1
+ import type { Server } from 'bun'
2
+ import { serverSlot } from './serverSlot.ts'
3
+
4
+ export function getActiveServer(): Server<unknown> | undefined {
5
+ return serverSlot.active
6
+ }
@@ -0,0 +1,29 @@
1
+ import { Glob } from 'bun'
2
+
3
+ /*
4
+ Scans `cwd` for files matching `pattern` and returns their request paths as
5
+ a Set, mapping each relative file path to a root-relative URL via `keyFor`.
6
+ Used to snapshot the on-disk asset trees (the `public/` files, the `_app`
7
+ precompressed `.gz` siblings) once at boot so the request path is a Set
8
+ lookup instead of a filesystem stat.
9
+
10
+ A missing directory makes scan throw ENOENT — swallowed to an empty Set so
11
+ the caller just falls through. This scan-and-catch is also the reliable
12
+ directory existence test: `Bun.file(dir).exists()` returns false for a
13
+ directory, so guarding the scan with it silently yields an empty Set.
14
+ */
15
+ export async function globToPathSet(
16
+ cwd: string,
17
+ pattern: string,
18
+ keyFor: (file: string) => string,
19
+ options?: { dot?: boolean },
20
+ ): Promise<Set<string>> {
21
+ try {
22
+ const files = await Array.fromAsync(
23
+ new Glob(pattern).scan({ cwd, dot: options?.dot ?? false }),
24
+ )
25
+ return new Set(files.map(keyFor))
26
+ } catch {
27
+ return new Set()
28
+ }
29
+ }
@@ -0,0 +1,46 @@
1
+ import { isStreamingResponse } from '../../shared/isStreamingResponse.ts'
2
+ import { acceptsGzip } from './acceptsGzip.ts'
3
+
4
+ /*
5
+ Compressible Content-Types — text and structured-text payloads. Binary or
6
+ already-compressed bodies (images, fonts, archives, zstd/gzip blobs) gain
7
+ nothing from a second pass and only burn CPU.
8
+ */
9
+ const COMPRESSIBLE_TYPE =
10
+ /^(?:text\/|application\/(?:json|javascript|xml|[\w.-]+\+(?:json|xml))|image\/svg)/
11
+
12
+ /*
13
+ Gzips a dynamic response (SSR HTML, rpc/json replies, the plain 404) when the
14
+ client accepts it, piping the body through a CompressionStream so a buffered
15
+ body and a streamed SSR document take the identical path. Static assets never
16
+ reach here — they already carry a precompressed Content-Encoding, which
17
+ short-circuits the first guard. Skipped for: already-encoded bodies, bodiless
18
+ responses (204/304/HEAD), non-compressible types (images, fonts, archives),
19
+ and frame-delimited streams (SSE/jsonl, where gzip buffering would stall
20
+ per-frame flush). No byte-size floor: Bun doesn't expose a string body's length
21
+ before send, and measuring would mean buffering the streamed SSR document —
22
+ the framing overhead on the rare tiny body is negligible against compressing
23
+ every page and rpc payload.
24
+ */
25
+ export function gzipResponse(req: Request, response: Response): Response {
26
+ if (!response.body || response.headers.has('Content-Encoding')) {
27
+ return response
28
+ }
29
+ if (!acceptsGzip(req) || isStreamingResponse(response)) {
30
+ return response
31
+ }
32
+ const contentType = (response.headers.get('content-type') ?? '').toLowerCase()
33
+ if (!COMPRESSIBLE_TYPE.test(contentType)) {
34
+ return response
35
+ }
36
+ const headers = new Headers(response.headers)
37
+ headers.set('Content-Encoding', 'gzip')
38
+ headers.append('Vary', 'Accept-Encoding')
39
+ /* The stored length no longer matches the compressed body (and is unknown for a stream). */
40
+ headers.delete('Content-Length')
41
+ return new Response(response.body.pipeThrough(new CompressionStream('gzip')), {
42
+ status: response.status,
43
+ statusText: response.statusText,
44
+ headers,
45
+ })
46
+ }
@@ -0,0 +1,20 @@
1
+ import type { Server } from 'bun'
2
+
3
+ /*
4
+ The Server `server()` hands back under in-process dispatch (CLI / MCP / test
5
+ client), where no Bun.serve has booted so there is no live connection to act on.
6
+ Each member is the honest no-op for a request that never rode a socket: timeout
7
+ and upgrade do nothing, publish reaches no subscribers (0 bytes sent),
8
+ subscriberCount is 0, requestIP has no peer (null). Handlers using these idioms
9
+ run unchanged in-process instead of throwing; createServer's live Server takes
10
+ precedence whenever one is booted. Connection-scoped only — config-shaped
11
+ members (port, url, hostname …) are intentionally absent: there is no server to
12
+ describe, and a stubbed value would mislead more than their plain absence.
13
+ */
14
+ export const inProcessServer = {
15
+ timeout() {},
16
+ upgrade: () => false,
17
+ publish: () => 0,
18
+ subscriberCount: () => 0,
19
+ requestIP: () => null,
20
+ } as unknown as Server<unknown>
@@ -0,0 +1,25 @@
1
+ import { NO_STORE } from '../../shared/CACHE_CONTROL_VALUES.ts'
2
+
3
+ /*
4
+ The framework's default 500 response. Shared by the per-request scope's catch
5
+ (runWithRequestScope) and Bun.serve's global error() fallback so the two can't
6
+ drift. Only reached when the app supplies no `handleError` hook.
7
+
8
+ Secure by default: a bare `Internal Server Error` so paths, library versions,
9
+ and message contents never leak to clients in production. The full stack is
10
+ shown only under `abide dev` (ABIDE_DEV=1, the orchestrator's signal); the
11
+ cause is logged server-side regardless.
12
+ */
13
+ export function internalErrorResponse(error: unknown): Response {
14
+ const body =
15
+ Bun.env.ABIDE_DEV === '1'
16
+ ? `<pre>${String((error as Error)?.stack ?? error)}</pre>`
17
+ : 'Internal Server Error'
18
+ return new Response(body, {
19
+ status: 500,
20
+ headers: {
21
+ 'Content-Type': 'text/html; charset=utf-8',
22
+ 'Cache-Control': NO_STORE,
23
+ },
24
+ })
25
+ }
@@ -0,0 +1,23 @@
1
+ /*
2
+ True when the request carries a browser Origin that doesn't match the
3
+ request's own host — the cross-site request forgery shape, in both its
4
+ WebSocket form (CSWSH) and its HTTP form (a hostile page firing a form post
5
+ or no-preflight fetch at an rpc/MCP URL inside a visitor's authenticated
6
+ browser, ambient cookies attached). Native clients (CLI, MCP, curl) send no
7
+ Origin, so an absent header is allowed; only a present-and-mismatched (or
8
+ unparseable) Origin is rejected. An unparseable Origin is treated as
9
+ cross-origin (fail closed). `requestUrl` lets a caller that already parsed
10
+ the URL pass it in; otherwise the parse is deferred until an Origin is
11
+ actually present, keeping the no-Origin hot path allocation-free.
12
+ */
13
+ export function isCrossOriginRequest(request: Request, requestUrl?: URL): boolean {
14
+ const origin = request.headers.get('origin')
15
+ if (!origin) {
16
+ return false
17
+ }
18
+ try {
19
+ return new URL(origin).host !== (requestUrl ?? new URL(request.url)).host
20
+ } catch {
21
+ return true
22
+ }
23
+ }