@belte/belte 0.19.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 (326) hide show
  1. package/CHANGELOG.md +313 -0
  2. package/LICENSE +21 -0
  3. package/README.md +559 -0
  4. package/bin/belte.ts +183 -0
  5. package/package.json +110 -0
  6. package/src/App.svelte +31 -0
  7. package/src/appEntry.ts +151 -0
  8. package/src/assets/app.html +14 -0
  9. package/src/belteResolverPlugin.ts +858 -0
  10. package/src/build.ts +147 -0
  11. package/src/buildCli.ts +129 -0
  12. package/src/buildDisconnected.ts +122 -0
  13. package/src/bundleApp.ts +149 -0
  14. package/src/bundleDisconnectedEntry.ts +17 -0
  15. package/src/cliEntry.ts +25 -0
  16. package/src/clientBuildPlugins.ts +41 -0
  17. package/src/clientEntry.ts +7 -0
  18. package/src/compile.ts +64 -0
  19. package/src/controlServerWorker.ts +422 -0
  20. package/src/dedupeSveltePlugin.ts +66 -0
  21. package/src/devEntry.ts +169 -0
  22. package/src/discoveryEntry.ts +81 -0
  23. package/src/lib/browser/applyStreamedResolution.ts +33 -0
  24. package/src/lib/browser/cacheEntryFromSnapshot.ts +48 -0
  25. package/src/lib/browser/flushUnresolvedPlaceholders.ts +16 -0
  26. package/src/lib/browser/installStreamingPlaceholders.ts +32 -0
  27. package/src/lib/browser/openResolveStream.ts +42 -0
  28. package/src/lib/browser/page.svelte.ts +258 -0
  29. package/src/lib/browser/pageStreamController.ts +17 -0
  30. package/src/lib/browser/refetchPlaceholder.ts +12 -0
  31. package/src/lib/browser/remoteProxy.ts +37 -0
  32. package/src/lib/browser/socketChannel.ts +192 -0
  33. package/src/lib/browser/socketProxy.ts +57 -0
  34. package/src/lib/browser/startClient.ts +153 -0
  35. package/src/lib/browser/subscribe.ts +131 -0
  36. package/src/lib/browser/types/Errors.ts +9 -0
  37. package/src/lib/browser/types/Layouts.ts +7 -0
  38. package/src/lib/browser/types/Pages.ts +7 -0
  39. package/src/lib/browser/types/StreamingDeferred.ts +9 -0
  40. package/src/lib/bundle/BundleMenu.ts +11 -0
  41. package/src/lib/bundle/BundleMenuItem.ts +24 -0
  42. package/src/lib/bundle/BundleWindow.ts +36 -0
  43. package/src/lib/bundle/WEBVIEW_BUILD_REVISION.ts +9 -0
  44. package/src/lib/bundle/WEBVIEW_VERSION.ts +7 -0
  45. package/src/lib/bundle/bindConnectedFlag.ts +29 -0
  46. package/src/lib/bundle/bindRequestNavigate.ts +31 -0
  47. package/src/lib/bundle/buildWebviewLib.ts +111 -0
  48. package/src/lib/bundle/disconnected.css +9 -0
  49. package/src/lib/bundle/disconnected.svelte +386 -0
  50. package/src/lib/bundle/ensureWebviewLib.ts +20 -0
  51. package/src/lib/bundle/exitWithParent.ts +28 -0
  52. package/src/lib/bundle/infoPlist.ts +46 -0
  53. package/src/lib/bundle/installDownloads.ts +24 -0
  54. package/src/lib/bundle/installMacMenu.ts +39 -0
  55. package/src/lib/bundle/listenLocalControlServer.ts +19 -0
  56. package/src/lib/bundle/native/belteMenu.mm +422 -0
  57. package/src/lib/bundle/native/webview.h +4557 -0
  58. package/src/lib/bundle/onMenu.ts +41 -0
  59. package/src/lib/bundle/openWebview.ts +104 -0
  60. package/src/lib/bundle/pngToIcns.ts +47 -0
  61. package/src/lib/bundle/probeBelteServer.ts +34 -0
  62. package/src/lib/bundle/resolveServerBinary.ts +12 -0
  63. package/src/lib/bundle/resolveWebviewLib.ts +53 -0
  64. package/src/lib/bundle/serverBinaryFilename.ts +8 -0
  65. package/src/lib/bundle/signMacApp.ts +35 -0
  66. package/src/lib/bundle/spawnEmbeddedServer.ts +65 -0
  67. package/src/lib/bundle/stableLocalPort.ts +19 -0
  68. package/src/lib/bundle/waitForServer.ts +23 -0
  69. package/src/lib/bundle/webviewCachePath.ts +23 -0
  70. package/src/lib/bundle/webviewLibName.ts +11 -0
  71. package/src/lib/cli/connectToServer.ts +23 -0
  72. package/src/lib/cli/createClient.ts +170 -0
  73. package/src/lib/cli/dispatchCommand.ts +71 -0
  74. package/src/lib/cli/loadEnvFromBinaryDir.ts +16 -0
  75. package/src/lib/cli/parseArgvForRpc.ts +97 -0
  76. package/src/lib/cli/printHelp.ts +119 -0
  77. package/src/lib/cli/printSessionHelp.ts +27 -0
  78. package/src/lib/cli/printSessionStatus.ts +21 -0
  79. package/src/lib/cli/printTrimmed.ts +8 -0
  80. package/src/lib/cli/printValue.ts +10 -0
  81. package/src/lib/cli/resolveCliTarget.ts +48 -0
  82. package/src/lib/cli/runCli.ts +139 -0
  83. package/src/lib/cli/runSession.ts +105 -0
  84. package/src/lib/cli/startLocalInstance.ts +14 -0
  85. package/src/lib/cli/tokenizeLine.ts +51 -0
  86. package/src/lib/cli/types/CliManifest.ts +9 -0
  87. package/src/lib/cli/types/CliManifestEntry.ts +17 -0
  88. package/src/lib/cli/types/CliTarget.ts +13 -0
  89. package/src/lib/mcp/annotationsForMethod.ts +29 -0
  90. package/src/lib/mcp/createMcpResourceServer.ts +101 -0
  91. package/src/lib/mcp/createMcpServer.ts +42 -0
  92. package/src/lib/mcp/dispatchMcpRequest.ts +146 -0
  93. package/src/lib/mcp/mcpResourceServerSlot.ts +18 -0
  94. package/src/lib/mcp/mcpSurface.ts +265 -0
  95. package/src/lib/mcp/toolResultFromResponse.ts +66 -0
  96. package/src/lib/mcp/types/JsonRpcRequest.ts +12 -0
  97. package/src/lib/mcp/types/JsonRpcResponse.ts +20 -0
  98. package/src/lib/mcp/types/McpResourceContents.ts +10 -0
  99. package/src/lib/mcp/types/McpResourceDescriptor.ts +6 -0
  100. package/src/lib/mcp/types/McpResourceServer.ts +12 -0
  101. package/src/lib/mcp/types/McpServer.ts +9 -0
  102. package/src/lib/mcp/types/McpServerOptions.ts +16 -0
  103. package/src/lib/server/AppModule.ts +33 -0
  104. package/src/lib/server/DELETE.ts +9 -0
  105. package/src/lib/server/GET.ts +9 -0
  106. package/src/lib/server/HEAD.ts +9 -0
  107. package/src/lib/server/PATCH.ts +9 -0
  108. package/src/lib/server/POST.ts +9 -0
  109. package/src/lib/server/PUT.ts +9 -0
  110. package/src/lib/server/agent.ts +76 -0
  111. package/src/lib/server/appDataDir.ts +15 -0
  112. package/src/lib/server/cli/buildEnvContent.ts +19 -0
  113. package/src/lib/server/cli/createTarGz.ts +76 -0
  114. package/src/lib/server/cli/handleCliDownload.ts +153 -0
  115. package/src/lib/server/cli/handleCliInstall.ts +37 -0
  116. package/src/lib/server/cli/installScript.ts +29 -0
  117. package/src/lib/server/cli/maxSourceMtime.ts +26 -0
  118. package/src/lib/server/cookies.ts +29 -0
  119. package/src/lib/server/env.ts +50 -0
  120. package/src/lib/server/error.ts +70 -0
  121. package/src/lib/server/json.ts +28 -0
  122. package/src/lib/server/jsonl.ts +46 -0
  123. package/src/lib/server/prompts/definePrompt.ts +20 -0
  124. package/src/lib/server/prompts/promptRegistry.ts +9 -0
  125. package/src/lib/server/prompts/registerPrompt.ts +6 -0
  126. package/src/lib/server/prompts/renderPromptTemplate.ts +16 -0
  127. package/src/lib/server/prompts/types/Prompt.ts +13 -0
  128. package/src/lib/server/prompts/types/PromptOptions.ts +12 -0
  129. package/src/lib/server/prompts/types/PromptRegistryEntry.ts +13 -0
  130. package/src/lib/server/prompts/types/PromptRoutes.ts +10 -0
  131. package/src/lib/server/redirect.ts +42 -0
  132. package/src/lib/server/request.ts +18 -0
  133. package/src/lib/server/rpc/defineVerb.ts +133 -0
  134. package/src/lib/server/rpc/dispatchVerbInProcess.ts +46 -0
  135. package/src/lib/server/rpc/findVerbByCommandName.ts +18 -0
  136. package/src/lib/server/rpc/parseArgs.ts +95 -0
  137. package/src/lib/server/rpc/registerVerb.ts +6 -0
  138. package/src/lib/server/rpc/types/RemoteHandler.ts +27 -0
  139. package/src/lib/server/rpc/types/RemoteRoutes.ts +13 -0
  140. package/src/lib/server/rpc/types/TypedResponse.ts +18 -0
  141. package/src/lib/server/rpc/types/VerbHelper.ts +68 -0
  142. package/src/lib/server/rpc/types/VerbRegistryEntry.ts +29 -0
  143. package/src/lib/server/rpc/unprocessed.ts +14 -0
  144. package/src/lib/server/rpc/verbRegistry.ts +11 -0
  145. package/src/lib/server/runtime/DEFAULT_PORT.ts +6 -0
  146. package/src/lib/server/runtime/DEV_REBUILD_MESSAGE.ts +4 -0
  147. package/src/lib/server/runtime/DEV_RELOAD_CLIENT_SCRIPT.ts +29 -0
  148. package/src/lib/server/runtime/acceptsZstd.ts +8 -0
  149. package/src/lib/server/runtime/buildOpenApiSpec.ts +106 -0
  150. package/src/lib/server/runtime/cacheControlForAsset.ts +22 -0
  151. package/src/lib/server/runtime/containsTraversal.ts +37 -0
  152. package/src/lib/server/runtime/createAssetHeaderCache.ts +35 -0
  153. package/src/lib/server/runtime/createPublicAssetServer.ts +63 -0
  154. package/src/lib/server/runtime/createRouteDispatcher.ts +100 -0
  155. package/src/lib/server/runtime/createServer.ts +692 -0
  156. package/src/lib/server/runtime/devReloadResponse.ts +35 -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 +35 -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/inProcessServer.ts +20 -0
  163. package/src/lib/server/runtime/internalErrorResponse.ts +25 -0
  164. package/src/lib/server/runtime/isCrossOriginUpgrade.ts +19 -0
  165. package/src/lib/server/runtime/listenOnOpenPort.ts +36 -0
  166. package/src/lib/server/runtime/logExposedSurfaces.ts +162 -0
  167. package/src/lib/server/runtime/mimeForExtension.ts +20 -0
  168. package/src/lib/server/runtime/parseIdleTimeout.ts +10 -0
  169. package/src/lib/server/runtime/parsePort.ts +11 -0
  170. package/src/lib/server/runtime/registryManifests.ts +66 -0
  171. package/src/lib/server/runtime/requestContext.ts +5 -0
  172. package/src/lib/server/runtime/resolveStreamResponse.ts +29 -0
  173. package/src/lib/server/runtime/runWithRequestScope.ts +57 -0
  174. package/src/lib/server/runtime/safeJsonForScript.ts +17 -0
  175. package/src/lib/server/runtime/serializeCacheSnapshot.ts +45 -0
  176. package/src/lib/server/runtime/serverSlot.ts +13 -0
  177. package/src/lib/server/runtime/setActiveServer.ts +6 -0
  178. package/src/lib/server/runtime/snapshotEntryFromCache.ts +81 -0
  179. package/src/lib/server/runtime/streamCacheResolutions.ts +37 -0
  180. package/src/lib/server/runtime/streamFromIterator.ts +86 -0
  181. package/src/lib/server/runtime/streamStash.ts +64 -0
  182. package/src/lib/server/runtime/types/Assets.ts +1 -0
  183. package/src/lib/server/runtime/types/RequestStore.ts +27 -0
  184. package/src/lib/server/runtime/withResponseDefaults.ts +24 -0
  185. package/src/lib/server/server.ts +32 -0
  186. package/src/lib/server/socket.ts +31 -0
  187. package/src/lib/server/sockets/createSocketDispatcher.ts +311 -0
  188. package/src/lib/server/sockets/defineSocket.ts +167 -0
  189. package/src/lib/server/sockets/lookupSocket.ts +6 -0
  190. package/src/lib/server/sockets/recentHistory.ts +11 -0
  191. package/src/lib/server/sockets/registerSocket.ts +6 -0
  192. package/src/lib/server/sockets/socketOperations.ts +35 -0
  193. package/src/lib/server/sockets/socketRegistry.ts +9 -0
  194. package/src/lib/server/sockets/types/Socket.ts +21 -0
  195. package/src/lib/server/sockets/types/SocketClientFrame.ts +18 -0
  196. package/src/lib/server/sockets/types/SocketOperation.ts +22 -0
  197. package/src/lib/server/sockets/types/SocketOptions.ts +22 -0
  198. package/src/lib/server/sockets/types/SocketRegistryEntry.ts +17 -0
  199. package/src/lib/server/sockets/types/SocketRoutes.ts +10 -0
  200. package/src/lib/server/sockets/types/SocketServerFrame.ts +15 -0
  201. package/src/lib/server/sse.ts +53 -0
  202. package/src/lib/shared/BELTE_PACKAGE_NAME.ts +7 -0
  203. package/src/lib/shared/CACHE_CONTROL_VALUES.ts +16 -0
  204. package/src/lib/shared/HttpError.ts +19 -0
  205. package/src/lib/shared/RESOLVE_STREAM_PATH.ts +7 -0
  206. package/src/lib/shared/STREAMING_CONTENT_TYPES.ts +11 -0
  207. package/src/lib/shared/activeCacheStore.ts +20 -0
  208. package/src/lib/shared/appDataDir.ts +34 -0
  209. package/src/lib/shared/belteImportName.ts +44 -0
  210. package/src/lib/shared/browserClientFlags.ts +10 -0
  211. package/src/lib/shared/buildRpcRequest.ts +70 -0
  212. package/src/lib/shared/bundleLayout.ts +36 -0
  213. package/src/lib/shared/bundled.ts +34 -0
  214. package/src/lib/shared/cache.ts +559 -0
  215. package/src/lib/shared/cacheStoreSlot.ts +16 -0
  216. package/src/lib/shared/canonicalJson.ts +63 -0
  217. package/src/lib/shared/carriesBodyArgs.ts +13 -0
  218. package/src/lib/shared/clearLastConnection.ts +7 -0
  219. package/src/lib/shared/commandNameForUrl.ts +17 -0
  220. package/src/lib/shared/createCacheStore.ts +75 -0
  221. package/src/lib/shared/createPushIterator.ts +93 -0
  222. package/src/lib/shared/createRemoteFunction.ts +99 -0
  223. package/src/lib/shared/decodeResponse.ts +47 -0
  224. package/src/lib/shared/detectTarget.ts +27 -0
  225. package/src/lib/shared/exeSuffix.ts +9 -0
  226. package/src/lib/shared/exitOnBuildFailure.ts +17 -0
  227. package/src/lib/shared/extraForwardHeaders.ts +16 -0
  228. package/src/lib/shared/fileStem.ts +9 -0
  229. package/src/lib/shared/findExportCallSite.ts +479 -0
  230. package/src/lib/shared/forwardHeaders.ts +41 -0
  231. package/src/lib/shared/getRemoteMeta.ts +5 -0
  232. package/src/lib/shared/globalCacheStore.ts +15 -0
  233. package/src/lib/shared/globalCacheStoreSlot.ts +14 -0
  234. package/src/lib/shared/importNamesToStrip.ts +13 -0
  235. package/src/lib/shared/invalidateEvent.ts +11 -0
  236. package/src/lib/shared/isCompileTarget.ts +15 -0
  237. package/src/lib/shared/isDebugEnabled.ts +23 -0
  238. package/src/lib/shared/isModuleNotFound.ts +16 -0
  239. package/src/lib/shared/isReadOnlyMethod.ts +14 -0
  240. package/src/lib/shared/isStreamingResponse.ts +11 -0
  241. package/src/lib/shared/jsonSchemaForPromptArguments.ts +29 -0
  242. package/src/lib/shared/jsonSchemaForSchema.ts +32 -0
  243. package/src/lib/shared/jsonlErrorFrame.ts +24 -0
  244. package/src/lib/shared/keyForRemoteCall.ts +29 -0
  245. package/src/lib/shared/lastConnectionPath.ts +7 -0
  246. package/src/lib/shared/loadEnvFile.ts +17 -0
  247. package/src/lib/shared/loadEnvFromDataDir.ts +15 -0
  248. package/src/lib/shared/loadSvelteConfig.ts +18 -0
  249. package/src/lib/shared/log.ts +104 -0
  250. package/src/lib/shared/manifestModule.ts +39 -0
  251. package/src/lib/shared/memoizeByKey.ts +24 -0
  252. package/src/lib/shared/nearestLayoutPrefix.ts +36 -0
  253. package/src/lib/shared/normalizeTarget.ts +10 -0
  254. package/src/lib/shared/pageUrlForFile.ts +14 -0
  255. package/src/lib/shared/parseBoundedEnvInt.ts +20 -0
  256. package/src/lib/shared/parseEnv.ts +30 -0
  257. package/src/lib/shared/parsePromptMarkdown.ts +34 -0
  258. package/src/lib/shared/parseRouteSegments.ts +22 -0
  259. package/src/lib/shared/prepareRpcModule.ts +59 -0
  260. package/src/lib/shared/prepareSocketModule.ts +49 -0
  261. package/src/lib/shared/programNameForPackage.ts +14 -0
  262. package/src/lib/shared/promptNameForFile.ts +10 -0
  263. package/src/lib/shared/queryStringFromArgs.ts +27 -0
  264. package/src/lib/shared/readEnvFile.ts +15 -0
  265. package/src/lib/shared/readLastConnection.ts +18 -0
  266. package/src/lib/shared/readPackageJson.ts +9 -0
  267. package/src/lib/shared/recordRemoteMeta.ts +5 -0
  268. package/src/lib/shared/remoteMetaStore.ts +16 -0
  269. package/src/lib/shared/resolveClientFlags.ts +20 -0
  270. package/src/lib/shared/responseErrorText.ts +9 -0
  271. package/src/lib/shared/rpcUrlForFile.ts +19 -0
  272. package/src/lib/shared/runningAsStandaloneBinary.ts +13 -0
  273. package/src/lib/shared/serializeEnv.ts +18 -0
  274. package/src/lib/shared/setCacheStoreResolver.ts +6 -0
  275. package/src/lib/shared/setGlobalCacheStoreResolver.ts +6 -0
  276. package/src/lib/shared/socketNameForFile.ts +11 -0
  277. package/src/lib/shared/sseErrorFrame.ts +29 -0
  278. package/src/lib/shared/streamResponse.ts +169 -0
  279. package/src/lib/shared/stripImport.ts +27 -0
  280. package/src/lib/shared/subscribableFromResponse.ts +51 -0
  281. package/src/lib/shared/toBunRoutePattern.ts +28 -0
  282. package/src/lib/shared/types/CacheEntry.ts +63 -0
  283. package/src/lib/shared/types/CacheInvalidation.ts +9 -0
  284. package/src/lib/shared/types/CacheOptions.ts +33 -0
  285. package/src/lib/shared/types/CacheSnapshot.ts +16 -0
  286. package/src/lib/shared/types/CacheSnapshotEntry.ts +15 -0
  287. package/src/lib/shared/types/CacheStore.ts +32 -0
  288. package/src/lib/shared/types/ClientFlags.ts +11 -0
  289. package/src/lib/shared/types/CompileTarget.ts +6 -0
  290. package/src/lib/shared/types/HttpVerb.ts +1 -0
  291. package/src/lib/shared/types/LastConnection.ts +9 -0
  292. package/src/lib/shared/types/PromptArgument.ts +12 -0
  293. package/src/lib/shared/types/RawRemoteFunction.ts +13 -0
  294. package/src/lib/shared/types/RemoteFunction.ts +42 -0
  295. package/src/lib/shared/types/StandardSchemaV1.ts +57 -0
  296. package/src/lib/shared/types/StreamedResolution.ts +10 -0
  297. package/src/lib/shared/types/StreamingPlaceholder.ts +13 -0
  298. package/src/lib/shared/types/Subscribable.ts +15 -0
  299. package/src/lib/shared/types/SvelteConfig.ts +5 -0
  300. package/src/lib/shared/withJsonSchema.ts +20 -0
  301. package/src/lib/shared/writeLastConnection.ts +13 -0
  302. package/src/lib/shared/writeRoutesDts.ts +67 -0
  303. package/src/lib/test/clearVerbRegistry.ts +11 -0
  304. package/src/lib/test/createTestClient.ts +78 -0
  305. package/src/preload.ts +20 -0
  306. package/src/scaffold.ts +92 -0
  307. package/src/serverBuildPlugins.ts +25 -0
  308. package/src/serverEntry.ts +94 -0
  309. package/src/sveltePlugin.ts +58 -0
  310. package/src/tailwindStylePreprocessor.ts +62 -0
  311. package/template/bunfig.toml +4 -0
  312. package/template/package.json +19 -0
  313. package/template/src/app.ts +23 -0
  314. package/template/src/browser/app.css +21 -0
  315. package/template/src/browser/app.html +24 -0
  316. package/template/src/browser/pages/about/page.svelte +5 -0
  317. package/template/src/browser/pages/layout.svelte +26 -0
  318. package/template/src/browser/pages/page.svelte +20 -0
  319. package/template/src/bundle/icon.png +0 -0
  320. package/template/src/cli/banner.txt +3 -0
  321. package/template/src/cli/footer.txt +1 -0
  322. package/template/src/server/config.ts +17 -0
  323. package/template/src/server/rpc/getHello.ts +35 -0
  324. package/template/svelte.config.js +12 -0
  325. package/template/tsconfig.json +18 -0
  326. package/tsconfig.app.json +16 -0
