comq 0.4.0-dev.2 → 0.4.0-dev.5

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.
@@ -0,0 +1,53 @@
1
+ name: Release
2
+
3
+ on:
4
+ pull_request:
5
+ types: [closed]
6
+ branches:
7
+ - main
8
+ - dev
9
+
10
+ jobs:
11
+ publish:
12
+ if: github.event.pull_request.merged == true
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - name: Setup Node
17
+ uses: actions/setup-node@v3
18
+ with:
19
+ node-version: 16
20
+ registry-url: 'https://registry.npmjs.org'
21
+
22
+ - name: Checkout
23
+ uses: actions/checkout@v3
24
+ with:
25
+ fetch-depth: 0
26
+
27
+ - name: Run tests
28
+ run: npm i && npm test
29
+
30
+ - name: Bump version
31
+ run: |
32
+ git config user.name "toabot"
33
+ git config user.email "127577558+toabot@users.noreply.github.com"
34
+
35
+ if [ ${{ github.base_ref }} = main ]; then
36
+ npx lerna@6.5.1 version --conventional-graduate --no-commit-hooks --no-changelog --yes --message "chore(release): %s"
37
+ git fetch
38
+ git checkout dev
39
+ git merge main
40
+ git push --all origin --no-verify
41
+ else
42
+ npx lerna@6.5.1 version --conventional-prerelease --preid dev --no-commit-hooks --no-changelog --yes --message "chore(prerelease): %s"
43
+ fi
44
+
45
+ - name: Publish packages
46
+ env:
47
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
48
+ run: |
49
+ if [ ${{ github.base_ref }} = main ]; then
50
+ npm publish
51
+ else
52
+ npm publish --tag dev
53
+ fi
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ npm test
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Toa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/docs/notes.md CHANGED
@@ -21,7 +21,7 @@ The current message is acknowledged once the Producer function is completed, whi
21
21
  considered to be published when a confirmation is received from the broker.
22
22
 
23
23
  In summary, the next "cause" message will be consumed from the queue only after the "effect" message
