@toa.io/extensions.exposition 0.20.0-alpha.1 → 0.20.0-alpha.2
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/context.toa.yaml +2 -2
- package/documentation/notes/sse.md +71 -0
- package/documentation/protocol.md +4 -1
- package/features/access.feature +48 -42
- package/features/annotation.feature +6 -4
- package/features/body.feature +24 -0
- package/features/directives.feature +2 -2
- package/features/dynamic.feature +11 -1
- package/features/errors.feature +14 -29
- package/features/identity.basic.feature +47 -6
- package/features/identity.tokens.feature +19 -16
- package/features/steps/Gateway.ts +26 -18
- package/features/steps/components/echo/manifest.toa.yaml +9 -0
- package/features/steps/components/echo/operations/affect.js +7 -0
- package/features/steps/components/echo/operations/compute.js +7 -0
- package/features/steps/components/greeter/manifest.toa.yaml +0 -4
- package/features/steps/components/greeter/operations/greet.js +1 -1
- package/features/steps/components/sequences/manifest.toa.yaml +10 -0
- package/features/steps/components/sequences/operations/numbers.js +7 -0
- package/features/steps/components/sequences/operations/tokens.js +16 -0
- package/features/streams.feature +26 -0
- package/package.json +7 -6
- package/readme.md +2 -0
- package/schemas/annotation.cos.yaml +5 -4
- package/schemas/method.cos.yaml +0 -1
- package/schemas/query.cos.yaml +1 -0
- package/source/Annotation.ts +1 -0
- package/source/Composition.ts +1 -2
- package/source/Endpoint.ts +5 -3
- package/source/Factory.ts +8 -10
- package/source/HTTP/Server.ts +1 -1
- package/source/HTTP/messages.ts +18 -6
- package/source/Mapping.ts +12 -9
- package/source/RTD/Node.ts +5 -5
- package/source/RTD/Route.ts +5 -4
- package/source/RTD/Tree.ts +2 -5
- package/source/RTD/syntax/parse.ts +1 -1
- package/source/Remotes.test.ts +2 -1
- package/source/Remotes.ts +2 -0
- package/source/deployment.ts +9 -2
- package/source/directives/dev/Family.ts +3 -1
- package/source/directives/dev/Throw.ts +14 -0
- package/source/manifest.test.ts +3 -1
- package/source/manifest.ts +22 -9
- package/transpiled/Annotation.d.ts +0 -6
- package/transpiled/Annotation.js +0 -3
- package/transpiled/Annotation.js.map +0 -1
- package/transpiled/Branch.d.ts +0 -7
- package/transpiled/Branch.js +0 -3
- package/transpiled/Branch.js.map +0 -1
- package/transpiled/Composition.d.ts +0 -14
- package/transpiled/Composition.js +0 -43
- package/transpiled/Composition.js.map +0 -1
- package/transpiled/Context.d.ts +0 -5
- package/transpiled/Context.js +0 -3
- package/transpiled/Context.js.map +0 -1
- package/transpiled/Directive.d.ts +0 -32
- package/transpiled/Directive.js +0 -76
- package/transpiled/Directive.js.map +0 -1
- package/transpiled/Endpoint.d.ts +0 -20
- package/transpiled/Endpoint.js +0 -44
- package/transpiled/Endpoint.js.map +0 -1
- package/transpiled/Factory.d.ts +0 -11
- package/transpiled/Factory.js +0 -67
- package/transpiled/Factory.js.map +0 -1
- package/transpiled/Gateway.d.ts +0 -19
- package/transpiled/Gateway.js +0 -90
- package/transpiled/Gateway.js.map +0 -1
- package/transpiled/HTTP/Server.d.ts +0 -22
- package/transpiled/HTTP/Server.fixtures.d.ts +0 -12
- package/transpiled/HTTP/Server.fixtures.js +0 -36
- package/transpiled/HTTP/Server.fixtures.js.map +0 -1
- package/transpiled/HTTP/Server.js +0 -111
- package/transpiled/HTTP/Server.js.map +0 -1
- package/transpiled/HTTP/exceptions.d.ts +0 -39
- package/transpiled/HTTP/exceptions.js +0 -78
- package/transpiled/HTTP/exceptions.js.map +0 -1
- package/transpiled/HTTP/formats/index.d.ts +0 -8
- package/transpiled/HTTP/formats/index.js +0 -38
- package/transpiled/HTTP/formats/index.js.map +0 -1
- package/transpiled/HTTP/formats/json.d.ts +0 -4
- package/transpiled/HTTP/formats/json.js +0 -15
- package/transpiled/HTTP/formats/json.js.map +0 -1
- package/transpiled/HTTP/formats/msgpack.d.ts +0 -4
- package/transpiled/HTTP/formats/msgpack.js +0 -36
- package/transpiled/HTTP/formats/msgpack.js.map +0 -1
- package/transpiled/HTTP/formats/text.d.ts +0 -4
- package/transpiled/HTTP/formats/text.js +0 -13
- package/transpiled/HTTP/formats/text.js.map +0 -1
- package/transpiled/HTTP/formats/yaml.d.ts +0 -4
- package/transpiled/HTTP/formats/yaml.js +0 -39
- package/transpiled/HTTP/formats/yaml.js.map +0 -1
- package/transpiled/HTTP/index.d.ts +0 -3
- package/transpiled/HTTP/index.js +0 -20
- package/transpiled/HTTP/index.js.map +0 -1
- package/transpiled/HTTP/messages.d.ts +0 -27
- package/transpiled/HTTP/messages.js +0 -49
- package/transpiled/HTTP/messages.js.map +0 -1
- package/transpiled/Mapping.d.ts +0 -8
- package/transpiled/Mapping.js +0 -35
- package/transpiled/Mapping.js.map +0 -1
- package/transpiled/Query.d.ts +0 -13
- package/transpiled/Query.js +0 -107
- package/transpiled/Query.js.map +0 -1
- package/transpiled/RTD/Context.d.ts +0 -11
- package/transpiled/RTD/Context.js +0 -3
- package/transpiled/RTD/Context.js.map +0 -1
- package/transpiled/RTD/Directives.d.ts +0 -7
- package/transpiled/RTD/Directives.js +0 -3
- package/transpiled/RTD/Directives.js.map +0 -1
- package/transpiled/RTD/Endpoint.d.ts +0 -9
- package/transpiled/RTD/Endpoint.js +0 -3
- package/transpiled/RTD/Endpoint.js.map +0 -1
- package/transpiled/RTD/Match.d.ts +0 -11
- package/transpiled/RTD/Match.js +0 -3
- package/transpiled/RTD/Match.js.map +0 -1
- package/transpiled/RTD/Method.d.ts +0 -9
- package/transpiled/RTD/Method.js +0 -16
- package/transpiled/RTD/Method.js.map +0 -1
- package/transpiled/RTD/Node.d.ts +0 -21
- package/transpiled/RTD/Node.js +0 -61
- package/transpiled/RTD/Node.js.map +0 -1
- package/transpiled/RTD/Route.d.ts +0 -14
- package/transpiled/RTD/Route.js +0 -48
- package/transpiled/RTD/Route.js.map +0 -1
- package/transpiled/RTD/Tree.d.ts +0 -14
- package/transpiled/RTD/Tree.js +0 -45
- package/transpiled/RTD/Tree.js.map +0 -1
- package/transpiled/RTD/factory.d.ts +0 -6
- package/transpiled/RTD/factory.js +0 -36
- package/transpiled/RTD/factory.js.map +0 -1
- package/transpiled/RTD/index.d.ts +0 -8
- package/transpiled/RTD/index.js +0 -38
- package/transpiled/RTD/index.js.map +0 -1
- package/transpiled/RTD/segment.d.ts +0 -8
- package/transpiled/RTD/segment.js +0 -23
- package/transpiled/RTD/segment.js.map +0 -1
- package/transpiled/RTD/syntax/index.d.ts +0 -2
- package/transpiled/RTD/syntax/index.js +0 -19
- package/transpiled/RTD/syntax/index.js.map +0 -1
- package/transpiled/RTD/syntax/parse.d.ts +0 -4
- package/transpiled/RTD/syntax/parse.js +0 -128
- package/transpiled/RTD/syntax/parse.js.map +0 -1
- package/transpiled/RTD/syntax/types.d.ts +0 -41
- package/transpiled/RTD/syntax/types.js +0 -5
- package/transpiled/RTD/syntax/types.js.map +0 -1
- package/transpiled/Remotes.d.ts +0 -7
- package/transpiled/Remotes.js +0 -19
- package/transpiled/Remotes.js.map +0 -1
- package/transpiled/Tenant.d.ts +0 -12
- package/transpiled/Tenant.js +0 -30
- package/transpiled/Tenant.js.map +0 -1
- package/transpiled/deployment.d.ts +0 -3
- package/transpiled/deployment.js +0 -61
- package/transpiled/deployment.js.map +0 -1
- package/transpiled/directives/auth/Anonymous.d.ts +0 -6
- package/transpiled/directives/auth/Anonymous.js +0 -17
- package/transpiled/directives/auth/Anonymous.js.map +0 -1
- package/transpiled/directives/auth/Echo.d.ts +0 -6
- package/transpiled/directives/auth/Echo.js +0 -13
- package/transpiled/directives/auth/Echo.js.map +0 -1
- package/transpiled/directives/auth/Family.d.ts +0 -20
- package/transpiled/directives/auth/Family.js +0 -125
- package/transpiled/directives/auth/Family.js.map +0 -1
- package/transpiled/directives/auth/Id.d.ts +0 -7
- package/transpiled/directives/auth/Id.js +0 -17
- package/transpiled/directives/auth/Id.js.map +0 -1
- package/transpiled/directives/auth/Incept.d.ts +0 -10
- package/transpiled/directives/auth/Incept.js +0 -59
- package/transpiled/directives/auth/Incept.js.map +0 -1
- package/transpiled/directives/auth/Role.d.ts +0 -11
- package/transpiled/directives/auth/Role.js +0 -44
- package/transpiled/directives/auth/Role.js.map +0 -1
- package/transpiled/directives/auth/Rule.d.ts +0 -9
- package/transpiled/directives/auth/Rule.js +0 -22
- package/transpiled/directives/auth/Rule.js.map +0 -1
- package/transpiled/directives/auth/Scheme.d.ts +0 -7
- package/transpiled/directives/auth/Scheme.js +0 -47
- package/transpiled/directives/auth/Scheme.js.map +0 -1
- package/transpiled/directives/auth/index.d.ts +0 -2
- package/transpiled/directives/auth/index.js +0 -7
- package/transpiled/directives/auth/index.js.map +0 -1
- package/transpiled/directives/auth/schemes.d.ts +0 -3
- package/transpiled/directives/auth/schemes.js +0 -9
- package/transpiled/directives/auth/schemes.js.map +0 -1
- package/transpiled/directives/auth/split.d.ts +0 -2
- package/transpiled/directives/auth/split.js +0 -38
- package/transpiled/directives/auth/split.js.map +0 -1
- package/transpiled/directives/auth/types.d.ts +0 -31
- package/transpiled/directives/auth/types.js +0 -3
- package/transpiled/directives/auth/types.js.map +0 -1
- package/transpiled/directives/dev/Family.d.ts +0 -10
- package/transpiled/directives/dev/Family.js +0 -25
- package/transpiled/directives/dev/Family.js.map +0 -1
- package/transpiled/directives/dev/Stub.d.ts +0 -7
- package/transpiled/directives/dev/Stub.js +0 -14
- package/transpiled/directives/dev/Stub.js.map +0 -1
- package/transpiled/directives/dev/index.d.ts +0 -2
- package/transpiled/directives/dev/index.js +0 -7
- package/transpiled/directives/dev/index.js.map +0 -1
- package/transpiled/directives/dev/types.d.ts +0 -4
- package/transpiled/directives/dev/types.js +0 -3
- package/transpiled/directives/dev/types.js.map +0 -1
- package/transpiled/directives/index.d.ts +0 -2
- package/transpiled/directives/index.js +0 -10
- package/transpiled/directives/index.js.map +0 -1
- package/transpiled/discovery.d.ts +0 -1
- package/transpiled/discovery.js +0 -3
- package/transpiled/discovery.js.map +0 -1
- package/transpiled/exceptions.d.ts +0 -2
- package/transpiled/exceptions.js +0 -39
- package/transpiled/exceptions.js.map +0 -1
- package/transpiled/index.d.ts +0 -5
- package/transpiled/index.js +0 -12
- package/transpiled/index.js.map +0 -1
- package/transpiled/manifest.d.ts +0 -3
- package/transpiled/manifest.js +0 -30
- package/transpiled/manifest.js.map +0 -1
- package/transpiled/root.d.ts +0 -2
- package/transpiled/root.js +0 -39
- package/transpiled/root.js.map +0 -1
- package/transpiled/schemas.d.ts +0 -3
- package/transpiled/schemas.js +0 -14
- package/transpiled/schemas.js.map +0 -1
- package/transpiled/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Feature: Reply streams
|
|
2
|
+
|
|
3
|
+
Scenario: Getting a Reply stream
|
|
4
|
+
Given the `sequences` is running with the following manifest:
|
|
5
|
+
"""yaml
|
|
6
|
+
exposition:
|
|
7
|
+
/:
|
|
8
|
+
POST: numbers
|
|
9
|
+
"""
|
|
10
|
+
When the following request is received:
|
|
11
|
+
"""
|
|
12
|
+
POST /sequences/ HTTP/1.1
|
|
13
|
+
content-type: text/plain
|
|
14
|
+
accept: text/plain
|
|
15
|
+
|
|
16
|
+
3
|
|
17
|
+
"""
|
|
18
|
+
Then the following reply is sent:
|
|
19
|
+
"""
|
|
20
|
+
201 Created
|
|
21
|
+
transfer-encoding: chunked
|
|
22
|
+
|
|
23
|
+
0
|
|
24
|
+
1
|
|
25
|
+
2
|
|
26
|
+
"""
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/extensions.exposition",
|
|
3
|
-
"version": "0.20.0-alpha.
|
|
3
|
+
"version": "0.20.0-alpha.2",
|
|
4
4
|
"description": "Toa Exposition",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -20,10 +20,11 @@
|
|
|
20
20
|
"nopeable": "*"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@toa.io/core": "0.20.0-alpha.
|
|
24
|
-
"@toa.io/generic": "0.20.0-alpha.
|
|
25
|
-
"@toa.io/http": "0.20.0-alpha.
|
|
26
|
-
"@toa.io/schemas": "0.20.0-alpha.
|
|
23
|
+
"@toa.io/core": "0.20.0-alpha.2",
|
|
24
|
+
"@toa.io/generic": "0.20.0-alpha.2",
|
|
25
|
+
"@toa.io/http": "0.20.0-alpha.2",
|
|
26
|
+
"@toa.io/schemas": "0.20.0-alpha.2",
|
|
27
|
+
"@toa.io/streams": "0.1.0-alpha.2",
|
|
27
28
|
"bcryptjs": "2.4.3",
|
|
28
29
|
"cors": "2.8.5",
|
|
29
30
|
"express": "4.18.2",
|
|
@@ -46,5 +47,5 @@
|
|
|
46
47
|
"@types/express": "4.17.17",
|
|
47
48
|
"@types/negotiator": "0.6.1"
|
|
48
49
|
},
|
|
49
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "d6e8c5bdae26e2beb66f4d7f37f71a3494fe9fcb"
|
|
50
51
|
}
|
package/readme.md
CHANGED
|
@@ -163,6 +163,7 @@ exposition:
|
|
|
163
163
|
host: the.example.com
|
|
164
164
|
host@staging: the.example.dev
|
|
165
165
|
class: alb
|
|
166
|
+
debug@staging: true
|
|
166
167
|
annotations:
|
|
167
168
|
alb.ingress.kubernetes.io/scheme: internet-facing
|
|
168
169
|
alb.ingress.kubernetes.io/target-type: ip
|
|
@@ -178,4 +179,5 @@ exposition:
|
|
|
178
179
|
- [Resource Tree Definition](documentation/tree.md)
|
|
179
180
|
- [Identity authentication](documentation/identity.md)
|
|
180
181
|
- [Access authorization](documentation/access.md)
|
|
182
|
+
- [Components and resources](documentation/components.md)
|
|
181
183
|
- [Features](features)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
host
|
|
2
|
-
class
|
|
3
|
-
annotations
|
|
4
|
-
|
|
1
|
+
host: string
|
|
2
|
+
class: string
|
|
3
|
+
annotations: <string>
|
|
4
|
+
debug: boolean
|
|
5
|
+
/: ~
|
package/schemas/method.cos.yaml
CHANGED
package/schemas/query.cos.yaml
CHANGED
package/source/Annotation.ts
CHANGED
package/source/Composition.ts
CHANGED
package/source/Endpoint.ts
CHANGED
|
@@ -28,11 +28,11 @@ export class Endpoint implements RTD.Endpoint<Endpoint> {
|
|
|
28
28
|
public async close (): Promise<void> {
|
|
29
29
|
this.remote ??= await this.discovery
|
|
30
30
|
|
|
31
|
-
await this.remote.disconnect()
|
|
31
|
+
await this.remote.disconnect(INTERRUPT)
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export class
|
|
35
|
+
export class EndpointsFactory implements RTD.EndpointsFactory<Endpoint> {
|
|
36
36
|
private readonly remotes: Remotes
|
|
37
37
|
|
|
38
38
|
public constructor (remotes: Remotes) {
|
|
@@ -43,7 +43,7 @@ export class EndpointFactory implements RTD.EndpointsFactory<Endpoint> {
|
|
|
43
43
|
if (method.mapping === undefined)
|
|
44
44
|
throw new Error('Cannot create Endpoint without mapping.')
|
|
45
45
|
|
|
46
|
-
const mapping = Mapping.create(method.
|
|
46
|
+
const mapping = Mapping.create(method.mapping.query)
|
|
47
47
|
const namespace = method.mapping.namespace ?? context.extension?.namespace
|
|
48
48
|
const component = method.mapping.component ?? context.extension?.component
|
|
49
49
|
|
|
@@ -55,3 +55,5 @@ export class EndpointFactory implements RTD.EndpointsFactory<Endpoint> {
|
|
|
55
55
|
return new Endpoint(method.mapping.endpoint, mapping, discovery)
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
const INTERRUPT = true
|
package/source/Factory.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Gateway } from './Gateway'
|
|
|
3
3
|
import { Remotes } from './Remotes'
|
|
4
4
|
import { Tree, syntax } from './RTD'
|
|
5
5
|
import { Server } from './HTTP'
|
|
6
|
-
import { type Endpoint,
|
|
6
|
+
import { type Endpoint, EndpointsFactory } from './Endpoint'
|
|
7
7
|
import * as directives from './directives'
|
|
8
8
|
import { type Directives, DirectivesFactory, type Family } from './Directive'
|
|
9
9
|
import { Composition } from './Composition'
|
|
@@ -19,28 +19,26 @@ export class Factory implements extensions.Factory {
|
|
|
19
19
|
this.families = directives.families
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
public tenant (locator: Locator,
|
|
22
|
+
public tenant (locator: Locator, node: syntax.Node): Connector {
|
|
23
23
|
const broadcast = this.boot.bindings.broadcast(CHANNEL, locator.id)
|
|
24
24
|
|
|
25
|
-
return new Tenant(broadcast, locator,
|
|
25
|
+
return new Tenant(broadcast, locator, node)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
public service (): Connector | null {
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
private gateway (): Gateway {
|
|
29
|
+
const debug = process.env.TOA_EXPOSITION_DEBUG === '1'
|
|
33
30
|
const broadcast = this.boot.bindings.broadcast(CHANNEL)
|
|
34
|
-
const server = Server.create({ methods: syntax.verbs })
|
|
31
|
+
const server = Server.create({ methods: syntax.verbs, debug })
|
|
35
32
|
const remotes = new Remotes(this.boot)
|
|
36
|
-
const methods = new EndpointFactory(remotes)
|
|
37
|
-
const directives = new DirectivesFactory(this.families, remotes)
|
|
38
33
|
const node = root.resolve()
|
|
34
|
+
const methods = new EndpointsFactory(remotes)
|
|
35
|
+
const directives = new DirectivesFactory(this.families, remotes)
|
|
39
36
|
const tree = new Tree<Endpoint, Directives>(node, methods, directives)
|
|
40
37
|
|
|
41
38
|
const composition = new Composition(this.boot)
|
|
42
39
|
const gateway = new Gateway(broadcast, server, tree)
|
|
43
40
|
|
|
41
|
+
gateway.depends(remotes)
|
|
44
42
|
gateway.depends(composition)
|
|
45
43
|
|
|
46
44
|
return gateway
|
package/source/HTTP/Server.ts
CHANGED
package/source/HTTP/messages.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { type IncomingHttpHeaders, type OutgoingHttpHeaders } from 'node:http'
|
|
2
|
+
import { Readable } from 'node:stream'
|
|
2
3
|
import { type Request, type Response } from 'express'
|
|
3
4
|
import Negotiator from 'negotiator'
|
|
4
5
|
import { buffer } from '@toa.io/generic'
|
|
6
|
+
import { map } from '@toa.io/streams'
|
|
5
7
|
import { formats, types } from './formats'
|
|
6
8
|
import { BadRequest, NotAcceptable, UnsupportedMediaType } from './exceptions'
|
|
7
9
|
|
|
8
10
|
export function write (request: Request, response: Response, body: any): void {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
response.send(buf)
|
|
11
|
+
if (body instanceof Readable) void pipe(body, request, response)
|
|
12
|
+
else send(body, request, response)
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export async function read (request: Request): Promise<any> {
|
|
@@ -29,8 +30,12 @@ export async function read (request: Request): Promise<any> {
|
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
function
|
|
33
|
-
if (body === undefined || body?.length === 0)
|
|
33
|
+
function send (body: any, request: Request, response: Response): void {
|
|
34
|
+
if (body === undefined || body?.length === 0) {
|
|
35
|
+
response.end()
|
|
36
|
+
|
|
37
|
+
return
|
|
38
|
+
}
|
|
34
39
|
|
|
35
40
|
const type = negotiate(request)
|
|
36
41
|
const format = formats[type]
|
|
@@ -38,8 +43,15 @@ function format (body: any, request: Request, response: Response): Buffer | unde
|
|
|
38
43
|
|
|
39
44
|
// content-length and etag are set by Express
|
|
40
45
|
response.set('content-type', type)
|
|
46
|
+
response.send(buf)
|
|
47
|
+
}
|
|
41
48
|
|
|
42
|
-
|
|
49
|
+
async function pipe (stream: Readable, request: Request, response: Response): Promise<void> {
|
|
50
|
+
const type = negotiate(request)
|
|
51
|
+
const format = formats[type]
|
|
52
|
+
|
|
53
|
+
response.set('content-type', type)
|
|
54
|
+
map(stream, format.encode).pipe(response)
|
|
43
55
|
}
|
|
44
56
|
|
|
45
57
|
function negotiate (request: Request): string {
|
package/source/Mapping.ts
CHANGED
|
@@ -5,13 +5,10 @@ import type * as syntax from './RTD/syntax'
|
|
|
5
5
|
import type * as core from '@toa.io/core'
|
|
6
6
|
|
|
7
7
|
export abstract class Mapping {
|
|
8
|
-
public static create (
|
|
9
|
-
if (
|
|
8
|
+
public static create (query?: syntax.Query): Mapping {
|
|
9
|
+
if (query === undefined || query === null)
|
|
10
10
|
return new InputMapping()
|
|
11
11
|
|
|
12
|
-
if (query === undefined)
|
|
13
|
-
throw new Error(`Query constraints must be defined for ${verb}`)
|
|
14
|
-
|
|
15
12
|
const q = new Query(query)
|
|
16
13
|
|
|
17
14
|
return new QueryableMapping(q)
|
|
@@ -37,12 +34,18 @@ class QueryableMapping extends Mapping {
|
|
|
37
34
|
}
|
|
38
35
|
|
|
39
36
|
class InputMapping extends Mapping {
|
|
40
|
-
public fit (
|
|
41
|
-
|
|
37
|
+
public fit (input: any, _: unknown, parameters: Parameter[]): core.Request {
|
|
38
|
+
if (input === undefined && parameters.length > 0)
|
|
39
|
+
input = {}
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
input
|
|
41
|
+
if (typeof input === 'object')
|
|
42
|
+
this.assign(input, parameters)
|
|
45
43
|
|
|
46
44
|
return { input }
|
|
47
45
|
}
|
|
46
|
+
|
|
47
|
+
private assign (input: Record<string, any>, parameters: Parameter[]): void {
|
|
48
|
+
for (const parameter of parameters)
|
|
49
|
+
input[parameter.name] = parameter.value
|
|
50
|
+
}
|
|
48
51
|
}
|
package/source/RTD/Node.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Route } from './Route'
|
|
2
2
|
import { type Methods } from './Method'
|
|
3
|
-
import { type Parameter } from './Match'
|
|
3
|
+
import { type Match, type Parameter } from './Match'
|
|
4
4
|
import { type Directives } from './Directives'
|
|
5
5
|
import { type Endpoint } from './Endpoint'
|
|
6
6
|
|
|
@@ -23,12 +23,12 @@ export class Node<
|
|
|
23
23
|
this.sort()
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
public match (fragments: string[], parameters: Parameter[]):
|
|
26
|
+
public match (fragments: string[], parameters: Parameter[] = []): Match | null {
|
|
27
27
|
for (const route of this.routes) {
|
|
28
|
-
const
|
|
28
|
+
const match = route.match(fragments, parameters)
|
|
29
29
|
|
|
30
|
-
if (
|
|
31
|
-
return
|
|
30
|
+
if (match !== null)
|
|
31
|
+
return match
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
return null
|
package/source/RTD/Route.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Node } from './Node'
|
|
2
2
|
import { type Segment } from './segment'
|
|
3
|
-
import { type Parameter } from './Match'
|
|
3
|
+
import { type Match, type Parameter } from './Match'
|
|
4
4
|
|
|
5
5
|
export class Route {
|
|
6
6
|
public readonly root: boolean
|
|
@@ -18,7 +18,7 @@ export class Route {
|
|
|
18
18
|
this.variables++
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
public match (fragments: string[], parameters: Parameter[]):
|
|
21
|
+
public match (fragments: string[], parameters: Parameter[]): Match | null {
|
|
22
22
|
for (let i = 0; i < this.segments.length; i++) {
|
|
23
23
|
const segment = this.segments[i]
|
|
24
24
|
|
|
@@ -31,7 +31,7 @@ export class Route {
|
|
|
31
31
|
|
|
32
32
|
const exact = this.segments.length === fragments.length
|
|
33
33
|
|
|
34
|
-
if (exact && !this.node.intermediate) return this.node
|
|
34
|
+
if (exact && !this.node.intermediate) return { node: this.node, parameters }
|
|
35
35
|
else return this.matchNested(fragments, parameters)
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -50,8 +50,9 @@ export class Route {
|
|
|
50
50
|
this.node.merge(route.node)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
private matchNested (fragments: string[], parameters: Parameter[]):
|
|
53
|
+
private matchNested (fragments: string[], parameters: Parameter[]): Match | null {
|
|
54
54
|
fragments = fragments.slice(this.segments.length)
|
|
55
|
+
parameters = parameters.slice()
|
|
55
56
|
|
|
56
57
|
return this.node.match(fragments, parameters)
|
|
57
58
|
}
|
package/source/RTD/Tree.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Node } from './Node'
|
|
2
2
|
import { createNode } from './factory'
|
|
3
3
|
import { fragment } from './segment'
|
|
4
|
-
import { type Match
|
|
4
|
+
import { type Match } from './Match'
|
|
5
5
|
import { type Context } from './Context'
|
|
6
6
|
import { type Directives, type DirectivesFactory } from './Directives'
|
|
7
7
|
import { type Endpoint, type EndpointsFactory } from './Endpoint'
|
|
@@ -26,11 +26,8 @@ export class Tree<
|
|
|
26
26
|
|
|
27
27
|
public match (path: string): Match<TEndpoint, TDirectives> | null {
|
|
28
28
|
const fragments = fragment(path)
|
|
29
|
-
const parameters: Parameter[] = []
|
|
30
|
-
const node = this.trunk.match(fragments, parameters)
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
else return { node, parameters }
|
|
30
|
+
return this.trunk.match(fragments)
|
|
34
31
|
}
|
|
35
32
|
|
|
36
33
|
public merge (node: syntax.Node, extension: any): void {
|
|
@@ -101,7 +101,7 @@ function parseEndpoint (mapping: Mapping): void {
|
|
|
101
101
|
function parseQuery (mapping: any): void {
|
|
102
102
|
const query = mapping.query
|
|
103
103
|
|
|
104
|
-
if (query === undefined)
|
|
104
|
+
if (query === undefined || query === null)
|
|
105
105
|
return
|
|
106
106
|
|
|
107
107
|
if (typeof query.limit === 'number')
|
package/source/Remotes.test.ts
CHANGED
|
@@ -10,7 +10,8 @@ jest.mock('@toa.io/boot', () => ({
|
|
|
10
10
|
|
|
11
11
|
const boot = {
|
|
12
12
|
remote: jest.fn(async (..._) => ({
|
|
13
|
-
|
|
13
|
+
connect: jest.fn(() => undefined),
|
|
14
|
+
link: jest.fn(() => undefined)
|
|
14
15
|
}))
|
|
15
16
|
} as unknown as jest.MockedObjectDeep<Bootloader>
|
|
16
17
|
|
package/source/Remotes.ts
CHANGED
package/source/deployment.ts
CHANGED
|
@@ -27,14 +27,21 @@ export function deployment (_: unknown, annotation: Annotation | undefined): Dep
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
if (annotation?.['/'] !== undefined) {
|
|
30
|
-
|
|
30
|
+
const node = { '/': annotation['/'] }
|
|
31
|
+
const tree = parse(node, shortcuts)
|
|
31
32
|
|
|
32
33
|
service.variables.push({
|
|
33
34
|
name: 'TOA_EXPOSITION',
|
|
34
|
-
value: encode(
|
|
35
|
+
value: encode(tree)
|
|
35
36
|
})
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
if (annotation?.debug === true)
|
|
40
|
+
service.variables.push({
|
|
41
|
+
name: 'TOA_EXPOSITION_DEBUG',
|
|
42
|
+
value: '1'
|
|
43
|
+
})
|
|
44
|
+
|
|
38
45
|
if (annotation !== undefined)
|
|
39
46
|
schemas.annotaion.validate(annotation)
|
|
40
47
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Input, type Output, type Family } from '../../Directive'
|
|
2
2
|
import { Stub } from './Stub'
|
|
3
|
+
import { Throw } from './Throw'
|
|
3
4
|
import { type Directive } from './types'
|
|
4
5
|
|
|
5
6
|
class Development implements Family<Directive> {
|
|
@@ -28,7 +29,8 @@ class Development implements Family<Directive> {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
const constructors: Record<string, new (value: any) => Directive> = {
|
|
31
|
-
stub: Stub
|
|
32
|
+
stub: Stub,
|
|
33
|
+
throw: Throw
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
export = new Development()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Output } from '../../Directive'
|
|
2
|
+
import { type Directive } from './types'
|
|
3
|
+
|
|
4
|
+
export class Throw implements Directive {
|
|
5
|
+
private readonly message: any
|
|
6
|
+
|
|
7
|
+
public constructor (message: any) {
|
|
8
|
+
this.message = message
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public apply (): Output {
|
|
12
|
+
throw new Error(this.message)
|
|
13
|
+
}
|
|
14
|
+
}
|
package/source/manifest.test.ts
CHANGED
|
@@ -7,8 +7,10 @@ const namespace = 'ns' + generate()
|
|
|
7
7
|
|
|
8
8
|
let mf: Manifest
|
|
9
9
|
|
|
10
|
+
const operations = { observe: {} }
|
|
11
|
+
|
|
10
12
|
beforeEach(() => {
|
|
11
|
-
mf = { namespace, name } as unknown as Manifest
|
|
13
|
+
mf = { namespace, name, operations } as unknown as Manifest
|
|
12
14
|
})
|
|
13
15
|
|
|
14
16
|
const declaration = {
|
package/source/manifest.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { parse, type Node } from './RTD/syntax'
|
|
1
|
+
import { parse, type Node, type Method, type Query } from './RTD/syntax'
|
|
2
2
|
import { shortcuts } from './Directive'
|
|
3
|
+
import * as schemas from './schemas'
|
|
3
4
|
import type { Manifest } from '@toa.io/norm'
|
|
4
5
|
|
|
5
6
|
export function manifest (declaration: object, manifest: Manifest): Node {
|
|
@@ -12,6 +13,8 @@ export function manifest (declaration: object, manifest: Manifest): Node {
|
|
|
12
13
|
|
|
13
14
|
concretize(node, manifest)
|
|
14
15
|
|
|
16
|
+
schemas.node.validate(node)
|
|
17
|
+
|
|
15
18
|
return node
|
|
16
19
|
}
|
|
17
20
|
|
|
@@ -21,15 +24,25 @@ function wrap (segment: string, declaration: object): object {
|
|
|
21
24
|
|
|
22
25
|
function concretize (node: Node, manifest: Manifest): void {
|
|
23
26
|
for (const route of node.routes) {
|
|
24
|
-
for (const method of route.node.methods)
|
|
25
|
-
|
|
26
|
-
if (method.mapping === undefined)
|
|
27
|
-
continue
|
|
28
|
-
|
|
29
|
-
method.mapping.namespace = manifest.namespace
|
|
30
|
-
method.mapping.component = manifest.name
|
|
31
|
-
}
|
|
27
|
+
for (const method of route.node.methods)
|
|
28
|
+
concretizeMethod(method, manifest)
|
|
32
29
|
|
|
33
30
|
concretize(route.node, manifest)
|
|
34
31
|
}
|
|
35
32
|
}
|
|
33
|
+
|
|
34
|
+
function concretizeMethod (method: Method, manifest: Manifest): void {
|
|
35
|
+
if (method.mapping === undefined)
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
const operation = manifest.operations[method.mapping.endpoint]
|
|
39
|
+
|
|
40
|
+
if (operation === undefined)
|
|
41
|
+
throw new Error(`Operation '${method.mapping.endpoint}' not found`)
|
|
42
|
+
|
|
43
|
+
if (method.mapping.query === undefined && operation.query !== false)
|
|
44
|
+
method.mapping.query = {} as unknown as Query // schema will substitute default values
|
|
45
|
+
|
|
46
|
+
method.mapping.namespace = manifest.namespace
|
|
47
|
+
method.mapping.component = manifest.name
|
|
48
|
+
}
|
package/transpiled/Annotation.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Annotation.js","sourceRoot":"","sources":["../source/Annotation.ts"],"names":[],"mappings":""}
|
package/transpiled/Branch.d.ts
DELETED
package/transpiled/Branch.js
DELETED
package/transpiled/Branch.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Branch.js","sourceRoot":"","sources":["../source/Branch.ts"],"names":[],"mappings":""}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Connector } from '@toa.io/core';
|
|
2
|
-
import { type Bootloader } from './Factory';
|
|
3
|
-
export declare class Composition extends Connector {
|
|
4
|
-
private readonly boot;
|
|
5
|
-
constructor(boot: Bootloader);
|
|
6
|
-
protected open(): Promise<void>;
|
|
7
|
-
protected dispose(): void;
|
|
8
|
-
}
|
|
9
|
-
export declare function components(): Components;
|
|
10
|
-
interface Components {
|
|
11
|
-
labels: string[];
|
|
12
|
-
paths: string[];
|
|
13
|
-
}
|
|
14
|
-
export {};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.components = exports.Composition = void 0;
|
|
4
|
-
const node_fs_1 = require("node:fs");
|
|
5
|
-
const node_path_1 = require("node:path");
|
|
6
|
-
const core_1 = require("@toa.io/core");
|
|
7
|
-
class Composition extends core_1.Connector {
|
|
8
|
-
boot;
|
|
9
|
-
constructor(boot) {
|
|
10
|
-
super();
|
|
11
|
-
this.boot = boot;
|
|
12
|
-
}
|
|
13
|
-
async open() {
|
|
14
|
-
const paths = find();
|
|
15
|
-
const composition = await this.boot.composition(paths);
|
|
16
|
-
await composition.connect();
|
|
17
|
-
this.depends(composition);
|
|
18
|
-
console.info('Composition complete.');
|
|
19
|
-
}
|
|
20
|
-
dispose() {
|
|
21
|
-
console.info('Composition shutdown complete.');
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
exports.Composition = Composition;
|
|
25
|
-
function find() {
|
|
26
|
-
return entries().map((entry) => (0, node_path_1.resolve)(ROOT, entry.name));
|
|
27
|
-
}
|
|
28
|
-
function entries() {
|
|
29
|
-
const entries = (0, node_fs_1.readdirSync)(ROOT, { withFileTypes: true });
|
|
30
|
-
return entries.filter((entry) => entry.isDirectory());
|
|
31
|
-
}
|
|
32
|
-
function components() {
|
|
33
|
-
const labels = [];
|
|
34
|
-
const paths = [];
|
|
35
|
-
for (const entry of entries()) {
|
|
36
|
-
labels.push(entry.name.replace('.', '-'));
|
|
37
|
-
paths.push((0, node_path_1.resolve)(ROOT, entry.name));
|
|
38
|
-
}
|
|
39
|
-
return { labels, paths };
|
|
40
|
-
}
|
|
41
|
-
exports.components = components;
|
|
42
|
-
const ROOT = (0, node_path_1.resolve)(__dirname, '../components/');
|
|
43
|
-
//# sourceMappingURL=Composition.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Composition.js","sourceRoot":"","sources":["../source/Composition.ts"],"names":[],"mappings":";;;AAAA,qCAAqC;AACrC,yCAAmC;AAEnC,uCAAwC;AAGxC,MAAa,WAAY,SAAQ,gBAAS;IACvB,IAAI,CAAY;IAEjC,YAAoB,IAAgB;QAClC,KAAK,EAAE,CAAA;QACP,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;IAEkB,KAAK,CAAC,IAAI;QAC3B,MAAM,KAAK,GAAG,IAAI,EAAE,CAAA;QACpB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;QAEtD,MAAM,WAAW,CAAC,OAAO,EAAE,CAAA;QAE3B,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;QAEzB,OAAO,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;IACvC,CAAC;IAEkB,OAAO;QACxB,OAAO,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAA;IAChD,CAAC;CACF;AAtBD,kCAsBC;AAED,SAAS,IAAI;IACX,OAAO,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAA,mBAAO,EAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;AAC5D,CAAC;AAED,SAAS,OAAO;IACd,MAAM,OAAO,GAAG,IAAA,qBAAW,EAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;IAE1D,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAA;AACvD,CAAC;AAED,SAAgB,UAAU;IACxB,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,EAAE;QAC7B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;QACzC,KAAK,CAAC,IAAI,CAAC,IAAA,mBAAO,EAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;KACtC;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;AAC1B,CAAC;AAVD,gCAUC;AAOD,MAAM,IAAI,GAAG,IAAA,mBAAO,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA"}
|
package/transpiled/Context.d.ts
DELETED
package/transpiled/Context.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Context.js","sourceRoot":"","sources":["../source/Context.ts"],"names":[],"mappings":""}
|