@toa.io/core 1.0.0-alpha.19 → 1.0.0-alpha.194

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.
Files changed (44) hide show
  1. package/package.json +6 -9
  2. package/src/call.js +6 -0
  3. package/src/cascade.js +2 -3
  4. package/src/component.js +15 -18
  5. package/src/composition.js +1 -1
  6. package/src/connector.js +3 -8
  7. package/src/contract/contract.js +22 -0
  8. package/src/contract/reply.js +26 -9
  9. package/src/contract/request.js +15 -5
  10. package/src/contract/schemas/query.yaml +7 -1
  11. package/src/discovery.js +2 -5
  12. package/src/effect.js +19 -0
  13. package/src/entities/changeset.js +5 -8
  14. package/src/entities/entity.js +47 -23
  15. package/src/entities/factory.js +11 -3
  16. package/src/exceptions.js +26 -19
  17. package/src/exposition.js +3 -2
  18. package/src/guard.js +17 -0
  19. package/src/index.js +6 -0
  20. package/src/observation.js +1 -9
  21. package/src/operation.js +28 -7
  22. package/src/query/options.js +3 -2
  23. package/src/query.js +2 -1
  24. package/src/receiver.js +13 -10
  25. package/src/remote.js +5 -7
  26. package/src/state.js +50 -33
  27. package/src/transition.js +8 -19
  28. package/src/transmission.js +12 -3
  29. package/src/unmanaged.js +11 -0
  30. package/test/component.test.js +4 -3
  31. package/test/contract/conditions.test.js +5 -5
  32. package/test/contract/request.test.js +7 -7
  33. package/test/entities/entity.test.js +0 -45
  34. package/test/state.test.js +0 -6
  35. package/types/bindings.d.ts +7 -5
  36. package/types/component.d.ts +4 -1
  37. package/types/extensions.d.ts +4 -3
  38. package/types/index.ts +1 -0
  39. package/types/operations.d.ts +6 -0
  40. package/types/query.d.ts +2 -0
  41. package/types/remote.d.ts +18 -0
  42. package/types/request.d.ts +3 -0
  43. package/types/storages.d.ts +11 -9
  44. package/src/contract/conditions.js +0 -21
package/src/index.js CHANGED
@@ -5,6 +5,7 @@ const { Composition } = require('./composition')
5
5
  const { Connector } = require('./connector')
6
6
  const { Context } = require('./context')
7
7
  const { Discovery } = require('./discovery')
8
+ const { Effect } = require('./effect')
8
9
  const { Emission } = require('./emission')
9
10
  const { Event } = require('./event')
10
11
  const { Exposition } = require('./exposition')
@@ -19,6 +20,8 @@ const { Component } = require('./component')
19
20
  const { State } = require('./state')
20
21
  const { Transition } = require('./transition')
21
22
  const { Transmission } = require('./transmission')
23
+ const { Unmanaged } = require('./unmanaged')
24
+ const { Guard } = require('./guard')
22
25
 
23
26
  exports.entities = require('./entities')
24
27
  exports.exceptions = require('./exceptions')
@@ -32,6 +35,7 @@ exports.Composition = Composition
32
35
  exports.Connector = Connector
33
36
  exports.Context = Context
34
37
  exports.Discovery = Discovery
38
+ exports.Effect = Effect
35
39
  exports.Emission = Emission
36
40
  exports.Event = Event
37
41
  exports.Exposition = Exposition
@@ -45,3 +49,5 @@ exports.Remote = Remote
45
49
  exports.State = State
46
50
  exports.Transition = Transition
47
51
  exports.Transmission = Transmission
52
+ exports.Unmanaged = Unmanaged
53
+ exports.Guard = Guard
@@ -3,16 +3,8 @@
3
3
  const { Operation } = require('./operation')
4
4
 
5
5
  class Observation extends Operation {
6
- async acquire (store) {
7
- const scope = await this.query(store.request.query)
8
- const state = scope === null ? null : scope.get()
9
-
10
- store.scope = scope
11
- store.state = state
12
- }
13
-
14
6
  async run (store) {
15
- if (store.scope === null) store.reply = null
7
+ if (store.scope === null || (store.scope?.deleted === true && store.request.query?.options?.deleted !== true)) store.reply = null
16
8
  else await super.run(store)
17
9
  }
18
10
  }
package/src/operation.js CHANGED
@@ -1,7 +1,8 @@
1
1
  'use strict'
