@abide/abide 0.49.0 → 0.50.1
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 +564 -437
- package/CHANGELOG.md +183 -0
- package/README.md +165 -202
- package/package.json +14 -5
- package/src/abideLsp.ts +5 -6
- package/src/abideResolverPlugin.ts +197 -169
- package/src/build.ts +79 -56
- package/src/buildDisconnected.ts +0 -2
- package/src/checkAbide.ts +12 -2
- 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/spawnEmbeddedServer.ts +13 -4
- package/src/lib/bundle/waitForServer.ts +6 -1
- package/src/lib/mcp/mcpTools.ts +15 -6
- 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 +98 -13
- package/src/lib/server/rpc/resolveRpcJsonSchema.ts +28 -0
- 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/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 +14 -14
- 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 +4 -1
- 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/changeAffectsClient.ts +12 -7
- package/src/lib/shared/createCacheStore.ts +31 -8
- 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/{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/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/snapshotShippable.ts +8 -7
- 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/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 -8
- 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/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 +51 -12
- package/src/lib/ui/compile/compileShadow.ts +145 -18
- package/src/lib/ui/compile/composeProps.ts +12 -2
- 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 +418 -36
- package/src/lib/ui/compile/expressionIsPrefixEvaluable.ts +19 -0
- package/src/lib/ui/compile/generateBuild.ts +52 -9
- package/src/lib/ui/compile/generateSSR.ts +242 -43
- 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/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 +26 -23
- 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 -1092
- 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 +21 -22
- 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 +43 -94
- 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/disposeRange.ts +2 -1
- package/src/lib/ui/dom/each.ts +26 -4
- package/src/lib/ui/dom/eachAsync.ts +39 -3
- 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/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/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/switchBlock.ts +30 -7
- package/src/lib/ui/dom/tryBlock.ts +230 -66
- 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 +2 -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/remoteProxy.ts +84 -159
- package/src/lib/ui/renderChain.ts +49 -13
- package/src/lib/ui/renderToStream.ts +22 -18
- package/src/lib/ui/resumeSeedScript.ts +1 -1
- package/src/lib/ui/router.ts +63 -36
- package/src/lib/ui/runtime/AsyncCellError.ts +20 -0
- package/src/lib/ui/runtime/CELL_SEED.ts +14 -0
- 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 +1 -1
- 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 +3 -42
- 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 +16 -6
- 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/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/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/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/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/mutateDocArray.ts +0 -38
- 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 -108
- package/src/lib/ui/installHotBridge.ts +0 -95
- 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 -43
- 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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { abideLog } from '../../shared/abideLog.ts'
|
|
1
2
|
import { messageFromError } from '../../shared/messageFromError.ts'
|
|
2
3
|
|
|
3
4
|
/*
|
|
@@ -27,6 +28,11 @@ export function streamFromIterator<T>(
|
|
|
27
28
|
const textEncoder = new TextEncoder()
|
|
28
29
|
const iterator = iterable[Symbol.asyncIterator]()
|
|
29
30
|
let keepalive: ReturnType<typeof setInterval> | undefined
|
|
31
|
+
/* Set once the stream closes or is cancelled. A `pull` parked on `iterator.next()`
|
|
32
|
+
resolves AFTER a client-disconnect `cancel()` has already closed the controller;
|
|
33
|
+
without this guard it would touch the dead controller and throw "Controller is
|
|
34
|
+
already closed" — noise on every mid-frame disconnect. */
|
|
35
|
+
let closed = false
|
|
30
36
|
|
|
31
37
|
function stopKeepalive(): void {
|
|
32
38
|
if (keepalive !== undefined) {
|
|
@@ -65,20 +71,42 @@ export function streamFromIterator<T>(
|
|
|
65
71
|
async pull(controller) {
|
|
66
72
|
try {
|
|
67
73
|
const next = await iterator.next()
|
|
74
|
+
/* Cancelled during the awaited next() — the controller is already closed,
|
|
75
|
+
so any close/enqueue here would throw. Nothing left to do. */
|
|
76
|
+
if (closed) {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
68
79
|
if (next.done) {
|
|
80
|
+
closed = true
|
|
69
81
|
stopKeepalive()
|
|
70
82
|
controller.close()
|
|
71
83
|
return
|
|
72
84
|
}
|
|
73
85
|
controller.enqueue(textEncoder.encode(encoder.encodeFrame(next.value)))
|
|
74
86
|
} catch (error) {
|
|
87
|
+
/* A throw during cancellation unwinding (the generator's `finally` rejecting
|
|
88
|
+
as `.return()` runs) is not a real stream error — the controller is gone. */
|
|
89
|
+
if (closed) {
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
/* Log the FULL error server-side (host/credentials/stack an operator needs) — the
|
|
93
|
+
unary rpc path does the same, and the jsonl/sse docs promise it. Only the
|
|
94
|
+
sanitized message crosses the wire in the sentinel error frame. */
|
|
95
|
+
abideLog.error(error)
|
|
75
96
|
const message = messageFromError(error)
|
|
76
|
-
|
|
97
|
+
closed = true
|
|
77
98
|
stopKeepalive()
|
|
78
|
-
|
|
99
|
+
try {
|
|
100
|
+
controller.enqueue(textEncoder.encode(encoder.encodeError(message)))
|
|
101
|
+
controller.close()
|
|
102
|
+
} catch {
|
|
103
|
+
/* Consumer vanished between the throw and the sentinel frame — the error
|
|
104
|
+
frame never lands, but the connection is already closing regardless. */
|
|
105
|
+
}
|
|
79
106
|
}
|
|
80
107
|
},
|
|
81
108
|
cancel(reason) {
|
|
109
|
+
closed = true
|
|
82
110
|
stopKeepalive()
|
|
83
111
|
/*
|
|
84
112
|
Route cancel into the generator's normal exit, but swallow a
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { NO_STORE } from '../../shared/CACHE_CONTROL_VALUES.ts'
|
|
2
|
+
import { TEXT_PLAIN } from '../../shared/TEXT_PLAIN.ts'
|
|
3
|
+
import { STATUS_TEXT } from './STATUS_TEXT.ts'
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
The framework's plain-text status response — a `text/plain`, `no-store` body at
|
|
7
|
+
`status`, shared by the 404/405 dispatch branches, the asset servers' miss, and
|
|
8
|
+
the failed-upgrade reply so those literals can't drift. `body` defaults to the
|
|
9
|
+
status reason phrase (STATUS_TEXT, e.g. 'Not Found'), falling back to `HTTP
|
|
10
|
+
<status>` for an unlisted code. `extraHeaders` overlays the defaults per-key —
|
|
11
|
+
the 405 passes `Allow` this way. A fresh Response per call: a body is
|
|
12
|
+
single-use, so it can't be hoisted to a shared const.
|
|
13
|
+
*/
|
|
14
|
+
export function textResponse(
|
|
15
|
+
status: number,
|
|
16
|
+
body?: string,
|
|
17
|
+
extraHeaders?: Record<string, string>,
|
|
18
|
+
): Response {
|
|
19
|
+
return new Response(body ?? STATUS_TEXT[status] ?? `HTTP ${status}`, {
|
|
20
|
+
status,
|
|
21
|
+
headers: { 'Content-Type': TEXT_PLAIN, 'Cache-Control': NO_STORE, ...extraHeaders },
|
|
22
|
+
})
|
|
23
|
+
}
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
/*
|
|
2
2
|
The dev live-reload stamp the worker announces on the channel, split so the
|
|
3
3
|
browser keeps its page across edits that don't need a reload:
|
|
4
|
-
- `structure` fingerprints
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
- `cssHref` is the entry stylesheet's current content-hashed URL; a change
|
|
9
|
-
|
|
10
|
-
- `components` maps each hot-swappable (leaf child) component's module id to a
|
|
11
|
-
hash of its client build (style-independent). A change here alone fetches the
|
|
12
|
-
component's hot module and replaces its live instances — no reload.
|
|
4
|
+
- `structure` fingerprints every source signal a reload must react to — each
|
|
5
|
+
`.abide`'s client build hash (no CSS), the component-id set, non-`.abide`
|
|
6
|
+
source, public assets, and the shell (with the stylesheet href normalised out).
|
|
7
|
+
Any change here reloads.
|
|
8
|
+
- `cssHref` is the entry stylesheet's current content-hashed URL; a change here
|
|
9
|
+
alone swaps the `<link>` in place. Undefined when no stylesheet is built.
|
|
13
10
|
*/
|
|
14
11
|
export type DevReloadStamp = {
|
|
15
12
|
structure: string
|
|
16
13
|
cssHref: string | undefined
|
|
17
|
-
components: Record<string, string>
|
|
18
14
|
}
|
|
@@ -19,6 +19,6 @@ export type InspectorCacheEntry = {
|
|
|
19
19
|
tags: string[]
|
|
20
20
|
/* A short JSON preview of the decoded warm value, when the entry holds one. */
|
|
21
21
|
value: string | undefined
|
|
22
|
-
/* An armed
|
|
22
|
+
/* An armed refetch policy (`refetch`, optionally + throttle/debounce + ms), if declared. */
|
|
23
23
|
policy: string | undefined
|
|
24
24
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { CacheStore } from '../../../shared/types/CacheStore.ts'
|
|
2
|
+
import type { PendingAsyncCells } from '../../../shared/types/PendingAsyncCells.ts'
|
|
3
|
+
import type { ResolvedCells } from '../../../shared/types/ResolvedCells.ts'
|
|
4
|
+
import type { StreamedCells } from '../../../shared/types/StreamedCells.ts'
|
|
2
5
|
import type { TraceContext } from '../../../shared/types/TraceContext.ts'
|
|
3
6
|
import type { Scope } from '../../../ui/types/Scope.ts'
|
|
4
7
|
|
|
@@ -14,6 +17,30 @@ export type RequestStore = {
|
|
|
14
17
|
req: Request
|
|
15
18
|
cache: CacheStore
|
|
16
19
|
/*
|
|
20
|
+
In-flight async-cell promises registered during this request's SSR pass. The
|
|
21
|
+
Tier-2 barrier (`settleAsyncCells`) drains and awaits them between a
|
|
22
|
+
component's cell declarations and its template so resolved values bake into
|
|
23
|
+
the HTML. Per-request (like `cache`) so concurrent renders never share a drain.
|
|
24
|
+
*/
|
|
25
|
+
pendingAsyncCells: PendingAsyncCells
|
|
26
|
+
/*
|
|
27
|
+
Async-cell values that RESOLVED during this request's SSR pass, keyed by render-path id.
|
|
28
|
+
`createAsyncCell.settleValue` pushes each; the page renderer stamps them into `__SSR__.cells`
|
|
29
|
+
(ref-json) so the client hydrates the cell warm. Sibling of `pendingAsyncCells` (the barrier's
|
|
30
|
+
in-flight list) — this one holds settled VALUES, read at render-return, not awaited.
|
|
31
|
+
*/
|
|
32
|
+
resolvedCells: ResolvedCells
|
|
33
|
+
/*
|
|
34
|
+
STREAMING async-cell settled VALUES recorded during this request's SSR pass, keyed by render-path
|
|
35
|
+
id (ADR-0035). A streaming cell ships pending in the shell; the page renderer drains this after the
|
|
36
|
+
shell and streams an `__abideResolve({ cellKey, value })` chunk for each so the client adopts the
|
|
37
|
+
resolved value post-hydration. These are already-settled values (pushed by `createAsyncCell`),
|
|
38
|
+
never awaited here — a cell that stays pending through the request is simply not recorded and the
|
|
39
|
+
client cold-runs it (awaiting one would hang the response). Per-request so concurrent renders never
|
|
40
|
+
mix. Sibling of `resolvedCells` (the blocking partition baked into the head snapshot).
|
|
41
|
+
*/
|
|
42
|
+
streamedCells: StreamedCells
|
|
43
|
+
/*
|
|
17
44
|
W3C trace position: inbound `traceparent` continued (prefer-incoming) or a
|
|
18
45
|
fresh sampled trace minted at the boundary. Read by trace()/log via the
|
|
19
46
|
request-scope resolver and stamped into __SSR__ for the browser half.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { abideLog } from '../../shared/abideLog.ts'
|
|
2
|
+
import { MCP_PATH } from '../../shared/MCP_PATH.ts'
|
|
2
3
|
import { rpcRegistry } from '../rpc/rpcRegistry.ts'
|
|
3
4
|
import { socketRegistry } from '../sockets/socketRegistry.ts'
|
|
4
5
|
import { ensureRegistriesLoaded } from './registryManifests.ts'
|
|
@@ -18,15 +19,24 @@ export async function warnUnguardedMcp(): Promise<void> {
|
|
|
18
19
|
} catch {
|
|
19
20
|
return
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
)
|
|
22
|
+
/* Rpc entries carry the resolved clients on `entry.remote` (ADR-0020); socket entries
|
|
23
|
+
keep their own `entry.clients`. Count each from its own home. */
|
|
24
|
+
let exposed = 0
|
|
25
|
+
for (const entry of rpcRegistry.values()) {
|
|
26
|
+
if (entry.remote.clients.mcp) {
|
|
27
|
+
exposed += 1
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
for (const entry of socketRegistry.values()) {
|
|
31
|
+
if (entry.clients.mcp) {
|
|
32
|
+
exposed += 1
|
|
33
|
+
}
|
|
34
|
+
}
|
|
25
35
|
if (exposed === 0) {
|
|
26
36
|
return
|
|
27
37
|
}
|
|
28
38
|
abideLog.warn(
|
|
29
|
-
`MCP endpoint
|
|
39
|
+
`MCP endpoint ${MCP_PATH} exposes ${exposed} declaration${exposed === 1 ? '' : 's'} ` +
|
|
30
40
|
'with no auth guard — add an app.handle middleware in src/app.ts to ' +
|
|
31
41
|
'authenticate machine clients, or set clients.mcp: false per declaration',
|
|
32
42
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ServerWebSocket } from 'bun'
|
|
2
2
|
import { abideLog } from '../../shared/abideLog.ts'
|
|
3
|
-
import {
|
|
3
|
+
import { decodeWireBody } from '../../shared/decodeWireBody.ts'
|
|
4
4
|
import { encodeRefJson } from '../../shared/encodeRefJson.ts'
|
|
5
5
|
import { memoizeByKey } from '../../shared/memoizeByKey.ts'
|
|
6
6
|
import { messageFromError } from '../../shared/messageFromError.ts'
|
|
@@ -245,7 +245,7 @@ export function createSocketDispatcher(sockets: SocketRoutes): SocketDispatcher
|
|
|
245
245
|
the process down.
|
|
246
246
|
*/
|
|
247
247
|
try {
|
|
248
|
-
entry.socket.
|
|
248
|
+
entry.socket.publish(frame.message)
|
|
249
249
|
} catch (publishError) {
|
|
250
250
|
abideLog.error(publishError)
|
|
251
251
|
}
|
|
@@ -309,7 +309,7 @@ export function createSocketDispatcher(sockets: SocketRoutes): SocketDispatcher
|
|
|
309
309
|
}
|
|
310
310
|
try {
|
|
311
311
|
// publish() validates against the socket schema and throws on a bad payload.
|
|
312
|
-
entry.socket.
|
|
312
|
+
entry.socket.publish(message)
|
|
313
313
|
} catch (publishError) {
|
|
314
314
|
return error(422, messageFromError(publishError))
|
|
315
315
|
}
|
|
@@ -338,14 +338,12 @@ export function createSocketDispatcher(sockets: SocketRoutes): SocketDispatcher
|
|
|
338
338
|
const text = typeof data === 'string' ? data : textDecoder.decode(data)
|
|
339
339
|
let frame: SocketClientFrame
|
|
340
340
|
try {
|
|
341
|
-
/*
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
frame = JSON.parse(text) as SocketClientFrame
|
|
348
|
-
}
|
|
341
|
+
/* No header rides a ws frame, so decodeWireBody sniffs: ref-json from abide's
|
|
342
|
+
own client, else a non-abide client's plain-JSON frame (which decodeRefJson
|
|
343
|
+
rejects — a frame is always an object, never the `[rootValue, slots]`
|
|
344
|
+
envelope — so it falls back to JSON.parse). A frame malformed under both
|
|
345
|
+
codecs throws here and is dropped. */
|
|
346
|
+
frame = decodeWireBody(text, undefined) as SocketClientFrame
|
|
349
347
|
} catch {
|
|
350
348
|
return
|
|
351
349
|
}
|
|
@@ -24,8 +24,8 @@ is the live stream — no replay. `chat.tail(count)` opens a subscription
|
|
|
24
24
|
seeded with the last `count` retained frames (no-arg = the whole
|
|
25
25
|
retained tail, clamped to the declared `tail` size). When `ttl` is set,
|
|
26
26
|
retained frames older than `ttl` ms are evicted lazily on every
|
|
27
|
-
read/append — no timer runs in the background. `chat.
|
|
28
|
-
called server-side it both notifies in-process iterators and
|
|
27
|
+
read/append — no timer runs in the background. `chat.publish(m)` is isomorphic —
|
|
28
|
+
called server-side it both notifies in-process iterators and fans out
|
|
29
29
|
to remote subscribers; called client-side (via socketProxy) it sends a
|
|
30
30
|
`pub` frame the dispatcher validates and forwards.
|
|
31
31
|
*/
|
|
@@ -178,8 +178,9 @@ export function defineSocket<T>(name: string, opts: SocketOptions = {}): Socket<
|
|
|
178
178
|
const self = {
|
|
179
179
|
name,
|
|
180
180
|
clients,
|
|
181
|
-
/* `
|
|
182
|
-
|
|
181
|
+
/* `publish` is the public fan-out (mirroring Bun's `server.publish()`); the internal
|
|
182
|
+
function shares the name. */
|
|
183
|
+
publish,
|
|
183
184
|
tail: (count?: number, hooks?: TailHooks) => iterate(count ?? 'all', hooks),
|
|
184
185
|
/* The latest retained frame (after ttl pruning), or undefined when none is held. */
|
|
185
186
|
peek: () => {
|
package/src/lib/server/sse.ts
CHANGED
|
@@ -24,6 +24,7 @@ EventSource surfaces this via its `error` listener and `tail()`
|
|
|
24
24
|
maps it to the entry's `error` field.
|
|
25
25
|
*/
|
|
26
26
|
import { NO_STORE } from '../shared/CACHE_CONTROL_VALUES.ts'
|
|
27
|
+
import { encodeWireBody } from '../shared/encodeWireBody.ts'
|
|
27
28
|
import { sseErrorFrame } from '../shared/sseErrorFrame.ts'
|
|
28
29
|
import type { TypedResponse } from './rpc/types/TypedResponse.ts'
|
|
29
30
|
import { streamFromIterator } from './runtime/streamFromIterator.ts'
|
|
@@ -37,7 +38,10 @@ export function sse<Frame>(
|
|
|
37
38
|
init?: ResponseInit,
|
|
38
39
|
): TypedResponse<AsyncIterable<Frame>> {
|
|
39
40
|
const body = streamFromIterator(iterable, {
|
|
40
|
-
|
|
41
|
+
/* Honest-JSON encode (same encoder as `json()`) so a frame carrying a Set/Map/bigint
|
|
42
|
+
crosses losslessly instead of the silent `{}` / bigint-throw plain JSON.stringify gave
|
|
43
|
+
— parseSse's JSON.parse reads it unchanged since the wire stays honest JSON. */
|
|
44
|
+
encodeFrame: (value) => `data: ${encodeWireBody(value)}\n\n`,
|
|
41
45
|
encodeError: (message) => sseErrorFrame.encode(message),
|
|
42
46
|
keepaliveMs: KEEPALIVE_INTERVAL_MS,
|
|
43
47
|
keepalivePayload: ': keepalive\n\n',
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/* Brand on an async cell's facet (`AsyncComputed`/`AsyncState`). The probe family
|
|
2
|
+
(`peek`/`pending`/`refreshing`/`refresh`) tests for it to route a cell to its own
|
|
3
|
+
methods, the way `Symbol.asyncIterator` routes a stream. A well-known symbol (not a
|
|
4
|
+
string key) so it never collides with a resolved value's own properties. */
|
|
5
|
+
export const ASYNC_CELL: unique symbol = Symbol.for('abide.asyncCell')
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Dev-only manual-rebuild trigger: POSTing here signals the orchestrator to rebuild +
|
|
3
|
+
restart. Mounted only under `abide dev`. Shared so the router mount and the launcher's
|
|
4
|
+
"POST … to apply" hint name the one path.
|
|
5
|
+
*/
|
|
6
|
+
export const DEV_REBUILD_PATH = '/__abide/reload'
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*
|
|
2
|
+
The canonical RPC/HTTP verbs abide understands. One source of truth so the `HttpMethod`
|
|
3
|
+
type, the loader's rpc-export detection, and the compiler's helper set can't drift on which
|
|
4
|
+
export names are rpc entrypoints.
|
|
5
|
+
*/
|
|
6
|
+
export const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD'] as const
|
|
@@ -14,11 +14,7 @@ export class HttpError extends Error {
|
|
|
14
14
|
payload it carried — parsed off the `{ $abideError, data }` body by decodeResponse.
|
|
15
15
|
`data` is typed `unknown` (a throw can't carry the rpc's per-kind type to the
|
|
16
16
|
catch); narrow it yourself — for `kind: 'validation'` the shape is the exported
|
|
17
|
-
`ValidationErrorData` (`{ issues, fields }`). Both undefined for a plain `error(status, text)`.
|
|
18
|
-
The framework also reserves `kind: 'queued'` for a durable (`outbox: true`) call
|
|
19
|
-
parked because the server was unreachable — `data` then holds the parked OutboxEntry,
|
|
20
|
-
so `(error.data as OutboxEntry).settled` awaits the eventual delivered result or
|
|
21
|
-
server refusal (the entry's own `error` carries the underlying cause). */
|
|
17
|
+
`ValidationErrorData` (`{ issues, fields }`). Both undefined for a plain `error(status, text)`. */
|
|
22
18
|
readonly kind?: string
|
|
23
19
|
readonly data?: unknown
|
|
24
20
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*
|
|
2
|
+
The MCP endpoint: inbound JSON-RPC over HTTP delegated to the app's `McpServer.handle`,
|
|
3
|
+
mounted only when an `mcp` is configured. Framework-internal (`/__abide/*`). Shared so the
|
|
4
|
+
router mount and the boot-time disclosure warning name the one path.
|
|
5
|
+
*/
|
|
6
|
+
export const MCP_PATH = '/__abide/mcp'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Single source of truth for the proxied/server-only split. These are the only
|
|
3
|
+
subdirectories under src/server/ whose modules the client bundle replaces with
|
|
4
|
+
proxy stubs instead of shipping their real source: src/server/rpc (each
|
|
5
|
+
HTTP-method handler → remoteProxy) and src/server/sockets (each socket
|
|
6
|
+
declaration → socketProxy). Every OTHER module under src/server/ is server-only
|
|
7
|
+
and must never reach the browser bundle.
|
|
8
|
+
|
|
9
|
+
Expressed as bare `src/server/`-relative segments so each caller joins them
|
|
10
|
+
against its own base — the resolver plugin against the absolute serverDir, the
|
|
11
|
+
dev orchestrator's changeAffectsClient against the `server/` string prefix —
|
|
12
|
+
rather than re-spelling the set. Adding a proxied directory is one edit here and
|
|
13
|
+
both side-classifiers move in lockstep.
|
|
14
|
+
*/
|
|
15
|
+
export const PROXIED_SERVER_SUBDIRS = ['rpc', 'sockets'] as const
|
|
@@ -26,6 +26,18 @@ export const REF_JSON_TAGS = {
|
|
|
26
26
|
BIGINT: '~g',
|
|
27
27
|
// ['~u'] — undefined (and functions/symbols, folded to it).
|
|
28
28
|
UNDEFINED: '~u',
|
|
29
|
-
// ['~n', token] — the numbers JSON flattens to null
|
|
29
|
+
// ['~n', token] — the numbers JSON flattens to null; the token is one of REF_JSON_NUMBER_TOKENS.
|
|
30
30
|
NUMBER: '~n',
|
|
31
31
|
} as const
|
|
32
|
+
|
|
33
|
+
/*
|
|
34
|
+
The tokens carried by a `['~n', token]` tag — the numbers JSON can't represent. Shared by
|
|
35
|
+
`encodeRefJson`'s `numberToken` (produces them) and `decodeRefJson`'s `decodeNumberToken`
|
|
36
|
+
(parses them) so the wire form can't drift between the two ends.
|
|
37
|
+
*/
|
|
38
|
+
export const REF_JSON_NUMBER_TOKENS = {
|
|
39
|
+
NAN: 'NaN',
|
|
40
|
+
INFINITY: 'Infinity',
|
|
41
|
+
NEG_INFINITY: '-Infinity',
|
|
42
|
+
NEG_ZERO: '-0',
|
|
43
|
+
} as const
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/*
|
|
2
|
+
The reserved global alias names the `$rpc`/`$socket` module rewrites target: the bundler's
|
|
3
|
+
banner binds each (`import { defineRpc as __abideDefineRpc__ }`, see abideResolverPlugin) and
|
|
4
|
+
the codegen emit (`prepareRpcModule` / `prepareSocketModule`) calls it. Shared so the emitted
|
|
5
|
+
call and the banner binding can't drift into an unbound-name ReferenceError at load.
|
|
6
|
+
*/
|
|
7
|
+
export const DEFINE_RPC_GLOBAL = '__abideDefineRpc__'
|
|
8
|
+
export const REMOTE_PROXY_GLOBAL = '__abideRemoteProxy__'
|
|
9
|
+
export const DEFINE_SOCKET_GLOBAL = '__abideDefineSocket__'
|
|
@@ -7,5 +7,6 @@ lazily-created fallback when none is registered (so isolated tests work). The
|
|
|
7
7
|
fallback creator guarantees a value, hence the non-null assertion.
|
|
8
8
|
*/
|
|
9
9
|
export function activeCacheStore(): CacheStore {
|
|
10
|
+
// biome-ignore lint/style/noNonNullAssertion: the slot's lazy fallback creator always returns a store
|
|
10
11
|
return cacheStoreSlot.get()!
|
|
11
12
|
}
|
|
@@ -7,5 +7,6 @@ single lazily-created empty snapshot when none is registered (so isolated tests
|
|
|
7
7
|
work). The fallback creator guarantees a value, hence the non-null assertion.
|
|
8
8
|
*/
|
|
9
9
|
export function activePage(): PageSnapshot {
|
|
10
|
+
// biome-ignore lint/style/noNonNullAssertion: the slot's lazy fallback creator always returns a snapshot
|
|
10
11
|
return pageSlot.get()!
|
|
11
12
|
}
|
|
@@ -11,7 +11,10 @@ this: it must clean its staging dir and return `false` rather than exit, so it
|
|
|
11
11
|
keeps its own epilogue.
|
|
12
12
|
*/
|
|
13
13
|
export async function buildArtifact(config: BuildConfig): Promise<BuildOutput> {
|
|
14
|
-
|
|
14
|
+
/* metafile: true so the abideResolverPlugin's onEnd reachability guard (ADR-0022 D3) can read
|
|
15
|
+
the post-DCE graph on a client build (buildDisconnected). Harmless extra output on the
|
|
16
|
+
server builds that also route through here. A caller can still override it explicitly. */
|
|
17
|
+
const result = await Bun.build({ metafile: true, ...config })
|
|
15
18
|
exitOnBuildFailure(result)
|
|
16
19
|
return result
|
|
17
20
|
}
|
|
@@ -63,9 +63,10 @@ export function buildSocketOverChannel<T>(
|
|
|
63
63
|
const socket = {
|
|
64
64
|
name,
|
|
65
65
|
clients: browserClientFlags,
|
|
66
|
-
/* `
|
|
67
|
-
topic's `clientPublish`)
|
|
68
|
-
|
|
66
|
+
/* `publish` sends a server-validated `pub` frame (the dispatcher gates it on the
|
|
67
|
+
topic's `clientPublish`), mirroring Bun's `server.publish()`; the internal
|
|
68
|
+
channel-send function shares the name. */
|
|
69
|
+
publish,
|
|
69
70
|
tail: (count?: number, hooks?: TailHooks) => iterate(count, hooks),
|
|
70
71
|
/* The latest frame this client has seen, synchronously. */
|
|
71
72
|
peek: () => lastFrame,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
import type { BuildMetafile } from 'bun'
|
|
3
|
+
|
|
4
|
+
/* One surviving module in the post-DCE bundle graph: its absolute path and input source byte
|
|
5
|
+
size. `bytes` is the metafile's `inputs[key].bytes` — the source weight the budget diagnostic
|
|
6
|
+
measures (a tree-shaken module is absent from the metafile entirely, so every module here
|
|
7
|
+
SURVIVED into the bundle). */
|
|
8
|
+
type BundleGraphModule = {
|
|
9
|
+
path: string
|
|
10
|
+
bytes: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
The post-DCE module graph reconstructed from a client build's `Bun.build` metafile — the reusable
|
|
15
|
+
analysis seam ADR-0031 D2 factors out. `metafile.inputs` is the DCE-accurate graph (a
|
|
16
|
+
textually-imported but tree-shaken module is ABSENT), so a single walk yields both the surviving
|
|
17
|
+
modules and their child→importer edges; consumers then judge the graph without re-walking it.
|
|
18
|
+
Two ride it today: the side-crossing reachability guard (a surviving server-only module is a
|
|
19
|
+
violation) and the bundle-budget diagnostic (a surviving input over a size budget is a warning).
|
|
20
|
+
The metafile carries module presence + input byte size, NOT export-level liveness — so a consumer
|
|
21
|
+
can judge "this module survived / is this big", not "this export is unused" (ADR-0031 D2 spike).
|
|
22
|
+
*/
|
|
23
|
+
export type BundleGraph = {
|
|
24
|
+
/* Every module present in the post-DCE graph, keyed by absolute path. */
|
|
25
|
+
modules: BundleGraphModule[]
|
|
26
|
+
/* The import chain from a graph root down to `target`, in root→target order (absolute paths),
|
|
27
|
+
reconstructed from the graph's own first-wins child→importer edges — one witness, cycle-safe.
|
|
28
|
+
Returns `[target]` when nothing imports it (a graph root). */
|
|
29
|
+
importerChain(target: string): string[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
Walks a client build's metafile once into a `BundleGraph`. `inputs` keys are relative to
|
|
34
|
+
`process.cwd()` while edge `path`s are absolute, so each module path is resolved against `cwd` to
|
|
35
|
+
match on absolute paths throughout. First edge wins for the importer map — enough to render one
|
|
36
|
+
witness chain, and cheap.
|
|
37
|
+
*/
|
|
38
|
+
export function bundleGraphFromMetafile(metafile: BuildMetafile, cwd: string): BundleGraph {
|
|
39
|
+
const modules: BundleGraphModule[] = []
|
|
40
|
+
/* child(absolute) → its importer(absolute); first edge wins — one witness chain. */
|
|
41
|
+
const importerOf = new Map<string, string>()
|
|
42
|
+
for (const [key, input] of Object.entries(metafile.inputs)) {
|
|
43
|
+
const modulePath = resolve(cwd, key)
|
|
44
|
+
modules.push({ path: modulePath, bytes: input.bytes })
|
|
45
|
+
for (const edge of input.imports) {
|
|
46
|
+
if (!importerOf.has(edge.path)) {
|
|
47
|
+
importerOf.set(edge.path, modulePath)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
modules,
|
|
53
|
+
importerChain(target) {
|
|
54
|
+
const chain = [target]
|
|
55
|
+
const seen = new Set([target])
|
|
56
|
+
let cursor = target
|
|
57
|
+
while (importerOf.has(cursor)) {
|
|
58
|
+
cursor = importerOf.get(cursor) as string
|
|
59
|
+
if (seen.has(cursor)) {
|
|
60
|
+
break
|
|
61
|
+
}
|
|
62
|
+
seen.add(cursor)
|
|
63
|
+
chain.push(cursor)
|
|
64
|
+
}
|
|
65
|
+
return chain.reverse()
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
}
|