@toa.io/bridges.node 0.20.0-dev.8 → 0.20.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/bridges.node",
3
- "version": "0.20.0-dev.8",
3
+ "version": "0.20.0",
4
4
  "description": "Toa Node Bridge (inproc)",
5
5
  "homepage": "https://toa.io",
6
6
  "author": {
@@ -25,14 +25,17 @@
25
25
  "scripts": {
26
26
  "test": "echo \"Error: run tests from root\" && exit 1"
27
27
  },
28
+ "peerDependencies": {
29
+ "nopeable": "*"
30
+ },
28
31
  "dependencies": {
29
- "@toa.io/core": "0.20.0-dev.8",
30
- "@toa.io/filesystem": "0.20.0-dev.8",
31
- "@toa.io/generic": "0.20.0-dev.8",
32
+ "@toa.io/core": "0.20.0",
33
+ "@toa.io/filesystem": "0.20.0",
34
+ "@toa.io/generic": "0.20.0",
32
35
  "fast-glob": "3.2.7"
33
36
  },
34
37
  "devDependencies": {
35
38
  "clone-deep": "4.0.1"
36
39
  },
37
- "gitHead": "d8c08ec7def70ad93de06541af497cce8c4c1b50"
40
+ "gitHead": "28fc4b45c224c3683acaaf0e4abd1eb04e07b408"
38
41
  }
package/readme.md CHANGED
@@ -17,7 +17,7 @@ Factory. Module file name without extension is an operation name (endpoint).
17
17
  function transition (input, object, context) {
18
18
  // ...
19
19
 
20
- return { output: { foo: 'bar' } }
20
+ return { foo: 'bar' }
21
21
  }
22
22
 
23
23
  exports.transition = transition
