@toa.io/extensions.exposition 1.0.0-alpha.283 → 1.0.0-alpha.285
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/components/exposition.octets/types/index.d.ts +1 -1
- package/components/identity.bans/operations/transit.js +1 -1
- package/components/identity.bans/tsconfig.json +1 -1
- package/components/identity.bans/tsconfig.tsbuildinfo +1 -1
- package/components/identity.bans/types/index.d.ts +1 -1
- package/components/identity.basic/operations/add.js +1 -1
- package/components/identity.basic/operations/authenticate.js +1 -1
- package/components/identity.basic/operations/check.js +1 -1
- package/components/identity.basic/operations/delete.js +1 -1
- package/components/identity.basic/operations/incept.js +18 -2
- package/components/identity.basic/operations/info.js +1 -1
- package/components/identity.basic/operations/lib/credentials.js +1 -1
- package/components/identity.basic/operations/transit.js +1 -1
- package/components/identity.basic/source/incept.ts +29 -1
- package/components/identity.basic/tsconfig.json +1 -1
- package/components/identity.basic/tsconfig.tsbuildinfo +1 -1
- package/components/identity.basic/types/index.d.ts +3 -2
- package/components/identity.clients/operations/describe.js +1 -1
- package/components/identity.clients/operations/lib/Context.js +1 -1
- package/components/identity.clients/operations/lib/Entity.js +1 -1
- package/components/identity.clients/operations/lib/canonical.js +1 -1
- package/components/identity.clients/operations/lib/cimd.js +1 -1
- package/components/identity.clients/operations/lib/errors.js +1 -1
- package/components/identity.clients/operations/lib/index.js +1 -1
- package/components/identity.clients/operations/lib/redirect.js +1 -1
- package/components/identity.clients/operations/register.js +1 -1
- package/components/identity.clients/tsconfig.json +1 -1
- package/components/identity.clients/tsconfig.tsbuildinfo +1 -1
- package/components/identity.clients/types/index.d.ts +1 -1
- package/components/identity.credentials/operations/list.js +1 -1
- package/components/identity.credentials/tsconfig.json +4 -2
- package/components/identity.credentials/tsconfig.tsbuildinfo +1 -1
- package/components/identity.credentials/types/index.d.ts +1 -1
- package/components/identity.federation/operations/authenticate.js +7 -3
- package/components/identity.federation/operations/create.js +1 -1
- package/components/identity.federation/operations/decode.js +1 -1
- package/components/identity.federation/operations/delete.js +1 -1
- package/components/identity.federation/operations/incept.js +6 -2
- package/components/identity.federation/operations/lib/Configuration.js +1 -1
- package/components/identity.federation/operations/lib/Ctx.js +1 -1
- package/components/identity.federation/operations/lib/Payload.js +1 -1
- package/components/identity.federation/operations/lib/decode.js +1 -1
- package/components/identity.federation/operations/lib/discovery.js +1 -1
- package/components/identity.federation/operations/lib/errors.js +1 -1
- package/components/identity.federation/operations/lib/exchange.js +1 -1
- package/components/identity.federation/operations/lib/index.js +2 -1
- package/components/identity.federation/operations/lib/jose.js +1 -1
- package/components/identity.federation/operations/lib/principal.js +14 -0
- package/components/identity.federation/operations/lib/resolve.js +1 -1
- package/components/identity.federation/operations/list.js +1 -1
- package/components/identity.federation/operations/types/Scheme.js +1 -1
- package/components/identity.federation/operations/types/configuration.js +1 -1
- package/components/identity.federation/operations/types/context.js +1 -1
- package/components/identity.federation/operations/types/entity.js +1 -1
- package/components/identity.federation/operations/types/index.js +1 -1
- package/components/identity.federation/source/authenticate.ts +8 -2
- package/components/identity.federation/source/incept.ts +7 -1
- package/components/identity.federation/source/lib/index.ts +1 -0
- package/components/identity.federation/source/lib/principal.ts +17 -0
- package/components/identity.federation/source/types/context.ts +3 -0
- package/components/identity.federation/tsconfig.json +4 -2
- package/components/identity.federation/tsconfig.tsbuildinfo +1 -1
- package/components/identity.federation/types/index.d.ts +1 -1
- package/components/identity.grants/operations/authorize.js +1 -1
- package/components/identity.grants/operations/exchange.js +1 -1
- package/components/identity.grants/operations/lib/code.js +1 -1
- package/components/identity.grants/operations/lib/identify.js +1 -1
- package/components/identity.grants/operations/lib/index.js +1 -1
- package/components/identity.grants/operations/list.js +1 -1
- package/components/identity.grants/operations/revoke.js +1 -1
- package/components/identity.grants/tsconfig.json +1 -1
- package/components/identity.grants/tsconfig.tsbuildinfo +1 -1
- package/components/identity.grants/types/index.d.ts +1 -1
- package/components/identity.keys/operations/create.js +1 -1
- package/components/identity.keys/operations/disable.js +1 -1
- package/components/identity.keys/operations/revoke.js +1 -1
- package/components/identity.keys/tsconfig.json +1 -1
- package/components/identity.keys/tsconfig.tsbuildinfo +1 -1
- package/components/identity.keys/types/index.d.ts +1 -1
- package/components/identity.otp/operations/authenticate.js +1 -1
- package/components/identity.otp/operations/issue.js +1 -1
- package/components/identity.otp/operations/lib/Context.js +1 -1
- package/components/identity.otp/operations/lib/Entity.js +1 -1
- package/components/identity.otp/operations/lib/index.js +1 -1
- package/components/identity.otp/tsconfig.json +1 -1
- package/components/identity.otp/tsconfig.tsbuildinfo +1 -1
- package/components/identity.otp/types/index.d.ts +1 -1
- package/components/identity.passkeys/operations/authenticate.js +1 -1
- package/components/identity.passkeys/operations/challenge.js +1 -1
- package/components/identity.passkeys/operations/create.js +1 -1
- package/components/identity.passkeys/operations/delete.js +1 -1
- package/components/identity.passkeys/operations/lib/const.js +1 -1
- package/components/identity.passkeys/operations/list.js +1 -1
- package/components/identity.passkeys/operations/types/Configuration.js +1 -1
- package/components/identity.passkeys/operations/types/Context.js +1 -1
- package/components/identity.passkeys/operations/types/Passkey.js +1 -1
- package/components/identity.passkeys/operations/types/index.js +1 -1
- package/components/identity.passkeys/operations/use.js +1 -1
- package/components/identity.passkeys/tsconfig.json +1 -1
- package/components/identity.passkeys/tsconfig.tsbuildinfo +1 -1
- package/components/identity.passkeys/types/index.d.ts +1 -1
- package/components/identity.roles/operations/grant.js +1 -1
- package/components/identity.roles/operations/lib/Entity.js +1 -1
- package/components/identity.roles/operations/list.js +1 -1
- package/components/identity.roles/operations/principal.js +29 -5
- package/components/identity.roles/source/principal.ts +33 -5
- package/components/identity.roles/tsconfig.json +1 -1
- package/components/identity.roles/tsconfig.tsbuildinfo +1 -1
- package/components/identity.roles/types/index.d.ts +1 -1
- package/components/identity.tokens/operations/authenticate.js +1 -1
- package/components/identity.tokens/operations/decrypt.js +1 -1
- package/components/identity.tokens/operations/encrypt.js +1 -1
- package/components/identity.tokens/operations/issue.js +1 -1
- package/components/identity.tokens/operations/lib/form.js +1 -1
- package/components/identity.tokens/operations/lib/index.js +1 -1
- package/components/identity.tokens/operations/lib/jose.js +1 -1
- package/components/identity.tokens/operations/lib/key.js +1 -1
- package/components/identity.tokens/operations/lib/pad.js +1 -1
- package/components/identity.tokens/operations/revoke.js +1 -1
- package/components/identity.tokens/tsconfig.json +1 -1
- package/components/identity.tokens/tsconfig.tsbuildinfo +1 -1
- package/components/identity.tokens/types/index.d.ts +1 -1
- package/documentation/access.md +13 -0
- package/documentation/components.md +3 -0
- package/documentation/introspection.md +13 -5
- package/documentation/io.md +6 -0
- package/documentation/map.md +8 -0
- package/documentation/mcp.md +186 -0
- package/documentation/oauth.md +8 -7
- package/documentation/rpc.md +144 -0
- package/documentation/tree.md +3 -0
- package/features/identity.basic.feature +44 -0
- package/features/identity.federation.feature +2 -5
- package/features/introspection.feature +333 -0
- package/features/mcp.feature +691 -0
- package/features/oauth.discovery.feature +10 -11
- package/features/oauth.grants.feature +22 -9
- package/features/octets.cloudinary.feature +1 -0
- package/features/rpc.feature +429 -0
- package/features/steps/Cloudinary.ts +13 -0
- package/features/steps/Components.ts +0 -4
- package/features/steps/Gateway.ts +19 -2
- package/features/steps/Parameters.ts +18 -7
- package/features/steps/Realtime.ts +3 -0
- package/features/steps/components/echo/manifest.toa.yaml +1 -0
- package/features/steps/components/pots/manifest.toa.yaml +2 -0
- package/package.json +3 -3
- package/readme.md +3 -0
- package/schemas/annotation.cos.yaml +33 -0
- package/schemas/call.cos.yaml +18 -0
- package/source/Annotation.ts +31 -0
- package/source/Directive.test.ts +15 -15
- package/source/Directive.ts +77 -9
- package/source/Endpoint.test.ts +67 -0
- package/source/Endpoint.ts +31 -11
- package/source/Factory.ts +5 -1
- package/source/Gateway.ts +73 -11
- package/source/HTTP/Context.ts +7 -0
- package/source/HTTP/Server.ts +7 -1
- package/source/HTTP/exceptions.ts +2 -2
- package/source/HTTP/messages.ts +10 -1
- package/source/Introspection.ts +105 -0
- package/source/MCP/Server.ts +275 -0
- package/source/MCP/discover.ts +52 -0
- package/source/MCP/errors.ts +81 -0
- package/source/MCP/index.ts +1 -0
- package/source/MCP/schema.test.ts +85 -0
- package/source/MCP/schema.ts +87 -0
- package/source/MCP/tools.ts +157 -0
- package/source/MCP/types.ts +84 -0
- package/source/Query.ts +48 -8
- package/source/RPC/Context.ts +78 -0
- package/source/RPC/Dispatcher.ts +130 -0
- package/source/RPC/errors.test.ts +52 -0
- package/source/RPC/errors.ts +83 -0
- package/source/RPC/index.ts +1 -0
- package/source/RPC/names.test.ts +122 -0
- package/source/RPC/names.ts +183 -0
- package/source/RPC/types.ts +34 -0
- package/source/RTD/Directives.ts +52 -2
- package/source/RTD/Endpoint.ts +2 -1
- package/source/RTD/Method.ts +14 -11
- package/source/RTD/Node.ts +38 -7
- package/source/RTD/Route.ts +30 -3
- package/source/RTD/Tree.ts +37 -1
- package/source/RTD/expiration.test.ts +1 -1
- package/source/RTD/walk.test.ts +110 -0
- package/source/const.ts +15 -0
- package/source/deployment.ts +8 -1
- package/source/directives/auth/Anonymous.test.ts +38 -0
- package/source/directives/auth/Anonymous.ts +12 -0
- package/source/directives/auth/Anyone.ts +4 -0
- package/source/directives/auth/Authorization.ts +62 -3
- package/source/directives/auth/Delegate.test.ts +36 -0
- package/source/directives/auth/Delegate.ts +14 -0
- package/source/directives/auth/Echo.ts +5 -0
- package/source/directives/auth/Incept.ts +2 -1
- package/source/directives/auth/Role.ts +13 -0
- package/source/directives/auth/Rule.ts +29 -0
- package/source/directives/auth/Scheme.ts +5 -0
- package/source/directives/auth/types.ts +21 -0
- package/source/directives/cache/Cache.ts +1 -1
- package/source/directives/dev/Development.ts +1 -1
- package/source/directives/flow/Flow.ts +1 -1
- package/source/directives/index.ts +3 -1
- package/source/directives/io/Directive.ts +1 -1
- package/source/directives/io/IO.ts +32 -3
- package/source/directives/io/Input.ts +3 -2
- package/source/directives/io/Output.ts +6 -3
- package/source/directives/io/Status.test.ts +2 -2
- package/source/directives/io/Status.ts +1 -1
- package/source/directives/io/Throttle.ts +1 -1
- package/source/directives/io/lib/throttle/Quotas.ts +2 -2
- package/source/directives/map/Headers.ts +11 -0
- package/source/directives/map/Map.ts +10 -1
- package/source/directives/map/Mapping.ts +23 -0
- package/source/directives/map/Segments.ts +12 -0
- package/source/directives/mcp/MCP.ts +40 -0
- package/source/directives/mcp/Tool.test.ts +90 -0
- package/source/directives/mcp/Tool.ts +47 -0
- package/source/directives/mcp/index.ts +6 -0
- package/source/directives/oauth/Discovery.ts +10 -16
- package/source/directives/octets/Octets.ts +1 -1
- package/source/directives/require/Directive.ts +1 -1
- package/source/directives/require/Headers.ts +1 -1
- package/source/directives/require/Require.ts +2 -2
- package/source/schemas.ts +2 -0
- package/transpiled/Annotation.d.ts +24 -0
- package/transpiled/Directive.d.ts +18 -1
- package/transpiled/Directive.js +50 -6
- package/transpiled/Directive.js.map +1 -1
- package/transpiled/Endpoint.d.ts +9 -0
- package/transpiled/Endpoint.js +27 -11
- package/transpiled/Endpoint.js.map +1 -1
- package/transpiled/Factory.js +5 -1
- package/transpiled/Factory.js.map +1 -1
- package/transpiled/Gateway.d.ts +19 -2
- package/transpiled/Gateway.js +51 -9
- package/transpiled/Gateway.js.map +1 -1
- package/transpiled/HTTP/Context.d.ts +6 -0
- package/transpiled/HTTP/Context.js +6 -0
- package/transpiled/HTTP/Context.js.map +1 -1
- package/transpiled/HTTP/Server.d.ts +5 -1
- package/transpiled/HTTP/exceptions.d.ts +1 -1
- package/transpiled/HTTP/exceptions.js +2 -2
- package/transpiled/HTTP/exceptions.js.map +1 -1
- package/transpiled/HTTP/messages.d.ts +6 -0
- package/transpiled/HTTP/messages.js +9 -1
- package/transpiled/HTTP/messages.js.map +1 -1
- package/transpiled/Introspection.d.ts +42 -0
- package/transpiled/Introspection.js +50 -1
- package/transpiled/Introspection.js.map +1 -1
- package/transpiled/MCP/Server.d.ts +41 -0
- package/transpiled/MCP/Server.js +180 -0
- package/transpiled/MCP/Server.js.map +1 -0
- package/transpiled/MCP/discover.d.ts +13 -0
- package/transpiled/MCP/discover.js +29 -0
- package/transpiled/MCP/discover.js.map +1 -0
- package/transpiled/MCP/errors.d.ts +24 -0
- package/transpiled/MCP/errors.js +67 -0
- package/transpiled/MCP/errors.js.map +1 -0
- package/transpiled/MCP/index.d.ts +1 -0
- package/transpiled/MCP/index.js +2 -0
- package/transpiled/MCP/index.js.map +1 -0
- package/transpiled/MCP/schema.d.ts +18 -0
- package/transpiled/MCP/schema.js +64 -0
- package/transpiled/MCP/schema.js.map +1 -0
- package/transpiled/MCP/tools.d.ts +31 -0
- package/transpiled/MCP/tools.js +122 -0
- package/transpiled/MCP/tools.js.map +1 -0
- package/transpiled/MCP/types.d.ts +66 -0
- package/transpiled/MCP/types.js +13 -0
- package/transpiled/MCP/types.js.map +1 -0
- package/transpiled/Query.d.ts +7 -0
- package/transpiled/Query.js +38 -7
- package/transpiled/Query.js.map +1 -1
- package/transpiled/RPC/Context.d.ts +11 -0
- package/transpiled/RPC/Context.js +63 -0
- package/transpiled/RPC/Context.js.map +1 -0
- package/transpiled/RPC/Dispatcher.d.ts +19 -0
- package/transpiled/RPC/Dispatcher.js +100 -0
- package/transpiled/RPC/Dispatcher.js.map +1 -0
- package/transpiled/RPC/errors.d.ts +18 -0
- package/transpiled/RPC/errors.js +67 -0
- package/transpiled/RPC/errors.js.map +1 -0
- package/transpiled/RPC/index.d.ts +1 -0
- package/transpiled/RPC/index.js +2 -0
- package/transpiled/RPC/index.js.map +1 -0
- package/transpiled/RPC/names.d.ts +31 -0
- package/transpiled/RPC/names.js +121 -0
- package/transpiled/RPC/names.js.map +1 -0
- package/transpiled/RPC/types.d.ts +27 -0
- package/transpiled/RPC/types.js +8 -0
- package/transpiled/RPC/types.js.map +1 -0
- package/transpiled/RTD/Directives.d.ts +41 -2
- package/transpiled/RTD/Endpoint.d.ts +2 -1
- package/transpiled/RTD/Method.d.ts +8 -3
- package/transpiled/RTD/Method.js +12 -10
- package/transpiled/RTD/Method.js.map +1 -1
- package/transpiled/RTD/Node.d.ts +20 -2
- package/transpiled/RTD/Node.js +22 -4
- package/transpiled/RTD/Node.js.map +1 -1
- package/transpiled/RTD/Route.d.ts +2 -1
- package/transpiled/RTD/Route.js +27 -2
- package/transpiled/RTD/Route.js.map +1 -1
- package/transpiled/RTD/Tree.d.ts +3 -1
- package/transpiled/RTD/Tree.js +26 -0
- package/transpiled/RTD/Tree.js.map +1 -1
- package/transpiled/const.d.ts +12 -0
- package/transpiled/const.js +12 -0
- package/transpiled/const.js.map +1 -1
- package/transpiled/deployment.js +4 -0
- package/transpiled/deployment.js.map +1 -1
- package/transpiled/directives/auth/Anonymous.d.ts +6 -0
- package/transpiled/directives/auth/Anonymous.js +10 -0
- package/transpiled/directives/auth/Anonymous.js.map +1 -1
- package/transpiled/directives/auth/Anyone.d.ts +1 -0
- package/transpiled/directives/auth/Anyone.js +3 -0
- package/transpiled/directives/auth/Anyone.js.map +1 -1
- package/transpiled/directives/auth/Authorization.d.ts +27 -1
- package/transpiled/directives/auth/Authorization.js +49 -1
- package/transpiled/directives/auth/Authorization.js.map +1 -1
- package/transpiled/directives/auth/Delegate.d.ts +5 -0
- package/transpiled/directives/auth/Delegate.js +10 -0
- package/transpiled/directives/auth/Delegate.js.map +1 -1
- package/transpiled/directives/auth/Echo.d.ts +2 -0
- package/transpiled/directives/auth/Echo.js +4 -0
- package/transpiled/directives/auth/Echo.js.map +1 -1
- package/transpiled/directives/auth/Incept.js +2 -1
- package/transpiled/directives/auth/Incept.js.map +1 -1
- package/transpiled/directives/auth/Role.d.ts +2 -0
- package/transpiled/directives/auth/Role.js +9 -0
- package/transpiled/directives/auth/Role.js.map +1 -1
- package/transpiled/directives/auth/Rule.d.ts +5 -0
- package/transpiled/directives/auth/Rule.js +20 -0
- package/transpiled/directives/auth/Rule.js.map +1 -1
- package/transpiled/directives/auth/Scheme.d.ts +2 -0
- package/transpiled/directives/auth/Scheme.js +4 -0
- package/transpiled/directives/auth/Scheme.js.map +1 -1
- package/transpiled/directives/auth/types.d.ts +16 -0
- package/transpiled/directives/cache/Cache.d.ts +1 -1
- package/transpiled/directives/cache/Cache.js +1 -1
- package/transpiled/directives/cache/Cache.js.map +1 -1
- package/transpiled/directives/dev/Development.d.ts +1 -1
- package/transpiled/directives/dev/Development.js +1 -1
- package/transpiled/directives/dev/Development.js.map +1 -1
- package/transpiled/directives/flow/Flow.d.ts +1 -1
- package/transpiled/directives/flow/Flow.js +1 -1
- package/transpiled/directives/flow/Flow.js.map +1 -1
- package/transpiled/directives/index.js +2 -1
- package/transpiled/directives/index.js.map +1 -1
- package/transpiled/directives/io/Directive.d.ts +1 -1
- package/transpiled/directives/io/IO.d.ts +7 -1
- package/transpiled/directives/io/IO.js +23 -3
- package/transpiled/directives/io/IO.js.map +1 -1
- package/transpiled/directives/io/Input.d.ts +3 -2
- package/transpiled/directives/io/Input.js +2 -1
- package/transpiled/directives/io/Input.js.map +1 -1
- package/transpiled/directives/io/Output.d.ts +5 -3
- package/transpiled/directives/io/Output.js +4 -2
- package/transpiled/directives/io/Output.js.map +1 -1
- package/transpiled/directives/io/Status.d.ts +1 -1
- package/transpiled/directives/io/Status.js +1 -1
- package/transpiled/directives/io/Status.js.map +1 -1
- package/transpiled/directives/io/Throttle.d.ts +1 -1
- package/transpiled/directives/io/Throttle.js +1 -1
- package/transpiled/directives/io/Throttle.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Quotas.d.ts +1 -1
- package/transpiled/directives/io/lib/throttle/Quotas.js +2 -2
- package/transpiled/directives/io/lib/throttle/Quotas.js.map +1 -1
- package/transpiled/directives/map/Headers.d.ts +2 -0
- package/transpiled/directives/map/Headers.js +8 -0
- package/transpiled/directives/map/Headers.js.map +1 -1
- package/transpiled/directives/map/Map.d.ts +3 -1
- package/transpiled/directives/map/Map.js +7 -1
- package/transpiled/directives/map/Map.js.map +1 -1
- package/transpiled/directives/map/Mapping.d.ts +13 -0
- package/transpiled/directives/map/Mapping.js +20 -0
- package/transpiled/directives/map/Mapping.js.map +1 -1
- package/transpiled/directives/map/Segments.d.ts +3 -0
- package/transpiled/directives/map/Segments.js +9 -0
- package/transpiled/directives/map/Segments.js.map +1 -1
- package/transpiled/directives/mcp/MCP.d.ts +15 -0
- package/transpiled/directives/mcp/MCP.js +29 -0
- package/transpiled/directives/mcp/MCP.js.map +1 -0
- package/transpiled/directives/mcp/Tool.d.ts +18 -0
- package/transpiled/directives/mcp/Tool.js +34 -0
- package/transpiled/directives/mcp/Tool.js.map +1 -0
- package/transpiled/directives/mcp/index.d.ts +4 -0
- package/transpiled/directives/mcp/index.js +4 -0
- package/transpiled/directives/mcp/index.js.map +1 -0
- package/transpiled/directives/oauth/Discovery.js +10 -13
- package/transpiled/directives/oauth/Discovery.js.map +1 -1
- package/transpiled/directives/octets/Octets.d.ts +1 -1
- package/transpiled/directives/octets/Octets.js +1 -1
- package/transpiled/directives/octets/Octets.js.map +1 -1
- package/transpiled/directives/require/Directive.d.ts +1 -1
- package/transpiled/directives/require/Headers.d.ts +1 -1
- package/transpiled/directives/require/Headers.js +1 -1
- package/transpiled/directives/require/Headers.js.map +1 -1
- package/transpiled/directives/require/Require.d.ts +1 -1
- package/transpiled/directives/require/Require.js +2 -2
- package/transpiled/directives/require/Require.js.map +1 -1
- package/transpiled/schemas.d.ts +2 -0
- package/transpiled/schemas.js +1 -0
- package/transpiled/schemas.js.map +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/components/identity.bans/operations/transit.d.ts +0 -14
- package/components/identity.bans/operations/transit.js.map +0 -1
- package/components/identity.basic/operations/add.d.ts +0 -3
- package/components/identity.basic/operations/add.js.map +0 -1
- package/components/identity.basic/operations/authenticate.d.ts +0 -13
- package/components/identity.basic/operations/authenticate.js.map +0 -1
- package/components/identity.basic/operations/check.d.ts +0 -7
- package/components/identity.basic/operations/check.js.map +0 -1
- package/components/identity.basic/operations/delete.d.ts +0 -7
- package/components/identity.basic/operations/delete.js.map +0 -1
- package/components/identity.basic/operations/incept.d.ts +0 -12
- package/components/identity.basic/operations/incept.js.map +0 -1
- package/components/identity.basic/operations/info.d.ts +0 -10
- package/components/identity.basic/operations/info.js.map +0 -1
- package/components/identity.basic/operations/lib/credentials.d.ts +0 -5
- package/components/identity.basic/operations/lib/credentials.js.map +0 -1
- package/components/identity.basic/operations/transit.d.ts +0 -15
- package/components/identity.basic/operations/transit.js.map +0 -1
- package/components/identity.clients/operations/describe.d.ts +0 -27
- package/components/identity.clients/operations/describe.js.map +0 -1
- package/components/identity.clients/operations/lib/Context.d.ts +0 -29
- package/components/identity.clients/operations/lib/Context.js.map +0 -1
- package/components/identity.clients/operations/lib/Entity.d.ts +0 -29
- package/components/identity.clients/operations/lib/Entity.js.map +0 -1
- package/components/identity.clients/operations/lib/canonical.d.ts +0 -11
- package/components/identity.clients/operations/lib/canonical.js.map +0 -1
- package/components/identity.clients/operations/lib/cimd.d.ts +0 -8
- package/components/identity.clients/operations/lib/cimd.js.map +0 -1
- package/components/identity.clients/operations/lib/errors.d.ts +0 -7
- package/components/identity.clients/operations/lib/errors.js.map +0 -1
- package/components/identity.clients/operations/lib/index.d.ts +0 -6
- package/components/identity.clients/operations/lib/index.js.map +0 -1
- package/components/identity.clients/operations/lib/redirect.d.ts +0 -10
- package/components/identity.clients/operations/lib/redirect.js.map +0 -1
- package/components/identity.clients/operations/register.d.ts +0 -37
- package/components/identity.clients/operations/register.js.map +0 -1
- package/components/identity.credentials/operations/list.d.ts +0 -52
- package/components/identity.credentials/operations/list.js.map +0 -1
- package/components/identity.federation/operations/authenticate.d.ts +0 -16
- package/components/identity.federation/operations/authenticate.js.map +0 -1
- package/components/identity.federation/operations/create.d.ts +0 -8
- package/components/identity.federation/operations/create.js.map +0 -1
- package/components/identity.federation/operations/decode.d.ts +0 -3
- package/components/identity.federation/operations/decode.js.map +0 -1
- package/components/identity.federation/operations/delete.d.ts +0 -8
- package/components/identity.federation/operations/delete.js.map +0 -1
- package/components/identity.federation/operations/incept.d.ts +0 -11
- package/components/identity.federation/operations/incept.js.map +0 -1
- package/components/identity.federation/operations/lib/Configuration.d.ts +0 -39
- package/components/identity.federation/operations/lib/Configuration.js.map +0 -1
- package/components/identity.federation/operations/lib/Ctx.d.ts +0 -8
- package/components/identity.federation/operations/lib/Ctx.js.map +0 -1
- package/components/identity.federation/operations/lib/Payload.d.ts +0 -5
- package/components/identity.federation/operations/lib/Payload.js.map +0 -1
- package/components/identity.federation/operations/lib/decode.d.ts +0 -3
- package/components/identity.federation/operations/lib/decode.js.map +0 -1
- package/components/identity.federation/operations/lib/discovery.d.ts +0 -5
- package/components/identity.federation/operations/lib/discovery.js.map +0 -1
- package/components/identity.federation/operations/lib/errors.d.ts +0 -77
- package/components/identity.federation/operations/lib/errors.js.map +0 -1
- package/components/identity.federation/operations/lib/exchange.d.ts +0 -3
- package/components/identity.federation/operations/lib/exchange.js.map +0 -1
- package/components/identity.federation/operations/lib/index.d.ts +0 -4
- package/components/identity.federation/operations/lib/index.js.map +0 -1
- package/components/identity.federation/operations/lib/jose.d.ts +0 -1
- package/components/identity.federation/operations/lib/jose.js.map +0 -1
- package/components/identity.federation/operations/lib/resolve.d.ts +0 -3
- package/components/identity.federation/operations/lib/resolve.js.map +0 -1
- package/components/identity.federation/operations/list.d.ts +0 -7
- package/components/identity.federation/operations/list.js.map +0 -1
- package/components/identity.federation/operations/types/Scheme.d.ts +0 -1
- package/components/identity.federation/operations/types/Scheme.js.map +0 -1
- package/components/identity.federation/operations/types/configuration.d.ts +0 -22
- package/components/identity.federation/operations/types/configuration.js.map +0 -1
- package/components/identity.federation/operations/types/context.d.ts +0 -36
- package/components/identity.federation/operations/types/context.js.map +0 -1
- package/components/identity.federation/operations/types/entity.d.ts +0 -9
- package/components/identity.federation/operations/types/entity.js.map +0 -1
- package/components/identity.federation/operations/types/index.d.ts +0 -4
- package/components/identity.federation/operations/types/index.js.map +0 -1
- package/components/identity.grants/operations/authorize.d.ts +0 -35
- package/components/identity.grants/operations/authorize.js.map +0 -1
- package/components/identity.grants/operations/exchange.d.ts +0 -37
- package/components/identity.grants/operations/exchange.js.map +0 -1
- package/components/identity.grants/operations/lib/code.d.ts +0 -15
- package/components/identity.grants/operations/lib/code.js.map +0 -1
- package/components/identity.grants/operations/lib/identify.d.ts +0 -6
- package/components/identity.grants/operations/lib/identify.js.map +0 -1
- package/components/identity.grants/operations/lib/index.d.ts +0 -3
- package/components/identity.grants/operations/lib/index.js.map +0 -1
- package/components/identity.grants/operations/list.d.ts +0 -13
- package/components/identity.grants/operations/list.js.map +0 -1
- package/components/identity.grants/operations/revoke.d.ts +0 -18
- package/components/identity.grants/operations/revoke.js.map +0 -1
- package/components/identity.keys/operations/create.d.ts +0 -22
- package/components/identity.keys/operations/create.js.map +0 -1
- package/components/identity.keys/operations/disable.d.ts +0 -5
- package/components/identity.keys/operations/disable.js.map +0 -1
- package/components/identity.keys/operations/revoke.d.ts +0 -15
- package/components/identity.keys/operations/revoke.js.map +0 -1
- package/components/identity.otp/operations/authenticate.d.ts +0 -12
- package/components/identity.otp/operations/authenticate.js.map +0 -1
- package/components/identity.otp/operations/issue.d.ts +0 -12
- package/components/identity.otp/operations/issue.js.map +0 -1
- package/components/identity.otp/operations/lib/Context.d.ts +0 -16
- package/components/identity.otp/operations/lib/Context.js.map +0 -1
- package/components/identity.otp/operations/lib/Entity.d.ts +0 -6
- package/components/identity.otp/operations/lib/Entity.js.map +0 -1
- package/components/identity.otp/operations/lib/index.d.ts +0 -1
- package/components/identity.otp/operations/lib/index.js.map +0 -1
- package/components/identity.passkeys/operations/authenticate.d.ts +0 -16
- package/components/identity.passkeys/operations/authenticate.js.map +0 -1
- package/components/identity.passkeys/operations/challenge.d.ts +0 -35
- package/components/identity.passkeys/operations/challenge.js.map +0 -1
- package/components/identity.passkeys/operations/create.d.ts +0 -19
- package/components/identity.passkeys/operations/create.js.map +0 -1
- package/components/identity.passkeys/operations/delete.d.ts +0 -8
- package/components/identity.passkeys/operations/delete.js.map +0 -1
- package/components/identity.passkeys/operations/lib/const.d.ts +0 -1
- package/components/identity.passkeys/operations/lib/const.js.map +0 -1
- package/components/identity.passkeys/operations/list.d.ts +0 -7
- package/components/identity.passkeys/operations/list.js.map +0 -1
- package/components/identity.passkeys/operations/types/Configuration.d.ts +0 -6
- package/components/identity.passkeys/operations/types/Configuration.js.map +0 -1
- package/components/identity.passkeys/operations/types/Context.d.ts +0 -16
- package/components/identity.passkeys/operations/types/Context.js.map +0 -1
- package/components/identity.passkeys/operations/types/Passkey.d.ts +0 -12
- package/components/identity.passkeys/operations/types/Passkey.js.map +0 -1
- package/components/identity.passkeys/operations/types/index.d.ts +0 -2
- package/components/identity.passkeys/operations/types/index.js.map +0 -1
- package/components/identity.passkeys/operations/use.d.ts +0 -16
- package/components/identity.passkeys/operations/use.js.map +0 -1
- package/components/identity.roles/operations/grant.d.ts +0 -10
- package/components/identity.roles/operations/grant.js.map +0 -1
- package/components/identity.roles/operations/lib/Entity.d.ts +0 -5
- package/components/identity.roles/operations/lib/Entity.js.map +0 -1
- package/components/identity.roles/operations/list.d.ts +0 -2
- package/components/identity.roles/operations/list.js.map +0 -1
- package/components/identity.roles/operations/principal.d.ts +0 -13
- package/components/identity.roles/operations/principal.js.map +0 -1
- package/components/identity.tokens/operations/authenticate.d.ts +0 -10
- package/components/identity.tokens/operations/authenticate.js.map +0 -1
- package/components/identity.tokens/operations/decrypt.d.ts +0 -16
- package/components/identity.tokens/operations/decrypt.js.map +0 -1
- package/components/identity.tokens/operations/encrypt.d.ts +0 -9
- package/components/identity.tokens/operations/encrypt.js.map +0 -1
- package/components/identity.tokens/operations/issue.d.ts +0 -25
- package/components/identity.tokens/operations/issue.js.map +0 -1
- package/components/identity.tokens/operations/lib/form.d.ts +0 -8
- package/components/identity.tokens/operations/lib/form.js.map +0 -1
- package/components/identity.tokens/operations/lib/index.d.ts +0 -4
- package/components/identity.tokens/operations/lib/index.js.map +0 -1
- package/components/identity.tokens/operations/lib/jose.d.ts +0 -1
- package/components/identity.tokens/operations/lib/jose.js.map +0 -1
- package/components/identity.tokens/operations/lib/key.d.ts +0 -1
- package/components/identity.tokens/operations/lib/key.js.map +0 -1
- package/components/identity.tokens/operations/lib/pad.d.ts +0 -1
- package/components/identity.tokens/operations/lib/pad.js.map +0 -1
- package/components/identity.tokens/operations/revoke.d.ts +0 -2
- package/components/identity.tokens/operations/revoke.js.map +0 -1
package/source/Gateway.ts
CHANGED
|
@@ -3,10 +3,13 @@ import { setTimeout } from 'node:timers/promises'
|
|
|
3
3
|
import { console } from 'openspan'
|
|
4
4
|
import { type bindings, Connector } from '@toa.io/core'
|
|
5
5
|
import * as http from './HTTP/index.js'
|
|
6
|
+
import { MCP, RPC } from './const.js'
|
|
6
7
|
import { rethrow } from './exceptions.js'
|
|
7
8
|
import { decide } from './Branch.js'
|
|
8
9
|
import type { Interception } from './Interception.js'
|
|
9
|
-
import type {
|
|
10
|
+
import type { Dispatcher } from './RPC/index.js'
|
|
11
|
+
import type { Server } from './MCP/index.js'
|
|
12
|
+
import type { DirectiveFactory, Method, Node, Parameter, Tree, Match } from './RTD/index.js'
|
|
10
13
|
import type { Label } from './discovery.js'
|
|
11
14
|
import type { Branch, Exposed } from './Branch.js'
|
|
12
15
|
|
|
@@ -14,6 +17,13 @@ export class Gateway extends Connector {
|
|
|
14
17
|
private readonly broadcast: Broadcast
|
|
15
18
|
private readonly tree: Tree
|
|
16
19
|
private readonly interceptor: Interception
|
|
20
|
+
private readonly directives: DirectiveFactory
|
|
21
|
+
|
|
22
|
+
/** JSON-RPC is served only where the annotation asked for it. */
|
|
23
|
+
private readonly dispatcher: Dispatcher | null
|
|
24
|
+
|
|
25
|
+
/** And the same of MCP. */
|
|
26
|
+
private readonly mcp: Server | null
|
|
17
27
|
private readonly branches = new Map<string, Exposed>()
|
|
18
28
|
private lastMerge = 0
|
|
19
29
|
private widestGap = 0
|
|
@@ -21,12 +31,17 @@ export class Gateway extends Connector {
|
|
|
21
31
|
private stopped = false
|
|
22
32
|
private resolveFirstMerge: (() => void) | null = null
|
|
23
33
|
|
|
24
|
-
|
|
34
|
+
// eslint-disable-next-line max-params
|
|
35
|
+
public constructor (broadcast: Broadcast, tree: Tree, interception: Interception,
|
|
36
|
+
directives: DirectiveFactory, dispatcher: Dispatcher | null, mcp: Server | null) {
|
|
25
37
|
super()
|
|
26
38
|
|
|
27
39
|
this.broadcast = broadcast
|
|
28
40
|
this.tree = tree
|
|
29
41
|
this.interceptor = interception
|
|
42
|
+
this.directives = directives
|
|
43
|
+
this.dispatcher = dispatcher
|
|
44
|
+
this.mcp = mcp
|
|
30
45
|
|
|
31
46
|
this.depends(broadcast)
|
|
32
47
|
}
|
|
@@ -38,10 +53,44 @@ export class Gateway extends Connector {
|
|
|
38
53
|
if (interception !== null)
|
|
39
54
|
return interception
|
|
40
55
|
|
|
56
|
+
// request-scoped, before anything is routed: this is where a credential is read
|
|
57
|
+
await context.timing.capture('preflight',
|
|
58
|
+
this.directives.preflight(context)).catch(rethrow)
|
|
59
|
+
|
|
60
|
+
const response = await this.endpoint(context)
|
|
61
|
+
|
|
62
|
+
// request-scoped, on whatever is going back: this is where a credential is re-issued
|
|
63
|
+
await context.timing.capture('depart',
|
|
64
|
+
this.directives.depart(context, response)).catch(rethrow)
|
|
65
|
+
|
|
66
|
+
return response
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* What answers the request: a pinned endpoint that makes calls of its own, or the route
|
|
71
|
+
* the path names.
|
|
72
|
+
*/
|
|
73
|
+
private async endpoint (context: http.Context): Promise<http.OutgoingMessage> {
|
|
74
|
+
const route: http.Processor = async (call) => await this.route(call)
|
|
75
|
+
|
|
76
|
+
if (this.dispatcher !== null && context.url.pathname === RPC)
|
|
77
|
+
return await context.timing.capture('rpc', this.dispatcher.dispatch(context, route))
|
|
78
|
+
|
|
79
|
+
if (this.mcp !== null && context.url.pathname === MCP)
|
|
80
|
+
return await context.timing.capture('mcp', this.mcp.process(context, route))
|
|
81
|
+
|
|
82
|
+
return await this.route(context)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* One call: everything that needs a node. A request makes one of these, and a request
|
|
87
|
+
* that carries several calls makes one per call.
|
|
88
|
+
*/
|
|
89
|
+
private async route (context: http.Context): Promise<http.OutgoingMessage> {
|
|
41
90
|
const { node, parameters } = this.match(context)
|
|
42
91
|
|
|
43
92
|
if (context.request.method === 'OPTIONS')
|
|
44
|
-
return await this.explain(node, parameters)
|
|
93
|
+
return await this.explain(context, node, parameters)
|
|
45
94
|
|
|
46
95
|
let verb = context.request.method
|
|
47
96
|
|
|
@@ -53,8 +102,8 @@ export class Gateway extends Connector {
|
|
|
53
102
|
|
|
54
103
|
const method = node.methods[verb]
|
|
55
104
|
|
|
56
|
-
const interruption = await context.timing.capture('
|
|
57
|
-
method.directives.
|
|
105
|
+
const interruption = await context.timing.capture('precall',
|
|
106
|
+
method.directives.precall(context, parameters)).catch(rethrow)
|
|
58
107
|
|
|
59
108
|
const response = interruption ??
|
|
60
109
|
await context.timing.capture('call', this.call(method, context, parameters))
|
|
@@ -68,7 +117,16 @@ export class Gateway extends Connector {
|
|
|
68
117
|
protected override async open (): Promise<void> {
|
|
69
118
|
await this.discover()
|
|
70
119
|
|
|
71
|
-
|
|
120
|
+
// what is served besides the tree, so that turning one on can be seen to have worked
|
|
121
|
+
const pinned: string[] = []
|
|
122
|
+
|
|
123
|
+
if (this.dispatcher !== null)
|
|
124
|
+
pinned.push(RPC)
|
|
125
|
+
|
|
126
|
+
if (this.mcp !== null)
|
|
127
|
+
pinned.push(MCP)
|
|
128
|
+
|
|
129
|
+
console.info('Gateway started', { endpoints: pinned.length === 0 ? 'none' : pinned.join(' ') })
|
|
72
130
|
}
|
|
73
131
|
|
|
74
132
|
/**
|
|
@@ -131,12 +189,16 @@ export class Gateway extends Connector {
|
|
|
131
189
|
.catch(rethrow) as http.OutgoingMessage
|
|
132
190
|
}
|
|
133
191
|
|
|
134
|
-
private async explain (
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
-
const
|
|
192
|
+
private async explain (context: http.Context, node: Node,
|
|
193
|
+
parameters: Parameter[]): Promise<http.OutgoingMessage> {
|
|
194
|
+
const body = await node.explain(context, parameters)
|
|
195
|
+
const verbs = Object.keys(body)
|
|
196
|
+
|
|
197
|
+
// what a caller may not use is not a resource to them, and describing it would be the leak
|
|
198
|
+
if (verbs.length === 0 && Object.keys(node.methods).length > 0)
|
|
199
|
+
throw new http.Forbidden()
|
|
138
200
|
|
|
139
|
-
return { body, headers }
|
|
201
|
+
return { body, headers: new Headers({ allow: verbs.join(', ') }) }
|
|
140
202
|
}
|
|
141
203
|
|
|
142
204
|
private async discover (): Promise<void> {
|
package/source/HTTP/Context.ts
CHANGED
|
@@ -22,6 +22,13 @@ export class Context {
|
|
|
22
22
|
public readonly timing: Timing
|
|
23
23
|
public readonly debug: boolean
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Whether this is a procedure a request made, rather than the request. What forks one
|
|
27
|
+
* says so, and a directive that answers differently to a procedure than to a request
|
|
28
|
+
* reads it here.
|
|
29
|
+
*/
|
|
30
|
+
public readonly procedural: boolean = false
|
|
31
|
+
|
|
25
32
|
public readonly pipelines: Pipelines = {
|
|
26
33
|
body: [],
|
|
27
34
|
response: []
|
package/source/HTTP/Server.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { ClientError, Exception } from './exceptions.js'
|
|
|
12
12
|
import { Context } from './Context.js'
|
|
13
13
|
import { PROBE, Probe } from './Probe.js'
|
|
14
14
|
import type { IncomingMessage, Protocol, ServerResponse } from './types.js'
|
|
15
|
-
import type { Bouncer, OAuth } from '../Annotation.js'
|
|
15
|
+
import type { Bouncer, MCP, OAuth, RPC } from '../Annotation.js'
|
|
16
16
|
|
|
17
17
|
export class Server extends Connector {
|
|
18
18
|
private readonly server: http.Server | http2.Http2Server
|
|
@@ -389,6 +389,12 @@ interface Properties {
|
|
|
389
389
|
|
|
390
390
|
/** The authorization server this context exposes; none is exposed without it. */
|
|
391
391
|
oauth?: OAuth
|
|
392
|
+
|
|
393
|
+
/** JSON-RPC at `/.rpc`; none is served without it. */
|
|
394
|
+
rpc?: RPC
|
|
395
|
+
|
|
396
|
+
/** MCP at `/.mcp`; none is served without it. */
|
|
397
|
+
mcp?: MCP
|
|
392
398
|
}
|
|
393
399
|
|
|
394
400
|
export type Options = { authorities: Properties['authorities'] } & {
|
package/source/HTTP/messages.ts
CHANGED
|
@@ -15,9 +15,18 @@ const server = `Exposition/${JSON.parse(readFileSync(new URL('../../package.json
|
|
|
15
15
|
|
|
16
16
|
const pending = new Map<string, PendingStream>()
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Applies what the request accumulated in `pipelines.response` — an `io:output` restriction,
|
|
20
|
+
* a `vary` a `map` directive owes. Separate from `write` because a message is not always
|
|
21
|
+
* written: one call of several produces a value the reply is assembled from.
|
|
22
|
+
*/
|
|
23
|
+
export async function shape (context: Context, message: OutgoingMessage): Promise<void> {
|
|
19
24
|
for (const transform of context.pipelines.response)
|
|
20
25
|
await transform(message)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function write (context: Context, response: ServerResponse, message: OutgoingMessage): Promise<void> {
|
|
29
|
+
await shape(context, message)
|
|
21
30
|
|
|
22
31
|
if (message?.status !== undefined)
|
|
23
32
|
response.statusCode = message.status
|
package/source/Introspection.ts
CHANGED
|
@@ -1,11 +1,116 @@
|
|
|
1
1
|
import type { Remote } from '@toa.io/core'
|
|
2
2
|
|
|
3
3
|
export interface Introspection {
|
|
4
|
+
/**
|
|
5
|
+
* What the route states this method is. The operation states what it is too, and that is
|
|
6
|
+
* not this: an operation is written without knowledge of any route, and a method is an
|
|
7
|
+
* operation and a route together — the same operation mounted twice is two methods, and
|
|
8
|
+
* one sentence cannot be true of both. The operation's own is for the Introspection.
|
|
9
|
+
*/
|
|
10
|
+
description?: string
|
|
11
|
+
|
|
12
|
+
/** what a person is shown where a client lists this method, which a name is not */
|
|
13
|
+
title?: string
|
|
4
14
|
route?: Record<string, Schema>
|
|
5
15
|
query?: Record<string, Schema>
|
|
16
|
+
|
|
17
|
+
/** what a request header carries, which is therefore not the body's to send */
|
|
18
|
+
headers?: Record<string, Sourced>
|
|
6
19
|
input?: Schema
|
|
7
20
|
output?: Schema
|
|
8
21
|
errors?: string[]
|
|
9
22
|
}
|
|
10
23
|
|
|
24
|
+
/** A property the gateway reads from somewhere else, and the schema it was declared with. */
|
|
25
|
+
export interface Sourced {
|
|
26
|
+
header: string
|
|
27
|
+
[keyword: string]: unknown
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
export type Schema = Awaited<ReturnType<Remote['explain']>>['input']
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The same, in the order the shape states — whatever order the families that filled it ran
|
|
34
|
+
* in. What a resource says about itself is read, so it is written the way it is documented.
|
|
35
|
+
*/
|
|
36
|
+
export function order (introspection: Introspection): Introspection {
|
|
37
|
+
const ordered: Introspection = {}
|
|
38
|
+
|
|
39
|
+
for (const key of KEYS)
|
|
40
|
+
if (introspection[key] !== undefined)
|
|
41
|
+
(ordered[key] as unknown) = introspection[key]
|
|
42
|
+
|
|
43
|
+
return ordered
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const KEYS = ['title', 'description', 'route', 'query', 'headers', 'input', 'output', 'errors'] as const
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The schema of one input property, taken out of it: a property another family fills is
|
|
50
|
+
* not the caller's to send, and what took it says where it comes from instead.
|
|
51
|
+
*/
|
|
52
|
+
export function take (carrier: Carrier, property: string): Schema | undefined {
|
|
53
|
+
const input = carrier.input as Shape | null | undefined
|
|
54
|
+
const properties = input?.properties
|
|
55
|
+
|
|
56
|
+
if (input === undefined || input === null || properties === undefined ||
|
|
57
|
+
!(property in properties))
|
|
58
|
+
return undefined
|
|
59
|
+
|
|
60
|
+
const schema = properties[property]
|
|
61
|
+
|
|
62
|
+
delete properties[property]
|
|
63
|
+
|
|
64
|
+
if (input.required !== undefined)
|
|
65
|
+
input.required = input.required.filter((name) => name !== property)
|
|
66
|
+
|
|
67
|
+
return schema
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A schema restricted to the properties a whitelist admits, and an array's items where it
|
|
72
|
+
* describes an array. What is not an object of properties is left alone: a whitelist has
|
|
73
|
+
* nothing to say about a string.
|
|
74
|
+
*/
|
|
75
|
+
export function restrict (schema: Schema | undefined, allowed: Set<string>): Schema | undefined {
|
|
76
|
+
const shape = schema as Shape | null | undefined
|
|
77
|
+
|
|
78
|
+
if (shape === undefined || shape === null)
|
|
79
|
+
return schema
|
|
80
|
+
|
|
81
|
+
if (shape.items !== undefined)
|
|
82
|
+
return { ...shape, items: restrict(shape.items, allowed) } as unknown as Schema
|
|
83
|
+
|
|
84
|
+
if (shape.properties === undefined)
|
|
85
|
+
return schema
|
|
86
|
+
|
|
87
|
+
const properties: Record<string, Schema> = {}
|
|
88
|
+
|
|
89
|
+
for (const [name, property] of Object.entries(shape.properties))
|
|
90
|
+
if (allowed.has(name))
|
|
91
|
+
properties[name] = property
|
|
92
|
+
|
|
93
|
+
const restricted: Shape = { ...shape, properties }
|
|
94
|
+
|
|
95
|
+
if (shape.required !== undefined)
|
|
96
|
+
restricted.required = shape.required.filter((name) => allowed.has(name))
|
|
97
|
+
|
|
98
|
+
return restricted as unknown as Schema
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* What a schema is read as here: the keywords these narrow, and whatever else it carries.
|
|
103
|
+
* `Schema` as core declares it requires `properties`, which a schema of a string has not,
|
|
104
|
+
* so the two are cast through rather than assigned.
|
|
105
|
+
*/
|
|
106
|
+
/** Whatever states an input: an explanation as the operation gave it, or as a route left it. */
|
|
107
|
+
interface Carrier {
|
|
108
|
+
input?: Schema
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface Shape {
|
|
112
|
+
properties?: Record<string, Schema>
|
|
113
|
+
required?: string[]
|
|
114
|
+
items?: Schema
|
|
115
|
+
[keyword: string]: unknown
|
|
116
|
+
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { console } from 'openspan'
|
|
2
|
+
import { BRANCH_TTL } from '../const.js'
|
|
3
|
+
import * as http from '../HTTP/index.js'
|
|
4
|
+
import { discovery, type Discovery } from './discover.js'
|
|
5
|
+
import { call, list, type Scope } from './tools.js'
|
|
6
|
+
import {
|
|
7
|
+
HEADER_MISMATCH,
|
|
8
|
+
INVALID_PARAMS,
|
|
9
|
+
INVALID_REQUEST,
|
|
10
|
+
METHOD_NOT_FOUND,
|
|
11
|
+
PARSE,
|
|
12
|
+
UNSUPPORTED_VERSION,
|
|
13
|
+
failure,
|
|
14
|
+
response
|
|
15
|
+
} from './errors.js'
|
|
16
|
+
import {
|
|
17
|
+
CLIENT_CAPABILITIES,
|
|
18
|
+
JSONRPC,
|
|
19
|
+
LEGACY,
|
|
20
|
+
MODERN,
|
|
21
|
+
PROTOCOL_VERSION,
|
|
22
|
+
SERVER_INFO,
|
|
23
|
+
VERSIONS,
|
|
24
|
+
type Cache,
|
|
25
|
+
type Message,
|
|
26
|
+
type Params
|
|
27
|
+
} from './types.js'
|
|
28
|
+
import type { Tree } from '../RTD/index.js'
|
|
29
|
+
import type { MCP } from '../Annotation.js'
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The Model Context Protocol, as one endpoint that remembers nothing between requests.
|
|
33
|
+
*
|
|
34
|
+
* Two revisions are answered from it. The modern one carries the version and the client's
|
|
35
|
+
* capabilities in every request; the one before it opens with `initialize`, which is what
|
|
36
|
+
* most clients still send. Neither needs a session, and neither needs a stream: every method
|
|
37
|
+
* here answers one object, which is why this can exist in a package that serves no SSE.
|
|
38
|
+
*/
|
|
39
|
+
export class Server {
|
|
40
|
+
private readonly options: MCP
|
|
41
|
+
private readonly tree: Tree
|
|
42
|
+
private readonly discovery: Discovery
|
|
43
|
+
private readonly origins: Set<string>
|
|
44
|
+
|
|
45
|
+
public constructor (options: MCP, tree: Tree) {
|
|
46
|
+
this.options = options
|
|
47
|
+
this.tree = tree
|
|
48
|
+
this.discovery = discovery(options)
|
|
49
|
+
this.origins = new Set(options.origins ?? [])
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public async process (context: http.Context,
|
|
53
|
+
route: http.Processor): Promise<http.OutgoingMessage> {
|
|
54
|
+
if (context.request.method !== 'POST')
|
|
55
|
+
throw new http.MethodNotAllowed(new Headers({ allow: 'POST' }))
|
|
56
|
+
|
|
57
|
+
this.admit(context)
|
|
58
|
+
|
|
59
|
+
const message = await this.read(context)
|
|
60
|
+
const version = this.version(context, message)
|
|
61
|
+
const modern = version === MODERN
|
|
62
|
+
|
|
63
|
+
if (modern)
|
|
64
|
+
this.mirrored(context, message)
|
|
65
|
+
|
|
66
|
+
const result = await this.answer({ context, route, tree: this.tree }, message, modern)
|
|
67
|
+
|
|
68
|
+
// a notification is answered by not answering, and there is nothing here to remember
|
|
69
|
+
if (message.id === undefined)
|
|
70
|
+
return { status: ACCEPTED }
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
status: OK,
|
|
74
|
+
body: { jsonrpc: JSONRPC, id: message.id, result },
|
|
75
|
+
headers: new Headers({ 'cache-control': 'no-store' })
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Who may reach the endpoint at all, before anything it carries is read. */
|
|
80
|
+
private admit (context: http.Context): void {
|
|
81
|
+
const origin = context.request.headers.origin
|
|
82
|
+
|
|
83
|
+
// the revision requires this against DNS rebinding; a request without one is no browser's
|
|
84
|
+
if (origin !== undefined && !this.origins.has(origin))
|
|
85
|
+
throw new http.Forbidden('Origin is not allowed')
|
|
86
|
+
|
|
87
|
+
if (this.options.anonymous === true)
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
if ((context as { identity?: unknown }).identity == null)
|
|
91
|
+
throw new http.Unauthorized()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private async answer (scope: Scope, message: Message, modern: boolean): Promise<unknown> {
|
|
95
|
+
const params = message.params ?? {}
|
|
96
|
+
|
|
97
|
+
switch (message.method) {
|
|
98
|
+
case 'server/discover':
|
|
99
|
+
return this.complete(this.discovery.modern, modern, DISCOVERY_CACHE)
|
|
100
|
+
|
|
101
|
+
case 'tools/list':
|
|
102
|
+
return this.complete({ tools: await list(this.tree, scope.context) }, modern, TOOLS_CACHE)
|
|
103
|
+
|
|
104
|
+
case 'tools/call':
|
|
105
|
+
return this.complete(await this.tool(scope, params), modern)
|
|
106
|
+
|
|
107
|
+
// what a client of an earlier revision opens with; no session is made and none is named
|
|
108
|
+
case 'initialize':
|
|
109
|
+
return this.discovery.legacy(declared(params))
|
|
110
|
+
|
|
111
|
+
case 'notifications/initialized':
|
|
112
|
+
return null
|
|
113
|
+
|
|
114
|
+
case 'ping':
|
|
115
|
+
return {}
|
|
116
|
+
|
|
117
|
+
default:
|
|
118
|
+
throw new http.NotFound(response(message.id ?? null,
|
|
119
|
+
failure(METHOD_NOT_FOUND, `'${message.method}' is not a method this server answers`)))
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private async tool (scope: Scope, params: Params): Promise<object> {
|
|
124
|
+
const named = params.name
|
|
125
|
+
|
|
126
|
+
if (typeof named !== 'string')
|
|
127
|
+
throw new http.BadRequest(response(null,
|
|
128
|
+
failure(INVALID_PARAMS, '`tools/call` states the tool it calls by name')))
|
|
129
|
+
|
|
130
|
+
const args = params.arguments ?? {}
|
|
131
|
+
|
|
132
|
+
if (typeof args !== 'object' || args === null || Array.isArray(args))
|
|
133
|
+
throw new http.BadRequest(response(null,
|
|
134
|
+
failure(INVALID_PARAMS, '`arguments` must be an object')))
|
|
135
|
+
|
|
136
|
+
return await console.span({ name: named },
|
|
137
|
+
async () => await call(scope, named, args as Params))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Every result of the modern revision says what kind it is, and who answered it. Where the
|
|
142
|
+
* revision names the operation as one whose result may be held, it says that too, and must.
|
|
143
|
+
*/
|
|
144
|
+
private complete (result: object, modern: boolean, cache?: Cache): object {
|
|
145
|
+
return modern
|
|
146
|
+
? { ...result, ...cache, resultType: 'complete', _meta: { [SERVER_INFO]: this.serverInfo() } }
|
|
147
|
+
: result
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private serverInfo (): unknown {
|
|
151
|
+
return (this.discovery.modern as { _meta: Record<string, unknown> })._meta[SERVER_INFO]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Which revision this request is of. `initialize` is one by itself; otherwise the header
|
|
156
|
+
* says, and a request that names none is of a revision that did not send one.
|
|
157
|
+
*/
|
|
158
|
+
private version (context: http.Context, message: Message): string {
|
|
159
|
+
if (message.method === 'initialize')
|
|
160
|
+
return LEGACY
|
|
161
|
+
|
|
162
|
+
const header = context.request.headers['mcp-protocol-version']
|
|
163
|
+
const stated = declared(message.params ?? {})
|
|
164
|
+
|
|
165
|
+
if (header !== undefined && stated !== undefined && header !== stated)
|
|
166
|
+
throw new http.BadRequest(response(message.id ?? null, failure(HEADER_MISMATCH,
|
|
167
|
+
`'MCP-Protocol-Version' says '${String(header)}' and the body says '${stated}'`)))
|
|
168
|
+
|
|
169
|
+
const value = (header as string | undefined) ?? stated
|
|
170
|
+
|
|
171
|
+
if (value === undefined)
|
|
172
|
+
return LEGACY
|
|
173
|
+
|
|
174
|
+
if (!VERSIONS.includes(value))
|
|
175
|
+
throw new http.BadRequest(response(message.id ?? null,
|
|
176
|
+
failure(UNSUPPORTED_VERSION, 'Unsupported protocol version',
|
|
177
|
+
{ supported: VERSIONS, requested: value })))
|
|
178
|
+
|
|
179
|
+
return value
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* What the modern revision mirrors into headers, so that what routes a request and what
|
|
184
|
+
* answers it cannot be told two different things.
|
|
185
|
+
*/
|
|
186
|
+
private mirrored (context: http.Context, message: Message): void {
|
|
187
|
+
const meta = metadata(message.params ?? {})
|
|
188
|
+
|
|
189
|
+
if (meta?.[PROTOCOL_VERSION] === undefined || meta[CLIENT_CAPABILITIES] === undefined)
|
|
190
|
+
throw new http.BadRequest(response(message.id ?? null, failure(INVALID_PARAMS,
|
|
191
|
+
`'_meta' states '${PROTOCOL_VERSION}' and '${CLIENT_CAPABILITIES}'`)))
|
|
192
|
+
|
|
193
|
+
const id = message.id ?? null
|
|
194
|
+
|
|
195
|
+
mirrors(context, { id, header: 'mcp-method', value: message.method })
|
|
196
|
+
|
|
197
|
+
if (message.method === 'tools/call')
|
|
198
|
+
mirrors(context, { id, header: 'mcp-name', value: (message.params ?? {}).name })
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** A body the decoder refuses is a parse error; a media type it does not know is not. */
|
|
202
|
+
private async read (context: http.Context): Promise<Message> {
|
|
203
|
+
let body: unknown
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
body = await context.body()
|
|
207
|
+
} catch (exception) {
|
|
208
|
+
if (exception instanceof http.BadRequest)
|
|
209
|
+
throw new http.BadRequest(response(null, failure(PARSE, 'Parse error')))
|
|
210
|
+
|
|
211
|
+
throw exception
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (typeof body !== 'object' || body === null || Array.isArray(body) ||
|
|
215
|
+
(body as Message).jsonrpc !== JSONRPC || typeof (body as Message).method !== 'string')
|
|
216
|
+
throw new http.BadRequest(response(null,
|
|
217
|
+
failure(INVALID_REQUEST, 'A request carries one JSON-RPC message')))
|
|
218
|
+
|
|
219
|
+
return body as Message
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** What a header says must be what the body says, or what routes and what answers differ. */
|
|
224
|
+
function mirrors (context: http.Context, mirror: Mirror): void {
|
|
225
|
+
const { id, header, value } = mirror
|
|
226
|
+
const stated = context.request.headers[header]
|
|
227
|
+
|
|
228
|
+
if (stated === undefined)
|
|
229
|
+
throw new http.BadRequest(response(id, failure(HEADER_MISMATCH, `'${header}' is required`)))
|
|
230
|
+
|
|
231
|
+
if (decode(String(stated)) !== value)
|
|
232
|
+
throw new http.BadRequest(response(id, failure(HEADER_MISMATCH,
|
|
233
|
+
`'${header}' says '${String(stated)}' and the body says '${String(value)}'`)))
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
interface Mirror {
|
|
237
|
+
id: string | number | null
|
|
238
|
+
header: string
|
|
239
|
+
value: unknown
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function metadata (params: Params): Record<string, unknown> | undefined {
|
|
243
|
+
const meta = params._meta
|
|
244
|
+
|
|
245
|
+
return typeof meta === 'object' && meta !== null
|
|
246
|
+
? meta as Record<string, unknown>
|
|
247
|
+
: undefined
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function declared (params: Params): string | undefined {
|
|
251
|
+
const stated = metadata(params)?.[PROTOCOL_VERSION]
|
|
252
|
+
|
|
253
|
+
return typeof stated === 'string' ? stated : undefined
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** What a header value that could not be written as ASCII was encoded as. */
|
|
257
|
+
function decode (value: string): string {
|
|
258
|
+
if (!value.startsWith(SENTINEL) || !value.endsWith(TERMINATOR))
|
|
259
|
+
return value
|
|
260
|
+
|
|
261
|
+
const encoded = value.slice(SENTINEL.length, -TERMINATOR.length)
|
|
262
|
+
|
|
263
|
+
return Buffer.from(encoded, 'base64').toString('utf8')
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** A tool list is what the tree holds, which stands until a branch of it expires. */
|
|
267
|
+
const TOOLS_CACHE: Cache = { ttlMs: BRANCH_TTL, cacheScope: 'private' }
|
|
268
|
+
|
|
269
|
+
/** What the annotation says, which is the same for every caller until the application is redeployed. */
|
|
270
|
+
const DISCOVERY_CACHE: Cache = { ttlMs: BRANCH_TTL, cacheScope: 'public' }
|
|
271
|
+
|
|
272
|
+
const OK = 200
|
|
273
|
+
const ACCEPTED = 202
|
|
274
|
+
const SENTINEL = '=?base64?'
|
|
275
|
+
const TERMINATOR = '?='
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { LEGACY, MODERN, SERVER_INFO, VERSIONS } from './types.js'
|
|
3
|
+
import type { MCP } from '../Annotation.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* What a client is told before it calls anything: the revisions served, what is served, and
|
|
7
|
+
* who serves it. It is a function of the annotation alone, so it is built once and answered
|
|
8
|
+
* as it is.
|
|
9
|
+
*/
|
|
10
|
+
export interface Discovery {
|
|
11
|
+
/** `server/discover`, which the modern revision has replaced the handshake with. */
|
|
12
|
+
modern: object
|
|
13
|
+
|
|
14
|
+
/** `initialize`, in the shape a client of an earlier revision reads. */
|
|
15
|
+
legacy: (offered: string | undefined) => object
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function discovery (options: MCP): Discovery {
|
|
19
|
+
const info = { name: options.name, version: VERSION }
|
|
20
|
+
|
|
21
|
+
// `listChanged` is a stream a client holds open, and this endpoint holds none
|
|
22
|
+
const capabilities = { tools: {} }
|
|
23
|
+
|
|
24
|
+
const modern: Record<string, unknown> = {
|
|
25
|
+
supportedVersions: VERSIONS,
|
|
26
|
+
capabilities,
|
|
27
|
+
_meta: { [SERVER_INFO]: info }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (options.instructions !== undefined)
|
|
31
|
+
modern.instructions = options.instructions
|
|
32
|
+
|
|
33
|
+
function legacy (offered: string | undefined): object {
|
|
34
|
+
const value: Record<string, unknown> = {
|
|
35
|
+
// what the client asked for where that is served, and the newest handshake otherwise
|
|
36
|
+
protocolVersion: offered !== undefined && offered !== MODERN ? offered : LEGACY,
|
|
37
|
+
capabilities,
|
|
38
|
+
serverInfo: info
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (options.instructions !== undefined)
|
|
42
|
+
value.instructions = options.instructions
|
|
43
|
+
|
|
44
|
+
return value
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return { modern, legacy }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** What this gateway is, which is what answers however an application names itself. */
|
|
51
|
+
const VERSION: string = JSON.parse(
|
|
52
|
+
readFileSync(new URL('../../package.json', import.meta.url), 'utf8')).version
|