@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,59 @@
|
|
|
1
|
+
import type { CacheEntry } from './types/CacheEntry.ts'
|
|
2
|
+
import type { CacheSnapshotEntry } from './types/CacheSnapshotEntry.ts'
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
Rebuilds a warm cache entry from a wire snapshot: an already-resolved Response
|
|
6
|
+
plus the synchronously-decoded warm value, so cache() reads it without a network
|
|
7
|
+
round-trip or a microtask hop. Shared by the initial inline snapshot hydration
|
|
8
|
+
and the streamed resolution path. `settled` is true — the body shipped fully
|
|
9
|
+
resolved either way. `hydrated` marks that the wrap options didn't travel:
|
|
10
|
+
the first cache() read adopts its call site's ttl (see CacheEntry).
|
|
11
|
+
*/
|
|
12
|
+
export function cacheEntryFromSnapshot(entry: CacheSnapshotEntry): CacheEntry {
|
|
13
|
+
const headers = new Headers(entry.headers)
|
|
14
|
+
const response = new Response(entry.body, {
|
|
15
|
+
status: entry.status,
|
|
16
|
+
statusText: entry.statusText,
|
|
17
|
+
headers,
|
|
18
|
+
})
|
|
19
|
+
return {
|
|
20
|
+
key: entry.key,
|
|
21
|
+
promise: Promise.resolve(response),
|
|
22
|
+
request: new Request(entry.url, { method: entry.method }),
|
|
23
|
+
ttl: undefined,
|
|
24
|
+
expiresAt: undefined,
|
|
25
|
+
value: warmValueFromSnapshot(entry.status, headers, entry.body),
|
|
26
|
+
settled: true,
|
|
27
|
+
hydrated: true,
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
Synchronously decodes a snapshot body so the warm entry reads without a
|
|
33
|
+
microtask hop on first render. Mirrors decodeResponse for the textual cases the
|
|
34
|
+
snapshot ships; non-2xx and 204 yield no warm value and fall back to the async
|
|
35
|
+
path, which throws HttpError / returns undefined exactly as a live call would.
|
|
36
|
+
Binary/xml bodies also skip the warm path and decode asynchronously.
|
|
37
|
+
*/
|
|
38
|
+
function warmValueFromSnapshot(status: number, headers: Headers, body: string): unknown {
|
|
39
|
+
if (status === 204 || status < 200 || status >= 300) {
|
|
40
|
+
return undefined
|
|
41
|
+
}
|
|
42
|
+
const contentType = (headers.get('content-type') ?? '').toLowerCase()
|
|
43
|
+
if (contentType.includes('json')) {
|
|
44
|
+
/*
|
|
45
|
+
`.includes('json')` also matches streaming/non-JSON types like
|
|
46
|
+
application/x-ndjson; fall back to the async path (return undefined)
|
|
47
|
+
rather than throwing a SyntaxError synchronously during hydration.
|
|
48
|
+
*/
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(body)
|
|
51
|
+
} catch {
|
|
52
|
+
return undefined
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (contentType.startsWith('text/')) {
|
|
56
|
+
return body
|
|
57
|
+
}
|
|
58
|
+
return undefined
|
|
59
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CacheStore } from './types/CacheStore.ts'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
Internal slot the runtime entries register their resolver into. The
|
|
5
|
+
server entry installs an ALS-backed resolver (request-scoped); the
|
|
6
|
+
client entry installs a module-singleton resolver. `fallback` is a
|
|
7
|
+
single lazy store used only when no resolver is registered — keeps
|
|
8
|
+
isolated tests working without forcing them to spin up the runtime.
|
|
9
|
+
*/
|
|
10
|
+
export const cacheStoreSlot: {
|
|
11
|
+
resolver: (() => CacheStore | undefined) | undefined
|
|
12
|
+
fallback: CacheStore | undefined
|
|
13
|
+
} = {
|
|
14
|
+
resolver: undefined,
|
|
15
|
+
fallback: undefined,
|
|
16
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { activeCacheStore } from './activeCacheStore.ts'
|
|
2
|
+
import { globalCacheStore } from './globalCacheStore.ts'
|
|
3
|
+
import type { CacheStore } from './types/CacheStore.ts'
|
|
4
|
+
|
|
5
|
+
/* Active + process-level stores, deduped (one tab store on the client). */
|
|
6
|
+
export function cacheStores(): CacheStore[] {
|
|
7
|
+
const active = activeCacheStore()
|
|
8
|
+
const global = globalCacheStore()
|
|
9
|
+
return active === global ? [active] : [active, global]
|
|
10
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Deterministic key string for a value. Object keys (and Map keys, Set members)
|
|
3
|
+
are sorted so values differing only in insertion order produce identical
|
|
4
|
+
strings, and every recognised type carries a tag so distinct types never
|
|
5
|
+
collide — a Date never equals the string of its ISO form, a Map never equals a
|
|
6
|
+
plain object. Used to derive cache keys from producer args and from auto-keyed
|
|
7
|
+
POST/PUT/PATCH bodies; the output is a key, not a request body, so it is free to
|
|
8
|
+
encode types JSON.stringify would silently flatten (Map/Set → {}), coerce
|
|
9
|
+
(Date → its ISO string, via toJSON before any replacer sees it) or drop
|
|
10
|
+
(undefined). Covers the value types commonly passed as rpc args: primitives,
|
|
11
|
+
arrays, plain objects, Date, Map, Set, and bigint. Functions and symbols can't
|
|
12
|
+
key anything meaningful but are tagged rather than dropped so a stray one can't
|
|
13
|
+
silently collapse two distinct argument sets onto the same key.
|
|
14
|
+
*/
|
|
15
|
+
export function canonicalJson(value: unknown): string {
|
|
16
|
+
if (value === null) {
|
|
17
|
+
return 'null'
|
|
18
|
+
}
|
|
19
|
+
if (value === undefined) {
|
|
20
|
+
return 'undefined'
|
|
21
|
+
}
|
|
22
|
+
const type = typeof value
|
|
23
|
+
if (type === 'string') {
|
|
24
|
+
return JSON.stringify(value)
|
|
25
|
+
}
|
|
26
|
+
if (type === 'bigint') {
|
|
27
|
+
return `${value}n`
|
|
28
|
+
}
|
|
29
|
+
if (type === 'number') {
|
|
30
|
+
// -0 and 0 stringify alike but are distinct keys; NaN/Infinity stay stable (JSON drops them to null).
|
|
31
|
+
return Object.is(value, -0) ? '-0' : String(value)
|
|
32
|
+
}
|
|
33
|
+
if (type === 'boolean') {
|
|
34
|
+
return String(value)
|
|
35
|
+
}
|
|
36
|
+
if (type !== 'object') {
|
|
37
|
+
// function | symbol — not serialisable; tag by type so the key can't crash or alias a real value.
|
|
38
|
+
return `${type}()`
|
|
39
|
+
}
|
|
40
|
+
if (value instanceof Date) {
|
|
41
|
+
return `Date(${value.getTime()})`
|
|
42
|
+
}
|
|
43
|
+
if (Array.isArray(value)) {
|
|
44
|
+
return `[${value.map(canonicalJson).join(',')}]`
|
|
45
|
+
}
|
|
46
|
+
if (value instanceof Map) {
|
|
47
|
+
// Sort by encoded entry so key order doesn't change the result.
|
|
48
|
+
const entries = Array.from(
|
|
49
|
+
value,
|
|
50
|
+
([key, val]) => `${canonicalJson(key)}=>${canonicalJson(val)}`,
|
|
51
|
+
).sort()
|
|
52
|
+
return `Map{${entries.join(',')}}`
|
|
53
|
+
}
|
|
54
|
+
if (value instanceof Set) {
|
|
55
|
+
const members = Array.from(value, canonicalJson).sort()
|
|
56
|
+
return `Set{${members.join(',')}}`
|
|
57
|
+
}
|
|
58
|
+
const record = value as Record<string, unknown>
|
|
59
|
+
const entries = Object.keys(record)
|
|
60
|
+
.sort()
|
|
61
|
+
.map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`)
|
|
62
|
+
return `{${entries.join(',')}}`
|
|
63
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { HttpVerb } from './types/HttpVerb.ts'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
Whether a verb carries its args in the request body (POST/PUT/PATCH) vs
|
|
5
|
+
on the query string (GET/DELETE/HEAD). Single source for the split so the
|
|
6
|
+
synthesized Request (buildRpcRequest), the handler-side parse (parseArgs),
|
|
7
|
+
the cache key (keyForRemoteCall), and the OpenAPI doc can't disagree.
|
|
8
|
+
*/
|
|
9
|
+
const BODY_METHODS = new Set<HttpVerb>(['POST', 'PUT', 'PATCH'])
|
|
10
|
+
|
|
11
|
+
export function carriesBodyArgs(method: HttpVerb): boolean {
|
|
12
|
+
return BODY_METHODS.has(method)
|
|
13
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { rm } from 'node:fs/promises'
|
|
2
|
+
import { lastConnectionPath } from './lastConnectionPath.ts'
|
|
3
|
+
|
|
4
|
+
// Forgets the saved connection (the `/disconnect` reset). Missing file is a no-op.
|
|
5
|
+
export async function clearLastConnection(programName: string): Promise<void> {
|
|
6
|
+
await rm(lastConnectionPath(programName), { force: true })
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Derives the MCP tool name / CLI subcommand name from an rpc URL. Strips
|
|
3
|
+
the framework's `/rpc/` mount and joins nested folder segments with `-`
|
|
4
|
+
so `users/list.ts` (mounted at `/rpc/users/list`) becomes `users-list`
|
|
5
|
+
across both surfaces. Folder prefixing prevents collisions when two
|
|
6
|
+
files in different folders share the same stem (e.g. `users/list.ts`
|
|
7
|
+
and `posts/list.ts`); `/` is not a valid character in MCP tool names or
|
|
8
|
+
typical CLI subcommands, so the join uses `-`.
|
|
9
|
+
*/
|
|
10
|
+
const RPC_PREFIX = '/rpc/'
|
|
11
|
+
|
|
12
|
+
export function commandNameForUrl(url: string): string {
|
|
13
|
+
const trimmed = url.startsWith(RPC_PREFIX)
|
|
14
|
+
? url.slice(RPC_PREFIX.length)
|
|
15
|
+
: url.replace(/^\//, '')
|
|
16
|
+
return trimmed.replaceAll('/', '-')
|
|
17
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { createLifecycleChannel } from './createLifecycleChannel.ts'
|
|
2
|
+
import { createSubscriber } from './createSubscriber.ts'
|
|
3
|
+
import { keyMatchesPrefix } from './keyMatchesPrefix.ts'
|
|
4
|
+
import type { CacheEntry } from './types/CacheEntry.ts'
|
|
5
|
+
import type { CacheInvalidation } from './types/CacheInvalidation.ts'
|
|
6
|
+
import type { CacheStore } from './types/CacheStore.ts'
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
Returns a fresh cache store. On the server, every request gets its own
|
|
10
|
+
store via the AsyncLocalStorage RequestStore. On the client, a single
|
|
11
|
+
module-level store is created at startup and shared across the tab.
|
|
12
|
+
|
|
13
|
+
Each key gets a lazily-created subscriber. Reading a key from a
|
|
14
|
+
tracking scope (derived / effect) subscribes that scope; invalidating
|
|
15
|
+
the key dispatches an 'invalidate' event whose detail is a Set of affected
|
|
16
|
+
keys so each listener's lookup is O(1). The subscriber outlives entry
|
|
17
|
+
eviction — invalidating/refetching a key reuses the same subscriber, so
|
|
18
|
+
there's no listener churn or duplicate registration as cache values come
|
|
19
|
+
and go. It's evicted only when its last reactive reader tears down (the
|
|
20
|
+
client store is module-level/tab-scoped, so retaining a thunk per distinct
|
|
21
|
+
key would otherwise grow unbounded across a session), identity-guarded so
|
|
22
|
+
a concurrent re-subscribe isn't clobbered — mirroring tail.ts.
|
|
23
|
+
*/
|
|
24
|
+
export function createCacheStore(): CacheStore {
|
|
25
|
+
const entries = new Map<string, CacheEntry>()
|
|
26
|
+
const events = new EventTarget()
|
|
27
|
+
const subscribers = new Map<string, () => void>()
|
|
28
|
+
const pendingRefresh = new Set<string>()
|
|
29
|
+
|
|
30
|
+
function subscribe(key: string): void {
|
|
31
|
+
const existing = subscribers.get(key)
|
|
32
|
+
if (existing) {
|
|
33
|
+
existing()
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
const registered = createSubscriber((update) => {
|
|
37
|
+
const onInvalidate = (event: Event) => {
|
|
38
|
+
if ((event as CustomEvent<CacheInvalidation>).detail.has(key)) {
|
|
39
|
+
update()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
events.addEventListener('invalidate', onInvalidate)
|
|
43
|
+
return () => {
|
|
44
|
+
events.removeEventListener('invalidate', onInvalidate)
|
|
45
|
+
if (subscribers.get(key) === registered) {
|
|
46
|
+
subscribers.delete(key)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
subscribers.set(key, registered)
|
|
51
|
+
registered()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Store-wide in-flight tap for the probes; semantics live in createLifecycleChannel. */
|
|
55
|
+
const lifecycle = createLifecycleChannel()
|
|
56
|
+
/*
|
|
57
|
+
Per-prefix channels arm fn-selector probes (pending(fn) / refreshing(fn))
|
|
58
|
+
without waking them on unrelated cache events. Keyed by selector prefix
|
|
59
|
+
(method+url / producer reference id — see selectorPrefix), so the
|
|
60
|
+
population is bounded by probe call sites in code, not by data; a channel
|
|
61
|
+
whose last reader tore down is an inert closure, not a leak.
|
|
62
|
+
*/
|
|
63
|
+
const prefixLifecycles = new Map<string, ReturnType<typeof createLifecycleChannel>>()
|
|
64
|
+
|
|
65
|
+
function trackLifecycle(keyPrefix?: string): void {
|
|
66
|
+
if (keyPrefix === undefined) {
|
|
67
|
+
lifecycle.track()
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
let channel = prefixLifecycles.get(keyPrefix)
|
|
71
|
+
if (channel === undefined) {
|
|
72
|
+
channel = createLifecycleChannel()
|
|
73
|
+
prefixLifecycles.set(keyPrefix, channel)
|
|
74
|
+
}
|
|
75
|
+
channel.track()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/*
|
|
79
|
+
Marks the store-wide channel always (bare/scope probes scan everything)
|
|
80
|
+
plus any probed prefix channel owning the changed key — a new entry's key
|
|
81
|
+
starts with its fn's prefix, so prefix probes see membership too.
|
|
82
|
+
*/
|
|
83
|
+
function markLifecycle(key?: string): void {
|
|
84
|
+
lifecycle.mark()
|
|
85
|
+
if (key === undefined) {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
prefixLifecycles.forEach((channel, prefix) => {
|
|
89
|
+
if (keyMatchesPrefix(key, prefix)) {
|
|
90
|
+
channel.mark()
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
entries,
|
|
97
|
+
events,
|
|
98
|
+
subscribe,
|
|
99
|
+
trackLifecycle,
|
|
100
|
+
markLifecycle,
|
|
101
|
+
pendingRefresh,
|
|
102
|
+
stats: { hits: 0, misses: 0, coalesced: 0 },
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { emitLogRecord } from './emitLogRecord.ts'
|
|
2
|
+
import { isDebugEnabled } from './isDebugEnabled.ts'
|
|
3
|
+
import { isDebugNegated } from './isDebugNegated.ts'
|
|
4
|
+
import { randomHexId } from './randomHexId.ts'
|
|
5
|
+
import type { ChannelLog } from './types/ChannelLog.ts'
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
Channel gating source. Server: the DEBUG env var, npm-debug conventions via
|
|
9
|
+
isDebugEnabled. Browser: the `abide-debug` localStorage key with the same
|
|
10
|
+
pattern syntax, read per call so toggling it in devtools takes effect without
|
|
11
|
+
a reload. localStorage access is guarded — privacy modes throw on read.
|
|
12
|
+
*/
|
|
13
|
+
function channelPatterns(): string | undefined {
|
|
14
|
+
if (typeof process !== 'undefined' && process.env.DEBUG) {
|
|
15
|
+
return process.env.DEBUG
|
|
16
|
+
}
|
|
17
|
+
if (typeof localStorage !== 'undefined') {
|
|
18
|
+
try {
|
|
19
|
+
return localStorage.getItem('abide-debug') ?? undefined
|
|
20
|
+
} catch {
|
|
21
|
+
return undefined
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return undefined
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Prefers a full stack trace when the value is an Error so logs include the call site.
|
|
28
|
+
function errorParts(value: unknown): { msg: string; stack?: string } {
|
|
29
|
+
if (value instanceof Error) {
|
|
30
|
+
return { msg: value.message, stack: value.stack }
|
|
31
|
+
}
|
|
32
|
+
return { msg: String(value) }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Times `work` under an operation name, minting the record's span id so a future exporter can materialise it as a span. */
|
|
36
|
+
async function traceWork<Return>(
|
|
37
|
+
name: string,
|
|
38
|
+
work: () => Return | Promise<Return>,
|
|
39
|
+
channel: string,
|
|
40
|
+
): Promise<Return> {
|
|
41
|
+
const spanId = randomHexId(8)
|
|
42
|
+
const startMs = performance.now()
|
|
43
|
+
try {
|
|
44
|
+
const result = await work()
|
|
45
|
+
emitLogRecord({
|
|
46
|
+
level: 'info',
|
|
47
|
+
msg: '',
|
|
48
|
+
name,
|
|
49
|
+
spanId,
|
|
50
|
+
durationMs: performance.now() - startMs,
|
|
51
|
+
channel,
|
|
52
|
+
})
|
|
53
|
+
return result
|
|
54
|
+
} catch (error) {
|
|
55
|
+
const { msg, stack } = errorParts(error)
|
|
56
|
+
emitLogRecord({
|
|
57
|
+
level: 'error',
|
|
58
|
+
msg,
|
|
59
|
+
stack,
|
|
60
|
+
name,
|
|
61
|
+
spanId,
|
|
62
|
+
durationMs: performance.now() - startMs,
|
|
63
|
+
channel,
|
|
64
|
+
})
|
|
65
|
+
throw error
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/*
|
|
70
|
+
Builds the callable-with-levels log shape bound to a channel. Every record
|
|
71
|
+
carries the channel; `getChannel` is a thunk because the default (app-name)
|
|
72
|
+
channel resolves after module init. `always` channels — the app's own and
|
|
73
|
+
abide's framework voice — emit unless a `-name` DEBUG pattern explicitly
|
|
74
|
+
shuts them off; everything else is a diagnostic channel gated by DEBUG
|
|
75
|
+
(browser: the abide-debug localStorage key). Levels never gate: a silenced
|
|
76
|
+
channel is silent at every level, an enabled one shows them all.
|
|
77
|
+
*/
|
|
78
|
+
export function createChannelLog(
|
|
79
|
+
getChannel: () => string,
|
|
80
|
+
always: boolean,
|
|
81
|
+
): ChannelLog & { enabled(): boolean } {
|
|
82
|
+
const enabled = () =>
|
|
83
|
+
always
|
|
84
|
+
? !isDebugNegated(getChannel(), channelPatterns())
|
|
85
|
+
: isDebugEnabled(getChannel(), channelPatterns())
|
|
86
|
+
const call = (message: string, data?: unknown): void => {
|
|
87
|
+
if (enabled()) {
|
|
88
|
+
emitLogRecord({ level: 'info', msg: message, data, channel: getChannel() })
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return Object.assign(call, {
|
|
92
|
+
/* Exposed so wrappers (abideLog's styling voices) emit through the same gate. */
|
|
93
|
+
enabled,
|
|
94
|
+
warn(message: string, data?: unknown): void {
|
|
95
|
+
if (enabled()) {
|
|
96
|
+
emitLogRecord({ level: 'warn', msg: message, data, channel: getChannel() })
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
error(value: unknown, data?: unknown): void {
|
|
100
|
+
if (enabled()) {
|
|
101
|
+
emitLogRecord({ level: 'error', ...errorParts(value), data, channel: getChannel() })
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
trace<Return>(name: string, work: () => Return | Promise<Return>): Promise<Return> {
|
|
105
|
+
if (enabled()) {
|
|
106
|
+
return traceWork(name, work, getChannel())
|
|
107
|
+
}
|
|
108
|
+
/*
|
|
109
|
+
No span: skip the async-wrapper allocation that every other method
|
|
110
|
+
already gates away, and hand back work()'s own promise untouched so
|
|
111
|
+
a coalesced cache join keeps the shared promise's identity. A
|
|
112
|
+
synchronous throw still surfaces as a rejection, matching traceWork.
|
|
113
|
+
*/
|
|
114
|
+
try {
|
|
115
|
+
const result = work()
|
|
116
|
+
return result instanceof Promise ? result : Promise.resolve(result)
|
|
117
|
+
} catch (error) {
|
|
118
|
+
return Promise.reject(error)
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { createSubscriber } from './createSubscriber.ts'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
Lifecycle tap shared by the cache store and the tail registry: one
|
|
5
|
+
"membership or state changed" signal for the pending()/refreshing() probes,
|
|
6
|
+
which match a group of entries and re-derive by scanning. The owning
|
|
7
|
+
registry decides the granularity — the cache store keeps a store-wide
|
|
8
|
+
channel plus one per probed selector prefix; this module only owns the
|
|
9
|
+
subscribe/notify semantics. track() inside a
|
|
10
|
+
tracking scope ($derived / $effect) re-runs that scope on every mark();
|
|
11
|
+
outside one it is a no-op. The subscriber is created lazily on the first
|
|
12
|
+
tracked read and self-evicts when its last reader tears down,
|
|
13
|
+
identity-guarded so a concurrent re-track isn't clobbered. mark() is a plain
|
|
14
|
+
callback — the channel only ever has the one memoized listener, so no
|
|
15
|
+
EventTarget dispatch is needed.
|
|
16
|
+
|
|
17
|
+
mark() defers its notify to a microtask: registry mutations happen inside
|
|
18
|
+
consumer read paths, and the documented read idiom is `$derived(await
|
|
19
|
+
cache(fn)())` — a cold read there registers an entry mid-derived, where
|
|
20
|
+
writing the subscriber's version source throws state_unsafe_mutation. The
|
|
21
|
+
probes scan the registry at re-derive time, so a deferred ping reads state
|
|
22
|
+
that is already current; marks within one tick coalesce into one notify.
|
|
23
|
+
*/
|
|
24
|
+
export function createLifecycleChannel(): { track: () => void; mark: () => void } {
|
|
25
|
+
let notify: (() => void) | undefined
|
|
26
|
+
let tracker: (() => void) | undefined
|
|
27
|
+
let marked = false
|
|
28
|
+
return {
|
|
29
|
+
track() {
|
|
30
|
+
if (!tracker) {
|
|
31
|
+
const created = createSubscriber((update) => {
|
|
32
|
+
notify = update
|
|
33
|
+
return () => {
|
|
34
|
+
notify = undefined
|
|
35
|
+
if (tracker === created) {
|
|
36
|
+
tracker = undefined
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
tracker = created
|
|
41
|
+
}
|
|
42
|
+
tracker()
|
|
43
|
+
},
|
|
44
|
+
mark() {
|
|
45
|
+
if (notify === undefined || marked) {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
marked = true
|
|
49
|
+
queueMicrotask(() => {
|
|
50
|
+
marked = false
|
|
51
|
+
/* Re-read: the last reader may have torn down during the deferral. */
|
|
52
|
+
notify?.()
|
|
53
|
+
})
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*
|
|
2
|
+
The liveness state machine shared by every "is that server still there?"
|
|
3
|
+
consumer: a recursive timer (never setInterval, so a slow probe can't overlap
|
|
4
|
+
the next) runs `probe(url)`; a success resets the miss count, `failureLimit`
|
|
5
|
+
consecutive misses declare the target down. Two modes by which hook is given:
|
|
6
|
+
|
|
7
|
+
- `onLost` (terminal): the bundle launcher's mode — down fires onLost once
|
|
8
|
+
and the watch stops; the user reconnects deliberately.
|
|
9
|
+
- `onChange` (continuous): the client health() mode — down fires
|
|
10
|
+
onChange(false), polling continues, and the first subsequent success fires
|
|
11
|
+
onChange(true). Transitions only, never per-poll — except the first success
|
|
12
|
+
after watch(), which always reports so a consumer that kept state across a
|
|
13
|
+
stop()/watch() cycle (health's backendAlive) resyncs with the machine.
|
|
14
|
+
|
|
15
|
+
watch(url) (re)starts against a new target (first probe after one interval —
|
|
16
|
+
probeNow() forces an immediate one); a probe resolving after the target
|
|
17
|
+
changed is discarded (the url capture is the staleness guard). Probe
|
|
18
|
+
transport is injected — the launcher passes the identity-endpoint check, the
|
|
19
|
+
client health() a browser fetch — so the machine is side-neutral.
|
|
20
|
+
*/
|
|
21
|
+
export function createLivenessWatch(options: {
|
|
22
|
+
probe: (url: string) => Promise<boolean>
|
|
23
|
+
onLost?: (url: string) => void
|
|
24
|
+
onChange?: (alive: boolean) => void
|
|
25
|
+
intervalMs?: number
|
|
26
|
+
failureLimit?: number
|
|
27
|
+
}): {
|
|
28
|
+
watch: (url: string) => void
|
|
29
|
+
stop: () => void
|
|
30
|
+
probeNow: () => void
|
|
31
|
+
} {
|
|
32
|
+
const intervalMs = options.intervalMs ?? 4000
|
|
33
|
+
const failureLimit = options.failureLimit ?? 2
|
|
34
|
+
let watchedUrl: string | undefined
|
|
35
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
36
|
+
let inFlight = false
|
|
37
|
+
let failures = 0
|
|
38
|
+
let alive = true
|
|
39
|
+
/* No verdict reported since watch() — makes the first success always report. */
|
|
40
|
+
let fresh = true
|
|
41
|
+
|
|
42
|
+
async function runProbe(): Promise<void> {
|
|
43
|
+
const url = watchedUrl
|
|
44
|
+
if (!url) {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
if (inFlight) {
|
|
48
|
+
/*
|
|
49
|
+
A stale probe from a previous target is still awaiting. Keep this
|
|
50
|
+
watch's timer armed — the stale resolution discards itself without
|
|
51
|
+
rescheduling, so returning bare here would leave no timer and the
|
|
52
|
+
new target silently unwatched.
|
|
53
|
+
*/
|
|
54
|
+
timer = setTimeout(runProbe, intervalMs)
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
inFlight = true
|
|
58
|
+
const up = await options.probe(url)
|
|
59
|
+
inFlight = false
|
|
60
|
+
// A stop or re-watch during the await moved the target — discard.
|
|
61
|
+
if (watchedUrl !== url) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
if (up) {
|
|
65
|
+
failures = 0
|
|
66
|
+
if (!alive || fresh) {
|
|
67
|
+
alive = true
|
|
68
|
+
fresh = false
|
|
69
|
+
options.onChange?.(true)
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
failures += 1
|
|
73
|
+
if (failures >= failureLimit && alive) {
|
|
74
|
+
alive = false
|
|
75
|
+
fresh = false
|
|
76
|
+
if (options.onChange) {
|
|
77
|
+
options.onChange(false)
|
|
78
|
+
} else {
|
|
79
|
+
stop()
|
|
80
|
+
options.onLost?.(url)
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
timer = setTimeout(runProbe, intervalMs)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function watch(url: string): void {
|
|
89
|
+
stop()
|
|
90
|
+
watchedUrl = url
|
|
91
|
+
fresh = true
|
|
92
|
+
timer = setTimeout(runProbe, intervalMs)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function stop(): void {
|
|
96
|
+
if (timer) {
|
|
97
|
+
clearTimeout(timer)
|
|
98
|
+
timer = undefined
|
|
99
|
+
}
|
|
100
|
+
watchedUrl = undefined
|
|
101
|
+
failures = 0
|
|
102
|
+
alive = true
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Event-accelerated check (visibility return, online event): probe immediately instead of waiting out the interval. */
|
|
106
|
+
function probeNow(): void {
|
|
107
|
+
if (!watchedUrl || inFlight) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
if (timer) {
|
|
111
|
+
clearTimeout(timer)
|
|
112
|
+
timer = undefined
|
|
113
|
+
}
|
|
114
|
+
void runProbe()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return { watch, stop, probeNow }
|
|
118
|
+
}
|