@@ -48,15 +48,15 @@ See [Operation properties](#).
48
48
 
49
49
  class Transition {
50
50
  #context
51
-
52
- async mount(context) {
51
+
52
+ async mount (context) {
53
53
  this.#context = context
54
54
  }
55
-
55
+
56
56
  execute (input, object) {
57
57
  // ...
58
58
 
59
- return { output: { foo: 'bar' } }
59
+ return { foo: 'bar' }
60
60
  }
61
61
  }
62
62
 
@@ -87,20 +87,6 @@ implement [Algorithm Factory interface](#).
87
87
  > Factory class name examples: `ObjectTransitionFactory`, `ObjectsObservationFactory`,
88
88
  > `ChangesetAssignmentFactory`.
89
89
 
90
- ### Return value
91
-
92
- Algorithm's return value must match [UCP Response](#), that is, to be an object with either `output`
93
- or `error` properties. If return value is a primitive or an object without neither `output`
94
- nor `error` properties, then it is considered as the value of `output`.
95
-
96
- Next two return values are equivalent.
97
-
98
- ```javascript
99
- return { ok: 1 }
100
-
101
- return { output: { ok: 1 } }
102
- ```
103
-
104
90
  ### Storing Context
105
91
 
106
92
  > Algorithm definition should store reference to the `context` object without copying its value
@@ -1,6 +1,3 @@
1
1
  'use strict'
2
2
 
3
- /** @type {toa.node.define.algorithms.Constructor} */
4
- const create = (Class) => new Class()
5
-
6
- exports.create = create
3
+ exports.create = (Class) => new Class()
@@ -1,6 +1,5 @@
1
1
  'use strict'
2
2
 
3
- /** @type {toa.node.define.algorithms.Constructor} */
4
3
  const create = (Factory) => {
5
4
  const factory = new Factory()
6
5
 
@@ -1,10 +1,9 @@
1
1
  'use strict'
2
2
 
3
+ const { Nope } = require('nopeable')
3
4
  const { Connector } = require('@toa.io/core')
5
+ const { Readable } = require('node:stream')
4
6
 
5
- /**
6
- * @implements {toa.core.bridges.Algorithm}
7
- */
8
7
  class Runner extends Connector {
9
8
  /** @type {toa.node.Algorithm} */
10
9
  #algorithm
@@ -12,10 +11,6 @@ class Runner extends Connector {
12
11
  /** @type {toa.node.Context} */
13
12
  #context
14
13
 
15
- /**
16
- * @param {toa.node.Algorithm} algorithm
17
- * @param {toa.node.Context} context
18
- */
19
14
  constructor (algorithm, context) {
20
15
  super()
21
16
 
@@ -30,23 +25,21 @@ class Runner extends Connector {
30
25
  }
31
26
 
32
27
  async execute (input, state) {
33
- let reply = await this.#algorithm.execute(input, state)
28
+ const reply = await this.#algorithm.execute(input, state)
34
29
 
35
- if (reply !== undefined) reply = normalize(reply)
36
- else reply = {}
37
-
38
- return reply
30
+ if (reply instanceof Nope) return { error: reply }
31
+ else if (isGenerator(reply)) return Readable.from(reply)
32
+ else if (reply instanceof Readable) return reply
33
+ else return { output: reply }
39
34
  }
40
35
  }
41
36
 
42
- function normalize (reply) {
43
- const object = typeof reply === 'object'
44
- const output = object && reply.output !== undefined
45
- const error = object && reply.error !== undefined
46
-
47
- if (!output && !error) reply = { output: reply }
37
+ function isGenerator (object) {
38
+ const constructor = object?.constructor?.[Symbol.toStringTag]
48
39
 
49
- return reply
40
+ return constructor !== undefined &&
41
+ (constructor === 'AsyncGeneratorFunction' ||
42
+ constructor === 'GeneratorFunction')
50
43
  }
51
44
 
52
45
  exports.Runner = Runner
@@ -10,6 +10,9 @@ const syntaxes = require('./syntaxes')
10
10
  const define = (module) => {
11
11
  const descriptor = extract(module)
12
12
 
13
+ if (descriptor === null)
14
+ return null
15
+
13
16
  return syntaxes[descriptor.syntax].define(descriptor)
14
17
  }
15
18
 
@@ -8,7 +8,12 @@ const syntaxes = require('./syntaxes')
8
8
  * @returns {toa.node.define.algorithms.Descriptor}
9
9
  */
10
10
  const extract = (module) => {
11
- const [name, func] = find(module)
11
+ const entry = find(module)
12
+
13
+ if (entry === null)
14
+ return null
15
+
16
+ const [name, func] = entry
12
17
  const statement = parse(func)
13
18
 
14
19
  /** @type {toa.node.define.algorithms.Descriptor} */
@@ -32,7 +37,7 @@ const find = (module) => {
32
37
  if (typeof value === 'function') return [key, value]
33
38
  }
34
39
 
35
- throw new Error('Module does not export function')
40
+ return null
36
41
  }
37
42
 
38
43
  /**
@@ -10,7 +10,7 @@ const define = (descriptor) => {
10
10
  /** @type {toa.node.define.operations.Definition} */
11
11
  const definition = {}
12
12
 
13
- definition.type = /** @type {typeof toa.norm.component.Operation.type} */ name
13
+ definition.type = name
14
14
 
15
15
  if (node.params.length > 1) definition.scope = scope(node.params[1].name)
16
16
  if (node.params.length === 0) definition.input = null
@@ -29,7 +29,7 @@ const test = (statement, type) => {
29
29
 
30
30
  /**
31
31
  * @param {string} name
32
- * @returns {typeof toa.norm.component.Operation.scope}
32
+ * @returns {string}
33
33
  */
34
34
  const scope = (name) => scopes.includes(name) ? name : undefined
35
35
 
@@ -10,7 +10,11 @@ const operations = async (root) => {
10
10
  /** @type {toa.node.define.algorithms.List} */
11
11
  const algorithms = {}
12
12
 
13
- for (const [name, module] of modules) algorithms[name] = algorithm.define(module)
13
+ for (const [name, module] of modules) {
14
+ const definition = algorithm.define(module)
15
+
16
+ if (definition !== null) algorithms[name] = definition
17
+ }
14
18
 
15
19
  return algorithms
16
20
  }
package/src/event.js CHANGED
@@ -7,15 +7,19 @@ const { Connector } = require('@toa.io/core')
7
7
  */
8
8
  class Event extends Connector {
9
9
  #event
10
+ #context
10
11
 
11
- constructor (event) {
12
+ constructor (event, context) {
12
13
  super()
13
14
 
14
15
  this.#event = event
16
+ this.#context = context
17
+
18
+ this.depends(context)
15
19
  }
16
20
 
17
- condition = async (...args) => this.#event.condition(...args)
18
- payload = async (...args) => this.#event.payload(...args)
21
+ condition = async (...args) => this.#event.condition(...args, this.#context)
22
+ payload = async (...args) => this.#event.payload(...args, this.#context)
19
23
  }
20
24
 
21
25
  exports.Event = Event
package/src/factory.js CHANGED
@@ -7,9 +7,6 @@ const { Receiver } = require('./receiver')
7
7
  const { Context } = require('./context')
8
8
  const { extract } = require('./define/operations')
9
9
 
10
- /**
11
- * @implements {toa.core.bridges.Factory}
12
- */
13
10
  class Factory {
14
11
  algorithm (root, name, context) {
15
12
  const module = load.operation(root, name)
@@ -18,10 +15,11 @@ class Factory {
18
15
  return runner(module, ctx)
19
16
  }
20
17
 
21
- event (root, label) {
18
+ event (root, label, context) {
22
19
  const event = load.event(root, label)
20
+ const ctx = new Context(context)
23
21
 
24
- return new Event(event)
22
+ return new Event(event, ctx)
25
23
  }
26
24
 
27
25
  receiver (root, label) {
@@ -26,7 +26,7 @@ it('should define shortcut', async () => {
26
26
  })
27
27
 
28
28
  it('should call invoke', async () => {
29
- const args = Array.from({ length: random(5) + 2 }, generate)
29
+ const args = Array.from({ length: random(5) + 2 }, () => generate())
30
30
 
31
31
  await context.amqp.test.emit(...args)
32
32
 
@@ -4,8 +4,10 @@ const { http } = require('./http')
4
4
  const { amqp } = require('./amqp')
5
5
  const { configuration } = require('./configuration')
6
6
  const { state } = require('./state')
7
+ const { stash } = require('./stash')
7
8
 
8
9
  exports.http = http
9
10
  exports.amqp = amqp
10
11
  exports.configuration = configuration
11
12
  exports.state = state
13
+ exports.stash = stash
@@ -0,0 +1,16 @@
1
+ 'use strict'
2
+
3
+ const { underlay } = require('@toa.io/generic')
4
+
5
+ /** @type {toa.node.shortcut} */
6
+ const stash = (context, aspect) => {
7
+ context.stash = underlay(async (segs, args) => {
8
+ if (segs.length !== 1) throw new Error(`Stash aspect call should have 1 segment, [${segs.join(', ')}] given`)
9
+
10
+ const method = segs[0]
11
+
12
+ return aspect.invoke(method, ...args)
13
+ })
14
+ }
15
+
16
+ exports.stash = stash
@@ -42,18 +42,6 @@ it('should return output', async () => {
42
42
  }
43
43
  })
44
44
 
45
- it('should not return undefined output', async () => {
46
- const execute = () => undefined
47
- const algorithm = /** @type {toa.node.Algorithm} */ { execute }
48
- const runner = new Runner(algorithm, context)
49
-
50
- await runner.connect()
51
-
52
- const reply = await runner.execute()
53
-
54
- expect(reply).not.toStrictEqual(undefined)
55
- })
56
-
57
45
  it('should mount', async () => {
58
46
  const execute = () => undefined
59
47
  const mount = jest.fn(() => undefined)
@@ -26,11 +26,11 @@ it('should throw if class does not match conventions', () => {
26
26
  expect(() => define(module)).toThrow('does not match conventions')
27
27
  })
28
28
 
29
- it('should throw if no function exported', () => {
29
+ it('should return null if no function exported', () => {
30
30
  const foo = 'bar'
31
31
  const module = { foo }
32
32
 
33
- expect(() => define(module)).toThrow('Module does not export function')
33
+ expect(define(module)).toBeNull()
34
34
  })
35
35
 
36
36
  describe('function', () => {
@@ -11,7 +11,7 @@ class Computation {
11
11
  }
12
12
 
13
13
  async execute (input) {
14
- return { output: { input, context: this.#context !== undefined } }
14
+ return { input, context: this.#context !== undefined }
15
15
  }
16
16
  }
17
17
 
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  async function computation (input, object, context) {
4
- return { output: { input, state: object, context: context !== undefined } }
4
+ return { input, state: object, context: context !== undefined }
5
5
  }
6
6
 
7
7
  exports.computation = computation
@@ -11,7 +11,7 @@ class Transition {
11
11
  }
12
12
 
13
13
  async execute (input, object) {
14
- return { output: { input, state: object, context: this.#context !== undefined } }
14
+ return { input, state: object, context: this.#context !== undefined }
15
15
  }
16
16
  }
17
17
 
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  async function transition (input, object, context) {
4
- return { output: { input, state: object, context: context !== undefined } }
4
+ return { input, state: object, context: context !== undefined }
5
5
  }
6
6
 
7
7
  exports.transition = transition
@@ -1,6 +1,6 @@
1
1
  import { bridges } from '@toa.io/core/types'
2
2
  import * as _context from './context'
3
- import * as _core from '@toa.io/core/types';
3
+ import * as _core from '@toa.io/core/types'
4
4
 
5
5
  declare namespace toa.node {
6
6
 
@@ -16,11 +16,11 @@ declare namespace toa.node {
16
16
  }
17
17
 
18
18
  interface Algorithm {
19
- mount?(context: _context.Context): Promise<void> | void
19
+ mount? (context: _context.Context): Promise<void> | void
20
20
 
21
- execute(input: any, scope: object | object[]): Promise<_core.Reply>
21
+ execute (input: any, scope: object | object[]): Promise<any>
22
22
 
23
- execute(input: any): Promise<_core.Reply>
23
+ execute (input: any): Promise<_core.Reply>
24
24
  }
25
25
 
26
26
  }