@toa.io/extensions.exposition 1.0.0-alpha.278 → 1.0.0-alpha.282
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/components/identity.basic/events/principal.js +5 -1
- package/components/identity.basic/manifest.toa.yaml +11 -1
- package/components/identity.basic/operations/authenticate.js +9 -5
- package/components/identity.basic/operations/authenticate.js.map +1 -1
- package/components/identity.basic/operations/check.js +2 -1
- package/components/identity.basic/operations/check.js.map +1 -1
- package/components/identity.basic/operations/incept.js +4 -5
- package/components/identity.basic/operations/incept.js.map +1 -1
- package/components/identity.basic/operations/lib/credentials.d.ts +5 -0
- package/components/identity.basic/operations/lib/credentials.js +12 -0
- package/components/identity.basic/operations/lib/credentials.js.map +1 -0
- package/components/identity.basic/operations/transit.d.ts +2 -0
- package/components/identity.basic/operations/transit.js +12 -2
- package/components/identity.basic/operations/transit.js.map +1 -1
- package/components/identity.basic/operations/types.d.ts +11 -1
- package/components/identity.basic/source/authenticate.ts +11 -5
- package/components/identity.basic/source/check.ts +2 -1
- package/components/identity.basic/source/incept.ts +5 -5
- package/components/identity.basic/source/lib/credentials.test.ts +18 -0
- package/components/identity.basic/source/lib/credentials.ts +13 -0
- package/components/identity.basic/source/transit.ts +16 -4
- package/components/identity.basic/source/types.ts +13 -1
- package/components/identity.basic/tsconfig.tsbuildinfo +1 -1
- package/components/identity.federation/events/principal.js +1 -0
- package/components/identity.federation/manifest.toa.yaml +5 -1
- package/components/identity.federation/operations/authenticate.js +3 -3
- package/components/identity.federation/operations/authenticate.js.map +1 -1
- package/components/identity.federation/operations/create.js +5 -1
- package/components/identity.federation/operations/create.js.map +1 -1
- package/components/identity.federation/operations/lib/decode.js +5 -1
- package/components/identity.federation/operations/lib/decode.js.map +1 -1
- package/components/identity.federation/operations/lib/exchange.js +3 -3
- package/components/identity.federation/operations/lib/exchange.js.map +1 -1
- package/components/identity.federation/operations/list.js +2 -1
- package/components/identity.federation/operations/list.js.map +1 -1
- package/components/identity.federation/operations/types/configuration.d.ts +2 -1
- package/components/identity.federation/source/authenticate.ts +3 -3
- package/components/identity.federation/source/create.ts +5 -1
- package/components/identity.federation/source/lib/decode.ts +5 -1
- package/components/identity.federation/source/lib/exchange.ts +3 -3
- package/components/identity.federation/source/list.test.ts +1 -1
- package/components/identity.federation/source/list.ts +2 -1
- package/components/identity.federation/source/types/configuration.ts +2 -1
- package/components/identity.federation/tsconfig.tsbuildinfo +1 -1
- package/components/identity.keys/manifest.toa.yaml +18 -1
- package/components/identity.keys/operations/disable.d.ts +5 -0
- package/components/identity.keys/operations/disable.js +5 -0
- package/components/identity.keys/operations/disable.js.map +1 -0
- package/components/identity.keys/operations/revoke.d.ts +15 -0
- package/components/identity.keys/operations/revoke.js +12 -0
- package/components/identity.keys/operations/revoke.js.map +1 -0
- package/components/identity.keys/receivers/identity.bans.created.js +1 -0
- package/components/identity.keys/receivers/identity.bans.updated.js +1 -0
- package/components/identity.keys/receivers/identity.roles.deleted.js +1 -0
- package/components/identity.keys/source/disable.ts +9 -0
- package/components/identity.keys/source/revoke.ts +30 -0
- package/components/identity.keys/tsconfig.tsbuildinfo +1 -1
- package/components/identity.otp/manifest.toa.yaml +6 -0
- package/components/identity.otp/operations/authenticate.js +13 -1
- package/components/identity.otp/operations/authenticate.js.map +1 -1
- package/components/identity.otp/operations/issue.js +3 -2
- package/components/identity.otp/operations/issue.js.map +1 -1
- package/components/identity.otp/operations/lib/Context.d.ts +1 -0
- package/components/identity.otp/source/authenticate.ts +19 -1
- package/components/identity.otp/source/issue.ts +3 -2
- package/components/identity.otp/source/lib/Context.ts +1 -0
- package/components/identity.otp/tsconfig.tsbuildinfo +1 -1
- package/components/identity.passkeys/operations/authenticate.js +2 -1
- package/components/identity.passkeys/operations/authenticate.js.map +1 -1
- package/components/identity.passkeys/operations/challenge.js +3 -3
- package/components/identity.passkeys/operations/challenge.js.map +1 -1
- package/components/identity.passkeys/operations/delete.js +2 -1
- package/components/identity.passkeys/operations/delete.js.map +1 -1
- package/components/identity.passkeys/operations/list.js +2 -1
- package/components/identity.passkeys/operations/list.js.map +1 -1
- package/components/identity.passkeys/source/authenticate.ts +2 -1
- package/components/identity.passkeys/source/challenge.ts +3 -3
- package/components/identity.passkeys/source/delete.ts +2 -1
- package/components/identity.passkeys/source/list.ts +2 -1
- package/components/identity.passkeys/tsconfig.tsbuildinfo +1 -1
- package/components/identity.roles/manifest.toa.yaml +4 -0
- package/components/identity.roles/operations/grant.js +5 -2
- package/components/identity.roles/operations/grant.js.map +1 -1
- package/components/identity.roles/source/grant.ts +6 -2
- package/components/identity.roles/tsconfig.tsbuildinfo +1 -1
- package/components/identity.tokens/manifest.toa.yaml +3 -0
- package/components/identity.tokens/operations/authenticate.js +4 -3
- package/components/identity.tokens/operations/authenticate.js.map +1 -1
- package/components/identity.tokens/operations/decrypt.js +7 -1
- package/components/identity.tokens/operations/decrypt.js.map +1 -1
- package/components/identity.tokens/operations/encrypt.js +3 -2
- package/components/identity.tokens/operations/encrypt.js.map +1 -1
- package/components/identity.tokens/operations/issue.js +2 -1
- package/components/identity.tokens/operations/issue.js.map +1 -1
- package/components/identity.tokens/operations/lib/types.d.ts +3 -0
- package/components/identity.tokens/source/authenticate.test.ts +26 -2
- package/components/identity.tokens/source/authenticate.ts +4 -3
- package/components/identity.tokens/source/decrypt.test.ts +35 -1
- package/components/identity.tokens/source/decrypt.ts +10 -1
- package/components/identity.tokens/source/encrypt.test.ts +15 -0
- package/components/identity.tokens/source/encrypt.ts +4 -2
- package/components/identity.tokens/source/issue.ts +2 -1
- package/components/identity.tokens/source/lib/types.ts +4 -0
- package/components/identity.tokens/tsconfig.tsbuildinfo +1 -1
- package/documentation/authorities.md +3 -0
- package/documentation/components.md +31 -11
- package/documentation/identity.md +38 -6
- package/documentation/io.md +2 -2
- package/documentation/ip.md +24 -0
- package/documentation/passkeys.md +6 -0
- package/features/auth.assert.feature +2 -4
- package/features/auth.claims.feature +1 -0
- package/features/auth.incept.feature +46 -0
- package/features/authorities.feature +39 -0
- package/features/authorities.federation.feature +1 -0
- package/features/identity.bans.feature +63 -0
- package/features/identity.basic.feature +95 -3
- package/features/identity.feature +151 -0
- package/features/identity.federation.feature +5 -0
- package/features/identity.otp.feature +41 -0
- package/features/identity.roles.feature +252 -0
- package/features/identity.tokens.custom.feature +145 -0
- package/features/map.feature +2 -0
- package/features/steps/Gateway.ts +8 -2
- package/features/steps/Realtime.ts +1 -1
- package/package.json +5 -5
- package/readme.md +3 -0
- package/schemas/annotation.cos.yaml +16 -0
- package/source/Annotation.ts +14 -0
- package/source/Composition.ts +5 -5
- package/source/Directive.test.ts +3 -1
- package/source/Directive.ts +6 -2
- package/source/Endpoint.ts +4 -2
- package/source/Factory.ts +12 -9
- package/source/HTTP/Context.ts +12 -2
- package/source/HTTP/Server.ts +16 -3
- package/source/HTTP/address.test.ts +22 -0
- package/source/HTTP/address.ts +17 -0
- package/source/Query.test.ts +15 -1
- package/source/Query.ts +3 -1
- package/source/RTD/Directives.ts +10 -1
- package/source/Remotes.test.ts +7 -12
- package/source/Remotes.ts +5 -5
- package/source/const.ts +3 -0
- package/source/deployment.ts +7 -1
- package/source/directives/auth/Assert.ts +3 -0
- package/source/directives/auth/Authorization.test.ts +24 -0
- package/source/directives/auth/Authorization.ts +80 -11
- package/source/directives/auth/Incept.ts +9 -4
- package/source/directives/auth/Role.test.ts +1 -1
- package/source/directives/auth/Role.ts +2 -1
- package/source/directives/auth/schemes.test.ts +14 -0
- package/source/directives/auth/schemes.ts +14 -0
- package/source/directives/auth/types.ts +3 -0
- package/source/directives/io/IO.ts +10 -3
- package/source/directives/io/lib/throttle/Keys.ts +10 -3
- package/source/directives/io/lib/throttle/Quotas.test.ts +14 -4
- package/source/directives/io/lib/throttle/Quotas.ts +15 -2
- package/source/directives/io/lib/throttle/Sync.test.ts +7 -9
- package/source/directives/io/lib/throttle/Sync.ts +4 -7
- package/source/directives/io/lib/throttle/Warning.test.ts +32 -0
- package/source/directives/io/lib/throttle/Warning.ts +30 -0
- package/source/directives/io/lib/throttle/components/Component.ts +2 -1
- package/source/directives/io/lib/throttle/components/IP.ts +19 -28
- package/source/directives/io/lib/throttle/index.ts +1 -0
- package/source/redact.test.ts +27 -0
- package/source/redact.ts +21 -0
- package/source/schemas.test.ts +17 -0
- package/transpiled/Annotation.d.ts +10 -0
- package/transpiled/Composition.d.ts +3 -3
- package/transpiled/Composition.js +4 -4
- package/transpiled/Composition.js.map +1 -1
- package/transpiled/Directive.d.ts +3 -2
- package/transpiled/Directive.js +3 -1
- package/transpiled/Directive.js.map +1 -1
- package/transpiled/Endpoint.js +3 -2
- package/transpiled/Endpoint.js.map +1 -1
- package/transpiled/Factory.d.ts +3 -3
- package/transpiled/Factory.js +11 -8
- package/transpiled/Factory.js.map +1 -1
- package/transpiled/HTTP/Context.d.ts +4 -0
- package/transpiled/HTTP/Context.js +7 -2
- package/transpiled/HTTP/Context.js.map +1 -1
- package/transpiled/HTTP/Server.d.ts +5 -0
- package/transpiled/HTTP/Server.js +8 -3
- package/transpiled/HTTP/Server.js.map +1 -1
- package/transpiled/HTTP/address.d.ts +7 -0
- package/transpiled/HTTP/address.js +14 -0
- package/transpiled/HTTP/address.js.map +1 -0
- package/transpiled/Query.js +3 -1
- package/transpiled/Query.js.map +1 -1
- package/transpiled/RTD/Directives.d.ts +9 -1
- package/transpiled/Remotes.d.ts +3 -3
- package/transpiled/Remotes.js +4 -4
- package/transpiled/Remotes.js.map +1 -1
- package/transpiled/const.d.ts +2 -0
- package/transpiled/const.js +2 -0
- package/transpiled/const.js.map +1 -1
- package/transpiled/deployment.js +4 -0
- package/transpiled/deployment.js.map +1 -1
- package/transpiled/directives/auth/Assert.js +2 -0
- package/transpiled/directives/auth/Assert.js.map +1 -1
- package/transpiled/directives/auth/Authorization.d.ts +8 -0
- package/transpiled/directives/auth/Authorization.js +61 -11
- package/transpiled/directives/auth/Authorization.js.map +1 -1
- package/transpiled/directives/auth/Incept.d.ts +3 -1
- package/transpiled/directives/auth/Incept.js +8 -4
- package/transpiled/directives/auth/Incept.js.map +1 -1
- package/transpiled/directives/auth/Role.js +2 -1
- package/transpiled/directives/auth/Role.js.map +1 -1
- package/transpiled/directives/auth/schemes.d.ts +10 -0
- package/transpiled/directives/auth/schemes.js +12 -0
- package/transpiled/directives/auth/schemes.js.map +1 -1
- package/transpiled/directives/auth/types.d.ts +2 -0
- package/transpiled/directives/io/IO.d.ts +4 -1
- package/transpiled/directives/io/IO.js +7 -3
- package/transpiled/directives/io/IO.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Keys.d.ts +2 -1
- package/transpiled/directives/io/lib/throttle/Keys.js +7 -2
- package/transpiled/directives/io/lib/throttle/Keys.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Quotas.d.ts +3 -2
- package/transpiled/directives/io/lib/throttle/Quotas.js +8 -1
- package/transpiled/directives/io/lib/throttle/Quotas.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Sync.d.ts +2 -3
- package/transpiled/directives/io/lib/throttle/Sync.js +1 -3
- package/transpiled/directives/io/lib/throttle/Sync.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Warning.d.ts +11 -0
- package/transpiled/directives/io/lib/throttle/Warning.js +24 -0
- package/transpiled/directives/io/lib/throttle/Warning.js.map +1 -0
- package/transpiled/directives/io/lib/throttle/components/Component.d.ts +2 -1
- package/transpiled/directives/io/lib/throttle/components/IP.d.ts +10 -2
- package/transpiled/directives/io/lib/throttle/components/IP.js +18 -23
- package/transpiled/directives/io/lib/throttle/components/IP.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/index.d.ts +1 -0
- package/transpiled/directives/io/lib/throttle/index.js +1 -0
- package/transpiled/directives/io/lib/throttle/index.js.map +1 -1
- package/transpiled/redact.d.ts +5 -0
- package/transpiled/redact.js +17 -0
- package/transpiled/redact.js.map +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/components/exposition.atom/manifest.toa.yaml +0 -21
- package/components/exposition.atom/operations/meter.js +0 -5
|
@@ -10,3 +10,17 @@ export const PROVIDERS: Record<Scheme, Remote> = {
|
|
|
10
10
|
|
|
11
11
|
export const INCEPTION: Remote[] = ['basic', 'federation']
|
|
12
12
|
export const PRIMARY: Scheme = 'token'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The provider of a scheme, or nothing for a scheme that is not one — including a name a
|
|
16
|
+
* plain object answers on its own, like `constructor`.
|
|
17
|
+
*/
|
|
18
|
+
export function provider (scheme: string): Remote | undefined {
|
|
19
|
+
return Object.hasOwn(PROVIDERS, scheme) ? PROVIDERS[scheme as Scheme] : undefined
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The rejection of credentials that are verifiable and owned by no identity: the one
|
|
24
|
+
* inception goes ahead with.
|
|
25
|
+
*/
|
|
26
|
+
export const UNKNOWN = 'NOT_FOUND'
|
|
@@ -6,14 +6,22 @@ import type * as http from '../../HTTP/index.js'
|
|
|
6
6
|
import type { Parameter, DirectiveFamily } from '../../RTD/index.js'
|
|
7
7
|
import type { Remotes } from '../../Remotes.js'
|
|
8
8
|
import type { Constructor, Directive } from './Directive.js'
|
|
9
|
+
import { ATOM_GROUP } from '../../const.js'
|
|
10
|
+
import type { extensions } from '@toa.io/core'
|
|
9
11
|
|
|
10
12
|
export class IO implements DirectiveFamily<Directive> {
|
|
11
13
|
public readonly name = 'io'
|
|
12
14
|
public readonly mandatory = true
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
private host!: extensions.Host
|
|
17
|
+
|
|
18
|
+
/** Throttling reconciles through the atom of the gateways, one for every directive. */
|
|
15
19
|
private sync: Sync | null = null
|
|
16
20
|
|
|
21
|
+
public mount (host: extensions.Host): void {
|
|
22
|
+
this.host = host
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
// eslint-disable-next-line max-params
|
|
18
26
|
public create (name: string, value: unknown, remotes: Remotes, route: string): Directive {
|
|
19
27
|
if (!(name in constructors))
|
|
@@ -23,9 +31,8 @@ export class IO implements DirectiveFamily<Directive> {
|
|
|
23
31
|
|
|
24
32
|
Directive.validate(value)
|
|
25
33
|
|
|
26
|
-
// discovering boots the component, so nothing is discovered until something throttles
|
|
27
34
|
if (name === 'throttle')
|
|
28
|
-
this.sync ??= new Sync(
|
|
35
|
+
this.sync ??= new Sync(this.host.atom(ATOM_GROUP))
|
|
29
36
|
|
|
30
37
|
return new Directive(value, this.sync!, route)
|
|
31
38
|
}
|
|
@@ -26,11 +26,18 @@ export class Keys {
|
|
|
26
26
|
return new this(components, conditions)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
/** The key of the request, or nothing when a component cannot key it. */
|
|
30
|
+
public get (context: Context, parameters: Parameter[] = NONE): string | undefined {
|
|
30
31
|
const hash = createHash('sha256')
|
|
31
32
|
|
|
32
|
-
for (const component of this.components)
|
|
33
|
-
|
|
33
|
+
for (const component of this.components) {
|
|
34
|
+
const part = component.get(context, parameters)
|
|
35
|
+
|
|
36
|
+
if (part === undefined)
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
hash.update(part)
|
|
40
|
+
}
|
|
34
41
|
|
|
35
42
|
return hash.digest('hex')
|
|
36
43
|
}
|
|
@@ -217,12 +217,13 @@ describe('path', () => {
|
|
|
217
217
|
describe('ip', () => {
|
|
218
218
|
beforeEach(() => {
|
|
219
219
|
configuration = createConfiguration({ key: [{ method: 'ip' }] })
|
|
220
|
-
quotas = Quotas.create(configuration)
|
|
221
220
|
})
|
|
222
221
|
|
|
223
|
-
it('should
|
|
224
|
-
|
|
225
|
-
|
|
222
|
+
it('should key on the address the context resolved', () => {
|
|
223
|
+
quotas = Quotas.create(configuration)
|
|
224
|
+
|
|
225
|
+
const one = createContext({ ip: '1.1.1.1' })
|
|
226
|
+
const two = createContext({ ip: '2.2.2.2' })
|
|
226
227
|
|
|
227
228
|
quotas.check(one, [])
|
|
228
229
|
quotas.check(one, [])
|
|
@@ -230,6 +231,15 @@ describe('ip', () => {
|
|
|
230
231
|
assert.ok(quotas.check(one, []) > 0)
|
|
231
232
|
assert.strictEqual(quotas.check(two, []), 0)
|
|
232
233
|
})
|
|
234
|
+
|
|
235
|
+
it('should let a request without an address through', () => {
|
|
236
|
+
quotas = Quotas.create(configuration)
|
|
237
|
+
|
|
238
|
+
const context = createContext({})
|
|
239
|
+
|
|
240
|
+
for (let i = 0; i < 5; i++)
|
|
241
|
+
assert.strictEqual(quotas.check(context, []), 0)
|
|
242
|
+
})
|
|
233
243
|
})
|
|
234
244
|
|
|
235
245
|
describe('route', () => {
|
|
@@ -50,7 +50,9 @@ export class Quotas {
|
|
|
50
50
|
this.period = period(options.interval)
|
|
51
51
|
|
|
52
52
|
// a key means one budget, so quotas that do not share one must not share a key
|
|
53
|
-
this.prefix =
|
|
53
|
+
this.prefix = options.name === undefined
|
|
54
|
+
? `t:${options.requests}:${options.interval}:`
|
|
55
|
+
: `${options.name}:`
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
public static create (configuration: Configuration, route: string = ''): Quotas {
|
|
@@ -70,6 +72,10 @@ export class Quotas {
|
|
|
70
72
|
public check (context: Context, parameters: Parameter[]): number {
|
|
71
73
|
const key = this.keys.get(context, parameters)
|
|
72
74
|
|
|
75
|
+
// a request that cannot be keyed is not metered
|
|
76
|
+
if (key === undefined)
|
|
77
|
+
return 0
|
|
78
|
+
|
|
73
79
|
this.keyed.set(context, key)
|
|
74
80
|
|
|
75
81
|
const now = Date.now()
|
|
@@ -93,6 +99,10 @@ export class Quotas {
|
|
|
93
99
|
|
|
94
100
|
// preflight always runs first, and a request it refuses never reaches settle
|
|
95
101
|
const key = this.keyed.get(input) ?? this.keys.get(input)
|
|
102
|
+
|
|
103
|
+
if (key === undefined)
|
|
104
|
+
return
|
|
105
|
+
|
|
96
106
|
const now = Date.now()
|
|
97
107
|
const entry = this.entries.get(key)
|
|
98
108
|
const tat = Math.max(entry?.tat ?? now, now)
|
|
@@ -175,9 +185,12 @@ interface Entry {
|
|
|
175
185
|
debt: number
|
|
176
186
|
}
|
|
177
187
|
|
|
178
|
-
interface Options {
|
|
188
|
+
export interface Options {
|
|
179
189
|
keys: Keys
|
|
180
190
|
requests: number
|
|
181
191
|
interval: number
|
|
182
192
|
conditional: boolean
|
|
193
|
+
|
|
194
|
+
/** what the keys are reported under, in place of the budget they carry */
|
|
195
|
+
name?: string
|
|
183
196
|
}
|
|
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict'
|
|
|
3
3
|
|
|
4
4
|
import { Sync } from './Sync.js'
|
|
5
5
|
import { Quotas } from './Quotas.js'
|
|
6
|
-
import type {
|
|
6
|
+
import type { atomicity } from '@toa.io/core'
|
|
7
7
|
import type { Configuration } from './Configuration.js'
|
|
8
8
|
import type { Input as Context } from '../../../../io.js'
|
|
9
9
|
|
|
@@ -141,18 +141,16 @@ function createContext (properties?: any): Context {
|
|
|
141
141
|
properties) as unknown as Context
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
function createStash (reply?: (deltas: number[]) => number[]):
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
function createStash (reply?: (deltas: number[]) => number[]): atomicity.Atom {
|
|
145
|
+
const atom = {
|
|
146
|
+
meter: async (keys: string[], deltas: number[]): Promise<number[]> => {
|
|
147
|
+
invocations.push({ keys, deltas })
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return reply === undefined ? request.input.deltas : reply(request.input.deltas)
|
|
149
|
+
return reply === undefined ? deltas : reply(deltas)
|
|
152
150
|
}
|
|
153
151
|
}
|
|
154
152
|
|
|
155
|
-
return
|
|
153
|
+
return atom as unknown as atomicity.Atom
|
|
156
154
|
}
|
|
157
155
|
|
|
158
156
|
interface Input {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { console } from 'openspan'
|
|
2
2
|
import type { Quotas } from './Quotas.js'
|
|
3
|
-
import type {
|
|
3
|
+
import type { atomicity } from '@toa.io/core'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Reconciles every quota of the process with the other gateways, on one tick.
|
|
@@ -11,16 +11,15 @@ import type { Remote } from '@toa.io/core'
|
|
|
11
11
|
* the debt the whole group has reached, which the quotas then decide on locally.
|
|
12
12
|
*/
|
|
13
13
|
export class Sync {
|
|
14
|
-
private readonly atom:
|
|
14
|
+
private readonly atom: atomicity.Atom
|
|
15
15
|
private readonly quotas: Quotas[] = []
|
|
16
|
-
private remote: Remote | null = null
|
|
17
16
|
private timer: NodeJS.Timeout | null = null
|
|
18
17
|
private period = Infinity
|
|
19
18
|
|
|
20
19
|
/** Ticks do not overlap: a slow round trip delays reconciling, it does not double it. */
|
|
21
20
|
private reconciling = false
|
|
22
21
|
|
|
23
|
-
public constructor (atom:
|
|
22
|
+
public constructor (atom: atomicity.Atom) {
|
|
24
23
|
this.atom = atom
|
|
25
24
|
}
|
|
26
25
|
|
|
@@ -74,12 +73,10 @@ export class Sync {
|
|
|
74
73
|
|
|
75
74
|
private async reconcile (batch: Batch[]): Promise<void> {
|
|
76
75
|
try {
|
|
77
|
-
this.remote ??= await this.atom
|
|
78
|
-
|
|
79
76
|
const keys = batch.map((entry) => entry.quotas.name(entry.key))
|
|
80
77
|
const deltas = batch.map((entry) => entry.delta)
|
|
81
78
|
|
|
82
|
-
const debts = await this.
|
|
79
|
+
const debts = await this.atom.meter(keys, deltas)
|
|
83
80
|
const now = Date.now()
|
|
84
81
|
|
|
85
82
|
for (let i = 0; i < batch.length; i++)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { it, beforeEach, afterEach, mock } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import { console } from 'openspan'
|
|
5
|
+
import { Warning } from './Warning.js'
|
|
6
|
+
|
|
7
|
+
let warn: ReturnType<typeof mock.method>
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
mock.timers.enable({ apis: ['Date'] })
|
|
11
|
+
warn = mock.method(console, 'warn', () => undefined)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
warn.mock.restore()
|
|
16
|
+
mock.timers.reset()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('should write once per interval', () => {
|
|
20
|
+
const warning = new Warning('no ip', 1000)
|
|
21
|
+
|
|
22
|
+
warning.emit()
|
|
23
|
+
warning.emit()
|
|
24
|
+
|
|
25
|
+
assert.equal(warn.mock.callCount(), 1)
|
|
26
|
+
|
|
27
|
+
mock.timers.tick(1000)
|
|
28
|
+
warning.emit()
|
|
29
|
+
|
|
30
|
+
assert.equal(warn.mock.callCount(), 2)
|
|
31
|
+
assert.equal(warn.mock.calls[0].arguments[0], 'no ip')
|
|
32
|
+
})
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { console } from 'openspan'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A warning about a condition that holds for request after request, written once per
|
|
5
|
+
* `interval` rather than once per request.
|
|
6
|
+
*/
|
|
7
|
+
export class Warning {
|
|
8
|
+
private readonly message: string
|
|
9
|
+
private readonly interval: number
|
|
10
|
+
private last = -Infinity
|
|
11
|
+
|
|
12
|
+
public constructor (message: string, interval: number = INTERVAL) {
|
|
13
|
+
this.message = message
|
|
14
|
+
this.interval = interval
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public emit (attributes?: Record<string, unknown>): void {
|
|
18
|
+
const now = Date.now()
|
|
19
|
+
|
|
20
|
+
if (now - this.last < this.interval)
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
this.last = now
|
|
24
|
+
|
|
25
|
+
console.warn(this.message, attributes)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** 100 seconds */
|
|
30
|
+
const INTERVAL = 100_000
|
|
@@ -2,5 +2,6 @@ import type { Parameter } from '../../../../../RTD/index.js'
|
|
|
2
2
|
import type { Input as Context } from '../../../../../io.js'
|
|
3
3
|
|
|
4
4
|
export interface Component {
|
|
5
|
-
|
|
5
|
+
/** what to key on, or nothing when the request cannot be keyed by this component */
|
|
6
|
+
get: (context: Context, parameters: Parameter[]) => string | undefined
|
|
6
7
|
}
|
|
@@ -1,40 +1,31 @@
|
|
|
1
|
+
import { Warning } from '../Warning.js'
|
|
1
2
|
import type { Context } from '../../../../../HTTP/index.js'
|
|
2
3
|
import type { Component } from './Component.js'
|
|
3
4
|
|
|
5
|
+
/**
|
|
6
|
+
* The client address, as the request context resolved it; see `documentation/ip.md`.
|
|
7
|
+
*
|
|
8
|
+
* A request without one cannot be keyed, so it is let through, and whoever keys on the
|
|
9
|
+
* address says so — once in a while rather than on every request, because the cause is
|
|
10
|
+
* the deployment, not the request.
|
|
11
|
+
*/
|
|
4
12
|
export class IP implements Component {
|
|
5
|
-
|
|
6
|
-
return this.xff(context) ?? context.request.socket.remoteAddress ?? ''
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
private xff (context: Context): string | undefined {
|
|
10
|
-
const xff = context.request.headers['x-forwarded-for']
|
|
13
|
+
private readonly warning: Warning
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
public constructor (options: unknown, route: string) {
|
|
16
|
+
const subject = typeof options === 'string' ? options : throttle(route)
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
for (const value of xff) {
|
|
18
|
-
ip = value.trim()
|
|
18
|
+
this.warning = new Warning(`${subject} is not in effect: the request has no ip`)
|
|
19
|
+
}
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
public get (context: Context): string | undefined {
|
|
22
|
+
if (context.ip === undefined)
|
|
23
|
+
this.warning.emit()
|
|
23
24
|
|
|
24
|
-
return ip
|
|
25
|
+
return context.ip
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
function
|
|
29
|
-
return
|
|
30
|
-
ip === 'unknown' ||
|
|
31
|
-
ip === '' ||
|
|
32
|
-
ip === '127.0.0.1' ||
|
|
33
|
-
ip === '::1' ||
|
|
34
|
-
ip.startsWith('10.') ||
|
|
35
|
-
ip.startsWith('192.168.') ||
|
|
36
|
-
ip.match(/^172\.(1[6-9]|2[0-9]|3[0-1])\./) !== null ||
|
|
37
|
-
ip.startsWith('fd') ||
|
|
38
|
-
ip.startsWith('fe80:')
|
|
39
|
-
)
|
|
29
|
+
function throttle (route: string): string {
|
|
30
|
+
return route === '' ? 'Throttle' : `Throttle of ${route}`
|
|
40
31
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import { redact } from './redact.js'
|
|
5
|
+
|
|
6
|
+
it('should replace credential values at any depth', () => {
|
|
7
|
+
const input = { input: { username: 'bob', password: 'secret', nested: [{ token: 't' }] }, query: { id: '1' } }
|
|
8
|
+
|
|
9
|
+
assert.deepEqual(redact(input), {
|
|
10
|
+
input: { username: 'bob', password: '[redacted]', nested: [{ token: '[redacted]' }] },
|
|
11
|
+
query: { id: '1' }
|
|
12
|
+
})
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('should leave an error and its code alone', () => {
|
|
16
|
+
const error = Object.assign(new Error('nope'), { code: 'NOT_FOUND' })
|
|
17
|
+
|
|
18
|
+
assert.equal(redact(error), error)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('should not modify the original', () => {
|
|
22
|
+
const input = { password: 'secret' }
|
|
23
|
+
|
|
24
|
+
redact(input)
|
|
25
|
+
|
|
26
|
+
assert.equal(input.password, 'secret')
|
|
27
|
+
})
|
package/source/redact.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A copy of a request or a reply fit for a log line: the values under the names a
|
|
3
|
+
* credential travels by are replaced, whatever their depth.
|
|
4
|
+
*/
|
|
5
|
+
export function redact<T> (value: T): T {
|
|
6
|
+
if (value === null || typeof value !== 'object' || value instanceof Error)
|
|
7
|
+
return value
|
|
8
|
+
|
|
9
|
+
if (Array.isArray(value))
|
|
10
|
+
return value.map(redact) as T
|
|
11
|
+
|
|
12
|
+
const copy: Record<string, unknown> = {}
|
|
13
|
+
|
|
14
|
+
for (const [key, item] of Object.entries(value))
|
|
15
|
+
copy[key] = SENSITIVE.has(key) ? REDACTED : redact(item)
|
|
16
|
+
|
|
17
|
+
return copy as T
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const SENSITIVE = new Set(['password', 'credentials', 'token', 'key', 'secret', 'code'])
|
|
21
|
+
const REDACTED = '[redacted]'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import * as schemas from './schemas.js'
|
|
5
|
+
|
|
6
|
+
const authorities = { nex: 'nex.toa.io' }
|
|
7
|
+
|
|
8
|
+
it('should require ip with bouncer', () => {
|
|
9
|
+
assert.throws(() => schemas.annotation.validate({ authorities, bouncer: {} }))
|
|
10
|
+
assert.doesNotThrow(() => schemas.annotation.validate({ authorities, bouncer: {}, ip: 'x-real-ip' }))
|
|
11
|
+
assert.doesNotThrow(() => schemas.annotation.validate({ authorities, ip: 'x-real-ip' }))
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('should default nothing in bouncer', () => {
|
|
15
|
+
assert.doesNotThrow(() => schemas.annotation.validate({ authorities, ip: 'x-real-ip', bouncer: { attempts: 5 } }))
|
|
16
|
+
assert.throws(() => schemas.annotation.validate({ authorities, ip: 'x-real-ip', bouncer: { attempts: 0 } }))
|
|
17
|
+
})
|
|
@@ -15,5 +15,15 @@ export interface Annotation {
|
|
|
15
15
|
annotations?: Record<string, string>;
|
|
16
16
|
};
|
|
17
17
|
debug?: boolean;
|
|
18
|
+
/** The header the client address is read from; the connection's without one. See `ip.md`. */
|
|
19
|
+
ip?: string;
|
|
20
|
+
/** Failed authentications an address may make; none are metered unless set. See `identity.md`. */
|
|
21
|
+
bouncer?: Bouncer;
|
|
18
22
|
'/'?: object;
|
|
19
23
|
}
|
|
24
|
+
export interface Bouncer {
|
|
25
|
+
/** what an address may fail at once, 20 by default */
|
|
26
|
+
attempts?: number;
|
|
27
|
+
/** seconds it takes to earn them back, 60 by default */
|
|
28
|
+
interval?: number;
|
|
29
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Connector } from '@toa.io/core';
|
|
2
|
-
import { type
|
|
2
|
+
import { type Host } from './Factory.js';
|
|
3
3
|
export declare class Composition extends Connector {
|
|
4
|
-
private readonly
|
|
5
|
-
constructor(
|
|
4
|
+
private readonly host;
|
|
5
|
+
constructor(host: Host);
|
|
6
6
|
protected open(): Promise<void>;
|
|
7
7
|
}
|
|
8
8
|
export declare function components(): Components;
|
|
@@ -2,14 +2,14 @@ import { readdirSync } from 'node:fs';
|
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { Connector } from '@toa.io/core';
|
|
4
4
|
export class Composition extends Connector {
|
|
5
|
-
|
|
6
|
-
constructor(
|
|
5
|
+
host;
|
|
6
|
+
constructor(host) {
|
|
7
7
|
super();
|
|
8
|
-
this.
|
|
8
|
+
this.host = host;
|
|
9
9
|
}
|
|
10
10
|
async open() {
|
|
11
11
|
const paths = find();
|
|
12
|
-
const composition = await this.
|
|
12
|
+
const composition = await this.host.composition(paths);
|
|
13
13
|
await composition.connect();
|
|
14
14
|
this.depends(composition);
|
|
15
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Composition.js","sourceRoot":"","sources":["../source/Composition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAe,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAGxC,MAAM,OAAO,WAAY,SAAQ,SAAS;IACvB,IAAI,
|
|
1
|
+
{"version":3,"file":"Composition.js","sourceRoot":"","sources":["../source/Composition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAe,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAGxC,MAAM,OAAO,WAAY,SAAQ,SAAS;IACvB,IAAI,CAAM;IAE3B,YAAoB,IAAU;QAC5B,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;IAC3B,CAAC;CACF;AAED,SAAS,IAAI;IACX,OAAO,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;AAC5D,CAAC;AAED,SAAS,OAAO;IACd,MAAM,OAAO,GAAG,WAAW,CAAC,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,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;QACzC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IACvC,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;AAC1B,CAAC;AAOD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { Context, OutgoingMessage } from './HTTP/index.js';
|
|
1
|
+
import type { Context, OutgoingMessage, Options } from './HTTP/index.js';
|
|
2
2
|
import type { Remotes } from './Remotes.js';
|
|
3
|
+
import type { Host } from './Factory.js';
|
|
3
4
|
import type { Output } from './io.js';
|
|
4
5
|
import type * as RTD from './RTD/index.js';
|
|
5
6
|
export declare class Directives implements RTD.Directives {
|
|
@@ -16,7 +17,7 @@ export declare class DirectivesFactory implements RTD.DirectiveFactory {
|
|
|
16
17
|
private readonly families;
|
|
17
18
|
private readonly mandatory;
|
|
18
19
|
private readonly instances;
|
|
19
|
-
constructor(families: RTD.DirectiveFamily[], remotes: Remotes);
|
|
20
|
+
constructor(families: RTD.DirectiveFamily[], remotes: Remotes, host: Host, options: Options);
|
|
20
21
|
create(declarations: RTD.syntax.Directive[], route?: string): Directives;
|
|
21
22
|
dispose(): void;
|
|
22
23
|
/** Mandatory families first, in their own order; everything else keeps its own. */
|
package/transpiled/Directive.js
CHANGED
|
@@ -43,8 +43,10 @@ export class DirectivesFactory {
|
|
|
43
43
|
families = {};
|
|
44
44
|
mandatory = [];
|
|
45
45
|
instances = [];
|
|
46
|
-
|
|
46
|
+
// eslint-disable-next-line max-params
|
|
47
|
+
constructor(families, remotes, host, options) {
|
|
47
48
|
for (const family of families) {
|
|
49
|
+
family.mount?.(host, options);
|
|
48
50
|
this.families[family.name] = family;
|
|
49
51
|
if (family.mandatory)
|
|
50
52
|
this.mandatory.push(family.name);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Directive.js","sourceRoot":"","sources":["../source/Directive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAoB,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"Directive.js","sourceRoot":"","sources":["../source/Directive.ts"],"names":[],"mappings":"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"}
|
package/transpiled/Endpoint.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Readable } from 'node:stream';
|
|
2
2
|
import { console } from 'openspan';
|
|
3
3
|
import { Mapping } from './Mapping.js';
|
|
4
|
+
import { redact } from './redact.js';
|
|
4
5
|
import * as http from './HTTP/index.js';
|
|
5
6
|
export class Endpoint {
|
|
6
7
|
endpoint;
|
|
@@ -18,9 +19,9 @@ export class Endpoint {
|
|
|
18
19
|
const request = this.mapping.fit(body, query, parameters);
|
|
19
20
|
this.remote ??= await this.discovery;
|
|
20
21
|
const endpoint = this.remote.locator.id + '.' + this.endpoint;
|
|
21
|
-
console.debug('Calling operation', { endpoint, request });
|
|
22
|
+
console.debug('Calling operation', { endpoint, request: redact(request) });
|
|
22
23
|
const reply = await this.remote.invoke(this.endpoint, request);
|
|
23
|
-
console.debug('Received reply', { endpoint, reply: reply instanceof Readable ? '[Readable stream]' : reply });
|
|
24
|
+
console.debug('Received reply', { endpoint, reply: reply instanceof Readable ? '[Readable stream]' : redact(reply) });
|
|
24
25
|
if (reply instanceof Error)
|
|
25
26
|
throw new http.UnprocessableEntity(reply);
|
|
26
27
|
const message = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Endpoint.js","sourceRoot":"","sources":["../source/Endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,KAAK,IAAI,MAAM,iBAAiB,CAAA;AAOvC,MAAM,OAAO,QAAQ;IACF,QAAQ,CAAQ;IAChB,OAAO,CAAS;IAChB,SAAS,CAAiB;IACnC,MAAM,GAAkB,IAAI,CAAA;IAEpC,YAAoB,QAAgB,EAAE,OAAgB,EAAE,SAA0B;QAChF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;IAC5B,CAAC;IAEM,KAAK,CAAC,IAAI,CAAE,OAAqB,EAAE,UAA2B;QACnE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAA;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,CAAA;QAEzD,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,SAAS,CAAA;QAEpC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAA;QAE7D,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"Endpoint.js","sourceRoot":"","sources":["../source/Endpoint.ts"],"names":[],"mappings":"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"}
|
package/transpiled/Factory.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { syntax } from './RTD/index.js';
|
|
2
2
|
import type { Connector, Locator, extensions } from '@toa.io/core';
|
|
3
3
|
export declare class Factory implements extensions.Factory {
|
|
4
|
-
private readonly
|
|
5
|
-
constructor(
|
|
4
|
+
private readonly host;
|
|
5
|
+
constructor(host: Host);
|
|
6
6
|
tenant(locator: Locator, node: syntax.Node): Promise<Connector>;
|
|
7
7
|
service(): Promise<Connector | null>;
|
|
8
8
|
}
|
|
9
|
-
export type
|
|
9
|
+
export type Host = extensions.Host;
|