ac-support-connector 0.1.1 → 1.0.1
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/.github/workflows/node.js.yml +1 -1
- package/.ncurc.js +8 -0
- package/CHANGELOG.md +30 -0
- package/README.md +41 -4
- package/eslint.config.js +30 -0
- package/index.js +38 -54
- package/package.json +9 -13
- package/test/test.js +15 -17
- package/.eslintrc.js +0 -27
package/.ncurc.js
ADDED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
<a name="1.0.1"></a>
|
|
2
|
+
|
|
3
|
+
## [1.0.1](https://github.com/admiralcloud/ac-support-connector/compare/v1.0.0..v1.0.1) (2024-08-27 14:05:03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fix
|
|
7
|
+
|
|
8
|
+
* **Connector:** Use ac-sqs | MP | [42dd23f9dde355204eb77a5f546cb2f12a8bb700](https://github.com/admiralcloud/ac-support-connector/commit/42dd23f9dde355204eb77a5f546cb2f12a8bb700)
|
|
9
|
+
Use our ac-sqs package
|
|
10
|
+
Related issues: [undefined/undefined#master](undefined/browse/master)
|
|
11
|
+
<a name="1.0.0"></a>
|
|
12
|
+
|
|
13
|
+
# [1.0.0](https://github.com/admiralcloud/ac-support-connector/compare/v0.1.1..v1.0.0) (2024-08-26 07:17:38)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fix
|
|
17
|
+
|
|
18
|
+
* **Connector:** Improved usage | MP | [c1962e78072ee709e52d1f2230ebf0655aef568c](https://github.com/admiralcloud/ac-support-connector/commit/c1962e78072ee709e52d1f2230ebf0655aef568c)
|
|
19
|
+
Improved message processing with more flexibility. See README.
|
|
20
|
+
Related issues: [undefined/undefined#master](undefined/browse/master)
|
|
21
|
+
* **Connector:** Package updates | MP | [ae989c837d20b4a68245c5683631dc2c4c71b3ce](https://github.com/admiralcloud/ac-support-connector/commit/ae989c837d20b4a68245c5683631dc2c4c71b3ce)
|
|
22
|
+
Package update
|
|
23
|
+
Related issues: [undefined/undefined#master](undefined/browse/master)
|
|
24
|
+
### Chores
|
|
25
|
+
|
|
26
|
+
* **Connector:** Updated packages | MP | [c469b370133e827a2e6994d04e1197f17d81357b](https://github.com/admiralcloud/ac-support-connector/commit/c469b370133e827a2e6994d04e1197f17d81357b)
|
|
27
|
+
Updated packages
|
|
28
|
+
Related issues: [undefined/undefined#master](undefined/browse/master)
|
|
29
|
+
## BREAKING CHANGES
|
|
30
|
+
* **Connector:** See README - changes version 1
|
|
1
31
|
<a name="0.1.1"></a>
|
|
2
32
|
|
|
3
33
|
## [0.1.1](https://github.com/admiralcloud/ac-support-connector/compare/v0.1.0..v0.1.1) (2023-07-26 19:49:09)
|
package/README.md
CHANGED
|
@@ -3,6 +3,14 @@ This module sends unified support payloads to SQS. A dedicated service (not part
|
|
|
3
3
|
|
|
4
4
|
[](https://github.com/AdmiralCloud/ac-support-connector/actions/workflows/node.js.yml)
|
|
5
5
|
|
|
6
|
+
# Breaking changes
|
|
7
|
+
## Version 1
|
|
8
|
+
+ platforms array is now required
|
|
9
|
+
+ channels are no longer supported, use platforms instead
|
|
10
|
+
+ use "text" for simple messages and "message" array for complex messages
|
|
11
|
+
+ level, service, project, etc are types in the message array (see example below)
|
|
12
|
+
+ messages with payload > 256kB will throw an exception (instead of truncating)
|
|
13
|
+
|
|
6
14
|
# Prerequisites
|
|
7
15
|
Create a SQS queue (e.g. supportQueue) and use a policy that allows all (or selected) IAM users from the account to send messages to the queue:
|
|
8
16
|
|
|
@@ -34,11 +42,38 @@ await supportConnector.init({
|
|
|
34
42
|
|
|
35
43
|
// now send logs like this
|
|
36
44
|
|
|
45
|
+
// SIMPLE MESSAGE
|
|
37
46
|
await supportConnector.createMessage({
|
|
47
|
+
platforms: ['jsm']
|
|
38
48
|
subject: 'Operation failed',
|
|
39
49
|
text: 'The operation ABC failed due to missing parameter',
|
|
40
|
-
level: 'warn' // optional, if none is set, the level is info
|
|
41
50
|
})
|
|
51
|
+
|
|
52
|
+
// COMPLEX MESSAGE
|
|
53
|
+
await supportConnector.createMessage({
|
|
54
|
+
platform: ['jsm', 'teams'],
|
|
55
|
+
subject: 'Operation failed',
|
|
56
|
+
reporter: 'jane.doe@admiralcloud.com',
|
|
57
|
+
message: [{
|
|
58
|
+
type: 'text',
|
|
59
|
+
content: 'The operation ABC failed due to missing parameter'
|
|
60
|
+
}, {
|
|
61
|
+
type: 'level,
|
|
62
|
+
content: 'warn'
|
|
63
|
+
}, {
|
|
64
|
+
type: 'service',
|
|
65
|
+
content: 'my-service'
|
|
66
|
+
}, {
|
|
67
|
+
type: 'instanceId',
|
|
68
|
+
content: 'abc123'
|
|
69
|
+
}, {
|
|
70
|
+
type: 'project',
|
|
71
|
+
content: 'playground-channel'
|
|
72
|
+
}]
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
NOTE: If instanceId and service are set during init, they will be automatically added to message payload.
|
|
76
|
+
|
|
42
77
|
```
|
|
43
78
|
|
|
44
79
|
# Parameters
|
|
@@ -55,13 +90,15 @@ await supportConnector.createMessage({
|
|
|
55
90
|
|---|---|---|
|
|
56
91
|
|subject|string|Subject of the message
|
|
57
92
|
|text|string|Text of the message
|
|
58
|
-
|
|
|
93
|
+
|message|array|Array of objects with properties types and content*
|
|
59
94
|
|block|integer|Seconds before the message is sent again (if the error occurs again). If Redis is not available, memory is used.
|
|
60
95
|
|
|
96
|
+
There is no limit to types in message array. Some of them have an effect when using ac-lambda-supportEventProcessor. Only type "text" must exist. Every type can be multiple times in the array.
|
|
97
|
+
|
|
98
|
+
Using message as array can help to "layout" your message, e.g. in Teams as nice message card.
|
|
61
99
|
|
|
62
100
|
## Links
|
|
63
101
|
- [Website](https://www.admiralcloud.com/)
|
|
64
|
-
- [Facebook](https://www.facebook.com/MediaAssetManagement/)
|
|
65
102
|
|
|
66
103
|
## License
|
|
67
|
-
Copyright AdmiralCloud AG, Mark Poepping
|
|
104
|
+
Copyright 2009 - today, AdmiralCloud AG, Mark Poepping
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const globals = require('globals');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
ignores: [
|
|
5
|
+
'config/env/**'
|
|
6
|
+
],
|
|
7
|
+
languageOptions: {
|
|
8
|
+
ecmaVersion: 2022,
|
|
9
|
+
sourceType: 'module',
|
|
10
|
+
globals: {
|
|
11
|
+
...globals.commonjs,
|
|
12
|
+
...globals.es6,
|
|
13
|
+
...globals.node,
|
|
14
|
+
expect: 'readonly',
|
|
15
|
+
describe: 'readonly',
|
|
16
|
+
it: 'readonly'
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
rules: {
|
|
20
|
+
'no-const-assign': 'error', // Ensure this rule is enabled
|
|
21
|
+
'space-before-function-paren': 'off',
|
|
22
|
+
'no-extra-semi': 'off',
|
|
23
|
+
'object-curly-spacing': ['error', 'always'],
|
|
24
|
+
'brace-style': ['error', 'stroustrup', { allowSingleLine: true }],
|
|
25
|
+
'no-useless-escape': 'off',
|
|
26
|
+
'standard/no-callback-literal': 'off',
|
|
27
|
+
'new-cap': 'off',
|
|
28
|
+
'no-console': ['warn', { allow: ['warn', 'error'] }]
|
|
29
|
+
}
|
|
30
|
+
};
|
package/index.js
CHANGED
|
@@ -1,53 +1,48 @@
|
|
|
1
|
-
const { SQSClient, SendMessageCommand } = require('@aws-sdk/client-sqs')
|
|
2
1
|
const { STSClient, GetCallerIdentityCommand } = require('@aws-sdk/client-sts')
|
|
3
|
-
const { fromIni } = require("@aws-sdk/credential-providers")
|
|
4
|
-
|
|
5
|
-
const getLength = require('utf8-byte-length')
|
|
6
|
-
const truncate = require('truncate-utf8-bytes')
|
|
7
|
-
|
|
8
2
|
const NodeCache = require('node-cache')
|
|
9
3
|
|
|
4
|
+
const ACSQS = require('ac-sqs')
|
|
5
|
+
|
|
10
6
|
const functionName = 'ac-support-connector'.padEnd(20)
|
|
11
7
|
|
|
12
8
|
module.exports = {
|
|
13
9
|
|
|
14
10
|
aws: {},
|
|
15
11
|
|
|
16
|
-
init: async function({ serviceName, instanceId, sqsQueue, redisInstance, region = 'eu-central-1', profile = process.env['profile'], debug } = {}) {
|
|
12
|
+
init: async function({ serviceName, instanceId, sqsQueue = 'AC-SupportQueue', bucket, redisInstance, region = 'eu-central-1', profile = process.env['profile'], debug } = {}) {
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (profile) {
|
|
25
|
-
console.error('%s | Using AWS profile | %s', functionName, profile)
|
|
26
|
-
awsConfig.credentials = fromIni({ profile })
|
|
27
|
-
}
|
|
14
|
+
this.sqsQueue = sqsQueue
|
|
15
|
+
this.serviceName = serviceName || 'SupportConnector'
|
|
16
|
+
this.instanceId = instanceId
|
|
17
|
+
this.redisInstance = redisInstance
|
|
18
|
+
this.cache = new NodeCache()
|
|
19
|
+
this.debugMode = debug
|
|
28
20
|
|
|
29
|
-
|
|
21
|
+
if (!debug) {
|
|
30
22
|
const client = new STSClient(awsConfig)
|
|
31
23
|
const command = new GetCallerIdentityCommand()
|
|
32
24
|
const response = await client.send(command)
|
|
33
25
|
const accountId = response?.Account
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
26
|
+
const sqsParams = {
|
|
27
|
+
account: accountId,
|
|
28
|
+
availableLists: [{
|
|
29
|
+
name: sqsQueue,
|
|
30
|
+
fifo: true
|
|
31
|
+
}]
|
|
39
32
|
}
|
|
33
|
+
if (profile) sqsParams.profile = profile // Optional AWS profile, see below
|
|
34
|
+
if (bucket) {
|
|
35
|
+
sqsParams.useS3 = {
|
|
36
|
+
enabled: true,
|
|
37
|
+
bucket
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
this.acsqs = new ACSQS(sqsParams)
|
|
40
41
|
}
|
|
41
|
-
|
|
42
|
-
this.serviceName = serviceName || 'SupportConnector'
|
|
43
|
-
this.instanceId = instanceId
|
|
44
|
-
this.sqsQueue = sqsQueue || 'supportQueue'
|
|
45
|
-
this.redisInstance = redisInstance
|
|
46
|
-
this.cache = new NodeCache()
|
|
47
42
|
},
|
|
48
43
|
|
|
49
44
|
|
|
50
|
-
createMessage: async function({ subject, text,
|
|
45
|
+
createMessage: async function({ subject, text, message = [], block, platforms, reporter }) {
|
|
51
46
|
// check block time in Redis, fallback to memory
|
|
52
47
|
if (block) {
|
|
53
48
|
if (block < 1) block = 1 // make sure to use reasonable value!
|
|
@@ -69,40 +64,29 @@ module.exports = {
|
|
|
69
64
|
}
|
|
70
65
|
}
|
|
71
66
|
|
|
67
|
+
// message is an array of objects, if it is empty and just text is set, add it to the array
|
|
68
|
+
if (message.length === 0) message.push({ type: 'text', content: text })
|
|
69
|
+
|
|
70
|
+
// service is also part of message array
|
|
71
|
+
message.push({ type: 'service', content: this.serviceName })
|
|
72
|
+
if (this.instanceId) message.push({ type: 'instanceId', content: this.instanceId })
|
|
73
|
+
|
|
72
74
|
const messagePayload = {
|
|
75
|
+
platforms,
|
|
73
76
|
subject,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
serviceName: this.serviceName
|
|
77
|
+
reporter,
|
|
78
|
+
message,
|
|
77
79
|
}
|
|
78
|
-
if (this.instanceId) messagePayload.instanceId = this.instanceId
|
|
79
|
-
if (channels) messagePayload.channels = channels
|
|
80
80
|
|
|
81
|
-
const maxSize = 256 * 1024 // 256kb
|
|
82
|
-
const recordLength = getLength(JSON.stringify(messagePayload))
|
|
83
|
-
if (recordLength > maxSize) {
|
|
84
|
-
// text must be truncated
|
|
85
|
-
const textLength = getLength(messagePayload.text)
|
|
86
|
-
const truncatedSize = textLength - (recordLength - maxSize)
|
|
87
|
-
messagePayload.text = truncate(messagePayload.text, truncatedSize)
|
|
88
|
-
console.log('%s | Subject %s | Truncated to %s', functionName, subject, truncatedSize)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
81
|
if (process.env.NODE_ENV === 'test') {
|
|
92
82
|
return messagePayload
|
|
93
83
|
}
|
|
94
|
-
|
|
95
|
-
const awsInput = {
|
|
96
|
-
QueueUrl: `https://sqs.${this.aws.region}.amazonaws.com/${this.aws.accountId}/${this.sqsQueue}`,
|
|
97
|
-
MessageBody: JSON.stringify(messagePayload)
|
|
98
|
-
}
|
|
99
|
-
const command = new SendMessageCommand(awsInput)
|
|
100
84
|
try {
|
|
101
|
-
|
|
102
|
-
console.
|
|
85
|
+
await this.acsqs.sendSQSMessage({ name: this.sqsQueue, message: JSON.stringify(messagePayload) })
|
|
86
|
+
if (this.debugMode) console.warn(response)
|
|
103
87
|
}
|
|
104
88
|
catch(e) {
|
|
105
|
-
console.
|
|
89
|
+
console.error('%s | Subject %s | Failed %j', functionName, subject, e?.message)
|
|
106
90
|
}
|
|
107
91
|
}
|
|
108
92
|
}
|
package/package.json
CHANGED
|
@@ -3,27 +3,23 @@
|
|
|
3
3
|
"author": "Mark Poepping (https://www.admiralcloud.com)",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": "admiralcloud/ac-support-connector",
|
|
6
|
-
"version": "0.1
|
|
6
|
+
"version": "1.0.1",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"@aws-sdk/credential-providers": "^3.378.0",
|
|
11
|
-
"node-cache": "^5.1.2",
|
|
12
|
-
"truncate-utf8-bytes": "^1.0.2",
|
|
13
|
-
"utf8-byte-length": "^1.0.4"
|
|
8
|
+
"ac-sqs": "^2.0.4",
|
|
9
|
+
"node-cache": "^5.1.2"
|
|
14
10
|
},
|
|
15
11
|
"devDependencies": {
|
|
16
12
|
"ac-semantic-release": "^0.4.2",
|
|
17
|
-
"chai": "^4.
|
|
18
|
-
"eslint": "^
|
|
19
|
-
"expect": "^29.
|
|
20
|
-
"ioredis": "^5.
|
|
21
|
-
"mocha": "^10.
|
|
13
|
+
"chai": "^4.5.0",
|
|
14
|
+
"eslint": "^9.9.1",
|
|
15
|
+
"expect": "^29.7.0",
|
|
16
|
+
"ioredis": "^5.4.1",
|
|
17
|
+
"mocha": "^10.7.3"
|
|
22
18
|
},
|
|
23
19
|
"scripts": {
|
|
24
20
|
"test": "NODE_ENV=test mocha --reporter spec || :"
|
|
25
21
|
},
|
|
26
22
|
"engines": {
|
|
27
|
-
"node": ">=
|
|
23
|
+
"node": ">=18.0.0"
|
|
28
24
|
}
|
|
29
25
|
}
|
package/test/test.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
const { expect } = require('chai');
|
|
2
2
|
|
|
3
|
-
const getLength = require("utf8-byte-length")
|
|
4
|
-
const truncate = require("truncate-utf8-bytes")
|
|
5
|
-
|
|
6
3
|
const Redis = require("ioredis");
|
|
7
4
|
const redisInstance = new Redis()
|
|
8
5
|
|
|
@@ -19,29 +16,30 @@ describe('Basic tests', () => {
|
|
|
19
16
|
it('Test properties', async() => {
|
|
20
17
|
let params = {
|
|
21
18
|
subject: 'Failed',
|
|
22
|
-
text: 'This failed'
|
|
23
|
-
level: 'warn'
|
|
19
|
+
text: 'This failed'
|
|
24
20
|
}
|
|
25
21
|
let response = await supCon.createMessage(params)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
expect(response).to.have.property('subject', params.subject)
|
|
23
|
+
expect(response).to.have.property('message').that.is.an('array').with.lengthOf.at.least(1);
|
|
24
|
+
expect(response.message[0]).to.have.property('type', 'text')
|
|
25
|
+
expect(response.message[0]).to.have.property('content', params.text)
|
|
30
26
|
})
|
|
31
27
|
|
|
32
|
-
it('Check truncated payload > 256KB -
|
|
28
|
+
it('Check truncated payload > 256KB - should not throw an error', async() => {
|
|
33
29
|
let params = {
|
|
34
30
|
subject: 'Failed',
|
|
35
|
-
|
|
31
|
+
message: [{
|
|
32
|
+
type: 'text',
|
|
33
|
+
content: string1001
|
|
34
|
+
}]
|
|
36
35
|
}
|
|
37
|
-
|
|
38
|
-
const recordLength = getLength(JSON.stringify(params))
|
|
39
|
-
const textLength = getLength(params.text)
|
|
40
|
-
const truncated = truncate(params.text, textLength - (recordLength - maxSize))
|
|
36
|
+
|
|
41
37
|
let response = await supCon.createMessage(params)
|
|
42
|
-
expect(response
|
|
38
|
+
expect(response).to.have.property('subject', params.subject)
|
|
39
|
+
expect(response).to.have.property('message').that.is.an('array').with.lengthOf.at.least(1);
|
|
40
|
+
expect(response.message[0]).to.have.property('type', 'text')
|
|
41
|
+
expect(response.message[0]).to.have.property('content', string1001)
|
|
43
42
|
})
|
|
44
|
-
|
|
45
43
|
})
|
|
46
44
|
|
|
47
45
|
describe('Block with Redis', () => {
|
package/.eslintrc.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const config = {
|
|
2
|
-
root: true,
|
|
3
|
-
'env': {
|
|
4
|
-
'commonjs': true,
|
|
5
|
-
'es6': true,
|
|
6
|
-
'node': true
|
|
7
|
-
},
|
|
8
|
-
'extends': 'eslint:recommended',
|
|
9
|
-
"rules": {
|
|
10
|
-
"space-before-function-paren": 0,
|
|
11
|
-
"no-extra-semi": 0,
|
|
12
|
-
"object-curly-spacing": ["error", "always"],
|
|
13
|
-
"brace-style": ["error", "stroustrup", { "allowSingleLine": true }],
|
|
14
|
-
"no-useless-escape": 0,
|
|
15
|
-
"standard/no-callback-literal": 0,
|
|
16
|
-
"new-cap": 0
|
|
17
|
-
},
|
|
18
|
-
globals: {
|
|
19
|
-
describe: true,
|
|
20
|
-
it: true
|
|
21
|
-
},
|
|
22
|
-
'parserOptions': {
|
|
23
|
-
'ecmaVersion': 2021
|
|
24
|
-
},
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = config
|