@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,337 @@
|
|
|
1
|
+
import type { ServerWebSocket } from 'bun'
|
|
2
|
+
import { abideLog } from '../../shared/abideLog.ts'
|
|
3
|
+
import { memoizeByKey } from '../../shared/memoizeByKey.ts'
|
|
4
|
+
import { error } from '../error.ts'
|
|
5
|
+
import { json } from '../json.ts'
|
|
6
|
+
import { sse } from '../sse.ts'
|
|
7
|
+
import { lookupSocket } from './lookupSocket.ts'
|
|
8
|
+
import type { SocketClientFrame } from './types/SocketClientFrame.ts'
|
|
9
|
+
import type { SocketRegistryEntry } from './types/SocketRegistryEntry.ts'
|
|
10
|
+
import type { SocketRoutes } from './types/SocketRoutes.ts'
|
|
11
|
+
import type { SocketServerFrame } from './types/SocketServerFrame.ts'
|
|
12
|
+
|
|
13
|
+
// Reused across every inbound binary frame rather than allocated per message.
|
|
14
|
+
const textDecoder = new TextDecoder()
|
|
15
|
+
|
|
16
|
+
/* Socket REST-face spans (CLI/MCP tail + publish), opt-in via DEBUG=abide:sockets. */
|
|
17
|
+
const socketsLog = abideLog.channel('abide:sockets')
|
|
18
|
+
|
|
19
|
+
type SocketDispatcher = {
|
|
20
|
+
open(ws: ServerWebSocket<unknown>): void
|
|
21
|
+
message(ws: ServerWebSocket<unknown>, data: string | Buffer): void
|
|
22
|
+
close(ws: ServerWebSocket<unknown>): void
|
|
23
|
+
rest(req: Request, name: string): Promise<Response>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
Per-connection state: which sockets this ws is currently subscribed to
|
|
28
|
+
(at the Bun-topic level), and which `sub` ids map to which socket. One
|
|
29
|
+
ws can hold multiple subs against the same socket (e.g. one seeded
|
|
30
|
+
from the retained tail, one live-only); the Bun-topic subscription is reference-counted
|
|
31
|
+
so we only `ws.unsubscribe` when the last local sub drops.
|
|
32
|
+
*/
|
|
33
|
+
type ConnectionState = {
|
|
34
|
+
subToSocket: Map<string, string>
|
|
35
|
+
socketSubs: Map<string, Set<string>>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
Bridges the framework's socket registry to a single ws per client. All
|
|
40
|
+
sockets multiplex over `/__abide/sockets`. Steady-state fan-out rides
|
|
41
|
+
Bun's native `server.publish('socket:<name>', frame)` so the dispatcher
|
|
42
|
+
is only on the path for sub/unsub bookkeeping and client-initiated pub
|
|
43
|
+
validation; the published `msg` frames go from publisher to subscribers
|
|
44
|
+
without touching JS per frame.
|
|
45
|
+
|
|
46
|
+
`sub` opens a subscription: the requested slice of the retained tail
|
|
47
|
+
is replayed directly to this ws, then the ws is added to the Bun
|
|
48
|
+
topic. `unsub` drops the local sub and unsubscribes the ws from
|
|
49
|
+
the Bun topic if no other local subs remain. `pub` validates the
|
|
50
|
+
socket's `allowClientPublish` policy and calls `socket.publish` —
|
|
51
|
+
which fans out to in-process iterators and republishes through Bun
|
|
52
|
+
to other connected clients.
|
|
53
|
+
|
|
54
|
+
Module-level lookups are cached per socket name: loading a socket
|
|
55
|
+
module triggers its `defineSocket` call, which inserts into the
|
|
56
|
+
registry. After that the dispatcher just reads the registry.
|
|
57
|
+
*/
|
|
58
|
+
export function createSocketDispatcher(sockets: SocketRoutes): SocketDispatcher {
|
|
59
|
+
const connections = new WeakMap<ServerWebSocket<unknown>, ConnectionState>()
|
|
60
|
+
|
|
61
|
+
const ensureLoaded = memoizeByKey((name): Promise<void> | undefined => {
|
|
62
|
+
const loader = sockets[name]
|
|
63
|
+
return loader ? loader().then(() => undefined) : undefined
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
Loads a socket module on first use and reads its registry entry — the
|
|
68
|
+
one statement of the load/lookup failure semantics (a throwing module is
|
|
69
|
+
logged here and stays cached as failed by ensureLoaded). Each face maps
|
|
70
|
+
the failure kind to its own rendering: sub emits err+end frames, pub
|
|
71
|
+
drops silently, rest answers with HTTP errors.
|
|
72
|
+
*/
|
|
73
|
+
async function resolveEntry(
|
|
74
|
+
name: string,
|
|
75
|
+
): Promise<
|
|
76
|
+
| { entry: SocketRegistryEntry }
|
|
77
|
+
| { failure: 'unregistered' | 'load-failed' | 'no-export'; message: string }
|
|
78
|
+
> {
|
|
79
|
+
const loader = ensureLoaded(name)
|
|
80
|
+
if (!loader) {
|
|
81
|
+
return { failure: 'unregistered', message: `[abide] no socket registered at ${name}` }
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
await loader
|
|
85
|
+
} catch (loadError) {
|
|
86
|
+
abideLog.error(loadError)
|
|
87
|
+
return {
|
|
88
|
+
failure: 'load-failed',
|
|
89
|
+
message: loadError instanceof Error ? loadError.message : String(loadError),
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const entry = lookupSocket(name)
|
|
93
|
+
if (!entry) {
|
|
94
|
+
return {
|
|
95
|
+
failure: 'no-export',
|
|
96
|
+
message: `[abide] socket module at ${name} did not register a Socket export`,
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return { entry }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function send(ws: ServerWebSocket<unknown>, frame: SocketServerFrame): void {
|
|
103
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
ws.send(JSON.stringify(frame))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function addSub(state: ConnectionState, name: string, sub: string): boolean {
|
|
110
|
+
state.subToSocket.set(sub, name)
|
|
111
|
+
let subs = state.socketSubs.get(name)
|
|
112
|
+
if (!subs) {
|
|
113
|
+
subs = new Set()
|
|
114
|
+
state.socketSubs.set(name, subs)
|
|
115
|
+
}
|
|
116
|
+
const wasEmpty = subs.size === 0
|
|
117
|
+
subs.add(sub)
|
|
118
|
+
return wasEmpty
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function removeSub(state: ConnectionState, sub: string): string | undefined {
|
|
122
|
+
const name = state.subToSocket.get(sub)
|
|
123
|
+
if (!name) {
|
|
124
|
+
return undefined
|
|
125
|
+
}
|
|
126
|
+
state.subToSocket.delete(sub)
|
|
127
|
+
const subs = state.socketSubs.get(name)
|
|
128
|
+
if (!subs) {
|
|
129
|
+
return undefined
|
|
130
|
+
}
|
|
131
|
+
subs.delete(sub)
|
|
132
|
+
if (subs.size === 0) {
|
|
133
|
+
state.socketSubs.delete(name)
|
|
134
|
+
return name
|
|
135
|
+
}
|
|
136
|
+
return undefined
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function handleSub(
|
|
140
|
+
ws: ServerWebSocket<unknown>,
|
|
141
|
+
state: ConnectionState,
|
|
142
|
+
frame: Extract<SocketClientFrame, { type: 'sub' }>,
|
|
143
|
+
): Promise<void> {
|
|
144
|
+
// Reject this sub: emit the error then the terminal end frame for its id.
|
|
145
|
+
function fail(message: string): void {
|
|
146
|
+
send(ws, { type: 'err', sub: frame.sub, message })
|
|
147
|
+
send(ws, { type: 'end', sub: frame.sub })
|
|
148
|
+
}
|
|
149
|
+
const resolution = await resolveEntry(frame.socket)
|
|
150
|
+
if ('failure' in resolution) {
|
|
151
|
+
return fail(resolution.message)
|
|
152
|
+
}
|
|
153
|
+
const { entry } = resolution
|
|
154
|
+
const isFirstLocalSub = addSub(state, frame.socket, frame.sub)
|
|
155
|
+
if (isFirstLocalSub) {
|
|
156
|
+
ws.subscribe(`socket:${frame.socket}`)
|
|
157
|
+
}
|
|
158
|
+
/*
|
|
159
|
+
Replay rides one per-sub `replay` frame (sent even when empty), not
|
|
160
|
+
socket-keyed msg frames: the batch demarcates replay from live for
|
|
161
|
+
the reader, and the per-sub address keeps this sub's replay out of
|
|
162
|
+
sibling subs on the same socket. Live messages flow through the Bun
|
|
163
|
+
topic the ws just joined; a frame published between the join and
|
|
164
|
+
this snapshot can appear in both, so user payloads should carry an
|
|
165
|
+
id/timestamp when ordering matters.
|
|
166
|
+
|
|
167
|
+
`replay === undefined` means the whole retained tail (`.tail()`
|
|
168
|
+
no-arg); a number is clamped to the buffer length so the client
|
|
169
|
+
can ask for "as many as available, up to N" — `0` (bare
|
|
170
|
+
`for await`) replays nothing.
|
|
171
|
+
*/
|
|
172
|
+
send(ws, { type: 'replay', sub: frame.sub, messages: entry.snapshotTail(frame.replay) })
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function handleUnsub(
|
|
176
|
+
ws: ServerWebSocket<unknown>,
|
|
177
|
+
state: ConnectionState,
|
|
178
|
+
frame: Extract<SocketClientFrame, { type: 'unsub' }>,
|
|
179
|
+
): void {
|
|
180
|
+
const emptied = removeSub(state, frame.sub)
|
|
181
|
+
if (emptied) {
|
|
182
|
+
ws.unsubscribe(`socket:${emptied}`)
|
|
183
|
+
}
|
|
184
|
+
send(ws, { type: 'end', sub: frame.sub })
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function handlePub(
|
|
188
|
+
ws: ServerWebSocket<unknown>,
|
|
189
|
+
frame: Extract<SocketClientFrame, { type: 'pub' }>,
|
|
190
|
+
): Promise<void> {
|
|
191
|
+
const resolution = await resolveEntry(frame.socket)
|
|
192
|
+
if ('failure' in resolution) {
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
const { entry } = resolution
|
|
196
|
+
if (!entry.allowClientPublish) {
|
|
197
|
+
/*
|
|
198
|
+
Silent drop: the publish is rejected because the topic
|
|
199
|
+
wasn't declared `{ clientPublish: true }`. Surfacing this as
|
|
200
|
+
an error per-publish would tempt apps to attempt-then-handle
|
|
201
|
+
instead of routing through an HTTP route for auth. Log it
|
|
202
|
+
once per process at debug level (out of scope here) if
|
|
203
|
+
visibility is needed.
|
|
204
|
+
*/
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
/*
|
|
208
|
+
publish() runs the topic's optional Standard Schema synchronously
|
|
209
|
+
and throws on failure (see defineSocket.validateSync). The
|
|
210
|
+
dispatcher invokes us via `void handlePub(...)`, so an unhandled
|
|
211
|
+
throw would surface as an unhandled promise rejection on every
|
|
212
|
+
malformed client frame. Catch + log so a buggy client can't take
|
|
213
|
+
the process down.
|
|
214
|
+
*/
|
|
215
|
+
try {
|
|
216
|
+
entry.socket.publish(frame.message)
|
|
217
|
+
} catch (error) {
|
|
218
|
+
abideLog.error(error)
|
|
219
|
+
}
|
|
220
|
+
/*
|
|
221
|
+
ws parameter retained for future per-ws auth context (cookies on
|
|
222
|
+
upgrade) the canPublish hook would consult.
|
|
223
|
+
*/
|
|
224
|
+
void ws
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/*
|
|
228
|
+
HTTP face of the sockets hub at `/__abide/sockets/<name>`, for the CLI
|
|
229
|
+
and MCP (which can't speak the ws multiplex protocol):
|
|
230
|
+
|
|
231
|
+
GET text/event-stream → live SSE stream; `?tail=N` seeds with the
|
|
232
|
+
last N retained frames before tailing live (default 0 = live only).
|
|
233
|
+
GET otherwise → JSON array of the retained tail
|
|
234
|
+
(`?tail=N` caps it; default all).
|
|
235
|
+
POST → publish the JSON body, gated by the socket's
|
|
236
|
+
clientPublish policy and validated against its schema.
|
|
237
|
+
|
|
238
|
+
Loads the socket module on first hit (same cache the ws path uses) so
|
|
239
|
+
its defineSocket call populates the registry.
|
|
240
|
+
*/
|
|
241
|
+
async function rest(req: Request, name: string): Promise<Response> {
|
|
242
|
+
return socketsLog.trace(`socket-rest ${name}`, () => restImpl(req, name))
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function restImpl(req: Request, name: string): Promise<Response> {
|
|
246
|
+
const resolution = await resolveEntry(name)
|
|
247
|
+
if ('failure' in resolution) {
|
|
248
|
+
return resolution.failure === 'load-failed'
|
|
249
|
+
? error(500, 'socket failed to load')
|
|
250
|
+
: error(404)
|
|
251
|
+
}
|
|
252
|
+
const { entry } = resolution
|
|
253
|
+
const tailParam = new URL(req.url).searchParams.get('tail')
|
|
254
|
+
const parsedTail = tailParam !== null ? Number(tailParam) : undefined
|
|
255
|
+
// A non-numeric ?tail= yields NaN; treat it as absent rather than letting
|
|
256
|
+
// snapshotTail(NaN)/slice(NaN) leak the whole retained buffer.
|
|
257
|
+
const count =
|
|
258
|
+
parsedTail !== undefined && Number.isFinite(parsedTail) ? parsedTail : undefined
|
|
259
|
+
if (req.method === 'GET' || req.method === 'HEAD') {
|
|
260
|
+
if ((req.headers.get('accept') ?? '').includes('text/event-stream')) {
|
|
261
|
+
return sse(entry.socket.tail(count ?? 0))
|
|
262
|
+
}
|
|
263
|
+
return json(entry.snapshotTail(count))
|
|
264
|
+
}
|
|
265
|
+
if (req.method === 'POST') {
|
|
266
|
+
if (!entry.allowClientPublish) {
|
|
267
|
+
return error(403, 'publishing not allowed')
|
|
268
|
+
}
|
|
269
|
+
let message: unknown
|
|
270
|
+
try {
|
|
271
|
+
message = await req.json()
|
|
272
|
+
} catch {
|
|
273
|
+
return error(400, 'body must be JSON')
|
|
274
|
+
}
|
|
275
|
+
try {
|
|
276
|
+
// publish() validates against the socket schema and throws on a bad payload.
|
|
277
|
+
entry.socket.publish(message)
|
|
278
|
+
} catch (publishError) {
|
|
279
|
+
return error(
|
|
280
|
+
422,
|
|
281
|
+
publishError instanceof Error ? publishError.message : String(publishError),
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
return json({ ok: true })
|
|
285
|
+
}
|
|
286
|
+
return error(405, undefined, { headers: { Allow: 'GET, POST' } })
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
rest,
|
|
291
|
+
|
|
292
|
+
open(ws) {
|
|
293
|
+
connections.set(ws, { subToSocket: new Map(), socketSubs: new Map() })
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
message(ws, data) {
|
|
297
|
+
const state = connections.get(ws)
|
|
298
|
+
if (!state) {
|
|
299
|
+
return
|
|
300
|
+
}
|
|
301
|
+
const text = typeof data === 'string' ? data : textDecoder.decode(data)
|
|
302
|
+
let frame: SocketClientFrame
|
|
303
|
+
try {
|
|
304
|
+
frame = JSON.parse(text) as SocketClientFrame
|
|
305
|
+
} catch {
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
// JSON.parse succeeds on `null`/`42`/`true`; ignore anything that isn't a frame object.
|
|
309
|
+
if (typeof frame !== 'object' || frame === null) {
|
|
310
|
+
return
|
|
311
|
+
}
|
|
312
|
+
if (frame.type === 'sub') {
|
|
313
|
+
void handleSub(ws, state, frame)
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
if (frame.type === 'unsub') {
|
|
317
|
+
handleUnsub(ws, state, frame)
|
|
318
|
+
return
|
|
319
|
+
}
|
|
320
|
+
if (frame.type === 'pub') {
|
|
321
|
+
void handlePub(ws, frame)
|
|
322
|
+
return
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
|
|
326
|
+
close(ws) {
|
|
327
|
+
const state = connections.get(ws)
|
|
328
|
+
if (!state) {
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
connections.delete(ws)
|
|
332
|
+
for (const name of state.socketSubs.keys()) {
|
|
333
|
+
ws.unsubscribe(`socket:${name}`)
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
}
|
|
337
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { createPushIterator } from '../../shared/createPushIterator.ts'
|
|
2
|
+
import { resolveClientFlags } from '../../shared/resolveClientFlags.ts'
|
|
3
|
+
import { socketTapSlot } from '../../shared/socketTapSlot.ts'
|
|
4
|
+
import type { TailHooks } from '../../shared/types/TailHooks.ts'
|
|
5
|
+
import { getActiveServer } from '../runtime/getActiveServer.ts'
|
|
6
|
+
import { registerSocket } from './registerSocket.ts'
|
|
7
|
+
import type { Socket } from './types/Socket.ts'
|
|
8
|
+
import type { SocketOptions } from './types/SocketOptions.ts'
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
Server-side construction of a Socket. The bundler rewrites every
|
|
12
|
+
`export const NAME = socket(opts)` inside `src/server/sockets/<file>.ts` into
|
|
13
|
+
`__abideDefineSocket__("<name>", opts)` so the file path becomes the
|
|
14
|
+
socket's identity. Each subscriber gets its own queue + notifier, the
|
|
15
|
+
optional retained tail is shared, and outbound fan-out rides Bun's
|
|
16
|
+
native `server.publish` so connected ws clients are notified by the
|
|
17
|
+
runtime in C rather than per-client iteration in JS.
|
|
18
|
+
|
|
19
|
+
The Socket itself is the AsyncIterable: `for await (const m of chat)`
|
|
20
|
+
is the live stream — no replay. `chat.tail(count)` opens a subscription
|
|
21
|
+
seeded with the last `count` retained frames (no-arg = the whole
|
|
22
|
+
retained tail, clamped to the declared `tail` size). When `ttl` is set,
|
|
23
|
+
retained frames older than `ttl` ms are evicted lazily on every
|
|
24
|
+
read/append — no timer runs in the background. `chat.publish(m)` is isomorphic —
|
|
25
|
+
called server-side it both notifies in-process iterators and broadcasts
|
|
26
|
+
to remote subscribers; called client-side (via socketProxy) it sends a
|
|
27
|
+
`pub` frame the dispatcher validates and forwards.
|
|
28
|
+
*/
|
|
29
|
+
// @readme plumbing
|
|
30
|
+
export function defineSocket<T>(name: string, opts: SocketOptions = {}): Socket<T> {
|
|
31
|
+
const retention = opts.tail ?? 0
|
|
32
|
+
const ttl = opts.ttl
|
|
33
|
+
const schema = opts.schema
|
|
34
|
+
/*
|
|
35
|
+
A schema makes the socket's payload safe to advertise to non-browser
|
|
36
|
+
surfaces, so it flips mcp/cli on by default — exposing the `tail` read
|
|
37
|
+
tool (and `publish` when clientPublish is set). Explicit `clients` wins.
|
|
38
|
+
*/
|
|
39
|
+
const hasSchema = schema !== undefined
|
|
40
|
+
const clients = resolveClientFlags(opts.clients, { mcp: hasSchema, cli: hasSchema })
|
|
41
|
+
type BufferEntry = { value: T; expiresAt: number | undefined }
|
|
42
|
+
const buffer: BufferEntry[] = []
|
|
43
|
+
const subscribers = new Set<(message: T) => void>()
|
|
44
|
+
const topic = `socket:${name}`
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
Retained frames are stored with an expiry timestamp. When `ttl` is set,
|
|
48
|
+
every read/append starts by dropping leading entries whose expiry has
|
|
49
|
+
passed — entries are appended in order so the expired prefix is
|
|
50
|
+
contiguous. No timer/setInterval is needed: expiry is lazy.
|
|
51
|
+
*/
|
|
52
|
+
function pruneExpired(now: number): void {
|
|
53
|
+
if (ttl === undefined) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
let drop = 0
|
|
57
|
+
for (const entry of buffer) {
|
|
58
|
+
if (entry.expiresAt !== undefined && entry.expiresAt <= now) {
|
|
59
|
+
drop++
|
|
60
|
+
} else {
|
|
61
|
+
break
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (drop > 0) {
|
|
65
|
+
buffer.splice(0, drop)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/*
|
|
70
|
+
Active server is set once per process during createServer's boot,
|
|
71
|
+
immediately after Bun.serve resolves, and never reassigned. Resolve
|
|
72
|
+
it lazily on the first publish then keep the reference so subsequent
|
|
73
|
+
publishes skip the per-call getter.
|
|
74
|
+
*/
|
|
75
|
+
let cachedServer: ReturnType<typeof getActiveServer>
|
|
76
|
+
/*
|
|
77
|
+
When a schema is attached, publish() validates synchronously and
|
|
78
|
+
throws on bad payloads. Standard Schema's validate() is generally
|
|
79
|
+
async — but for the synchronous server-side publish path we treat
|
|
80
|
+
a Promise return as a programming error (publish must be sync to
|
|
81
|
+
preserve in-process notify ordering). Schemas that need async
|
|
82
|
+
refinement should pre-validate at the call site instead.
|
|
83
|
+
*/
|
|
84
|
+
function validateSync(message: T): T {
|
|
85
|
+
if (!schema) {
|
|
86
|
+
return message
|
|
87
|
+
}
|
|
88
|
+
const result = schema['~standard'].validate(message)
|
|
89
|
+
if (result instanceof Promise) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`[abide] socket "${name}" schema returned a Promise — sockets require sync validation`,
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
if (result.issues) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`[abide] socket "${name}" publish payload failed validation: ${JSON.stringify(result.issues)}`,
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
return result.value as T
|
|
100
|
+
}
|
|
101
|
+
function publish(message: T): void {
|
|
102
|
+
const validated = validateSync(message)
|
|
103
|
+
if (retention > 0) {
|
|
104
|
+
const now = Date.now()
|
|
105
|
+
pruneExpired(now)
|
|
106
|
+
buffer.push({ value: validated, expiresAt: ttl === undefined ? undefined : now + ttl })
|
|
107
|
+
if (buffer.length > retention) {
|
|
108
|
+
buffer.shift()
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (const notify of subscribers) {
|
|
112
|
+
notify(validated)
|
|
113
|
+
}
|
|
114
|
+
// Observe the fanned-out frame (inspector); no-op when unobserved.
|
|
115
|
+
socketTapSlot.tap?.({ socket: name, message: validated })
|
|
116
|
+
if (cachedServer === undefined) {
|
|
117
|
+
cachedServer = getActiveServer()
|
|
118
|
+
}
|
|
119
|
+
const server = cachedServer
|
|
120
|
+
if (server) {
|
|
121
|
+
server.publish(topic, JSON.stringify({ type: 'msg', socket: name, message: validated }))
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/*
|
|
126
|
+
replay === 'all' replays the whole retained tail (`.tail()` no-arg);
|
|
127
|
+
a number replays the last min(count, buffer.length) items — `0` is
|
|
128
|
+
live-only, the bare `for await` behavior. `hooks.replayed` is queued
|
|
129
|
+
in-band after the replayed frames so a window reader commits its seed
|
|
130
|
+
atomically, strictly before any live frame.
|
|
131
|
+
*/
|
|
132
|
+
function iterate(replay: number | 'all', hooks?: TailHooks): AsyncIterable<T> {
|
|
133
|
+
return {
|
|
134
|
+
[Symbol.asyncIterator](): AsyncIterator<T, void, undefined> {
|
|
135
|
+
let subscriber: ((message: T) => void) | undefined
|
|
136
|
+
const iter = createPushIterator<T>(() => {
|
|
137
|
+
if (subscriber) {
|
|
138
|
+
subscribers.delete(subscriber)
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
pruneExpired(Date.now())
|
|
142
|
+
const replayCount =
|
|
143
|
+
replay === 'all' ? buffer.length : Math.min(replay, buffer.length)
|
|
144
|
+
if (replayCount > 0) {
|
|
145
|
+
const start = buffer.length - replayCount
|
|
146
|
+
for (let index = start; index < buffer.length; index++) {
|
|
147
|
+
iter.push((buffer[index] as BufferEntry).value)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (hooks?.replayed) {
|
|
151
|
+
iter.control(hooks.replayed)
|
|
152
|
+
}
|
|
153
|
+
subscriber = (message: T) => iter.push(message)
|
|
154
|
+
subscribers.add(subscriber)
|
|
155
|
+
return iter
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const self: Socket<T> = {
|
|
161
|
+
name,
|
|
162
|
+
clients,
|
|
163
|
+
publish,
|
|
164
|
+
tail: (count?: number, hooks?: TailHooks) => iterate(count ?? 'all', hooks),
|
|
165
|
+
[Symbol.asyncIterator]: () => iterate(0)[Symbol.asyncIterator](),
|
|
166
|
+
}
|
|
167
|
+
registerSocket({
|
|
168
|
+
socket: self as Socket<unknown>,
|
|
169
|
+
allowClientPublish: opts.clientPublish ?? false,
|
|
170
|
+
schema,
|
|
171
|
+
clients,
|
|
172
|
+
snapshotTail: (count?: number) => {
|
|
173
|
+
pruneExpired(Date.now())
|
|
174
|
+
const start = count === undefined ? 0 : Math.max(0, buffer.length - count)
|
|
175
|
+
return buffer.slice(start).map((entry) => entry.value)
|
|
176
|
+
},
|
|
177
|
+
})
|
|
178
|
+
return self
|
|
179
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { commandNameForUrl } from '../../shared/commandNameForUrl.ts'
|
|
2
|
+
import { SOCKETS_PATH } from '../../shared/SOCKETS_PATH.ts'
|
|
3
|
+
import type { SocketOperation } from './types/SocketOperation.ts'
|
|
4
|
+
import type { SocketRegistryEntry } from './types/SocketRegistryEntry.ts'
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
Projects a socket registry entry into the operations it exposes to the
|
|
8
|
+
CLI and MCP. Single source for the naming convention (`<base>-tail` /
|
|
9
|
+
`<base>-publish`), the existence rule (tail always; publish only when the
|
|
10
|
+
socket allows client publishing), and each operation's HTTP face — so the
|
|
11
|
+
CLI manifest builder, the MCP tool list, and the MCP tool dispatcher can't
|
|
12
|
+
disagree about which operations a socket has or what they're called.
|
|
13
|
+
*/
|
|
14
|
+
export function socketOperations(entry: SocketRegistryEntry): SocketOperation[] {
|
|
15
|
+
const base = commandNameForUrl(entry.socket.name)
|
|
16
|
+
const restUrl = `${SOCKETS_PATH}/${entry.socket.name}`
|
|
17
|
+
const operations: SocketOperation[] = [
|
|
18
|
+
{
|
|
19
|
+
kind: 'tail',
|
|
20
|
+
name: `${base}-tail`,
|
|
21
|
+
socketName: entry.socket.name,
|
|
22
|
+
restUrl,
|
|
23
|
+
method: 'GET',
|
|
24
|
+
},
|
|
25
|
+
]
|
|
26
|
+
if (entry.allowClientPublish) {
|
|
27
|
+
operations.push({
|
|
28
|
+
kind: 'publish',
|
|
29
|
+
name: `${base}-publish`,
|
|
30
|
+
socketName: entry.socket.name,
|
|
31
|
+
restUrl,
|
|
32
|
+
method: 'POST',
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
return operations
|
|
36
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SocketRegistryEntry } from './types/SocketRegistryEntry.ts'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
Process-wide registry of every Socket declared in the app. defineSocket
|
|
5
|
+
inserts on first construction; the dispatcher reads on every `sub` /
|
|
6
|
+
`pub` frame so it can find the right Socket by name and check the
|
|
7
|
+
opted-in `allowClientPublish` policy.
|
|
8
|
+
*/
|
|
9
|
+
export const socketRegistry = new Map<string, SocketRegistryEntry>()
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ClientFlags } from '../../../shared/types/ClientFlags.ts'
|
|
2
|
+
import type { TailHooks } from '../../../shared/types/TailHooks.ts'
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
Bidirectional named broadcast primitive. Declared once with `socket<T>()`
|
|
6
|
+
inside a file under `src/server/sockets/`; the same import resolves to a server-side
|
|
7
|
+
fan-out and a client-side ws proxy by build target. Iterating the socket
|
|
8
|
+
is the live stream — no replay. `.tail(count)` opens a subscription seeded
|
|
9
|
+
with the last `count` frames of the retained tail (declared via
|
|
10
|
+
`{ tail: n }`; no-arg = the whole retained tail) before going live — the
|
|
11
|
+
optional Subscribable retention capability the reactive `tail()` consumer
|
|
12
|
+
seeds from. `publish` is isomorphic: server code publishes in-process
|
|
13
|
+
and fans out to remote subscribers; client code sends a `pub` frame the
|
|
14
|
+
dispatcher validates against the topic's `clientPublish` flag. `clients`
|
|
15
|
+
exposes which adapter surfaces (browser / mcp / cli) advertise this
|
|
16
|
+
socket.
|
|
17
|
+
*/
|
|
18
|
+
export interface Socket<T> extends AsyncIterable<T> {
|
|
19
|
+
readonly name: string
|
|
20
|
+
readonly clients: ClientFlags
|
|
21
|
+
publish(message: T): void
|
|
22
|
+
tail(count?: number, hooks?: TailHooks): AsyncIterable<T>
|
|
23
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Wire frame the browser sends over the multiplexed socket connection.
|
|
3
|
+
`sub` opens a subscription against `socket`. The optional `replay`
|
|
4
|
+
controls seeding from the retained tail: omitted = the whole retained
|
|
5
|
+
tail (`.tail()` no-arg); a number = at most that many trailing frames,
|
|
6
|
+
clamped server-side to what the topic retains — `0` (bare `for await`)
|
|
7
|
+
is live-only. `unsub` closes one. `pub` publishes a message —
|
|
8
|
+
the dispatcher checks the topic's `clientPublish` flag before fanning
|
|
9
|
+
out.
|
|
10
|
+
|
|
11
|
+
`sub` is the per-subscription id minted client-side; the server treats
|
|
12
|
+
it as opaque and routes inbound `msg|err|end` frames back to the same
|
|
13
|
+
id so one ws can multiplex many subscriptions to the same or different
|
|
14
|
+
sockets.
|
|
15
|
+
*/
|
|
16
|
+
export type SocketClientFrame =
|
|
17
|
+
| { type: 'sub'; sub: string; socket: string; replay?: number }
|
|
18
|
+
| { type: 'unsub'; sub: string }
|
|
19
|
+
| { type: 'pub'; socket: string; message: unknown }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HttpVerb } from '../../../shared/types/HttpVerb.ts'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
One operation a socket exposes to the non-browser surfaces. A socket
|
|
5
|
+
always offers a `tail` (read recent / stream live) and, when
|
|
6
|
+
`clientPublish` is set, a `publish` (send a message). This is the shared
|
|
7
|
+
skeleton — name, kind, HTTP face — that the CLI manifest, the MCP tool
|
|
8
|
+
list, and the MCP dispatcher all read instead of re-deriving the naming
|
|
9
|
+
convention and existence rule independently. Each surface dresses it with
|
|
10
|
+
its own presentation (descriptions, input schema, annotations).
|
|
11
|
+
*/
|
|
12
|
+
export type SocketOperation = {
|
|
13
|
+
kind: 'tail' | 'publish'
|
|
14
|
+
// Command/tool name: the socket's command-name base plus `-tail` / `-publish`.
|
|
15
|
+
name: string
|
|
16
|
+
// Raw socket name, for the HTTP path and human-facing descriptions.
|
|
17
|
+
socketName: string
|
|
18
|
+
// HTTP face of the operation: `/__abide/sockets/<name>`.
|
|
19
|
+
restUrl: string
|
|
20
|
+
// GET for tail, POST for publish.
|
|
21
|
+
method: HttpVerb
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ClientFlags } from '../../../shared/types/ClientFlags.ts'
|
|
2
|
+
import type { StandardSchemaV1 } from '../../../shared/types/StandardSchemaV1.ts'
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
Server-side options passed when declaring a socket via `socket<T>(opts)`.
|
|
6
|
+
`tail` opts the topic into retention: the socket keeps its last `tail`
|
|
7
|
+
frames so readers that weren't there — late joiners, reconnects, the
|
|
8
|
+
CLI/MCP/SSE read surfaces — can seed from `.tail(count)`. Omitted, the
|
|
9
|
+
socket is a pure live pipe and storage is the consumer's concern (a
|
|
10
|
+
`tail(chat, { last: n })` window fills from live frames only). Per-frame
|
|
11
|
+
TTL (retained frames older than `ttl` ms are evicted before replay), and
|
|
12
|
+
the client-publish gate (off by default — server-only topics ignore pub
|
|
13
|
+
frames coming over the wire). Optional Standard Schema validates payloads on
|
|
14
|
+
publish and gives MCP / CLI a typed payload to describe (projected via the
|
|
15
|
+
schema's own `toJSONSchema()` — wrap with withJsonSchema if its library lacks
|
|
16
|
+
one). `clients` controls which non-browser surfaces (mcp / cli) expose this
|
|
17
|
+
socket; browser is the historical default. All server-only state the bundler
|
|
18
|
+
strips out of the client stub.
|
|
19
|
+
*/
|
|
20
|
+
export type SocketOptions<Schema extends StandardSchemaV1 = StandardSchemaV1> = {
|
|
21
|
+
tail?: number
|
|
22
|
+
ttl?: number
|
|
23
|
+
clientPublish?: boolean
|
|
24
|
+
schema?: Schema
|
|
25
|
+
clients?: Partial<ClientFlags>
|
|
26
|
+
}
|