@toa.io/userland 0.2.1-dev.3
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/example/components/echo/beacon/manifest.toa.yaml +9 -0
- package/example/components/echo/beacon/operations/signal.js +7 -0
- package/example/components/echo/beacon/samples/signal.yaml +7 -0
- package/example/components/math/calculations/manifest.toa.yaml +16 -0
- package/example/components/math/calculations/operations/add.js +7 -0
- package/example/components/math/calculations/operations/increment.js +15 -0
- package/example/components/math/calculations/samples/add.yaml +11 -0
- package/example/components/math/calculations/samples/increment.yaml +30 -0
- package/example/components/math/proxy/manifest.toa.yaml +11 -0
- package/example/components/math/proxy/operations/add.js +10 -0
- package/example/components/math/proxy/samples/add.yaml +11 -0
- package/example/components/tea/pots/manifest.toa.yaml +28 -0
- package/example/components/tea/pots/operations/same.js +13 -0
- package/example/components/tea/pots/receivers/store.orders.created.js +8 -0
- package/example/components/tea/pots/samples/messages/store.orders.created.yaml +37 -0
- package/example/components/tea/pots/samples/same.yaml +8 -0
- package/example/components/tea/pots/samples/transit.yaml +43 -0
- package/example/context.toa.yaml +3 -0
- package/example/samples/math.proxy.add.yaml +5 -0
- package/example/samples/messages/store.orders.created.yaml +8 -0
- package/example/stage/call.test.js +39 -0
- package/example/stage/events.test.js +48 -0
- package/example/stage/invoke.test.js +29 -0
- package/package.json +36 -0
- package/readme.md +9 -0
- package/samples/docs/sampling-dark.jpg +0 -0
- package/samples/docs/sampling-light.jpg +0 -0
- package/samples/notes.md +12 -0
- package/samples/package.json +5 -0
- package/samples/readme.md +66 -0
- package/samples/src/.replay/.suite/component.js +25 -0
- package/samples/src/.replay/.suite/index.js +7 -0
- package/samples/src/.replay/.suite/messages.js +39 -0
- package/samples/src/.replay/.suite/operation.js +28 -0
- package/samples/src/.replay/.suite/operations.js +18 -0
- package/samples/src/.replay/.suite/translate/.message/index.js +5 -0
- package/samples/src/.replay/.suite/translate/.message/request.js +31 -0
- package/samples/src/.replay/.suite/translate/.operation/calls.js +49 -0
- package/samples/src/.replay/.suite/translate/.operation/cleanup.js +16 -0
- package/samples/src/.replay/.suite/translate/.operation/events.js +16 -0
- package/samples/src/.replay/.suite/translate/.operation/index.js +11 -0
- package/samples/src/.replay/.suite/translate/.operation/prepare.js +14 -0
- package/samples/src/.replay/.suite/translate/.operation/specials/configuration.js +26 -0
- package/samples/src/.replay/.suite/translate/.operation/specials/index.js +5 -0
- package/samples/src/.replay/.suite/translate/index.js +7 -0
- package/samples/src/.replay/.suite/translate/message.js +26 -0
- package/samples/src/.replay/.suite/translate/operation.js +47 -0
- package/samples/src/.replay/.suite/translate/schemas/index.js +7 -0
- package/samples/src/.replay/.suite/translate/schemas/message.cos.yaml +10 -0
- package/samples/src/.replay/.suite/translate/schemas/operation.cos.yaml +23 -0
- package/samples/src/.replay/index.js +5 -0
- package/samples/src/.replay/suite.js +22 -0
- package/samples/src/.replay/test.js +17 -0
- package/samples/src/components.js +13 -0
- package/samples/src/context.js +18 -0
- package/samples/src/index.js +9 -0
- package/samples/src/replay.js +17 -0
- package/samples/src/suite/.read/index.js +7 -0
- package/samples/src/suite/.read/messages.js +35 -0
- package/samples/src/suite/.read/operations.js +45 -0
- package/samples/src/suite/.read/parse.js +24 -0
- package/samples/src/suite/components.js +28 -0
- package/samples/src/suite/context.js +19 -0
- package/samples/src/suite/index.js +7 -0
- package/samples/test/components.test.js +39 -0
- package/samples/test/context/components/ok/manifest.toa.yaml +2 -0
- package/samples/test/context/components/ok/samples/do.yaml +11 -0
- package/samples/test/context/components/ok/samples/dummies.dummy.do.yaml +11 -0
- package/samples/test/context/components/ok/samples/dummies.dummy.undo.yaml +7 -0
- package/samples/test/context/components/ok/samples/messages/somewhere.something.happened.yaml +6 -0
- package/samples/test/context/context.toa.yaml +3 -0
- package/samples/test/context/samples/dummies.dummy.observe.yaml +6 -0
- package/samples/test/context/samples/dummies.dummy.transit.yaml +10 -0
- package/samples/test/context/samples/messages/somewhere.something.happened.yaml +6 -0
- package/samples/test/context.fixtures.js +8 -0
- package/samples/test/context.test.js +78 -0
- package/samples/test/replay.fixtures.js +72 -0
- package/samples/test/replay.mock.js +7 -0
- package/samples/test/replay.test.js +116 -0
- package/samples/test/replay.translate.message.fixtures.js +24 -0
- package/samples/test/replay.translate.message.test.js +123 -0
- package/samples/test/replay.translate.mock.js +17 -0
- package/samples/test/replay.translate.operation.fixtures.js +107 -0
- package/samples/test/replay.translate.operation.test.js +68 -0
- package/samples/test/stage.mock.js +34 -0
- package/samples/test/suite.components.test.js +85 -0
- package/samples/test/suite.context.test.js +79 -0
- package/samples/test/suite.mock.js +10 -0
- package/samples/types/index.d.ts +8 -0
- package/samples/types/message.d.ts +24 -0
- package/samples/types/operation.d.ts +36 -0
- package/samples/types/replay.d.ts +13 -0
- package/samples/types/suite.d.ts +19 -0
- package/stage/package.json +5 -0
- package/stage/readme.md +41 -0
- package/stage/src/binding/binding.js +49 -0
- package/stage/src/binding/consumer.js +30 -0
- package/stage/src/binding/emitter.js +26 -0
- package/stage/src/binding/factory.js +49 -0
- package/stage/src/binding/index.js +10 -0
- package/stage/src/binding/label.js +12 -0
- package/stage/src/binding/producer.js +43 -0
- package/stage/src/binding/receiver.js +35 -0
- package/stage/src/component.js +18 -0
- package/stage/src/composition.js +19 -0
- package/stage/src/index.js +18 -0
- package/stage/src/manifest.js +12 -0
- package/stage/src/remote.js +22 -0
- package/stage/src/shutdown.js +19 -0
- package/stage/src/state.js +17 -0
- package/stage/test/binding/binding.test.js +15 -0
- package/stage/test/binding/consumer.test.js +52 -0
- package/stage/test/binding/emitter.test.js +54 -0
- package/stage/test/binding/producer.fixtures.js +10 -0
- package/stage/test/binding/producer.test.js +49 -0
- package/stage/test/binding/receiver.fixtures.js +7 -0
- package/stage/test/binding/receiver.test.js +54 -0
- package/stage/test/binding.mock.js +8 -0
- package/stage/test/boot.mock.js +16 -0
- package/stage/test/component.test.js +25 -0
- package/stage/test/composition.test.js +38 -0
- package/stage/test/manifest.test.js +24 -0
- package/stage/test/remote.test.js +32 -0
- package/stage/test/shutdown.test.js +66 -0
- package/stage/test/state.mock.js +8 -0
- package/stage/test/state.test.js +27 -0
- package/stage/types/binding.d.ts +20 -0
- package/stage/types/index.d.ts +28 -0
- package/stage/types/state.d.ts +14 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// noinspection JSCheckFunctionSignatures
|
|
2
|
+
|
|
3
|
+
'use strict'
|
|
4
|
+
|
|
5
|
+
const { generate } = require('randomstring')
|
|
6
|
+
const { Locator } = require('@toa.io/core')
|
|
7
|
+
|
|
8
|
+
const locator = () => {
|
|
9
|
+
const name = generate()
|
|
10
|
+
const namespace = generate()
|
|
11
|
+
|
|
12
|
+
return new Locator(name, namespace)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// stage
|
|
16
|
+
const manifest = jest.fn(async (path) => ({ path, locator: locator() }))
|
|
17
|
+
const composition = jest.fn()
|
|
18
|
+
const shutdown = jest.fn()
|
|
19
|
+
|
|
20
|
+
const remote = jest.fn(async (id) => {
|
|
21
|
+
const [namespace, name] = id.split('.')
|
|
22
|
+
const locator = new Locator(name, namespace)
|
|
23
|
+
const invoke = jest.fn(async (operation, request) => request.reply)
|
|
24
|
+
const disconnect = jest.fn(async () => undefined)
|
|
25
|
+
|
|
26
|
+
return { locator, invoke, disconnect }
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const emit = jest.fn()
|
|
30
|
+
const binding = { binding: { emit } }
|
|
31
|
+
|
|
32
|
+
const stage = { manifest, composition, remote, shutdown, binding }
|
|
33
|
+
|
|
34
|
+
exports.stage = stage
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { resolve } = require('node:path')
|
|
4
|
+
const yaml = require('@toa.io/yaml')
|
|
5
|
+
|
|
6
|
+
const { components } = require('../src/suite')
|
|
7
|
+
|
|
8
|
+
it('should be', () => {
|
|
9
|
+
expect(components).toBeDefined()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const root = resolve(__dirname, 'context/components/ok')
|
|
13
|
+
const paths = [root]
|
|
14
|
+
const component = 'dummies.dummy'
|
|
15
|
+
|
|
16
|
+
/** @type {toa.samples.Suite} */
|
|
17
|
+
let suite
|
|
18
|
+
|
|
19
|
+
beforeAll(async () => {
|
|
20
|
+
suite = await components(paths)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should return object', () => {
|
|
24
|
+
expect(typeof suite).toStrictEqual('object')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('should set title', async () => {
|
|
28
|
+
expect(suite.title).toStrictEqual('Component samples')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('should define suite as autonomous', async () => {
|
|
32
|
+
expect(suite.autonomous).toStrictEqual(true)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('should load component samples', async () => {
|
|
36
|
+
const expected = await operations()
|
|
37
|
+
|
|
38
|
+
expect(Object.keys(suite.operations)).toStrictEqual([component])
|
|
39
|
+
|
|
40
|
+
const set = suite.operations[component]
|
|
41
|
+
|
|
42
|
+
expect(Object.keys(set)).toStrictEqual(['do', 'undo'])
|
|
43
|
+
|
|
44
|
+
expect(set.do).toStrictEqual(expected.do)
|
|
45
|
+
expect(set.undo).toStrictEqual(expected.undo)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('should load message samples', async () => {
|
|
49
|
+
const expected = await messages()
|
|
50
|
+
|
|
51
|
+
expect(suite.messages).toStrictEqual(expected)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @returns {Promise<toa.samples.operations.Set>}
|
|
56
|
+
*/
|
|
57
|
+
const operations = async () => {
|
|
58
|
+
const path = resolve(root, 'samples')
|
|
59
|
+
|
|
60
|
+
/** @type {toa.samples.Operation[]} */
|
|
61
|
+
const do1 = (await yaml.load.all(resolve(path, 'do.yaml')))
|
|
62
|
+
|
|
63
|
+
/** @type {toa.samples.Operation[]} */
|
|
64
|
+
const do2 = (await yaml.load.all(resolve(path, 'dummies.dummy.do.yaml')))
|
|
65
|
+
|
|
66
|
+
/** @type {toa.samples.Operation[]} */
|
|
67
|
+
const undo = (await yaml.load.all(resolve(path, 'dummies.dummy.undo.yaml')))
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
do: [...do1, ...do2], undo
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
*
|
|
76
|
+
* @returns {Promise<toa.samples.messages.Set>}
|
|
77
|
+
*/
|
|
78
|
+
const messages = async () => {
|
|
79
|
+
const label = 'somewhere.something.happened'
|
|
80
|
+
const file = resolve(root, 'samples/messages', label + '.yaml')
|
|
81
|
+
const declarations = await yaml.load.all(file)
|
|
82
|
+
const messages = declarations.map((sample) => ({ component, ...sample }))
|
|
83
|
+
|
|
84
|
+
return { [label]: messages }
|
|
85
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { join } = require('node:path')
|
|
4
|
+
const yaml = require('@toa.io/yaml')
|
|
5
|
+
|
|
6
|
+
const { context } = require('../src/suite')
|
|
7
|
+
|
|
8
|
+
it('should be', async () => {
|
|
9
|
+
expect(context).toBeDefined()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const root = join(__dirname, 'context')
|
|
13
|
+
|
|
14
|
+
/** @type {toa.samples.Suite} */
|
|
15
|
+
let suite
|
|
16
|
+
|
|
17
|
+
beforeAll(async () => {
|
|
18
|
+
suite = await context(root)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('should return object', async () => {
|
|
22
|
+
expect(typeof suite).toStrictEqual('object')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should set title', async () => {
|
|
26
|
+
expect(suite.title).toStrictEqual('Integration samples')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('should define suite as non-autonomous', async () => {
|
|
30
|
+
expect(suite.autonomous).toStrictEqual(false)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('should load operation samples', async () => {
|
|
34
|
+
const expected = await operations()
|
|
35
|
+
|
|
36
|
+
expect(suite.operations).toStrictEqual(expected)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should load message samples', async () => {
|
|
40
|
+
const expected = await messages()
|
|
41
|
+
|
|
42
|
+
expect(suite.messages).toStrictEqual(expected)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @returns {Promise<toa.samples.suite.Operations>}
|
|
47
|
+
*/
|
|
48
|
+
const operations = async () => {
|
|
49
|
+
const path = join(root, 'samples')
|
|
50
|
+
const component = 'dummies.dummy'
|
|
51
|
+
const endpoints = ['transit', 'observe']
|
|
52
|
+
|
|
53
|
+
/** @type {toa.samples.suite.Operations} */
|
|
54
|
+
const operations = {}
|
|
55
|
+
|
|
56
|
+
/** @type {toa.samples.operations.Set} */
|
|
57
|
+
const set = operations[component] = {}
|
|
58
|
+
|
|
59
|
+
for (const endpoint of endpoints) {
|
|
60
|
+
const filename = component + '.' + endpoint + '.yaml'
|
|
61
|
+
const filepath = join(path, filename)
|
|
62
|
+
|
|
63
|
+
set[endpoint] = /** @type {toa.samples.Operation[]} */ await yaml.load.all(filepath)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return operations
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @returns {Promise<toa.samples.messages.Set>}
|
|
71
|
+
*/
|
|
72
|
+
const messages = async () => {
|
|
73
|
+
const label = 'somewhere.something.happened'
|
|
74
|
+
const file = label + '.yaml'
|
|
75
|
+
const path = join(root, 'samples/messages', file)
|
|
76
|
+
const samples = /** @type {toa.samples.Message[]} */ await yaml.load.all(path)
|
|
77
|
+
|
|
78
|
+
return { [label]: samples }
|
|
79
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type * as _core from '@toa.io/core/types'
|
|
2
|
+
import type * as _operation from './operation'
|
|
3
|
+
|
|
4
|
+
declare namespace toa.samples {
|
|
5
|
+
|
|
6
|
+
namespace messages {
|
|
7
|
+
|
|
8
|
+
type Set = Record<string, Message[]>
|
|
9
|
+
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type Message = {
|
|
13
|
+
title?: string
|
|
14
|
+
component: string
|
|
15
|
+
payload: Object
|
|
16
|
+
input?: any
|
|
17
|
+
query?: _core.Query
|
|
18
|
+
request?: _operation.Operation | null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type Message = toa.samples.Message
|
|
24
|
+
export type Set = toa.samples.messages.Set
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as _core from '@toa.io/core/types'
|
|
2
|
+
import * as _sampling from '@toa.io/extensions.sampling'
|
|
3
|
+
|
|
4
|
+
declare namespace toa.samples {
|
|
5
|
+
|
|
6
|
+
namespace operations {
|
|
7
|
+
|
|
8
|
+
type Call = {
|
|
9
|
+
input?: any
|
|
10
|
+
output?: any
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type Calls = Record<string, Call[]>
|
|
14
|
+
|
|
15
|
+
type Events = Record<string, Object>
|
|
16
|
+
|
|
17
|
+
type Set = Record<string, Operation[]>
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type Operation = {
|
|
22
|
+
title?: string
|
|
23
|
+
input?: any
|
|
24
|
+
output?: any
|
|
25
|
+
current?: _core.storages.Record
|
|
26
|
+
next?: _core.storages.Record
|
|
27
|
+
remote?: operations.Calls
|
|
28
|
+
local?: operations.Calls
|
|
29
|
+
events?: operations.Events
|
|
30
|
+
extensions?: _sampling.request.Extensions
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type Operation = toa.samples.Operation
|
|
36
|
+
export type Set = toa.samples.operations.Set
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as _suite from "./suite";
|
|
2
|
+
|
|
3
|
+
declare namespace toa.samples.replay {
|
|
4
|
+
|
|
5
|
+
type components = (paths: string[]) => Promise<boolean>
|
|
6
|
+
type context = (path: string) => Promise<boolean>
|
|
7
|
+
type replay = (suite: _suite.Suite, paths: string[]) => Promise<boolean>
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type context = toa.samples.replay.context
|
|
12
|
+
export type components = toa.samples.replay.components
|
|
13
|
+
export type replay = toa.samples.replay.replay
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as _operations from './operation'
|
|
2
|
+
import * as _messages from './message'
|
|
3
|
+
|
|
4
|
+
declare namespace toa.samples {
|
|
5
|
+
|
|
6
|
+
namespace suite {
|
|
7
|
+
type Operations = Record<string, _operations.Set>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type Suite = {
|
|
11
|
+
title: string
|
|
12
|
+
autonomous: boolean
|
|
13
|
+
operations?: suite.Operations
|
|
14
|
+
messages?: _messages.Set
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type Suite = toa.samples.Suite
|
package/stage/readme.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Toa integration tests framework
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
|
|
5
|
+
```javascript
|
|
6
|
+
const stage = require('@toa.io/userland/stage')
|
|
7
|
+
|
|
8
|
+
const component = await stage.component('dummies.dummy')
|
|
9
|
+
const reply = await component.invoke('do', { input: 'foo' })
|
|
10
|
+
|
|
11
|
+
await stage.shutdown()
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
See [examples](../example/stage).
|
|
15
|
+
|
|
16
|
+
## Component
|
|
17
|
+
|
|
18
|
+
`async component(path: string): toa.core.Component`
|
|
19
|
+
|
|
20
|
+
Boot the component.
|
|
21
|
+
|
|
22
|
+
> Components consuming events must be able to discover event sources, that is, either they must be
|
|
23
|
+
> booted after event sources are composed or within the same composition.
|
|
24
|
+
|
|
25
|
+
## Composition
|
|
26
|
+
|
|
27
|
+
`async composition(paths: string[]): void`
|
|
28
|
+
|
|
29
|
+
Boot the composition.
|
|
30
|
+
|
|
31
|
+
## Remote
|
|
32
|
+
|
|
33
|
+
`async remote(paths: string[]): toa.core.Component`
|
|
34
|
+
|
|
35
|
+
Connect the remote.
|
|
36
|
+
|
|
37
|
+
## Shutdown
|
|
38
|
+
|
|
39
|
+
`async sutdown(): void`
|
|
40
|
+
|
|
41
|
+
Shutdown all components, compositions and services.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @implements {toa.stage.binding.Binding}
|
|
5
|
+
*/
|
|
6
|
+
class Binding {
|
|
7
|
+
/** @type {Record<string, function[]>} */
|
|
8
|
+
#subs = {}
|
|
9
|
+
|
|
10
|
+
/** @type {Record<string, function>} */
|
|
11
|
+
#calls = {}
|
|
12
|
+
|
|
13
|
+
async subscribe (label, callback) {
|
|
14
|
+
if (this.#subs[label] === undefined) this.#subs[label] = []
|
|
15
|
+
|
|
16
|
+
this.#subs[label].push(callback)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async emit (label, message) {
|
|
20
|
+
const callbacks = this.#subs[label]
|
|
21
|
+
|
|
22
|
+
if (callbacks === undefined) return undefined
|
|
23
|
+
|
|
24
|
+
const promises = callbacks.map((callback) => callback(message))
|
|
25
|
+
|
|
26
|
+
await Promise.all(promises)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async reply (label, produce) {
|
|
30
|
+
if (this.#calls[label] !== undefined) throw new Error(`Label '${label}' is already bound`)
|
|
31
|
+
|
|
32
|
+
this.#calls[label] = produce
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async request (label, request) {
|
|
36
|
+
if (this.#calls[label] === undefined) throw new Error(`Label '${label}' is not bound`)
|
|
37
|
+
|
|
38
|
+
return this.#calls[label](request)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
reset () {
|
|
42
|
+
this.#subs = {}
|
|
43
|
+
this.#calls = {}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const binding = new Binding()
|
|
48
|
+
|
|
49
|
+
exports.binding = binding
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { Connector } = require('@toa.io/core')
|
|
4
|
+
|
|
5
|
+
const { binding } = require('./binding')
|
|
6
|
+
const { label } = require('./label')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @implements {toa.core.bindings.Consumer}
|
|
10
|
+
*/
|
|
11
|
+
class Consumer extends Connector {
|
|
12
|
+
/** @type {string} */
|
|
13
|
+
#label
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {toa.core.Locator} locator
|
|
17
|
+
* @param {string} endpoint
|
|
18
|
+
*/
|
|
19
|
+
constructor (locator, endpoint) {
|
|
20
|
+
super()
|
|
21
|
+
|
|
22
|
+
this.#label = label(locator, endpoint)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async request (request) {
|
|
26
|
+
return binding.request(this.#label, request)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
exports.Consumer = Consumer
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { Connector } = require('@toa.io/core')
|
|
4
|
+
|
|
5
|
+
const { binding } = require('./binding')
|
|
6
|
+
const { label } = require('./label')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @implements {toa.core.bindings.Emitter}
|
|
10
|
+
*/
|
|
11
|
+
class Emitter extends Connector {
|
|
12
|
+
/** @type {string} */
|
|
13
|
+
#label
|
|
14
|
+
|
|
15
|
+
constructor (locator, endpoint) {
|
|
16
|
+
super()
|
|
17
|
+
|
|
18
|
+
this.#label = label(locator, endpoint)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async emit (message) {
|
|
22
|
+
return binding.emit(this.#label, message)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
exports.Emitter = Emitter
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { Emitter } = require('./emitter')
|
|
4
|
+
const { Receiver } = require('./receiver')
|
|
5
|
+
const { Consumer } = require('./consumer')
|
|
6
|
+
const { Producer } = require('./producer')
|
|
7
|
+
|
|
8
|
+
class Factory {
|
|
9
|
+
/**
|
|
10
|
+
* @param {toa.core.Locator} locator
|
|
11
|
+
* @param {string} label
|
|
12
|
+
* @param {string} id
|
|
13
|
+
* @param {toa.core.Receiver} receiver
|
|
14
|
+
* @returns {toa.core.Connector}
|
|
15
|
+
*/
|
|
16
|
+
receiver (locator, label, id, receiver) {
|
|
17
|
+
return new Receiver(locator, label, receiver)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {toa.core.Locator} locator
|
|
22
|
+
* @param {string} label
|
|
23
|
+
* @returns {toa.core.bindings.Emitter}
|
|
24
|
+
*/
|
|
25
|
+
emitter (locator, label) {
|
|
26
|
+
return new Emitter(locator, label)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {toa.core.Locator} locator
|
|
31
|
+
* @param {string} endpoint
|
|
32
|
+
* @returns {toa.core.bindings.Consumer}
|
|
33
|
+
*/
|
|
34
|
+
consumer (locator, endpoint) {
|
|
35
|
+
return new Consumer(locator, endpoint)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {toa.core.Locator} locator
|
|
40
|
+
* @param {string[]} endpoints
|
|
41
|
+
* @param {toa.core.Component} component
|
|
42
|
+
* @returns {toa.core.Connector}
|
|
43
|
+
*/
|
|
44
|
+
producer (locator, endpoints, component) {
|
|
45
|
+
return new Producer(locator, endpoints, component)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
exports.Factory = Factory
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { Connector } = require('@toa.io/core')
|
|
4
|
+
|
|
5
|
+
const { binding } = require('./binding')
|
|
6
|
+
const { label } = require('./label')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @implements {toa.core.Connector}
|
|
10
|
+
*/
|
|
11
|
+
class Producer extends Connector {
|
|
12
|
+
/** @type {toa.core.Locator} */
|
|
13
|
+
#locator
|
|
14
|
+
|
|
15
|
+
/** @type {string[]} */
|
|
16
|
+
#endpoints
|
|
17
|
+
|
|
18
|
+
/** @type {toa.core.Component} */
|
|
19
|
+
#component
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {toa.core.Locator} locator
|
|
23
|
+
* @param {string[]} endpoints
|
|
24
|
+
* @param {toa.core.Component} component
|
|
25
|
+
*/
|
|
26
|
+
constructor (locator, endpoints, component) {
|
|
27
|
+
super()
|
|
28
|
+
|
|
29
|
+
this.#locator = locator
|
|
30
|
+
this.#endpoints = endpoints
|
|
31
|
+
this.#component = component
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async connection () {
|
|
35
|
+
for (const endpoint of this.#endpoints) {
|
|
36
|
+
const command = label(this.#locator, endpoint)
|
|
37
|
+
|
|
38
|
+
await binding.reply(command, (request) => this.#component.invoke(endpoint, request))
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
exports.Producer = Producer
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { Connector } = require('@toa.io/core')
|
|
4
|
+
|
|
5
|
+
const { binding } = require('./binding')
|
|
6
|
+
const { label } = require('./label')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @implements {toa.core.Connector}
|
|
10
|
+
*/
|
|
11
|
+
class Receiver extends Connector {
|
|
12
|
+
/** @type {string} */
|
|
13
|
+
#label
|
|
14
|
+
|
|
15
|
+
/** @type {toa.core.Receiver} */
|
|
16
|
+
#receiver
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {toa.core.Locator} locator
|
|
20
|
+
* @param {string} endpoint
|
|
21
|
+
* @param {toa.core.Receiver} receiver
|
|
22
|
+
*/
|
|
23
|
+
constructor (locator, endpoint, receiver) {
|
|
24
|
+
super()
|
|
25
|
+
|
|
26
|
+
this.#label = label(locator, endpoint)
|
|
27
|
+
this.#receiver = receiver
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async connection () {
|
|
31
|
+
await binding.subscribe(this.#label, (message) => this.#receiver.receive(message))
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
exports.Receiver = Receiver
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const boot = require('@toa.io/boot')
|
|
4
|
+
const { state } = require('./state')
|
|
5
|
+
|
|
6
|
+
/** @type {toa.stage.Component} */
|
|
7
|
+
const component = async (path) => {
|
|
8
|
+
const manifest = await boot.manifest(path)
|
|
9
|
+
const component = await boot.component(manifest)
|
|
10
|
+
|
|
11
|
+
await component.connect()
|
|
12
|
+
|
|
13
|
+
state.components.push(component)
|
|
14
|
+
|
|
15
|
+
return component
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
exports.component = component
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const boot = require('@toa.io/boot')
|
|
4
|
+
const { state } = require('./state')
|
|
5
|
+
|
|
6
|
+
const binding = require.resolve('./binding')
|
|
7
|
+
|
|
8
|
+
/** @type {toa.stage.Composition} */
|
|
9
|
+
const composition = async (paths) => {
|
|
10
|
+
/** @type {toa.boot.composition.Options} */
|
|
11
|
+
const options = { bindings: [binding] }
|
|
12
|
+
const composition = await boot.composition(paths, options)
|
|
13
|
+
|
|
14
|
+
await composition.connect()
|
|
15
|
+
|
|
16
|
+
state.compositions.push(composition)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
exports.composition = composition
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { manifest } = require('./manifest')
|
|
4
|
+
const { component } = require('./component')
|
|
5
|
+
const { composition } = require('./composition')
|
|
6
|
+
const { remote } = require('./remote')
|
|
7
|
+
const { shutdown } = require('./shutdown')
|
|
8
|
+
const binding = require('./binding')
|
|
9
|
+
|
|
10
|
+
// staging always runs on local deployment environment
|
|
11
|
+
process.env.TOA_ENV = 'local'
|
|
12
|
+
|
|
13
|
+
exports.manifest = manifest
|
|
14
|
+
exports.component = component
|
|
15
|
+
exports.composition = composition
|
|
16
|
+
exports.remote = remote
|
|
17
|
+
exports.shutdown = shutdown
|
|
18
|
+
exports.binding = binding
|