@outliant/sunrise-utils 1.1.32 → 1.2.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/CHANGELOG.md CHANGED
@@ -4,9 +4,16 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ #### [1.2.0](https://github.com/outliant/sunrise-utils/compare/1.1.32...1.2.0)
8
+
9
+ - chore: event service with sns #86b0xg1gf [`7baa9ec`](https://github.com/outliant/sunrise-utils/commit/7baa9ec2d0c85f78d3573854d1216d974551465c)
10
+
7
11
  #### [1.1.32](https://github.com/outliant/sunrise-utils/compare/1.1.31...1.1.32)
8
12
 
13
+ > 23 July 2024
14
+
9
15
  - chore add is_any_of filter to user_select field condition #86b0b3k2r [`#42`](https://github.com/outliant/sunrise-utils/pull/42)
16
+ - chore(release): 1.1.32 [`cdeeae5`](https://github.com/outliant/sunrise-utils/commit/cdeeae5e959518d725badd30ea3cb40724654cf5)
10
17
 
11
18
  #### [1.1.31](https://github.com/outliant/sunrise-utils/compare/1.1.29...1.1.31)
12
19
 
package/index.d.ts CHANGED
@@ -43,7 +43,7 @@ declare namespace Utils {
43
43
  field: string;
44
44
  direction: 'asc' | 'desc';
45
45
  text: string;
46
- }[],
46
+ }[];
47
47
  columns?: string[];
48
48
  }
49
49
 
@@ -95,6 +95,42 @@ declare namespace Utils {
95
95
  export function getIsPausedQuery(): any;
96
96
  export function getNotIsPausedQuery(): any;
97
97
  }
98
+
99
+ interface SNSService {
100
+ publishBatch(params: {
101
+ TopicArn: string;
102
+ PublishBatchRequestEntries: {
103
+ Id: string;
104
+ Message: string;
105
+ [key: string]: any;
106
+ }[];
107
+ }): Promise<void>;
108
+ }
109
+
110
+ type EventServiceTypes =
111
+ | 'customer'
112
+ | 'customer.fields'
113
+ | 'project'
114
+ | 'project.fields'
115
+ | 'project.stage'
116
+ | 'task'
117
+ | 'task.fields';
118
+ type EventServiceAction = 'create' | 'update' | 'delete';
119
+
120
+ type EventParams = {
121
+ orgId: string;
122
+ type: EventServiceTypes;
123
+ action: EventServiceAction;
124
+ sourceId: string;
125
+ data: any;
126
+ attributes?: Record<string, string | string[] | number>;
127
+ };
128
+
129
+ class EventService {
130
+ constructor(snsService: SNSService, eventsTopicArn: string);
131
+
132
+ send(events: EventParams[]): Promise<any>;
133
+ }
98
134
  }
99
135
 
100
136
  export = Utils;
package/index.js CHANGED
@@ -4,6 +4,7 @@ const taskPipeline = require('./lib/taskPipeline');
4
4
  const projectPipeline = require('./lib/projectPipeline');
5
5
  const usersPipeline = require('./lib/usersPipeline');
6
6
  const queries = require('./lib/queries');
7
+ const EventService = require('./lib/eventService');
7
8
 