2
2
 
3
3
  const { Connector } = require('./connector')
4
- const { SystemException } = require('./exceptions')
4
+ const { SystemException, RequestContractException } = require('./exceptions')
5
+ const { Readable } = require('node:stream')
5
6
 
6
7
  class Operation extends Connector {
7
8
  scope
@@ -26,8 +27,15 @@ class Operation extends Connector {
26
27
 
27
28
  async invoke (request) {
28
29
  try {
29
- if (request.authentic !== true) this.#contracts.request.fit(request)
30
- if ('query' in request) request.query = this.#query.parse(request.query)
30
+ if (request.authentic !== true)
31
+ this.#contracts.request.fit(request)
32
+
33
+ if ('query' in request)
34
+ request.query = this.#query.parse(request.query)
35
+
36
+ // validate entity
37
+ if ('entity' in request)
38
+ this.scope.fit(request.entity)
31
39
 
32
40
  const store = { request }
33
41
 
@@ -47,14 +55,24 @@ class Operation extends Connector {
47
55
  return store.reply
48
56
  }
49
57
 
50
- async acquire () {}
58
+ async acquire (store) {
59
+ if (this.#scope === 'none')
60
+ return
61
+
62
+ const scope = await this.query(store.request.query)
63
+ const raw = scope === null || scope instanceof Readable
64
+
65
+ store.scope = scope
66
+ store.state = raw ? scope : scope.get()
67
+ }
51
68
 
52
69
  async run (store) {
53
70
  const { request, state } = store
54
- // noinspection UnnecessaryLocalVariableJS
55
- const reply = await this.#cascade.run(request.input, state) || {}
71
+ const reply = await this.#cascade.run(request.input, state)
56
72
 
57
- // this.#contracts.reply.fit(reply)
73
+ // validate reply only on local environments
74
+ if (process.env.TOA_ENV === 'local' && !(reply instanceof Readable))
75
+ this.#contracts.reply.fit(reply)
58
76
 
59
77
  store.reply = reply
60
78
  }
@@ -62,6 +80,9 @@ class Operation extends Connector {
62
80
  async commit () {}
63
81
 
64
82
  async query (query) {
83
+ if (query === undefined)
84
+ throw new RequestContractException('Request query is required')
85
+
65
86
  return this.scope[this.#scope](query)
66
87
  }
67
88
  }
@@ -33,8 +33,9 @@ const projection = (projection, properties) => {
33
33
  }
34
34
  }
35
35
 
36
- if (projection.includes('_version') === false)
37
- projection.push('_version')
36
+ for (const property of ['_version', '_created', '_updated', '_deleted'])
37
+ if (!projection.includes(property))
38
+ projection.push(property)
38
39
  }
39
40
 
40
41
  exports.options = options
package/src/query.js CHANGED
@@ -19,13 +19,14 @@ class Query {
19
19
  parse (query) {
20
20
  /** @type {toa.core.storages.Query} */
21
21
  const result = {}
22
- const { id, version, criteria, ...rest } = query
22
+ const { id, version, criteria, search, ...rest } = query
23
23
 
24
24
  const options = this.#options(rest)
25
25
 
26
26
  if (id !== undefined) result.id = id
27
27
  if (version !== undefined) result.version = version
28
28
  if (criteria !== undefined) result.criteria = parse.criteria(criteria, this.#properties)
29
+ if (search !== undefined) result.search = search
29
30
  if (options !== undefined) result.options = options
30
31
 
31
32
  return result
package/src/receiver.js CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const { console } = require('openspan')
3
4
  const { add } = require('@toa.io/generic')
4
5
  const { Connector } = require('./connector')
5
6
 
@@ -16,18 +17,13 @@ class Receiver extends Connector {
16
17
  /** @type {string} */
17
18
  #endpoint
18
19
 
19
- /** @type {toa.core.Component} */
20
+ /** @type {unknown[]} */
21
+ #arguments
22
+
20
23
  #local
21
24
 
22
- /** @type {toa.core.bridges.Receiver} */
23
25
  #bridge
24
26
 
25
- /**
26
- *
27
- * @param {toa.norm.component.Receiver} definition
28
- * @param {toa.core.Component} local
29
- * @param {toa.core.bridges.Receiver} bridge
30
- */
31
27
  constructor (definition, local, bridge) {
32
28
  super()
33
29
 
@@ -36,6 +32,7 @@ class Receiver extends Connector {
36
32
  this.#conditioned = conditioned
37
33
  this.#adaptive = adaptive
38
34
  this.#endpoint = operation
35
+ this.#arguments = definition.arguments
39
36
 
40
37
  this.#local = local
41
38
  this.#bridge = bridge
@@ -54,11 +51,17 @@ class Receiver extends Connector {
54
51
 
55
52
  add(request, extensions)
56
53
 
57
- await this.#local.invoke(this.#endpoint, request)
54
+ try {
55
+ await this.#local.invoke(this.#endpoint, request)
56
+ } catch (error) {
57
+ console.error('Receiver error', error)
58
+
59
+ throw error
60
+ }
58
61
  }
59
62
 
60
63
  async #request (payload) {
61
- return this.#adaptive ? await this.#bridge.request(payload) : { input: payload }
64
+ return this.#adaptive ? await this.#bridge.request(payload, ...(this.#arguments ?? [])) : { input: payload }
62
65
  }
63
66
  }
64
67
 
package/src/remote.js CHANGED
@@ -1,16 +1,14 @@
1
1
  'use strict'
2
2
 
3
- const { console } = require('@toa.io/console')
4
-
3
+ const assert = require('node:assert')
5
4
  const { Component } = require('./component')
6
5
 
7
6
  class Remote extends Component {
8
- async open () {
9
- console.info(`Remote '${this.locator.id}' connected`)
10
- }
7
+ explain (endpoint) {
8
+ assert.ok(endpoint in this.operations,
9
+ `Endpoint '${endpoint}' is not provided by '${this.locator.id}'`)
11
10
 
12
- async dispose () {
13
- console.info(`Remote '${this.locator.id}' disconnected`)
11
+ return this.operations[endpoint].explain()
14
12
  }
15
13
  }
16
14
 
package/src/state.js CHANGED
@@ -1,73 +1,90 @@
1
1
  'use strict'
2
2
 
3
- const { empty } = require('@toa.io/generic')
4
-
5
- const {
6
- StatePreconditionException,
7
- StateNotFoundException
8
- } = require('./exceptions')
3
+ const { StatePreconditionException, StateNotFoundException } = require('./exceptions')
9
4
 
10
5
  class State {
6
+ storage
7
+
11
8
  #associated
12
- #storage
13
- #entity
9
+ #entities
14
10
  #emission
15
11
 
16
12
  constructor (storage, entity, emission, associated) {
17
- this.#storage = storage
18
- this.#entity = entity
13
+ this.storage = storage
14
+ this.#entities = entity
19
15
  this.#emission = emission
20
16
  this.#associated = associated === true
21
17
  }
22
18
 
23
19
  init (id) {
24
- return this.#entity.init(id)
20
+ return this.#entities.init(id)
21
+ }
22
+
23
+ fit (values) {
24
+ return this.#entities.fit(values)
25
25
  }
26
26
 
27
27
  async object (query) {
28
- const record = await this.#storage.get(query)
28
+ const record = await this.storage.get(query)
29
29
 
30
30
  if (record === null) {
31
- if (this.#associated && query.id !== undefined && query.version === undefined) {
31
+ if (this.#associated && query.id !== undefined && query.criteria === undefined && query.version === undefined)
32
32
  return this.init(query.id)
33
- } else if (query.version !== undefined) throw new StatePreconditionException()
34
- }
33
+ else if (query.version !== undefined)
34
+ throw new StatePreconditionException()
35
35
 
36
- if (record === null) {
37
36
  return null
38
- } else {
39
- return this.#entity.object(record)
40
- }
37
+ } else
38
+ return this.#entities.object(record)
41
39
  }
42
40
 
43
41
  async objects (query) {
44
- const recordset = await this.#storage.find(query)
42
+ const recordset = await this.storage.find(query)
45
43
 
46
- return this.#entity.objects(recordset)
44
+ return this.#entities.objects(recordset)
45
+ }
46
+
47
+ async stream (query) {
48
+ return this.storage.stream(query)
47
49
  }
48
50
 
49
51
  changeset (query) {
50
- return this.#entity.changeset(query)
52
+ return this.#entities.changeset(query)
51
53
  }
52
54
 
53
55
  none () {
54
56
  return null
55
57
  }
56
58
 
57
- async commit (state) {
58
- const event = state.event()
59
+ async ensure (query, properties, input) {
60
+ const object = this.#entities.init()
61
+ const blank = object.get()
59
62
 
60
- let ok = true
63
+ Object.assign(blank, properties)
61
64
 
62
- if (!empty(event.changeset)) {
63
- const object = state.get()
65
+ object.set(blank)
64
66
 
65
- ok = await this.#storage.store(object)
67
+ const record = await this.storage.ensure(query, properties, object.get())
66
68
 
67
- // #20
68
- if (ok === true) {
69
- await this.#emission.emit(event)
70
- }
69
+ if (record.id !== blank.id) // exists
70
+ return this.#entities.object(record)
71
+
72
+ const event = object.event(input)
73
+
74
+ await this.#emission.emit(event)
75
+
76
+ return object
77
+ }
78
+
79
+ async commit (state, input) {
80
+ const object = state.get()
81
+ const ok = await this.storage.store(object)
82
+
83
+ // #20
84
+ if (ok === true) {
85
+ const event = state.event(input)
86
+
87
+ await this.#emission.emit(event)
71
88
  }
72
89
 
73
90
  return ok
@@ -76,7 +93,7 @@ class State {
76
93
  async apply (state) {
77
94
  const changeset = state.export()
78
95
 
79
- const result = await this.#storage.upsert(state.query, changeset)
96
+ const result = await this.storage.upsert(state.query, changeset)
80
97
 
81
98
  if (result === null) {
82
99
  if (state.query.version !== undefined) {
package/src/transition.js CHANGED
@@ -1,12 +1,8 @@
1
1
  'use strict'
2
2
 
3
3
  const { retry } = require('@toa.io/generic')
4
-
5
4
  const { Operation } = require('./operation')
6
- const {
7
- StateConcurrencyException,
8
- StateNotFoundException
9
- } = require('./exceptions')
5
+ const { StateConcurrencyException, StateNotFoundException } = require('./exceptions')
10
6
 
11
7
  class Transition extends Operation {
12
8
  #concurrency
@@ -26,33 +22,26 @@ class Transition extends Operation {
26
22
 
27
23
  store.scope = request.query ? await this.query(request.query) : this.scope.init()
28
24
 
29
- if (store.scope === null) {
25
+ if (store.scope === null || (store.scope.deleted === true && request.query?.options?.deleted !== true))
30
26
  throw new StateNotFoundException()
31
- }
32
-
27
+
33
28
  store.state = store.scope.get()
34
29
  }
35
30
 
36
31
  async commit (store) {
37
- const {
38
- scope,
39
- state,
40
- reply,
41
- retry
42
- } = store
32
+ const { scope, state, reply, retry } = store
43
33
 
44
34
  if (reply.error !== undefined) return
45
35
 
46
36
  scope.set(state)
47
37
 
48
- const result = await this.scope.commit(scope)
38
+ const result = await this.scope.commit(scope, store.request.input)
49
39
 
50
40
  if (result === false) {
51
- if (this.#concurrency === 'retry') {
41
+ if (this.#concurrency === 'retry')
52
42
  return retry()
53
- } else {
43
+ else
54
44
  throw new StateConcurrencyException()
55
- }
56
45
  }
57
46
  }
58
47
 
@@ -67,7 +56,7 @@ const RETRY = {
67
56
  base: 10,
68
57
  max: 5000,
69
58
  dispersion: 1,
70
- retries: Infinity
59
+ retries: 32
71
60
  }
72
61
 
73
62
  exports.Transition = Transition
@@ -18,13 +18,22 @@ class Transmission extends Connector {
18
18
  let i = 0
19
19
 
20
20
  while (reply === false && i < this.#bindings.length) {
21
- reply = await this.#bindings[i].request(request)
21
+ const binding = this.#bindings[i]
22
+
22
23
  i++
24
+
25
+ if (request?.task === true) {
26
+ if (binding.task === undefined)
27
+ continue
28
+
29
+ await binding.task(request)
30
+ reply = null
31
+ } else
32
+ reply = await binding.request(request)
23
33
  }
24
34
 
25
- if (reply === false) {
35
+ if (reply === false)
26
36
  throw new TransmissionException(`All (${this.#bindings.length}) bindings rejected.`)
27
- }
28
37
 
29
38
  return reply
30
39
  }
@@ -0,0 +1,11 @@
1
+ 'use strict'
2
+
3
+ const { Operation } = require('./operation')
4
+
5
+ class Unmanaged extends Operation {
6
+ acquire (context) {
7
+ context.state = this.scope.storage.raw
8
+ }
9
+ }
10
+
11
+ exports.Unmanaged = Unmanaged
@@ -3,6 +3,7 @@
3
3
  const { Component } = require('../src/component')
4
4
  const { codes } = require('../src/exceptions')
5
5
  const fixtures = require('./component.fixtures')
6
+ const { AssertionError } = require('node:assert')
6
7
 
7
8
  describe('Invocations', () => {
8
9
  const name = ['foo', 'bar'][Math.floor(2 * Math.random())]
@@ -16,12 +17,12 @@ describe('Invocations', () => {
16
17
  it('should invoke', async () => {
17
18
  await component.invoke(name)
18
19
 
19
- expect(invocation.invoke).toBeCalled()
20
+ expect(invocation.invoke).toHaveBeenCalled()
20
21
  })
21
22
 
22
23
  it('should throw on unknown invocation name', async () => {
23
24
  await expect(() => component.invoke('baz'))
24
- .rejects.toMatchObject({ code: codes.NotImplemented })
25
+ .rejects.toThrow(AssertionError)
25
26
  })
26
27
 
27
28
  it('should invoke input and query', async () => {
@@ -29,7 +30,7 @@ describe('Invocations', () => {
29
30
  const query = { test: Math.random() }
30
31
  await component.invoke(name, { input, query })
31
32
 
32
- expect(invocation.invoke).toBeCalledWith({ input, query })
33
+ expect(invocation.invoke).toHaveBeenCalledWith({ input, query })
33
34
  })
34
35
 
35
36
  it('should return io', async () => {
@@ -2,19 +2,19 @@
2
2
 
3
3
  const { generate } = require('randomstring')
4
4
 
5
- const { Conditions } = require('../../src/contract/conditions')
5
+ const { Contract } = require('../../src/contract/contract')
6
6
  const fixtures = require('./contract.fixtures')
7
7
 
8
- let conditions
8
+ let contract
9
9
 
10
10
  beforeEach(() => {
11
- conditions = new Conditions(fixtures.schema)
11
+ contract = new Contract(fixtures.schema)
12
12
  })
13
13
 
14
14
  it('should fit value', () => {
15
15
  const value = { foo: generate() }
16
16
 
17
- conditions.fit(value)
17
+ contract.fit(value)
18
18
 
19
19
  expect(fixtures.schema.fit).toHaveBeenCalledWith(value)
20
20
  })
@@ -22,5 +22,5 @@ it('should fit value', () => {
22
22
  it('should throw on invalid value', () => {
23
23
  const value = { invalid: true }
24
24
 
25
- expect(() => conditions.fit(value)).toThrow()
25
+ expect(() => contract.fit(value)).toThrow()
26
26
  })
@@ -3,10 +3,10 @@
3
3
  const clone = require('clone-deep')
4
4
  const { generate } = require('randomstring')
5
5
 
6
- jest.mock('../../src/contract/conditions')
6
+ jest.mock('../../src/contract/contract')
7
7
 
8
8
  const { Request } = require('../../src/contract/request')
9
- const { Conditions } = require('../../src/contract/conditions')
9
+ const { Contract } = require('../../src/contract/contract')
10
10
  const fixtures = require('./contract.fixtures')
11
11
 
12
12
  let contract
@@ -14,14 +14,14 @@ let contract
14
14
  beforeEach(() => {
15
15
  jest.clearAllMocks()
16
16
 
17
- contract = new Request(fixtures.schema)
17
+ contract = new Request(fixtures.schema, {})
18
18
  })
19
19
 
20
20
  const dummy = { schema: { properties: {} } }
21
21
 
22
22
  it('should extend Conditions', () => {
23
- expect(contract).toBeInstanceOf(Conditions)
24
- expect(Conditions).toHaveBeenCalledWith(fixtures.schema)
23
+ expect(contract).toBeInstanceOf(Contract)
24
+ expect(Contract).toHaveBeenCalledWith(fixtures.schema)
25
25
  })
26
26
 
27
27
  it('should fit request', () => {
@@ -29,7 +29,7 @@ it('should fit request', () => {
29
29
 
30
30
  contract.fit(request)
31
31
 
32
- expect(Conditions.mock.instances[0].fit).toHaveBeenCalledWith(request)
32
+ expect(Contract.mock.instances[0].fit).toHaveBeenCalledWith(request)
33
33
  })
34
34
 
35
35
  describe('schema', () => {
@@ -59,7 +59,7 @@ describe('schema', () => {
59
59
 
60
60
  it('should not contain query if declaration.query is false', () => {
61
61
  schema.properties.query = { type: 'null' }
62
- expect(Request.schema({ query: false }, dummy)).toStrictEqual(schema)
62
+ expect(Request.schema({ query: false }, dummy)).toMatchObject(schema)
63
63
  })
64
64
 
65
65
  it('should require query if declaration.query is true', () => {
@@ -7,35 +7,7 @@ beforeEach(() => {
7
7
  jest.clearAllMocks()
8
8
  })
9
9
 
10
- describe('new', () => {
11
- it('should throw on schema error', () => {
12
- const entity = new Entity(fixtures.schema)
13
-
14
- expect(() => entity.set(fixtures.failed())).toThrow()
15
- })
16
-
17
- it('should provide state', () => {
18
- const entity = new Entity(fixtures.schema)
19
- const state = fixtures.state()
20
-
21
- entity.set(state)
22
-
23
- expect(entity.get()).toEqual(state)
24
- })
25
- })
26
-
27
10
  describe('argument', () => {
28
- it('should provide initial state if no argument passed', () => {
29
- const entity = new Entity(fixtures.schema)
30
- const defaults = fixtures.schema.defaults.mock.results[0].value
31
- const expected = {
32
- ...defaults,
33
- _version: 0
34
- }
35
-
36
- expect(entity.get()).toStrictEqual(expect.objectContaining(expected))
37
- })
38
-
39
11
  it('should set state', () => {
40
12
  const state = fixtures.state()
41
13
  const entity = new Entity(fixtures.schema, state)
@@ -63,20 +35,3 @@ it('should provide event', () => {
63
35
  })
64
36
  }))
65
37
  })
66
-
67
- it('should define `id` as readonly', async () => {
68
- const origin = fixtures.state()
69
- const entity = new Entity(fixtures.schema, origin)
70
- const state = entity.get()
71
-
72
- expect(() => (state.id = 1)).toThrow('assign to read only property')
73
- })
74
-
75
- it('should seal id', async () => {
76
- const origin = fixtures.state()
77
- const entity = new Entity(fixtures.schema, origin)
78
- const state = entity.get()
79
- const redefine = () => Object.defineProperty(state, 'id', { writable: true })
80
-
81
- expect(redefine).toThrow('redefine property')
82
- })
@@ -38,9 +38,3 @@ it('should emit', async () => {
38
38
 
39
39
  expect(fixtures.emitter.emit).toHaveBeenCalledWith(fixtures.entity.event.mock.results[0].value)
40
40
  })
41
-
42
- it('should not emit if state has not been changed', async () => {
43
- await state.commit(fixtures.unchanged)
44
-
45
- expect(fixtures.emitter.emit).not.toHaveBeenCalled()
46
- })
@@ -1,26 +1,28 @@
1
1
  import * as _core from './index'
2
2
 
3
- declare namespace toa.core.bindings{
3
+ declare namespace toa.core.bindings {
4
4
 
5
5
  type Properties = {
6
6
  async?: boolean
7
7
  }
8
8
 
9
- interface Consumer extends _core.Connector{
9
+ interface Consumer extends _core.Connector {
10
10
  request (request: Request): Promise<_core.Reply>
11
+
12
+ task (request: Request): Promise<void>
11
13
  }
12
14
 
13
- interface Emitter extends _core.Connector{
15
+ interface Emitter extends _core.Connector {
14
16
  emit (message: _core.Message): Promise<void>
15
17
  }
16
18
 
17
- interface Broadcast<L> extends _core.Connector{
19
+ interface Broadcast<L> extends _core.Connector {
18
20
  transmit<T> (label: L, payload: T): Promise<void>
19
21
 
20
22
  receive<T> (label: L, callback: (payload: T) => void | Promise<void>): Promise<void>
21
23
  }
22
24
 
23
- interface Factory{
25
+ interface Factory {
24
26
  producer? (locator: _core.Locator, endpoints: Array<string>, producer: _core.Component): _core.Connector
25
27
 
26
28
  consumer? (locator: _core.Locator, endpoint: string): Consumer