@abide/abide 0.49.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 +70 -52
- package/CHANGELOG.md +177 -0
- package/README.md +12 -7
- 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,9 +1,12 @@
|
|
|
1
1
|
import { carriesBodyArgs } from '../../shared/carriesBodyArgs.ts'
|
|
2
2
|
import { contentTypeOf } from '../../shared/contentTypeOf.ts'
|
|
3
|
-
import {
|
|
3
|
+
import { decodeWireBody } from '../../shared/decodeWireBody.ts'
|
|
4
4
|
import { HttpError } from '../../shared/HttpError.ts'
|
|
5
5
|
import { REF_JSON_HEADER } from '../../shared/REF_JSON_HEADER.ts'
|
|
6
|
+
import { reviveWireField } from '../../shared/reviveWireField.ts'
|
|
6
7
|
import type { HttpMethod } from '../../shared/types/HttpMethod.ts'
|
|
8
|
+
import type { InputCoercion } from '../../shared/types/InputCoercion.ts'
|
|
9
|
+
import type { WireKind } from '../../shared/types/WireKind.ts'
|
|
7
10
|
import { error } from '../error.ts'
|
|
8
11
|
import { requestContext } from '../runtime/requestContext.ts'
|
|
9
12
|
import { readBodyWithinLimit } from './readBodyWithinLimit.ts'
|
|
@@ -62,6 +65,7 @@ export async function parseArgs(
|
|
|
62
65
|
method: HttpMethod,
|
|
63
66
|
request: Request,
|
|
64
67
|
maxBodySize?: number,
|
|
68
|
+
coerce?: InputCoercion,
|
|
65
69
|
): Promise<unknown> {
|
|
66
70
|
/*
|
|
67
71
|
Skip the URL parse entirely when the raw request URL has no query —
|
|
@@ -99,9 +103,7 @@ export async function parseArgs(
|
|
|
99
103
|
OpenAPI SDK) omits it and sends ordinary JSON — read with plain
|
|
100
104
|
JSON.parse, since the ref-json envelope is ambiguous with a 2-element
|
|
101
105
|
array body. */
|
|
102
|
-
body = bounded.headers.has(REF_JSON_HEADER)
|
|
103
|
-
? decodeRefJson(text)
|
|
104
|
-
: JSON.parse(text)
|
|
106
|
+
body = decodeWireBody(text, bounded.headers.has(REF_JSON_HEADER))
|
|
105
107
|
}
|
|
106
108
|
} else if (
|
|
107
109
|
contentType.includes('application/x-www-form-urlencoded') ||
|
|
@@ -122,19 +124,22 @@ export async function parseArgs(
|
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
if (!url) {
|
|
125
|
-
/* `body` is undefined or a plain object here
|
|
127
|
+
/* `body` is undefined or a plain object here. A form-encoded body arrives stringly, so
|
|
128
|
+
coerce its numeric/boolean fields (a JSON body's values are already typed — non-strings
|
|
129
|
+
the coercion leaves untouched). */
|
|
130
|
+
if (body !== undefined && coerce !== undefined) {
|
|
131
|
+
applyCoercion(body as Record<string, unknown>, coerce)
|
|
132
|
+
}
|
|
126
133
|
return body
|
|
127
134
|
}
|
|
128
135
|
|
|
129
136
|
/*
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
version strings like '1.0'), silently breaking GET validation. A correct fix
|
|
137
|
-
needs the schema threaded in here (or a coercing schema adapter at the rpc).
|
|
137
|
+
Query params (and form-encoded body fields) arrive as strings, so a numeric/boolean field
|
|
138
|
+
would reach schema validation as `'2'`/`'true'`. `coerce` (ADR-0028) is the build-time plan
|
|
139
|
+
of exactly which fields are numeric/boolean in the endpoint's `Args` type — resolved through
|
|
140
|
+
the warm server program, so a string-typed field that merely looks numeric (an id, a zip code,
|
|
141
|
+
`'1.0'`) is never listed and stays a string. Applied to the merged bag below; a JSON body's
|
|
142
|
+
already-typed values are non-strings the coercion skips.
|
|
138
143
|
*/
|
|
139
144
|
const bodyObject = (body ?? {}) as Record<string, unknown>
|
|
140
145
|
/* Collect the query into an object, arraying repeated keys (`?tag=a&tag=b` → `['a','b']`)
|
|
@@ -155,5 +160,85 @@ export async function parseArgs(
|
|
|
155
160
|
if (Object.keys(merged).length === 0) {
|
|
156
161
|
return undefined
|
|
157
162
|
}
|
|
163
|
+
if (coerce !== undefined) {
|
|
164
|
+
applyCoercion(merged, coerce)
|
|
165
|
+
}
|
|
158
166
|
return merged
|
|
159
167
|
}
|
|
168
|
+
|
|
169
|
+
/*
|
|
170
|
+
Revives the plain-JSON wire values in `args` into the runtime types the plan declares, in place
|
|
171
|
+
(ADR-0028 scalars, ADR-0029 structured). The scalar kinds (number/boolean/date/bigint) touch
|
|
172
|
+
strings only — a value the merge layered in from a typed JSON body is already the right type and
|
|
173
|
+
left alone; a repeated key (`?tag=1&tag=2`) is an array whose string members revive per element.
|
|
174
|
+
The container kinds (set/map) build from a JSON array (or object) but pass an already-typed value
|
|
175
|
+
(from the abide client's ref-json body) through untouched. Every branch is fail-open: an
|
|
176
|
+
unrevivable value stays its JSON form so the schema surfaces an honest issue rather than a throw.
|
|
177
|
+
*/
|
|
178
|
+
function applyCoercion(args: Record<string, unknown>, coerce: InputCoercion): void {
|
|
179
|
+
for (const key in coerce) {
|
|
180
|
+
const kind = coerce[key]
|
|
181
|
+
if (kind === undefined || !(key in args)) {
|
|
182
|
+
continue
|
|
183
|
+
}
|
|
184
|
+
args[key] = reviveValue(args[key], kind)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* One field's wire value → its runtime type per `kind`, fail-open. The container kinds wrap a JSON
|
|
189
|
+
array/object; the scalar kinds revive a string (or each string in a repeated-key array). An
|
|
190
|
+
already-typed value (Set/Map/Date/bigint from the abide ref-json body) passes through. */
|
|
191
|
+
function reviveValue(value: unknown, kind: WireKind): unknown {
|
|
192
|
+
/* Container kinds (set/map) decode through the shared wire codec; the input side additionally
|
|
193
|
+
accepts a plain object as Map entries — a query/form body can't send a JSON entries array
|
|
194
|
+
(ADR-0029 defers descending into array MEMBERS). */
|
|
195
|
+
if (kind === 'set' || kind === 'map') {
|
|
196
|
+
if (
|
|
197
|
+
kind === 'map' &&
|
|
198
|
+
!(value instanceof Map) &&
|
|
199
|
+
!Array.isArray(value) &&
|
|
200
|
+
value !== null &&
|
|
201
|
+
typeof value === 'object'
|
|
202
|
+
) {
|
|
203
|
+
return new Map(Object.entries(value))
|
|
204
|
+
}
|
|
205
|
+
return reviveWireField(value, kind)
|
|
206
|
+
}
|
|
207
|
+
/* Scalar kinds (number/boolean/date/bigint): query/form values arrive as strings — a lone
|
|
208
|
+
value, or each string in a repeated-key array. */
|
|
209
|
+
if (typeof value === 'string') {
|
|
210
|
+
return reviveScalar(value, kind)
|
|
211
|
+
}
|
|
212
|
+
if (Array.isArray(value)) {
|
|
213
|
+
return value.map((element) =>
|
|
214
|
+
typeof element === 'string' ? reviveScalar(element, kind) : element,
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
return value
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* One string → its number/boolean/date/bigint value, or the original string when it doesn't parse
|
|
221
|
+
cleanly (empty/whitespace, `NaN`, a non-`true`/`false` boolean, an unparseable date, a
|
|
222
|
+
non-integer bigint), so a bad value fails validation with the field intact instead of coercing
|
|
223
|
+
to `0`/`NaN`/`Invalid Date`. */
|
|
224
|
+
function reviveScalar(value: string, kind: WireKind): unknown {
|
|
225
|
+
if (kind === 'number') {
|
|
226
|
+
if (value.trim() === '') {
|
|
227
|
+
return value
|
|
228
|
+
}
|
|
229
|
+
const parsed = Number(value)
|
|
230
|
+
return Number.isNaN(parsed) ? value : parsed
|
|
231
|
+
}
|
|
232
|
+
if (kind === 'boolean') {
|
|
233
|
+
if (value === 'true') {
|
|
234
|
+
return true
|
|
235
|
+
}
|
|
236
|
+
if (value === 'false') {
|
|
237
|
+
return false
|
|
238
|
+
}
|
|
239
|
+
return value
|
|
240
|
+
}
|
|
241
|
+
/* date/bigint from a query/form string decode identically to the shared wire codec (ISO
|
|
242
|
+
string → Date, digit string → bigint), fail-open. */
|
|
243
|
+
return reviveWireField(value, kind)
|
|
244
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsonSchemaForSchema } from '../../shared/jsonSchemaForSchema.ts'
|
|
2
|
+
import type { RpcRegistryEntry } from './types/RpcRegistryEntry.ts'
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
The ONE resolution every surface (MCP tools, OpenAPI, the inspector catalog, and the
|
|
6
|
+
standalone CLI manifest) uses for an rpc's advertised INPUT shape: a declared
|
|
7
|
+
`inputSchema` VALIDATOR overrides the build-projected `inputJsonSchema` (ADR-0030 input
|
|
8
|
+
side); with neither, `undefined`. Callers that need a non-empty schema apply the opaque
|
|
9
|
+
`?? jsonSchemaForSchema(undefined)` fallback themselves (MCP/OpenAPI/CLI want it; the
|
|
10
|
+
inspector leaves it undefined). One origin so the surfaces can't drift — the CLI manifest
|
|
11
|
+
emitter previously read only `inputSchema` and silently dropped every plainly-typed
|
|
12
|
+
handler's projected shape (no typed flags, no `--help`, array flags overwriting).
|
|
13
|
+
*/
|
|
14
|
+
export function resolveInputJsonSchema(
|
|
15
|
+
entry: RpcRegistryEntry,
|
|
16
|
+
): Record<string, unknown> | undefined {
|
|
17
|
+
return entry.inputSchema ? jsonSchemaForSchema(entry.inputSchema) : entry.inputJsonSchema
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
The output analog: an `outputSchema` VALIDATOR overrides the projected `outputJsonSchema`;
|
|
22
|
+
with neither, `undefined` (no output shape advertised — every surface leaves it off).
|
|
23
|
+
*/
|
|
24
|
+
export function resolveOutputJsonSchema(
|
|
25
|
+
entry: RpcRegistryEntry,
|
|
26
|
+
): Record<string, unknown> | undefined {
|
|
27
|
+
return entry.outputSchema ? jsonSchemaForSchema(entry.outputSchema) : entry.outputJsonSchema
|
|
28
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import type { CachePolicy } from '../../../shared/types/CachePolicy.ts'
|
|
1
2
|
import type { ClientFlags } from '../../../shared/types/ClientFlags.ts'
|
|
2
3
|
import type { ErrorSpec } from '../../../shared/types/ErrorSpec.ts'
|
|
3
4
|
import type { RemoteFunction } from '../../../shared/types/RemoteFunction.ts'
|
|
4
5
|
import type { StandardSchemaV1 } from '../../../shared/types/StandardSchemaV1.ts'
|
|
6
|
+
import type { StreamPolicy } from '../../../shared/types/StreamPolicy.ts'
|
|
5
7
|
import type { TypedError } from './TypedError.ts'
|
|
6
8
|
import type { TypedResponse } from './TypedResponse.ts'
|
|
7
9
|
|
|
@@ -49,25 +51,39 @@ type RpcArgs<F extends RpcFn> = Parameters<F> extends [infer Args, ...unknown[]]
|
|
|
49
51
|
The RemoteFunction a bare overload produces from handler `F`. `SuccessBody`/`InferredErrors`
|
|
50
52
|
run over `Awaited<ReturnType<F>>` INLINE (not via an intermediate `extends RpcFn`-constrained
|
|
51
53
|
alias) — such an alias resolves `ReturnType` against the constraint bound and degrades the
|
|
52
|
-
body to `any`.
|
|
54
|
+
body to `any`.
|
|
53
55
|
*/
|
|
54
|
-
type RpcOf<F extends RpcFn
|
|
56
|
+
type RpcOf<F extends RpcFn> = RemoteFunction<
|
|
55
57
|
RpcArgs<F>,
|
|
56
58
|
SuccessBody<Awaited<ReturnType<F>>>,
|
|
57
|
-
InferredErrors<Awaited<ReturnType<F
|
|
58
|
-
Durable
|
|
59
|
+
InferredErrors<Awaited<ReturnType<F>>>
|
|
59
60
|
>
|
|
60
61
|
|
|
61
62
|
/*
|
|
62
|
-
|
|
63
|
-
`
|
|
64
|
-
|
|
65
|
-
`
|
|
66
|
-
|
|
67
|
-
(see MutatingRpcOpts) — a read RPC never accepts it.
|
|
63
|
+
The schema namespace (ADR-0020): `schemas: { input?, output?, files? }` replaces the
|
|
64
|
+
flat `inputSchema`/`outputSchema`/`filesSchema`. `input` drives the handler's arg type,
|
|
65
|
+
`output` is the success-body schema (OpenAPI 200 / MCP outputSchema — never drives arg
|
|
66
|
+
inference), `files` validates multipart File parts. The schema-bearing helper overloads
|
|
67
|
+
tighten specific members to required.
|
|
68
68
|
*/
|
|
69
|
-
type
|
|
70
|
-
|
|
69
|
+
type RpcSchemas = {
|
|
70
|
+
input?: StandardSchemaV1
|
|
71
|
+
output?: StandardSchemaV1
|
|
72
|
+
files?: StandardSchemaV1
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/*
|
|
76
|
+
Options every rpc overload accepts: the `schemas` namespace, the `clients` surface
|
|
77
|
+
flags (browser/mcp/cli), the same-origin
|
|
78
|
+
CSRF exemption (`crossOrigin`), the pre-parse body-byte ceiling
|
|
79
|
+
(`maxBodySize`), and the per-surface handler `timeout` (ms). Read helpers add the
|
|
80
|
+
endpoint `cache`/`stream` policy (ADR-0020); mutating helpers add neither — a write has
|
|
81
|
+
no replayable value to retain or stream. The kind-scoping is what makes `POST(fn, { cache })`
|
|
82
|
+
a compile error rather than a silent no-op. The single canonical source both `defineRpc`
|
|
83
|
+
and `RpcRegistryEntry` project from.
|
|
84
|
+
*/
|
|
85
|
+
type RpcSharedOpts = {
|
|
86
|
+
schemas?: RpcSchemas
|
|
71
87
|
clients?: Partial<ClientFlags>
|
|
72
88
|
crossOrigin?: boolean
|
|
73
89
|
maxBodySize?: number
|
|
@@ -75,63 +91,38 @@ type RpcBaseOpts = {
|
|
|
75
91
|
}
|
|
76
92
|
|
|
77
93
|
/*
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
so `
|
|
81
|
-
|
|
94
|
+
Read-helper (GET/HEAD) options: the shared base plus the endpoint `cache` policy
|
|
95
|
+
(`ttl`/`tags`/`throttle`/`debounce`/`shared`) and `stream` policy (`n`, replay depth).
|
|
96
|
+
Generic over `Args` so `cache.tags`'s `(args) => string[]` form is typed against the
|
|
97
|
+
rpc's own argument shape.
|
|
82
98
|
*/
|
|
83
|
-
type
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
unchanged — `rpc.outbox` exposes the queue. */
|
|
87
|
-
outbox?: boolean
|
|
99
|
+
type RpcReadOpts<Args> = RpcSharedOpts & {
|
|
100
|
+
cache?: CachePolicy<Args>
|
|
101
|
+
stream?: StreamPolicy
|
|
88
102
|
}
|
|
89
103
|
|
|
90
104
|
/*
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
becomes the
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
Four overloads by argument source:
|
|
105
|
+
The read helpers (GET/HEAD). The handler's return type is inferred whole
|
|
106
|
+
(`Awaited<ReturnType<F>>`), then split: `SuccessBody` becomes the caller's `Return`,
|
|
107
|
+
`InferredErrors` becomes the rpc's `Errors` (driving `isError`). Typed errors are raised
|
|
108
|
+
by returning an `error.typed(name, status, schema?)` constructor — there is no `errors:`
|
|
109
|
+
opt. Four overloads by argument source (most-specific first):
|
|
97
110
|
|
|
98
|
-
- `
|
|
99
|
-
|
|
100
|
-
`InferOutput<
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
execution on every surface (SSR / MCP / CLI / network) — a 504 once
|
|
112
|
-
exceeded; on the network path it also aborts request().signal so a
|
|
113
|
-
handler's `fetch(ext, { signal: request().signal })` is cancelled, not
|
|
114
|
-
just abandoned.
|
|
115
|
-
- `Rpc(fn, { clients })` — schemaless but with explicit client
|
|
116
|
-
targeting (e.g. server-internal RPC with `clients: { browser: false }`).
|
|
117
|
-
- `Rpc(fn)` — bare handler, a single `F extends RpcFn` generic. Everything
|
|
118
|
-
is read off the handler: `Args` from its parameter (annotate it —
|
|
119
|
-
`POST((a: { id: string }) => …)` — or leave it nullary for `undefined`),
|
|
120
|
-
`Return` from the `TypedResponse<T>` brand on
|
|
121
|
-
`json`/`error`/`redirect`/`jsonl`/`sse`, `Errors` from any
|
|
122
|
-
`error.typed(...)` branches. You never pass `<Args, Return>` generics; a
|
|
123
|
-
stray one is a loud constraint error, not a silent `unknown` body.
|
|
111
|
+
- `GET(fn, { schemas: { input, files, output? }, cache?, … })` — multipart upload.
|
|
112
|
+
The handler receives the text fields (`InferOutput<input>`) intersected with the
|
|
113
|
+
validated File parts (`InferOutput<files>`); the call site sends a FormData. `files`
|
|
114
|
+
stays off the JSON-Schema projection (a File has no honest conversion) — only `input`
|
|
115
|
+
feeds MCP/CLI/OpenAPI. `Args` (the RemoteFunction's call type) is `InferInput<input>`.
|
|
116
|
+
- `GET(fn, { schemas: { input, output? }, cache?, … })` — `Args` = `InferInput<input>`,
|
|
117
|
+
the handler receives `InferOutput<input>`. `output` feeds the OpenAPI 200 / MCP tool
|
|
118
|
+
outputSchema and never drives arg inference.
|
|
119
|
+
- `GET(fn, opts)` — schemaless-with-opts (includes `schemas: { output }`-only): args
|
|
120
|
+
read off the handler `F`. `cache`/`clients`/`timeout`/… live here.
|
|
121
|
+
- `GET(fn)` — bare handler; everything reads off `F`: `Args` from its parameter, `Return`
|
|
122
|
+
from the `TypedResponse<T>` brand, `Errors` from any `error.typed(...)` branches. You
|
|
123
|
+
never pass `<Args, Return>` generics; a stray one is a loud constraint error.
|
|
124
124
|
*/
|
|
125
|
-
type
|
|
126
|
-
/*
|
|
127
|
-
`Rpc(fn, { inputSchema, filesSchema, … })` — multipart upload. The
|
|
128
|
-
handler receives the text fields (`InferOutput<InputSchema>`) intersected
|
|
129
|
-
with the validated File parts (`InferOutput<FilesSchema>`); both are merged
|
|
130
|
-
into one args bag. The call site sends a FormData (RemoteFunction's call
|
|
131
|
-
accepts it), since a File can't ride a JSON body. filesSchema stays off the
|
|
132
|
-
JSON-Schema projection — a File has no honest conversion (see
|
|
133
|
-
jsonSchemaForSchema) — so only inputSchema feeds MCP/CLI/OpenAPI.
|
|
134
|
-
*/
|
|
125
|
+
export type RpcHelper = {
|
|
135
126
|
<
|
|
136
127
|
R extends Response,
|
|
137
128
|
InputSchema extends StandardSchemaV1 = StandardSchemaV1,
|
|
@@ -141,30 +132,28 @@ type RpcHelperOf<Opts> = {
|
|
|
141
132
|
args: StandardSchemaV1.InferOutput<InputSchema> &
|
|
142
133
|
StandardSchemaV1.InferOutput<FilesSchema>,
|
|
143
134
|
) => R | Promise<R>,
|
|
144
|
-
opts:
|
|
145
|
-
|
|
146
|
-
filesSchema: FilesSchema
|
|
135
|
+
opts: RpcReadOpts<StandardSchemaV1.InferInput<InputSchema>> & {
|
|
136
|
+
schemas: { input: InputSchema; files: FilesSchema; output?: StandardSchemaV1 }
|
|
147
137
|
},
|
|
148
138
|
): RemoteFunction<StandardSchemaV1.InferInput<InputSchema>, SuccessBody<R>, InferredErrors<R>>
|
|
149
139
|
<R extends Response, InputSchema extends StandardSchemaV1 = StandardSchemaV1>(
|
|
150
140
|
fn: (args: StandardSchemaV1.InferOutput<InputSchema>) => R | Promise<R>,
|
|
151
|
-
opts:
|
|
141
|
+
opts: RpcReadOpts<StandardSchemaV1.InferInput<InputSchema>> & {
|
|
142
|
+
schemas: { input: InputSchema; output?: StandardSchemaV1 }
|
|
143
|
+
},
|
|
152
144
|
): RemoteFunction<StandardSchemaV1.InferInput<InputSchema>, SuccessBody<R>, InferredErrors<R>>
|
|
153
|
-
<F extends RpcFn>(fn: F, opts:
|
|
145
|
+
<F extends RpcFn>(fn: F, opts: RpcReadOpts<RpcArgs<F>>): RpcOf<F>
|
|
154
146
|
<F extends RpcFn>(fn: F): RpcOf<F>
|
|
155
147
|
}
|
|
156
148
|
|
|
157
|
-
/* The read helpers (GET/HEAD): no `outbox` — a read has nothing to durably deliver. */
|
|
158
|
-
export type RpcHelper = RpcHelperOf<RpcBaseOpts>
|
|
159
|
-
|
|
160
149
|
/*
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
150
|
+
The mutating helpers (POST/PUT/PATCH/DELETE). The base opts is the shared `RpcSharedOpts`
|
|
151
|
+
(no `cache`/`stream`) — coalesce-only is the method default and a write has no replayable
|
|
152
|
+
value to retain or stream — which is what makes `cache`/`stream` a compile error here while
|
|
153
|
+
they stay legal on the read helpers (`RpcReadOpts`) — the kind-scoping. Overloads mirror the read helpers by argument source
|
|
154
|
+
(multipart-upload, schema'd, schemaless-with-opts, bare).
|
|
166
155
|
*/
|
|
167
|
-
type
|
|
156
|
+
export type MutatingRpcHelper = {
|
|
168
157
|
<
|
|
169
158
|
R extends Response,
|
|
170
159
|
InputSchema extends StandardSchemaV1 = StandardSchemaV1,
|
|
@@ -174,35 +163,16 @@ type DurableMutatingRpcHelper = {
|
|
|
174
163
|
args: StandardSchemaV1.InferOutput<InputSchema> &
|
|
175
164
|
StandardSchemaV1.InferOutput<FilesSchema>,
|
|
176
165
|
) => R | Promise<R>,
|
|
177
|
-
opts:
|
|
178
|
-
|
|
179
|
-
filesSchema: FilesSchema
|
|
180
|
-
outbox: true
|
|
166
|
+
opts: RpcSharedOpts & {
|
|
167
|
+
schemas: { input: InputSchema; files: FilesSchema; output?: StandardSchemaV1 }
|
|
181
168
|
},
|
|
182
|
-
): RemoteFunction<
|
|
183
|
-
StandardSchemaV1.InferInput<InputSchema>,
|
|
184
|
-
SuccessBody<R>,
|
|
185
|
-
InferredErrors<R>,
|
|
186
|
-
true
|
|
187
|
-
>
|
|
169
|
+
): RemoteFunction<StandardSchemaV1.InferInput<InputSchema>, SuccessBody<R>, InferredErrors<R>>
|
|
188
170
|
<R extends Response, InputSchema extends StandardSchemaV1 = StandardSchemaV1>(
|
|
189
171
|
fn: (args: StandardSchemaV1.InferOutput<InputSchema>) => R | Promise<R>,
|
|
190
|
-
opts:
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
>
|
|
197
|
-
<F extends RpcFn>(fn: F, opts: MutatingRpcOpts & { outbox: true }): RpcOf<F, true>
|
|
172
|
+
opts: RpcSharedOpts & {
|
|
173
|
+
schemas: { input: InputSchema; output?: StandardSchemaV1 }
|
|
174
|
+
},
|
|
175
|
+
): RemoteFunction<StandardSchemaV1.InferInput<InputSchema>, SuccessBody<R>, InferredErrors<R>>
|
|
176
|
+
<F extends RpcFn>(fn: F, opts: RpcSharedOpts): RpcOf<F>
|
|
177
|
+
<F extends RpcFn>(fn: F): RpcOf<F>
|
|
198
178
|
}
|
|
199
|
-
|
|
200
|
-
/*
|
|
201
|
-
The mutating helpers (POST/PUT/PATCH/DELETE). A durable (`outbox`) call is a normal
|
|
202
|
-
RemoteFunction — it throws exactly like a non-durable one and only parks the request as a
|
|
203
|
-
side-effect on an unreachable server — so there is no separate return shape; `outbox` rides
|
|
204
|
-
MutatingRpcOpts and `rpc.outbox` exposes the queue. The distinct opts base is what makes
|
|
205
|
-
`outbox` legal here and a compile error on the read helpers; the durable overloads then set
|
|
206
|
-
the return type's `Durable` bit so `rpc.outbox` is present without an optional chain.
|
|
207
|
-
*/
|
|
208
|
-
export type MutatingRpcHelper = DurableMutatingRpcHelper & RpcHelperOf<MutatingRpcOpts>
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ErrorJsonSchemas } from '../../../shared/types/ErrorJsonSchemas.ts'
|
|
2
2
|
import type { RemoteFunction } from '../../../shared/types/RemoteFunction.ts'
|
|
3
3
|
import type { StandardSchemaV1 } from '../../../shared/types/StandardSchemaV1.ts'
|
|
4
4
|
|
|
5
5
|
/*
|
|
6
6
|
Per-rpc registry record on the server side. MCP and CLI enumerate this
|
|
7
|
-
to discover
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
to discover what shapes an rpc expects/returns. The schemas stay off the
|
|
8
|
+
public RemoteFunction shape so the browser-side proxy doesn't need to carry
|
|
9
|
+
server-only state; the resolved `clients` and `crossOrigin` ride on
|
|
10
|
+
`entry.remote` (ADR-0020 sweep finding #4 — no duplicate fields), so readers
|
|
11
|
+
reach them via `entry.remote.clients` / `entry.remote.crossOrigin`.
|
|
11
12
|
|
|
12
13
|
`inputSchema` validates the argument bag and feeds the MCP tool
|
|
13
14
|
`inputSchema` / OpenAPI parameters; `outputSchema` describes the success
|
|
@@ -23,13 +24,27 @@ multipart body advertises the file parts generically as binary.
|
|
|
23
24
|
export type RpcRegistryEntry = {
|
|
24
25
|
remote: RemoteFunction<unknown, unknown>
|
|
25
26
|
inputSchema: StandardSchemaV1 | undefined
|
|
27
|
+
/* The handler's input args projected to JSON Schema at build time (ADR-0030 input side) — the
|
|
28
|
+
input surface's fallback when no `inputSchema` VALIDATOR is declared, mirroring how
|
|
29
|
+
`outputJsonSchema` backs the output surface. Already JSON Schema (not a validator), so surfaces
|
|
30
|
+
use it verbatim; `inputSchema`, when present, overrides it. It also makes the endpoint
|
|
31
|
+
advertisable (MCP/CLI) — the same role a declared `inputSchema` plays — but purely as a SHAPE
|
|
32
|
+
description: it is never run as runtime validation, so it can't produce a 422. */
|
|
33
|
+
inputJsonSchema: Record<string, unknown> | undefined
|
|
26
34
|
outputSchema: StandardSchemaV1 | undefined
|
|
35
|
+
/* The handler's return type projected to JSON Schema at build time (ADR-0030 D2) — the output
|
|
36
|
+
surface's fallback when no `outputSchema` VALIDATOR is declared. Already JSON Schema (not a
|
|
37
|
+
validator), so surfaces use it verbatim; `outputSchema`, when present, overrides it. */
|
|
38
|
+
outputJsonSchema: Record<string, unknown> | undefined
|
|
39
|
+
/* The handler's typed-error branches projected to a status-keyed JSON-Schema map at build time
|
|
40
|
+
(ADR-0030) — each `error.typed(...)` return branch's status + `data` payload. Feeds the OpenAPI
|
|
41
|
+
`responses[status]` entries alongside the 200; undefined when the handler declares no typed
|
|
42
|
+
errors or the build couldn't resolve them, so the surface omits the error responses. */
|
|
43
|
+
errorJsonSchemas: ErrorJsonSchemas | undefined
|
|
27
44
|
filesSchema: StandardSchemaV1 | undefined
|
|
28
|
-
clients: ClientFlags
|
|
29
45
|
/* The rpc's declared opts, recorded so introspection (inspector) can report
|
|
30
|
-
the deadline/body-cap
|
|
31
|
-
|
|
46
|
+
the deadline/body-cap a handler runs under. Undefined = the framework default
|
|
47
|
+
(no deadline, Bun's server-wide body ceiling). */
|
|
32
48
|
timeout: number | undefined
|
|
33
49
|
maxBodySize: number | undefined
|
|
34
|
-
crossOrigin: boolean | undefined
|
|
35
50
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { fieldErrorsFromIssues } from '../../shared/fieldErrorsFromIssues.ts'
|
|
1
2
|
import type { StandardSchemaV1 } from '../../shared/types/StandardSchemaV1.ts'
|
|
2
3
|
import type { ValidationErrorData } from '../../shared/types/ValidationErrorData.ts'
|
|
3
4
|
import { typedErrorResponse } from '../runtime/typedErrorResponse.ts'
|
|
4
|
-
import { fieldErrorsFromIssues } from './fieldErrorsFromIssues.ts'
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
The framework-reserved `validation` typed error a 422 carries: the raw Standard
|
|
@@ -21,11 +21,9 @@ slept still reloads it. The initial connect runs even when the page loads
|
|
|
21
21
|
hidden (the baseline must be the serving worker's stamp, captured before a swap
|
|
22
22
|
can replace it) and releases itself once that first event lands.
|
|
23
23
|
*/
|
|
24
|
-
import { DEV_HOT_PREFIX } from '../../shared/DEV_HOT_PREFIX.ts'
|
|
25
24
|
import { DEV_RELOAD_PATH } from '../../shared/DEV_RELOAD_PATH.ts'
|
|
26
25
|
|
|
27
26
|
export const DEV_RELOAD_CLIENT_SCRIPT = `<script>
|
|
28
|
-
window.__abideDev = true;
|
|
29
27
|
;(() => {
|
|
30
28
|
let stamp
|
|
31
29
|
let source
|
|
@@ -48,18 +46,6 @@ window.__abideDev = true;
|
|
|
48
46
|
}
|
|
49
47
|
}
|
|
50
48
|
}
|
|
51
|
-
function swapComponents(next, prev) {
|
|
52
|
-
const components = next.components || {}
|
|
53
|
-
const before = prev.components || {}
|
|
54
|
-
for (const id in components) {
|
|
55
|
-
if (components[id] !== before[id]) {
|
|
56
|
-
// The hot module sources its runtime from window.__abide and self-invokes
|
|
57
|
-
// hotReplace; a load/compile failure or a component with no live instance
|
|
58
|
-
// falls back to a reload.
|
|
59
|
-
import('${DEV_HOT_PREFIX}' + id + '?v=' + components[id]).catch(() => location.reload())
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
49
|
function connect() {
|
|
64
50
|
if (source) {
|
|
65
51
|
return
|
|
@@ -84,7 +70,6 @@ window.__abideDev = true;
|
|
|
84
70
|
if (next.cssHref && next.cssHref !== stamp.cssHref) {
|
|
85
71
|
swapCss(next.cssHref)
|
|
86
72
|
}
|
|
87
|
-
swapComponents(next, stamp)
|
|
88
73
|
stamp = next
|
|
89
74
|
}
|
|
90
75
|
source.onerror = () => {
|
|
@@ -18,20 +18,20 @@ function preview(value: unknown): string | undefined {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
/* The entry's armed
|
|
22
|
-
|
|
21
|
+
/* The entry's armed refetch (stale-while-revalidate) policy as a label, if it declared
|
|
22
|
+
one. A windowless policy refetches immediately, so it labels as plain `refetch`. */
|
|
23
23
|
function policyLabel(entry: CacheEntry): string | undefined {
|
|
24
24
|
const policy = entry.invalidation
|
|
25
25
|
if (!policy) {
|
|
26
26
|
return undefined
|
|
27
27
|
}
|
|
28
28
|
if (policy.debounce !== undefined) {
|
|
29
|
-
return `
|
|
29
|
+
return `refetch debounce ${policy.debounce}ms`
|
|
30
30
|
}
|
|
31
31
|
if (policy.throttle !== undefined) {
|
|
32
|
-
return `
|
|
32
|
+
return `refetch throttle ${policy.throttle}ms`
|
|
33
33
|
}
|
|
34
|
-
return '
|
|
34
|
+
return 'refetch'
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function projectEntry(entry: CacheEntry, now: number): InspectorCacheEntry {
|
|
@@ -48,10 +48,11 @@ function projectEntry(entry: CacheEntry, now: number): InspectorCacheEntry {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/*
|
|
51
|
-
Snapshots the process-level cache store (the persistent one
|
|
52
|
-
true, ttl
|
|
53
|
-
|
|
54
|
-
excluded — they're ephemeral and
|
|
51
|
+
Snapshots the process-level cache store (the persistent one an endpoint declaring
|
|
52
|
+
`cache: { shared: true, ttl }` — or a producer `cache(fn, args, { shared: true, ttl })`
|
|
53
|
+
— writes to) for the inspector. Read at call time, so it reflects the store as it
|
|
54
|
+
stands; request-scoped stores are deliberately excluded — they're ephemeral and
|
|
55
|
+
already visible as per-request cache tallies.
|
|
55
56
|
*/
|
|
56
57
|
export function buildCacheSnapshot(): InspectorCacheSnapshot {
|
|
57
58
|
const now = Date.now()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { jsonSchemaForSchema } from '../../shared/jsonSchemaForSchema.ts'
|
|
2
1
|
import { promptRegistry } from '../prompts/promptRegistry.ts'
|
|
2
|
+
import { resolveInputJsonSchema, resolveOutputJsonSchema } from '../rpc/resolveRpcJsonSchema.ts'
|
|
3
3
|
import { rpcRegistry } from '../rpc/rpcRegistry.ts'
|
|
4
4
|
import { socketOperations } from '../sockets/socketOperations.ts'
|
|
5
5
|
import { socketRegistry } from '../sockets/socketRegistry.ts'
|
|
@@ -18,12 +18,14 @@ export function buildInspectorSurface(): InspectorSurface {
|
|
|
18
18
|
url: entry.remote.url,
|
|
19
19
|
method: entry.remote.method,
|
|
20
20
|
clients: { ...entry.remote.clients },
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// The declared inputSchema VALIDATOR wins; else the build-projected input-type schema
|
|
22
|
+
// (ADR-0030 input side); with neither the rpc advertises no input shape, as before.
|
|
23
|
+
inputSchema: resolveInputJsonSchema(entry),
|
|
24
|
+
outputSchema: resolveOutputJsonSchema(entry),
|
|
23
25
|
files: entry.filesSchema !== undefined,
|
|
24
26
|
timeout: entry.timeout,
|
|
25
27
|
maxBodySize: entry.maxBodySize,
|
|
26
|
-
crossOrigin: entry.crossOrigin,
|
|
28
|
+
crossOrigin: entry.remote.crossOrigin,
|
|
27
29
|
}))
|
|
28
30
|
const sockets = Array.from(socketRegistry.values()).map((entry) => ({
|
|
29
31
|
name: entry.socket.name,
|