8
9
  module.exports = {
9
10
  log,
@@ -11,5 +12,6 @@ module.exports = {
11
12
  taskPipeline,
12
13
  projectPipeline,
13
14
  usersPipeline,
14
- queries
15
+ queries,
16
+ EventService
15
17
  };
@@ -0,0 +1,88 @@
1
+ const _ = require('lodash');
2
+ const { v4: uuid } = require('uuid');
3
+
4
+ class EventService {
5
+ constructor(snsService, eventsTopicArn) {
6
+ this.snsService = snsService;
7
+ this.eventsTopicArn = eventsTopicArn;
8
+ }
9
+
10
+ async send(events) {
11
+ const groups = _.chunk(events, 10);
12
+
13
+ for (const group of groups) {
14
+ const now = new Date().getTime();
15
+ const entries = _.map(
16
+ group,
17
+ ({ orgId, type, action, sourceId, data, attributes = {} }) => {
18
+ const params = {
19
+ organization_id: orgId,
20
+ type,
21
+ action,
22
+ source_id: sourceId,
23
+ data,
24
+ status: 'pending',
25
+ created_at: now,
26
+ updated_at: now
27
+ };
28
+
29
+ return {
30
+ Id: this.generateMessageId(),
31
+ Message: JSON.stringify(params),
32
+ MessageAttributes: {
33
+ type: {
34
+ DataType: 'String',
35
+ StringValue: type
36
+ },
37
+ action: {
38
+ DataType: 'String',
39
+ StringValue: action
40
+ },
41
+ ...this.createSnsMessageAttributes(attributes)
42
+ }
43
+ };
44
+ }
45
+ );
46
+
47
+ this.snsService.publishBatch({
48
+ TopicArn: this.eventsTopicArn,
49
+ PublishBatchRequestEntries: entries
50
+ });
51
+ }
52
+ }
53
+
54
+ createSnsMessageAttributes(attributes) {
55
+ const snsAttributes = {};
56
+
57
+ for (const [key, value] of Object.entries(attributes)) {
58
+ if (_.isString(value)) {
59
+ snsAttributes[key] = {
60
+ DataType: 'String',
61
+ StringValue: value
62
+ };
63
+ } else if (_.isArray(value)) {
64
+ snsAttributes[key] = {
65
+ DataType: 'String.Array',
66
+ StringValue: JSON.stringify(_.map(value, (v) => v.toString()))
67
+ };
68
+ } else if (_.isNumber(value)) {
69
+ snsAttributes[key] = {
70
+ DataType: 'Number',
71
+ StringValue: value.toString()
72
+ };
73
+ } else {
74
+ throw new Error(
75
+ `Unsupported attribute type for key "${key}": ${typeof value}`
76
+ );
77
+ }
78
+ }
79
+
80
+ return snsAttributes;
81
+ }
82
+
83
+ generateMessageId() {
84
+ return uuid();
85
+ }
86
+ }
87
+
88
+ module.exports = EventService;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@outliant/sunrise-utils",
3
3
  "description": "Helper functions for project Sunrise",
4
- "version": "1.1.32",
4
+ "version": "1.2.0",
5
5
  "license": "ISC",
6
6
  "author": "Outliant",
7
7
  "main": "index.js",
@@ -0,0 +1,85 @@
1
+ 'use strict';
2
+
3
+ /* eslint-env node, mocha */
4
+ const { expect } = require('chai');
5
+ const sinon = require('sinon');
6
+
7
+ const EventService = require('../../lib/eventService');
8
+
9
+ describe('eventService', function () {
10
+ let sandbox;
11
+
12
+ beforeEach(() => {
13
+ sandbox = sinon.createSandbox();
14
+ sandbox.stub(Date.prototype, 'getTime').returns(111111111);
15
+ });
16
+
17
+ afterEach(() => {
18
+ sandbox.restore();
19
+ });
20
+
21
+ it('should publish sns message to events topic', async () => {
22
+ sandbox
23
+ .stub(EventService.prototype, 'generateMessageId')
24
+ .returns('test-id');
25
+ const snsService = {
26
+ publishBatch: sandbox.stub()
27
+ };
28
+ const eventService = new EventService(snsService, 'test-sns-topic');
29
+
30
+ await eventService.send([
31
+ {
32
+ orgId: 'test-org-id',
33
+ type: 'project.fields',
34
+ action: 'update',
35
+ sourceId: 'test-project-id',
36
+ data: {
37
+ id: 'property-id',
38
+ old: '',
39
+ new: 'new value',
40
+ propertyName: 'test-property'
41
+ },
42
+ attributes: {
43
+ projectId: 'test-project-id',
44
+ projectCreatedAt: 111111,
45
+ projectTags: ['tag1', 'tag2', 'tag3']
46
+ }
47
+ }
48
+ ]);
49
+
50
+ expect(
51
+ snsService.publishBatch.calledWith({
52
+ TopicArn: 'test-sns-topic',
53
+ PublishBatchRequestEntries: [
54
+ {
55
+ Id: 'test-id',
56
+ Message:
57
+ '{"organization_id":"test-org-id","type":"project.fields","action":"update","source_id":"test-project-id","data":{"id":"property-id","old":"","new":"new value","propertyName":"test-property"},"status":"pending","created_at":111111111,"updated_at":111111111}',
58
+ MessageAttributes: {
59
+ type: {
60
+ DataType: 'String',
61
+ StringValue: 'project.fields'
62
+ },
63
+ action: {
64
+ DataType: 'String',
65
+ StringValue: 'update'
66
+ },
67
+ projectId: {
68
+ DataType: 'String',
69
+ StringValue: 'test-project-id'
70
+ },
71
+ projectCreatedAt: {
72
+ DataType: 'Number',
73
+ StringValue: '111111'
74
+ },
75
+ projectTags: {
76
+ DataType: 'String.Array',
77
+ StringValue: '["tag1","tag2","tag3"]'
78
+ }
79
+ }
80
+ }
81
+ ]
82
+ })
83
+ ).to.be.true;
84
+ });
85
+ });