24
- publication has been confirmed. Due to the ["at least once" effect](#-at-least-once-), *there is a
24
+ publication has been confirmed. Due to the "at least once" effect, *there is a
25
25
  delay between the moment when a Reply **is delivered** to the Consumer and the moment when the
26
26
  next Request is consumed from the Request queue*.
27
27
 
@@ -1,7 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const { generate } = require('randomstring')
4
-
5
3
  const io = () => ({
6
4
  diagnose: jest.fn(() => undefined),
7
5
  close: jest.fn(async () => undefined)
@@ -52,7 +52,7 @@ describe('Given (that ){token} is consuming events from the {token} exchange', (
52
52
  })
53
53
 
54
54
  describe('Given {token} consuming events from the {token} exchange is expected', () => {
55
- const step = tomato.steps.Gi('{token} consuming events from the {token} exchange is expected')
55
+ tomato.steps.Gi('{token} consuming events from the {token} exchange is expected')
56
56
 
57
57
  it('should be', async () => undefined)
58
58
  })
@@ -15,7 +15,7 @@ Given('the broker is/has {status}',
15
15
  })
16
16
 
17
17
  const actions = {
18
- up: async (context) => {
18
+ up: async () => {
19
19
  await execute('docker start comq-rmq')
20
20
  await healthy()
21
21
  },
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { World } = require('@cucumber/cucumber')
4
- const { connect } = require('comq')
4
+ const { connect } = require('../../')
5
5
 
6
6
  /**
7
7
  * @implements {comq.features.Context}
package/lerna.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "useWorkspaces": true,
3
+ "version": "0.4.0-dev.0",
4
+ "conventionalCommits": true
5
+ }
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "comq",
3
- "version": "0.4.0-dev.2",
3
+ "version": "0.4.0-dev.5",
4
4
  "description": "ComQ",
5
- "homepage": "https://toa.io",
6
5
  "author": {
7
6
  "name": "Artem Gurtovoi",
8
7
  "url": "https://github.com/temich"
@@ -10,10 +9,10 @@
10
9
  "license": "MIT",
11
10
  "repository": {
12
11
  "type": "git",
13
- "url": "git+https://github.com/toa-io/toa.git"
12
+ "url": "git+https://github.com/toa-io/comq.git"
14
13
  },
15
14
  "bugs": {
16
- "url": "https://github.com/toa-io/toa/issues"
15
+ "url": "https://github.com/toa-io/comq/issues"
17
16
  },
18
17
  "engines": {
19
18
  "node": ">= 12.0.0"
@@ -24,13 +23,36 @@
24
23
  "main": "source/index.js",
25
24
  "types": "types/index.d.ts",
26
25
  "devDependencies": {
27
- "@toa.io/command": "0.4.0-dev.2",
28
- "@toa.io/mock": "0.4.0-dev.2",
29
- "@toa.io/yaml": "0.4.0-dev.2"
26
+ "@cucumber/cucumber": "9.0.0",
27
+ "@toa.io/command": "0.3.0",
28
+ "@toa.io/mock": "0.3.0",
29
+ "@toa.io/tomato": "0.4.0-dev.2",
30
+ "@toa.io/yaml": "0.4.0-dev.2",
31
+ "@types/amqplib": "0.10.1",
32
+ "@types/jest": "29.4.2",
33
+ "husky": "8.0.3",
34
+ "jest": "29.5.0",
35
+ "randomstring": "1.2.3",
36
+ "snazzy": "9.0.0",
37
+ "standard": "17.0.0"
30
38
  },
31
39
  "dependencies": {
32
- "@toa.io/generic": "0.4.0-dev.2",
40
+ "@toa.io/generic": "0.3.0",
33
41
  "amqplib": "0.10.3",
34
42
  "msgpackr": "1.8.5"
35
- }
43
+ },
44
+ "scripts": {
45
+ "prepare": "husky install",
46
+ "test": "npm run lint && jest",
47
+ "test:features": "npx cucumber-js",
48
+ "lint": "npx standard --verbose | npx snazzy"
49
+ },
50
+ "standard": {
51
+ "env": [
52
+ "jest"
53
+ ]
54
+ },
55
+ "workspaces": [
56
+ "."
57
+ ]
36
58
  }
package/readme.md CHANGED
@@ -51,7 +51,8 @@ await io.close()
51
51
 
52
52
  The following documentation refers to a few terms:
53
53
 
54
- **Request** is an AMQP message that has the `replyTo` and `correlationId` properties set.
54
+ **Request** is an AMQP message that is sent to a queue and has the `replyTo` and `correlationId`
55
+ properties set.
55
56
 
56
57
  **Reply** is an AMQP message sent in response to a Request and sent to the queue specified in
57
58
  the `replyTo` property of the Request. The `correlationId` property of the Reply is set to the same
@@ -93,7 +94,7 @@ await io.reply('add_numbers', ({ a, b }) => (a + b))
93
94
 
94
95
  ## Request
95
96
 
96
- `async IO.request(queue: string, payload: any, [encoding: string])`
97
+ `async IO.request(queue: string, payload: any, [encoding: string, replyTo: string])`
97
98
 
98
99
  Send encoded Request message with `replyTo` and `correlationId` properties set and
99
100
  return decoded Reply content.
package/source/io.js CHANGED
@@ -61,13 +61,16 @@ class IO {
61
61
  * @param {string} queue
62
62
  * @param {any} payload
63
63
  * @param {comq.encoding} [encoding]
64
+ * @param {string} replyTo
64
65
  * @returns {Promise<void>}
65
66
  */
66
- async (queue, payload, encoding) => {
67
+ async (queue, payload, encoding, replyTo) => {
67
68
  const [buffer, contentType] = this.#encode(payload, encoding)
68
69
  const correlationId = randomBytes(8).toString('hex')
69
70
  const emitter = this.#emitters[queue]
70
- const replyTo = emitter.queue
71
+
72
+ replyTo ??= emitter.queue
73
+
71
74
  const properties = { contentType, correlationId, replyTo }
72
75
  const reply = this.#createReply()
73
76
 
@@ -1,11 +1,11 @@
1
1
  'use strict'
2
2
 
3
+ const { randomBytes } = require('node:crypto')
3
4
  const { generate } = require('randomstring')
4
5
  const { promex, immediate } = require('@toa.io/generic')
5
6
 
6
7
  const mock = require('./connection.mock')
7
8
  const { IO } = require('../source/io')
8
- const { randomBytes } = require('crypto')
9
9
 
10
10
  /** @type {comq.IO} */
11
11
  let io
@@ -29,7 +29,7 @@ const produce = jest.fn(async () => generate())
29
29
 
30
30
  // endregion
31
31
 
32
- describe('channels', (type) => {
32
+ describe('channels', () => {
33
33
  it('should create request-reply channels', async () => {
34
34
  await io.reply(queue, produce)
35
35
 
@@ -43,6 +43,8 @@ let promise
43
43
  const REPLY = new RegExp(`^${queue}..[0-9a-f]+$`)
44
44
 
45
45
  beforeEach(async () => {
46
+ jest.clearAllMocks()
47
+
46
48
  promise = io.request(queue, payload)
47
49
 
48
50
  // allows initializers to run
@@ -81,11 +83,36 @@ describe('send', () => {
81
83
  expect(typeof properties.correlationId).toStrictEqual('string')
82
84
  })
83
85
 
84
- it('should set replyTo', async () => {
85
- const request = call[2]
86
+ it('should set default replyTo', async () => {
87
+ const properties = call[2]
88
+ const rx = new RegExp(`^${queue}..[a-z0-9]+`)
89
+
90
+ expect(properties.replyTo).toMatch(rx)
91
+ })
92
+
93
+ it('should set specified replyTo', async () => {
94
+ jest.clearAllMocks()
95
+
96
+ /** @type {comq.encoding} */
97
+ const encoding = 'application/json'
98
+ const replyTo = generate()
99
+
100
+ promise = io.request(queue, payload, encoding, replyTo)
101
+
102
+ await immediate()
103
+
104
+ call = requests.send.mock.calls[0]
105
+
106
+ const properties = requests.send.mock.calls[0][2]
107
+
108
+ expect(properties.replyTo).toStrictEqual(replyTo)
109
+ })
110
+
111
+ it('should consume replyTo', async () => {
112
+ const properties = call[2]
86
113
  const queue = replies.consume.mock.calls[0][0]
87
114
 
88
- expect(request.replyTo).toStrictEqual(queue)
115
+ expect(properties.replyTo).toStrictEqual(queue)
89
116
  })
90
117
 
91
118
  it('should encode message with msgpack by default', async () => {
package/types/io.d.ts CHANGED
@@ -19,7 +19,7 @@ declare namespace comq {
19
19
  interface IO {
20
20
  reply(queue: string, produce: producer): Promise<void>
21
21
 
22
- request(queue: string, payload: any, encoding?: _encoding.encoding): Promise<any>
22
+ request(queue: string, payload: any, encoding?: _encoding.encoding, replyTo?: string): Promise<any>
23
23
 
24
24
  consume(exchange: string, group: string, consumer: consumer): Promise<void>
25
25