@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.
- package/CHANGELOG.md +313 -0
- package/LICENSE +21 -0
- package/README.md +559 -0
- package/bin/belte.ts +183 -0
- package/package.json +110 -0
- package/src/App.svelte +31 -0
- package/src/appEntry.ts +151 -0
- package/src/assets/app.html +14 -0
- package/src/belteResolverPlugin.ts +858 -0
- package/src/build.ts +147 -0
- package/src/buildCli.ts +129 -0
- package/src/buildDisconnected.ts +122 -0
- package/src/bundleApp.ts +149 -0
- package/src/bundleDisconnectedEntry.ts +17 -0
- package/src/cliEntry.ts +25 -0
- package/src/clientBuildPlugins.ts +41 -0
- package/src/clientEntry.ts +7 -0
- package/src/compile.ts +64 -0
- package/src/controlServerWorker.ts +422 -0
- package/src/dedupeSveltePlugin.ts +66 -0
- package/src/devEntry.ts +169 -0
- package/src/discoveryEntry.ts +81 -0
- package/src/lib/browser/applyStreamedResolution.ts +33 -0
- package/src/lib/browser/cacheEntryFromSnapshot.ts +48 -0
- package/src/lib/browser/flushUnresolvedPlaceholders.ts +16 -0
- package/src/lib/browser/installStreamingPlaceholders.ts +32 -0
- package/src/lib/browser/openResolveStream.ts +42 -0
- package/src/lib/browser/page.svelte.ts +258 -0
- package/src/lib/browser/pageStreamController.ts +17 -0
- package/src/lib/browser/refetchPlaceholder.ts +12 -0
- package/src/lib/browser/remoteProxy.ts +37 -0
- package/src/lib/browser/socketChannel.ts +192 -0
- package/src/lib/browser/socketProxy.ts +57 -0
- package/src/lib/browser/startClient.ts +153 -0
- package/src/lib/browser/subscribe.ts +131 -0
- package/src/lib/browser/types/Errors.ts +9 -0
- package/src/lib/browser/types/Layouts.ts +7 -0
- package/src/lib/browser/types/Pages.ts +7 -0
- package/src/lib/browser/types/StreamingDeferred.ts +9 -0
- package/src/lib/bundle/BundleMenu.ts +11 -0
- package/src/lib/bundle/BundleMenuItem.ts +24 -0
- package/src/lib/bundle/BundleWindow.ts +36 -0
- package/src/lib/bundle/WEBVIEW_BUILD_REVISION.ts +9 -0
- package/src/lib/bundle/WEBVIEW_VERSION.ts +7 -0
- package/src/lib/bundle/bindConnectedFlag.ts +29 -0
- package/src/lib/bundle/bindRequestNavigate.ts +31 -0
- package/src/lib/bundle/buildWebviewLib.ts +111 -0
- package/src/lib/bundle/disconnected.css +9 -0
- package/src/lib/bundle/disconnected.svelte +386 -0
- package/src/lib/bundle/ensureWebviewLib.ts +20 -0
- package/src/lib/bundle/exitWithParent.ts +28 -0
- package/src/lib/bundle/infoPlist.ts +46 -0
- package/src/lib/bundle/installDownloads.ts +24 -0
- package/src/lib/bundle/installMacMenu.ts +39 -0
- package/src/lib/bundle/listenLocalControlServer.ts +19 -0
- package/src/lib/bundle/native/belteMenu.mm +422 -0
- package/src/lib/bundle/native/webview.h +4557 -0
- package/src/lib/bundle/onMenu.ts +41 -0
- package/src/lib/bundle/openWebview.ts +104 -0
- package/src/lib/bundle/pngToIcns.ts +47 -0
- package/src/lib/bundle/probeBelteServer.ts +34 -0
- package/src/lib/bundle/resolveServerBinary.ts +12 -0
- package/src/lib/bundle/resolveWebviewLib.ts +53 -0
- package/src/lib/bundle/serverBinaryFilename.ts +8 -0
- package/src/lib/bundle/signMacApp.ts +35 -0
- package/src/lib/bundle/spawnEmbeddedServer.ts +65 -0
- package/src/lib/bundle/stableLocalPort.ts +19 -0
- package/src/lib/bundle/waitForServer.ts +23 -0
- package/src/lib/bundle/webviewCachePath.ts +23 -0
- package/src/lib/bundle/webviewLibName.ts +11 -0
- package/src/lib/cli/connectToServer.ts +23 -0
- package/src/lib/cli/createClient.ts +170 -0
- package/src/lib/cli/dispatchCommand.ts +71 -0
- package/src/lib/cli/loadEnvFromBinaryDir.ts +16 -0
- package/src/lib/cli/parseArgvForRpc.ts +97 -0
- package/src/lib/cli/printHelp.ts +119 -0
- package/src/lib/cli/printSessionHelp.ts +27 -0
- package/src/lib/cli/printSessionStatus.ts +21 -0
- package/src/lib/cli/printTrimmed.ts +8 -0
- package/src/lib/cli/printValue.ts +10 -0
- package/src/lib/cli/resolveCliTarget.ts +48 -0
- package/src/lib/cli/runCli.ts +139 -0
- package/src/lib/cli/runSession.ts +105 -0
- package/src/lib/cli/startLocalInstance.ts +14 -0
- package/src/lib/cli/tokenizeLine.ts +51 -0
- package/src/lib/cli/types/CliManifest.ts +9 -0
- package/src/lib/cli/types/CliManifestEntry.ts +17 -0
- package/src/lib/cli/types/CliTarget.ts +13 -0
- package/src/lib/mcp/annotationsForMethod.ts +29 -0
- package/src/lib/mcp/createMcpResourceServer.ts +101 -0
- package/src/lib/mcp/createMcpServer.ts +42 -0
- package/src/lib/mcp/dispatchMcpRequest.ts +146 -0
- package/src/lib/mcp/mcpResourceServerSlot.ts +18 -0
- package/src/lib/mcp/mcpSurface.ts +265 -0
- package/src/lib/mcp/toolResultFromResponse.ts +66 -0
- package/src/lib/mcp/types/JsonRpcRequest.ts +12 -0
- package/src/lib/mcp/types/JsonRpcResponse.ts +20 -0
- package/src/lib/mcp/types/McpResourceContents.ts +10 -0
- package/src/lib/mcp/types/McpResourceDescriptor.ts +6 -0
- package/src/lib/mcp/types/McpResourceServer.ts +12 -0
- package/src/lib/mcp/types/McpServer.ts +9 -0
- package/src/lib/mcp/types/McpServerOptions.ts +16 -0
- package/src/lib/server/AppModule.ts +33 -0
- package/src/lib/server/DELETE.ts +9 -0
- package/src/lib/server/GET.ts +9 -0
- package/src/lib/server/HEAD.ts +9 -0
- package/src/lib/server/PATCH.ts +9 -0
- package/src/lib/server/POST.ts +9 -0
- package/src/lib/server/PUT.ts +9 -0
- package/src/lib/server/agent.ts +76 -0
- package/src/lib/server/appDataDir.ts +15 -0
- package/src/lib/server/cli/buildEnvContent.ts +19 -0
- package/src/lib/server/cli/createTarGz.ts +76 -0
- package/src/lib/server/cli/handleCliDownload.ts +153 -0
- package/src/lib/server/cli/handleCliInstall.ts +37 -0
- package/src/lib/server/cli/installScript.ts +29 -0
- package/src/lib/server/cli/maxSourceMtime.ts +26 -0
- package/src/lib/server/cookies.ts +29 -0
- package/src/lib/server/env.ts +50 -0
- package/src/lib/server/error.ts +70 -0
- package/src/lib/server/json.ts +28 -0
- package/src/lib/server/jsonl.ts +46 -0
- package/src/lib/server/prompts/definePrompt.ts +20 -0
- package/src/lib/server/prompts/promptRegistry.ts +9 -0
- package/src/lib/server/prompts/registerPrompt.ts +6 -0
- package/src/lib/server/prompts/renderPromptTemplate.ts +16 -0
- package/src/lib/server/prompts/types/Prompt.ts +13 -0
- package/src/lib/server/prompts/types/PromptOptions.ts +12 -0
- package/src/lib/server/prompts/types/PromptRegistryEntry.ts +13 -0
- package/src/lib/server/prompts/types/PromptRoutes.ts +10 -0
- package/src/lib/server/redirect.ts +42 -0
- package/src/lib/server/request.ts +18 -0
- package/src/lib/server/rpc/defineVerb.ts +133 -0
- package/src/lib/server/rpc/dispatchVerbInProcess.ts +46 -0
- package/src/lib/server/rpc/findVerbByCommandName.ts +18 -0
- package/src/lib/server/rpc/parseArgs.ts +95 -0
- package/src/lib/server/rpc/registerVerb.ts +6 -0
- package/src/lib/server/rpc/types/RemoteHandler.ts +27 -0
- package/src/lib/server/rpc/types/RemoteRoutes.ts +13 -0
- package/src/lib/server/rpc/types/TypedResponse.ts +18 -0
- package/src/lib/server/rpc/types/VerbHelper.ts +68 -0
- package/src/lib/server/rpc/types/VerbRegistryEntry.ts +29 -0
- package/src/lib/server/rpc/unprocessed.ts +14 -0
- package/src/lib/server/rpc/verbRegistry.ts +11 -0
- package/src/lib/server/runtime/DEFAULT_PORT.ts +6 -0
- package/src/lib/server/runtime/DEV_REBUILD_MESSAGE.ts +4 -0
- package/src/lib/server/runtime/DEV_RELOAD_CLIENT_SCRIPT.ts +29 -0
- package/src/lib/server/runtime/acceptsZstd.ts +8 -0
- package/src/lib/server/runtime/buildOpenApiSpec.ts +106 -0
- package/src/lib/server/runtime/cacheControlForAsset.ts +22 -0
- package/src/lib/server/runtime/containsTraversal.ts +37 -0
- package/src/lib/server/runtime/createAssetHeaderCache.ts +35 -0
- package/src/lib/server/runtime/createPublicAssetServer.ts +63 -0
- package/src/lib/server/runtime/createRouteDispatcher.ts +100 -0
- package/src/lib/server/runtime/createServer.ts +692 -0
- package/src/lib/server/runtime/devReloadResponse.ts +35 -0
- package/src/lib/server/runtime/disableIdleTimeoutForStream.ts +27 -0
- package/src/lib/server/runtime/envSchemaStore.ts +15 -0
- package/src/lib/server/runtime/findOpenPort.ts +35 -0
- package/src/lib/server/runtime/getActiveServer.ts +6 -0
- package/src/lib/server/runtime/globToPathSet.ts +29 -0
- package/src/lib/server/runtime/inProcessServer.ts +20 -0
- package/src/lib/server/runtime/internalErrorResponse.ts +25 -0
- package/src/lib/server/runtime/isCrossOriginUpgrade.ts +19 -0
- package/src/lib/server/runtime/listenOnOpenPort.ts +36 -0
- package/src/lib/server/runtime/logExposedSurfaces.ts +162 -0
- package/src/lib/server/runtime/mimeForExtension.ts +20 -0
- package/src/lib/server/runtime/parseIdleTimeout.ts +10 -0
- package/src/lib/server/runtime/parsePort.ts +11 -0
- package/src/lib/server/runtime/registryManifests.ts +66 -0
- package/src/lib/server/runtime/requestContext.ts +5 -0
- package/src/lib/server/runtime/resolveStreamResponse.ts +29 -0
- package/src/lib/server/runtime/runWithRequestScope.ts +57 -0
- package/src/lib/server/runtime/safeJsonForScript.ts +17 -0
- package/src/lib/server/runtime/serializeCacheSnapshot.ts +45 -0
- package/src/lib/server/runtime/serverSlot.ts +13 -0
- package/src/lib/server/runtime/setActiveServer.ts +6 -0
- package/src/lib/server/runtime/snapshotEntryFromCache.ts +81 -0
- package/src/lib/server/runtime/streamCacheResolutions.ts +37 -0
- package/src/lib/server/runtime/streamFromIterator.ts +86 -0
- package/src/lib/server/runtime/streamStash.ts +64 -0
- package/src/lib/server/runtime/types/Assets.ts +1 -0
- package/src/lib/server/runtime/types/RequestStore.ts +27 -0
- package/src/lib/server/runtime/withResponseDefaults.ts +24 -0
- package/src/lib/server/server.ts +32 -0
- package/src/lib/server/socket.ts +31 -0
- package/src/lib/server/sockets/createSocketDispatcher.ts +311 -0
- package/src/lib/server/sockets/defineSocket.ts +167 -0
- package/src/lib/server/sockets/lookupSocket.ts +6 -0
- package/src/lib/server/sockets/recentHistory.ts +11 -0
- package/src/lib/server/sockets/registerSocket.ts +6 -0
- package/src/lib/server/sockets/socketOperations.ts +35 -0
- package/src/lib/server/sockets/socketRegistry.ts +9 -0
- package/src/lib/server/sockets/types/Socket.ts +21 -0
- package/src/lib/server/sockets/types/SocketClientFrame.ts +18 -0
- package/src/lib/server/sockets/types/SocketOperation.ts +22 -0
- package/src/lib/server/sockets/types/SocketOptions.ts +22 -0
- package/src/lib/server/sockets/types/SocketRegistryEntry.ts +17 -0
- package/src/lib/server/sockets/types/SocketRoutes.ts +10 -0
- package/src/lib/server/sockets/types/SocketServerFrame.ts +15 -0
- package/src/lib/server/sse.ts +53 -0
- package/src/lib/shared/BELTE_PACKAGE_NAME.ts +7 -0
- package/src/lib/shared/CACHE_CONTROL_VALUES.ts +16 -0
- package/src/lib/shared/HttpError.ts +19 -0
- package/src/lib/shared/RESOLVE_STREAM_PATH.ts +7 -0
- package/src/lib/shared/STREAMING_CONTENT_TYPES.ts +11 -0
- package/src/lib/shared/activeCacheStore.ts +20 -0
- package/src/lib/shared/appDataDir.ts +34 -0
- package/src/lib/shared/belteImportName.ts +44 -0
- package/src/lib/shared/browserClientFlags.ts +10 -0
- package/src/lib/shared/buildRpcRequest.ts +70 -0
- package/src/lib/shared/bundleLayout.ts +36 -0
- package/src/lib/shared/bundled.ts +34 -0
- package/src/lib/shared/cache.ts +559 -0
- package/src/lib/shared/cacheStoreSlot.ts +16 -0
- package/src/lib/shared/canonicalJson.ts +63 -0
- package/src/lib/shared/carriesBodyArgs.ts +13 -0
- package/src/lib/shared/clearLastConnection.ts +7 -0
- package/src/lib/shared/commandNameForUrl.ts +17 -0
- package/src/lib/shared/createCacheStore.ts +75 -0
- package/src/lib/shared/createPushIterator.ts +93 -0
- package/src/lib/shared/createRemoteFunction.ts +99 -0
- package/src/lib/shared/decodeResponse.ts +47 -0
- package/src/lib/shared/detectTarget.ts +27 -0
- package/src/lib/shared/exeSuffix.ts +9 -0
- package/src/lib/shared/exitOnBuildFailure.ts +17 -0
- package/src/lib/shared/extraForwardHeaders.ts +16 -0
- package/src/lib/shared/fileStem.ts +9 -0
- package/src/lib/shared/findExportCallSite.ts +479 -0
- package/src/lib/shared/forwardHeaders.ts +41 -0
- package/src/lib/shared/getRemoteMeta.ts +5 -0
- package/src/lib/shared/globalCacheStore.ts +15 -0
- package/src/lib/shared/globalCacheStoreSlot.ts +14 -0
- package/src/lib/shared/importNamesToStrip.ts +13 -0
- package/src/lib/shared/invalidateEvent.ts +11 -0
- package/src/lib/shared/isCompileTarget.ts +15 -0
- package/src/lib/shared/isDebugEnabled.ts +23 -0
- package/src/lib/shared/isModuleNotFound.ts +16 -0
- package/src/lib/shared/isReadOnlyMethod.ts +14 -0
- package/src/lib/shared/isStreamingResponse.ts +11 -0
- package/src/lib/shared/jsonSchemaForPromptArguments.ts +29 -0
- package/src/lib/shared/jsonSchemaForSchema.ts +32 -0
- package/src/lib/shared/jsonlErrorFrame.ts +24 -0
- package/src/lib/shared/keyForRemoteCall.ts +29 -0
- package/src/lib/shared/lastConnectionPath.ts +7 -0
- package/src/lib/shared/loadEnvFile.ts +17 -0
- package/src/lib/shared/loadEnvFromDataDir.ts +15 -0
- package/src/lib/shared/loadSvelteConfig.ts +18 -0
- package/src/lib/shared/log.ts +104 -0
- package/src/lib/shared/manifestModule.ts +39 -0
- package/src/lib/shared/memoizeByKey.ts +24 -0
- package/src/lib/shared/nearestLayoutPrefix.ts +36 -0
- package/src/lib/shared/normalizeTarget.ts +10 -0
- package/src/lib/shared/pageUrlForFile.ts +14 -0
- package/src/lib/shared/parseBoundedEnvInt.ts +20 -0
- package/src/lib/shared/parseEnv.ts +30 -0
- package/src/lib/shared/parsePromptMarkdown.ts +34 -0
- package/src/lib/shared/parseRouteSegments.ts +22 -0
- package/src/lib/shared/prepareRpcModule.ts +59 -0
- package/src/lib/shared/prepareSocketModule.ts +49 -0
- package/src/lib/shared/programNameForPackage.ts +14 -0
- package/src/lib/shared/promptNameForFile.ts +10 -0
- package/src/lib/shared/queryStringFromArgs.ts +27 -0
- package/src/lib/shared/readEnvFile.ts +15 -0
- package/src/lib/shared/readLastConnection.ts +18 -0
- package/src/lib/shared/readPackageJson.ts +9 -0
- package/src/lib/shared/recordRemoteMeta.ts +5 -0
- package/src/lib/shared/remoteMetaStore.ts +16 -0
- package/src/lib/shared/resolveClientFlags.ts +20 -0
- package/src/lib/shared/responseErrorText.ts +9 -0
- package/src/lib/shared/rpcUrlForFile.ts +19 -0
- package/src/lib/shared/runningAsStandaloneBinary.ts +13 -0
- package/src/lib/shared/serializeEnv.ts +18 -0
- package/src/lib/shared/setCacheStoreResolver.ts +6 -0
- package/src/lib/shared/setGlobalCacheStoreResolver.ts +6 -0
- package/src/lib/shared/socketNameForFile.ts +11 -0
- package/src/lib/shared/sseErrorFrame.ts +29 -0
- package/src/lib/shared/streamResponse.ts +169 -0
- package/src/lib/shared/stripImport.ts +27 -0
- package/src/lib/shared/subscribableFromResponse.ts +51 -0
- package/src/lib/shared/toBunRoutePattern.ts +28 -0
- package/src/lib/shared/types/CacheEntry.ts +63 -0
- package/src/lib/shared/types/CacheInvalidation.ts +9 -0
- package/src/lib/shared/types/CacheOptions.ts +33 -0
- package/src/lib/shared/types/CacheSnapshot.ts +16 -0
- package/src/lib/shared/types/CacheSnapshotEntry.ts +15 -0
- package/src/lib/shared/types/CacheStore.ts +32 -0
- package/src/lib/shared/types/ClientFlags.ts +11 -0
- package/src/lib/shared/types/CompileTarget.ts +6 -0
- package/src/lib/shared/types/HttpVerb.ts +1 -0
- package/src/lib/shared/types/LastConnection.ts +9 -0
- package/src/lib/shared/types/PromptArgument.ts +12 -0
- package/src/lib/shared/types/RawRemoteFunction.ts +13 -0
- package/src/lib/shared/types/RemoteFunction.ts +42 -0
- package/src/lib/shared/types/StandardSchemaV1.ts +57 -0
- package/src/lib/shared/types/StreamedResolution.ts +10 -0
- package/src/lib/shared/types/StreamingPlaceholder.ts +13 -0
- package/src/lib/shared/types/Subscribable.ts +15 -0
- package/src/lib/shared/types/SvelteConfig.ts +5 -0
- package/src/lib/shared/withJsonSchema.ts +20 -0
- package/src/lib/shared/writeLastConnection.ts +13 -0
- package/src/lib/shared/writeRoutesDts.ts +67 -0
- package/src/lib/test/clearVerbRegistry.ts +11 -0
- package/src/lib/test/createTestClient.ts +78 -0
- package/src/preload.ts +20 -0
- package/src/scaffold.ts +92 -0
- package/src/serverBuildPlugins.ts +25 -0
- package/src/serverEntry.ts +94 -0
- package/src/sveltePlugin.ts +58 -0
- package/src/tailwindStylePreprocessor.ts +62 -0
- package/template/bunfig.toml +4 -0
- package/template/package.json +19 -0
- package/template/src/app.ts +23 -0
- package/template/src/browser/app.css +21 -0
- package/template/src/browser/app.html +24 -0
- package/template/src/browser/pages/about/page.svelte +5 -0
- package/template/src/browser/pages/layout.svelte +26 -0
- package/template/src/browser/pages/page.svelte +20 -0
- package/template/src/bundle/icon.png +0 -0
- package/template/src/cli/banner.txt +3 -0
- package/template/src/cli/footer.txt +1 -0
- package/template/src/server/config.ts +17 -0
- package/template/src/server/rpc/getHello.ts +35 -0
- package/template/svelte.config.js +12 -0
- package/template/tsconfig.json +18 -0
- 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,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
|
+
}
|