@abide/abide 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +607 -0
- package/LICENSE +21 -0
- package/README.md +154 -0
- package/bin/abide.ts +212 -0
- package/package.json +155 -0
- package/src/abideLsp.ts +211 -0
- package/src/abideModules.d.ts +8 -0
- package/src/abideResolverPlugin.ts +923 -0
- package/src/appEntry.ts +151 -0
- package/src/assets/app.html +12 -0
- package/src/build.ts +143 -0
- package/src/buildCli.ts +127 -0
- package/src/buildDisconnected.ts +118 -0
- package/src/bundleApp.ts +147 -0
- package/src/bundleDisconnectedEntry.ts +14 -0
- package/src/checkAbide.ts +77 -0
- package/src/cliEntry.ts +25 -0
- package/src/clientBuildPlugins.ts +33 -0
- package/src/clientEntry.ts +17 -0
- package/src/compile.ts +63 -0
- package/src/controlServerWorker.ts +426 -0
- package/src/devEntry.ts +250 -0
- package/src/discoveryEntry.ts +81 -0
- package/src/lib/bundle/BundleMenu.ts +12 -0
- package/src/lib/bundle/BundleMenuItem.ts +25 -0
- package/src/lib/bundle/BundleWindow.ts +37 -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 +34 -0
- package/src/lib/bundle/buildWebviewLib.ts +111 -0
- package/src/lib/bundle/bundled.ts +35 -0
- package/src/lib/bundle/disconnected.abide +236 -0
- package/src/lib/bundle/disconnected.css +9 -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/abideMenu.mm +422 -0
- package/src/lib/bundle/native/webview.h +4557 -0
- package/src/lib/bundle/onMenu.ts +42 -0
- package/src/lib/bundle/openWebview.ts +104 -0
- package/src/lib/bundle/pngToIcns.ts +47 -0
- package/src/lib/bundle/probeAbideServer.ts +57 -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 +37 -0
- package/src/lib/bundle/spawnEmbeddedServer.ts +64 -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 +108 -0
- package/src/lib/cli/dispatchCommand.ts +71 -0
- package/src/lib/cli/loadEnvFromBinaryDir.ts +15 -0
- package/src/lib/cli/parseArgvForRpc.ts +100 -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 +176 -0
- package/src/lib/cli/runSession.ts +108 -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 +102 -0
- package/src/lib/mcp/createMcpServer.ts +48 -0
- package/src/lib/mcp/dispatchMcpRequest.ts +138 -0
- package/src/lib/mcp/mcpResourceServerSlot.ts +18 -0
- package/src/lib/mcp/mcpSurface.ts +295 -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 +47 -0
- package/src/lib/server/DELETE.ts +10 -0
- package/src/lib/server/GET.ts +10 -0
- package/src/lib/server/HEAD.ts +10 -0
- package/src/lib/server/PATCH.ts +10 -0
- package/src/lib/server/POST.ts +10 -0
- package/src/lib/server/PUT.ts +10 -0
- package/src/lib/server/agent.ts +86 -0
- package/src/lib/server/appDataDir.ts +16 -0
- package/src/lib/server/cli/buildEnvContent.ts +19 -0
- package/src/lib/server/cli/createTarGz.ts +77 -0
- package/src/lib/server/cli/handleCliDownload.ts +150 -0
- package/src/lib/server/cli/handleCliInstall.ts +37 -0
- package/src/lib/server/cli/installScript.ts +31 -0
- package/src/lib/server/cli/maxSourceMtime.ts +26 -0
- package/src/lib/server/cookies.ts +30 -0
- package/src/lib/server/env.ts +51 -0
- package/src/lib/server/error.ts +73 -0
- package/src/lib/server/json.ts +42 -0
- package/src/lib/server/jsonl.ts +47 -0
- package/src/lib/server/prompts/definePrompt.ts +21 -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 +17 -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/reachable.ts +45 -0
- package/src/lib/server/redirect.ts +43 -0
- package/src/lib/server/request.ts +19 -0
- package/src/lib/server/rpc/defineVerb.ts +210 -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 +127 -0
- package/src/lib/server/rpc/readBodyWithinLimit.ts +44 -0
- package/src/lib/server/rpc/registerVerb.ts +6 -0
- package/src/lib/server/rpc/runWithVerbTimeout.ts +49 -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 +87 -0
- package/src/lib/server/rpc/types/VerbRegistryEntry.ts +35 -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_READY_MESSAGE.ts +6 -0
- package/src/lib/server/runtime/DEV_REBUILD_MESSAGE.ts +4 -0
- package/src/lib/server/runtime/DEV_RELOAD_CLIENT_SCRIPT.ts +107 -0
- package/src/lib/server/runtime/SSR_SWAP_SCRIPT.ts +16 -0
- package/src/lib/server/runtime/acceptsGzip.ts +24 -0
- package/src/lib/server/runtime/buildCacheSnapshot.ts +61 -0
- package/src/lib/server/runtime/buildHealthPayload.ts +34 -0
- package/src/lib/server/runtime/buildInspectorSurface.ts +37 -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/createAppAssetServer.ts +76 -0
- package/src/lib/server/runtime/createAssetHeaderCache.ts +31 -0
- package/src/lib/server/runtime/createPublicAssetServer.ts +67 -0
- package/src/lib/server/runtime/createReachable.ts +109 -0
- package/src/lib/server/runtime/createRouteDispatcher.ts +127 -0
- package/src/lib/server/runtime/createServer.ts +674 -0
- package/src/lib/server/runtime/createUiPageRenderer.ts +181 -0
- package/src/lib/server/runtime/crossOriginForbidden.ts +17 -0
- package/src/lib/server/runtime/crossOriginGate.ts +29 -0
- package/src/lib/server/runtime/devClientFingerprint.ts +117 -0
- package/src/lib/server/runtime/devHotModuleResponse.ts +40 -0
- package/src/lib/server/runtime/devReloadResponse.ts +41 -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 +21 -0
- package/src/lib/server/runtime/getActiveServer.ts +6 -0
- package/src/lib/server/runtime/globToPathSet.ts +29 -0
- package/src/lib/server/runtime/gzipResponse.ts +46 -0
- package/src/lib/server/runtime/inProcessServer.ts +20 -0
- package/src/lib/server/runtime/internalErrorResponse.ts +25 -0
- package/src/lib/server/runtime/isCrossOriginRequest.ts +23 -0
- package/src/lib/server/runtime/listenOnOpenPort.ts +36 -0
- package/src/lib/server/runtime/logExposedSurfaces.ts +156 -0
- package/src/lib/server/runtime/maybeMountInspector.ts +97 -0
- package/src/lib/server/runtime/mimeForExtension.ts +14 -0
- package/src/lib/server/runtime/pageUrlFromStore.ts +15 -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/resolvePageSnapshot.ts +25 -0
- package/src/lib/server/runtime/respondWithEmbeddedAsset.ts +18 -0
- package/src/lib/server/runtime/runWithRequestScope.ts +150 -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 +83 -0
- package/src/lib/server/runtime/streamCacheResolutions.ts +37 -0
- package/src/lib/server/runtime/streamFromIterator.ts +86 -0
- package/src/lib/server/runtime/types/Assets.ts +6 -0
- package/src/lib/server/runtime/types/DevReloadStamp.ts +18 -0
- package/src/lib/server/runtime/types/InspectorCacheEntry.ts +24 -0
- package/src/lib/server/runtime/types/InspectorCacheSnapshot.ts +11 -0
- package/src/lib/server/runtime/types/InspectorContext.ts +30 -0
- package/src/lib/server/runtime/types/InspectorSocket.ts +17 -0
- package/src/lib/server/runtime/types/InspectorSurface.ts +13 -0
- package/src/lib/server/runtime/types/InspectorVerb.ts +27 -0
- package/src/lib/server/runtime/types/RequestStore.ts +55 -0
- package/src/lib/server/runtime/warnUnguardedMcp.ts +32 -0
- package/src/lib/server/runtime/withResponseDefaults.ts +24 -0
- package/src/lib/server/server.ts +33 -0
- package/src/lib/server/socket.ts +32 -0
- package/src/lib/server/sockets/createSocketDispatcher.ts +337 -0
- package/src/lib/server/sockets/defineSocket.ts +179 -0
- package/src/lib/server/sockets/lookupSocket.ts +6 -0
- package/src/lib/server/sockets/registerSocket.ts +6 -0
- package/src/lib/server/sockets/socketOperations.ts +36 -0
- package/src/lib/server/sockets/socketRegistry.ts +9 -0
- package/src/lib/server/sockets/types/Socket.ts +23 -0
- package/src/lib/server/sockets/types/SocketClientFrame.ts +19 -0
- package/src/lib/server/sockets/types/SocketOperation.ts +22 -0
- package/src/lib/server/sockets/types/SocketOptions.ts +26 -0
- package/src/lib/server/sockets/types/SocketRegistryEntry.ts +19 -0
- package/src/lib/server/sockets/types/SocketRoutes.ts +10 -0
- package/src/lib/server/sockets/types/SocketServerFrame.ts +24 -0
- package/src/lib/server/sse.ts +54 -0
- package/src/lib/shared/ABIDE_PACKAGE_NAME.ts +7 -0
- package/src/lib/shared/ABIDE_VERSION.ts +9 -0
- package/src/lib/shared/CACHE_CONTROL_VALUES.ts +16 -0
- package/src/lib/shared/CACHE_WRAPPED.ts +8 -0
- package/src/lib/shared/CLI_PATH.ts +7 -0
- package/src/lib/shared/DEV_HOT_PREFIX.ts +7 -0
- package/src/lib/shared/DEV_RELOAD_PATH.ts +6 -0
- package/src/lib/shared/HEALTH_PATH.ts +7 -0
- package/src/lib/shared/HttpError.ts +20 -0
- package/src/lib/shared/IDENTITY_PATH.ts +6 -0
- package/src/lib/shared/INSPECTOR_PATH.ts +7 -0
- package/src/lib/shared/NAV_HEADER.ts +8 -0
- package/src/lib/shared/OFFLINE_HEADER.ts +8 -0
- package/src/lib/shared/REMOTE_FUNCTION.ts +8 -0
- package/src/lib/shared/REPLAYABLE_METHODS.ts +12 -0
- package/src/lib/shared/SOCKETS_PATH.ts +7 -0
- package/src/lib/shared/STREAMING_CONTENT_TYPES.ts +11 -0
- package/src/lib/shared/SocketDisconnectedError.ts +13 -0
- package/src/lib/shared/TEXT_PLAIN.ts +7 -0
- package/src/lib/shared/abideImportName.ts +44 -0
- package/src/lib/shared/abideLog.ts +38 -0
- package/src/lib/shared/activeCacheStore.ts +20 -0
- package/src/lib/shared/activePage.ts +25 -0
- package/src/lib/shared/appDataDir.ts +34 -0
- package/src/lib/shared/appNameSlot.ts +10 -0
- package/src/lib/shared/basePath.ts +10 -0
- package/src/lib/shared/basePathFromAppUrl.ts +20 -0
- package/src/lib/shared/baseSlot.ts +14 -0
- package/src/lib/shared/binaryDirEnvPath.ts +12 -0
- package/src/lib/shared/browserClientFlags.ts +10 -0
- package/src/lib/shared/buildRpcProxy.ts +39 -0
- package/src/lib/shared/buildRpcRequest.ts +70 -0
- package/src/lib/shared/buildSocketOverChannel.ts +58 -0
- package/src/lib/shared/bundleLayout.ts +36 -0
- package/src/lib/shared/cache.ts +951 -0
- package/src/lib/shared/cacheEntryFromSnapshot.ts +59 -0
- package/src/lib/shared/cacheStoreSlot.ts +16 -0
- package/src/lib/shared/cacheStores.ts +10 -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 +104 -0
- package/src/lib/shared/createChannelLog.ts +122 -0
- package/src/lib/shared/createLifecycleChannel.ts +56 -0
- package/src/lib/shared/createLivenessWatch.ts +118 -0
- package/src/lib/shared/createPushIterator.ts +127 -0
- package/src/lib/shared/createRemoteFunction.ts +122 -0
- package/src/lib/shared/createSubscriber.ts +55 -0
- package/src/lib/shared/createTraceContext.ts +21 -0
- package/src/lib/shared/dataDirEnvPath.ts +12 -0
- package/src/lib/shared/decodeResponse.ts +47 -0
- package/src/lib/shared/detectTarget.ts +27 -0
- package/src/lib/shared/detectVerbMethod.ts +17 -0
- package/src/lib/shared/emitLogRecord.ts +190 -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 +476 -0
- package/src/lib/shared/formatTraceparent.ts +6 -0
- package/src/lib/shared/forwardHeaders.ts +44 -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/health.ts +179 -0
- package/src/lib/shared/healthReadSlot.ts +11 -0
- package/src/lib/shared/healthSeedSlot.ts +12 -0
- package/src/lib/shared/html.ts +38 -0
- package/src/lib/shared/importNamesToStrip.ts +13 -0
- package/src/lib/shared/invalidateEvent.ts +11 -0
- package/src/lib/shared/invalidateTripwire.ts +40 -0
- package/src/lib/shared/isAbideHealthPayload.ts +11 -0
- package/src/lib/shared/isCompileTarget.ts +15 -0
- package/src/lib/shared/isDebugEnabled.ts +26 -0
- package/src/lib/shared/isDebugNegated.ts +19 -0
- package/src/lib/shared/isModuleNotFound.ts +16 -0
- package/src/lib/shared/isReadOnlyMethod.ts +14 -0
- package/src/lib/shared/isReplayableMethod.ts +7 -0
- package/src/lib/shared/isStreamingResponse.ts +11 -0
- package/src/lib/shared/isSubscribable.ts +15 -0
- package/src/lib/shared/jsonSchemaForPromptArguments.ts +29 -0
- package/src/lib/shared/jsonSchemaForSchema.ts +39 -0
- package/src/lib/shared/jsonlErrorFrame.ts +24 -0
- package/src/lib/shared/keyForRemoteCall.ts +29 -0
- package/src/lib/shared/keyMatchesPrefix.ts +9 -0
- package/src/lib/shared/lastConnectionPath.ts +7 -0
- package/src/lib/shared/layoutChainForRoute.ts +22 -0
- package/src/lib/shared/loadEnvFile.ts +17 -0
- package/src/lib/shared/loadEnvFromDataDir.ts +14 -0
- package/src/lib/shared/log.ts +24 -0
- package/src/lib/shared/logClosingRecord.ts +28 -0
- package/src/lib/shared/logTapSlot.ts +13 -0
- package/src/lib/shared/manifestModule.ts +39 -0
- package/src/lib/shared/matchesDebugPattern.ts +16 -0
- package/src/lib/shared/memoizeByKey.ts +32 -0
- package/src/lib/shared/normalizeTarget.ts +10 -0
- package/src/lib/shared/online.ts +51 -0
- package/src/lib/shared/page.ts +30 -0
- package/src/lib/shared/pageSlot.ts +17 -0
- package/src/lib/shared/pageUrlForFile.ts +14 -0
- package/src/lib/shared/parseBoundedEnvInt.ts +20 -0
- package/src/lib/shared/parseDebugPatterns.ts +21 -0
- package/src/lib/shared/parseEnv.ts +30 -0
- package/src/lib/shared/parsePromptMarkdown.ts +35 -0
- package/src/lib/shared/parseRouteSegments.ts +22 -0
- package/src/lib/shared/parseTraceparent.ts +26 -0
- package/src/lib/shared/pending.ts +30 -0
- package/src/lib/shared/prepareRpcModule.ts +59 -0
- package/src/lib/shared/prepareSocketModule.ts +49 -0
- package/src/lib/shared/probeRegistries.ts +68 -0
- package/src/lib/shared/producerKey.ts +32 -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/randomHexId.ts +14 -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/refreshing.ts +31 -0
- package/src/lib/shared/remoteMetaStore.ts +16 -0
- package/src/lib/shared/requestScopeSlot.ts +15 -0
- package/src/lib/shared/resolveClientFlags.ts +20 -0
- package/src/lib/shared/responseErrorText.ts +9 -0
- package/src/lib/shared/rpcTimeoutSlot.ts +9 -0
- package/src/lib/shared/rpcUrlForFile.ts +19 -0
- package/src/lib/shared/runningAsStandaloneBinary.ts +13 -0
- package/src/lib/shared/selectorMatcher.ts +68 -0
- package/src/lib/shared/selectorPrefix.ts +39 -0
- package/src/lib/shared/serializeEnv.ts +18 -0
- package/src/lib/shared/setAppName.ts +5 -0
- package/src/lib/shared/setBaseResolver.ts +6 -0
- package/src/lib/shared/setCacheStoreResolver.ts +6 -0
- package/src/lib/shared/setGlobalCacheStoreResolver.ts +6 -0
- package/src/lib/shared/setPageResolver.ts +7 -0
- package/src/lib/shared/setRequestScopeResolver.ts +6 -0
- package/src/lib/shared/snippet.ts +25 -0
- package/src/lib/shared/socketNameForFile.ts +11 -0
- package/src/lib/shared/socketTapSlot.ts +12 -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/tailProbeSlot.ts +16 -0
- package/src/lib/shared/toBunRoutePattern.ts +28 -0
- package/src/lib/shared/toScopeSet.ts +4 -0
- package/src/lib/shared/trace.ts +16 -0
- package/src/lib/shared/types/CacheEntry.ts +84 -0
- package/src/lib/shared/types/CacheInvalidation.ts +9 -0
- package/src/lib/shared/types/CacheOnContext.ts +25 -0
- package/src/lib/shared/types/CacheOptions.ts +39 -0
- package/src/lib/shared/types/CacheSelector.ts +17 -0
- package/src/lib/shared/types/CacheSnapshot.ts +16 -0
- package/src/lib/shared/types/CacheSnapshotEntry.ts +17 -0
- package/src/lib/shared/types/CacheStats.ts +13 -0
- package/src/lib/shared/types/CacheStore.ts +39 -0
- package/src/lib/shared/types/ChannelLog.ts +13 -0
- package/src/lib/shared/types/ClientFlags.ts +11 -0
- package/src/lib/shared/types/CompileTarget.ts +6 -0
- package/src/lib/shared/types/FrameworkLog.ts +13 -0
- package/src/lib/shared/types/HttpVerb.ts +1 -0
- package/src/lib/shared/types/LastConnection.ts +9 -0
- package/src/lib/shared/types/Log.ts +13 -0
- package/src/lib/shared/types/LogRecord.ts +42 -0
- package/src/lib/shared/types/LogVoice.ts +7 -0
- package/src/lib/shared/types/PageSnapshot.ts +14 -0
- package/src/lib/shared/types/PromptArgument.ts +12 -0
- package/src/lib/shared/types/RawRemoteFunction.ts +14 -0
- package/src/lib/shared/types/RemoteCallable.ts +12 -0
- package/src/lib/shared/types/RemoteFunction.ts +47 -0
- package/src/lib/shared/types/ReplayableMethod.ts +7 -0
- package/src/lib/shared/types/RequestScopeInfo.ts +16 -0
- package/src/lib/shared/types/RpcInvoker.ts +6 -0
- package/src/lib/shared/types/SocketChannel.ts +17 -0
- package/src/lib/shared/types/SocketSubCallbacks.ts +13 -0
- package/src/lib/shared/types/StandardSchemaV1.ts +56 -0
- package/src/lib/shared/types/StreamedResolution.ts +10 -0
- package/src/lib/shared/types/Subscribable.ts +26 -0
- package/src/lib/shared/types/TailHooks.ts +12 -0
- package/src/lib/shared/types/TailOptions.ts +10 -0
- package/src/lib/shared/types/TraceContext.ts +17 -0
- package/src/lib/shared/url.ts +118 -0
- package/src/lib/shared/withBase.ts +11 -0
- package/src/lib/shared/withBaseUrl.ts +17 -0
- package/src/lib/shared/withJsonSchema.ts +21 -0
- package/src/lib/shared/writeDts.ts +12 -0
- package/src/lib/shared/writeHealthDts.ts +36 -0
- package/src/lib/shared/writeLastConnection.ts +13 -0
- package/src/lib/shared/writePublicAssetsDts.ts +31 -0
- package/src/lib/shared/writeRoutesDts.ts +73 -0
- package/src/lib/shared/writeRpcDts.ts +49 -0
- package/src/lib/shared/writeTestRpcDts.ts +45 -0
- package/src/lib/shared/writeTestSocketsDts.ts +34 -0
- package/src/lib/test/assertAgentFrameConformance.ts +73 -0
- package/src/lib/test/createScriptedSurface.ts +45 -0
- package/src/lib/test/createTestApp.ts +203 -0
- package/src/lib/test/createTestSocketChannel.ts +142 -0
- package/src/lib/ui/README.md +86 -0
- package/src/lib/ui/compile/SSR_ESCAPE.ts +25 -0
- package/src/lib/ui/compile/UI_RUNTIME_IMPORTS.ts +36 -0
- package/src/lib/ui/compile/VOID_TAGS.ts +21 -0
- package/src/lib/ui/compile/abideUiPlugin.ts +65 -0
- package/src/lib/ui/compile/analyzeComponent.ts +117 -0
- package/src/lib/ui/compile/assetModulesFile.ts +32 -0
- package/src/lib/ui/compile/branchElements.ts +50 -0
- package/src/lib/ui/compile/collectAbideDiagnostics.ts +59 -0
- package/src/lib/ui/compile/compileComponent.ts +20 -0
- package/src/lib/ui/compile/compileModule.ts +116 -0
- package/src/lib/ui/compile/compileSSR.ts +36 -0
- package/src/lib/ui/compile/compileShadow.ts +352 -0
- package/src/lib/ui/compile/createShadowLanguageService.ts +197 -0
- package/src/lib/ui/compile/createShadowProgram.ts +96 -0
- package/src/lib/ui/compile/decodeHtmlEntities.ts +49 -0
- package/src/lib/ui/compile/desugarSignals.ts +133 -0
- package/src/lib/ui/compile/escapeHtml.ts +15 -0
- package/src/lib/ui/compile/generateBuild.ts +638 -0
- package/src/lib/ui/compile/generateSSR.ts +380 -0
- package/src/lib/ui/compile/groupBindParts.ts +28 -0
- package/src/lib/ui/compile/hoistCells.ts +120 -0
- package/src/lib/ui/compile/loadShadowTsConfig.ts +31 -0
- package/src/lib/ui/compile/lowerDocAccess.ts +202 -0
- package/src/lib/ui/compile/nearestProjectRoot.ts +16 -0
- package/src/lib/ui/compile/parseTemplate.ts +396 -0
- package/src/lib/ui/compile/partitionSlots.ts +36 -0
- package/src/lib/ui/compile/prepareNestedScript.ts +42 -0
- package/src/lib/ui/compile/remapShadowDiagnostic.ts +30 -0
- package/src/lib/ui/compile/renameSignalRefs.ts +85 -0
- package/src/lib/ui/compile/resolveAbideImports.ts +29 -0
- package/src/lib/ui/compile/scopeCss.ts +115 -0
- package/src/lib/ui/compile/shadowNaming.ts +11 -0
- package/src/lib/ui/compile/sourceToShadowOffset.ts +24 -0
- package/src/lib/ui/compile/staticAttrValue.ts +13 -0
- package/src/lib/ui/compile/stripEffects.ts +32 -0
- package/src/lib/ui/compile/types/AbideDiagnostic.ts +14 -0
- package/src/lib/ui/compile/types/AnalyzedComponent.ts +25 -0
- package/src/lib/ui/compile/types/CompiledShadow.ts +15 -0
- package/src/lib/ui/compile/types/TemplateAttr.ts +16 -0
- package/src/lib/ui/compile/types/TemplateNode.ts +78 -0
- package/src/lib/ui/compile/types/TextPart.ts +8 -0
- package/src/lib/ui/derived.ts +28 -0
- package/src/lib/ui/doc.ts +15 -0
- package/src/lib/ui/dom/appendSnippet.ts +34 -0
- package/src/lib/ui/dom/appendStatic.ts +27 -0
- package/src/lib/ui/dom/appendText.ts +114 -0
- package/src/lib/ui/dom/applyResolved.ts +72 -0
- package/src/lib/ui/dom/attach.ts +20 -0
- package/src/lib/ui/dom/attr.ts +19 -0
- package/src/lib/ui/dom/awaitBlock.ts +224 -0
- package/src/lib/ui/dom/cloneStatic.ts +52 -0
- package/src/lib/ui/dom/each.ts +115 -0
- package/src/lib/ui/dom/eachAsync.ts +153 -0
- package/src/lib/ui/dom/hydrate.ts +35 -0
- package/src/lib/ui/dom/mount.ts +29 -0
- package/src/lib/ui/dom/mountChild.ts +33 -0
- package/src/lib/ui/dom/on.ts +15 -0
- package/src/lib/ui/dom/openChild.ts +22 -0
- package/src/lib/ui/dom/openRoot.ts +20 -0
- package/src/lib/ui/dom/switchBlock.ts +75 -0
- package/src/lib/ui/dom/text.ts +20 -0
- package/src/lib/ui/dom/tryBlock.ts +112 -0
- package/src/lib/ui/dom/types/EachRow.ts +3 -0
- package/src/lib/ui/dom/types/SwitchCase.ts +6 -0
- package/src/lib/ui/dom/when.ts +73 -0
- package/src/lib/ui/effect.ts +16 -0
- package/src/lib/ui/installHotBridge.ts +73 -0
- package/src/lib/ui/matchRoute.ts +89 -0
- package/src/lib/ui/navigate.ts +17 -0
- package/src/lib/ui/probeNavigation.ts +33 -0
- package/src/lib/ui/remoteProxy.ts +97 -0
- package/src/lib/ui/renderChain.ts +50 -0
- package/src/lib/ui/renderToStream.ts +104 -0
- package/src/lib/ui/router.ts +286 -0
- package/src/lib/ui/runtime/OUTLET_TAG.ts +8 -0
- package/src/lib/ui/runtime/OWNER.ts +8 -0
- package/src/lib/ui/runtime/REACTIVE_CONTEXT.ts +14 -0
- package/src/lib/ui/runtime/RENDER.ts +23 -0
- package/src/lib/ui/runtime/RESUME.ts +16 -0
- package/src/lib/ui/runtime/applyPatchToTree.ts +41 -0
- package/src/lib/ui/runtime/claimChild.ts +10 -0
- package/src/lib/ui/runtime/clientPage.ts +16 -0
- package/src/lib/ui/runtime/createComputedNode.ts +16 -0
- package/src/lib/ui/runtime/createDoc.ts +177 -0
- package/src/lib/ui/runtime/createEffectNode.ts +58 -0
- package/src/lib/ui/runtime/createSignalNode.ts +16 -0
- package/src/lib/ui/runtime/detachLink.ts +21 -0
- package/src/lib/ui/runtime/endTracking.ts +24 -0
- package/src/lib/ui/runtime/enterRenderPass.ts +12 -0
- package/src/lib/ui/runtime/exitRenderPass.ts +7 -0
- package/src/lib/ui/runtime/firstOutlet.ts +22 -0
- package/src/lib/ui/runtime/flushEffects.ts +17 -0
- package/src/lib/ui/runtime/hotInstances.ts +10 -0
- package/src/lib/ui/runtime/hotReloadEnabled.ts +8 -0
- package/src/lib/ui/runtime/hotReplace.ts +25 -0
- package/src/lib/ui/runtime/nextBlockId.ts +11 -0
- package/src/lib/ui/runtime/pathExists.ts +23 -0
- package/src/lib/ui/runtime/readNode.ts +17 -0
- package/src/lib/ui/runtime/registerHotInstance.ts +23 -0
- package/src/lib/ui/runtime/runNode.ts +28 -0
- package/src/lib/ui/runtime/runtimePath.ts +9 -0
- package/src/lib/ui/runtime/scope.ts +24 -0
- package/src/lib/ui/runtime/toTeardown.ts +26 -0
- package/src/lib/ui/runtime/track.ts +58 -0
- package/src/lib/ui/runtime/trigger.ts +44 -0
- package/src/lib/ui/runtime/types/Cell.ts +5 -0
- package/src/lib/ui/runtime/types/Derived.ts +3 -0
- package/src/lib/ui/runtime/types/Doc.ts +19 -0
- package/src/lib/ui/runtime/types/EffectResult.ts +10 -0
- package/src/lib/ui/runtime/types/HotInstance.ts +14 -0
- package/src/lib/ui/runtime/types/NavVerdict.ts +9 -0
- package/src/lib/ui/runtime/types/Patch.ts +11 -0
- package/src/lib/ui/runtime/types/ReactiveLink.ts +21 -0
- package/src/lib/ui/runtime/types/ReactiveNode.ts +25 -0
- package/src/lib/ui/runtime/types/Route.ts +8 -0
- package/src/lib/ui/runtime/types/RouteLoader.ts +7 -0
- package/src/lib/ui/runtime/types/SsrRender.ts +22 -0
- package/src/lib/ui/runtime/types/State.ts +3 -0
- package/src/lib/ui/runtime/types/Teardown.ts +5 -0
- package/src/lib/ui/runtime/types/UiComponent.ts +16 -0
- package/src/lib/ui/runtime/types/UiProps.ts +15 -0
- package/src/lib/ui/runtime/unlinkDeps.ts +20 -0
- package/src/lib/ui/runtime/untrack.ts +20 -0
- package/src/lib/ui/runtime/valueAtPath.ts +18 -0
- package/src/lib/ui/runtime/writeNode.ts +16 -0
- package/src/lib/ui/socketChannel.ts +227 -0
- package/src/lib/ui/socketProxy.ts +25 -0
- package/src/lib/ui/startClient.ts +58 -0
- package/src/lib/ui/state.ts +25 -0
- package/src/lib/ui/tail.ts +324 -0
- package/src/lib/ui/types/Layouts.ts +9 -0
- package/src/lib/ui/types/Pages.ts +8 -0
- package/src/preload.ts +19 -0
- package/src/scaffold.ts +153 -0
- package/src/serverBuildPlugins.ts +19 -0
- package/src/serverEntry.ts +95 -0
- package/template/bunfig.toml +4 -0
- package/template/package.json +18 -0
- package/template/src/app.ts +28 -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 +36 -0
- package/template/src/ui/Layout.abide +19 -0
- package/template/src/ui/app.css +21 -0
- package/template/src/ui/app.html +24 -0
- package/template/src/ui/pages/about/page.abide +9 -0
- package/template/src/ui/pages/page.abide +22 -0
- package/template/test/app.test.ts +30 -0
- package/template/tsconfig.json +18 -0
- package/tsconfig.app.json +17 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { canonicalJson } from './canonicalJson.ts'
|
|
2
|
+
import { createLivenessWatch } from './createLivenessWatch.ts'
|
|
3
|
+
import { createSubscriber } from './createSubscriber.ts'
|
|
4
|
+
import { HEALTH_PATH } from './HEALTH_PATH.ts'
|
|
5
|
+
import { healthReadSlot } from './healthReadSlot.ts'
|
|
6
|
+
import { healthSeedSlot } from './healthSeedSlot.ts'
|
|
7
|
+
import { isAbideHealthPayload } from './isAbideHealthPayload.ts'
|
|
8
|
+
import { withBase } from './withBase.ts'
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
Augmented by the generated `src/.abide/health.d.ts` with
|
|
12
|
+
`{ fields: <the app health() hook's resolved return> }`, so a project's
|
|
13
|
+
`health()` reads type against its own hook. Unaugmented (no app.ts, or no
|
|
14
|
+
hook), AppHealth resolves to no fields.
|
|
15
|
+
*/
|
|
16
|
+
// @readme observability
|
|
17
|
+
// biome-ignore lint/suspicious/noEmptyInterface: augmented by the generated health.d.ts
|
|
18
|
+
export interface AppHealthMap {}
|
|
19
|
+
export type AppHealth = AppHealthMap extends { fields: infer Fields }
|
|
20
|
+
? Fields extends object
|
|
21
|
+
? Fields
|
|
22
|
+
: Record<never, never>
|
|
23
|
+
: Record<never, never>
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
What health() reports: `reachable` is the framework's transport verdict; the
|
|
27
|
+
rest is the last successful payload, whole — the framework identity (`abide`
|
|
28
|
+
carries the framework version, `name`/`version` the app's) plus the app
|
|
29
|
+
health() hook's fields, exactly as /__abide/health serves them. Fields
|
|
30
|
+
persist while unreachable (last-known state beats vanishing fields: "was
|
|
31
|
+
authenticated, currently unreachable" and "reachable, not authenticated"
|
|
32
|
+
need different UI) and are Partial because nothing has arrived before the
|
|
33
|
+
first poll — unless the SSR seed shipped them with the document.
|
|
34
|
+
*/
|
|
35
|
+
export type HealthState = {
|
|
36
|
+
reachable: boolean
|
|
37
|
+
abide?: string
|
|
38
|
+
name?: string
|
|
39
|
+
version?: string
|
|
40
|
+
} & Partial<AppHealth>
|
|
41
|
+
|
|
42
|
+
const PROBE_INTERVAL_MS = 10_000
|
|
43
|
+
const PROBE_TIMEOUT_MS = 5_000
|
|
44
|
+
|
|
45
|
+
/* Last successful payload's app fields (framework identity keys stripped). */
|
|
46
|
+
let fields: Record<string, unknown> = {}
|
|
47
|
+
/* The watch's verdict; composed with navigator.onLine at read time. */
|
|
48
|
+
let backendAlive = true
|
|
49
|
+
let notify: (() => void) | undefined
|
|
50
|
+
|
|
51
|
+
/*
|
|
52
|
+
One probe: the same standard of proof as the launcher's probeAbideServer —
|
|
53
|
+
a `abide` key in the body, never response.ok alone, because a captive
|
|
54
|
+
portal answers any GET with a 200. Captures the whole payload (identity
|
|
55
|
+
keys included) as a side effect; a changed payload (e.g. authenticated
|
|
56
|
+
flipping) notifies readers even though reachability didn't transition.
|
|
57
|
+
*/
|
|
58
|
+
async function probeHealth(url: string): Promise<boolean> {
|
|
59
|
+
try {
|
|
60
|
+
const response = await fetch(url, {
|
|
61
|
+
headers: { accept: 'application/json' },
|
|
62
|
+
cache: 'no-store',
|
|
63
|
+
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),
|
|
64
|
+
})
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
const body = (await response.json()) as Record<string, unknown>
|
|
69
|
+
if (!isAbideHealthPayload(body)) {
|
|
70
|
+
return false
|
|
71
|
+
}
|
|
72
|
+
applyFields(body)
|
|
73
|
+
return true
|
|
74
|
+
} catch {
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Swaps in a changed payload and notifies readers; identical payloads stay silent. */
|
|
80
|
+
function applyFields(payload: Record<string, unknown>): void {
|
|
81
|
+
if (canonicalJson(payload) !== canonicalJson(fields)) {
|
|
82
|
+
fields = payload
|
|
83
|
+
notify?.()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const watch = createLivenessWatch({
|
|
88
|
+
probe: probeHealth,
|
|
89
|
+
onChange(alive) {
|
|
90
|
+
backendAlive = alive
|
|
91
|
+
notify?.()
|
|
92
|
+
},
|
|
93
|
+
intervalMs: PROBE_INTERVAL_MS,
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
/*
|
|
97
|
+
Reader-driven lifecycle (the createSubscriber rule): the first tracking
|
|
98
|
+
reader starts the poll, the last one tears it down — an app that never
|
|
99
|
+
reads health() never sends a byte. Mirrors the socket channel's visibility
|
|
100
|
+
philosophy: hidden tabs hold no poll (nobody is looking at the banner),
|
|
101
|
+
and the visible transition probes immediately so the value is honest the
|
|
102
|
+
moment eyes return. The online event also probes immediately — recovery
|
|
103
|
+
confirmation shouldn't wait out the interval; offline needs no probe
|
|
104
|
+
because read-time composition with navigator.onLine reports it instantly.
|
|
105
|
+
*/
|
|
106
|
+
const subscribeHealth =
|
|
107
|
+
typeof window === 'undefined'
|
|
108
|
+
? undefined
|
|
109
|
+
: createSubscriber((update) => {
|
|
110
|
+
notify = update
|
|
111
|
+
const onVisibility = () => {
|
|
112
|
+
if (document.visibilityState === 'hidden') {
|
|
113
|
+
watch.stop()
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
watch.watch(withBase(HEALTH_PATH))
|
|
117
|
+
watch.probeNow()
|
|
118
|
+
}
|
|
119
|
+
const onOnline = () => {
|
|
120
|
+
watch.probeNow()
|
|
121
|
+
update()
|
|
122
|
+
}
|
|
123
|
+
const onOffline = () => update()
|
|
124
|
+
document.addEventListener('visibilitychange', onVisibility)
|
|
125
|
+
window.addEventListener('online', onOnline)
|
|
126
|
+
window.addEventListener('offline', onOffline)
|
|
127
|
+
watch.watch(withBase(HEALTH_PATH))
|
|
128
|
+
/*
|
|
129
|
+
SSR seed: a page that read health() during its server render
|
|
130
|
+
shipped the payload in __SSR__ (startClient parks it on the
|
|
131
|
+
slot). The document's arrival just proved the server
|
|
132
|
+
reachable, so the immediate first probe is skipped — the
|
|
133
|
+
watch's interval owns the next one — and the fields apply a
|
|
134
|
+
microtask after connect: the hydration read still matches the
|
|
135
|
+
server-rendered DOM (the server render carried no fields),
|
|
136
|
+
while the update lands before first paint. Consumed once;
|
|
137
|
+
later reconnects probe immediately as usual.
|
|
138
|
+
*/
|
|
139
|
+
const seed = healthSeedSlot.payload
|
|
140
|
+
healthSeedSlot.payload = undefined
|
|
141
|
+
if (seed) {
|
|
142
|
+
queueMicrotask(() => applyFields(seed))
|
|
143
|
+
} else {
|
|
144
|
+
watch.probeNow()
|
|
145
|
+
}
|
|
146
|
+
return () => {
|
|
147
|
+
document.removeEventListener('visibilitychange', onVisibility)
|
|
148
|
+
window.removeEventListener('online', onOnline)
|
|
149
|
+
window.removeEventListener('offline', onOffline)
|
|
150
|
+
watch.stop()
|
|
151
|
+
notify = undefined
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
/*
|
|
156
|
+
Reactive backend-health read: `reachable` plus whatever the app's
|
|
157
|
+
health(request) hook reports, polled from /__abide/health only while a
|
|
158
|
+
tracking scope ($derived/$effect) is reading it. Like tail and cache —
|
|
159
|
+
and unlike the pending()/refreshing() probes — reading this opens a
|
|
160
|
+
resource (the poll). Constant `{ reachable: true }` on the server: the
|
|
161
|
+
server is its own backend. navigator.onLine composes in at read time, so
|
|
162
|
+
a lost network reports instantly without waiting for a probe to time out.
|
|
163
|
+
*/
|
|
164
|
+
export function health(): HealthState {
|
|
165
|
+
/* window, not navigator: Bun defines a partial navigator with no onLine. */
|
|
166
|
+
if (typeof window === 'undefined') {
|
|
167
|
+
/*
|
|
168
|
+
Mark the request (when the server runtime installed a marker) so the
|
|
169
|
+
renderer stamps the health payload into __SSR__ — the client's seed.
|
|
170
|
+
The render itself stays fields-less: the hook may be async and this
|
|
171
|
+
read is sync, so the payload is built after the render returns.
|
|
172
|
+
*/
|
|
173
|
+
healthReadSlot.mark?.()
|
|
174
|
+
return { reachable: true } as HealthState
|
|
175
|
+
}
|
|
176
|
+
subscribeHealth?.()
|
|
177
|
+
/* reachable last: it is the framework's verdict, never a hook field's to shadow. */
|
|
178
|
+
return { ...fields, reachable: backendAlive && navigator.onLine } as HealthState
|
|
179
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Server-side registration point for health()'s SSR read mark. createServer
|
|
3
|
+
installs a marker that flags the current request store; the renderer reads
|
|
4
|
+
the flag to stamp the health payload into __SSR__ only for pages that
|
|
5
|
+
actually read health() during their render — the same reader-driven rule as
|
|
6
|
+
the client poll. Browser bundles never install one, so the shared module's
|
|
7
|
+
call no-ops there. Mirrors requestScopeSlot.
|
|
8
|
+
*/
|
|
9
|
+
export const healthReadSlot: { mark: (() => void) | undefined } = {
|
|
10
|
+
mark: undefined,
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/*
|
|
2
|
+
One-shot handoff of the SSR-stamped health payload (__SSR__.health) from
|
|
3
|
+
startClient to the shared health module. startClient writes it before
|
|
4
|
+
hydrate; health()'s first subscriber consumes it, applying the fields
|
|
5
|
+
without the immediate first probe — the document's arrival just proved the
|
|
6
|
+
server reachable, so the first poll waits a full interval. A slot rather
|
|
7
|
+
than a second export on health.ts keeps the seeding one-way and the module
|
|
8
|
+
single-callable. Mirrors healthReadSlot, its server half.
|
|
9
|
+
*/
|
|
10
|
+
export const healthSeedSlot: { payload: Record<string, unknown> | undefined } = {
|
|
11
|
+
payload: undefined,
|
|
12
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const RAW_HTML = Symbol.for('abide.rawHtml')
|
|
2
|
+
|
|
3
|
+
/* A value marked as trusted raw markup — a `{expr}` interpolation inserts it
|
|
4
|
+
verbatim (not escaped) on both sides. The brand is a registered Symbol, so it
|
|
5
|
+
survives across module/bundle copies. */
|
|
6
|
+
export type RawHtml = { readonly [RAW_HTML]: string }
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
Marks a string as trusted raw HTML so a `{expr}` interpolation inserts its nodes
|
|
10
|
+
instead of escaped text — the abide idiom for raw markup (no `{@html}` mustache).
|
|
11
|
+
Works two ways:
|
|
12
|
+
|
|
13
|
+
html(trustedString) // plain call — insert the string verbatim
|
|
14
|
+
html`<b>${name}</b>` // tagged — concatenate parts verbatim
|
|
15
|
+
|
|
16
|
+
Calling `html` is the explicit opt-in to raw insertion; plain `{value}` always
|
|
17
|
+
escapes. The tag does NOT auto-escape interpolations (it's raw by intent), so only
|
|
18
|
+
build markup from values you trust, or escape them yourself.
|
|
19
|
+
*/
|
|
20
|
+
// @readme plumbing
|
|
21
|
+
export function html(strings: TemplateStringsArray | string, ...values: unknown[]): RawHtml {
|
|
22
|
+
if (typeof strings === 'string') {
|
|
23
|
+
return { [RAW_HTML]: strings }
|
|
24
|
+
}
|
|
25
|
+
let markup = strings[0] ?? ''
|
|
26
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
27
|
+
markup += String(values[index]) + (strings[index + 1] ?? '')
|
|
28
|
+
}
|
|
29
|
+
return { [RAW_HTML]: markup }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* The raw markup of a `html`-branded value, or undefined for anything else
|
|
33
|
+
(so text bindings can fast-path plain values and only branded ones go raw). */
|
|
34
|
+
export function rawHtmlString(value: unknown): string | undefined {
|
|
35
|
+
return value !== null && typeof value === 'object' && RAW_HTML in value
|
|
36
|
+
? (value as RawHtml)[RAW_HTML]
|
|
37
|
+
: undefined
|
|
38
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ABIDE_PACKAGE_NAME } from './ABIDE_PACKAGE_NAME.ts'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
The names a user may import a abide 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 === ABIDE_PACKAGE_NAME
|
|
11
|
+
? [ABIDE_PACKAGE_NAME]
|
|
12
|
+
: [importName, ABIDE_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,40 @@
|
|
|
1
|
+
import { abideLog } from './abideLog.ts'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
Same-selector invalidations within one macrotask before the warning fires. A
|
|
5
|
+
reactive loop spins on microtasks (lifecycle mark → effect flush →
|
|
6
|
+
invalidate), starving macrotasks — so the reset timer below never runs while
|
|
7
|
+
one is live, and legitimate repeats (socket frames, user events) arriving
|
|
8
|
+
across macrotasks clear the count instead.
|
|
9
|
+
*/
|
|
10
|
+
const LOOP_THRESHOLD = 25
|
|
11
|
+
|
|
12
|
+
const invalidationCounts = new Map<string, number>()
|
|
13
|
+
let resetTimer: ReturnType<typeof setTimeout> | undefined
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
Cycle tripwire for cache.invalidate. A synchronous re-run counter (an
|
|
17
|
+
effect-update-depth limit) counts synchronous re-runs, but the probes' lifecycle marks defer a microtask
|
|
18
|
+
(createLifecycleChannel), so a self-feeding effect — one that reads a probe or
|
|
19
|
+
cached value and invalidates a selector that re-wakes its own scope — spins
|
|
20
|
+
forever without tripping it, pinning the CPU. Many invalidations of one
|
|
21
|
+
selector inside a single macrotask is that signature. Warns once per episode
|
|
22
|
+
(the starved reset timer can't fire mid-loop, so the count only crosses the
|
|
23
|
+
threshold once); reporting only — invalidation proceeds.
|
|
24
|
+
*/
|
|
25
|
+
export function invalidateTripwire(selectorLabel: string): void {
|
|
26
|
+
const count = (invalidationCounts.get(selectorLabel) ?? 0) + 1
|
|
27
|
+
invalidationCounts.set(selectorLabel, count)
|
|
28
|
+
if (resetTimer === undefined) {
|
|
29
|
+
resetTimer = setTimeout(() => {
|
|
30
|
+
resetTimer = undefined
|
|
31
|
+
invalidationCounts.clear()
|
|
32
|
+
}, 0)
|
|
33
|
+
resetTimer.unref?.()
|
|
34
|
+
}
|
|
35
|
+
if (count === LOOP_THRESHOLD) {
|
|
36
|
+
abideLog.warn(
|
|
37
|
+
`cache.invalidate(${selectorLabel}) fired ${LOOP_THRESHOLD}× within one task — likely a reactive loop: an effect that reads pending()/refreshing() or a cached value and invalidates a selector waking its own scope re-triggers itself across microtasks, invisible to synchronous loop detection. Find the effect invalidating ${selectorLabel}.`,
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Whether a health/identity response body identifies a abide server. The
|
|
3
|
+
`abide` field carries the framework version (a non-empty string) on current
|
|
4
|
+
servers and `true` on older ones — both accepted, so a newer prober still
|
|
5
|
+
recognises an older server. The body check (never response.ok alone) is the
|
|
6
|
+
captive-portal defense shared by every prober: a portal answers any GET with
|
|
7
|
+
a 200, but it doesn't answer with this.
|
|
8
|
+
*/
|
|
9
|
+
export function isAbideHealthPayload(body: { abide?: unknown }): boolean {
|
|
10
|
+
return body.abide === true || (typeof body.abide === 'string' && body.abide !== '')
|
|
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,26 @@
|
|
|
1
|
+
import { isDebugNegated } from './isDebugNegated.ts'
|
|
2
|
+
import { matchesDebugPattern } from './matchesDebugPattern.ts'
|
|
3
|
+
import { parseDebugPatterns } from './parseDebugPatterns.ts'
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
Whether a DEBUG-gated channel is enabled, npm-debug conventions:
|
|
7
|
+
DEBUG="abide" → enables "abide"
|
|
8
|
+
DEBUG="abide:*" → enables "abide" and "abide:anything"
|
|
9
|
+
DEBUG="*" → enables everything
|
|
10
|
+
DEBUG="a,abide" → comma-separated list
|
|
11
|
+
DEBUG="abide:*,-abide:cache" → negation: exclusions win over inclusions
|
|
12
|
+
Always-on channels don't consult this — they check isDebugNegated only.
|
|
13
|
+
The default is guarded: this runs in the browser bundle, where `process`
|
|
14
|
+
doesn't exist.
|
|
15
|
+
*/
|
|
16
|
+
export function isDebugEnabled(
|
|
17
|
+
name: string,
|
|
18
|
+
env: string | undefined = typeof process === 'undefined' ? undefined : process.env.DEBUG,
|
|
19
|
+
): boolean {
|
|
20
|
+
if (isDebugNegated(name, env)) {
|
|
21
|
+
return false
|
|
22
|
+
}
|
|
23
|
+
return parseDebugPatterns(env)
|
|
24
|
+
.filter((pattern) => !pattern.startsWith('-'))
|
|
25
|
+
.some((pattern) => matchesDebugPattern(name, pattern))
|
|
26
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { matchesDebugPattern } from './matchesDebugPattern.ts'
|
|
2
|
+
import { parseDebugPatterns } from './parseDebugPatterns.ts'
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
Whether a `-` pattern in DEBUG explicitly shuts a channel off — the off
|
|
6
|
+
switch for the always-on channels (the app's name, 'abide'): DEBUG="-abide"
|
|
7
|
+
silences framework lines including the per-request closing records,
|
|
8
|
+
DEBUG="-myapp" the app's own. Silencing a channel silences all its levels —
|
|
9
|
+
levels never gate, in either direction. The default is guarded: this runs in
|
|
10
|
+
the browser bundle, where `process` doesn't exist.
|
|
11
|
+
*/
|
|
12
|
+
export function isDebugNegated(
|
|
13
|
+
name: string,
|
|
14
|
+
env: string | undefined = typeof process === 'undefined' ? undefined : process.env.DEBUG,
|
|
15
|
+
): boolean {
|
|
16
|
+
return parseDebugPatterns(env)
|
|
17
|
+
.filter((pattern) => pattern.startsWith('-'))
|
|
18
|
+
.some((pattern) => matchesDebugPattern(name, pattern.slice(1)))
|
|
19
|
+
}
|
|
@@ -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. Abide
|
|
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,7 @@
|
|
|
1
|
+
import { REPLAYABLE_METHODS } from './REPLAYABLE_METHODS.ts'
|
|
2
|
+
import type { ReplayableMethod } from './types/ReplayableMethod.ts'
|
|
3
|
+
|
|
4
|
+
/* Narrowing gate over REPLAYABLE_METHODS so callers get the typed method without a cast. */
|
|
5
|
+
export function isReplayableMethod(method: string): method is ReplayableMethod {
|
|
6
|
+
return REPLAYABLE_METHODS.has(method)
|
|
7
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Subscribable } from './types/Subscribable.ts'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
A Subscribable is a named AsyncIterable — distinguishes a stream argument from
|
|
5
|
+
the other probe selector shapes (callables and `{ scope }` objects, neither of
|
|
6
|
+
which carries Symbol.asyncIterator).
|
|
7
|
+
*/
|
|
8
|
+
export function isSubscribable(value: unknown): value is Subscribable<unknown> {
|
|
9
|
+
return (
|
|
10
|
+
typeof value === 'object' &&
|
|
11
|
+
value !== null &&
|
|
12
|
+
Symbol.asyncIterator in value &&
|
|
13
|
+
'name' in value
|
|
14
|
+
)
|
|
15
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PromptArgument } from './types/PromptArgument.ts'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
Turns a markdown prompt's frontmatter `arguments` list into the JSON
|
|
5
|
+
Schema the MCP dispatcher advertises in `prompts/list` (top-level string
|
|
6
|
+
properties + a `required` array). Prompt arguments are always strings —
|
|
7
|
+
MCP fills them from model output — so every property is `{ type: 'string' }`.
|
|
8
|
+
Returns undefined for an argument-less prompt so the generated module
|
|
9
|
+
omits the field entirely.
|
|
10
|
+
*/
|
|
11
|
+
export function jsonSchemaForPromptArguments(
|
|
12
|
+
args: PromptArgument[],
|
|
13
|
+
): Record<string, unknown> | undefined {
|
|
14
|
+
if (args.length === 0) {
|
|
15
|
+
return undefined
|
|
16
|
+
}
|
|
17
|
+
const properties = Object.fromEntries(
|
|
18
|
+
args.map((arg) => [
|
|
19
|
+
arg.name,
|
|
20
|
+
{ type: 'string', ...(arg.description ? { description: arg.description } : {}) },
|
|
21
|
+
]),
|
|
22
|
+
)
|
|
23
|
+
const required = args.filter((arg) => arg.required).map((arg) => arg.name)
|
|
24
|
+
return {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties,
|
|
27
|
+
...(required.length > 0 ? { required } : {}),
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from './types/StandardSchemaV1.ts'
|
|
2
|
+
|
|
3
|
+
const OPAQUE = { type: 'object', additionalProperties: true } as const
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
Resolves a JSON Schema for an MCP tool's `inputSchema`, an OpenAPI body, a CLI
|
|
7
|
+
flag set, or the bundle setup form. Probes the schema's own projection:
|
|
8
|
+
|
|
9
|
+
1. `schema.toJsonSchema()` (Arktype 2+)
|
|
10
|
+
2. `schema.toJSONSchema()` (Zod 4, Effect Schema, or a withJsonSchema wrap)
|
|
11
|
+
3. Opaque object — the surface still works, the consumer just gets no shape hint
|
|
12
|
+
|
|
13
|
+
A projection that exists but throws (e.g. Zod 4 can't render `z.custom()`)
|
|
14
|
+
degrades to the same opaque fallback rather than escaping — one un-serializable
|
|
15
|
+
schema must not take down the whole list its caller is building (an MCP
|
|
16
|
+
tools/list, an OpenAPI doc). Wrap with withJsonSchema to supply a shape.
|
|
17
|
+
|
|
18
|
+
Schemas whose library exposes neither carry one via withJsonSchema. Returns a
|
|
19
|
+
fresh object each call; callers can mutate (e.g. add a description) without
|
|
20
|
+
aliasing the schema's own.
|
|
21
|
+
*/
|
|
22
|
+
export function jsonSchemaForSchema(schema: StandardSchemaV1 | undefined): Record<string, unknown> {
|
|
23
|
+
if (!schema) {
|
|
24
|
+
return { ...OPAQUE }
|
|
25
|
+
}
|
|
26
|
+
const candidate = schema as unknown as {
|
|
27
|
+
toJsonSchema?: () => Record<string, unknown>
|
|
28
|
+
toJSONSchema?: () => Record<string, unknown>
|
|
29
|
+
}
|
|
30
|
+
const project = candidate.toJsonSchema ?? candidate.toJSONSchema
|
|
31
|
+
if (typeof project !== 'function') {
|
|
32
|
+
return { ...OPAQUE }
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
return { ...project.call(candidate) }
|
|
36
|
+
} catch {
|
|
37
|
+
return { ...OPAQUE }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
The in-band error sentinel for a JSONL/NDJSON stream: when a handler's
|
|
3
|
+
generator throws, `jsonl()` emits a final `{"$error":"<message>"}` line,
|
|
4
|
+
and `streamResponse` re-throws it on the consumer side. Encoder and decoder
|
|
5
|
+
live together here so the sentinel field has one definition and can't drift
|
|
6
|
+
between the two ends of the wire.
|
|
7
|
+
*/
|
|
8
|
+
export const jsonlErrorFrame = {
|
|
9
|
+
// Error line for a thrown message, including the trailing newline.
|
|
10
|
+
encode(message: string): string {
|
|
11
|
+
return `${JSON.stringify({ $error: message })}\n`
|
|
12
|
+
},
|
|
13
|
+
// The message carried by a parsed line, or undefined when it isn't the error sentinel.
|
|
14
|
+
decode(parsed: unknown): string | undefined {
|
|
15
|
+
if (
|
|
16
|
+
parsed &&
|
|
17
|
+
typeof parsed === 'object' &&
|
|
18
|
+
typeof (parsed as { $error?: unknown }).$error === 'string'
|
|
19
|
+
) {
|
|
20
|
+
return (parsed as { $error: string }).$error
|
|
21
|
+
}
|
|
22
|
+
return undefined
|
|
23
|
+
},
|
|
24
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { canonicalJson } from './canonicalJson.ts'
|
|
2
|
+
import { carriesBodyArgs } from './carriesBodyArgs.ts'
|
|
3
|
+
import { queryStringFromArgs } from './queryStringFromArgs.ts'
|
|
4
|
+
import type { HttpVerb } from './types/HttpVerb.ts'
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
Derives a cache key from a verb-defined remote function and its args. The
|
|
8
|
+
prefix is `${method} ${url}` where `url` is the route template. GET/DELETE/HEAD
|
|
9
|
+
serialise args onto the URL as `?key=value` (sorted, via queryStringFromArgs —
|
|
10
|
+
the same encoder buildRpcRequest builds its query with, so the key and the
|
|
11
|
+
synthesized Request can't disagree); POST/PUT/PATCH join args after a space as
|
|
12
|
+
canonical JSON. The verb split mirrors buildRpcRequest exactly.
|
|
13
|
+
*/
|
|
14
|
+
export function keyForRemoteCall(method: HttpVerb, url: string, args: unknown): string {
|
|
15
|
+
const prefix = `${method} ${url}`
|
|
16
|
+
if (!carriesBodyArgs(method)) {
|
|
17
|
+
if (args && typeof args === 'object' && !Array.isArray(args)) {
|
|
18
|
+
const search = queryStringFromArgs(args as Record<string, unknown>, true)
|
|
19
|
+
if (search.length > 0) {
|
|
20
|
+
return `${prefix}?${search}`
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return prefix
|
|
24
|
+
}
|
|
25
|
+
if (args === undefined) {
|
|
26
|
+
return prefix
|
|
27
|
+
}
|
|
28
|
+
return `${prefix} ${canonicalJson(args)}`
|
|
29
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/*
|
|
2
|
+
The selector-prefix grammar shared by selectorMatcher and the cache store's
|
|
3
|
+
scoped lifecycle marks: a prefix owns its exact key plus arg-bearing
|
|
4
|
+
extensions — `?` (GET/DELETE query args) or ` ` (canonical-json body /
|
|
5
|
+
producer args) — so `GET /a` never matches `GET /ab`.
|
|
6
|
+
*/
|
|
7
|
+
export function keyMatchesPrefix(key: string, prefix: string): boolean {
|
|
8
|
+
return key === prefix || key.startsWith(`${prefix}?`) || key.startsWith(`${prefix} `)
|
|
9
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
import { appDataDir } from './appDataDir.ts'
|
|
3
|
+
|
|
4
|
+
// Path to the per-program last-connection record, beside the data-dir `.env`.
|
|
5
|
+
export function lastConnectionPath(programName: string): string {
|
|
6
|
+
return join(appDataDir(programName), 'last-connection.json')
|
|
7
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
The ordered layout chain that wraps a page route: every directory prefix that
|
|
3
|
+
holds a `layout.abide` and is an ancestor of (or equal to) the route, outermost
|
|
4
|
+
first. `layoutKeys` are directory URLs (a layout's URL is its folder path, via
|
|
5
|
+
pageUrlForFile). `/` matches every route; a deeper prefix matches when the route
|
|
6
|
+
equals it or descends into it. Dynamic segments compare literally (`/media/[id]`)
|
|
7
|
+
since both keys and routes carry the same `[name]` form. Pure — both the SSR
|
|
8
|
+
renderer and the client router resolve a page's chain from the same function so
|
|
9
|
+
they nest identically.
|
|
10
|
+
*/
|
|
11
|
+
export function layoutChainForRoute(routeUrl: string, layoutKeys: Iterable<string>): string[] {
|
|
12
|
+
const route = routeUrl === '/' ? '' : routeUrl.replace(/^\//, '')
|
|
13
|
+
const applies: string[] = []
|
|
14
|
+
for (const key of layoutKeys) {
|
|
15
|
+
const dir = key === '/' ? '' : key.replace(/^\//, '')
|
|
16
|
+
if (dir === '' || route === dir || route.startsWith(`${dir}/`)) {
|
|
17
|
+
applies.push(key)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/* Outermost first: a shorter prefix is an ancestor of a longer one. */
|
|
21
|
+
return applies.sort((first, second) => first.length - second.length)
|
|
22
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { readEnvFile } from './readEnvFile.ts'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
Reads a `.env` at `path` and merges each declared var into `process.env`
|
|
5
|
+
only when not already set. Fill-when-unset is the precedence rule the whole
|
|
6
|
+
env stack relies on: layers loaded earlier (shell/ambient, Bun's CWD `.env`)
|
|
7
|
+
win, and later callers back-fill only what's still missing. So a value's
|
|
8
|
+
source is invisible to the app — it reads one flat `process.env` (Bun.env is
|
|
9
|
+
the same object). Missing file is a no-op.
|
|
10
|
+
*/
|
|
11
|
+
export async function loadEnvFile(path: string): Promise<void> {
|
|
12
|
+
for (const [key, value] of Object.entries(await readEnvFile(path))) {
|
|
13
|
+
if (process.env[key] === undefined) {
|
|
14
|
+
process.env[key] = value
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|