@toa.io/extensions.exposition 1.0.0-alpha.291 → 1.0.0-alpha.293
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/components/identity.basic/package.json +8 -0
- package/components/identity.federation/package.json +8 -0
- package/components/identity.passkeys/package.json +8 -0
- package/components/identity.tokens/package.json +10 -0
- package/package.json +25 -13
- package/transpiled/Discovery/Explorer.js +1 -1
- package/transpiled/Discovery/Explorer.js.map +1 -1
- package/transpiled/Discovery/Site.js +1 -1
- package/transpiled/Discovery/Site.js.map +1 -1
- package/transpiled/Discovery/trunk.js +1 -1
- package/transpiled/Discovery/trunk.js.map +1 -1
- package/transpiled/Endpoint.js +3 -0
- package/transpiled/Endpoint.js.map +1 -1
- package/transpiled/Factory.js +1 -1
- package/transpiled/Factory.js.map +1 -1
- package/transpiled/Gateway.js +1 -1
- package/transpiled/Gateway.js.map +1 -1
- package/transpiled/HTTP/Server.d.ts +1 -1
- package/transpiled/HTTP/Server.js +1 -1
- package/transpiled/HTTP/Server.js.map +1 -1
- package/transpiled/Introspection.d.ts +6 -0
- package/transpiled/Introspection.js +1 -0
- package/transpiled/Introspection.js.map +1 -1
- package/transpiled/MCP/Server.d.ts +1 -1
- package/transpiled/MCP/Server.js +1 -1
- package/transpiled/MCP/Server.js.map +1 -1
- package/transpiled/MCP/discover.d.ts +1 -1
- package/transpiled/MCP/schema.js +2 -2
- package/transpiled/Query.d.ts +2 -12
- package/transpiled/Query.js +3 -13
- package/transpiled/Query.js.map +1 -1
- package/transpiled/RPC/Dispatcher.d.ts +1 -1
- package/transpiled/RPC/Dispatcher.js +2 -2
- package/transpiled/RPC/Dispatcher.js.map +1 -1
- package/transpiled/RTD/Endpoint.d.ts +2 -3
- package/transpiled/RTD/Tree.js +1 -1
- package/transpiled/RTD/Tree.js.map +1 -1
- package/transpiled/RTD/factory.js +1 -1
- package/transpiled/RTD/factory.js.map +1 -1
- package/transpiled/RTD/syntax/index.d.ts +1 -2
- package/transpiled/RTD/syntax/index.js +1 -2
- package/transpiled/RTD/syntax/index.js.map +1 -1
- package/transpiled/Tenant.js +1 -1
- package/transpiled/Tenant.js.map +1 -1
- package/transpiled/directives/auth/Authorization.js +1 -1
- package/transpiled/directives/auth/Authorization.js.map +1 -1
- package/transpiled/directives/io/IO.js +1 -1
- package/transpiled/directives/io/IO.js.map +1 -1
- package/transpiled/directives/oauth/documents.d.ts +1 -1
- package/transpiled/index.d.ts +0 -2
- package/transpiled/index.js +0 -2
- package/transpiled/index.js.map +1 -1
- package/transpiled/service.js +1 -1
- package/transpiled/service.js.map +1 -1
- package/ui/dist/_app/immutable/assets/0.Cu0AnR_8.css +2 -0
- package/ui/dist/_app/immutable/assets/2.BghF56l_.css +1 -0
- package/ui/dist/_app/immutable/assets/ui.C8aD6zzF.css +1 -0
- package/ui/dist/_app/immutable/chunks/B8GvXrmq.js +1 -0
- package/ui/dist/_app/immutable/chunks/BVDJTrf4.js +3 -0
- package/ui/dist/_app/immutable/chunks/D6q28_Ok.js +86 -0
- package/ui/dist/_app/immutable/chunks/{D9tE1yyO.js → DVlaUfVU.js} +1 -1
- package/ui/dist/_app/immutable/chunks/DpB73ZB6.js +6 -0
- package/ui/dist/_app/immutable/entry/app.CTava8yn.js +2 -0
- package/ui/dist/_app/immutable/entry/start.yWN0gSLA.js +1 -0
- package/ui/dist/_app/immutable/nodes/0.HKRDBYrC.js +1 -0
- package/ui/dist/_app/immutable/nodes/1.CLa0ydOi.js +1 -0
- package/ui/dist/_app/immutable/nodes/2.C9Kaym8C.js +8 -0
- package/ui/dist/_app/immutable/nodes/3.C1X4_rXZ.js +1 -0
- package/ui/dist/_app/immutable/nodes/4.DdzDIi9E.js +1 -0
- package/ui/dist/_app/immutable/nodes/5.DpbmCMdw.js +1 -0
- package/ui/dist/_app/version.json +1 -1
- package/ui/dist/index.html +12 -12
- package/CHANGELOG.md +0 -35
- package/components/identity.bans/tsconfig.tsbuildinfo +0 -1
- package/components/identity.basic/source/lib/credentials.test.ts +0 -18
- package/components/identity.basic/tsconfig.tsbuildinfo +0 -1
- package/components/identity.clients/source/lib/canonical.test.ts +0 -43
- package/components/identity.clients/source/lib/cimd.test.ts +0 -122
- package/components/identity.clients/source/lib/redirect.test.ts +0 -47
- package/components/identity.clients/tsconfig.tsbuildinfo +0 -1
- package/components/identity.credentials/source/list.test.ts +0 -70
- package/components/identity.credentials/tsconfig.tsbuildinfo +0 -1
- package/components/identity.federation/source/lib/discovery.test.ts +0 -60
- package/components/identity.federation/source/list.test.ts +0 -41
- package/components/identity.federation/tsconfig.tsbuildinfo +0 -1
- package/components/identity.grants/tsconfig.tsbuildinfo +0 -1
- package/components/identity.keys/tsconfig.tsbuildinfo +0 -1
- package/components/identity.otp/tsconfig.tsbuildinfo +0 -1
- package/components/identity.passkeys/source/errors.test.ts +0 -34
- package/components/identity.passkeys/source/webauthn.test.ts +0 -26
- package/components/identity.passkeys/tsconfig.tsbuildinfo +0 -1
- package/components/identity.roles/tsconfig.tsbuildinfo +0 -1
- package/components/identity.tokens/source/authenticate.test.ts +0 -112
- package/components/identity.tokens/source/decrypt.test.ts +0 -216
- package/components/identity.tokens/source/encrypt.test.ts +0 -150
- package/components/identity.tokens/source/issue.test.ts +0 -73
- package/components/identity.tokens/source/lib/form.test.ts +0 -25
- package/components/identity.tokens/source/lib/paseto.test.ts +0 -62
- package/components/identity.tokens/tsconfig.tsbuildinfo +0 -1
- package/context.toa.yaml +0 -31
- package/cucumber.mjs +0 -7
- package/documentation/.assets/ia3-dark.jpg +0 -0
- package/documentation/.assets/ia3-light.jpg +0 -0
- package/documentation/.assets/overview-dark.jpg +0 -0
- package/documentation/.assets/overview-light.jpg +0 -0
- package/documentation/.assets/role-scopes-dark.jpg +0 -0
- package/documentation/.assets/role-scopes-light.jpg +0 -0
- package/documentation/.assets/rtd-dark.jpg +0 -0
- package/documentation/.assets/rtd-light.jpg +0 -0
- package/documentation/access.md +0 -350
- package/documentation/authorities.md +0 -51
- package/documentation/cache.md +0 -72
- package/documentation/components.md +0 -472
- package/documentation/consent.md +0 -101
- package/documentation/credentials.md +0 -88
- package/documentation/dev.md +0 -30
- package/documentation/discovery.md +0 -81
- package/documentation/flow.md +0 -44
- package/documentation/help.md +0 -122
- package/documentation/identity.md +0 -304
- package/documentation/introspection.md +0 -123
- package/documentation/io.md +0 -167
- package/documentation/ip.md +0 -24
- package/documentation/map.md +0 -123
- package/documentation/mcp.md +0 -183
- package/documentation/notes/desync.jpg +0 -0
- package/documentation/notes/peers.md +0 -59
- package/documentation/notes/sse.md +0 -71
- package/documentation/notes/throttling.md +0 -122
- package/documentation/oauth.md +0 -180
- package/documentation/octets.md +0 -334
- package/documentation/passkeys.md +0 -11
- package/documentation/protocol.md +0 -120
- package/documentation/query.md +0 -324
- package/documentation/require.md +0 -15
- package/documentation/rpc.md +0 -154
- package/documentation/tracing.md +0 -70
- package/documentation/tree.md +0 -199
- package/features/access.feature +0 -596
- package/features/annotation.feature +0 -32
- package/features/auth.assert.feature +0 -55
- package/features/auth.bearer.feature +0 -120
- package/features/auth.claims.feature +0 -171
- package/features/auth.incept.feature +0 -166
- package/features/auth.input.feature +0 -59
- package/features/authorities.basic.feature +0 -141
- package/features/authorities.feature +0 -71
- package/features/authorities.federation.feature +0 -100
- package/features/authorities.tokens.feature +0 -117
- package/features/body.feature +0 -76
- package/features/cache.feature +0 -368
- package/features/configuration.feature +0 -206
- package/features/cors.feature +0 -127
- package/features/credentials.feature +0 -106
- package/features/debug.feature +0 -34
- package/features/dev.feature +0 -90
- package/features/directives.feature +0 -61
- package/features/discovery.feature +0 -213
- package/features/discovery.ui.feature +0 -213
- package/features/dynamic.feature +0 -192
- package/features/errors.feature +0 -258
- package/features/etag.feature +0 -239
- package/features/flow.feature +0 -148
- package/features/help.feature +0 -512
- package/features/identity.bans.feature +0 -200
- package/features/identity.basic.feature +0 -666
- package/features/identity.feature +0 -240
- package/features/identity.federation.feature +0 -396
- package/features/identity.otp.feature +0 -142
- package/features/identity.roles.feature +0 -568
- package/features/identity.tokens.custom.feature +0 -430
- package/features/identity.tokens.feature +0 -131
- package/features/interruptions.feature +0 -20
- package/features/introspection.feature +0 -565
- package/features/introspection.map.feature +0 -108
- package/features/io.feature +0 -204
- package/features/io.throttle.feature +0 -166
- package/features/map.feature +0 -360
- package/features/mcp.feature +0 -753
- package/features/methods.feature +0 -48
- package/features/oauth.clients.feature +0 -195
- package/features/oauth.discovery.feature +0 -164
- package/features/oauth.grants.feature +0 -301
- package/features/octets.cloudinary.feature +0 -233
- package/features/octets.download.feature +0 -194
- package/features/octets.entries.feature +0 -83
- package/features/octets.feature +0 -306
- package/features/octets.head.feature +0 -40
- package/features/octets.location.feature +0 -83
- package/features/octets.meta.feature +0 -117
- package/features/octets.workflows.feature +0 -565
- package/features/passkeys.feature +0 -66
- package/features/probes.feature +0 -18
- package/features/query.feature +0 -389
- package/features/realtime.feature +0 -34
- package/features/require.feature +0 -66
- package/features/response.feature +0 -103
- package/features/routes.feature +0 -224
- package/features/rpc.feature +0 -429
- package/features/server.feature +0 -21
- package/features/site/_app/immutable/asset.js +0 -1
- package/features/site/favicon.ico +0 -0
- package/features/site/index.html +0 -10
- package/features/steps/.env.example +0 -5
- package/features/steps/Captures.ts +0 -20
- package/features/steps/Cloudinary.ts +0 -12
- package/features/steps/Common.ts +0 -38
- package/features/steps/Components.ts +0 -115
- package/features/steps/Database.ts +0 -106
- package/features/steps/Gateway.ts +0 -240
- package/features/steps/HTTP.ts +0 -96
- package/features/steps/IDP.ts +0 -361
- package/features/steps/Identity.ts +0 -54
- package/features/steps/OTP.ts +0 -42
- package/features/steps/Parameters.ts +0 -162
- package/features/steps/Probe.ts +0 -38
- package/features/steps/Realtime.ts +0 -175
- package/features/steps/Workspace.ts +0 -48
- package/features/steps/components/audit/manifest.toa.yaml +0 -20
- package/features/steps/components/audit/operations/record.js +0 -5
- package/features/steps/components/echo/manifest.toa.yaml +0 -59
- package/features/steps/components/echo/operations/affect.js +0 -3
- package/features/steps/components/echo/operations/compute.js +0 -3
- package/features/steps/components/echo/operations/echo.js +0 -3
- package/features/steps/components/echo/operations/error.js +0 -7
- package/features/steps/components/echo/operations/identity.js +0 -3
- package/features/steps/components/echo/operations/parameters.js +0 -3
- package/features/steps/components/echo/operations/ping.js +0 -3
- package/features/steps/components/echo/operations/unwrap.js +0 -3
- package/features/steps/components/echo.beacon/manifest.toa.yaml +0 -2
- package/features/steps/components/echo.beacon/operations/hello.js +0 -3
- package/features/steps/components/greeter/manifest.toa.yaml +0 -5
- package/features/steps/components/greeter/operations/greet.js +0 -3
- package/features/steps/components/notify/manifest.toa.yaml +0 -20
- package/features/steps/components/notify/operations/send.js +0 -5
- package/features/steps/components/octets.tester/manifest.toa.yaml +0 -73
- package/features/steps/components/octets.tester/operations/authority.js +0 -3
- package/features/steps/components/octets.tester/operations/bar.js +0 -9
- package/features/steps/components/octets.tester/operations/baz.js +0 -9
- package/features/steps/components/octets.tester/operations/concat.js +0 -5
- package/features/steps/components/octets.tester/operations/echo.js +0 -5
- package/features/steps/components/octets.tester/operations/err.js +0 -14
- package/features/steps/components/octets.tester/operations/foo.js +0 -5
- package/features/steps/components/octets.tester/operations/id.js +0 -5
- package/features/steps/components/octets.tester/operations/identity.js +0 -5
- package/features/steps/components/octets.tester/operations/lenna.png +0 -0
- package/features/steps/components/octets.tester/operations/redirect.js +0 -17
- package/features/steps/components/octets.tester/operations/yex.js +0 -14
- package/features/steps/components/octets.tester/operations/yield.js +0 -11
- package/features/steps/components/orders/manifest.toa.yaml +0 -30
- package/features/steps/components/orders/operations/create.js +0 -7
- package/features/steps/components/pots/manifest.toa.yaml +0 -91
- package/features/steps/components/pots/migrations/0002-indexes.yaml +0 -4
- package/features/steps/components/pricing/manifest.toa.yaml +0 -13
- package/features/steps/components/pricing/operations/quote.js +0 -3
- package/features/steps/components/sequences/manifest.toa.yaml +0 -11
- package/features/steps/components/sequences/operations/numbers.js +0 -5
- package/features/steps/components/sequences/operations/tokens.js +0 -14
- package/features/steps/components/users/manifest.toa.yaml +0 -30
- package/features/steps/components/users/operations/create.js +0 -11
- package/features/steps/components/users.properties/manifest.toa.yaml +0 -22
- package/features/steps/map.ts +0 -30
- package/features/steps/tsconfig.json +0 -9
- package/features/streams.feature +0 -35
- package/features/timestamps.feature +0 -41
- package/features/timing.feature +0 -49
- package/features/tracing.feature +0 -123
- package/schemas/annotation.cos.yaml +0 -125
- package/schemas/call.cos.yaml +0 -18
- package/schemas/directive.cos.yaml +0 -7
- package/schemas/method.cos.yaml +0 -23
- package/schemas/node.cos.yaml +0 -22
- package/schemas/query.cos.yaml +0 -31
- package/schemas/querystring.cos.yaml +0 -19
- package/schemas/range.cos.yaml +0 -10
- package/schemas/route.cos.yaml +0 -6
- package/source/Annotation.ts +0 -89
- package/source/Branch.test.ts +0 -40
- package/source/Branch.ts +0 -44
- package/source/Composition.ts +0 -51
- package/source/Context.ts +0 -11
- package/source/Directive.test.ts +0 -199
- package/source/Directive.ts +0 -248
- package/source/Discovery/Explorer.ts +0 -34
- package/source/Discovery/Site.test.ts +0 -147
- package/source/Discovery/Site.ts +0 -202
- package/source/Discovery/index.ts +0 -3
- package/source/Discovery/tree.test.ts +0 -175
- package/source/Discovery/tree.ts +0 -77
- package/source/Discovery/trunk.ts +0 -33
- package/source/Endpoint.test.ts +0 -67
- package/source/Endpoint.ts +0 -157
- package/source/Factory.ts +0 -42
- package/source/Gateway.ts +0 -390
- package/source/HTTP/Context.ts +0 -143
- package/source/HTTP/Probe.ts +0 -99
- package/source/HTTP/Server.ts +0 -430
- package/source/HTTP/Timing.ts +0 -14
- package/source/HTTP/address.test.ts +0 -28
- package/source/HTTP/address.ts +0 -16
- package/source/HTTP/exceptions.ts +0 -99
- package/source/HTTP/formats/form.ts +0 -21
- package/source/HTTP/formats/index.ts +0 -36
- package/source/HTTP/formats/json.ts +0 -14
- package/source/HTTP/formats/msgpack.ts +0 -14
- package/source/HTTP/formats/text.ts +0 -10
- package/source/HTTP/formats/yaml.test.ts +0 -22
- package/source/HTTP/formats/yaml.ts +0 -40
- package/source/HTTP/index.ts +0 -6
- package/source/HTTP/messages.test.ts +0 -196
- package/source/HTTP/messages.ts +0 -186
- package/source/HTTP/types.ts +0 -39
- package/source/Interception.ts +0 -37
- package/source/Introspection.ts +0 -179
- package/source/MCP/Server.ts +0 -335
- package/source/MCP/discover.ts +0 -51
- package/source/MCP/errors.ts +0 -80
- package/source/MCP/index.ts +0 -1
- package/source/MCP/schema.test.ts +0 -91
- package/source/MCP/schema.ts +0 -94
- package/source/MCP/tools.ts +0 -144
- package/source/MCP/types.ts +0 -84
- package/source/Mapping.ts +0 -101
- package/source/Query.test.ts +0 -54
- package/source/Query.ts +0 -277
- package/source/RPC/Context.ts +0 -75
- package/source/RPC/Dispatcher.ts +0 -150
- package/source/RPC/errors.test.ts +0 -77
- package/source/RPC/errors.ts +0 -82
- package/source/RPC/index.ts +0 -1
- package/source/RPC/names.test.ts +0 -141
- package/source/RPC/names.ts +0 -176
- package/source/RPC/types.ts +0 -34
- package/source/RTD/Context.ts +0 -16
- package/source/RTD/Directives.ts +0 -126
- package/source/RTD/Endpoint.ts +0 -27
- package/source/RTD/Match.ts +0 -11
- package/source/RTD/Method.ts +0 -39
- package/source/RTD/Node.ts +0 -169
- package/source/RTD/Route.ts +0 -93
- package/source/RTD/Tree.ts +0 -137
- package/source/RTD/expiration.test.ts +0 -81
- package/source/RTD/factory.ts +0 -105
- package/source/RTD/index.ts +0 -8
- package/source/RTD/segment.test.ts +0 -35
- package/source/RTD/segment.ts +0 -51
- package/source/RTD/syntax/index.ts +0 -2
- package/source/RTD/syntax/parse.test.ts +0 -196
- package/source/RTD/syntax/parse.ts +0 -171
- package/source/RTD/syntax/types.ts +0 -69
- package/source/RTD/walk.test.ts +0 -147
- package/source/Remotes.test.ts +0 -79
- package/source/Remotes.ts +0 -39
- package/source/Tenant.ts +0 -73
- package/source/const.ts +0 -45
- package/source/deployment.ts +0 -96
- package/source/directives/auth/Anonymous.test.ts +0 -70
- package/source/directives/auth/Anonymous.ts +0 -36
- package/source/directives/auth/Anyone.ts +0 -23
- package/source/directives/auth/Assert.ts +0 -43
- package/source/directives/auth/Authorization.test.ts +0 -24
- package/source/directives/auth/Authorization.ts +0 -388
- package/source/directives/auth/Delegate.test.ts +0 -36
- package/source/directives/auth/Delegate.ts +0 -54
- package/source/directives/auth/Echo.ts +0 -24
- package/source/directives/auth/Federation.ts +0 -104
- package/source/directives/auth/Id.ts +0 -37
- package/source/directives/auth/Incept.ts +0 -117
- package/source/directives/auth/Input.ts +0 -92
- package/source/directives/auth/Role.test.ts +0 -147
- package/source/directives/auth/Role.ts +0 -99
- package/source/directives/auth/Rule.ts +0 -59
- package/source/directives/auth/Scheme.ts +0 -31
- package/source/directives/auth/create.ts +0 -11
- package/source/directives/auth/index.ts +0 -3
- package/source/directives/auth/schemes.test.ts +0 -18
- package/source/directives/auth/schemes.ts +0 -39
- package/source/directives/auth/split.ts +0 -14
- package/source/directives/auth/types.ts +0 -75
- package/source/directives/cache/Cache.ts +0 -92
- package/source/directives/cache/Control.ts +0 -81
- package/source/directives/cache/Exact.ts +0 -7
- package/source/directives/cache/etag.ts +0 -38
- package/source/directives/cache/index.ts +0 -3
- package/source/directives/cache/types.ts +0 -9
- package/source/directives/cors/CORS.test.ts +0 -75
- package/source/directives/cors/CORS.ts +0 -88
- package/source/directives/cors/index.ts +0 -3
- package/source/directives/dev/Development.ts +0 -41
- package/source/directives/dev/Faulty.ts +0 -31
- package/source/directives/dev/Sleep.ts +0 -53
- package/source/directives/dev/Stub.ts +0 -14
- package/source/directives/dev/Throw.ts +0 -14
- package/source/directives/dev/index.ts +0 -3
- package/source/directives/dev/types.ts +0 -5
- package/source/directives/flow/Compose.ts +0 -98
- package/source/directives/flow/Fetch.ts +0 -86
- package/source/directives/flow/Flow.ts +0 -43
- package/source/directives/flow/index.ts +0 -3
- package/source/directives/flow/types.ts +0 -7
- package/source/directives/help/Family.ts +0 -122
- package/source/directives/help/Help.test.ts +0 -227
- package/source/directives/help/Help.ts +0 -47
- package/source/directives/help/Parameters.ts +0 -47
- package/source/directives/help/described.ts +0 -57
- package/source/directives/help/index.ts +0 -45
- package/source/directives/index.ts +0 -33
- package/source/directives/io/Directive.ts +0 -17
- package/source/directives/io/IO.ts +0 -118
- package/source/directives/io/Input.ts +0 -55
- package/source/directives/io/Message.ts +0 -1
- package/source/directives/io/Output.ts +0 -81
- package/source/directives/io/Status.test.ts +0 -88
- package/source/directives/io/Status.ts +0 -47
- package/source/directives/io/Throttle.ts +0 -30
- package/source/directives/io/index.ts +0 -3
- package/source/directives/io/lib/throttle/Configuration.test.ts +0 -72
- package/source/directives/io/lib/throttle/Configuration.ts +0 -68
- package/source/directives/io/lib/throttle/Keys.ts +0 -53
- package/source/directives/io/lib/throttle/Quotas.test.ts +0 -411
- package/source/directives/io/lib/throttle/Quotas.ts +0 -190
- package/source/directives/io/lib/throttle/Sync.test.ts +0 -163
- package/source/directives/io/lib/throttle/Sync.ts +0 -93
- package/source/directives/io/lib/throttle/Warning.test.ts +0 -32
- package/source/directives/io/lib/throttle/Warning.ts +0 -29
- package/source/directives/io/lib/throttle/components/Component.ts +0 -7
- package/source/directives/io/lib/throttle/components/IP.ts +0 -30
- package/source/directives/io/lib/throttle/components/Identity.ts +0 -19
- package/source/directives/io/lib/throttle/components/Path.ts +0 -8
- package/source/directives/io/lib/throttle/components/Route.ts +0 -19
- package/source/directives/io/lib/throttle/components/Segment.ts +0 -19
- package/source/directives/io/lib/throttle/components/index.ts +0 -19
- package/source/directives/io/lib/throttle/conditions/Condition.ts +0 -5
- package/source/directives/io/lib/throttle/conditions/Status.ts +0 -17
- package/source/directives/io/lib/throttle/conditions/index.ts +0 -11
- package/source/directives/io/lib/throttle/index.ts +0 -4
- package/source/directives/io/schemas.test.ts +0 -40
- package/source/directives/io/schemas.ts +0 -16
- package/source/directives/map/Authority.ts +0 -15
- package/source/directives/map/Buffer.ts +0 -15
- package/source/directives/map/Claims.ts +0 -63
- package/source/directives/map/Directive.ts +0 -4
- package/source/directives/map/Headers.ts +0 -60
- package/source/directives/map/Language.ts +0 -45
- package/source/directives/map/Languages.ts +0 -17
- package/source/directives/map/Map.ts +0 -85
- package/source/directives/map/Mapping.ts +0 -45
- package/source/directives/map/Properties.ts +0 -15
- package/source/directives/map/Segments.ts +0 -52
- package/source/directives/map/index.ts +0 -3
- package/source/directives/mcp/MCP.ts +0 -33
- package/source/directives/mcp/Tool.test.ts +0 -56
- package/source/directives/mcp/Tool.ts +0 -32
- package/source/directives/mcp/index.ts +0 -6
- package/source/directives/oauth/Discovery.ts +0 -66
- package/source/directives/oauth/documents.ts +0 -110
- package/source/directives/oauth/index.ts +0 -3
- package/source/directives/octets/Context.ts +0 -23
- package/source/directives/octets/Delete.ts +0 -96
- package/source/directives/octets/Directive.ts +0 -21
- package/source/directives/octets/Get.ts +0 -88
- package/source/directives/octets/Octets.ts +0 -82
- package/source/directives/octets/Put.ts +0 -186
- package/source/directives/octets/Workflow.ts +0 -60
- package/source/directives/octets/bytes.test.ts +0 -33
- package/source/directives/octets/bytes.ts +0 -18
- package/source/directives/octets/index.ts +0 -3
- package/source/directives/octets/schemas.test.ts +0 -20
- package/source/directives/octets/schemas.ts +0 -15
- package/source/directives/octets/types.ts +0 -9
- package/source/directives/octets/workflows/Execution.ts +0 -130
- package/source/directives/octets/workflows/Workflow.ts +0 -51
- package/source/directives/octets/workflows/index.ts +0 -1
- package/source/directives/require/Directive.ts +0 -5
- package/source/directives/require/Headers.ts +0 -19
- package/source/directives/require/Require.ts +0 -27
- package/source/directives/require/index.ts +0 -3
- package/source/discovery.ts +0 -1
- package/source/exceptions.ts +0 -47
- package/source/index.ts +0 -12
- package/source/io.ts +0 -4
- package/source/manifest.test.ts +0 -56
- package/source/manifest.ts +0 -56
- package/source/octets.d.ts +0 -17
- package/source/root.ts +0 -59
- package/source/schemas.test.ts +0 -31
- package/source/schemas.ts +0 -15
- package/source/service.ts +0 -94
- package/source/shortcuts.ts +0 -14
- package/source/userland.ts +0 -47
- package/transpiled/Annotation.d.ts +0 -70
- package/transpiled/Annotation.js +0 -2
- package/transpiled/Annotation.js.map +0 -1
- package/transpiled/RTD/syntax/parse.d.ts +0 -4
- package/transpiled/RTD/syntax/parse.js +0 -112
- package/transpiled/RTD/syntax/parse.js.map +0 -1
- package/transpiled/RTD/syntax/types.d.ts +0 -52
- package/transpiled/RTD/syntax/types.js +0 -11
- package/transpiled/RTD/syntax/types.js.map +0 -1
- package/transpiled/const.d.ts +0 -36
- package/transpiled/const.js +0 -37
- package/transpiled/const.js.map +0 -1
- package/transpiled/deployment.d.ts +0 -6
- package/transpiled/deployment.js +0 -76
- package/transpiled/deployment.js.map +0 -1
- package/transpiled/manifest.d.ts +0 -3
- package/transpiled/manifest.js +0 -39
- package/transpiled/manifest.js.map +0 -1
- package/transpiled/schemas.d.ts +0 -9
- package/transpiled/schemas.js +0 -9
- package/transpiled/schemas.js.map +0 -1
- package/transpiled/shortcuts.d.ts +0 -3
- package/transpiled/shortcuts.js +0 -13
- package/transpiled/shortcuts.js.map +0 -1
- package/tsconfig.json +0 -13
- package/tsconfig.tsbuildinfo +0 -1
- package/ui/dist/_app/immutable/assets/0.Bl7vLmIK.css +0 -2
- package/ui/dist/_app/immutable/assets/2.BC0-Jhqu.css +0 -1
- package/ui/dist/_app/immutable/chunks/B_pK3U1C.js +0 -6
- package/ui/dist/_app/immutable/chunks/CiKbPLyY.js +0 -1
- package/ui/dist/_app/immutable/chunks/DjIYL2zC.js +0 -3
- package/ui/dist/_app/immutable/entry/app.DMqmL4NY.js +0 -2
- package/ui/dist/_app/immutable/entry/start.CRe7HWBI.js +0 -1
- package/ui/dist/_app/immutable/nodes/0.D9m-6cbM.js +0 -1
- package/ui/dist/_app/immutable/nodes/1.Cgi_RcSO.js +0 -1
- package/ui/dist/_app/immutable/nodes/2.D_Cbxgz4.js +0 -14
package/source/Gateway.ts
DELETED
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert'
|
|
2
|
-
import { setTimeout } from 'node:timers/promises'
|
|
3
|
-
import { console } from 'openspan'
|
|
4
|
-
import { Connector } from '@toa.io/core'
|
|
5
|
-
import type { bindings } from '@toa.io/core/types'
|
|
6
|
-
import * as http from './HTTP/index.js'
|
|
7
|
-
import { DISCOVERY, MCP, RPC } from './const.js'
|
|
8
|
-
import { rethrow } from './exceptions.js'
|
|
9
|
-
import { decide } from './Branch.js'
|
|
10
|
-
import { describing } from './Introspection.js'
|
|
11
|
-
import { Explorer, looking } from './Discovery/index.js'
|
|
12
|
-
import type { Interception } from './Interception.js'
|
|
13
|
-
import type { Dispatcher } from './RPC/index.js'
|
|
14
|
-
import type { Server } from './MCP/index.js'
|
|
15
|
-
import type {
|
|
16
|
-
DirectiveFactory,
|
|
17
|
-
Method,
|
|
18
|
-
Node,
|
|
19
|
-
Parameter,
|
|
20
|
-
Tree,
|
|
21
|
-
Match
|
|
22
|
-
} from './RTD/index.js'
|
|
23
|
-
import type { Label } from './discovery.js'
|
|
24
|
-
import type { Branch, Exposed } from './Branch.js'
|
|
25
|
-
|
|
26
|
-
export class Gateway extends Connector {
|
|
27
|
-
private readonly broadcast: Broadcast
|
|
28
|
-
private readonly tree: Tree
|
|
29
|
-
private readonly interceptor: Interception
|
|
30
|
-
private readonly directives: DirectiveFactory
|
|
31
|
-
|
|
32
|
-
/** JSON-RPC is served only where the annotation asked for it. */
|
|
33
|
-
private readonly dispatcher: Dispatcher | null
|
|
34
|
-
|
|
35
|
-
/** And the same of MCP. */
|
|
36
|
-
private readonly mcp: Server | null
|
|
37
|
-
|
|
38
|
-
/** The tree, for every route at once. Served always, and so not nullable. */
|
|
39
|
-
private readonly explorer: Explorer
|
|
40
|
-
private readonly branches = new Map<string, Exposed>()
|
|
41
|
-
private lastMerge = 0
|
|
42
|
-
private widestGap = 0
|
|
43
|
-
private lastPing = 0
|
|
44
|
-
private stopped = false
|
|
45
|
-
private resolveFirstMerge: (() => void) | null = null
|
|
46
|
-
|
|
47
|
-
// eslint-disable-next-line max-params
|
|
48
|
-
public constructor(
|
|
49
|
-
broadcast: Broadcast,
|
|
50
|
-
tree: Tree,
|
|
51
|
-
interception: Interception,
|
|
52
|
-
directives: DirectiveFactory,
|
|
53
|
-
dispatcher: Dispatcher | null,
|
|
54
|
-
mcp: Server | null
|
|
55
|
-
) {
|
|
56
|
-
super()
|
|
57
|
-
|
|
58
|
-
this.broadcast = broadcast
|
|
59
|
-
this.tree = tree
|
|
60
|
-
this.interceptor = interception
|
|
61
|
-
this.directives = directives
|
|
62
|
-
this.dispatcher = dispatcher
|
|
63
|
-
this.mcp = mcp
|
|
64
|
-
this.explorer = new Explorer(tree)
|
|
65
|
-
|
|
66
|
-
this.depends(broadcast)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
public async process(context: http.Context): Promise<http.OutgoingMessage> {
|
|
70
|
-
const interception = await this.interceptor.intercept(context)
|
|
71
|
-
|
|
72
|
-
if (interception !== null) return interception
|
|
73
|
-
|
|
74
|
-
// request-scoped, before anything is routed: this is where a credential is read
|
|
75
|
-
await this.directives.preflight(context).catch(rethrow)
|
|
76
|
-
|
|
77
|
-
const response = await this.endpoint(context)
|
|
78
|
-
|
|
79
|
-
// request-scoped, on whatever is going back: this is where a credential is re-issued
|
|
80
|
-
await this.directives.depart(context, response).catch(rethrow)
|
|
81
|
-
|
|
82
|
-
return response
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* What answers the request: a pinned endpoint that makes calls of its own, or the route
|
|
87
|
-
* the path names.
|
|
88
|
-
*/
|
|
89
|
-
private async endpoint(context: http.Context): Promise<http.OutgoingMessage> {
|
|
90
|
-
const route: http.Processor = async (call) => await this.route(call)
|
|
91
|
-
|
|
92
|
-
if (this.dispatcher !== null && context.url.pathname === RPC)
|
|
93
|
-
return await this.dispatcher.dispatch(context, route)
|
|
94
|
-
|
|
95
|
-
if (this.mcp !== null && context.url.pathname === MCP)
|
|
96
|
-
return await this.mcp.process(context, route)
|
|
97
|
-
|
|
98
|
-
// the page under this prefix is an interceptor's, and has already answered
|
|
99
|
-
if (context.url.pathname === DISCOVERY || context.url.pathname === DISCOVERY + '/')
|
|
100
|
-
return await this.explorer.process(context)
|
|
101
|
-
|
|
102
|
-
// a browser that asked for the trunk of an API is looking for the page, and where the
|
|
103
|
-
// application answers there itself, that is what answers
|
|
104
|
-
if (context.url.pathname === '/' && !this.serves(context)) {
|
|
105
|
-
const page = looking(context)
|
|
106
|
-
|
|
107
|
-
if (page !== null) return page
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return await this.route(context)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/** Whether the application serves the trunk with the verb the request was made with. */
|
|
114
|
-
private serves(context: http.Context): boolean {
|
|
115
|
-
const match = this.tree.match('/')
|
|
116
|
-
|
|
117
|
-
return match !== null && context.request.method in match.node.methods
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* One call: everything that needs a node. A request makes one of these, and a request
|
|
122
|
-
* that carries several calls makes one per call.
|
|
123
|
-
*/
|
|
124
|
-
private async route(context: http.Context): Promise<http.OutgoingMessage> {
|
|
125
|
-
const { node, parameters } = this.match(context)
|
|
126
|
-
|
|
127
|
-
if (context.request.method === 'OPTIONS')
|
|
128
|
-
return await this.explain(context, node, parameters)
|
|
129
|
-
|
|
130
|
-
let verb = context.request.method
|
|
131
|
-
|
|
132
|
-
if (!(verb in node.methods) && verb === 'HEAD' && 'GET' in node.methods) verb = 'GET'
|
|
133
|
-
|
|
134
|
-
if (!(verb in node.methods)) throw new http.MethodNotAllowed()
|
|
135
|
-
|
|
136
|
-
const method = node.methods[verb]
|
|
137
|
-
|
|
138
|
-
const interruption = await method.directives
|
|
139
|
-
.precall(context, parameters)
|
|
140
|
-
.catch(rethrow)
|
|
141
|
-
const response = interruption ?? (await this.call(method, context, parameters))
|
|
142
|
-
|
|
143
|
-
await method.directives.settle(context, response).catch(rethrow)
|
|
144
|
-
|
|
145
|
-
return response
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
protected override async open(): Promise<void> {
|
|
149
|
-
await this.discover()
|
|
150
|
-
|
|
151
|
-
// what is served besides the tree, so that turning one on can be seen to have worked
|
|
152
|
-
const pinned: string[] = []
|
|
153
|
-
|
|
154
|
-
if (this.dispatcher !== null) pinned.push(RPC)
|
|
155
|
-
|
|
156
|
-
if (this.mcp !== null) pinned.push(MCP)
|
|
157
|
-
|
|
158
|
-
console.info('Gateway started', {
|
|
159
|
-
endpoints: pinned.length === 0 ? 'none' : pinned.join(' ')
|
|
160
|
-
})
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Both of these reach into components, and a dependency is torn down only once this has
|
|
165
|
-
* returned — where `dispose` runs after every one of them already has. The throttling
|
|
166
|
-
* ticker firing in between calls an endpoint that has just been unbound, and reports the
|
|
167
|
-
* refusal as a failure to reconcile.
|
|
168
|
-
*/
|
|
169
|
-
protected override async close(): Promise<void> {
|
|
170
|
-
this.stopped = true
|
|
171
|
-
|
|
172
|
-
this.tree.dispose()
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
protected override dispose(): void {
|
|
176
|
-
console.info('Gateway is closed')
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
private match(context: http.Context): Match {
|
|
180
|
-
const match = this.tree.match(context.url.pathname)
|
|
181
|
-
|
|
182
|
-
if (match === null) {
|
|
183
|
-
// the route may be missing because an expose has been lost
|
|
184
|
-
this.reping()
|
|
185
|
-
|
|
186
|
-
throw new http.NotFound('Route not found')
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (match.node.forward === null) return match
|
|
190
|
-
|
|
191
|
-
const destination = match.node.forward.replace(/\/:([^/]+)/g, (_, name) => {
|
|
192
|
-
const value = match.parameters.find((parameter) => parameter.name === name)?.value
|
|
193
|
-
|
|
194
|
-
assert.ok(value !== undefined, `Forwarded parameter '${name}' not found`)
|
|
195
|
-
|
|
196
|
-
return `/${value}`
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
const forward = this.tree.match(destination)
|
|
200
|
-
|
|
201
|
-
assert.ok(forward !== null, 'Forwarded route not found')
|
|
202
|
-
|
|
203
|
-
return forward
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
private async call(
|
|
207
|
-
method: Method,
|
|
208
|
-
context: http.Context,
|
|
209
|
-
parameters: Parameter[]
|
|
210
|
-
): Promise<http.OutgoingMessage> {
|
|
211
|
-
if (context.url.pathname[context.url.pathname.length - 1] !== '/')
|
|
212
|
-
throw new http.NotFound('Trailing slash is required')
|
|
213
|
-
|
|
214
|
-
if (context.encoder === null) throw new http.NotAcceptable()
|
|
215
|
-
|
|
216
|
-
if (method.endpoint === null) throw new http.MethodNotAllowed()
|
|
217
|
-
|
|
218
|
-
return (await method.endpoint
|
|
219
|
-
.call(context, parameters)
|
|
220
|
-
.catch(rethrow)) as http.OutgoingMessage
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
private async explain(
|
|
224
|
-
context: http.Context,
|
|
225
|
-
node: Node,
|
|
226
|
-
parameters: Parameter[]
|
|
227
|
-
): Promise<http.OutgoingMessage> {
|
|
228
|
-
const { described, methods } = await node.explain(describing(context), parameters)
|
|
229
|
-
const verbs = Object.keys(methods)
|
|
230
|
-
|
|
231
|
-
// what a caller may not use is not a resource to them, and describing it would be the leak
|
|
232
|
-
if (verbs.length === 0 && Object.keys(node.methods).length > 0)
|
|
233
|
-
throw new http.Forbidden()
|
|
234
|
-
|
|
235
|
-
// what the resource is, beside the methods it serves; a verb is upper case and cannot
|
|
236
|
-
// collide with either key
|
|
237
|
-
return {
|
|
238
|
-
body: { ...described, ...methods },
|
|
239
|
-
headers: new Headers({ allow: verbs.join(', ') })
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
private async discover(): Promise<void> {
|
|
244
|
-
const first = new Promise<void>((resolve) => {
|
|
245
|
-
this.resolveFirstMerge = resolve
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
await this.broadcast.receive<Branch>('expose', this.merge.bind(this))
|
|
249
|
-
|
|
250
|
-
void this.knock()
|
|
251
|
-
|
|
252
|
-
await this.settled(first)
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* A single ping is enough only if every tenant is listening by then, which is
|
|
257
|
-
* not the case while the deployment is still rolling out.
|
|
258
|
-
*/
|
|
259
|
-
private async knock(): Promise<void> {
|
|
260
|
-
for (const delay of KNOCK_DELAYS) {
|
|
261
|
-
if (this.stopped) return
|
|
262
|
-
|
|
263
|
-
if (delay > 0) await setTimeout(delay, undefined, { ref: false })
|
|
264
|
-
|
|
265
|
-
await this.ping()
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
private async ping(): Promise<void> {
|
|
270
|
-
if (this.stopped) return
|
|
271
|
-
|
|
272
|
-
this.lastPing = Date.now()
|
|
273
|
-
|
|
274
|
-
await this.broadcast
|
|
275
|
-
.transmit<null>('ping', null)
|
|
276
|
-
.catch((exception: Error) =>
|
|
277
|
-
console.error('Discovery ping failed', { message: exception.message })
|
|
278
|
-
)
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
private reping(): void {
|
|
282
|
-
if (Date.now() - this.lastPing < PING_COOLDOWN) return
|
|
283
|
-
|
|
284
|
-
void this.ping()
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
private async settled(first: Promise<void>): Promise<void> {
|
|
288
|
-
const deadline = Date.now() + SETTLE_TIMEOUT
|
|
289
|
-
const abort = new AbortController()
|
|
290
|
-
|
|
291
|
-
// an uncancelled timer keeps the process alive long after the race is won
|
|
292
|
-
await Promise.race([
|
|
293
|
-
first,
|
|
294
|
-
setTimeout(SETTLE_TIMEOUT, undefined, { signal: abort.signal })
|
|
295
|
-
])
|
|
296
|
-
.finally(() => {
|
|
297
|
-
abort.abort()
|
|
298
|
-
})
|
|
299
|
-
.catch(() => {})
|
|
300
|
-
|
|
301
|
-
if (this.lastMerge === 0) {
|
|
302
|
-
console.warn('Discovery timed out waiting for the first expose')
|
|
303
|
-
|
|
304
|
-
return
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
while (Date.now() - this.lastMerge < this.quiet()) {
|
|
308
|
-
if (Date.now() >= deadline) break
|
|
309
|
-
|
|
310
|
-
await setTimeout(SETTLE_POLL)
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* How long the branches must stay quiet before discovery counts as settled.
|
|
316
|
-
*
|
|
317
|
-
* Every tenant of a local composition answers the first ping at once, so a short window
|
|
318
|
-
* is enough; a rolling deployment brings them up seconds apart, and the window grows with
|
|
319
|
-
* the widest gap seen so far to keep waiting for the ones still starting.
|
|
320
|
-
*/
|
|
321
|
-
private quiet(): number {
|
|
322
|
-
const adaptive = this.widestGap * SETTLE_QUIET_FACTOR
|
|
323
|
-
|
|
324
|
-
return Math.min(Math.max(adaptive, SETTLE_QUIET_MIN), SETTLE_QUIET_MAX)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
private merge(branch: Branch): void {
|
|
328
|
-
const id = branch.namespace + '.' + branch.component
|
|
329
|
-
|
|
330
|
-
const attributes = {
|
|
331
|
-
namespace: branch.namespace,
|
|
332
|
-
component: branch.component,
|
|
333
|
-
version: branch.version
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const exposed = this.branches.get(id)
|
|
337
|
-
|
|
338
|
-
if (exposed !== undefined)
|
|
339
|
-
switch (decide(exposed, branch)) {
|
|
340
|
-
// rebuilding an identical branch would only tear down its live endpoints
|
|
341
|
-
case 'refresh':
|
|
342
|
-
this.tree.refresh(exposed.nodes)
|
|
343
|
-
console.trace('Branch refreshed', attributes)
|
|
344
|
-
|
|
345
|
-
return
|
|
346
|
-
|
|
347
|
-
case 'superseded':
|
|
348
|
-
console.debug('Branch superseded', {
|
|
349
|
-
...attributes,
|
|
350
|
-
timestamp: branch.timestamp,
|
|
351
|
-
exposed: exposed.timestamp
|
|
352
|
-
})
|
|
353
|
-
|
|
354
|
-
return
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
let nodes: Node[]
|
|
358
|
-
|
|
359
|
-
try {
|
|
360
|
-
nodes = this.tree.merge(branch.node, branch)
|
|
361
|
-
} catch (exception: unknown) {
|
|
362
|
-
const message = exception instanceof Error ? exception.message : 'Unknown error'
|
|
363
|
-
|
|
364
|
-
console.error('Branch merge exception', { message, ...attributes })
|
|
365
|
-
|
|
366
|
-
return
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
this.branches.set(id, { version: branch.version, timestamp: branch.timestamp, nodes })
|
|
370
|
-
|
|
371
|
-
if (this.lastMerge !== 0)
|
|
372
|
-
this.widestGap = Math.max(this.widestGap, Date.now() - this.lastMerge)
|
|
373
|
-
|
|
374
|
-
this.lastMerge = Date.now()
|
|
375
|
-
this.resolveFirstMerge?.()
|
|
376
|
-
this.resolveFirstMerge = null
|
|
377
|
-
|
|
378
|
-
console.info('Branch merged', attributes)
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
export type Broadcast = bindings.Broadcast<Label>
|
|
383
|
-
|
|
384
|
-
const SETTLE_QUIET_MIN = 500
|
|
385
|
-
const SETTLE_QUIET_MAX = 10_000
|
|
386
|
-
const SETTLE_QUIET_FACTOR = 2
|
|
387
|
-
const SETTLE_TIMEOUT = 30_000
|
|
388
|
-
const SETTLE_POLL = 50
|
|
389
|
-
const KNOCK_DELAYS = [0, 500, 1000, 1500]
|
|
390
|
-
const PING_COOLDOWN = 5_000
|
package/source/HTTP/Context.ts
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { buffer } from 'node:stream/consumers'
|
|
2
|
-
import Negotiator from 'negotiator'
|
|
3
|
-
import { console } from 'openspan'
|
|
4
|
-
import { Timing } from './Timing.js'
|
|
5
|
-
import { type Format, formats, types } from './formats/index.js'
|
|
6
|
-
import { read } from './messages.js'
|
|
7
|
-
import { address } from './address.js'
|
|
8
|
-
import type { OutgoingMessage } from './messages.js'
|
|
9
|
-
import type { IncomingMessage } from './types.js'
|
|
10
|
-
|
|
11
|
-
export class Context {
|
|
12
|
-
public readonly authority: string
|
|
13
|
-
public readonly request: IncomingMessage
|
|
14
|
-
|
|
15
|
-
/** the client address, read as the deployment says; none otherwise, see `documentation/ip.md` */
|
|
16
|
-
public readonly ip: string | undefined
|
|
17
|
-
public readonly url: URL
|
|
18
|
-
public readonly subtype: string | null = null
|
|
19
|
-
public readonly encoder: Format | null = null
|
|
20
|
-
public readonly timing: Timing
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Whether this is a procedure a request made, rather than the request. What forks one
|
|
24
|
-
* says so, and a directive that answers differently to a procedure than to a request
|
|
25
|
-
* reads it here.
|
|
26
|
-
*/
|
|
27
|
-
public readonly procedural: boolean = false
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Whether this describes a resource rather than calling one. What builds a describing
|
|
31
|
-
* context says so, and a directive that answers differently to a description than to a
|
|
32
|
-
* call reads it here.
|
|
33
|
-
*/
|
|
34
|
-
public readonly exploratory: boolean = false
|
|
35
|
-
|
|
36
|
-
public readonly pipelines: Pipelines = {
|
|
37
|
-
body: [],
|
|
38
|
-
response: []
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
private consumed = false
|
|
42
|
-
|
|
43
|
-
// eslint-disable-next-line max-params
|
|
44
|
-
public constructor(
|
|
45
|
-
authority: string,
|
|
46
|
-
request: IncomingMessage,
|
|
47
|
-
properties: Properties,
|
|
48
|
-
url: URL
|
|
49
|
-
) {
|
|
50
|
-
this.authority = authority
|
|
51
|
-
this.request = request
|
|
52
|
-
this.ip = address(request, properties.ip)
|
|
53
|
-
|
|
54
|
-
// parsed by the server, which had to parse it anyway to know the request is valid
|
|
55
|
-
this.url = url
|
|
56
|
-
this.timing = new Timing()
|
|
57
|
-
this.log(request)
|
|
58
|
-
|
|
59
|
-
const accept = this.request.headers.accept
|
|
60
|
-
|
|
61
|
-
if (accept !== undefined) {
|
|
62
|
-
const match = SUBTYPE.exec(accept)
|
|
63
|
-
|
|
64
|
-
if (match !== null) {
|
|
65
|
-
const { type, subtype, suffix } = match.groups!
|
|
66
|
-
|
|
67
|
-
this.request.headers.accept = `${type}/${suffix}`
|
|
68
|
-
this.subtype = subtype
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const encoder = negotiate(this.request)
|
|
73
|
-
|
|
74
|
-
if (encoder !== undefined) this.encoder = encoder
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
public async buffer(): Promise<Buffer> {
|
|
78
|
-
this.consumed = true
|
|
79
|
-
|
|
80
|
-
return await buffer(this.request)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public async body<T>(): Promise<T> {
|
|
84
|
-
let value = this.consumed ? null : await read(this)
|
|
85
|
-
|
|
86
|
-
for (const transform of this.pipelines.body) value = await transform(value)
|
|
87
|
-
|
|
88
|
-
return value
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
private log(request: IncomingMessage): void {
|
|
92
|
-
// built only when the line is written, which at `info` it is not
|
|
93
|
-
console.debug('Received request', () => {
|
|
94
|
-
const headers = { ...request.headers }
|
|
95
|
-
|
|
96
|
-
if (headers.authorization !== undefined)
|
|
97
|
-
headers.authorization = SCHEME.exec(headers.authorization)?.[1] ?? '[malformed]'
|
|
98
|
-
|
|
99
|
-
return { method: request.method, url: request.url, headers }
|
|
100
|
-
})
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** The scheme of an `authorization` header; the value after it is a credential. */
|
|
105
|
-
const SCHEME = /^(\w{1,32})(?: |$)/
|
|
106
|
-
|
|
107
|
-
interface Pipelines {
|
|
108
|
-
body: Array<(input: unknown) => unknown>
|
|
109
|
-
response: Array<(output: OutgoingMessage) => void | Promise<void>>
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
interface Properties {
|
|
113
|
-
/** the header the client address is read from; the connection's without one */
|
|
114
|
-
ip?: string
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Negotiation parses the header and sorts the candidates, and the value repeats:
|
|
119
|
-
* clients send one of a handful of `accept` strings. Bounded, the header is theirs.
|
|
120
|
-
*/
|
|
121
|
-
function negotiate(request: IncomingMessage): Format | undefined {
|
|
122
|
-
const accept = request.headers.accept ?? ''
|
|
123
|
-
const known = NEGOTIATED.get(accept)
|
|
124
|
-
|
|
125
|
-
if (known !== undefined) return known === NONE ? undefined : known
|
|
126
|
-
|
|
127
|
-
const mediaType = new Negotiator(request).mediaType(types)
|
|
128
|
-
const encoder = mediaType === undefined ? undefined : formats[mediaType]
|
|
129
|
-
|
|
130
|
-
if (NEGOTIATED.size >= NEGOTIATED_LIMIT) NEGOTIATED.clear()
|
|
131
|
-
|
|
132
|
-
NEGOTIATED.set(accept, encoder ?? NONE)
|
|
133
|
-
|
|
134
|
-
return encoder
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/** distinguishes "negotiated to nothing" from "not negotiated yet" */
|
|
138
|
-
const NONE = Symbol('not acceptable') as unknown as Format
|
|
139
|
-
const NEGOTIATED = new Map<string, Format>()
|
|
140
|
-
const NEGOTIATED_LIMIT = 1024
|
|
141
|
-
|
|
142
|
-
const SUBTYPE =
|
|
143
|
-
/^(?<type>\w{1,32})\/(vnd\.toa\.(?<subtype>\S{1,32})\+)(?<suffix>\S{1,32})$/
|
package/source/HTTP/Probe.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import * as http from 'node:http'
|
|
2
|
-
import { console } from 'openspan'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* The readiness probe, on a port of its own.
|
|
6
|
-
*
|
|
7
|
-
* It cannot share the port the gateway serves traffic on: kubelet speaks HTTP/1.1 only, and a
|
|
8
|
-
* cleartext HTTP/2 server answers nothing else on its port — there is no ALPN to negotiate with.
|
|
9
|
-
*
|
|
10
|
-
* It is the gateway's own readiness, not the process's. The identity composition nested in this
|
|
11
|
-
* process connects before route discovery has settled, so a probe tied to that composition would
|
|
12
|
-
* report ready while the gateway still had no routes and no open port.
|
|
13
|
-
*/
|
|
14
|
-
export class Probe {
|
|
15
|
-
private readonly server = http.createServer()
|
|
16
|
-
private readonly port: number
|
|
17
|
-
private readonly path: string
|
|
18
|
-
|
|
19
|
-
private ready = false
|
|
20
|
-
private startedAt = 0
|
|
21
|
-
private listening = false
|
|
22
|
-
private skipped = false
|
|
23
|
-
|
|
24
|
-
public constructor(port: number, path: string = PATH) {
|
|
25
|
-
this.port = port
|
|
26
|
-
this.path = path
|
|
27
|
-
|
|
28
|
-
this.server.on('request', (request, response) => this.listener(request, response))
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
public async listen(): Promise<void> {
|
|
32
|
-
this.startedAt = Date.now()
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
await new Promise<void>((resolve, reject) => {
|
|
36
|
-
this.server.once('error', reject)
|
|
37
|
-
this.server.listen(this.port, () => {
|
|
38
|
-
this.server.removeListener('error', reject)
|
|
39
|
-
resolve()
|
|
40
|
-
})
|
|
41
|
-
})
|
|
42
|
-
} catch (error: any) {
|
|
43
|
-
// processes sharing a host share the port; in a pod nothing else claims it
|
|
44
|
-
if (error?.code === 'EADDRINUSE') {
|
|
45
|
-
this.skipped = true
|
|
46
|
-
|
|
47
|
-
console.warn('Ready probe port already in use, skipping', { port: this.port })
|
|
48
|
-
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
throw error
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
this.listening = true
|
|
56
|
-
|
|
57
|
-
// a probe answers while the process runs; it must never be the reason it keeps running
|
|
58
|
-
this.server.unref()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** The gateway is listening and has routes: answer `200`. */
|
|
62
|
-
public complete(): void {
|
|
63
|
-
this.ready = true
|
|
64
|
-
|
|
65
|
-
// the IPC signal is not tied to the probe: a process that gave up the shared port is
|
|
66
|
-
// still ready, and pm2 `wait_ready` would otherwise block until `listen_timeout`
|
|
67
|
-
process.send?.('ready')
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
public async close(): Promise<void> {
|
|
71
|
-
this.ready = false
|
|
72
|
-
|
|
73
|
-
if (!this.listening || this.skipped) return
|
|
74
|
-
|
|
75
|
-
this.listening = false
|
|
76
|
-
|
|
77
|
-
// keep-alive connections would otherwise hold the server handle, delaying the exit
|
|
78
|
-
this.server.closeAllConnections()
|
|
79
|
-
|
|
80
|
-
await new Promise<void>((resolve) => this.server.close(() => resolve()))
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
private listener(request: http.IncomingMessage, response: http.ServerResponse): void {
|
|
84
|
-
if (request.url !== this.path) {
|
|
85
|
-
response.writeHead(404).end()
|
|
86
|
-
|
|
87
|
-
return
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (this.ready) response.writeHead(200, { 'cache-control': 'no-store' }).end()
|
|
91
|
-
else {
|
|
92
|
-
const remaining = Math.ceil((Date.now() - this.startedAt) / 1000).toString()
|
|
93
|
-
|
|
94
|
-
response.writeHead(503, { 'retry-after': remaining }).end()
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export const PATH = '/.ready'
|