@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,479 @@
1
+ /*
2
+ Scans a module source character-by-character — skipping strings,
3
+ templates, comments, and TypeScript generics — for an
4
+ `export const <name> = <IDENT>(...)` binding the caller cares about.
5
+ On a match returns the identifier text, the export name, and the byte
6
+ ranges of the call's open and close parens; the $rpc and $sockets
7
+ rewriters splice their runtime bindings into those ranges.
8
+
9
+ The scanner enforces a single matching export per module: a second match
10
+ throws `singleExportError` so each $rpc / $sockets file is required to
11
+ declare exactly one remote function / socket.
12
+
13
+ A regex pass would be tidier but it can't tell a `GET` mention inside a
14
+ docstring or template literal from the real call, and it can't follow
15
+ nested generics like `GET<Map<K, V>>(`.
16
+ */
17
+
18
+ export type ExportCallSite = {
19
+ ident: string
20
+ exportName: string
21
+ callStart: number
22
+ parenStart: number
23
+ parenEnd: number
24
+ }
25
+
26
+ export function findExportCallSite(
27
+ source: string,
28
+ matchIdent: (ident: string) => boolean,
29
+ singleExportError: string,
30
+ ): ExportCallSite | undefined {
31
+ let found: ExportCallSite | undefined
32
+ const len = source.length
33
+ let i = 0
34
+ while (i < len) {
35
+ const c = source[i]
36
+ const next = source[i + 1]
37
+ if (c === '/' && next === '/') {
38
+ const newline = source.indexOf('\n', i + 2)
39
+ i = newline === -1 ? len : newline + 1
40
+ continue
41
+ }
42
+ if (c === '/' && next === '*') {
43
+ const end = source.indexOf('*/', i + 2)
44
+ i = end === -1 ? len : end + 2
45
+ continue
46
+ }
47
+ if (c === '/' && isRegexContext(source, i)) {
48
+ i = skipRegex(source, i + 1)
49
+ continue
50
+ }
51
+ if (c === '"' || c === "'") {
52
+ i = skipString(source, i + 1, c)
53
+ continue
54
+ }
55
+ if (c === '`') {
56
+ i = skipTemplate(source, i + 1)
57
+ continue
58
+ }
59
+ if (isIdentStart(c) && !isIdentPart(source[i - 1])) {
60
+ let j = i + 1
61
+ while (j < len && isIdentPart(source[j])) {
62
+ j++
63
+ }
64
+ const ident = source.slice(i, j)
65
+ if (matchIdent(ident)) {
66
+ const tail = matchCallTail(source, j)
67
+ if (tail !== undefined) {
68
+ const exportName = detectExportName(source, i)
69
+ if (exportName !== undefined) {
70
+ if (found !== undefined) {
71
+ throw new Error(singleExportError)
72
+ }
73
+ const parenEnd = findCallEnd(source, tail)
74
+ if (parenEnd === undefined) {
75
+ throw new Error(`[belte] unmatched \`(\` after \`${ident}\` identifier`)
76
+ }
77
+ found = {
78
+ ident,
79
+ exportName,
80
+ callStart: i,
81
+ parenStart: tail,
82
+ parenEnd,
83
+ }
84
+ i = parenEnd + 1
85
+ continue
86
+ }
87
+ }
88
+ }
89
+ i = j
90
+ continue
91
+ }
92
+ i++
93
+ }
94
+ return found
95
+ }
96
+
97
+ function skipString(source: string, start: number, quote: string): number {
98
+ let i = start
99
+ while (i < source.length) {
100
+ const c = source[i]
101
+ if (c === '\\') {
102
+ i += 2
103
+ continue
104
+ }
105
+ if (c === quote) {
106
+ return i + 1
107
+ }
108
+ if (c === '\n') {
109
+ return i
110
+ }
111
+ i++
112
+ }
113
+ return source.length
114
+ }
115
+
116
+ function skipTemplate(source: string, start: number): number {
117
+ let i = start
118
+ while (i < source.length) {
119
+ const c = source[i]
120
+ if (c === '\\') {
121
+ i += 2
122
+ continue
123
+ }
124
+ if (c === '`') {
125
+ return i + 1
126
+ }
127
+ if (c === '$' && source[i + 1] === '{') {
128
+ i = skipTemplateExpression(source, i + 2)
129
+ continue
130
+ }
131
+ i++
132
+ }
133
+ return source.length
134
+ }
135
+
136
+ function skipTemplateExpression(source: string, start: number): number {
137
+ let depth = 1
138
+ let i = start
139
+ while (i < source.length && depth > 0) {
140
+ const c = source[i]
141
+ if (c === '{') {
142
+ depth++
143
+ i++
144
+ continue
145
+ }
146
+ if (c === '}') {
147
+ depth--
148
+ i++
149
+ continue
150
+ }
151
+ if (c === '"' || c === "'") {
152
+ i = skipString(source, i + 1, c)
153
+ continue
154
+ }
155
+ if (c === '`') {
156
+ i = skipTemplate(source, i + 1)
157
+ continue
158
+ }
159
+ if (c === '/' && source[i + 1] === '/') {
160
+ const newline = source.indexOf('\n', i + 2)
161
+ i = newline === -1 ? source.length : newline + 1
162
+ continue
163
+ }
164
+ if (c === '/' && source[i + 1] === '*') {
165
+ const end = source.indexOf('*/', i + 2)
166
+ i = end === -1 ? source.length : end + 2
167
+ continue
168
+ }
169
+ if (c === '/' && isRegexContext(source, i)) {
170
+ i = skipRegex(source, i + 1)
171
+ continue
172
+ }
173
+ i++
174
+ }
175
+ return i
176
+ }
177
+
178
+ function matchCallTail(source: string, after: number): number | undefined {
179
+ let j = after
180
+ while (j < source.length && isWhitespace(source[j])) {
181
+ j++
182
+ }
183
+ if (source[j] === '<') {
184
+ const closed = skipGenerics(source, j)
185
+ if (closed === undefined) {
186
+ return undefined
187
+ }
188
+ j = closed
189
+ while (j < source.length && isWhitespace(source[j])) {
190
+ j++
191
+ }
192
+ }
193
+ return source[j] === '(' ? j : undefined
194
+ }
195
+
196
+ /*
197
+ Returns the index immediately after the matching `>` for a generic
198
+ argument list starting at `start`. TypeScript type literals inside the
199
+ generic (`<{ a: string; b: number }>`, function types `<() => X>`,
200
+ tuples `<[A, B]>`, etc.) bring their own paired brackets and
201
+ semicolons, so track depth across `<>`, `()`, `{}`, and `[]` and only
202
+ count a closing `>` when every other bracket is balanced.
203
+ Arrow-function `=>` is treated as a single token so the `>` doesn't
204
+ prematurely close the generic.
205
+ */
206
+ function skipGenerics(source: string, start: number): number | undefined {
207
+ let angleDepth = 0
208
+ let parenDepth = 0
209
+ let braceDepth = 0
210
+ let bracketDepth = 0
211
+ let i = start
212
+ while (i < source.length) {
213
+ const c = source[i]
214
+ if (c === '"' || c === "'") {
215
+ i = skipString(source, i + 1, c)
216
+ continue
217
+ }
218
+ if (c === '`') {
219
+ i = skipTemplate(source, i + 1)
220
+ continue
221
+ }
222
+ if (c === '<') {
223
+ angleDepth++
224
+ } else if (c === '>') {
225
+ const isArrow = source[i - 1] === '='
226
+ if (!isArrow && parenDepth === 0 && braceDepth === 0 && bracketDepth === 0) {
227
+ angleDepth--
228
+ if (angleDepth === 0) {
229
+ return i + 1
230
+ }
231
+ }
232
+ } else if (c === '(') {
233
+ parenDepth++
234
+ } else if (c === ')') {
235
+ parenDepth--
236
+ } else if (c === '{') {
237
+ braceDepth++
238
+ } else if (c === '}') {
239
+ braceDepth--
240
+ } else if (c === '[') {
241
+ bracketDepth++
242
+ } else if (c === ']') {
243
+ bracketDepth--
244
+ }
245
+ i++
246
+ }
247
+ return undefined
248
+ }
249
+
250
+ /*
251
+ Walks the call body, skipping strings/templates/comments and respecting
252
+ nested `()` so brackets inside object literals or nested calls don't
253
+ throw the depth count.
254
+ */
255
+ function findCallEnd(source: string, parenStart: number): number | undefined {
256
+ let depth = 1
257
+ let i = parenStart + 1
258
+ while (i < source.length) {
259
+ const c = source[i]
260
+ if (c === '"' || c === "'") {
261
+ i = skipString(source, i + 1, c)
262
+ continue
263
+ }
264
+ if (c === '`') {
265
+ i = skipTemplate(source, i + 1)
266
+ continue
267
+ }
268
+ if (c === '/' && source[i + 1] === '/') {
269
+ const newline = source.indexOf('\n', i + 2)
270
+ i = newline === -1 ? source.length : newline + 1
271
+ continue
272
+ }
273
+ if (c === '/' && source[i + 1] === '*') {
274
+ const end = source.indexOf('*/', i + 2)
275
+ i = end === -1 ? source.length : end + 2
276
+ continue
277
+ }
278
+ if (c === '/' && isRegexContext(source, i)) {
279
+ i = skipRegex(source, i + 1)
280
+ continue
281
+ }
282
+ if (c === '(') {
283
+ depth++
284
+ } else if (c === ')') {
285
+ depth--
286
+ if (depth === 0) {
287
+ return i
288
+ }
289
+ }
290
+ i++
291
+ }
292
+ return undefined
293
+ }
294
+
295
+ /*
296
+ Looks backwards from a `<IDENT>(` callStart to confirm it was bound by
297
+ `export const <name> = ...`. Returns the identifier in `<name>` if so,
298
+ undefined otherwise — used to skip mentions of an identifier that
299
+ isn't the module's declared export.
300
+ */
301
+ function detectExportName(source: string, callStart: number): string | undefined {
302
+ let i = callStart - 1
303
+ while (i >= 0 && isWhitespace(source[i])) {
304
+ i--
305
+ }
306
+ if (source[i] !== '=') {
307
+ return undefined
308
+ }
309
+ i--
310
+ while (i >= 0 && isWhitespace(source[i])) {
311
+ i--
312
+ }
313
+ const nameEnd = i + 1
314
+ while (i >= 0 && isIdentPart(source[i])) {
315
+ i--
316
+ }
317
+ const nameStart = i + 1
318
+ if (nameStart === nameEnd) {
319
+ return undefined
320
+ }
321
+ const name = source.slice(nameStart, nameEnd)
322
+ while (i >= 0 && isWhitespace(source[i])) {
323
+ i--
324
+ }
325
+ if (!matchesBackwards(source, i, 'const')) {
326
+ return undefined
327
+ }
328
+ i -= 'const'.length
329
+ while (i >= 0 && isWhitespace(source[i])) {
330
+ i--
331
+ }
332
+ if (!matchesBackwards(source, i, 'export')) {
333
+ return undefined
334
+ }
335
+ return name
336
+ }
337
+
338
+ function matchesBackwards(source: string, end: number, keyword: string): boolean {
339
+ const start = end - keyword.length + 1
340
+ if (start < 0) {
341
+ return false
342
+ }
343
+ if (source.slice(start, end + 1) !== keyword) {
344
+ return false
345
+ }
346
+ return start === 0 || !isIdentPart(source[start - 1])
347
+ }
348
+
349
+ function isIdentStart(c: string | undefined): boolean {
350
+ if (c === undefined) {
351
+ return false
352
+ }
353
+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c === '_' || c === '$'
354
+ }
355
+
356
+ function isIdentPart(c: string | undefined): boolean {
357
+ if (c === undefined) {
358
+ return false
359
+ }
360
+ return isIdentStart(c) || (c >= '0' && c <= '9')
361
+ }
362
+
363
+ function isWhitespace(c: string | undefined): boolean {
364
+ return c === ' ' || c === '\t' || c === '\n' || c === '\r'
365
+ }
366
+
367
+ /*
368
+ A `/` starts a regex literal when the prior expression context expects an
369
+ expression rather than a value — after an open delimiter, operator, or
370
+ expression-prefix keyword (return, typeof, instanceof, in, of, delete,
371
+ void, await, yield, new, throw, case, do). Otherwise `/` is division.
372
+ Without this disambiguation a regex like `/^\//` reads as `/` (division),
373
+ then `^`, `\`, `/`, `/` — and the final `//` pair fakes a line comment
374
+ that swallows the rest of the line, eating any `)` that closes the
375
+ enclosing call.
376
+ */
377
+ const REGEX_PREFIX_KEYWORDS = new Set([
378
+ 'return',
379
+ 'typeof',
380
+ 'instanceof',
381
+ 'in',
382
+ 'of',
383
+ 'delete',
384
+ 'void',
385
+ 'await',
386
+ 'yield',
387
+ 'new',
388
+ 'throw',
389
+ 'case',
390
+ 'do',
391
+ ])
392
+
393
+ const REGEX_PUNCTUATION = new Set([
394
+ '(',
395
+ '[',
396
+ '{',
397
+ ',',
398
+ ';',
399
+ ':',
400
+ '?',
401
+ '!',
402
+ '&',
403
+ '|',
404
+ '^',
405
+ '~',
406
+ '+',
407
+ '-',
408
+ '*',
409
+ '%',
410
+ '<',
411
+ '>',
412
+ '=',
413
+ '/',
414
+ ])
415
+
416
+ function isRegexContext(source: string, slashIndex: number): boolean {
417
+ let i = slashIndex - 1
418
+ while (i >= 0 && isWhitespace(source[i])) {
419
+ i--
420
+ }
421
+ if (i < 0) {
422
+ return true
423
+ }
424
+ const prev = source[i] as string
425
+ if (REGEX_PUNCTUATION.has(prev)) {
426
+ return true
427
+ }
428
+ if (isIdentPart(prev)) {
429
+ let start = i
430
+ while (start > 0 && isIdentPart(source[start - 1])) {
431
+ start--
432
+ }
433
+ return REGEX_PREFIX_KEYWORDS.has(source.slice(start, i + 1))
434
+ }
435
+ return false
436
+ }
437
+
438
+ /*
439
+ Walks past a regex literal body, respecting character classes (`[...]`
440
+ where `/` is literal) and backslash escapes, then consumes trailing
441
+ flag identifiers. Returns the index immediately after the regex. An
442
+ unterminated regex (newline before closing `/`) returns the newline
443
+ position so the outer scanner can resume normally on the next line.
444
+ */
445
+ function skipRegex(source: string, start: number): number {
446
+ let i = start
447
+ let inClass = false
448
+ while (i < source.length) {
449
+ const c = source[i]
450
+ if (c === '\\') {
451
+ i += 2
452
+ continue
453
+ }
454
+ if (c === '\n') {
455
+ return i
456
+ }
457
+ if (inClass) {
458
+ if (c === ']') {
459
+ inClass = false
460
+ }
461
+ i++
462
+ continue
463
+ }
464
+ if (c === '[') {
465
+ inClass = true
466
+ i++
467
+ continue
468
+ }
469
+ if (c === '/') {
470
+ let j = i + 1
471
+ while (j < source.length && isIdentPart(source[j])) {
472
+ j++
473
+ }
474
+ return j
475
+ }
476
+ i++
477
+ }
478
+ return source.length
479
+ }
@@ -0,0 +1,41 @@
1
+ import { extraForwardHeaders } from './extraForwardHeaders.ts'
2
+
3
+ /*
4
+ Headers belte forwards from an inbound HTTP/MCP request onto every
5
+ synthesized in-process rpc Request — cookies + bearer auth + the four
6
+ forwarding hints proxies set when terminating TLS in front of the app.
7
+ defineVerb uses this when an SSR pass calls a verb in-process; the MCP
8
+ dispatcher uses it when piping a tool invocation through verb.fetch.
9
+
10
+ WARNING — this is an allowlist: every inbound header NOT named here (and
11
+ not added via app.forwardHeaders) is DROPPED on the in-process path. A
12
+ handler that reads e.g. `accept-language`, an idempotency key, a trace
13
+ header, or a custom `x-tenant-*` during SSR or an MCP call sees nothing,
14
+ and the call still succeeds with a degraded request. Add the names you
15
+ rely on via the `forwardHeaders` export in src/app.ts.
16
+
17
+ Centralised so both call sites can't drift on which headers are
18
+ considered "auth/identity" context.
19
+ */
20
+ export const FORWARDED_HEADERS = [
21
+ 'cookie',
22
+ 'authorization',
23
+ 'x-forwarded-for',
24
+ 'x-forwarded-proto',
25
+ 'x-forwarded-host',
26
+ ]
27
+
28
+ export function forwardHeaders(source: Headers): Headers {
29
+ const headers = new Headers()
30
+ // Iterate the two fixed arrays directly — both are request-invariant, so
31
+ // a spread-concat here would allocate a fresh array on every SSR/MCP call.
32
+ const copy = (name: string) => {
33
+ const value = source.get(name)
34
+ if (value) {
35
+ headers.set(name, value)
36
+ }
37
+ }
38
+ FORWARDED_HEADERS.forEach(copy)
39
+ extraForwardHeaders.get().forEach(copy)
40
+ return headers
41
+ }
@@ -0,0 +1,5 @@
1
+ import { remoteMetaStore } from './remoteMetaStore.ts'
2
+
3
+ export function getRemoteMeta(promise: Promise<unknown>): Request | undefined {
4
+ return remoteMetaStore.get(promise)?.()
5
+ }
@@ -0,0 +1,15 @@
1
+ import { activeCacheStore } from './activeCacheStore.ts'
2
+ import { globalCacheStoreSlot } from './globalCacheStoreSlot.ts'
3
+ import type { CacheStore } from './types/CacheStore.ts'
4
+
5
+ /*
6
+ Resolves the process-level CacheStore that `cache(fn, { global: true })` entries
7
+ live in. The server entry registers a module-singleton resolver so the store
8
+ survives across requests; the client points it at the active tab store. When no
9
+ resolver is registered (isolated tests, or a client that never set one) it falls
10
+ back to the active store, so `global` degrades to request/tab-scoped rather than
11
+ throwing.
12
+ */
13
+ export function globalCacheStore(): CacheStore {
14
+ return globalCacheStoreSlot.resolver?.() ?? activeCacheStore()
15
+ }
@@ -0,0 +1,14 @@
1
+ import type { CacheStore } from './types/CacheStore.ts'
2
+
3
+ /*
4
+ Slot for the process-level cache store resolver used by cache() entries opting
5
+ into `global: true`. The server entry registers a module-singleton store that
6
+ outlives any one request; the client entry points it at its single tab store so
7
+ `global` is a no-op there. Unset means no global store is registered, in which
8
+ case globalCacheStore() falls back to the active (request/tab) store.
9
+ */
10
+ export const globalCacheStoreSlot: {
11
+ resolver: (() => CacheStore | undefined) | undefined
12
+ } = {
13
+ resolver: undefined,
14
+ }
@@ -0,0 +1,13 @@
1
+ import { BELTE_PACKAGE_NAME } from './BELTE_PACKAGE_NAME.ts'
2
+
3
+ /*
4
+ The names a user may import a belte server helper under: the project's chosen
5
+ alias plus the canonical package name. The resolver strips the dead import
6
+ under both so it can't side-effect-load the server stub into the client
7
+ bundle. When the alias already is the canonical name, there's only one.
8
+ */
9
+ export function importNamesToStrip(importName: string): string[] {
10
+ return importName === BELTE_PACKAGE_NAME
11
+ ? [BELTE_PACKAGE_NAME]
12
+ : [importName, BELTE_PACKAGE_NAME]
13
+ }
@@ -0,0 +1,11 @@
1
+ import type { CacheInvalidation } from './types/CacheInvalidation.ts'
2
+
3
+ /*
4
+ Constructs the cache store's 'invalidate' event from the keys an
5
+ invalidation touched. The single definition of the event name + detail
6
+ shape, so the two dispatch sites (cache.invalidate and the streamed-
7
+ resolution placeholder settle) can't drift from the cache store's listener.
8
+ */
9
+ export function invalidateEvent(keys: Iterable<string>): CustomEvent<CacheInvalidation> {
10
+ return new CustomEvent('invalidate', { detail: new Set(keys) })
11
+ }
@@ -0,0 +1,15 @@
1
+ import type { CompileTarget } from './types/CompileTarget.ts'
2
+
3
+ /* The canonical cross-compile targets, as a runtime set for validation. */
4
+ const COMPILE_TARGETS: readonly CompileTarget[] = [
5
+ 'bun-darwin-arm64',
6
+ 'bun-darwin-x64',
7
+ 'bun-linux-arm64',
8
+ 'bun-linux-x64',
9
+ 'bun-windows-x64',
10
+ ]
11
+
12
+ /* Narrows an arbitrary string to a known CompileTarget. */
13
+ export function isCompileTarget(value: string): value is CompileTarget {
14
+ return (COMPILE_TARGETS as readonly string[]).includes(value)
15
+ }
@@ -0,0 +1,23 @@
1
+ /*
2
+ Matches the conventions of the `debug` npm package.
3
+ DEBUG="belte" → enables "belte"
4
+ DEBUG="belte:*" → enables "belte" and "belte:anything"
5
+ DEBUG="*" → enables everything
6
+ DEBUG="a,belte" → comma-separated list
7
+ */
8
+ export function isDebugEnabled(name: string, env: string | undefined = process.env.DEBUG): boolean {
9
+ if (!env) {
10
+ return false
11
+ }
12
+ return env.split(',').some((raw) => {
13
+ const pattern = raw.trim()
14
+ if (pattern === '*') {
15
+ return true
16
+ }
17
+ if (pattern.endsWith(':*')) {
18
+ const prefix = pattern.slice(0, -2)
19
+ return name === prefix || name.startsWith(`${prefix}:`)
20
+ }
21
+ return pattern === name
22
+ })
23
+ }
@@ -0,0 +1,16 @@
1
+ /*
2
+ True when an error from a dynamic `import(...)` is a module-resolution
3
+ failure (the package isn't installed) rather than an error thrown while
4
+ the module's own code ran. Lets optional-peer loads swallow "not installed"
5
+ while letting a genuine load-time failure surface. Bun surfaces the former
6
+ as a ResolveMessage / ERR_MODULE_NOT_FOUND; the message check is the
7
+ cross-runtime fallback.
8
+ */
9
+ export function isModuleNotFound(error: unknown): boolean {
10
+ const code = (error as { code?: string })?.code
11
+ if (code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') {
12
+ return true
13
+ }
14
+ const message = error instanceof Error ? error.message : String(error)
15
+ return /cannot find (module|package)|failed to resolve/i.test(message)
16
+ }
@@ -0,0 +1,14 @@
1
+ import type { HttpVerb } from './types/HttpVerb.ts'
2
+
3
+ /*
4
+ Read-only (safe) HTTP methods — they don't mutate server state. Belte
5
+ uses this to decide which verbs auto-expose to MCP: reads flip MCP on
6
+ when a schema is present, mutations require an explicit `clients.mcp`
7
+ opt-in so a model can't delete/overwrite data just because the handler
8
+ carries a schema. Also feeds the MCP tool `readOnlyHint` annotation.
9
+ */
10
+ const READ_ONLY_METHODS = new Set<HttpVerb>(['GET', 'HEAD'])
11
+
12
+ export function isReadOnlyMethod(method: HttpVerb): boolean {
13
+ return READ_ONLY_METHODS.has(method)
14
+ }
@@ -0,0 +1,11 @@
1
+ import { STREAMING_CONTENT_TYPES } from './STREAMING_CONTENT_TYPES.ts'
2
+
3
+ /*
4
+ Whether a Response carries a streaming body (SSE / JSONL / NDJSON) by its
5
+ Content-Type, so callers drain it frame-by-frame instead of buffering.
6
+ Shared by the CLI print path and the MCP tool dispatcher.
7
+ */
8
+ export function isStreamingResponse(response: Response): boolean {
9
+ const contentType = (response.headers.get('content-type') ?? '').toLowerCase()
10
+ return STREAMING_CONTENT_TYPES.some((type) => contentType.startsWith(type))
11
+ }