@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,108 +1,77 @@
|
|
|
1
|
-
import { createLivenessWatch } from './createLivenessWatch.ts'
|
|
2
|
-
|
|
3
1
|
/*
|
|
4
|
-
The reachability registry behind `abide/shared/reachable`. A probe transport
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Per origin, the first read awaits one real probe (the FAITHFUL first answer —
|
|
9
|
-
its latency, including a full timeout when the host is down, is the price of
|
|
10
|
-
not guessing) and then hands the origin to a createLivenessWatch that re-probes
|
|
11
|
-
every `intervalMs` to keep the value warm. Every later read resolves instantly
|
|
12
|
-
off that warm value, fresh within one interval — the faithful cost is paid once.
|
|
2
|
+
The reachability registry behind `abide/shared/reachable`. A probe transport and the
|
|
3
|
+
TTL are injected so the public name wires them from env + a real HEAD while tests drive
|
|
4
|
+
scripted outcomes.
|
|
13
5
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
host
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
6
|
+
Per origin, a TTL memoize: the first read — and any read after the cached verdict has
|
|
7
|
+
aged past `ttlMs` — awaits a real probe (the FAITHFUL answer; its latency, a full timeout
|
|
8
|
+
when the host is down, is the price of not guessing) and caches the verdict with its
|
|
9
|
+
timestamp. Every read within the TTL resolves instantly off that cached value. Concurrent
|
|
10
|
+
reads of a cold/stale origin share the one in-flight probe. No background poll: a host that
|
|
11
|
+
goes down (or recovers) is noticed on the next read after its entry ages out, not
|
|
12
|
+
continuously.
|
|
20
13
|
*/
|
|
21
14
|
export function createReachable(options: {
|
|
22
15
|
probe: (origin: string) => Promise<boolean>
|
|
23
|
-
|
|
24
|
-
idleMs: number
|
|
16
|
+
ttlMs: number
|
|
25
17
|
}): {
|
|
26
18
|
reachable: (host: string | URL) => Promise<boolean>
|
|
27
|
-
/*
|
|
19
|
+
/* Drop every cached verdict — graceful reset and test isolation. */
|
|
28
20
|
stop: () => void
|
|
29
|
-
/* `using registry = createReachable(...)` — disposal
|
|
21
|
+
/* `using registry = createReachable(...)` — disposal clears the cache. */
|
|
30
22
|
[Symbol.dispose]: () => void
|
|
31
23
|
} {
|
|
32
24
|
type Entry = {
|
|
33
25
|
alive: boolean
|
|
34
|
-
/*
|
|
26
|
+
/* `Date.now()` when `alive` was taken; a read past `ttlMs` re-probes. */
|
|
27
|
+
probedAt: number
|
|
28
|
+
/* A probe in flight — concurrent cold/stale reads await the same one. */
|
|
35
29
|
inflight: Promise<boolean> | undefined
|
|
36
|
-
watch: ReturnType<typeof createLivenessWatch> | undefined
|
|
37
|
-
lastReadAt: number
|
|
38
|
-
}
|
|
39
|
-
const registry = new Map<string, Entry>()
|
|
40
|
-
|
|
41
|
-
/* The ongoing poll's probe: reap an idle origin, else run the real probe. */
|
|
42
|
-
function watchProbe(origin: string): Promise<boolean> {
|
|
43
|
-
const entry = registry.get(origin)
|
|
44
|
-
if (entry && Date.now() - entry.lastReadAt > options.idleMs) {
|
|
45
|
-
entry.watch?.stop()
|
|
46
|
-
registry.delete(origin)
|
|
47
|
-
/* Discarded — stop() moved the watched url, so the watch won't reschedule. */
|
|
48
|
-
return Promise.resolve(false)
|
|
49
|
-
}
|
|
50
|
-
return options.probe(origin)
|
|
51
30
|
}
|
|
31
|
+
const cache = new Map<string, Entry>()
|
|
52
32
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
entry.alive = alive
|
|
58
|
-
},
|
|
59
|
-
intervalMs: options.intervalMs,
|
|
60
|
-
})
|
|
61
|
-
entry.watch.watch(origin)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async function reachable(host: string | URL): Promise<boolean> {
|
|
65
|
-
/*
|
|
66
|
-
HEAD the origin root: this answers host connectivity, not endpoint
|
|
67
|
-
health. A bare host string defaults to https (the external-dependency
|
|
68
|
-
norm); an explicit http://… is honored.
|
|
69
|
-
*/
|
|
70
|
-
const url =
|
|
71
|
-
typeof host === 'string' && !/^https?:\/\//i.test(host) ? `https://${host}` : host
|
|
72
|
-
const origin = new URL(url).origin
|
|
73
|
-
const existing = registry.get(origin)
|
|
74
|
-
if (existing) {
|
|
75
|
-
existing.lastReadAt = Date.now()
|
|
76
|
-
return existing.inflight ?? existing.alive
|
|
77
|
-
}
|
|
78
|
-
/* Cold: optimistic seed, but the first read awaits a real probe before returning. */
|
|
79
|
-
const entry: Entry = {
|
|
80
|
-
alive: true,
|
|
81
|
-
inflight: undefined,
|
|
82
|
-
watch: undefined,
|
|
83
|
-
lastReadAt: Date.now(),
|
|
84
|
-
}
|
|
85
|
-
registry.set(origin, entry)
|
|
86
|
-
/* A rejecting probe reads as unreachable, not a permanent wedge: without
|
|
87
|
-
the catch a thrown probe leaves inflight set forever (every later read
|
|
88
|
-
returns the rejected promise) and never starts the watch. */
|
|
33
|
+
/* Re-probe an origin, folding the verdict + its timestamp back into the entry. A rejecting
|
|
34
|
+
probe reads as unreachable, not a permanent wedge (without the catch a thrown probe would
|
|
35
|
+
leave `inflight` set forever). */
|
|
36
|
+
function refresh(origin: string, entry: Entry): Promise<boolean> {
|
|
89
37
|
entry.inflight = options
|
|
90
38
|
.probe(origin)
|
|
91
39
|
.catch(() => false)
|
|
92
40
|
.then((alive) => {
|
|
93
41
|
entry.alive = alive
|
|
42
|
+
entry.probedAt = Date.now()
|
|
94
43
|
entry.inflight = undefined
|
|
95
|
-
startWatch(entry, origin)
|
|
96
44
|
return alive
|
|
97
45
|
})
|
|
98
46
|
return entry.inflight
|
|
99
47
|
}
|
|
100
48
|
|
|
101
|
-
function
|
|
102
|
-
|
|
103
|
-
|
|
49
|
+
function reachable(host: string | URL): Promise<boolean> {
|
|
50
|
+
/* HEAD the origin root: host connectivity, not endpoint health. A bare host defaults to
|
|
51
|
+
https (the external-dependency norm); an explicit http://… is honored. */
|
|
52
|
+
const url =
|
|
53
|
+
typeof host === 'string' && !/^https?:\/\//i.test(host) ? `https://${host}` : host
|
|
54
|
+
const origin = new URL(url).origin
|
|
55
|
+
const existing = cache.get(origin)
|
|
56
|
+
if (existing !== undefined) {
|
|
57
|
+
/* A probe already running → share it (dedupes concurrent cold/stale reads). */
|
|
58
|
+
if (existing.inflight !== undefined) {
|
|
59
|
+
return existing.inflight
|
|
60
|
+
}
|
|
61
|
+
/* Fresh within the TTL → instant warm read. */
|
|
62
|
+
if (Date.now() - existing.probedAt < options.ttlMs) {
|
|
63
|
+
return Promise.resolve(existing.alive)
|
|
64
|
+
}
|
|
65
|
+
/* Aged out → re-probe on this read. */
|
|
66
|
+
return refresh(origin, existing)
|
|
104
67
|
}
|
|
105
|
-
|
|
68
|
+
const entry: Entry = { alive: true, probedAt: 0, inflight: undefined }
|
|
69
|
+
cache.set(origin, entry)
|
|
70
|
+
return refresh(origin, entry)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function stop(): void {
|
|
74
|
+
cache.clear()
|
|
106
75
|
}
|
|
107
76
|
|
|
108
77
|
return { reachable, stop, [Symbol.dispose]: stop }
|
|
@@ -4,22 +4,25 @@ import { HttpError } from './HttpError.ts'
|
|
|
4
4
|
import { keyForRemoteCall } from './keyForRemoteCall.ts'
|
|
5
5
|
import { REMOTE_FUNCTION } from './REMOTE_FUNCTION.ts'
|
|
6
6
|
import { recordRemoteMeta } from './recordRemoteMeta.ts'
|
|
7
|
+
import { reviveWireOutput } from './reviveWireOutput.ts'
|
|
7
8
|
import { rpcErrorRegistry } from './rpcErrorRegistry.ts'
|
|
8
9
|
import { subscribableFromResponse } from './subscribableFromResponse.ts'
|
|
9
|
-
import type {
|
|
10
|
+
import type { CachePolicy } from './types/CachePolicy.ts'
|
|
10
11
|
import type { ClientFlags } from './types/ClientFlags.ts'
|
|
11
12
|
import type { HttpMethod } from './types/HttpMethod.ts'
|
|
13
|
+
import type { NamedAsyncIterable } from './types/NamedAsyncIterable.ts'
|
|
14
|
+
import type { OutputWirePlan } from './types/OutputWirePlan.ts'
|
|
12
15
|
import type { RawRemoteFunction } from './types/RawRemoteFunction.ts'
|
|
13
16
|
import type { RemoteFunction } from './types/RemoteFunction.ts'
|
|
14
17
|
import type { RpcOptions } from './types/RpcOptions.ts'
|
|
15
|
-
import type {
|
|
18
|
+
import type { StreamPolicy } from './types/StreamPolicy.ts'
|
|
16
19
|
|
|
17
20
|
/*
|
|
18
21
|
Assembles the public RemoteFunction shape used identically by the
|
|
19
22
|
server-side defineRpc (in-process handler invocation) and the
|
|
20
23
|
client-side remoteProxy (network fetch). Centralising the wiring here
|
|
21
24
|
keeps the call/raw/stream/fetch semantics — including WeakMap meta
|
|
22
|
-
recording, Content-Type decode, and
|
|
25
|
+
recording, Content-Type decode, and NamedAsyncIterable derivation — in one
|
|
23
26
|
place so the two halves can't drift.
|
|
24
27
|
|
|
25
28
|
- `buildRequest(args)` synthesizes the Request a meta reader (cache()) or
|
|
@@ -50,10 +53,19 @@ export function createRemoteFunction<Args, Return>(opts: {
|
|
|
50
53
|
opts?: RpcOptions,
|
|
51
54
|
) => Promise<Response>
|
|
52
55
|
parseArgsForFetch?: (request: Request) => Promise<Args | undefined>
|
|
53
|
-
/* A streaming rpc (handler returns jsonl()/sse()): the bare call returns the
|
|
56
|
+
/* A streaming rpc (handler returns jsonl()/sse()): the bare call returns the NamedAsyncIterable
|
|
54
57
|
directly (the iterable IS the value) rather than decoding one Response body. Emitted by
|
|
55
58
|
the bundler's syntactic scan; false/undefined keeps the decode-a-Response path. */
|
|
56
59
|
streaming?: boolean
|
|
60
|
+
/* Endpoint cache/stream policy (ADR-0020) — stamped onto both callable variants so
|
|
61
|
+
readThrough reads it as the bottom policy layer. Declared once on the rpc definition. */
|
|
62
|
+
cache?: CachePolicy<Args>
|
|
63
|
+
stream?: StreamPolicy
|
|
64
|
+
/* Client-only: the output wire codec plan (ADR-0029) the remoteProxy stub carries — the decoded
|
|
65
|
+
response body's structured fields are revived through it (a `Set`/`Map`/`bigint`/`Date`). The
|
|
66
|
+
server defineRpc never sets it, so an in-process read is untouched. undefined leaves the body
|
|
67
|
+
as its honest-JSON form. */
|
|
68
|
+
outputWirePlan?: OutputWirePlan
|
|
57
69
|
}): RemoteFunction<Args, Return> {
|
|
58
70
|
const {
|
|
59
71
|
method,
|
|
@@ -64,6 +76,9 @@ export function createRemoteFunction<Args, Return>(opts: {
|
|
|
64
76
|
invoke,
|
|
65
77
|
parseArgsForFetch,
|
|
66
78
|
streaming,
|
|
79
|
+
cache: cachePolicy,
|
|
80
|
+
stream: streamPolicy,
|
|
81
|
+
outputWirePlan,
|
|
67
82
|
} = opts
|
|
68
83
|
|
|
69
84
|
/*
|
|
@@ -102,20 +117,21 @@ export function createRemoteFunction<Args, Return>(opts: {
|
|
|
102
117
|
}
|
|
103
118
|
rawCall.method = method
|
|
104
119
|
rawCall.url = url
|
|
120
|
+
/* Endpoint policy on both variants so readThrough can read it off whichever the caller
|
|
121
|
+
passed (`fn` for the decoded read, `fn.raw` for the raw escape hatch). */
|
|
122
|
+
rawCall.cache = cachePolicy
|
|
123
|
+
rawCall.stream = streamPolicy
|
|
105
124
|
/* Non-enumerable brand on both variants; see REMOTE_FUNCTION. */
|
|
106
125
|
Object.defineProperty(rawCall, REMOTE_FUNCTION, { value: true })
|
|
107
126
|
const raw = rawCall as RawRemoteFunction<Args>
|
|
108
127
|
|
|
109
|
-
function callable(
|
|
110
|
-
|
|
111
|
-
opts?: RpcOptions,
|
|
112
|
-
): Promise<Return> | Subscribable<Return> {
|
|
113
|
-
/* A streaming rpc (jsonl/sse) returns the Subscribable directly — the iterable IS the
|
|
128
|
+
function callable(args: Args | FormData): Promise<Return> | NamedAsyncIterable<Return> {
|
|
129
|
+
/* A streaming rpc (jsonl/sse) returns the NamedAsyncIterable directly — the iterable IS the
|
|
114
130
|
value (for await / state(fn(args))). Deferred fetch, keyForRemoteCall-keyed so tail()
|
|
115
131
|
dedupes readers; no decode, so the error-capture path below doesn't apply. */
|
|
116
132
|
if (streaming) {
|
|
117
133
|
return subscribableFromResponse(keyForRemoteCall(method, url, args), () =>
|
|
118
|
-
raw(args as Args
|
|
134
|
+
raw(args as Args),
|
|
119
135
|
)
|
|
120
136
|
}
|
|
121
137
|
/* The bare call IS the smart read: route through the cache store's smart-read
|
|
@@ -123,34 +139,40 @@ export function createRemoteFunction<Args, Return>(opts: {
|
|
|
123
139
|
reactive, while a write is coalesce-only — the raw fetch moves to `.raw`.
|
|
124
140
|
`cache.read(callable, …)` brand-reads `callable.raw` for the undecoded variant
|
|
125
141
|
and decodes on the way out, so pass the callable (which carries `.raw`), not
|
|
126
|
-
`raw`.
|
|
127
|
-
transport options live on `.raw
|
|
142
|
+
`raw`. There is no call-site options argument any more — all cache policy is read
|
|
143
|
+
from the endpoint (`callable.cache`); per-call transport options live on `.raw`. */
|
|
128
144
|
const key = keyForRemoteCall(method, url, args)
|
|
129
|
-
return cache
|
|
130
|
-
|
|
131
|
-
.then(
|
|
132
|
-
/* Capture the rejection into the rpc error registry (design Part 4) keyed by call
|
|
145
|
+
return cache.read(callable as RemoteFunction<Args, Return>, args as Args).then(
|
|
146
|
+
/* Capture the rejection into the rpc error registry (design Part 4) keyed by call
|
|
133
147
|
identity, and clear it on success — the reactive `fn.error()` probe reads it. */
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
+
(value) => {
|
|
149
|
+
rpcErrorRegistry.clear(key)
|
|
150
|
+
/* Revive the decoded body's structured fields per the baked output plan (ADR-0029):
|
|
151
|
+
a wire array → `Set`/`Map`, a digit string → `bigint`, an ISO string → `Date`. The
|
|
152
|
+
decoded value is call-private (a fresh decode or cloned warm value), so the revive
|
|
153
|
+
mutates in place. No plan (undefined — every server-side read, or a client endpoint
|
|
154
|
+
with no structured field) returns the value untouched. */
|
|
155
|
+
return reviveWireOutput(value, outputWirePlan) as Return
|
|
156
|
+
},
|
|
157
|
+
(error: unknown) => {
|
|
158
|
+
rpcErrorRegistry.record(key, error)
|
|
159
|
+
throw error
|
|
160
|
+
},
|
|
161
|
+
)
|
|
148
162
|
}
|
|
149
163
|
callable.method = method
|
|
150
164
|
callable.url = url
|
|
151
165
|
callable.clients = clients
|
|
152
166
|
callable.crossOrigin = crossOrigin
|
|
167
|
+
callable.cache = cachePolicy
|
|
168
|
+
callable.stream = streamPolicy
|
|
153
169
|
callable.raw = raw
|
|
170
|
+
/* Stamp the output wire codec plan (ADR-0029) so the public `cache(fn, args)` and
|
|
171
|
+
`cache.peek(fn, args)` can revive the decoded body's structured fields (Set/Map/Date/bigint)
|
|
172
|
+
exactly as the bare `fn(args)` read does above — otherwise those two read APIs return the raw
|
|
173
|
+
honest-JSON form and disagree with `fn(args)`. A runtime affordance, not on the RemoteFunction
|
|
174
|
+
surface (read via cast in cache.ts, like `settled`); undefined server-side / plan-less. */
|
|
175
|
+
;(callable as { outputWirePlan?: OutputWirePlan }).outputWirePlan = outputWirePlan
|
|
154
176
|
/* Uniform runtime guard for every rpc — the per-rpc data typing lives entirely in the
|
|
155
177
|
RpcErrorGuard<Errors> signature RemoteFunction projects onto it (Errors flows from the
|
|
156
178
|
rpc helper's declared type, not from here). */
|