@toa.io/extensions.exposition 1.0.0-alpha.292 → 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 +24 -13
- package/transpiled/Endpoint.js +3 -0
- package/transpiled/Endpoint.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/schema.js +2 -2
- package/transpiled/Query.d.ts +2 -12
- package/transpiled/Query.js +2 -12
- package/transpiled/Query.js.map +1 -1
- package/transpiled/RTD/Endpoint.d.ts +2 -3
- 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/{aLpTDmOc.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 -42
- 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 -239
- 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/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 -435
- 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 -1
- 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/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 -10
- package/source/io.ts +0 -4
- package/source/octets.d.ts +0 -17
- package/source/root.ts +0 -59
- package/source/service.ts +0 -95
- package/source/userland.ts +0 -47
- 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/BaWe3aOV.js +0 -1
- package/ui/dist/_app/immutable/chunks/DjIYL2zC.js +0 -3
- package/ui/dist/_app/immutable/chunks/GZTfV0ks.js +0 -6
- package/ui/dist/_app/immutable/entry/app.D5v4JoUx.js +0 -2
- package/ui/dist/_app/immutable/entry/start.CWxFoIyZ.js +0 -1
- package/ui/dist/_app/immutable/nodes/0.DIh5T_5-.js +0 -1
- package/ui/dist/_app/immutable/nodes/1.CY-bFzHC.js +0 -1
- package/ui/dist/_app/immutable/nodes/2.6Ubd1ItY.js +0 -14
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'
|
package/source/HTTP/Server.ts
DELETED
|
@@ -1,435 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert'
|
|
2
|
-
import fs from 'node:fs'
|
|
3
|
-
import os from 'node:os'
|
|
4
|
-
import * as http from 'node:http'
|
|
5
|
-
import * as http2 from 'node:http2'
|
|
6
|
-
import { once } from 'node:events'
|
|
7
|
-
import { setTimeout } from 'node:timers/promises'
|
|
8
|
-
import { console, current, decide, decode, run, type SpanContext } from 'openspan'
|
|
9
|
-
import { Connector } from '@toa.io/core'
|
|
10
|
-
import { type OutgoingMessage, write } from './messages.js'
|
|
11
|
-
import { ClientError, Exception } from './exceptions.js'
|
|
12
|
-
import { Context } from './Context.js'
|
|
13
|
-
import { Probe } from './Probe.js'
|
|
14
|
-
import { PORT, PROBE } from '@toa.io/definitions/extensions.exposition'
|
|
15
|
-
import type { IncomingMessage, Protocol, ServerResponse } from './types.js'
|
|
16
|
-
import type {
|
|
17
|
-
Bouncer,
|
|
18
|
-
MCPAnnotation as MCP,
|
|
19
|
-
OAuth,
|
|
20
|
-
RPCAnnotation as RPC
|
|
21
|
-
} from '@toa.io/definitions/extensions.exposition'
|
|
22
|
-
|
|
23
|
-
export class Server extends Connector {
|
|
24
|
-
private readonly server: http.Server | http2.Http2Server
|
|
25
|
-
private readonly properties: Properties
|
|
26
|
-
/** Host to authority. A map: a `Host` of `constructor` names what a plain object answers. */
|
|
27
|
-
private readonly authorities: Map<string, string>
|
|
28
|
-
|
|
29
|
-
/** Tracked for the drain: `Http2Server` has no `closeIdleConnections`. */
|
|
30
|
-
private readonly sessions = new Set<http2.ServerHttp2Session>()
|
|
31
|
-
|
|
32
|
-
private readonly probe: Probe
|
|
33
|
-
|
|
34
|
-
private process?: Processor
|
|
35
|
-
|
|
36
|
-
private constructor(properties: Properties) {
|
|
37
|
-
super()
|
|
38
|
-
|
|
39
|
-
this.properties = properties
|
|
40
|
-
this.authorities = new Map(
|
|
41
|
-
Object.entries(properties.authorities).map(([key, value]) => [value, key])
|
|
42
|
-
)
|
|
43
|
-
this.server = instantiate(properties.protocol)
|
|
44
|
-
this.probe = new Probe(properties.probe)
|
|
45
|
-
|
|
46
|
-
this.server.on('request', (req, res) =>
|
|
47
|
-
this.listener(req as unknown as IncomingMessage, res as unknown as ServerResponse)
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
if (properties.protocol === 'h1') this.h1(this.server as http.Server)
|
|
51
|
-
else this.h2(this.server as http2.Http2Server)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
public static create(options: Options): Server {
|
|
55
|
-
const properties: Properties = { ...DEFAULTS, ...options }
|
|
56
|
-
|
|
57
|
-
return new Server(properties)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
public attach(process: Processor): void {
|
|
61
|
-
this.process = process
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
protected override async open(): Promise<void> {
|
|
65
|
-
// answers 503 from here; the gateway's dependencies have settled by the time `open` runs
|
|
66
|
-
await this.probe.listen()
|
|
67
|
-
|
|
68
|
-
this.server.listen(this.properties.port)
|
|
69
|
-
|
|
70
|
-
await once(this.server, 'listening')
|
|
71
|
-
|
|
72
|
-
console.info('HTTP Server is listening')
|
|
73
|
-
|
|
74
|
-
this.probe.complete()
|
|
75
|
-
|
|
76
|
-
console.info('Ready')
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
protected override async close(): Promise<void> {
|
|
80
|
-
await this.probe.close()
|
|
81
|
-
|
|
82
|
-
this.server.close()
|
|
83
|
-
|
|
84
|
-
// GOAWAY lets in-flight streams finish; `Http2Server` has no `closeIdleConnections`
|
|
85
|
-
if (this.properties.protocol === 'h1')
|
|
86
|
-
(this.server as http.Server).closeIdleConnections()
|
|
87
|
-
else for (const session of this.sessions) session.close()
|
|
88
|
-
|
|
89
|
-
console.info('Stopped accepting new connections')
|
|
90
|
-
|
|
91
|
-
// keep-alive clients hold connections open indefinitely, so the drain is bounded
|
|
92
|
-
await Promise.race([
|
|
93
|
-
once(this.server, 'close'),
|
|
94
|
-
setTimeout(this.properties.drain, undefined, { ref: false })
|
|
95
|
-
])
|
|
96
|
-
|
|
97
|
-
if (this.properties.protocol === 'h1')
|
|
98
|
-
(this.server as http.Server).closeAllConnections()
|
|
99
|
-
else for (const session of this.sessions) session.destroy()
|
|
100
|
-
|
|
101
|
-
console.info('Stopped')
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** A malformed HTTP/1.1 request has no framing to answer in, so the status line is written by hand. */
|
|
105
|
-
private h1(server: http.Server): void {
|
|
106
|
-
server.on('clientError', (error, socket) => {
|
|
107
|
-
console.warn('Client connection error', error)
|
|
108
|
-
|
|
109
|
-
if (socket.writable) socket.end('HTTP/1.1 400 Bad Request\r\n\r\n')
|
|
110
|
-
else socket.destroy()
|
|
111
|
-
})
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** HTTP/2 has no `clientError`: failures surface per session, per stream, or per frame. */
|
|
115
|
-
private h2(server: http2.Http2Server): void {
|
|
116
|
-
server.on('session', (session) => {
|
|
117
|
-
this.sessions.add(session)
|
|
118
|
-
session.on('close', () => this.sessions.delete(session))
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
server.on('sessionError', (error) => console.warn('Session error', error))
|
|
122
|
-
server.on('streamError', (error) => console.warn('Stream error', error))
|
|
123
|
-
|
|
124
|
-
server.on('unknownProtocol', (socket) => {
|
|
125
|
-
console.warn('Unknown protocol')
|
|
126
|
-
socket.destroy()
|
|
127
|
-
})
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private listener(request: IncomingMessage, response: ServerResponse): void {
|
|
131
|
-
request.once('error', (error) => {
|
|
132
|
-
console.warn('Request error', errorAttributes(request, error))
|
|
133
|
-
|
|
134
|
-
if (!response.writableEnded) response.destroy()
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
// no listener on `request.socket`: under HTTP/2 it is the session's socket, shared by
|
|
138
|
-
// every concurrent stream, and removing listeners on it would strip the siblings'
|
|
139
|
-
|
|
140
|
-
const host = authorityOf(request)?.toLowerCase()
|
|
141
|
-
|
|
142
|
-
if (host === undefined || !HOST.test(host)) {
|
|
143
|
-
console.warn(
|
|
144
|
-
'Request without a valid authority',
|
|
145
|
-
errorAttributes(request, new Error('Invalid authority'))
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
response.writeHead(400).end()
|
|
149
|
-
|
|
150
|
-
return
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// directives and components read `host`; HTTP/2 sends `:authority` instead, and what a
|
|
154
|
-
// component sees must not depend on the protocol the request arrived over
|
|
155
|
-
request.headers.host ??= host
|
|
156
|
-
|
|
157
|
-
const url = parse(request, host)
|
|
158
|
-
|
|
159
|
-
if (url instanceof Error) {
|
|
160
|
-
console.warn('Invalid request', errorAttributes(request, url))
|
|
161
|
-
|
|
162
|
-
response.writeHead(400).end()
|
|
163
|
-
|
|
164
|
-
return
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (request.method === undefined || !this.properties.methods.has(request.method)) {
|
|
168
|
-
response.writeHead(501).end()
|
|
169
|
-
|
|
170
|
-
return
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
assert(this.process !== undefined, 'Request processor is not attached')
|
|
174
|
-
|
|
175
|
-
const authority = this.authorities.get(host) ?? host
|
|
176
|
-
|
|
177
|
-
// if the request carries no trace context, the trace starts here
|
|
178
|
-
const remote = trace(request.headers)
|
|
179
|
-
|
|
180
|
-
const processing =
|
|
181
|
-
remote === null
|
|
182
|
-
? this.serve(request, response, authority, url)
|
|
183
|
-
: run(remote, async () => await this.serve(request, response, authority, url))
|
|
184
|
-
|
|
185
|
-
processing.catch((error) => {
|
|
186
|
-
console.error('Request processing failed', error)
|
|
187
|
-
|
|
188
|
-
if (!response.writableEnded) response.writeHead(500).end()
|
|
189
|
-
})
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// eslint-disable-next-line max-params
|
|
193
|
-
private async serve(
|
|
194
|
-
request: IncomingMessage,
|
|
195
|
-
response: ServerResponse,
|
|
196
|
-
authority: string,
|
|
197
|
-
url: URL
|
|
198
|
-
): Promise<void> {
|
|
199
|
-
await console.span(
|
|
200
|
-
{
|
|
201
|
-
name: `${request.method} ${request.url}`,
|
|
202
|
-
kind: 'server',
|
|
203
|
-
service: 'exposition',
|
|
204
|
-
attributes: { method: request.method, url: request.url, authority }
|
|
205
|
-
},
|
|
206
|
-
async () => {
|
|
207
|
-
response.setHeader('ray', current()!.traceId)
|
|
208
|
-
|
|
209
|
-
const context = new Context(authority, request, this.properties, url)
|
|
210
|
-
|
|
211
|
-
await this.process!(context)
|
|
212
|
-
.then(this.success(context, response))
|
|
213
|
-
.catch(this.fail(context, response))
|
|
214
|
-
.finally(() => request.removeAllListeners('error'))
|
|
215
|
-
}
|
|
216
|
-
)
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
private success(context: Context, response: ServerResponse) {
|
|
220
|
-
return async (message: OutgoingMessage) => {
|
|
221
|
-
let status = message.status
|
|
222
|
-
|
|
223
|
-
if (status === undefined)
|
|
224
|
-
if (message.body === null) status = 404
|
|
225
|
-
else if (context.request.method === 'POST') status = 201
|
|
226
|
-
else if (message.body === undefined && context.request.method !== 'HEAD')
|
|
227
|
-
status = 204
|
|
228
|
-
else status = 200
|
|
229
|
-
|
|
230
|
-
message.status = status
|
|
231
|
-
|
|
232
|
-
await write(context, response, message)
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
private fail(context: Context, response: ServerResponse) {
|
|
237
|
-
return async (exception: Error) => {
|
|
238
|
-
try {
|
|
239
|
-
// Over HTTP/2 the reply is followed by RST_STREAM(NO_ERROR), which tells the client
|
|
240
|
-
// to stop sending without discarding the response — so the body is never read.
|
|
241
|
-
if (!context.request.complete && this.properties.protocol === 'h1')
|
|
242
|
-
await adam(context.request)
|
|
243
|
-
|
|
244
|
-
const status = exception instanceof Exception ? exception.status : 500
|
|
245
|
-
const span = current()
|
|
246
|
-
|
|
247
|
-
// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
|
|
248
|
-
if (status >= 500 && span !== undefined) span.status = 'error'
|
|
249
|
-
|
|
250
|
-
if (!response.writableEnded) {
|
|
251
|
-
response.statusCode = status
|
|
252
|
-
|
|
253
|
-
const message: OutgoingMessage = {
|
|
254
|
-
status: response.statusCode,
|
|
255
|
-
authentic: true
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// eslint-disable-next-line max-depth
|
|
259
|
-
if (exception instanceof Exception && exception.headers !== undefined)
|
|
260
|
-
message.headers = exception.headers
|
|
261
|
-
|
|
262
|
-
// eslint-disable-next-line max-depth
|
|
263
|
-
if (context.encoder === null) message.body = undefined
|
|
264
|
-
else if (exception instanceof ClientError || this.properties.debug)
|
|
265
|
-
message.body =
|
|
266
|
-
exception instanceof Exception
|
|
267
|
-
? exception.body
|
|
268
|
-
: ((this.properties.debug && exception.stack) ?? exception.message)
|
|
269
|
-
|
|
270
|
-
await write(context, response, message)
|
|
271
|
-
}
|
|
272
|
-
} catch (final) {
|
|
273
|
-
console.error('Error in error handler', final)
|
|
274
|
-
|
|
275
|
-
if (!response.writableEnded)
|
|
276
|
-
try {
|
|
277
|
-
response.writeHead(500).end()
|
|
278
|
-
} catch {
|
|
279
|
-
// Nothing more we can do
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function instantiate(protocol: Protocol): http.Server | http2.Http2Server {
|
|
287
|
-
if (protocol === 'h1') return http.createServer()
|
|
288
|
-
|
|
289
|
-
return http2.createServer({
|
|
290
|
-
// realtime pins one stream per subscription, and they all share a session
|
|
291
|
-
maxSessionMemory: SESSION_MEMORY,
|
|
292
|
-
settings: { initialWindowSize: WINDOW }
|
|
293
|
-
})
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* The authority the request is addressed to. HTTP/2 carries it in `:authority` and omits
|
|
298
|
-
* `host` entirely, so reading `host` alone would leave every HTTP/2 request unattributed.
|
|
299
|
-
*/
|
|
300
|
-
function authorityOf(request: IncomingMessage): string | undefined {
|
|
301
|
-
return request.headers[':authority'] ?? request.headers.host
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/** Parsing the URL is how a request is validated, so the `Context` is handed the result. */
|
|
305
|
-
function parse(request: IncomingMessage, authority: string): URL | Error {
|
|
306
|
-
try {
|
|
307
|
-
return new URL(request.url, `https://${authority}`)
|
|
308
|
-
} catch (error) {
|
|
309
|
-
return error as Error
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// https://github.com/whatwg/fetch/issues/1254
|
|
314
|
-
async function adam(request: IncomingMessage): Promise<void> {
|
|
315
|
-
const devnull = fs.createWriteStream(os.devNull)
|
|
316
|
-
|
|
317
|
-
devnull.on('error', () => undefined)
|
|
318
|
-
request.pipe(devnull).on('error', () => undefined)
|
|
319
|
-
|
|
320
|
-
await once(request, 'end')
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
function errorAttributes(
|
|
324
|
-
request: IncomingMessage,
|
|
325
|
-
error: Error & any
|
|
326
|
-
): RequestErrorAttributes {
|
|
327
|
-
const attributes: RequestErrorAttributes = {
|
|
328
|
-
path: request.url,
|
|
329
|
-
method: request.method,
|
|
330
|
-
name: error.name
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (typeof error.code === 'string') attributes.code = error.code
|
|
334
|
-
|
|
335
|
-
if (typeof error.stack === 'string') attributes.stack = error.stack
|
|
336
|
-
|
|
337
|
-
return attributes
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
export const DRAIN = 10 // seconds
|
|
341
|
-
|
|
342
|
-
/** Megabytes a single HTTP/2 session may hold, over Node's default of 10. */
|
|
343
|
-
const SESSION_MEMORY = 128
|
|
344
|
-
|
|
345
|
-
/** Per-stream flow control window. The default 64 KiB throttles in proportion to RTT. */
|
|
346
|
-
const WINDOW = 1024 * 1024
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Extracts the remote trace context from the request headers.
|
|
350
|
-
*
|
|
351
|
-
* The `ray` header adopts the trace by ID only and does not bypass sampling:
|
|
352
|
-
* the sampling decision is made by the server.
|
|
353
|
-
*/
|
|
354
|
-
function trace(headers: IncomingMessage['headers']): SpanContext | null {
|
|
355
|
-
if (typeof headers.traceparent === 'string') return decode(headers.traceparent)
|
|
356
|
-
|
|
357
|
-
// adopting a trace by ID does not bypass sampling
|
|
358
|
-
if (
|
|
359
|
-
typeof headers.ray === 'string' &&
|
|
360
|
-
RAY.test(headers.ray) &&
|
|
361
|
-
headers.ray !== ZERO_RAY
|
|
362
|
-
)
|
|
363
|
-
return { traceId: headers.ray.toLowerCase(), sampled: decide() }
|
|
364
|
-
|
|
365
|
-
return null
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* A host name with an optional port, or a bracketed IPv6 literal. The URL parser admits
|
|
370
|
-
* `,` `;` `=` `(` `)` and quotes in a host, and the authority is written into criteria.
|
|
371
|
-
*/
|
|
372
|
-
const HOST = /^(?:[a-z0-9.-]{1,253}|\[[0-9a-f:.]{2,45}\])(?::\d{1,5})?$/
|
|
373
|
-
|
|
374
|
-
const RAY = /^[\da-f]{32}$/i
|
|
375
|
-
const ZERO_RAY = '0'.repeat(32)
|
|
376
|
-
|
|
377
|
-
const DEFAULTS: Omit<Properties, 'authorities'> = {
|
|
378
|
-
methods: new Set<string>([
|
|
379
|
-
'OPTIONS',
|
|
380
|
-
'GET',
|
|
381
|
-
'HEAD',
|
|
382
|
-
'POST',
|
|
383
|
-
'PUT',
|
|
384
|
-
'PATCH',
|
|
385
|
-
'DELETE',
|
|
386
|
-
'LOCK',
|
|
387
|
-
'UNLOCK'
|
|
388
|
-
]),
|
|
389
|
-
debug: false,
|
|
390
|
-
port: PORT,
|
|
391
|
-
drain: DRAIN * 1000,
|
|
392
|
-
protocol: 'h1',
|
|
393
|
-
probe: PROBE
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
interface Properties {
|
|
397
|
-
authorities: Record<string, string>
|
|
398
|
-
methods: Set<string>
|
|
399
|
-
debug: boolean
|
|
400
|
-
port: number
|
|
401
|
-
drain: number
|
|
402
|
-
protocol: Protocol
|
|
403
|
-
|
|
404
|
-
/** Port of the readiness probe, which is HTTP/1.1 whatever the gateway serves. */
|
|
405
|
-
probe: number
|
|
406
|
-
|
|
407
|
-
/** The header the client address is read from; the connection's address without one. */
|
|
408
|
-
ip?: string
|
|
409
|
-
|
|
410
|
-
/** Failed authentications an address may make; none are metered unless set. */
|
|
411
|
-
bouncer?: Bouncer
|
|
412
|
-
|
|
413
|
-
/** The authorization server this context exposes; none is exposed without it. */
|
|
414
|
-
oauth?: OAuth
|
|
415
|
-
|
|
416
|
-
/** JSON-RPC at `/.rpc`; none is served without it. */
|
|
417
|
-
rpc?: RPC
|
|
418
|
-
|
|
419
|
-
/** MCP at `/.mcp`; none is served without it. */
|
|
420
|
-
mcp?: MCP
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
export type Options = { authorities: Properties['authorities'] } & {
|
|
424
|
-
[K in Exclude<keyof Properties, 'authorities'>]?: Properties[K]
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
export type Processor = (input: Context) => Promise<OutgoingMessage>
|
|
428
|
-
|
|
429
|
-
interface RequestErrorAttributes {
|
|
430
|
-
path: string
|
|
431
|
-
method: string
|
|
432
|
-
name: string
|
|
433
|
-
code?: string
|
|
434
|
-
stack?: string
|
|
435
|
-
}
|
package/source/HTTP/Timing.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { performance } from 'node:perf_hooks'
|
|
2
|
-
import type { ServerResponse } from './types.js'
|
|
3
|
-
|
|
4
|
-
/** How long the request took, from received to written: one number, the header's. */
|
|
5
|
-
export class Timing {
|
|
6
|
-
private readonly start = performance.now()
|
|
7
|
-
|
|
8
|
-
public append(response: ServerResponse): void {
|
|
9
|
-
response.setHeader(
|
|
10
|
-
'server-timing',
|
|
11
|
-
`total;dur=${(performance.now() - this.start).toFixed(3)}`
|
|
12
|
-
)
|
|
13
|
-
}
|
|
14
|
-
}
|