@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,106 @@
1
+ import { carriesBodyArgs } from '../../shared/carriesBodyArgs.ts'
2
+ import { commandNameForUrl } from '../../shared/commandNameForUrl.ts'
3
+ import { jsonSchemaForSchema } from '../../shared/jsonSchemaForSchema.ts'
4
+ import { verbRegistry } from '../rpc/verbRegistry.ts'
5
+
6
+ /*
7
+ Turns a verb's resolved JSON Schema into OpenAPI query parameters — one
8
+ per top-level property, marked required when the schema lists it. Used
9
+ for GET/DELETE/HEAD operations, which carry their args on the query
10
+ string (mirroring buildRpcRequest).
11
+ */
12
+ function queryParameters(jsonSchema: Record<string, unknown>): Array<Record<string, unknown>> {
13
+ const properties = jsonSchema.properties as Record<string, unknown> | undefined
14
+ if (!properties) {
15
+ return []
16
+ }
17
+ const required = new Set((jsonSchema.required as string[] | undefined) ?? [])
18
+ return Object.entries(properties).map(([name, schema]) => ({
19
+ name,
20
+ in: 'query',
21
+ required: required.has(name),
22
+ schema,
23
+ }))
24
+ }
25
+
26
+ /*
27
+ Request body schema for a multipart upload verb: the text fields from
28
+ inputSchema, plus the binary parts. A File has no honest
29
+ Standard-Schema→JSON-Schema conversion, so the file parts are advertised
30
+ generically as additional binary properties rather than named per field.
31
+ */
32
+ function multipartBodySchema(textSchema: Record<string, unknown>): Record<string, unknown> {
33
+ const textProperties = (textSchema.properties as Record<string, unknown> | undefined) ?? {}
34
+ const schema: Record<string, unknown> = {
35
+ type: 'object',
36
+ properties: { ...textProperties },
37
+ additionalProperties: { type: 'string', format: 'binary' },
38
+ }
39
+ const required = (textSchema.required as string[] | undefined) ?? []
40
+ if (required.length > 0) {
41
+ schema.required = required
42
+ }
43
+ return schema
44
+ }
45
+
46
+ /*
47
+ Builds an OpenAPI 3.1 document from the verb registry — the HTTP surface
48
+ every rpc exposes regardless of which non-browser clients it advertises.
49
+ GET/DELETE/HEAD args become query parameters; POST/PUT/PATCH args become
50
+ a JSON request body. operationId is the folder-prefixed command name so
51
+ it lines up with the MCP tool / CLI subcommand identifiers.
52
+ */
53
+ export function buildOpenApiSpec(info: {
54
+ title: string
55
+ version: string
56
+ }): Record<string, unknown> {
57
+ const paths: Record<string, Record<string, unknown>> = {}
58
+ for (const entry of verbRegistry.values()) {
59
+ const url = entry.remote.url
60
+ const method = entry.remote.method
61
+ const jsonSchema = jsonSchemaForSchema(entry.inputSchema)
62
+ const description = jsonSchema.description as string | undefined
63
+ /*
64
+ When the verb declares an `outputSchema`, describe the 200 body
65
+ with it so external tooling sees the real return shape; otherwise
66
+ fall back to a bare OK.
67
+ */
68
+ const okResponse: Record<string, unknown> = { description: 'OK' }
69
+ if (entry.outputSchema) {
70
+ okResponse.content = {
71
+ 'application/json': {
72
+ schema: jsonSchemaForSchema(entry.outputSchema),
73
+ },
74
+ }
75
+ }
76
+ const operation: Record<string, unknown> = {
77
+ operationId: commandNameForUrl(url),
78
+ ...(description ? { description } : {}),
79
+ responses: { '200': okResponse },
80
+ }
81
+ if (carriesBodyArgs(method)) {
82
+ operation.requestBody = entry.filesSchema
83
+ ? {
84
+ content: {
85
+ 'multipart/form-data': {
86
+ schema: multipartBodySchema(jsonSchema),
87
+ },
88
+ },
89
+ }
90
+ : { content: { 'application/json': { schema: jsonSchema } } }
91
+ } else {
92
+ const parameters = queryParameters(jsonSchema)
93
+ if (parameters.length > 0) {
94
+ operation.parameters = parameters
95
+ }
96
+ }
97
+ paths[url] ??= {}
98
+ const path = paths[url]
99
+ path[method.toLowerCase()] = operation
100
+ }
101
+ return {
102
+ openapi: '3.1.0',
103
+ info: { title: info.title, version: info.version },
104
+ paths,
105
+ }
106
+ }
@@ -0,0 +1,22 @@
1
+ import {
2
+ IMMUTABLE_ASSET_CACHE_CONTROL,
3
+ REVALIDATE_ASSET_CACHE_CONTROL,
4
+ } from '../../shared/CACHE_CONTROL_VALUES.ts'
5
+
6
+ /*
7
+ Bun.build emits `[name]-[hash].[ext]` for chunks; hash is alnum and >=8 chars.
8
+ Source maps inherit the same name (e.g. foo-abc12345.js.map), so the suffix may be `.map`.
9
+ */
10
+ const HASHED = /-[a-z0-9]{8,}\.[a-z0-9]+(\.map)?$/i
11
+
12
+ /*
13
+ Returns the right `Cache-Control` for an asset path served under `/_app/`.
14
+ Hashed chunk filenames are content-addressed and immutable; everything else
15
+ (the entry bundle, the html shell, etc.) must revalidate every time.
16
+ */
17
+ export function cacheControlForAsset(pathname: string): string {
18
+ if (HASHED.test(pathname)) {
19
+ return IMMUTABLE_ASSET_CACHE_CONTROL
20
+ }
21
+ return REVALIDATE_ASSET_CACHE_CONTROL
22
+ }
@@ -0,0 +1,37 @@
1
+ /*
2
+ Inspects the raw request URL (not the parsed pathname) for path-traversal
3
+ patterns. The WHATWG URL parser decodes `%2E%2E` to `..` and then collapses
4
+ dot-segments out of the pathname during normalization, so by the time
5
+ `url.pathname` is observable any encoded traversal has been masked. The
6
+ remaining literal `..` check guards against any future URL-parser quirk
7
+ that lets a normalised path through.
8
+
9
+ Hot path early-out: if none of the suspect substrings appear in the raw
10
+ URL we never lowercase the whole string nor walk segments.
11
+ */
12
+ export function containsTraversal(rawUrl: string): boolean {
13
+ if (rawUrl.includes('\\')) {
14
+ return true
15
+ }
16
+ if (rawUrl.includes('..') && segmentContainsDotDot(rawUrl)) {
17
+ return true
18
+ }
19
+ if (rawUrl.indexOf('%') === -1) {
20
+ return false
21
+ }
22
+ const lower = rawUrl.toLowerCase()
23
+ return lower.includes('%2e%2e') || lower.includes('%2f') || lower.includes('%5c')
24
+ }
25
+
26
+ function segmentContainsDotDot(rawUrl: string): boolean {
27
+ const queryStart = rawUrl.indexOf('?')
28
+ const pathEnd = queryStart === -1 ? rawUrl.length : queryStart
29
+ const pathStart = rawUrl.indexOf('/', rawUrl.indexOf('://') + 3)
30
+ if (pathStart === -1 || pathStart >= pathEnd) {
31
+ return false
32
+ }
33
+ return rawUrl
34
+ .slice(pathStart, pathEnd)
35
+ .split('/')
36
+ .some((segment) => segment === '..')
37
+ }
@@ -0,0 +1,35 @@
1
+ import { mimeForExtension } from './mimeForExtension.ts'
2
+
3
+ /*
4
+ A static-asset response's headers depend only on its pathname (extension →
5
+ Content-Type, path → Cache-Control), so each distinct pathname's header bundle
6
+ is built once and reused across every hit on that chunk — avoiding a per-request
7
+ allocation on a cold page load that pulls dozens of files. Each bundle carries
8
+ the plain `base` headers plus a `zstd` variant with `Content-Encoding: zstd`.
9
+ `cacheControlFor` lets callers vary the policy: hashed-aware for `/_app/`,
10
+ fixed for public/.
11
+ */
12
+ type AssetHeaderBundle = {
13
+ base: HeadersInit
14
+ zstd: HeadersInit
15
+ }
16
+
17
+ export function createAssetHeaderCache(
18
+ cacheControlFor: (pathname: string) => string,
19
+ ): (pathname: string) => AssetHeaderBundle {
20
+ const cache = new Map<string, AssetHeaderBundle>()
21
+ return function headersFor(pathname) {
22
+ const cached = cache.get(pathname)
23
+ if (cached) {
24
+ return cached
25
+ }
26
+ const base: HeadersInit = {
27
+ 'Content-Type': mimeForExtension(pathname),
28
+ Vary: 'Accept-Encoding',
29
+ 'Cache-Control': cacheControlFor(pathname),
30
+ }
31
+ const bundle: AssetHeaderBundle = { base, zstd: { ...base, 'Content-Encoding': 'zstd' } }
32
+ cache.set(pathname, bundle)
33
+ return bundle
34
+ }
35
+ }
@@ -0,0 +1,63 @@
1
+ import { PUBLIC_ASSET_CACHE_CONTROL } from '../../shared/CACHE_CONTROL_VALUES.ts'
2
+ import { acceptsZstd } from './acceptsZstd.ts'
3
+ import { containsTraversal } from './containsTraversal.ts'
4
+ import { createAssetHeaderCache } from './createAssetHeaderCache.ts'
5
+ import { globToPathSet } from './globToPathSet.ts'
6
+ import type { Assets } from './types/Assets.ts'
7
+
8
+ /*
9
+ Serves files from the project's `public/` folder at the site root. Two
10
+ sources, picked at construction:
11
+
12
+ - `publicAssets` (standalone compile): a map of root path → zstd bytes
13
+ embedded into the binary, mirroring the `_app` asset embed.
14
+ - `publicDir` on disk (dev + `belte start`): files read straight from
15
+ `${cwd}/src/browser/public`, with the set of paths snapshotted once at
16
+ boot (see below).
17
+
18
+ Returns a server fn that resolves to `undefined` when no public file
19
+ matches the request path, so the caller falls through to its own 404 /
20
+ middleware path. The path-traversal guard mirrors serveStaticAsset's
21
+ defence against encoded `..` segments in the raw URL.
22
+
23
+ Async because disk mode globs `publicDir` once at construction to build a
24
+ Set of the available paths: every page nav and RPC falls through here, so
25
+ a Set lookup beats a filesystem stat per miss. A file added to public/
26
+ after boot needs a server restart to be seen — the same restart a code
27
+ change already triggers under `bun --watch`.
28
+ */
29
+ export async function createPublicAssetServer({
30
+ publicDir,
31
+ publicAssets,
32
+ }: {
33
+ publicDir: string
34
+ publicAssets?: Assets
35
+ }): Promise<(req: Request, url: URL) => Promise<Response | undefined>> {
36
+ const headersFor = createAssetHeaderCache(() => PUBLIC_ASSET_CACHE_CONTROL)
37
+ // `dot: true` keeps dotfiles (e.g. `.well-known/…`) servable, matching a raw disk stat.
38
+ const diskPaths = publicAssets
39
+ ? new Set<string>()
40
+ : await globToPathSet(publicDir, '**/*', (file) => `/${file}`, { dot: true })
41
+
42
+ return async function servePublicAsset(req, url) {
43
+ if (containsTraversal(req.url)) {
44
+ return undefined
45
+ }
46
+ const wantsZstd = acceptsZstd(req)
47
+ const { base, zstd } = headersFor(url.pathname)
48
+ if (publicAssets) {
49
+ const compressed = publicAssets[url.pathname]
50
+ if (!compressed) {
51
+ return undefined
52
+ }
53
+ if (wantsZstd) {
54
+ return new Response(compressed, { headers: zstd })
55
+ }
56
+ return new Response(await Bun.zstdDecompress(compressed), { headers: base })
57
+ }
58
+ if (!diskPaths.has(url.pathname)) {
59
+ return undefined
60
+ }
61
+ return new Response(Bun.file(publicDir + url.pathname), { headers: base })
62
+ }
63
+ }
@@ -0,0 +1,100 @@
1
+ import type { Pages } from '../../browser/types/Pages.ts'
2
+ import { NO_STORE } from '../../shared/CACHE_CONTROL_VALUES.ts'
3
+ import { memoizeByKey } from '../../shared/memoizeByKey.ts'
4
+ import type { HttpVerb } from '../../shared/types/HttpVerb.ts'
5
+ import type { RemoteFunction } from '../../shared/types/RemoteFunction.ts'
6
+ import type { RemoteRoutes } from '../rpc/types/RemoteRoutes.ts'
7
+ import type { RequestStore } from './types/RequestStore.ts'
8
+
9
+ type AnyRemoteFunction = RemoteFunction<unknown, unknown>
10
+
11
+ /* Resolves a matched route to a Response, given the request and its scope. */
12
+ type RouteHandler = (
13
+ req: Request,
14
+ pathParams: Record<string, string>,
15
+ store: RequestStore,
16
+ ) => Promise<Response>
17
+
18
+ /* Renders the page at `routeUrl` — injected so dispatch is testable without SSR. */
19
+ type RenderPage = (
20
+ routeUrl: string,
21
+ params: Record<string, string>,
22
+ store: RequestStore,
23
+ ) => Promise<Response>
24
+
25
+ /* The framework's 405 — `Allow` names the permitted verb(s), body and NO_STORE shared so the rpc and page branches can't drift. */
26
+ function methodNotAllowed(allow: string): Response {
27
+ return new Response('Method Not Allowed', {
28
+ status: 405,
29
+ headers: { Allow: allow, 'Cache-Control': NO_STORE },
30
+ })
31
+ }
32
+
33
+ /*
34
+ Owns route dispatch: deciding, per registered URL, whether a request hits an
35
+ rpc verb, a page render, or nothing — and the method-matching that picks the
36
+ status. Page URLs (under src/browser/pages/) serve GET/HEAD by rendering; rpc
37
+ URLs (under src/server/rpc/, `/rpc/...`) dispatch to the single declared verb,
38
+ 405 on method mismatch; an unregistered URL is 404. Page and rpc URLs are
39
+ disjoint by construction, so each route lands in exactly one branch.
40
+
41
+ `renderPage` is injected rather than built here: dispatch decisions (the
42
+ 405/404 branches and the rpc method match) are the behaviour worth testing,
43
+ and keeping the Svelte render behind the seam lets a test exercise them with a
44
+ stub instead of booting a server. The rpc-module loader is memoised internally
45
+ so each module loads once.
46
+ */
47
+ export function createRouteDispatcher({
48
+ pages,
49
+ rpc,
50
+ renderPage,
51
+ }: {
52
+ pages: Pages
53
+ rpc: RemoteRoutes
54
+ renderPage: RenderPage
55
+ }): (routeUrl: string) => RouteHandler {
56
+ const loadRpc = memoizeByKey((url): Promise<AnyRemoteFunction | undefined> | undefined => {
57
+ const loader = rpc[url]
58
+ if (!loader) {
59
+ return undefined
60
+ }
61
+ /*
62
+ Each $rpc module has exactly one named export, validated at build
63
+ time. Pick the first export that looks like a RemoteFunction so the
64
+ framework stays tolerant of incidental re-exports.
65
+ */
66
+ return loader().then((mod) => {
67
+ for (const value of Object.values(mod)) {
68
+ if (typeof value === 'function' && 'method' in value && 'url' in value) {
69
+ return value as AnyRemoteFunction
70
+ }
71
+ }
72
+ return undefined
73
+ })
74
+ })
75
+
76
+ return function buildRouteHandler(routeUrl: string): RouteHandler {
77
+ const hasPage = pages[routeUrl] !== undefined
78
+ const hasRpc = rpc[routeUrl] !== undefined
79
+ return async function routeHandler(req, pathParams, store) {
80
+ const method = req.method as HttpVerb
81
+ if (hasRpc) {
82
+ const fn = await loadRpc(routeUrl)
83
+ if (fn && fn.method === method) {
84
+ return fn.fetch(req)
85
+ }
86
+ return methodNotAllowed(fn ? fn.method : '')
87
+ }
88
+ if (hasPage) {
89
+ if (method !== 'GET' && method !== 'HEAD') {
90
+ return methodNotAllowed('GET, HEAD')
91
+ }
92
+ return renderPage(routeUrl, pathParams, store)
93
+ }
94
+ return new Response('Not Found', {
95
+ status: 404,
96
+ headers: { 'Cache-Control': NO_STORE },
97
+ })
98
+ }
99
+ }
100
+ }