@@ -0,0 +1,42 @@
1
+ /*
2
+ Redirect Response with belte-friendly ergonomics — accepts relative
3
+ URLs (the platform's `Response.redirect` throws on them), defaults to
4
+ 302, and matches the helper-style call site of `json`/`error` for
5
+ visual consistency inside a handler.
6
+
7
+ return redirect('/login') // 302 to /login
8
+ return redirect('/articles/1', 301) // permanent
9
+ return redirect(externalUrl, 307) // preserve method (POST stays POST)
10
+
11
+ Status guidance:
12
+ - 301 — moved permanently (cacheable; browsers may swap method to GET)
13
+ - 302 — found / temporary (default; browsers may swap method to GET)
14
+ - 303 — "after a POST, GET this" (forces GET on the follow-up)
15
+ - 307 — temporary, preserve method
16
+ - 308 — permanent, preserve method
17
+
18
+ A final `ResponseInit` adds headers (e.g. a `Set-Cookie` on the redirect);
19
+ the positional `status` always wins over any `init.status`.
20
+ */
21
+ import { NO_STORE } from '../shared/CACHE_CONTROL_VALUES.ts'
22
+ import type { TypedResponse } from './rpc/types/TypedResponse.ts'
23
+ import { withResponseDefaults } from './runtime/withResponseDefaults.ts'
24
+
25
+ type RedirectStatus = 301 | 302 | 303 | 307 | 308
26
+
27
+ /*
28
+ Return type is `TypedResponse<never>` for the same reason `error()` is —
29
+ the wire response is a 3xx with no body the caller resolves to, so it
30
+ must not pollute the inferred `Return` of a route that conditionally
31
+ redirects vs returns json.
32
+ */
33
+ export function redirect(
34
+ url: string,
35
+ status: RedirectStatus = 302,
36
+ init?: ResponseInit,
37
+ ): TypedResponse<never> {
38
+ return new Response(
39
+ null,
40
+ withResponseDefaults(init, { Location: url, 'Cache-Control': NO_STORE }, status),
41
+ ) as TypedResponse<never>
42
+ }
@@ -0,0 +1,18 @@
1
+ import { requestContext } from './runtime/requestContext.ts'
2
+
3
+ /*
4
+ Returns the inbound Request for the current SSR/RPC pass. Implemented as an
5
+ AsyncLocalStorage lookup over the per-request store the server installs at
6
+ the fetch boundary. Throws if called outside a request scope (e.g. from
7
+ top-level module code or from app.ts init) — silent undefined would mask
8
+ the misuse.
9
+ */
10
+ export function request(): Request {
11
+ const store = requestContext.getStore()
12
+ if (!store) {
13
+ throw new Error(
14
+ '[belte] request() called outside a request scope — it only resolves while an SSR render or rpc handler is in flight',
15
+ )
16
+ }
17
+ return store.req
18
+ }
@@ -0,0 +1,133 @@
1
+ import { buildRpcRequest } from '../../shared/buildRpcRequest.ts'
2
+ import { createRemoteFunction } from '../../shared/createRemoteFunction.ts'
3
+ import { forwardHeaders } from '../../shared/forwardHeaders.ts'
4
+ import { isReadOnlyMethod } from '../../shared/isReadOnlyMethod.ts'
5
+ import { resolveClientFlags } from '../../shared/resolveClientFlags.ts'
6
+ import type { ClientFlags } from '../../shared/types/ClientFlags.ts'
7
+ import type { HttpVerb } from '../../shared/types/HttpVerb.ts'
8
+ import type { RemoteFunction } from '../../shared/types/RemoteFunction.ts'
9
+ import type { StandardSchemaV1 } from '../../shared/types/StandardSchemaV1.ts'
10
+ import { json } from '../json.ts'
11
+ import { requestContext } from '../runtime/requestContext.ts'
12
+ import { parseArgs } from './parseArgs.ts'
13
+ import { registerVerb } from './registerVerb.ts'
14
+ import type { RemoteHandler } from './types/RemoteHandler.ts'
15
+
16
+ /*
17
+ Builds a RemoteFunction from an HTTP verb + RPC URL + handler. The bundler
18
+ rewrites every `export const VERB = handler(fn)` inside an `$rpc/**` module
19
+ so the verb (from the export name) and the URL (from the file path under
20
+ `src/server/rpc/`, with `/rpc/` prefix) are threaded into defineVerb.
21
+
22
+ The plain call (`fn(args)`) resolves to the Content-Type-decoded body;
23
+ non-2xx responses throw HttpError. `.raw(args)` returns the underlying
24
+ Response for callers that need status/headers/body streaming.
25
+ `.fetch(req)` is the dispatch hook the framework's router uses to
26
+ invoke the handler from an incoming HTTP request (with args parsed off
27
+ the Request via parseArgs).
28
+
29
+ Every raw invocation records the synthesized Request against the returned
30
+ promise so cache() can stash it on the entry without re-building.
31
+ */
32
+ export function defineVerb<Args, Return>(
33
+ method: HttpVerb,
34
+ url: string,
35
+ handler: RemoteHandler<Args, Return>,
36
+ opts?: {
37
+ inputSchema?: StandardSchemaV1
38
+ outputSchema?: StandardSchemaV1
39
+ filesSchema?: StandardSchemaV1
40
+ clients?: Partial<ClientFlags>
41
+ },
42
+ ): RemoteFunction<Args, Return> {
43
+ const inputSchema = opts?.inputSchema
44
+ const outputSchema = opts?.outputSchema
45
+ const filesSchema = opts?.filesSchema
46
+ /*
47
+ An input schema makes the handler safe to advertise to non-browser
48
+ surfaces. CLI flips on for any verb with one (a human/script invokes it
49
+ deliberately). MCP only auto-exposes read-only verbs (GET/HEAD) — a
50
+ model shouldn't be able to mutate/delete just because the handler
51
+ carries a schema, so mutating verbs require an explicit clients.mcp.
52
+ Explicit `clients` always wins.
53
+ */
54
+ const hasSchema = inputSchema !== undefined
55
+ const clients = resolveClientFlags(opts?.clients, {
56
+ mcp: hasSchema && isReadOnlyMethod(method),
57
+ cli: hasSchema,
58
+ })
59
+
60
+ function buildRequest(args: Args | undefined): Request {
61
+ const store = requestContext.getStore()
62
+ const baseUrl = store ? store.url.href : 'http://localhost/'
63
+ const headers = store ? forwardHeaders(store.req.headers) : new Headers()
64
+ return buildRpcRequest({ method, url, args, baseUrl, headers })
65
+ }
66
+
67
+ /*
68
+ Handler bodies may throw synchronously (e.g. an `assert(...)` at the
69
+ top of the function). The `async function` wrapper coerces both sync
70
+ throws and returned non-promises into the Promise<Response> shape
71
+ callers expect, so an SSR caller's `await` always sees the rejection
72
+ through the cache layer's snapshot boundary instead of the error
73
+ escaping the request scope.
74
+ */
75
+ async function runHandler(args: Args | undefined): Promise<Response> {
76
+ return handler(args as Args) as unknown as Response
77
+ }
78
+
79
+ /*
80
+ Validates the parsed args against inputSchema (text fields), then — when the
81
+ verb declares filesSchema — validates the File parts parseArgs split onto
82
+ the request store and merges them into the args bag the handler receives.
83
+ Either schema's issues become a 422. Files stay out of inputSchema so its
84
+ JSON-Schema projection (OpenAPI/MCP/CLI) never has to model a binary.
85
+ */
86
+ async function validateThenHandle(args: Args | undefined): Promise<Response> {
87
+ let value: unknown = args
88
+ if (inputSchema) {
89
+ const result = await inputSchema['~standard'].validate(value)
90
+ if (result.issues) {
91
+ return json({ issues: result.issues }, { status: 422 })
92
+ }
93
+ value = result.value
94
+ }
95
+ if (filesSchema) {
96
+ const files = requestContext.getStore()?.files ?? {}
97
+ const result = await filesSchema['~standard'].validate(files)
98
+ if (result.issues) {
99
+ return json({ issues: result.issues }, { status: 422 })
100
+ }
101
+ value = { ...(value as object), ...(result.value as object) }
102
+ }
103
+ return runHandler(value as Args)
104
+ }
105
+
106
+ /*
107
+ `getRequest` is unused on the server path — handlers receive parsed
108
+ `args` directly and reach the inbound Request via `request()`.
109
+ createRemoteFunction passes a thunk so the client side can lazily
110
+ synthesize its Request without forcing the server to allocate one per
111
+ SSR call.
112
+ */
113
+ function invoke(args: Args | undefined): Promise<Response> {
114
+ return inputSchema || filesSchema ? validateThenHandle(args) : runHandler(args)
115
+ }
116
+
117
+ const remote = createRemoteFunction<Args, Return>({
118
+ method,
119
+ url,
120
+ clients,
121
+ buildRequest,
122
+ invoke,
123
+ parseArgsForFetch: (request) => parseArgs(method, request) as Promise<Args | undefined>,
124
+ })
125
+ registerVerb({
126
+ remote: remote as RemoteFunction<unknown, unknown>,
127
+ inputSchema,
128
+ outputSchema,
129
+ filesSchema,
130
+ clients,
131
+ })
132
+ return remote
133
+ }
@@ -0,0 +1,46 @@
1
+ import { buildRpcRequest } from '../../shared/buildRpcRequest.ts'
2
+ import type { AppModule } from '../AppModule.ts'
3
+ import { runWithRequestScope } from '../runtime/runWithRequestScope.ts'
4
+ import type { VerbRegistryEntry } from './types/VerbRegistryEntry.ts'
5
+
6
+ /*
7
+ Runs a registered verb in-process: synthesizes the rpc Request from the
8
+ entry's own method + url and pipes it through entry.remote.fetch — the
9
+ same handler/validation/error path the HTTP router uses, no network hop.
10
+ The single in-process dispatch every registry-backed consumer surface (the
11
+ CLI client, the MCP tool dispatcher, and the test client) routes through, so
12
+ they can't drift on how a verb is invoked. `baseUrl` gives the synthetic
13
+ Request its origin (handlers reading request.url see the caller's host);
14
+ `headers` carries forwarded auth/identity context.
15
+
16
+ Runs inside the runWithRequestScope seam createServer crosses for real
17
+ requests, so a handler sees an identical scope to a live HTTP request: a fresh
18
+ per-request cache, the cookie jar with Set-Cookie flush, request()/server()
19
+ resolution, and the app's handleError (or the 500 fallback) on a throw. The
20
+ synthesized Request is shared between the scope store and the handler fetch so
21
+ request() returns the same Request parseArgs read from.
22
+ */
23
+ export function dispatchVerbInProcess({
24
+ entry,
25
+ args,
26
+ baseUrl,
27
+ headers,
28
+ app,
29
+ }: {
30
+ entry: VerbRegistryEntry
31
+ args: unknown
32
+ baseUrl: string
33
+ headers?: Headers
34
+ app?: AppModule
35
+ }): Promise<Response> {
36
+ const request = buildRpcRequest({
37
+ method: entry.remote.method,
38
+ url: entry.remote.url,
39
+ args,
40
+ baseUrl,
41
+ headers,
42
+ })
43
+ return runWithRequestScope(request, { app, logRequests: false }, () =>
44
+ entry.remote.fetch(request),
45
+ )
46
+ }
@@ -0,0 +1,18 @@
1
+ import { commandNameForUrl } from '../../shared/commandNameForUrl.ts'
2
+ import type { VerbRegistryEntry } from './types/VerbRegistryEntry.ts'
3
+ import { verbRegistry } from './verbRegistry.ts'
4
+
5
+ /*
6
+ Finds the registered verb whose URL maps to a given command name (folder
7
+ segments joined with `-`, per commandNameForUrl). The CLI client proxy and
8
+ the MCP tool dispatcher both key off this name, so the scan lives here once
9
+ rather than being re-implemented — and reused — at each call site.
10
+ */
11
+ export function findVerbByCommandName(name: string): VerbRegistryEntry | undefined {
12
+ for (const entry of verbRegistry.values()) {
13
+ if (commandNameForUrl(entry.remote.url) === name) {
14
+ return entry
15
+ }
16
+ }
17
+ return undefined
18
+ }
@@ -0,0 +1,95 @@
1
+ import { carriesBodyArgs } from '../../shared/carriesBodyArgs.ts'
2
+ import type { HttpVerb } from '../../shared/types/HttpVerb.ts'
3
+ import { requestContext } from '../runtime/requestContext.ts'
4
+
5
+ /*
6
+ Splits a parsed FormData into the text fields that become args and the File
7
+ parts that don't. Repeated text keys collapse into an array (an HTML form posts
8
+ multiple same-named inputs); File parts group by field name and stash on the
9
+ request store for files() to read — they never enter args, so the input schema
10
+ keeps validating a plain object with no binary in it.
11
+ */
12
+ function splitFormData(form: FormData): Record<string, unknown> {
13
+ const fileMap: Record<string, File[]> = {}
14
+ const fields: Record<string, unknown> = {}
15
+ for (const [key, value] of form) {
16
+ if (value instanceof File) {
17
+ fileMap[key] ??= []
18
+ fileMap[key].push(value)
19
+ continue
20
+ }
21
+ const existing = fields[key]
22
+ if (!(key in fields)) {
23
+ fields[key] = value
24
+ } else if (Array.isArray(existing)) {
25
+ existing.push(value)
26
+ } else {
27
+ fields[key] = [existing, value]
28
+ }
29
+ }
30
+ const store = requestContext.getStore()
31
+ if (store && Object.keys(fileMap).length > 0) {
32
+ store.files = fileMap
33
+ }
34
+ return fields
35
+ }
36
+
37
+ /*
38
+ Parses + merges every source of args available for a verb-defined handler:
39
+ - body (json or form-encoded, ignored for GET/DELETE/HEAD)
40
+ - url query string
41
+
42
+ When both are present and the body is a plain object, the merge layers the
43
+ body on top of the query so the typed body wins on collision — the query
44
+ supplies defaults a body field can override, and a URL param can't silently
45
+ shadow a validated body value. A non-object body (array, primitive, null)
46
+ skips the merge entirely and is returned as-is — there's no key on the body
47
+ to layer the query into, and the framework's args type is a single bag rather
48
+ than a `{body, query}` envelope. Returns undefined when no source contributes
49
+ any key.
50
+ */
51
+ export async function parseArgs(method: HttpVerb, request: Request): Promise<unknown> {
52
+ /*
53
+ Skip the URL parse entirely when the raw request URL has no query —
54
+ typical POST/PUT/PATCH calls land here with a flat rpc URL and no
55
+ `?…`, so the `new URL(...)` constructor cost (which dwarfs the
56
+ indexOf check) is wasted work.
57
+ */
58
+ const queryStart = request.url.indexOf('?')
59
+ const hasQuery = queryStart !== -1
60
+ const url = hasQuery ? new URL(request.url) : undefined
61
+
62
+ let body: unknown
63
+ if (carriesBodyArgs(method)) {
64
+ const contentType = (request.headers.get('content-type') ?? '').toLowerCase()
65
+ if (contentType.includes('application/json')) {
66
+ const text = await request.text()
67
+ if (text !== '') {
68
+ body = JSON.parse(text)
69
+ }
70
+ } else if (
71
+ contentType.includes('application/x-www-form-urlencoded') ||
72
+ contentType.includes('multipart/form-data')
73
+ ) {
74
+ body = splitFormData(await request.formData())
75
+ }
76
+ }
77
+
78
+ if (body !== undefined && (typeof body !== 'object' || body === null || Array.isArray(body))) {
79
+ return body
80
+ }
81
+
82
+ if (!url) {
83
+ if (body === undefined) {
84
+ return undefined
85
+ }
86
+ return body
87
+ }
88
+
89
+ const bodyObject = (body ?? {}) as Record<string, unknown>
90
+ const merged = { ...Object.fromEntries(url.searchParams), ...bodyObject }
91
+ if (Object.keys(merged).length === 0) {
92
+ return undefined
93
+ }
94
+ return merged
95
+ }
@@ -0,0 +1,6 @@
1
+ import type { VerbRegistryEntry } from './types/VerbRegistryEntry.ts'
2
+ import { verbRegistry } from './verbRegistry.ts'
3
+
4
+ export function registerVerb(entry: VerbRegistryEntry): void {
5
+ verbRegistry.set(entry.remote.url, entry)
6
+ }
@@ -0,0 +1,27 @@
1
+ import type { TypedResponse } from './TypedResponse.ts'
2
+
3
+ /*
4
+ Handler signature for verb-defined remote functions. Args is `undefined` for
5
+ GETs/DELETEs with no query, JSON-shaped objects for json bodies, and
6
+ form-shaped objects for form-encoded bodies. For a multipart upload it's the
7
+ text fields (`inputSchema`) intersected with the validated File parts
8
+ (`filesSchema`), merged into one bag. For a raw binary body Args is `undefined`
9
+ — read the stream via `request()` from `belte/server` instead.
10
+
11
+ Return is the value type the call site sees after Content-Type-driven
12
+ decoding (a parsed object for JSON, a string for text/*, a Blob otherwise,
13
+ `undefined` for 204). The handler must return a Response at runtime; the
14
+ `TypedResponse<Return>` brand on `json`/`error`/`redirect`/`jsonl`/`sse`
15
+ carries the body shape through the function's inferred return type so the
16
+ verb helper can infer `Return` automatically — no need to annotate
17
+ `GET<Args, Return>` when the handler returns one of the respond helpers.
18
+ A bare `new Response(...)` is still acceptable: the brand is optional, so
19
+ untagged Responses fall back to `Return = unknown`.
20
+
21
+ Handlers that need the inbound Request (headers, `request.signal`, …) read
22
+ it via `request()` from `belte/server` rather than a handler parameter, so
23
+ the signature stays a single parsed-`args` bag.
24
+ */
25
+ export type RemoteHandler<Args, Return> = (
26
+ args: Args,
27
+ ) => TypedResponse<Return> | Promise<TypedResponse<Return>>
@@ -0,0 +1,13 @@
1
+ import type { RemoteFunction } from '../../../shared/types/RemoteFunction.ts'
2
+
3
+ /*
4
+ Manifest of RPC URL → module loader. Produced by the resolver plugin from
5
+ every `.ts` under src/server/rpc — each file maps to one URL (derived from its
6
+ path under `$rpc`, prefixed with `/rpc/`). Each module has exactly one
7
+ named export, a RemoteFunction whose `.method` and `.url` were stamped in
8
+ by the bundler rewrite.
9
+ */
10
+ export type RemoteRoutes = Record<
11
+ string,
12
+ () => Promise<Record<string, RemoteFunction<unknown, unknown>>>
13
+ >
@@ -0,0 +1,18 @@
1
+ /*
2
+ A `Response` tagged with the body type the framework will hand back to
3
+ callers after Content-Type-driven decoding. The tag is phantom — it
4
+ adds no runtime field, only a type-level slot so the verb helpers can
5
+ infer `Return` from the handler's return type instead of forcing every
6
+ route to annotate it via `GET<Args, Return>`.
7
+
8
+ The respond helpers (`json<T>`, `error`, `redirect`, `jsonl<F>`,
9
+ `sse<F>`) all return a `TypedResponse<T>`, so a handler ending in
10
+ `return json({ user })` exposes `{ user: ... }` as its body type; the
11
+ verb overload picks it up via `RemoteHandler<Args, Return>`.
12
+
13
+ `T` is optional on the brand so a plain `new Response(...)` (untagged)
14
+ remains assignable to `TypedResponse<unknown>`; in that case `Return`
15
+ just falls back to its `unknown` default, matching pre-existing
16
+ behaviour for handlers that build Responses by hand.
17
+ */
18
+ export type TypedResponse<T> = Response & { readonly __body?: T }
@@ -0,0 +1,68 @@
1
+ import type { ClientFlags } from '../../../shared/types/ClientFlags.ts'
2
+ import type { RemoteFunction } from '../../../shared/types/RemoteFunction.ts'
3
+ import type { StandardSchemaV1 } from '../../../shared/types/StandardSchemaV1.ts'
4
+ import type { RemoteHandler } from './RemoteHandler.ts'
5
+
6
+ /*
7
+ Shared signature for every verb helper (GET / POST / …). Three overloads:
8
+
9
+ - `Verb(fn, { inputSchema, outputSchema?, clients? })` — `Args` infers
10
+ from `InferInput<InputSchema>`, the handler receives
11
+ `InferOutput<InputSchema>`. Generic order is `<Return, InputSchema>` so
12
+ users can override `Return` while letting `InputSchema` infer from
13
+ `opts.inputSchema`. `outputSchema` is an optional Standard Schema for
14
+ the success body — it feeds the OpenAPI 200 response and the MCP tool
15
+ `outputSchema`. JSON Schema is projected from each schema's own
16
+ `toJSONSchema()` (wrap with withJsonSchema if the library lacks one).
17
+ `clients` controls which surfaces (browser / mcp / cli) expose this verb.
18
+ - `Verb(fn, { clients })` — schemaless but with explicit client
19
+ targeting (e.g. server-internal RPC with `clients: { browser: false }`).
20
+ - `Verb(fn)` — bare handler. `Args` and `Return` come from the handler
21
+ type; `Return` is usually inferred via the `TypedResponse<T>` brand on
22
+ `json`/`error`/`redirect`/`jsonl`/`sse`.
23
+ */
24
+ export type VerbHelper = {
25
+ /*
26
+ `Verb(fn, { inputSchema, filesSchema, … })` — multipart upload. The
27
+ handler receives the text fields (`InferOutput<InputSchema>`) intersected
28
+ with the validated File parts (`InferOutput<FilesSchema>`); both are merged
29
+ into one args bag. The call site sends a FormData (RemoteFunction's call
30
+ accepts it), since a File can't ride a JSON body. filesSchema stays off the
31
+ JSON-Schema projection — a File has no honest conversion (see
32
+ jsonSchemaForSchema) — so only inputSchema feeds MCP/CLI/OpenAPI.
33
+ */
34
+ <
35
+ Return = unknown,
36
+ InputSchema extends StandardSchemaV1 = StandardSchemaV1,
37
+ FilesSchema extends StandardSchemaV1 = StandardSchemaV1,
38
+ >(
39
+ fn: RemoteHandler<
40
+ StandardSchemaV1.InferOutput<InputSchema> & StandardSchemaV1.InferOutput<FilesSchema>,
41
+ Return
42
+ >,
43
+ opts: {
44
+ inputSchema: InputSchema
45
+ filesSchema: FilesSchema
46
+ outputSchema?: StandardSchemaV1
47
+ clients?: Partial<ClientFlags>
48
+ },
49
+ ): RemoteFunction<StandardSchemaV1.InferInput<InputSchema>, Return>
50
+ <Return = unknown, InputSchema extends StandardSchemaV1 = StandardSchemaV1>(
51
+ fn: RemoteHandler<StandardSchemaV1.InferOutput<InputSchema>, Return>,
52
+ opts: {
53
+ inputSchema: InputSchema
54
+ outputSchema?: StandardSchemaV1
55
+ clients?: Partial<ClientFlags>
56
+ },
57
+ ): RemoteFunction<StandardSchemaV1.InferInput<InputSchema>, Return>
58
+ <Args = undefined, Return = unknown>(
59
+ fn: RemoteHandler<Args, Return>,
60
+ opts: {
61
+ outputSchema?: StandardSchemaV1
62
+ clients: Partial<ClientFlags>
63
+ },
64
+ ): RemoteFunction<Args, Return>
65
+ <Args = undefined, Return = unknown>(
66
+ fn: RemoteHandler<Args, Return>,
67
+ ): RemoteFunction<Args, Return>
68
+ }
@@ -0,0 +1,29 @@
1
+ import type { ClientFlags } from '../../../shared/types/ClientFlags.ts'
2
+ import type { RemoteFunction } from '../../../shared/types/RemoteFunction.ts'
3
+ import type { StandardSchemaV1 } from '../../../shared/types/StandardSchemaV1.ts'
4
+
5
+ /*
6
+ Per-verb registry record on the server side. MCP and CLI enumerate this
7
+ to discover which RPCs are advertised (clients flags) and what shapes
8
+ they expect/return. The schemas and resolved clients stay off the public
9
+ RemoteFunction shape so the browser-side proxy doesn't need to carry
10
+ server-only state.
11
+
12
+ `inputSchema` validates the argument bag and feeds the MCP tool
13
+ `inputSchema` / OpenAPI parameters; `outputSchema` describes the success
14
+ body and feeds the OpenAPI 200 response + MCP tool `outputSchema`. Each
15
+ projects to JSON Schema via its own `toJSONSchema()` (jsonSchemaForSchema) —
16
+ schemas whose library lacks one are wrapped with withJsonSchema.
17
+
18
+ `filesSchema` validates the File parts of a multipart body, kept separate
19
+ from `inputSchema` because a File has no honest JSON-Schema conversion — it
20
+ stays out of the MCP/CLI projection that `inputSchema` feeds, and the OpenAPI
21
+ multipart body advertises the file parts generically as binary.
22
+ */
23
+ export type VerbRegistryEntry = {
24
+ remote: RemoteFunction<unknown, unknown>
25
+ inputSchema: StandardSchemaV1 | undefined
26
+ outputSchema: StandardSchemaV1 | undefined
27
+ filesSchema: StandardSchemaV1 | undefined
28
+ clients: ClientFlags
29
+ }
@@ -0,0 +1,14 @@
1
+ import type { RemoteFunction } from '../../shared/types/RemoteFunction.ts'
2
+
3
+ /*
4
+ Verb helpers (GET / POST / …) are placeholders — the bundler rewrites every
5
+ `export const x = GET(fn)` inside `src/server/rpc/<file>.ts` into a call to
6
+ defineVerb (server target) or remoteProxy (client target). If a call slips
7
+ through, the bundler plugin didn't process the file; throwing here surfaces
8
+ that cleanly instead of silently returning undefined.
9
+ */
10
+ export function unprocessed<Args, Return>(verb: string): RemoteFunction<Args, Return> {
11
+ throw new Error(
12
+ `[belte] \`${verb}\` was called outside an $rpc module — verb helpers are only valid as the value of \`export const <filename> = ...\` inside a file under src/server/rpc/`,
13
+ )
14
+ }
@@ -0,0 +1,11 @@
1
+ import type { VerbRegistryEntry } from './types/VerbRegistryEntry.ts'
2
+
3
+ /*
4
+ Process-wide registry of every verb-bound RPC declared in the app.
5
+ defineVerb inserts on first construction (which happens at module-load
6
+ time inside the rpc dispatcher cache or eagerly when MCP / CLI walks the
7
+ rpc manifest). MCP server reads this to build its tools list; the CLI
8
+ binary reads it to generate subcommands. The browser path never touches
9
+ this — the client stub has no schema or clients metadata to register.
10
+ */
11
+ export const verbRegistry = new Map<string, VerbRegistryEntry>()
@@ -0,0 +1,6 @@
1
+ /*
2
+ The port scanning starts from when no PORT is configured. Every selector (the
3
+ real listener, the embedded launcher, the dev orchestrator) scans upward from
4
+ here so all modes land on the same predictable 3000+ address.
5
+ */
6
+ export const DEFAULT_PORT = 3000
@@ -0,0 +1,4 @@
1
+ // IPC payload the dev server sends its orchestrator parent (via process.send) to
2
+ // request a rebuild + restart. Shared so producer (createServer) and consumer
3
+ // (devEntry) can't drift.
4
+ export const DEV_REBUILD_MESSAGE = 'belte:reload'
@@ -0,0 +1,29 @@
1
+ /*
2
+ Dev-only live-reload client, injected into the served shell when the server
3
+ runs under `belte dev`. It opens an EventSource to /__belte/dev and reloads on
4
+ *reconnect*: the channel only drops when the dev orchestrator restarts the
5
+ server after a rebuild, so re-establishing the connection is the signal that
6
+ fresh code is being served. The first open is the initial page load (no
7
+ reload); every open after that is a restart. Self-managed retry keeps the gap
8
+ short instead of relying on EventSource's multi-second default backoff.
9
+ */
10
+ export const DEV_RELOAD_CLIENT_SCRIPT = `<script>
11
+ ;(() => {
12
+ let opened = false
13
+ function connect() {
14
+ const source = new EventSource('/__belte/dev')
15
+ source.onopen = () => {
16
+ if (opened) {
17
+ location.reload()
18
+ return
19
+ }
20
+ opened = true
21
+ }
22
+ source.onerror = () => {
23
+ source.close()
24
+ setTimeout(connect, 250)
25
+ }
26
+ }
27
+ connect()
28
+ })()
29
+ </script>`
@@ -0,0 +1,8 @@
1
+ /*
2
+ Whether the client advertised zstd in Accept-Encoding. Both static-asset
3
+ servers (the `/_app/` chunk server and the public/ server) gate their
4
+ pre-compressed responses on this, so the check lives in one place.
5
+ */
6
+ export function acceptsZstd(req: Request): boolean {
7
+ return (req.headers.get('accept-encoding') ?? '').toLowerCase().includes('zstd')
8
+ }