@abide/abide 0.48.0 → 0.50.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/AGENTS.md +85 -59
- package/CHANGELOG.md +216 -0
- package/README.md +21 -10
- package/package.json +15 -4
- package/src/abideLsp.ts +5 -6
- package/src/abideResolverPlugin.ts +197 -169
- package/src/build.ts +79 -56
- package/src/buildCli.ts +3 -5
- package/src/buildDisconnected.ts +2 -5
- package/src/bundleApp.ts +2 -3
- package/src/checkAbide.ts +12 -2
- package/src/compile.ts +2 -4
- package/src/devEntry.ts +113 -28
- package/src/discoveryEntry.ts +3 -2
- package/src/lib/bundle/disconnected.abide +69 -73
- package/src/lib/bundle/infoPlist.ts +13 -7
- package/src/lib/bundle/installDownloads.ts +13 -3
- package/src/lib/bundle/installMacMenu.ts +13 -3
- package/src/lib/bundle/spawnEmbeddedServer.ts +13 -4
- package/src/lib/bundle/waitForServer.ts +6 -1
- package/src/lib/cli/parseArgvForRpc.ts +36 -9
- package/src/lib/cli/tokenizeArgvFlags.ts +4 -2
- package/src/lib/mcp/createMcpResourceServer.ts +13 -2
- package/src/lib/mcp/mcpTools.ts +15 -6
- package/src/lib/mcp/toolResultFromResponse.ts +40 -12
- package/src/lib/server/error.ts +6 -6
- package/src/lib/server/json.ts +17 -3
- package/src/lib/server/rpc/defineRpc.ts +58 -24
- package/src/lib/server/rpc/parseArgs.ts +113 -14
- package/src/lib/server/rpc/resolveRpcJsonSchema.ts +28 -0
- package/src/lib/server/rpc/runWithRpcTimeout.ts +12 -1
- package/src/lib/server/rpc/types/RpcHelper.ts +75 -105
- package/src/lib/server/rpc/types/RpcRegistryEntry.ts +24 -9
- package/src/lib/server/rpc/validationError.ts +1 -1
- package/src/lib/server/runtime/DEV_RELOAD_CLIENT_SCRIPT.ts +0 -15
- package/src/lib/server/runtime/buildCacheSnapshot.ts +10 -9
- package/src/lib/server/runtime/buildInspectorSurface.ts +6 -4
- package/src/lib/server/runtime/buildOpenApiSpec.ts +55 -11
- package/src/lib/server/runtime/buildPreloadManifest.ts +12 -10
- package/src/lib/server/runtime/createAppAssetServer.ts +18 -15
- package/src/lib/server/runtime/createAppRouteResolver.ts +145 -0
- package/src/lib/server/runtime/createPlumbingRouter.ts +212 -0
- package/src/lib/server/runtime/createRouteDispatcher.ts +4 -10
- package/src/lib/server/runtime/createServer.ts +120 -324
- package/src/lib/server/runtime/createUiPageRenderer.ts +137 -26
- package/src/lib/server/runtime/devClientFingerprint.ts +19 -34
- package/src/lib/server/runtime/finalizeResponse.ts +11 -1
- package/src/lib/server/runtime/installAmbientScopeStore.ts +30 -9
- package/src/lib/server/runtime/logExposedSurfaces.ts +8 -7
- package/src/lib/server/runtime/pathStore.ts +15 -0
- package/src/lib/server/runtime/registryManifests.ts +1 -1
- package/src/lib/server/runtime/renderCellBarrierStore.ts +15 -0
- package/src/lib/server/runtime/runWithRequestScope.ts +3 -0
- package/src/lib/server/runtime/serializeCacheSnapshot.ts +6 -4
- package/src/lib/server/runtime/snapshotEntryFromCache.ts +24 -16
- package/src/lib/server/runtime/streamCacheResolutions.ts +14 -7
- package/src/lib/server/runtime/streamFromIterator.ts +30 -2
- package/src/lib/server/runtime/textResponse.ts +23 -0
- package/src/lib/server/runtime/types/DevReloadStamp.ts +6 -10
- package/src/lib/server/runtime/types/InspectorCacheEntry.ts +1 -1
- package/src/lib/server/runtime/types/RequestStore.ts +27 -0
- package/src/lib/server/runtime/warnUnguardedMcp.ts +15 -5
- package/src/lib/server/sockets/createSocketDispatcher.ts +9 -11
- package/src/lib/server/sockets/defineSocket.ts +5 -4
- package/src/lib/server/sse.ts +5 -1
- package/src/lib/shared/ASYNC_CELL.ts +5 -0
- package/src/lib/shared/DEV_REBUILD_PATH.ts +6 -0
- package/src/lib/shared/HTTP_METHODS.ts +6 -0
- package/src/lib/shared/HttpError.ts +1 -5
- package/src/lib/shared/MCP_PATH.ts +6 -0
- package/src/lib/shared/PROXIED_SERVER_SUBDIRS.ts +15 -0
- package/src/lib/shared/REF_JSON_TAGS.ts +13 -1
- package/src/lib/shared/RPC_SHIM_GLOBALS.ts +9 -0
- package/src/lib/shared/activeCacheStore.ts +1 -0
- package/src/lib/shared/activePage.ts +1 -0
- package/src/lib/shared/buildArtifact.ts +20 -0
- package/src/lib/shared/buildRpcRequest.ts +6 -2
- package/src/lib/shared/buildSocketOverChannel.ts +4 -3
- package/src/lib/shared/bundleGraphFromMetafile.ts +68 -0
- package/src/lib/shared/cache.ts +156 -131
- package/src/lib/shared/canonicalJson.ts +24 -1
- package/src/lib/shared/changeAffectsClient.ts +12 -7
- package/src/lib/shared/createCacheStore.ts +31 -8
- package/src/lib/shared/createChannelLog.ts +24 -0
- package/src/lib/shared/createLifecycleChannel.ts +7 -1
- package/src/lib/shared/createReachable.ts +47 -78
- package/src/lib/shared/createRemoteFunction.ts +52 -30
- package/src/lib/shared/createRpcServerProgram.ts +820 -0
- package/src/lib/shared/decodeRefJson.ts +4 -4
- package/src/lib/shared/decodeResponse.ts +2 -2
- package/src/lib/shared/decodeWireBody.ts +35 -0
- package/src/lib/shared/detectRpcMethod.ts +8 -1
- package/src/lib/shared/done.ts +8 -2
- package/src/lib/shared/encodeRefJson.ts +4 -4
- package/src/lib/shared/encodeWireBody.ts +18 -0
- package/src/lib/shared/exitOnBuildFailure.ts +4 -3
- package/src/lib/{server/rpc → shared}/fieldErrorsFromIssues.ts +5 -1
- package/src/lib/shared/generateDeclarations.ts +72 -0
- package/src/lib/shared/hasSeedableRequest.ts +25 -0
- package/src/lib/shared/hydrationWindow.ts +53 -0
- package/src/lib/shared/isAsyncCell.ts +11 -0
- package/src/lib/shared/isAsyncIterable.ts +8 -0
- package/src/lib/shared/isSubscribable.ts +3 -3
- package/src/lib/shared/isThenable.ts +9 -0
- package/src/lib/shared/jsonSchemaForType.ts +258 -0
- package/src/lib/shared/lenientDecode.ts +15 -0
- package/src/lib/shared/loadProjectTsConfig.ts +28 -0
- package/src/lib/shared/markFrameworkSourcesIgnored.ts +1 -1
- package/src/lib/shared/matchRoute.ts +4 -14
- package/src/lib/shared/parseEnv.ts +17 -6
- package/src/lib/shared/peek.ts +14 -0
- package/src/lib/shared/pending.ts +9 -6
- package/src/lib/shared/pendingAsyncCellsSlot.ts +13 -0
- package/src/lib/shared/prepareRpcModule.ts +91 -93
- package/src/lib/shared/prepareSocketModule.ts +3 -2
- package/src/lib/shared/probeRegistries.ts +5 -18
- package/src/lib/shared/reachable.ts +7 -10
- package/src/lib/shared/refresh.ts +12 -2
- package/src/lib/shared/refreshing.ts +8 -2
- package/src/lib/shared/resolvedCellsSlot.ts +13 -0
- package/src/lib/shared/reviveWireField.ts +49 -0
- package/src/lib/shared/reviveWireOutput.ts +36 -0
- package/src/lib/shared/rpcServerForRoot.ts +25 -0
- package/src/lib/shared/scanPages.ts +25 -0
- package/src/lib/shared/serializeEnv.ts +18 -6
- package/src/lib/shared/snapshotShippable.ts +8 -7
- package/src/lib/shared/snippet.ts +11 -6
- package/src/lib/shared/streamedCellsSlot.ts +14 -0
- package/src/lib/shared/subscribableFromResponse.ts +4 -4
- package/src/lib/shared/subscribableProbes.ts +1 -1
- package/src/lib/shared/tailProbeSlot.ts +1 -1
- package/src/lib/shared/types/AsyncComputed.ts +20 -0
- package/src/lib/shared/types/AsyncState.ts +13 -0
- package/src/lib/shared/types/CacheEntry.ts +7 -7
- package/src/lib/shared/types/CacheOptions.ts +23 -37
- package/src/lib/shared/types/CachePolicy.ts +25 -0
- package/src/lib/shared/types/CacheSnapshotEntry.ts +6 -5
- package/src/lib/shared/types/ErrorJsonSchemas.ts +8 -0
- package/src/lib/shared/types/HttpMethod.ts +3 -1
- package/src/lib/shared/types/InputCoercion.ts +17 -0
- package/src/lib/shared/types/{Subscribable.ts → NamedAsyncIterable.ts} +1 -1
- package/src/lib/shared/types/OutputWirePlan.ts +17 -0
- package/src/lib/shared/types/PagesScan.ts +7 -0
- package/src/lib/shared/types/PendingAsyncCells.ts +10 -0
- package/src/lib/shared/types/RawRemoteFunction.ts +6 -0
- package/src/lib/shared/types/RemoteCallable.ts +8 -7
- package/src/lib/shared/types/RemoteFunction.ts +16 -15
- package/src/lib/shared/types/ResolvedCells.ts +11 -0
- package/src/lib/shared/types/ReturnBody.ts +15 -0
- package/src/lib/shared/types/RpcBuildStamps.ts +23 -0
- package/src/lib/shared/types/RpcErrorGuard.ts +3 -8
- package/src/lib/shared/types/Socket.ts +4 -4
- package/src/lib/shared/types/SsrPayload.ts +5 -1
- package/src/lib/shared/types/StreamPolicy.ts +11 -0
- package/src/lib/shared/types/StreamedCells.ts +19 -0
- package/src/lib/shared/types/StreamedResolution.ts +24 -6
- package/src/lib/shared/types/TailHooks.ts +1 -1
- package/src/lib/shared/types/WireKind.ts +11 -0
- package/src/lib/shared/url.ts +5 -0
- package/src/lib/shared/validationHttpError.ts +33 -0
- package/src/lib/shared/warmSeedKey.ts +16 -0
- package/src/lib/shared/wireJsonReplacer.ts +30 -0
- package/src/lib/shared/writeRpcDts.ts +11 -1
- package/src/lib/shared/writeTestSocketsDts.ts +1 -1
- package/src/lib/test/createTestApp.ts +19 -1
- package/src/lib/ui/README.md +1 -1
- package/src/lib/ui/activePendingCells.ts +14 -0
- package/src/lib/ui/compile/BLOCK_KEYWORDS.ts +21 -0
- package/src/lib/ui/compile/SSR_ESCAPE.ts +4 -1
- package/src/lib/ui/compile/UI_RUNTIME_IMPORTS.ts +35 -7
- package/src/lib/ui/compile/abideUiPlugin.ts +19 -2
- package/src/lib/ui/compile/analyzeComponent.ts +89 -6
- package/src/lib/ui/compile/assignmentTargetNames.ts +54 -0
- package/src/lib/ui/compile/asyncInterpolationFields.ts +152 -0
- package/src/lib/ui/compile/asyncValuePositionError.ts +21 -0
- package/src/lib/ui/compile/asyncValuePositionInterpolations.ts +64 -0
- package/src/lib/ui/compile/attrLiftPosition.ts +18 -0
- package/src/lib/ui/compile/bindListenEvent.ts +5 -6
- package/src/lib/ui/compile/cachedSourceFile.ts +40 -0
- package/src/lib/ui/compile/catchBinding.ts +7 -5
- package/src/lib/ui/compile/classifyInterpolationType.ts +46 -0
- package/src/lib/ui/compile/collectAbideDiagnostics.ts +96 -0
- package/src/lib/ui/compile/compileComponent.ts +19 -3
- package/src/lib/ui/compile/compileModule.ts +27 -58
- package/src/lib/ui/compile/compileSSR.ts +52 -13
- package/src/lib/ui/compile/compileShadow.ts +265 -42
- package/src/lib/ui/compile/composeProps.ts +15 -4
- package/src/lib/ui/compile/createShadowLanguageService.ts +116 -68
- package/src/lib/ui/compile/createShadowProgram.ts +35 -6
- package/src/lib/ui/compile/declaredNames.ts +36 -0
- package/src/lib/ui/compile/desugarSignals.ts +419 -37
- package/src/lib/ui/compile/expressionIsPrefixEvaluable.ts +19 -0
- package/src/lib/ui/compile/generateBuild.ts +74 -17
- package/src/lib/ui/compile/generateSSR.ts +286 -75
- package/src/lib/ui/compile/hoistableAwaits.ts +193 -0
- package/src/lib/ui/compile/hoistableChildRenders.ts +112 -0
- package/src/lib/ui/compile/interpolatedTemplateLiteral.ts +3 -1
- package/src/lib/ui/compile/interpolationClassifierForRoot.ts +37 -0
- package/src/lib/ui/compile/isSpuriousAsyncReadDiagnostic.ts +174 -0
- package/src/lib/ui/compile/isWhitespaceText.ts +10 -2
- package/src/lib/ui/compile/liftAsyncSubExpressions.ts +166 -0
- package/src/lib/ui/compile/lowerAsyncInterpolations.ts +92 -0
- package/src/lib/ui/compile/lowerContext.ts +10 -0
- package/src/lib/ui/compile/lowerDocAccess.ts +51 -10
- package/src/lib/ui/compile/lowerScript.ts +40 -4
- package/src/lib/ui/compile/nodeAtShadowOffset.ts +28 -0
- package/src/lib/ui/compile/parseTemplate.ts +18 -1090
- package/src/lib/ui/compile/parseTemplateRecovering.ts +1385 -0
- package/src/lib/ui/compile/referencedIdentifiers.ts +35 -0
- package/src/lib/ui/compile/renameSignalRefs.ts +26 -40
- package/src/lib/ui/compile/resolveReactiveExport.ts +4 -7
- package/src/lib/ui/compile/scopeCss.ts +27 -4
- package/src/lib/ui/compile/seedTypeClassifierForRoot.ts +65 -0
- package/src/lib/ui/compile/shadowInterpolationClassifier.ts +47 -0
- package/src/lib/ui/compile/sourceFileOptionsSignature.ts +20 -0
- package/src/lib/ui/compile/structuralHeadTokens.ts +107 -0
- package/src/lib/ui/compile/templateSemanticTokens.ts +21 -0
- package/src/lib/ui/compile/templateStartOffset.ts +15 -0
- package/src/lib/ui/compile/tryPlan.ts +4 -3
- package/src/lib/ui/compile/types/AnalyzedComponent.ts +4 -0
- package/src/lib/ui/compile/types/AsyncInterpolationField.ts +19 -0
- package/src/lib/ui/compile/types/InterpolationClassifier.ts +12 -0
- package/src/lib/ui/compile/types/InterpolationKind.ts +7 -0
- package/src/lib/ui/compile/types/ParseDiagnostic.ts +8 -0
- package/src/lib/ui/compile/types/SeedTypeClassifier.ts +15 -0
- package/src/lib/ui/compile/types/TemplateNode.ts +36 -4
- package/src/lib/ui/compile/types/ValuePositionInterpolation.ts +13 -0
- package/src/lib/ui/compile/writtenTemplateNames.ts +84 -0
- package/src/lib/ui/computed.ts +28 -1
- package/src/lib/ui/createScope.ts +35 -68
- package/src/lib/ui/dom/anchoredBranch.ts +142 -0
- package/src/lib/ui/dom/appendText.ts +8 -3
- package/src/lib/ui/dom/awaitBlock.ts +62 -75
- package/src/lib/ui/dom/bindProp.ts +22 -0
- package/src/lib/ui/dom/bindableProp.ts +47 -0
- package/src/lib/ui/dom/cellPending.ts +24 -0
- package/src/lib/ui/dom/discardBoundary.ts +24 -6
- package/src/lib/ui/dom/disposeRange.ts +2 -1
- package/src/lib/ui/dom/each.ts +41 -12
- package/src/lib/ui/dom/eachAsync.ts +39 -3
- package/src/lib/ui/dom/fillBefore.ts +6 -7
- package/src/lib/ui/dom/fillBoundary.ts +2 -3
- package/src/lib/ui/dom/fillRange.ts +4 -4
- package/src/lib/ui/dom/hydrate.ts +6 -12
- package/src/lib/ui/dom/isComment.ts +1 -1
- package/src/lib/ui/dom/matchingRangeClose.ts +29 -0
- package/src/lib/ui/dom/mergeProps.ts +1 -1
- package/src/lib/ui/dom/mount.ts +1 -2
- package/src/lib/ui/dom/mountChild.ts +9 -40
- package/src/lib/ui/dom/mountRange.ts +2 -3
- package/src/lib/ui/dom/mountSlot.ts +1 -1
- package/src/lib/ui/dom/mountStreamedChild.ts +84 -0
- package/src/lib/ui/dom/mountSwappableRange.ts +46 -4
- package/src/lib/ui/dom/mutateDocContainer.ts +65 -0
- package/src/lib/ui/dom/on.ts +2 -2
- package/src/lib/ui/dom/readCell.ts +40 -0
- package/src/lib/ui/dom/restProps.ts +2 -2
- package/src/lib/ui/dom/spreadProps.ts +3 -4
- package/src/lib/ui/dom/switchBlock.ts +30 -7
- package/src/lib/ui/dom/tryBlock.ts +233 -70
- package/src/lib/ui/dom/types/SwitchCase.ts +5 -1
- package/src/lib/ui/dom/when.ts +12 -2
- package/src/lib/ui/dom/withScope.ts +9 -2
- package/src/lib/ui/finalizeStreamedChildren.ts +89 -0
- package/src/lib/ui/flight.ts +56 -0
- package/src/lib/ui/html.ts +12 -1
- package/src/lib/ui/isolateCellBarrier.ts +17 -0
- package/src/lib/ui/linked.ts +48 -2
- package/src/lib/ui/props.ts +17 -0
- package/src/lib/ui/remoteProxy.ts +84 -159
- package/src/lib/ui/renderChain.ts +53 -13
- package/src/lib/ui/renderToStream.ts +22 -18
- package/src/lib/ui/resumeSeedScript.ts +1 -1
- package/src/lib/ui/router.ts +86 -53
- package/src/lib/ui/runtime/AsyncCellError.ts +20 -0
- package/src/lib/ui/runtime/CELL_SEED.ts +14 -0
- package/src/lib/ui/runtime/CHILD_PRESENT.ts +2 -2
- package/src/lib/ui/runtime/CURRENT_BOUNDARY.ts +11 -0
- package/src/lib/ui/runtime/CURRENT_PATH.ts +29 -0
- package/src/lib/ui/runtime/RENDER.ts +10 -7
- package/src/lib/ui/runtime/RESUME.ts +4 -4
- package/src/lib/ui/runtime/STREAMED_CELLS.ts +57 -0
- package/src/lib/ui/runtime/ambientPathBacking.ts +32 -0
- package/src/lib/ui/runtime/applyPatchToTree.ts +17 -4
- package/src/lib/ui/runtime/blockId.ts +31 -0
- package/src/lib/ui/runtime/boundaryFor.ts +11 -0
- package/src/lib/ui/runtime/cellBarrierBacking.ts +30 -0
- package/src/lib/ui/runtime/createAsyncCell.ts +300 -0
- package/src/lib/ui/runtime/createDoc.ts +31 -54
- package/src/lib/ui/runtime/createEffectNode.ts +9 -0
- package/src/lib/ui/runtime/enterRenderPass.ts +5 -4
- package/src/lib/ui/runtime/flushEffects.ts +33 -1
- package/src/lib/ui/runtime/isAsyncFunction.ts +14 -0
- package/src/lib/ui/runtime/nextBlockId.ts +8 -7
- package/src/lib/ui/runtime/renderPath.ts +16 -0
- package/src/lib/ui/runtime/scope.ts +11 -0
- package/src/lib/ui/runtime/toTeardown.ts +10 -3
- package/src/lib/ui/runtime/types/Boundary.ts +9 -0
- package/src/lib/ui/runtime/types/RenderContext.ts +9 -7
- package/src/lib/ui/runtime/types/SsrRender.ts +9 -2
- package/src/lib/ui/runtime/types/UiComponent.ts +1 -5
- package/src/lib/ui/runtime/types/UiProps.ts +6 -5
- package/src/lib/ui/runtime/withOptionalPath.ts +8 -0
- package/src/lib/ui/runtime/withPath.ts +16 -0
- package/src/lib/ui/runtime/withPathFrom.ts +20 -0
- package/src/lib/ui/runtime/withoutHydration.ts +22 -0
- package/src/lib/ui/seedStreamedResolution.ts +31 -6
- package/src/lib/ui/settleAsyncCells.ts +24 -0
- package/src/lib/ui/socketProxy.ts +1 -1
- package/src/lib/ui/startClient.ts +16 -31
- package/src/lib/ui/state.ts +9 -3
- package/src/lib/ui/trackedComputed.ts +68 -0
- package/src/lib/ui/types/Scope.ts +8 -24
- package/src/lib/ui/watch.ts +3 -3
- package/src/serverEntry.ts +14 -0
- package/template/src/server/rpc/getHello.ts +15 -13
- package/template/test/app.test.ts +1 -1
- package/src/lib/server/runtime/devHotModuleResponse.ts +0 -41
- package/src/lib/shared/DEV_HOT_PREFIX.ts +0 -7
- package/src/lib/shared/UNREACHABLE_STATUSES.ts +0 -13
- package/src/lib/shared/hasReplayableRequest.ts +0 -17
- package/src/lib/shared/hydratingSlot.ts +0 -12
- package/src/lib/shared/outboxProbeSlot.ts +0 -20
- package/src/lib/shared/types/Outbox.ts +0 -9
- package/src/lib/shared/types/OutboxEntry.ts +0 -27
- package/src/lib/shared/types/SmartReadOptions.ts +0 -36
- package/src/lib/shared/wakeHydrationPeeks.ts +0 -20
- package/src/lib/ui/COMPONENT_WRAPPER_PREFIX.ts +0 -5
- package/src/lib/ui/compile/REACTIVE_CALLEES.ts +0 -11
- package/src/lib/ui/compile/assertRuntimeHelpersBound.ts +0 -80
- package/src/lib/ui/compile/markupTokens.ts +0 -313
- package/src/lib/ui/compile/structuralBlockTokens.ts +0 -100
- package/src/lib/ui/dom/applyResolved.ts +0 -87
- package/src/lib/ui/dom/scopeLabel.ts +0 -21
- package/src/lib/ui/dom/text.ts +0 -20
- package/src/lib/ui/history.ts +0 -101
- package/src/lib/ui/installHotBridge.ts +0 -93
- package/src/lib/ui/installInspectorBridge.ts +0 -140
- package/src/lib/ui/outbox.ts +0 -35
- package/src/lib/ui/persist.ts +0 -115
- package/src/lib/ui/rpcOutbox/createOutboxQueue.ts +0 -281
- package/src/lib/ui/rpcOutbox/outboxRegistry.ts +0 -69
- package/src/lib/ui/runtime/PATCH_BUS.ts +0 -28
- package/src/lib/ui/runtime/captureModelDoc.ts +0 -28
- package/src/lib/ui/runtime/hotInstances.ts +0 -10
- package/src/lib/ui/runtime/hotReloadEnabled.ts +0 -8
- package/src/lib/ui/runtime/hotReplace.ts +0 -38
- package/src/lib/ui/runtime/liveScopes.ts +0 -15
- package/src/lib/ui/runtime/localStoragePersistence.ts +0 -47
- package/src/lib/ui/runtime/registerHotInstance.ts +0 -23
- package/src/lib/ui/runtime/seedModelDoc.ts +0 -26
- package/src/lib/ui/runtime/types/HotInstance.ts +0 -22
- package/src/lib/ui/runtime/types/PatchEvent.ts +0 -16
- package/src/lib/ui/seedResolved.ts +0 -28
- package/src/lib/ui/sync.ts +0 -48
- package/src/lib/ui/types/History.ts +0 -14
- package/src/lib/ui/types/PersistHandle.ts +0 -11
- package/src/lib/ui/types/PersistenceStore.ts +0 -12
- package/src/lib/ui/types/ResolvedFrame.ts +0 -15
- package/src/lib/ui/types/SyncTransport.ts +0 -13
|
@@ -5,31 +5,17 @@ import type { McpServer } from '../../mcp/types/McpServer.ts'
|
|
|
5
5
|
import { abideLog } from '../../shared/abideLog.ts'
|
|
6
6
|
import { basePathFromAppUrl } from '../../shared/basePathFromAppUrl.ts'
|
|
7
7
|
import { baseSlot } from '../../shared/baseSlot.ts'
|
|
8
|
-
import { NO_STORE } from '../../shared/CACHE_CONTROL_VALUES.ts'
|
|
9
|
-
import { CLI_PATH } from '../../shared/CLI_PATH.ts'
|
|
10
|
-
import { DEV_HOT_PREFIX } from '../../shared/DEV_HOT_PREFIX.ts'
|
|
11
|
-
import { DEV_RELOAD_PATH } from '../../shared/DEV_RELOAD_PATH.ts'
|
|
12
8
|
import { extraForwardHeaders } from '../../shared/extraForwardHeaders.ts'
|
|
13
|
-
import { HEALTH_PATH } from '../../shared/HEALTH_PATH.ts'
|
|
14
9
|
import { healthReadSlot } from '../../shared/healthReadSlot.ts'
|
|
15
|
-
import { IDENTITY_PATH } from '../../shared/IDENTITY_PATH.ts'
|
|
16
|
-
import { INSPECTOR_PATH } from '../../shared/INSPECTOR_PATH.ts'
|
|
17
10
|
import { isDebugNegated } from '../../shared/isDebugNegated.ts'
|
|
18
11
|
import { logClosingRecord } from '../../shared/logClosingRecord.ts'
|
|
19
|
-
import { matchRoute } from '../../shared/matchRoute.ts'
|
|
20
|
-
import { normalizePathname } from '../../shared/normalizePathname.ts'
|
|
21
12
|
import { OFFLINE_HEADER } from '../../shared/OFFLINE_HEADER.ts'
|
|
22
13
|
import { parseBoundedEnvInt } from '../../shared/parseBoundedEnvInt.ts'
|
|
23
|
-
import { parseRouteSegments } from '../../shared/parseRouteSegments.ts'
|
|
24
14
|
import { requestScopeSlot } from '../../shared/requestScopeSlot.ts'
|
|
25
|
-
import { SOCKETS_PATH } from '../../shared/SOCKETS_PATH.ts'
|
|
26
15
|
import { setAppName } from '../../shared/setAppName.ts'
|
|
27
|
-
import { TEXT_PLAIN } from '../../shared/TEXT_PLAIN.ts'
|
|
28
16
|
import type { Layouts } from '../../ui/types/Layouts.ts'
|
|
29
17
|
import type { Pages } from '../../ui/types/Pages.ts'
|
|
30
18
|
import type { AppModule } from '../AppModule.ts'
|
|
31
|
-
import { handleCliDownload } from '../cli/handleCliDownload.ts'
|
|
32
|
-
import { handleCliInstall } from '../cli/handleCliInstall.ts'
|
|
33
19
|
import type { PromptRoutes } from '../prompts/types/PromptRoutes.ts'
|
|
34
20
|
import type { RemoteRoutes } from '../rpc/types/RemoteRoutes.ts'
|
|
35
21
|
import { createSocketDispatcher } from '../sockets/createSocketDispatcher.ts'
|
|
@@ -38,20 +24,16 @@ import { buildHealthPayload } from './buildHealthPayload.ts'
|
|
|
38
24
|
import { buildOpenApiSpec } from './buildOpenApiSpec.ts'
|
|
39
25
|
import { buildPreloadManifest } from './buildPreloadManifest.ts'
|
|
40
26
|
import { createAppAssetServer } from './createAppAssetServer.ts'
|
|
27
|
+
import { createAppRouteResolver } from './createAppRouteResolver.ts'
|
|
28
|
+
import { createPlumbingRouter, PLUMBING_PASS } from './createPlumbingRouter.ts'
|
|
41
29
|
import { createPublicAssetServer } from './createPublicAssetServer.ts'
|
|
42
30
|
import { createRouteDispatcher } from './createRouteDispatcher.ts'
|
|
43
31
|
import { createUiPageRenderer } from './createUiPageRenderer.ts'
|
|
44
|
-
import { crossOriginGate } from './crossOriginGate.ts'
|
|
45
32
|
import { DEFAULT_PORT } from './DEFAULT_PORT.ts'
|
|
46
33
|
import { DEV_READY_MESSAGE } from './DEV_READY_MESSAGE.ts'
|
|
47
|
-
import { DEV_REBUILD_MESSAGE } from './DEV_REBUILD_MESSAGE.ts'
|
|
48
34
|
import { DEV_RELOAD_CLIENT_SCRIPT } from './DEV_RELOAD_CLIENT_SCRIPT.ts'
|
|
49
35
|
import { devClientFingerprint } from './devClientFingerprint.ts'
|
|
50
|
-
import { devHotModuleResponse } from './devHotModuleResponse.ts'
|
|
51
|
-
import { devReloadResponse } from './devReloadResponse.ts'
|
|
52
|
-
import { disableIdleTimeoutForStream } from './disableIdleTimeoutForStream.ts'
|
|
53
36
|
import { finalizeResponse } from './finalizeResponse.ts'
|
|
54
|
-
import { gzipResponse } from './gzipResponse.ts'
|
|
55
37
|
import { installAmbientScopeStore } from './installAmbientScopeStore.ts'
|
|
56
38
|
import { internalErrorResponse } from './internalErrorResponse.ts'
|
|
57
39
|
import { listenOnOpenPort } from './listenOnOpenPort.ts'
|
|
@@ -63,15 +45,11 @@ import { ensureRegistriesLoaded, setRegistryManifests } from './registryManifest
|
|
|
63
45
|
import { requestContext } from './requestContext.ts'
|
|
64
46
|
import { runWithRequestScope } from './runWithRequestScope.ts'
|
|
65
47
|
import { setActiveServer } from './setActiveServer.ts'
|
|
48
|
+
import { textResponse } from './textResponse.ts'
|
|
66
49
|
import type { Assets } from './types/Assets.ts'
|
|
67
50
|
import type { RequestStore } from './types/RequestStore.ts'
|
|
68
51
|
import { warnUnguardedMcp } from './warnUnguardedMcp.ts'
|
|
69
52
|
|
|
70
|
-
const SOCKETS_REST_PREFIX = `${SOCKETS_PATH}/`
|
|
71
|
-
const MCP_PATH = '/__abide/mcp'
|
|
72
|
-
const CLI_DOWNLOAD_PREFIX = `${CLI_PATH}/`
|
|
73
|
-
// Dev-only manual rebuild trigger; POSTing signals the orchestrator to rebuild + restart.
|
|
74
|
-
const DEV_REBUILD_PATH = '/__abide/reload'
|
|
75
53
|
/*
|
|
76
54
|
Unlike the framework's own plumbing routes above (the socket multiplex, MCP
|
|
77
55
|
endpoint, CLI download), the OpenAPI document describes the app's public HTTP
|
|
@@ -196,13 +174,6 @@ export async function createServer({
|
|
|
196
174
|
// In dev, append the live-reload client to the shell so every rendered
|
|
197
175
|
// page reconnects to /__abide/dev and reloads after a restart.
|
|
198
176
|
const devShell = dev ? shell.replace('</body>', `${DEV_RELOAD_CLIENT_SCRIPT}</body>`) : shell
|
|
199
|
-
// When the inspector is enabled, flag the client so startClient installs the
|
|
200
|
-
// BroadcastChannel bridge that streams scope + router state to the inspector
|
|
201
|
-
// page. Independent of dev — the inspector can run on a build server too.
|
|
202
|
-
const inspectedShell =
|
|
203
|
-
process.env.ABIDE_ENABLE_INSPECTOR === 'true'
|
|
204
|
-
? devShell.replace('</body>', `<script>window.__abideInspect=true</script></body>`)
|
|
205
|
-
: devShell
|
|
206
177
|
/*
|
|
207
178
|
Mount base from APP_URL's pathname (e.g. https://foo.com/v2 → /v2). Install
|
|
208
179
|
the server-side resolver so url() prefixes SSR-generated links, and rewrite
|
|
@@ -214,9 +185,17 @@ export async function createServer({
|
|
|
214
185
|
baseSlot.resolver = () => base
|
|
215
186
|
// Rebase the shell's rooted `/_app/` entry refs onto the mount base, matching
|
|
216
187
|
// either quote style so a custom app.html using single quotes still rewrites.
|
|
217
|
-
const activeShell = base
|
|
218
|
-
|
|
219
|
-
|
|
188
|
+
const activeShell = base ? devShell.replace(/(["'])\/_app\//g, `$1${base}/_app/`) : devShell
|
|
189
|
+
/*
|
|
190
|
+
The physical dir the `/_app/*` URLs map onto. Production reads the stable
|
|
191
|
+
`dist/_app`; under `abide dev` the orchestrator serves each build generation from
|
|
192
|
+
its own `_app.gen-<id>` dir and passes it as ABIDE_APP_DIR, so this worker serves
|
|
193
|
+
exactly the generation it was spawned on. A rebuild's replacement worker gets a
|
|
194
|
+
fresh dir while this one keeps reading its own, immutable for its lifetime — which
|
|
195
|
+
is why a retiring worker never 500s on chunks a rebuild would otherwise have
|
|
196
|
+
deleted. Must match the dir abideResolverPlugin rewrote the shell's entry ref from.
|
|
197
|
+
*/
|
|
198
|
+
const appDir = process.env.ABIDE_APP_DIR ?? `${distDir}/_app`
|
|
220
199
|
/*
|
|
221
200
|
Boot-path disk scans run concurrently — they share no data, and under
|
|
222
201
|
`abide dev` the worker-swap window is bounded by exactly this boot.
|
|
@@ -235,9 +214,20 @@ export async function createServer({
|
|
|
235
214
|
})
|
|
236
215
|
: undefined,
|
|
237
216
|
createPublicAssetServer({ publicDir, publicAssets }),
|
|
238
|
-
createAppAssetServer({
|
|
239
|
-
buildPreloadManifest({
|
|
217
|
+
createAppAssetServer({ appDir, assets }),
|
|
218
|
+
buildPreloadManifest({ appDir, assets }),
|
|
240
219
|
])
|
|
220
|
+
/*
|
|
221
|
+
Diagnostic (DEBUG=abide:dev): one line recording what this worker actually serves —
|
|
222
|
+
its generation dir and the hashed client entry the shell points at. Pinning makes a
|
|
223
|
+
shell⇄disk mismatch structurally impossible (the entry always lives in appDir), so
|
|
224
|
+
this is confirmation/defense-in-depth, not a routine line: it stays off by default.
|
|
225
|
+
Dev only — an embedded standalone build has no on-disk generation dir.
|
|
226
|
+
*/
|
|
227
|
+
if (dev && !assets) {
|
|
228
|
+
const entryRef = activeShell.match(/\/_app\/(client-[a-z0-9]+\.js)/i)?.[1] ?? 'client.js'
|
|
229
|
+
abideLog.channel('abide:dev')(`serving ${appDir.split('/').pop()} · entry ${entryRef}`)
|
|
230
|
+
}
|
|
241
231
|
setRegistryManifests({ rpc, sockets, prompts })
|
|
242
232
|
mcpResourceServerSlot.server = createMcpResourceServer({ resourcesDir, mcpResources })
|
|
243
233
|
const cliName = cliProgramName ?? 'app'
|
|
@@ -246,17 +236,16 @@ export async function createServer({
|
|
|
246
236
|
const appVersion = appInfo?.version ?? '0.0.0'
|
|
247
237
|
/* The app's default log channel — every unchanneled record speaks as [appName]. */
|
|
248
238
|
setAppName(appName)
|
|
239
|
+
/* The single health-payload builder, bound to this app's identity — shared by the
|
|
240
|
+
/__abide/health probe and the renderer's __SSR__ seed so the wire and seed can't drift. */
|
|
241
|
+
const healthPayloadFor = (request: Request) =>
|
|
242
|
+
buildHealthPayload(request, { app, appName, appVersion })
|
|
249
243
|
/*
|
|
250
244
|
Opt-in inspector (ABIDE_ENABLE_INSPECTOR=true): a dynamically-imported
|
|
251
245
|
`@abide/inspector` handler, or undefined when the flag is off / the package
|
|
252
246
|
isn't installed. Resolved at boot so the fetch route below can branch on it.
|
|
253
247
|
*/
|
|
254
248
|
const inspectorHandler = await maybeMountInspector({ name: appName, version: appVersion })
|
|
255
|
-
/* Built on first request, then reused — the rpc registry is frozen after load.
|
|
256
|
-
Memoised as a promise so two concurrent cold requests share one build instead
|
|
257
|
-
of both building (the second otherwise clobbering the first). A rejected build
|
|
258
|
-
clears the memo so the next request retries rather than caching the failure. */
|
|
259
|
-
let openApiSpec: Promise<ReturnType<typeof buildOpenApiSpec>> | undefined
|
|
260
249
|
const cliCwd = process.cwd()
|
|
261
250
|
|
|
262
251
|
/* Request closing records are on by default — DEBUG=-abide is the off switch (negation, like the abide channel itself). */
|
|
@@ -305,7 +294,7 @@ export async function createServer({
|
|
|
305
294
|
layouts,
|
|
306
295
|
routePreloads,
|
|
307
296
|
/* The wire payload, rebuilt per marked render — the __SSR__ health seed must match what /__abide/health serves. */
|
|
308
|
-
healthPayload:
|
|
297
|
+
healthPayload: healthPayloadFor,
|
|
309
298
|
})
|
|
310
299
|
|
|
311
300
|
/*
|
|
@@ -319,32 +308,25 @@ export async function createServer({
|
|
|
319
308
|
const buildRouteHandler = createRouteDispatcher({ pages, rpc, renderPage })
|
|
320
309
|
|
|
321
310
|
/*
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
311
|
+
URL-shape resolution — canonical-slash 308s, the openapi doc's build + memo,
|
|
312
|
+
and asset precedence (page routes shadow same-path public files; `/_app/`
|
|
313
|
+
before public/) — lives behind createAppRouteResolver. It composes the
|
|
314
|
+
dispatcher's per-URL handlers and returns a data-only decision the fetch
|
|
315
|
+
closure wires to its effect (ALS dispatch, asset serve, 404 render), so those
|
|
316
|
+
URL-shape decisions stay testable without booting Bun.serve. The openapi doc
|
|
317
|
+
is built from the frozen rpc registry, memoised across concurrent cold
|
|
318
|
+
requests, and cleared on a failed build so a later request retries.
|
|
326
319
|
*/
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const catchAllIndex = segments.findIndex(
|
|
338
|
-
(segment) => segment.kind === 'param' && segment.catchAll,
|
|
339
|
-
)
|
|
340
|
-
if (catchAllIndex !== -1 && catchAllIndex !== segments.length - 1) {
|
|
341
|
-
throw new Error(
|
|
342
|
-
`[abide] invalid page route ${routeUrl}: a [...name] catch-all must be the last segment`,
|
|
343
|
-
)
|
|
344
|
-
}
|
|
345
|
-
pageHandlers.set(routeUrl, buildRouteHandler(routeUrl))
|
|
346
|
-
}
|
|
347
|
-
const pageRouteUrls = Object.keys(pages)
|
|
320
|
+
const resolveAppRoute = createAppRouteResolver({
|
|
321
|
+
pages,
|
|
322
|
+
rpc,
|
|
323
|
+
buildRouteHandler,
|
|
324
|
+
openApiPath: OPENAPI_PATH,
|
|
325
|
+
buildOpenApiDocument: () =>
|
|
326
|
+
ensureRegistriesLoaded().then(() =>
|
|
327
|
+
buildOpenApiSpec({ title: appName, version: appVersion }),
|
|
328
|
+
),
|
|
329
|
+
})
|
|
348
330
|
|
|
349
331
|
function dispatchRequest(
|
|
350
332
|
req: Request,
|
|
@@ -376,6 +358,24 @@ export async function createServer({
|
|
|
376
358
|
*/
|
|
377
359
|
const socketDispatcher = createSocketDispatcher(sockets)
|
|
378
360
|
|
|
361
|
+
/*
|
|
362
|
+
Framework HTTP surface — the health/identity probe, inspector, dev
|
|
363
|
+
channels, sockets upgrade + REST face, MCP, and CLI — resolved ahead of the
|
|
364
|
+
app's rpc/page routes. Returns PLUMBING_PASS for any path it doesn't own so
|
|
365
|
+
the fetch handler falls through to the app routes below.
|
|
366
|
+
*/
|
|
367
|
+
const routePlumbing = createPlumbingRouter({
|
|
368
|
+
dev,
|
|
369
|
+
clientFingerprint,
|
|
370
|
+
inspectorHandler,
|
|
371
|
+
socketDispatcher,
|
|
372
|
+
mcp,
|
|
373
|
+
cliName,
|
|
374
|
+
cliCwd,
|
|
375
|
+
healthPayload: healthPayloadFor,
|
|
376
|
+
dispatchRequest,
|
|
377
|
+
})
|
|
378
|
+
|
|
379
379
|
/*
|
|
380
380
|
Bind the real server on `boundPort`. Only the port varies between scan
|
|
381
381
|
attempts, so the rest of the config lives inline and just the port is spread
|
|
@@ -411,233 +411,31 @@ export async function createServer({
|
|
|
411
411
|
async fetch(req, bunServer) {
|
|
412
412
|
const url = new URL(req.url)
|
|
413
413
|
/*
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
the app
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
bug can't masquerade as an unreachable server. IDENTITY_PATH is
|
|
422
|
-
the compatibility alias for the same payload.
|
|
423
|
-
*/
|
|
424
|
-
if (url.pathname === HEALTH_PATH || url.pathname === IDENTITY_PATH) {
|
|
425
|
-
const payload = await buildHealthPayload(req, { app, appName, appVersion })
|
|
426
|
-
return gzipResponse(
|
|
427
|
-
req,
|
|
428
|
-
Response.json(
|
|
429
|
-
/*
|
|
430
|
-
The IDENTITY_PATH alias keeps the legacy `abide: true`
|
|
431
|
-
shape: already-shipped probers check it with strict
|
|
432
|
-
equality, and a version string would make them treat
|
|
433
|
-
an upgraded healthy server as not-abide.
|
|
434
|
-
*/
|
|
435
|
-
url.pathname === IDENTITY_PATH ? { ...payload, abide: true } : payload,
|
|
436
|
-
{ headers: { 'Cache-Control': NO_STORE } },
|
|
437
|
-
),
|
|
438
|
-
)
|
|
439
|
-
}
|
|
440
|
-
/*
|
|
441
|
-
Inspector surface — answered directly, ahead of app.handle, since
|
|
442
|
-
it's privileged operator tooling gated by ABIDE_ENABLE_INSPECTOR
|
|
443
|
-
(not the app's user auth). Undefined handler = flag off, so the
|
|
444
|
-
whole block compiles out of the hot path when the inspector's off.
|
|
445
|
-
*/
|
|
446
|
-
if (
|
|
447
|
-
inspectorHandler &&
|
|
448
|
-
(url.pathname === INSPECTOR_PATH ||
|
|
449
|
-
url.pathname.startsWith(`${INSPECTOR_PATH}/`))
|
|
450
|
-
) {
|
|
451
|
-
// The events feed is long-lived SSE: opt it out of the idle
|
|
452
|
-
// timeout, else Bun reaps it and the reconnect replays the
|
|
453
|
-
// whole buffer (duplicate boot logs every ~10s).
|
|
454
|
-
return disableIdleTimeoutForStream(
|
|
455
|
-
bunServer,
|
|
456
|
-
req,
|
|
457
|
-
await inspectorHandler(req, url),
|
|
458
|
-
)
|
|
459
|
-
}
|
|
460
|
-
/*
|
|
461
|
-
Dev live-reload channel — answered directly, ahead of app.handle,
|
|
462
|
-
so a restart-driven reconnect always lands even when the app guards
|
|
463
|
-
everything behind auth. Only mounted under `abide dev`.
|
|
464
|
-
*/
|
|
465
|
-
if (clientFingerprint !== undefined && url.pathname === DEV_RELOAD_PATH) {
|
|
466
|
-
// Long-lived SSE: opt out of the idle timeout, else Bun reaps
|
|
467
|
-
// it and the reconnect triggers a spurious reload loop.
|
|
468
|
-
return disableIdleTimeoutForStream(
|
|
469
|
-
bunServer,
|
|
470
|
-
req,
|
|
471
|
-
devReloadResponse(clientFingerprint),
|
|
472
|
-
)
|
|
473
|
-
}
|
|
474
|
-
/* Component hot module — the browser imports one edited `.abide`'s
|
|
475
|
-
hot build here instead of reloading (dev component HMR). */
|
|
476
|
-
if (clientFingerprint !== undefined && url.pathname.startsWith(DEV_HOT_PREFIX)) {
|
|
477
|
-
/* This endpoint serves `application/javascript` for the browser's
|
|
478
|
-
`import()`. A TOP-LEVEL NAVIGATION to it — clicking the module link in a
|
|
479
|
-
stack trace, or opening the URL — would DOWNLOAD the file, since browsers
|
|
480
|
-
can't render JS as a document. A navigation sends `Accept: text/html`;
|
|
481
|
-
`import()` sends a wildcard Accept. Redirect a navigation back to a real
|
|
482
|
-
page (the referring page when same-origin, else the mount root) so the
|
|
483
|
-
error surfaces in context as a normal render instead of saving a file. */
|
|
484
|
-
if ((req.headers.get('accept') ?? '').includes('text/html')) {
|
|
485
|
-
const referer = req.headers.get('referer')
|
|
486
|
-
const page =
|
|
487
|
-
referer !== null &&
|
|
488
|
-
URL.canParse(referer) &&
|
|
489
|
-
new URL(referer).origin === url.origin &&
|
|
490
|
-
!new URL(referer).pathname.startsWith(DEV_HOT_PREFIX)
|
|
491
|
-
? referer
|
|
492
|
-
: base || '/'
|
|
493
|
-
return new Response(null, {
|
|
494
|
-
status: 302,
|
|
495
|
-
headers: { Location: page, 'Cache-Control': NO_STORE },
|
|
496
|
-
})
|
|
497
|
-
}
|
|
498
|
-
return devHotModuleResponse(
|
|
499
|
-
decodePathSegment(url.pathname.slice(DEV_HOT_PREFIX.length)),
|
|
500
|
-
)
|
|
501
|
-
}
|
|
502
|
-
/*
|
|
503
|
-
Manual rebuild trigger: signal the orchestrator parent over IPC to
|
|
504
|
-
rebuild + restart. Same-origin sibling of the live-reload channel, so
|
|
505
|
-
a script refreshes on the app's own port. process.send exists only when
|
|
506
|
-
the dev orchestrator spawned us with ipc; the optional chain no-ops on a
|
|
507
|
-
bare server.
|
|
414
|
+
Framework HTTP surface — the health/identity probe, inspector,
|
|
415
|
+
the dev live-reload/rebuild channels, the sockets
|
|
416
|
+
upgrade and its SSE/JSON face, MCP, and CLI — resolved ahead of
|
|
417
|
+
the app's rpc/page routes (see createPlumbingRouter). Each answers
|
|
418
|
+
either directly (ahead of app.handle) or through dispatchRequest,
|
|
419
|
+
exactly as before. PLUMBING_PASS means the path is none of them, so
|
|
420
|
+
fall through to the app routes below.
|
|
508
421
|
*/
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
return
|
|
512
|
-
headers: { 'Content-Type': TEXT_PLAIN },
|
|
513
|
-
})
|
|
514
|
-
}
|
|
515
|
-
if (url.pathname === SOCKETS_PATH) {
|
|
516
|
-
// Reject cross-origin upgrades (CSWSH) before handing off to Bun.
|
|
517
|
-
const upgradeForbidden = crossOriginGate(req, url)
|
|
518
|
-
if (upgradeForbidden) {
|
|
519
|
-
return upgradeForbidden
|
|
520
|
-
}
|
|
521
|
-
if (bunServer.upgrade(req, { data: {} })) {
|
|
522
|
-
return undefined as unknown as Response
|
|
523
|
-
}
|
|
524
|
-
return new Response('Upgrade failed', {
|
|
525
|
-
status: 400,
|
|
526
|
-
headers: { 'Content-Type': TEXT_PLAIN },
|
|
527
|
-
})
|
|
422
|
+
const plumbed = routePlumbing(req, url, bunServer)
|
|
423
|
+
if (plumbed !== PLUMBING_PASS) {
|
|
424
|
+
return plumbed
|
|
528
425
|
}
|
|
529
426
|
/*
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
427
|
+
App routes — the rpc-vs-page-vs-308-vs-asset URL-shape decision
|
|
428
|
+
lives behind createAppRouteResolver, resolved AFTER the `/__abide/*`
|
|
429
|
+
plumbing above (a reserved namespace no app route occupies). It
|
|
430
|
+
returns a data-only decision; the closure below is the thin wiring
|
|
431
|
+
that applies each to its effect.
|
|
535
432
|
*/
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
GET tail reads stay open cross-origin like rpc reads; only
|
|
540
|
-
the mutating POST is gated.
|
|
541
|
-
*/
|
|
542
|
-
const publishForbidden = crossOriginGate(req, url, { allowReadOnly: true })
|
|
543
|
-
if (publishForbidden) {
|
|
544
|
-
return publishForbidden
|
|
545
|
-
}
|
|
546
|
-
const name = decodePathSegment(url.pathname.slice(SOCKETS_REST_PREFIX.length))
|
|
547
|
-
return dispatchRequest(
|
|
548
|
-
req,
|
|
549
|
-
{},
|
|
550
|
-
async () => socketDispatcher.rest(req, name),
|
|
551
|
-
url,
|
|
552
|
-
)
|
|
553
|
-
}
|
|
554
|
-
if (url.pathname === MCP_PATH && mcp) {
|
|
555
|
-
// Gate cross-site browser posts (CSRF, see crossOriginGate).
|
|
556
|
-
const mcpForbidden = crossOriginGate(req, url)
|
|
557
|
-
if (mcpForbidden) {
|
|
558
|
-
return mcpForbidden
|
|
559
|
-
}
|
|
560
|
-
return dispatchRequest(req, {}, async () => mcp.handle(req), url)
|
|
433
|
+
const resolution = resolveAppRoute(req, url)
|
|
434
|
+
if (resolution.kind === 'handler') {
|
|
435
|
+
return dispatchRequest(req, resolution.params, resolution.handler, url)
|
|
561
436
|
}
|
|
562
|
-
if (
|
|
563
|
-
return
|
|
564
|
-
}
|
|
565
|
-
if (url.pathname.startsWith(CLI_DOWNLOAD_PREFIX)) {
|
|
566
|
-
const platform = url.pathname.slice(CLI_DOWNLOAD_PREFIX.length)
|
|
567
|
-
return dispatchRequest(
|
|
568
|
-
req,
|
|
569
|
-
{},
|
|
570
|
-
async () => handleCliDownload(req, platform, cliName, cliCwd),
|
|
571
|
-
url,
|
|
572
|
-
)
|
|
573
|
-
}
|
|
574
|
-
/*
|
|
575
|
-
App routes — rpc by flat lookup, pages through the shared
|
|
576
|
-
matcher (the client router runs the same one). Matched AFTER
|
|
577
|
-
the `/__abide/*` plumbing above (a reserved namespace no app
|
|
578
|
-
route occupies) and BEFORE the root-level framework surfaces
|
|
579
|
-
(/openapi.json, /_app/, public/ files), so a page route
|
|
580
|
-
shadows a same-path public file — the precedence the Bun
|
|
581
|
-
routes table used to impose implicitly, now pinned here.
|
|
582
|
-
*/
|
|
583
|
-
const rpcHandler = rpcHandlers.get(url.pathname)
|
|
584
|
-
if (rpcHandler) {
|
|
585
|
-
return dispatchRequest(req, {}, rpcHandler, url)
|
|
586
|
-
}
|
|
587
|
-
/*
|
|
588
|
-
Pages match only in canonical slash form; a non-canonical
|
|
589
|
-
request (`/admin/`, `//admin`) that would match is 308'd to the
|
|
590
|
-
canonical URL instead of served. Serving it directly would hand
|
|
591
|
-
app.handle — the auth seam — a pathname the matcher silently
|
|
592
|
-
normalized away, so an exact-match guard on `/admin` never sees
|
|
593
|
-
the request it's guarding (the old Bun routes table 404'd these
|
|
594
|
-
forms; the redirect keeps the guard sound AND the URL friendly).
|
|
595
|
-
rpc URLs stay exact-match strict, as they always were.
|
|
596
|
-
*/
|
|
597
|
-
const canonicalPathname = normalizePathname(url.pathname)
|
|
598
|
-
if (canonicalPathname !== url.pathname) {
|
|
599
|
-
if (matchRoute(pageRouteUrls, canonicalPathname)) {
|
|
600
|
-
return new Response(null, {
|
|
601
|
-
status: 308,
|
|
602
|
-
headers: {
|
|
603
|
-
Location: `${canonicalPathname}${url.search}`,
|
|
604
|
-
'Cache-Control': NO_STORE,
|
|
605
|
-
},
|
|
606
|
-
})
|
|
607
|
-
}
|
|
608
|
-
} else {
|
|
609
|
-
const matchedPage = matchRoute(pageRouteUrls, url.pathname)
|
|
610
|
-
if (matchedPage) {
|
|
611
|
-
const pageHandler = pageHandlers.get(matchedPage.route)
|
|
612
|
-
if (pageHandler) {
|
|
613
|
-
return dispatchRequest(req, matchedPage.params, pageHandler, url)
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
if (url.pathname === OPENAPI_PATH) {
|
|
618
|
-
return dispatchRequest(
|
|
619
|
-
req,
|
|
620
|
-
{},
|
|
621
|
-
async () => {
|
|
622
|
-
openApiSpec ??= ensureRegistriesLoaded()
|
|
623
|
-
.then(() =>
|
|
624
|
-
buildOpenApiSpec({
|
|
625
|
-
title: appName,
|
|
626
|
-
version: appVersion,
|
|
627
|
-
}),
|
|
628
|
-
)
|
|
629
|
-
.catch((error) => {
|
|
630
|
-
// Don't cache a failed build — clear the memo so a
|
|
631
|
-
// later request retries instead of 500-ing forever.
|
|
632
|
-
openApiSpec = undefined
|
|
633
|
-
throw error
|
|
634
|
-
})
|
|
635
|
-
return Response.json(await openApiSpec, {
|
|
636
|
-
headers: { 'Cache-Control': NO_STORE },
|
|
637
|
-
})
|
|
638
|
-
},
|
|
639
|
-
url,
|
|
640
|
-
)
|
|
437
|
+
if (resolution.kind === 'redirect') {
|
|
438
|
+
return resolution.response
|
|
641
439
|
}
|
|
642
440
|
/*
|
|
643
441
|
Static assets sidestep ALS + the per-request CacheStore + the
|
|
@@ -646,7 +444,7 @@ export async function createServer({
|
|
|
646
444
|
dozens of chunks. The global server.error() handler still
|
|
647
445
|
catches anything that goes wrong inside serveAppAsset.
|
|
648
446
|
*/
|
|
649
|
-
if (
|
|
447
|
+
if (resolution.kind === 'appAsset') {
|
|
650
448
|
return timedServe(() => serveAppAsset(req, url), req, url)
|
|
651
449
|
}
|
|
652
450
|
/*
|
|
@@ -669,13 +467,7 @@ export async function createServer({
|
|
|
669
467
|
req,
|
|
670
468
|
{},
|
|
671
469
|
async (_req, _pathParams, store) => {
|
|
672
|
-
return (
|
|
673
|
-
(await renderError(404, 'Not Found', store)) ??
|
|
674
|
-
new Response('Not Found', {
|
|
675
|
-
status: 404,
|
|
676
|
-
headers: { 'Content-Type': TEXT_PLAIN, 'Cache-Control': NO_STORE },
|
|
677
|
-
})
|
|
678
|
-
)
|
|
470
|
+
return (await renderError(404, 'Not Found', store)) ?? textResponse(404)
|
|
679
471
|
},
|
|
680
472
|
url,
|
|
681
473
|
)
|
|
@@ -729,20 +521,6 @@ export async function createServer({
|
|
|
729
521
|
process.once('SIGINT', shutdown)
|
|
730
522
|
process.once('SIGTERM', shutdown)
|
|
731
523
|
|
|
732
|
-
/*
|
|
733
|
-
Diagnostic only, and only under `abide` debug logging — eager-loads the
|
|
734
|
-
registry to print the page/socket/rpc surface maps (routing + which
|
|
735
|
-
declarations reach mcp/cli/openapi), making abide's multimodal-by-default
|
|
736
|
-
exposure auditable. Awaited so `ready` lands after all of abide's own
|
|
737
|
-
startup output rather than interleaving with it.
|
|
738
|
-
*/
|
|
739
|
-
if (logRequests) {
|
|
740
|
-
await logExposedSurfaces({ pages })
|
|
741
|
-
}
|
|
742
|
-
// Unguarded machine surface check — app.handle is the blessed auth seam.
|
|
743
|
-
if (mcp && !app?.handle) {
|
|
744
|
-
await warnUnguardedMcp()
|
|
745
|
-
}
|
|
746
524
|
abideLog.success(`ready at http://localhost:${server.port}`)
|
|
747
525
|
// Tell the dev orchestrator (when it spawned us with ipc) that boot is
|
|
748
526
|
// complete, so it can retire the previous worker — finishing the
|
|
@@ -750,17 +528,35 @@ export async function createServer({
|
|
|
750
528
|
if (dev) {
|
|
751
529
|
process.send?.(DEV_READY_MESSAGE)
|
|
752
530
|
}
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
}
|
|
764
|
-
|
|
531
|
+
/* Unguarded machine surface check — app.handle is the blessed auth seam. Runs AFTER ready
|
|
532
|
+
like the surface map below: warnUnguardedMcp eager-loads the registry (building the rpc
|
|
533
|
+
ts.Program via the onLoad transform), so leaving it pre-ready would re-block boot for an
|
|
534
|
+
unguarded-MCP app. Guarded so the warning can't fell a now-ready worker. */
|
|
535
|
+
if (mcp && !app?.handle) {
|
|
536
|
+
try {
|
|
537
|
+
await warnUnguardedMcp()
|
|
538
|
+
} catch (error) {
|
|
539
|
+
abideLog.error(error)
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
/*
|
|
543
|
+
Diagnostic surface map (on by default via `logRequests`; opt out with DEBUG=-abide):
|
|
544
|
+
eager-loads the registry to
|
|
545
|
+
print the page/socket/rpc surface (routing + which declarations reach mcp/cli/openapi),
|
|
546
|
+
making abide's multimodal-by-default exposure auditable. It runs AFTER the ready signal
|
|
547
|
+
because that eager load imports every rpc/socket module — which builds the rpc ts.Program
|
|
548
|
+
via the onLoad transform — ~1.4s that used to block readiness on EVERY dev worker boot.
|
|
549
|
+
The server is already listening, so printing it now costs nothing off time-to-ready, and
|
|
550
|
+
the registry (and its program) stays lazy on the reload hot path. In dev only the first
|
|
551
|
+
worker prints it (ABIDE_DEV_SURFACE, set by the orchestrator) — a respawn's surface is
|
|
552
|
+
identical. Guarded: a diagnostic failure must never fell a now-ready worker.
|
|
553
|
+
*/
|
|
554
|
+
if (logRequests && (!dev || process.env.ABIDE_DEV_SURFACE === '1')) {
|
|
555
|
+
try {
|
|
556
|
+
await logExposedSurfaces({ pages })
|
|
557
|
+
} catch (error) {
|
|
558
|
+
abideLog.error(error)
|
|
559
|
+
}
|
|
765
560
|
}
|
|
561
|
+
return server
|
|
766
562
|
}
|