@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,286 @@
1
+ import { layoutChainForRoute } from '../shared/layoutChainForRoute.ts'
2
+ import { effect } from './effect.ts'
3
+ import { matchRoute } from './matchRoute.ts'
4
+ import { navigate } from './navigate.ts'
5
+ import { clientPage } from './runtime/clientPage.ts'
6
+ import { enterRenderPass } from './runtime/enterRenderPass.ts'
7
+ import { exitRenderPass } from './runtime/exitRenderPass.ts'
8
+ import { firstOutlet } from './runtime/firstOutlet.ts'
9
+ import { runtimePath } from './runtime/runtimePath.ts'
10
+ import type { NavVerdict } from './runtime/types/NavVerdict.ts'
11
+ import type { Route } from './runtime/types/Route.ts'
12
+ import type { RouteLoader } from './runtime/types/RouteLoader.ts'
13
+ import { untrack } from './runtime/untrack.ts'
14
+
15
+ /* A layout mounted in the active chain: its route key (the directory URL — its
16
+ identity for the diff), the disposer that stops its reactivity, and the outlet
17
+ element the next layer mounts into. */
18
+ type MountedLayout = { key: string; dispose: () => void; outlet: Element }
19
+
20
+ /* A layout mount that returns no disposer still needs one for the chain teardown. */
21
+ const noop = (): void => {}
22
+
23
+ /*
24
+ A minimal client router on the History API. `router` matches the current path
25
+ against the route patterns (literal / `[name]` / `[...rest]`, via matchRoute),
26
+ imports the matching page's chunk — plus every `layout.abide` chunk that wraps it
27
+ (`layoutChainForRoute`) — on demand, and mounts them as a chain: each layout into
28
+ the previous layout's `<slot/>` outlet, the page into the innermost outlet.
29
+
30
+ Navigation re-resolves the chain and DIFFS it against the mounted one: layouts whose
31
+ route key still matches at the same depth stay mounted (their state, effects, scroll,
32
+ and DOM survive); from the first divergent layout down — the leaf layers — everything
33
+ is disposed and rebuilt, and the page (always the leaf) re-mounts every time. The
34
+ reactive `page` proxy means a persisted layout reading route/params updates in place
35
+ without a remount. Each chunk loads only on first visit, cached after.
36
+
37
+ `probe` (when given) runs each post-boot navigation's destination through the
38
+ server's app.handle first, so auth/redirect gating applies to client navigation
39
+ just as it does to a fresh load; its verdict either clears the mount, soft-redirects
40
+ where handle() pointed, or hands off to a full browser load. The first render
41
+ adopts a document handle() already ran on, so it isn't probed. There is no server
42
+ router — the server picks the page by request URL directly; this is the client
43
+ half. `*` is the fallback route.
44
+ */
45
+ // @readme plumbing
46
+ export function router(
47
+ host: Element,
48
+ loaders: Record<string, RouteLoader>,
49
+ layoutLoaders: Record<string, RouteLoader> = {},
50
+ probe?: (path: string) => Promise<NavVerdict>,
51
+ ): () => void {
52
+ /* The mounted layout chain (outermost first) + the page disposer. */
53
+ const mountedLayouts: MountedLayout[] = []
54
+ let disposePage: (() => void) | undefined
55
+ const patterns = Object.keys(loaders).filter((key) => key !== '*')
56
+ const layoutKeys = Object.keys(layoutLoaders)
57
+
58
+ /* A code-split resolver over one loader map: resolved chunks keyed by route
59
+ pattern, so a revisit re-mounts without a second import. */
60
+ const resolver = (
61
+ map: Record<string, RouteLoader>,
62
+ ): ((key: string) => Promise<Route | undefined>) => {
63
+ const resolved = new Map<string, Route | undefined>()
64
+ return async (key) => {
65
+ if (resolved.has(key)) {
66
+ return resolved.get(key)
67
+ }
68
+ const loader = map[key]
69
+ const view = loader === undefined ? undefined : (await loader()).default
70
+ resolved.set(key, view)
71
+ return view
72
+ }
73
+ }
74
+ const resolvePage = resolver(loaders)
75
+ const resolveLayout = resolver(layoutLoaders)
76
+
77
+ /* Tear down the page and every layout from `index` inward (innermost first), then
78
+ return the container the rebuild mounts into — the surviving layout's outlet, or
79
+ `host` when the whole chain goes. */
80
+ const disposeFrom = (index: number): Element => {
81
+ disposePage?.()
82
+ disposePage = undefined
83
+ for (let depth = mountedLayouts.length - 1; depth >= index; depth -= 1) {
84
+ mountedLayouts[depth]?.dispose()
85
+ }
86
+ const base = index === 0 ? host : (mountedLayouts[index - 1] as MountedLayout).outlet
87
+ mountedLayouts.length = index
88
+ return base
89
+ }
90
+
91
+ /* Mount (or hydrate) the chain tail — layouts `[index..]` then the page — into
92
+ `base`, threading each layer into the previous one's outlet. Hydration brackets
93
+ ONE render pass across all layers so await/try block ids stay unique and aligned
94
+ with the SSR stream; a fresh mount needs no shared pass. */
95
+ const buildFrom = (
96
+ base: Element,
97
+ index: number,
98
+ chainKeys: string[],
99
+ layoutViews: Route[],
100
+ pageView: Route | undefined,
101
+ params: Record<string, string>,
102
+ hydrating: boolean,
103
+ ): void => {
104
+ const run = (): void => {
105
+ let container = base
106
+ for (let depth = index; depth < layoutViews.length; depth += 1) {
107
+ const view = layoutViews[depth] as Route
108
+ const dispose = hydrating
109
+ ? (view.hydrate as NonNullable<Route['hydrate']>)(container, params)
110
+ : (view(container, params) ?? noop)
111
+ const outlet = firstOutlet(container)
112
+ if (outlet === undefined) {
113
+ throw new Error('[abide] a layout.abide must contain a <slot/> outlet')
114
+ }
115
+ mountedLayouts.push({ key: chainKeys[depth] as string, dispose, outlet })
116
+ container = outlet
117
+ }
118
+ if (pageView === undefined) {
119
+ return
120
+ }
121
+ disposePage = hydrating
122
+ ? (pageView.hydrate as NonNullable<Route['hydrate']>)(container, params)
123
+ : (pageView(container, params) ?? undefined)
124
+ }
125
+ if (hydrating) {
126
+ enterRenderPass()
127
+ try {
128
+ run()
129
+ } finally {
130
+ exitRenderPass()
131
+ }
132
+ return
133
+ }
134
+ run()
135
+ }
136
+
137
+ const onPopState = (): void => {
138
+ runtimePath.value = location.pathname + location.search + location.hash
139
+ }
140
+ const onClick = (event: MouseEvent): void => {
141
+ /* Let the browser own anything that isn't a plain primary-button click:
142
+ modified clicks (open in a new tab/window), middle/right buttons, and
143
+ already-handled events. */
144
+ if (
145
+ event.defaultPrevented ||
146
+ event.button !== 0 ||
147
+ event.metaKey ||
148
+ event.ctrlKey ||
149
+ event.shiftKey ||
150
+ event.altKey
151
+ ) {
152
+ return
153
+ }
154
+ const target = event.target as Element
155
+ const link = target.closest?.('a[href]') as HTMLAnchorElement | null
156
+ if (link === null) {
157
+ return
158
+ }
159
+ /* Defer to the browser for links it should own: a new-tab target, a
160
+ download, or an explicitly external rel. */
161
+ if (
162
+ (link.target !== '' && link.target !== '_self') ||
163
+ link.hasAttribute('download') ||
164
+ link.getAttribute('rel') === 'external'
165
+ ) {
166
+ return
167
+ }
168
+ const destination = new URL(link.href)
169
+ if (destination.origin !== location.origin) {
170
+ return
171
+ }
172
+ event.preventDefault()
173
+ /* Carry the query and hash, not just the pathname, so the destination page's
174
+ page.url sees them and an SPA navigation matches a fresh server load. */
175
+ navigate(destination.pathname + destination.search + destination.hash)
176
+ }
177
+ if (typeof window !== 'undefined') {
178
+ window.addEventListener('popstate', onPopState)
179
+ document.addEventListener('click', onClick as EventListener)
180
+ }
181
+
182
+ /* First render adopts the server-rendered DOM (when the matching page is
183
+ hydratable); navigation after that re-mounts fresh. */
184
+ let first = true
185
+ /* Monotonic token: a newer navigation that resolves first wins, so a slow
186
+ chunk landing late never overwrites the page the user has since moved to. */
187
+ let sequence = 0
188
+ /* Latched on teardown so a navigation whose imports/probe were in flight at
189
+ dispose can't run its `.then` and rebuild a chain we just tore down — the
190
+ `token` guard only catches a *newer* navigation, not disposal. */
191
+ let disposed = false
192
+ const stop = effect(() => {
193
+ /* The route is the only dependency the router should re-run on. Everything
194
+ else runs untracked so the page's build-time reads (each interpolation
195
+ reads its value once before wrapping it in its own effect) bind to the
196
+ page's own effects, not this one — otherwise any in-page state change
197
+ would re-run the router and re-mount the page, dropping local state. */
198
+ const path = runtimePath.value
199
+ untrack(() => {
200
+ /* The route matches on the pathname only; the query/hash ride along for
201
+ the probe (so server gating sees them) and for clientPage.url. */
202
+ const pathname = path.split(/[?#]/)[0] ?? path
203
+ const matched = matchRoute(patterns, pathname)
204
+ const key = matched?.route ?? '*'
205
+ const params = matched?.params ?? {}
206
+ /* The layout chain resolves off the literal route key (so a layout at a
207
+ `[id]` directory matches the `[name]` pattern, not the concrete path). */
208
+ const chainRoute = matched?.route ?? pathname
209
+ const chainKeys = layoutChainForRoute(chainRoute, layoutKeys)
210
+ sequence += 1
211
+ const token = sequence
212
+ /* First paint adopts a document the server already ran handle() on;
213
+ only later navigations re-run it through the probe. */
214
+ const verdict: Promise<NavVerdict> =
215
+ first || probe === undefined ? Promise.resolve({ kind: 'mount' }) : probe(path)
216
+ /* Resolve the page chunk, its layout chunks, and the gate in parallel,
217
+ keeping the current chain mounted until all land — no blank frame while
218
+ imports are in flight or the probe is in the air. */
219
+ void Promise.all([
220
+ resolvePage(key),
221
+ Promise.all(chainKeys.map((layoutKey) => resolveLayout(layoutKey))),
222
+ verdict,
223
+ ]).then(([pageView, resolvedLayouts, decision]) => {
224
+ if (token !== sequence || disposed) {
225
+ return
226
+ }
227
+ /* handle() redirected: go where it pointed, replacing the blocked
228
+ URL so back doesn't trap on it. The router re-probes the target. */
229
+ if (decision.kind === 'redirect') {
230
+ navigate(decision.path, true)
231
+ return
232
+ }
233
+ /* handle() blocked it / redirected off-origin / the probe failed:
234
+ let the browser load the server's real response. */
235
+ if (decision.kind === 'reload') {
236
+ if (typeof location !== 'undefined') {
237
+ location.href = decision.url
238
+ }
239
+ return
240
+ }
241
+ /* Publish the active page so the `page` proxy resolves route/params/url. */
242
+ clientPage.value = {
243
+ route: matched?.route ?? pathname,
244
+ params,
245
+ url:
246
+ typeof location === 'undefined'
247
+ ? new URL(`http://localhost${path}`)
248
+ : new URL(location.href),
249
+ navigating: false,
250
+ }
251
+ const layoutViews = resolvedLayouts.filter(
252
+ (view): view is Route => view !== undefined,
253
+ )
254
+ /* The shared prefix of layouts (same route key at the same depth) stays
255
+ mounted; the first divergence and everything inward is rebuilt. */
256
+ let divergence = 0
257
+ while (
258
+ divergence < mountedLayouts.length &&
259
+ divergence < chainKeys.length &&
260
+ mountedLayouts[divergence]?.key === chainKeys[divergence]
261
+ ) {
262
+ divergence += 1
263
+ }
264
+ const hydrating =
265
+ first && pageView?.hydratable === true && pageView.hydrate !== undefined
266
+ first = false
267
+ const base = disposeFrom(divergence)
268
+ /* A fresh mount clears the torn-down DOM; hydration adopts it in place. */
269
+ if (!hydrating) {
270
+ base.textContent = ''
271
+ }
272
+ buildFrom(base, divergence, chainKeys, layoutViews, pageView, params, hydrating)
273
+ })
274
+ })
275
+ })
276
+
277
+ return () => {
278
+ disposed = true
279
+ if (typeof window !== 'undefined') {
280
+ window.removeEventListener('popstate', onPopState)
281
+ document.removeEventListener('click', onClick as EventListener)
282
+ }
283
+ stop()
284
+ disposeFrom(0)
285
+ }
286
+ }
@@ -0,0 +1,8 @@
1
+ /* The element a layout's `<slot/>` lowers to: an empty structural container the
2
+ router fills with the next layer of the route's layout chain (the nested layout
3
+ or the page). SSR emits it empty so the renderer can fold the child's html into
4
+ it; on the client the router mounts/hydrates the child into it and finds it by
5
+ tag. Shared by both compiler back-ends, the SSR chain composer, and the router so
6
+ they all agree on the marker. */
7
+ // @readme plumbing
8
+ export const OUTLET_TAG = 'abide-outlet'
@@ -0,0 +1,8 @@
1
+ /*
2
+ The ownership scope currently collecting teardown callbacks. While a component
3
+ (or a list row) builds, `scope()` points this at an array; every effect and event
4
+ listener created during the build pushes its disposer here, so the whole instance
5
+ tears down together. undefined outside any build — effects in plain code own
6
+ their own lifecycle via the disposer they return.
7
+ */
8
+ export const OWNER: { current: Array<() => void> | undefined } = { current: undefined }
@@ -0,0 +1,14 @@
1
+ import type { ReactiveNode } from './types/ReactiveNode.ts'
2
+
3
+ /*
4
+ Mutable singletons shared by every reactive primitive: the observer currently
5
+ running (so a read can register itself as that observer's dependency), the set
6
+ of effects dirtied since the last flush, and the batch depth (writes inside a
7
+ batch queue effects and flush once on exit). Held on one object so signal,
8
+ computed, and effect all reference the same graph state without a barrel.
9
+ */
10
+ export const REACTIVE_CONTEXT: {
11
+ observer: ReactiveNode | undefined
12
+ pendingEffects: Set<ReactiveNode>
13
+ batchDepth: number
14
+ } = { observer: undefined, pendingEffects: new Set(), batchDepth: 0 }
@@ -0,0 +1,23 @@
1
+ /*
2
+ Render mode shared by the dom helpers. In the default (create) mode `hydration`
3
+ is undefined and helpers build fresh nodes. During `hydrate` it holds, per parent,
4
+ the next server-rendered child node to claim — a node pointer (not an index) so it
5
+ survives nodes a block inserts (anchors) mid-hydration. Helpers claim in build
6
+ order, which matches the SSR order, advancing the pointer to the next sibling.
7
+
8
+ `blockId`/`depth` drive the render-pass block-id counter: every `await`/`try` block
9
+ draws an id from `blockId` in document order, shared across a component and the
10
+ child components it inlines, so ids are globally unique within one render pass (the
11
+ SSR stream and client hydration agree on them — `RESUME` is keyed by id). `depth`
12
+ tracks nesting so the OUTERMOST render/mount resets the counter and a child render/
13
+ mount continues it. See `enterRenderPass`/`nextBlockId`.
14
+ */
15
+ export const RENDER: {
16
+ hydration: { next: Map<Node, Node | null> } | undefined
17
+ blockId: number
18
+ depth: number
19
+ } = {
20
+ hydration: undefined,
21
+ blockId: 0,
22
+ depth: 0,
23
+ }
@@ -0,0 +1,16 @@
1
+ /* The await-resume manifest: the resolved value (or error) of each streamed
2
+ `await` block, keyed by its boundary id. The SSR stream serializes each value
3
+ alongside its fragment; the client registers it (via `applyResolved` or the
4
+ inline swap script), and hydration reads it so an `await` block adopts the
5
+ resolved branch with the real value instead of re-running the promise.
6
+
7
+ Backed by `globalThis.__abideResume` so the inline stream-swap script (vanilla,
8
+ running during the stream before the bundle loads) and the framework share one
9
+ store: whoever runs first creates it, the other adopts the same reference. */
10
+ export type ResumeEntry = { ok: true; value: unknown } | { ok: false; error: unknown }
11
+
12
+ const globalScope = globalThis as { __abideResume?: Record<number, ResumeEntry> }
13
+ globalScope.__abideResume ??= {}
14
+
15
+ // @readme plumbing
16
+ export const RESUME: Record<number, ResumeEntry> = globalScope.__abideResume
@@ -0,0 +1,41 @@
1
+ import type { Patch } from './types/Patch.ts'
2
+
3
+ /*
4
+ Applies `patch` to `tree` by mutating in place and returns the root (a fresh
5
+ value only when the root itself is replaced). In-place is the deliberate choice:
6
+ the patch path already names exactly what changed, so we never need copy-on-write
7
+ to *detect* a change — and cloning the spine made every leaf write O(width) of
8
+ the widest ancestor (a 5k-item list copied 50k times in the bench). Mutating is
9
+ O(depth). History/undo is served by journalling patches (the change is a value),
10
+ not by retaining old roots — which is cheaper anyway. The wake step in createDoc
11
+ force-notifies ancestor readers from the path, since their container keeps its
12
+ identity now.
13
+
14
+ `segments` is the patch path pre-split by the caller (createDoc also needs it),
15
+ threaded in so the path is split once per patch rather than here and there.
16
+ */
17
+ export function applyPatchToTree(tree: unknown, patch: Patch, segments: string[]): unknown {
18
+ /* Replacing the root can't mutate in place — hand back the new value. */
19
+ if (segments.length === 0) {
20
+ return patch.op === 'remove' ? undefined : patch.value
21
+ }
22
+ let parent = tree as Record<string, unknown>
23
+ for (const segment of segments.slice(0, -1)) {
24
+ parent = parent[segment] as Record<string, unknown>
25
+ }
26
+ const key = segments[segments.length - 1] as string
27
+ if (patch.op === 'replace') {
28
+ parent[key] = patch.value
29
+ } else if (patch.op === 'add') {
30
+ if (Array.isArray(parent)) {
31
+ parent.splice(key === '-' ? parent.length : Number(key), 0, patch.value)
32
+ } else {
33
+ parent[key] = patch.value
34
+ }
35
+ } else if (Array.isArray(parent)) {
36
+ parent.splice(Number(key), 1)
37
+ } else {
38
+ delete parent[key]
39
+ }
40
+ return tree
41
+ }
@@ -0,0 +1,10 @@
1
+ import type { RENDER } from './RENDER.ts'
2
+
3
+ /* The next server-rendered node to claim under `parent` during hydration,
4
+ defaulting to its first child when the pointer hasn't been set yet. */
5
+ export function claimChild(
6
+ hydration: NonNullable<(typeof RENDER)['hydration']>,
7
+ parent: Node,
8
+ ): Node | null {
9
+ return hydration.next.has(parent) ? (hydration.next.get(parent) ?? null) : parent.firstChild
10
+ }
@@ -0,0 +1,16 @@
1
+ import type { PageSnapshot } from '../../shared/types/PageSnapshot.ts'
2
+ import { state } from '../state.ts'
3
+
4
+ /*
5
+ The client-side page snapshot the `page` proxy reads (startClient registers
6
+ `() => clientPage.value` as the page resolver). It's a abide-ui signal, so a
7
+ component reading page.url/params/route inside an effect re-runs when the router
8
+ updates it on navigation. Server renders never touch this — there the resolver
9
+ reads the per-request store instead.
10
+ */
11
+ export const clientPage = state<PageSnapshot>({
12
+ route: '',
13
+ params: {},
14
+ url: typeof location === 'undefined' ? new URL('http://localhost/') : new URL(location.href),
15
+ navigating: false,
16
+ })
@@ -0,0 +1,16 @@
1
+ import type { ReactiveNode } from './types/ReactiveNode.ts'
2
+
3
+ /* Creates a lazy derived node. Born dirty so its first read computes; thereafter
4
+ it recomputes only when a dependency triggers it. */
5
+ export function createComputedNode(compute: () => unknown): ReactiveNode {
6
+ return {
7
+ value: undefined,
8
+ compute,
9
+ depsHead: undefined,
10
+ depsTail: undefined,
11
+ subsHead: undefined,
12
+ subsTail: undefined,
13
+ dirty: true,
14
+ isEffect: false,
15
+ }
16
+ }
@@ -0,0 +1,177 @@
1
+ import { applyPatchToTree } from './applyPatchToTree.ts'
2
+ import { createSignalNode } from './createSignalNode.ts'
3
+ import { flushEffects } from './flushEffects.ts'
4
+ import { pathExists } from './pathExists.ts'
5
+ import { REACTIVE_CONTEXT } from './REACTIVE_CONTEXT.ts'
6
+ import { readNode } from './readNode.ts'
7
+ import { trigger } from './trigger.ts'
8
+ import type { Cell } from './types/Cell.ts'
9
+ import type { Doc } from './types/Doc.ts'
10
+ import type { Patch } from './types/Patch.ts'
11
+ import type { ReactiveNode } from './types/ReactiveNode.ts'
12
+ import { valueAtPath } from './valueAtPath.ts'
13
+ import { writeNode } from './writeNode.ts'
14
+
15
+ /*
16
+ Builds a reactive document over `initial`. Each path read for the first time
17
+ mints a signal node; the node is the notification token, the (mutable) tree is
18
+ the source of truth. A patch mutates the tree in place — O(depth), not O(width) —
19
+ then wakes from the patch's **change root** with shape-only reactivity:
20
+
21
+ - a value change at a path (an object key replaced with a new value) wakes only
22
+ that path and, if it became a container, its descendants — NOT its ancestors.
23
+ Reading a container subscribes to its own shape, so a deep field change never
24
+ re-runs a reader of the array/object above it (the reason a single list-item
25
+ edit doesn't reconcile the whole `each`).
26
+ - a structural change (add/remove anywhere, or replacing an array element by
27
+ index) changes the *parent container's* shape, so the parent is the change
28
+ root: it is force-notified (its identity is unchanged after in-place mutation)
29
+ and its descendants are re-read to pick up index shifts.
30
+
31
+ Reads of exactly the changed path are gated by `Object.is`, so an equal write
32
+ wakes nobody. Change is addressed, not diffed, and the address is as shallow as
33
+ the change.
34
+ */
35
+ export function createDoc(initial: unknown): Doc {
36
+ let tree = initial
37
+ const nodes = new Map<string, ReactiveNode>()
38
+
39
+ function nodeFor(path: string): ReactiveNode {
40
+ let node = nodes.get(path)
41
+ if (node === undefined) {
42
+ node = createSignalNode(valueAtPath(tree, path))
43
+ nodes.set(path, node)
44
+ }
45
+ return node
46
+ }
47
+
48
+ function read<T>(path: string): T {
49
+ return readNode(nodeFor(path)) as T
50
+ }
51
+
52
+ /*
53
+ Wakes readers from `rootPath`. `force` notifies the root unconditionally (a
54
+ structural change keeps the container's identity, so there is no new value to
55
+ compare); otherwise the root is written through the `Object.is` gate. When
56
+ `descend`, a container root also re-reads its existing descendant nodes (gated)
57
+ to catch nested and index-shifted values. `descend` is skipped for a change
58
+ that leaves every existing descendant path addressing the same value (an
59
+ end-append or an object-key add), so those updates stay O(depth) instead of
60
+ paying a scan over every minted node.
61
+ */
62
+ function wakeSubtree(rootPath: string, force: boolean, descend: boolean): void {
63
+ const rootValue = valueAtPath(tree, rootPath)
64
+ const rootNode = nodes.get(rootPath)
65
+ if (rootNode !== undefined) {
66
+ if (force) {
67
+ trigger(rootNode)
68
+ } else {
69
+ writeNode(rootNode, rootValue)
70
+ }
71
+ }
72
+ if (!descend || rootValue === null || typeof rootValue !== 'object') {
73
+ return
74
+ }
75
+ const prefix = rootPath === '' ? '' : `${rootPath}/`
76
+ for (const [candidate, node] of nodes) {
77
+ if (candidate !== rootPath && candidate.startsWith(prefix)) {
78
+ /* A descendant whose path the mutation removed — a deleted key, an
79
+ out-of-range index after a shrink — is woken to undefined, then
80
+ dropped from the registry. Without eviction `nodes` grows for the
81
+ life of the session over churning keys (items/<uuid>, message ids),
82
+ and this very descend scan degrades linearly with it. The woken
83
+ reader re-mints a fresh node on its flush if the path ever returns.
84
+ Deleting the current entry mid-iteration is safe on a Map. */
85
+ if (pathExists(tree, candidate)) {
86
+ writeNode(node, valueAtPath(tree, candidate))
87
+ } else {
88
+ writeNode(node, undefined)
89
+ nodes.delete(candidate)
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ function apply(patch: Patch): void {
96
+ const segments = patch.path === '' ? [] : patch.path.split('/')
97
+ tree = applyPatchToTree(tree, patch, segments)
98
+ const parentPath = segments.slice(0, -1).join('/')
99
+ const parentValue = valueAtPath(tree, parentPath)
100
+ const leafKey = segments[segments.length - 1] as string | undefined
101
+ /* A structural change (add/remove, or an array element replaced by index)
102
+ reshapes the parent; a plain value replace reshapes only its own path. */
103
+ const parentIsArray = Array.isArray(parentValue)
104
+ const structural = patch.op !== 'replace' || parentIsArray
105
+ const arrayLength = parentIsArray ? (parentValue as unknown[]).length : 0
106
+ /* An add that introduces a new path without shifting any existing sibling —
107
+ an object-key add or an array append at the end — changes only the added
108
+ slot's subtree plus (for an array) its `length` node, never the existing
109
+ element nodes. Waking exactly those two avoids re-reading every descendant
110
+ of a large container. Every other structural change (any remove, a
111
+ mid-array insert, an array element replace) shifts indices or replaces a
112
+ subtree, so all descendants must be re-read. */
113
+ const nonShiftingAdd =
114
+ patch.op === 'add' &&
115
+ (!parentIsArray || leafKey === '-' || Number(leafKey) === arrayLength - 1)
116
+ REACTIVE_CONTEXT.batchDepth += 1
117
+ try {
118
+ if (segments.length === 0) {
119
+ wakeSubtree('', true, true)
120
+ } else if (!structural) {
121
+ wakeSubtree(patch.path, false, true)
122
+ } else if (nonShiftingAdd) {
123
+ wakeSubtree(parentPath, true, false)
124
+ /* The appended slot resolves to its real index when keyed by `-`. */
125
+ const addedPath =
126
+ parentIsArray && leafKey === '-'
127
+ ? `${parentPath}/${arrayLength - 1}`
128
+ : patch.path
129
+ wakeSubtree(addedPath, false, true)
130
+ const lengthNode = parentIsArray ? nodes.get(`${parentPath}/length`) : undefined
131
+ if (lengthNode !== undefined) {
132
+ writeNode(lengthNode, arrayLength)
133
+ }
134
+ } else {
135
+ wakeSubtree(parentPath, true, true)
136
+ }
137
+ } finally {
138
+ REACTIVE_CONTEXT.batchDepth -= 1
139
+ }
140
+ flushEffects()
141
+ }
142
+
143
+ /*
144
+ A stable accessor bound to one scalar leaf — what the compiler emits so a hot
145
+ loop has zero string work: the node, the parent container, and the leaf key
146
+ are resolved once. `set` mutates the parent directly and writes the node
147
+ through the gate; no ancestor walk, because a scalar leaf change is shape-only
148
+ (it never reshapes its container). Valid while ancestors keep their identity
149
+ (the scalar-field case); a wholesale ancestor replace re-binds the cell.
150
+ */
151
+ function cell<T>(path: string): Cell<T> {
152
+ const node = nodeFor(path)
153
+ const segments = path.split('/')
154
+ const leafKey = segments[segments.length - 1] as string
155
+ let parent = tree as Record<string, unknown>
156
+ for (const segment of segments.slice(0, -1)) {
157
+ parent = parent[segment] as Record<string, unknown>
158
+ }
159
+ return {
160
+ get: () => readNode(node) as T,
161
+ set: (value: T) => {
162
+ parent[leafKey] = value
163
+ writeNode(node, value)
164
+ },
165
+ }
166
+ }
167
+
168
+ return {
169
+ read,
170
+ cell,
171
+ apply,
172
+ replace: (path, value) => apply({ op: 'replace', path, value }),
173
+ add: (path, value) => apply({ op: 'add', path, value }),
174
+ remove: (path) => apply({ op: 'remove', path }),
175
+ snapshot: () => tree,
176
+ }
177
+ }