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.
@@ -16,7 +16,7 @@ jobs:
16
16
 
17
17
  strategy:
18
18
  matrix:
19
- node-version: [16.x, 18.x]
19
+ node-version: [18.x, 20.x, 22.x]
20
20
  # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
21
21
  redis-version: [6]
22
22
 
package/.ncurc.js ADDED
@@ -0,0 +1,8 @@
1
+ // List packages for minor updates
2
+ const minorUpdatePackages = ['chai']
3
+
4
+ module.exports = {
5
+ target: packageName => {
6
+ return minorUpdatePackages.includes(packageName) ? 'minor' : 'latest'
7
+ }
8
+ }
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
  [![Node.js CI](https://github.com/AdmiralCloud/ac-geoip/actions/workflows/node.js.yml/badge.svg)](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
- |level|string|Level of the message, if not set defaults to info. Available: error, warn, debug, verbose, info
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
@@ -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
- if (!debug) {
19
- const awsConfig = {
20
- region
21
- }
22
- // credentials are determined from role.
23
- // But you can also use a set profile
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
- // determine accountId
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
- this.aws = {
36
- sqs: new SQSClient(awsConfig),
37
- region,
38
- accountId
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, level, block, channels }) {
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
- text,
75
- level,
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
- const response = await this.aws.sqs.send(command)
102
- console.log(response)
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.log('%s | Subject %s | Failed %j', functionName, subject, e?.message)
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.1",
6
+ "version": "1.0.1",
7
7
  "dependencies": {
8
- "@aws-sdk/client-sqs": "^3.378.0",
9
- "@aws-sdk/client-sts": "^3.378.0",
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.3.7",
18
- "eslint": "^8.45.0",
19
- "expect": "^29.6.1",
20
- "ioredis": "^5.3.2",
21
- "mocha": "^10.2.0"
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": ">=16.0.0"
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
- Object.keys(params).forEach(prop => {
27
- const val = params[prop]
28
- expect(response).to.have.property(prop, val)
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 - truncated', async() => {
28
+ it('Check truncated payload > 256KB - should not throw an error', async() => {
33
29
  let params = {
34
30
  subject: 'Failed',
35
- text: string1001
31
+ message: [{
32
+ type: 'text',
33
+ content: string1001
34
+ }]
36
35
  }
37
- const maxSize = 256 * 1024 // 256kb
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.text).to.equal(truncated)
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