@toa.io/extensions.exposition 1.0.0-alpha.25 → 1.0.0-alpha.27

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.
@@ -77,8 +77,12 @@ query:
77
77
 
78
78
  ### Path variables
79
79
 
80
- Path variables are prepended to the `criteria` request query parameter using logical AND,
81
- except for the [`POST` method](#post-method).
80
+ Path variables are prepended to the `criteria` request query parameter except for
81
+ the [`POST` method](#post-method).
82
+
83
+ If query criteria starts with logical operator (`,` or `;`), then path variables are prepended
84
+ accordingly.
85
+ `AND` logical operator is used by default.
82
86
 
83
87
  Given the following declaration:
84
88
 
@@ -92,7 +96,7 @@ exposition:
92
96
  GET:
93
97
  endpoint: observe
94
98
  query:
95
- criteria: state==hot; # open criteria
99
+ criteria: ,state==hot; # open criteria
96
100
  ```
97
101
 
98
102
  and the following request:
@@ -104,7 +108,7 @@ GET /dummies/cool/?criteria=rank==5
104
108
  Operation call will have the following query criteria:
105
109
 
106
110
  ```yaml
107
- criteria: state==hot;type==cool;rank=5
111
+ criteria: (type==cool,state==hot);(rank=5)
108
112
  ```
109
113
 
110
114
  #### POST method
@@ -0,0 +1,34 @@
1
+ Feature: Debugging
2
+
3
+ Scenario: Operation call
4
+ Given the `identity.basic` database contains:
5
+ | _id | authority | username | password |
6
+ | efe3a65ebbee47ed95a73edd911ea328 | nex | developer | $2b$10$ZRSKkgZoGnrcTNA5w5eCcu3pxDzdTduhteVYXcp56AaNcilNkwJ.O |
7
+ And the `identity.roles` database contains:
8
+ | _id | identity | role |
9
+ | 775a648d054e4ce1a65f8f17e5b51803 | efe3a65ebbee47ed95a73edd911ea328 | developer |
10
+ And the annotation:
11
+ """yaml
12
+ debug: true
13
+ """
14
+ And the `greeter` is running with the following manifest:
15
+ """yaml
16
+ exposition:
17
+ /:
18
+ auth:role: developer
19
+ io:output: true
20
+ GET: greet
21
+ """
22
+ When the following request is received:
23
+ """
24
+ GET /greeter/ HTTP/1.1
25
+ host: nex.toa.io
26
+ authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
27
+ accept: text/plain
28
+ """
29
+ Then the following reply is sent:
30
+ """
31
+ 200 OK
32
+
33
+ Hello
34
+ """
@@ -183,6 +183,17 @@ Feature: Octets directive family
183
183
  type: image/svg+xml
184
184
  """
185
185
 
186
+ Scenario: Rejection video/avi
187
+ When the stream of `sample.avi` is received with the following headers:
188
+ """
189
+ POST /media/images/ HTTP/1.1
190
+ host: nex.toa.io
191
+ """
192
+ Then the following reply is sent:
193
+ """
194
+ 415 Unsupported Media Type
195
+ """
196
+
186
197
  Scenario: Fetching non-existent BLOB
187
198
  When the following request is received:
188
199
  """
@@ -0,0 +1,14 @@
1
+ Feature: Probes
2
+
3
+ Scenario: Startup probe
4
+ Given the Gateway is running
5
+ And after 1 second
6
+ When the following request is received:
7
+ """
8
+ GET /.ready HTTP/1.1
9
+ """
10
+ Then the following reply is sent:
11
+ """
12
+ 200 OK
13
+ cache-control: no-store
14
+ """
@@ -137,6 +137,37 @@ Feature: Queries
137
137
  volume: 200
138
138
  """
139
139
 
140
+ Scenario: Request to a route with path variable using OR operator
141
+ Given the `pots` is running with the following manifest:
142
+ """yaml
143
+ exposition:
144
+ /:volume:
145
+ io:output: true
146
+ GET:
147
+ query:
148
+ criteria: ',volume==100'
149
+ endpoint: enumerate
150
+ """
151
+ When the following request is received:
152
+ """
153
+ GET /pots/200/ HTTP/1.1
154
+ host: nex.toa.io
155
+ accept: application/yaml
156
+ """
157
+ Then the following reply is sent:
158
+ """
159
+ 200 OK
160
+ content-type: application/yaml
161
+
162
+ - id: 4c4759e6f9c74da989d64511df42d6f4
163
+ title: First pot
164
+ volume: 100
165
+ temperature: 80
166
+ - id: 99988d785d7d445cad45dbf8531f560b
167
+ title: Second pot
168
+ volume: 200
169
+ """
170
+
140
171
  Scenario: Request to a route with predefined criteria
141
172
  Given the `pots` is running with the following manifest:
142
173
  """yaml
@@ -99,8 +99,7 @@ Feature: Routes
99
99
  """
100
100
 
101
101
  Scenario: Routes with naming conflicts
102
- Given the Gateway is running
103
- And the `users` is running with the following manifest:
102
+ Given the `users` is running with the following manifest:
104
103
  """yaml
105
104
  exposition:
106
105
  /:
@@ -23,7 +23,7 @@ Feature: Server timing
23
23
  server-timing:
24
24
  """
25
25
 
26
- Scenario: Server timing is sent when debug is enabled
26
+ Scenario: Server timing is sent when `trace` is enabled
27
27
  Given the annotation:
28
28
  """
29
29
  trace: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/extensions.exposition",
3
- "version": "1.0.0-alpha.25",
3
+ "version": "1.0.0-alpha.27",
4
4
  "description": "Toa Exposition",
5
5
  "author": "temich <tema.gurtovoy@gmail.com>",
6
6
  "homepage": "https://github.com/toa-io/toa#readme",
@@ -17,9 +17,9 @@
17
17
  "access": "public"
18
18
  },
19
19
  "dependencies": {
20
- "@toa.io/core": "1.0.0-alpha.25",
21
- "@toa.io/generic": "1.0.0-alpha.25",
22
- "@toa.io/schemas": "1.0.0-alpha.25",
20
+ "@toa.io/core": "1.0.0-alpha.27",
21
+ "@toa.io/generic": "1.0.0-alpha.27",
22
+ "@toa.io/schemas": "1.0.0-alpha.27",
23
23
  "bcryptjs": "2.4.3",
24
24
  "error-value": "0.3.0",
25
25
  "js-yaml": "4.1.0",
@@ -45,11 +45,11 @@
45
45
  "features:security": "cucumber-js --tags @security"
46
46
  },
47
47
  "devDependencies": {
48
- "@toa.io/agent": "1.0.0-alpha.25",
49
- "@toa.io/extensions.storages": "1.0.0-alpha.25",
48
+ "@toa.io/agent": "1.0.0-alpha.27",
49
+ "@toa.io/extensions.storages": "1.0.0-alpha.27",
50
50
  "@types/bcryptjs": "2.4.3",
51
51
  "@types/cors": "2.8.13",
52
52
  "@types/negotiator": "0.6.1"
53
53
  },
54
- "gitHead": "756ea259f35dda03d45047f8153d441191026877"
54
+ "gitHead": "9bc4bdb919688c5272791020746f70d51a520750"
55
55
  }
package/source/Gateway.ts CHANGED
@@ -55,16 +55,16 @@ export class Gateway extends Connector {
55
55
  protected override async open (): Promise<void> {
56
56
  await this.discover()
57
57
 
58
- console.info('Gateway has started and is awaiting resource branches.')
58
+ console.info('Gateway has started and is awaiting resource branches')
59
59
  }
60
60
 
61
61
  protected override dispose (): void {
62
- console.info('Gateway is closed.')
62
+ console.info('Gateway is closed')
63
63
  }
64
64
 
65
65
  private async call (method: Method, context: http.Context, parameters: Parameter[]): Promise<http.OutgoingMessage> {
66
66
  if (context.url.pathname[context.url.pathname.length - 1] !== '/')
67
- throw new http.NotFound('Trailing slash is required.')
67
+ throw new http.NotFound('Trailing slash is required')
68
68
 
69
69
  if (context.encoder === null)
70
70
  throw new http.NotAcceptable()
@@ -87,7 +87,7 @@ export class Gateway extends Connector {
87
87
  this.tree.merge(branch.node, branch)
88
88
 
89
89
  console.info('Resource branch of ' +
90
- `'${branch.namespace}.${branch.component}' has been merged.`)
90
+ `'${branch.namespace}.${branch.component}' has been merged`)
91
91
  } catch (exception) {
92
92
  console.error(exception)
93
93
  }
@@ -27,6 +27,9 @@ export class Context {
27
27
  this.timing = new Timing(properties.trace)
28
28
  this.debug = properties.debug
29
29
 
30
+ if (this.debug)
31
+ this.log(request)
32
+
30
33
  if (this.request.headers.accept !== undefined) {
31
34
  const match = SUBTYPE.exec(this.request.headers.accept)
32
35
 
@@ -56,6 +59,16 @@ export class Context {
56
59
  ? value
57
60
  : this.pipelines.body.reduce((value, transform) => transform(value), value)
58
61
  }
62
+
63
+ private log (request: IncomingMessage): void {
64
+ const message = `${request.method} ${request.url}`
65
+ const { authorization, ...headers } = request.headers
66
+
67
+ if (authorization !== undefined)
68
+ headers.authorization = authorization.slice(0, authorization.indexOf(' '))
69
+
70
+ console.debug(message, headers)
71
+ }
59
72
  }
60
73
 
61
74
  export interface IncomingMessage extends http.IncomingMessage {
@@ -2,6 +2,7 @@ import fs from 'node:fs'
2
2
  import os from 'node:os'
3
3
  import * as http from 'node:http'
4
4
  import { once } from 'node:events'
5
+ import { setTimeout } from 'node:timers/promises'
5
6
  import { Connector } from '@toa.io/core'
6
7
  import { type OutgoingMessage, write } from './messages'
7
8
  import { ClientError, Exception } from './exceptions'
@@ -13,6 +14,8 @@ export class Server extends Connector {
13
14
  private readonly properties: Properties
14
15
  private readonly authorities: Record<string, string>
15
16
  private process?: Processing
17
+ private ready: boolean = false
18
+ private startedAt: number = 0
16
19
 
17
20
  private constructor (properties: Properties) {
18
21
  super()
@@ -23,18 +26,6 @@ export class Server extends Connector {
23
26
  this.server.on('request', (req, res) => this.listener(req, res))
24
27
  }
25
28
 
26
- public get port (): number {
27
- if (this.properties.port !== 0)
28
- return this.properties.port
29
-
30
- const address = this.server.address()
31
-
32
- if (address === null || typeof address === 'string')
33
- throw new Error('Server is not listening on a port.')
34
-
35
- return address.port
36
- }
37
-
38
29
  public static create (options: Options): Server {
39
30
  const properties: Properties = Object.assign({}, DEFAULTS, options)
40
31
 
@@ -46,21 +37,29 @@ export class Server extends Connector {
46
37
  }
47
38
 
48
39
  protected override async open (): Promise<void> {
40
+ this.startedAt = Date.now()
49
41
  this.server.listen(this.properties.port)
50
42
 
51
43
  await once(this.server, 'listening')
52
44
 
53
- console.info('HTTP Server is listening.')
45
+ console.info('HTTP Server is listening')
46
+
47
+ await setTimeout(this.properties.delay)
48
+
49
+ this.ready = true
50
+
51
+ console.info('Ready')
54
52
  }
55
53
 
56
54
  protected override async close (): Promise<void> {
57
55
  this.server.close()
56
+ this.ready = false
58
57
 
59
- console.info('HTTP Server stopped accepting new connections.')
58
+ console.info('HTTP Server stopped accepting new connections')
60
59
 
61
60
  await once(this.server, 'close')
62
61
 
63
- console.info('HTTP Server has been stopped.')
62
+ console.info('HTTP Server has been stopped')
64
63
  }
65
64
 
66
65
  private listener (request: http.IncomingMessage, response: http.ServerResponse): void {
@@ -70,6 +69,18 @@ export class Server extends Connector {
70
69
  return
71
70
  }
72
71
 
72
+ if (request.url === '/.ready') {
73
+ if (this.ready)
74
+ response.writeHead(200, { 'cache-control': 'no-store' }).end()
75
+ else {
76
+ const remaining = (Math.ceil((Date.now() - this.startedAt) / 1000)).toString()
77
+
78
+ response.writeHead(503, { 'retry-after': remaining }).end()
79
+ }
80
+
81
+ return
82
+ }
83
+
73
84
  if (request.headers.host === undefined || !(request.headers.host in this.authorities)) {
74
85
  response.writeHead(404).end('Unknown authority')
75
86
 
@@ -133,11 +144,15 @@ async function adam (request: http.IncomingMessage): Promise<any> {
133
144
  return once(request, 'end')
134
145
  }
135
146
 
147
+ export const PORT = 8000
148
+ export const DELAY = 3 // seconds
149
+
136
150
  const DEFAULTS: Omit<Properties, 'authorities'> = {
137
151
  methods: new Set<string>(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']),
138
152
  debug: false,
139
153
  trace: false,
140
- port: 8000
154
+ port: PORT,
155
+ delay: DELAY * 1000
141
156
  }
142
157
 
143
158
  interface Properties {
@@ -146,6 +161,7 @@ interface Properties {
146
161
  debug: boolean
147
162
  trace: boolean
148
163
  port: number
164
+ delay: number
149
165
  }
150
166
 
151
167
  export type Options = { authorities: Properties['authorities'] } & {
package/source/Mapping.ts CHANGED
@@ -38,6 +38,8 @@ class QueryableMapping extends Mapping {
38
38
 
39
39
  class InputMapping extends Mapping {
40
40
  public fit (input: any, _: unknown, parameters: Parameter[]): core.Request {
41
+ const request: core.Request = {}
42
+
41
43
  if (input === undefined && parameters.length > 0)
42
44
  input = {}
43
45
 
@@ -45,6 +47,9 @@ class InputMapping extends Mapping {
45
47
  for (const parameter of parameters)
46
48
  input[parameter.name] = parameter.value
47
49
 
48
- return { input }
50
+ if (input !== undefined)
51
+ request.input = input
52
+
53
+ return request
49
54
  }
50
55
  }
@@ -16,7 +16,7 @@ it('should combine request criteria', async () => {
16
16
  const instance = new Query(query)
17
17
  const result = instance.fit({ criteria: 'qux==4' }, parameters)
18
18
 
19
- expect(result.criteria).toStrictEqual('(foo==1);(bar==2;baz==3);(qux==4)')
19
+ expect(result.criteria).toStrictEqual('(bar==2;baz==3);(foo==1);(qux==4)')
20
20
  })
21
21
 
22
22
  it('should set id parameter as query.id', async () => {
package/source/Query.ts CHANGED
@@ -7,15 +7,20 @@ import type * as core from '@toa.io/core'
7
7
  export class Query {
8
8
  private readonly query: syntax.Query
9
9
  private readonly closed: boolean = false
10
+ private readonly prepend: ',' | ';' = ';'
10
11
 
11
12
  public constructor (query: syntax.Query) {
12
13
  if (query.criteria !== undefined) {
13
- const open = query.criteria[query.criteria.length - 1] === ';'
14
-
15
- if (open)
14
+ if (query.criteria.endsWith(';'))
16
15
  query.criteria = query.criteria.slice(0, -1)
17
16
  else
18
17
  this.closed = true
18
+
19
+ if (query.criteria.startsWith(',') || query.criteria.startsWith(';')) {
20
+ this.prepend = query.criteria[0] as ',' | ';'
21
+
22
+ query.criteria = query.criteria.slice(1)
23
+ }
19
24
  }
20
25
 
21
26
  this.query = query
@@ -35,11 +40,7 @@ export class Query {
35
40
  }
36
41
 
37
42
  private fitCriteria (query: http.Query, parameters: Parameter[]): void {
38
- const criteria: string[] = []
39
-
40
- if (this.query.criteria !== undefined)
41
- criteria.push(this.query.criteria)
42
-
43
+ const groups: CriteriaGroup[] = []
43
44
  const idx = parameters.findIndex((parameter) => parameter.name === 'id')
44
45
 
45
46
  if (idx !== -1) {
@@ -49,29 +50,28 @@ export class Query {
49
50
  }
50
51
 
51
52
  if (parameters.length > 0) {
52
- const chunks = parameters
53
+ const criteria = parameters
53
54
  .map(({ name, value }) => `${name}==${value}`)
54
55
  .join(';')
55
56
 
56
- criteria.push(chunks)
57
+ groups.push({ criteria, operator: this.prepend })
57
58
  }
58
59
 
60
+ if (this.query.criteria !== undefined)
61
+ groups.push({ criteria: this.query.criteria, operator: ';' })
62
+
59
63
  if (query.criteria !== undefined)
60
64
  if (this.closed)
61
65
  throw new http.BadRequest('Query criteria is closed')
62
66
  else
63
- criteria.push(query.criteria)
64
-
65
- switch (criteria.length) {
66
- case 0:
67
- break
68
- case 1:
69
- query.criteria = criteria[0]
70
- break
71
- default:
72
- query.criteria = '(' + criteria.join(');(') + ')'
73
- break
74
- }
67
+ groups.push({ criteria: query.criteria, operator: WHATEVER })
68
+
69
+ if (groups.length > 0)
70
+ query.criteria = groups.reduce((acc, { criteria, operator }, i) => {
71
+ return i === groups.length - 1
72
+ ? `${acc}(${criteria})`
73
+ : `${acc}(${criteria})${operator}`
74
+ }, '')
75
75
  }
76
76
 
77
77
  private fitRanges (qs: http.Query): void {
@@ -107,3 +107,10 @@ function fit (string: string, range: [number, number], name: string): number {
107
107
 
108
108
  return number
109
109
  }
110
+
111
+ const WHATEVER = ';'
112
+
113
+ interface CriteriaGroup {
114
+ criteria: string
115
+ operator: ',' | ';'
116
+ }
@@ -6,6 +6,7 @@ import * as schemas from './schemas'
6
6
  import { shortcuts } from './Directive'
7
7
  import { components } from './Composition'
8
8
  import { parse } from './RTD/syntax'
9
+ import { DELAY, PORT } from './HTTP/Server'
9
10
 
10
11
  export function deployment (_: unknown, annotation?: Annotation): Dependency {
11
12
  assert.ok(annotation !== undefined, 'Exposition context annotation is required')
@@ -16,12 +17,17 @@ export function deployment (_: unknown, annotation?: Annotation): Dependency {
16
17
  const service: Service = {
17
18
  group: 'exposition',
18
19
  name: 'gateway',
19
- port: 8000,
20
+ port: PORT,
20
21
  // eslint-disable-next-line @typescript-eslint/no-var-requires
21
22
  version: require('../package.json').version,
22
23
  variables: [],
23
24
  components: labels,
24
- ingress: { hosts: [] }
25
+ ingress: { hosts: [] },
26
+ probe: {
27
+ path: '/.ready',
28
+ port: PORT,
29
+ delay: DELAY
30
+ }
25
31
  }
26
32
 
27
33
  if (annotation?.['/'] !== undefined) {
@@ -57,14 +57,14 @@ class Gateway extends core_1.Connector {
57
57
  }
58
58
  async open() {
59
59
  await this.discover();
60
- console.info('Gateway has started and is awaiting resource branches.');
60
+ console.info('Gateway has started and is awaiting resource branches');
61
61
  }
62
62
  dispose() {
63
- console.info('Gateway is closed.');
63
+ console.info('Gateway is closed');
64
64
  }
65
65
  async call(method, context, parameters) {
66
66
  if (context.url.pathname[context.url.pathname.length - 1] !== '/')
67
- throw new http.NotFound('Trailing slash is required.');
67
+ throw new http.NotFound('Trailing slash is required');
68
68
  if (context.encoder === null)
69
69
  throw new http.NotAcceptable();
70
70
  if (method.endpoint === null)
@@ -81,7 +81,7 @@ class Gateway extends core_1.Connector {
81
81
  try {
82
82
  this.tree.merge(branch.node, branch);
83
83
  console.info('Resource branch of ' +
84
- `'${branch.namespace}.${branch.component}' has been merged.`);
84
+ `'${branch.namespace}.${branch.component}' has been merged`);
85
85
  }
86
86
  catch (exception) {
87
87
  console.error(exception);
@@ -1 +1 @@
1
- {"version":3,"file":"Gateway.js","sourceRoot":"","sources":["../source/Gateway.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Gateway.js","sourceRoot":"","sources":["../source/Gateway.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAuD;AACvD,6CAA8B;AAC9B,6CAAsC;AAMtC,MAAa,OAAQ,SAAQ,gBAAS;IACnB,SAAS,CAAW;IACpB,IAAI,CAAM;IACV,WAAW,CAAc;IAE1C,YAAoB,SAAoB,EAAE,IAAU,EAAE,YAA0B;QAC9E,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,WAAW,GAAG,YAAY,CAAA;QAE/B,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACzB,CAAC;IAEM,KAAK,CAAC,OAAO,CAAE,OAAqB;QACzC,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAC3D,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;QAEtC,IAAI,YAAY,KAAK,IAAI;YACvB,OAAO,YAAY,CAAA;QAErB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAEnD,IAAI,KAAK,KAAK,IAAI;YAChB,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAA;QAE5C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,KAAK,CAAA;QAElC,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC;YAC3C,MAAM,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAA;QAEnC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QAEnD,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,EAC3D,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAO,CAAC,CAAA;QAElE,MAAM,QAAQ,GAAG,YAAY;YAC3B,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAA;QAE9E,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,EACnC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAO,CAAC,CAAA;QAE7D,OAAO,QAAQ,CAAA;IACjB,CAAC;IAEkB,KAAK,CAAC,IAAI;QAC3B,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAA;QAErB,OAAO,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAA;IACvE,CAAC;IAEkB,OAAO;QACxB,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;IACnC,CAAC;IAEO,KAAK,CAAC,IAAI,CAAE,MAAc,EAAE,OAAqB,EAAE,UAAuB;QAChF,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG;YAC/D,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAA;QAEvD,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI;YAC1B,MAAM,IAAI,IAAI,CAAC,aAAa,EAAE,CAAA;QAEhC,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI;YAC1B,MAAM,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAA;QAEnC,OAAO,MAAM,MAAM,CAAC,QAAQ;aACzB,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC;aACzB,KAAK,CAAC,oBAAO,CAAyB,CAAA;IAC3C,CAAC;IAEO,KAAK,CAAC,QAAQ;QACpB,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAS,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACrE,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAO,MAAM,EAAE,IAAI,CAAC,CAAA;IACnD,CAAC;IAEO,KAAK,CAAE,MAAc;QAC3B,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;YAEpC,OAAO,CAAC,IAAI,CAAC,qBAAqB;gBAChC,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,mBAAmB,CAAC,CAAA;QAChE,CAAC;QAAC,OAAO,SAAS,EAAE,CAAC;YACnB,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QAC1B,CAAC;IACH,CAAC;CACF;AAtFD,0BAsFC"}
@@ -14,6 +14,7 @@ export declare class Context {
14
14
  readonly pipelines: Pipelines;
15
15
  constructor(authority: string, request: IncomingMessage, properties: Properties);
16
16
  body<T>(): Promise<T>;
17
+ private log;
17
18
  }
18
19
  export interface IncomingMessage extends http.IncomingMessage {
19
20
  url: string;
@@ -26,6 +26,8 @@ class Context {
26
26
  this.url = new URL(request.url, `https://${request.headers.host}`);
27
27
  this.timing = new Timing_1.Timing(properties.trace);
28
28
  this.debug = properties.debug;
29
+ if (this.debug)
30
+ this.log(request);
29
31
  if (this.request.headers.accept !== undefined) {
30
32
  const match = SUBTYPE.exec(this.request.headers.accept);
31
33
  if (match !== null) {
@@ -45,6 +47,13 @@ class Context {
45
47
  ? value
46
48
  : this.pipelines.body.reduce((value, transform) => transform(value), value);
47
49
  }
50
+ log(request) {
51
+ const message = `${request.method} ${request.url}`;
52
+ const { authorization, ...headers } = request.headers;
53
+ if (authorization !== undefined)
54
+ headers.authorization = authorization.slice(0, authorization.indexOf(' '));
55
+ console.debug(message, headers);
56
+ }
48
57
  }
49
58
  exports.Context = Context;
50
59
  const SUBTYPE = /^(?<type>\w{1,32})\/(vnd\.toa\.(?<subtype>\S{1,32})\+)(?<suffix>\S{1,32})$/;
@@ -1 +1 @@
1
- {"version":3,"file":"Context.js","sourceRoot":"","sources":["../../source/HTTP/Context.ts"],"names":[],"mappings":";;;;;;AAAA,4DAAmC;AACnC,qCAAiC;AACjC,uCAAuD;AACvD,yCAAiC;AAIjC,MAAa,OAAO;IACF,SAAS,CAAQ;IACjB,OAAO,CAAiB;IACxB,GAAG,CAAK;IACR,OAAO,GAAkB,IAAI,CAAA;IAC7B,OAAO,GAAkB,IAAI,CAAA;IAC7B,MAAM,CAAQ;IACd,KAAK,CAAS;IAEd,SAAS,GAAc;QACrC,IAAI,EAAE,EAAE;QACR,QAAQ,EAAE,EAAE;KACb,CAAA;IAED,YAAoB,SAAiB,EAAE,OAAwB,EAAE,UAAsB;QACrF,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QAEtB,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;QAClE,IAAI,CAAC,MAAM,GAAG,IAAI,eAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QAC1C,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAA;QAE7B,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YAEvD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,MAAM,EACJ,IAAI,EACJ,OAAO,EACP,MAAM,EACP,GAAG,KAAK,CAAC,MAAO,CAAA;gBAEjB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,IAAI,IAAI,MAAM,EAAE,CAAA;gBACjD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;YACxB,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,oBAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC/C,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,eAAK,CAAC,CAAA;QAE7C,IAAI,SAAS,KAAK,SAAS;YACzB,IAAI,CAAC,OAAO,GAAG,iBAAO,CAAC,SAAS,CAAC,CAAA;IACrC,CAAC;IAEM,KAAK,CAAC,IAAI;QACf,MAAM,KAAK,GAAG,MAAM,IAAA,eAAI,EAAC,IAAI,CAAC,CAAA;QAE9B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;YACrC,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAA;IAC/E,CAAC;CACF;AAnDD,0BAmDC;AAiBD,MAAM,OAAO,GAAG,4EAA4E,CAAA"}
1
+ {"version":3,"file":"Context.js","sourceRoot":"","sources":["../../source/HTTP/Context.ts"],"names":[],"mappings":";;;;;;AAAA,4DAAmC;AACnC,qCAAiC;AACjC,uCAAuD;AACvD,yCAAiC;AAIjC,MAAa,OAAO;IACF,SAAS,CAAQ;IACjB,OAAO,CAAiB;IACxB,GAAG,CAAK;IACR,OAAO,GAAkB,IAAI,CAAA;IAC7B,OAAO,GAAkB,IAAI,CAAA;IAC7B,MAAM,CAAQ;IACd,KAAK,CAAS;IAEd,SAAS,GAAc;QACrC,IAAI,EAAE,EAAE;QACR,QAAQ,EAAE,EAAE;KACb,CAAA;IAED,YAAoB,SAAiB,EAAE,OAAwB,EAAE,UAAsB;QACrF,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QAEtB,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;QAClE,IAAI,CAAC,MAAM,GAAG,IAAI,eAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QAC1C,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAA;QAE7B,IAAI,IAAI,CAAC,KAAK;YACZ,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QAEnB,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YAEvD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,MAAM,EACJ,IAAI,EACJ,OAAO,EACP,MAAM,EACP,GAAG,KAAK,CAAC,MAAO,CAAA;gBAEjB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,IAAI,IAAI,MAAM,EAAE,CAAA;gBACjD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;YACxB,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,oBAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC/C,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,eAAK,CAAC,CAAA;QAE7C,IAAI,SAAS,KAAK,SAAS;YACzB,IAAI,CAAC,OAAO,GAAG,iBAAO,CAAC,SAAS,CAAC,CAAA;IACrC,CAAC;IAEM,KAAK,CAAC,IAAI;QACf,MAAM,KAAK,GAAG,MAAM,IAAA,eAAI,EAAC,IAAI,CAAC,CAAA;QAE9B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;YACrC,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAA;IAC/E,CAAC;IAEO,GAAG,CAAE,OAAwB;QACnC,MAAM,OAAO,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;QAClD,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAA;QAErD,IAAI,aAAa,KAAK,SAAS;YAC7B,OAAO,CAAC,aAAa,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;QAE5E,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACjC,CAAC;CACF;AAhED,0BAgEC;AAiBD,MAAM,OAAO,GAAG,4EAA4E,CAAA"}
@@ -6,8 +6,9 @@ export declare class Server extends Connector {
6
6
  private readonly properties;
7
7
  private readonly authorities;
8
8
  private process?;
9
+ private ready;
10
+ private startedAt;
9
11
  private constructor();
10
- get port(): number;
11
12
  static create(options: Options): Server;
12
13
  attach(process: Processing): void;
13
14
  protected open(): Promise<void>;
@@ -16,12 +17,15 @@ export declare class Server extends Connector {
16
17
  private success;
17
18
  private fail;
18
19
  }
20
+ export declare const PORT = 8000;
21
+ export declare const DELAY = 3;
19
22
  interface Properties {
20
23
  authorities: Record<string, string>;
21
24
  methods: Set<string>;
22
25
  debug: boolean;
23
26
  trace: boolean;
24
27
  port: number;
28
+ delay: number;
25
29
  }
26
30
  export type Options = {
27
31
  authorities: Properties['authorities'];