@universis/webhooks 1.1.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.
Files changed (38) hide show
  1. package/.gitlab-ci.yml +40 -0
  2. package/LICENSE +163 -0
  3. package/README.md +113 -0
  4. package/dist/SchemaLoader.d.ts +4 -0
  5. package/dist/SchemaLoader.js +46 -0
  6. package/dist/SchemaLoader.js.map +1 -0
  7. package/dist/WebHookService.d.ts +11 -0
  8. package/dist/WebHookService.js +272 -0
  9. package/dist/WebHookService.js.map +1 -0
  10. package/dist/config/models/WebHook.json +182 -0
  11. package/dist/config/models/WebHookAction.json +85 -0
  12. package/dist/config/models/WebHookConfiguration.json +66 -0
  13. package/dist/config/scope.access.js +30 -0
  14. package/dist/config/scope.access.js.map +1 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.js +3 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/listeners/OnWebHook.js +33 -0
  19. package/dist/listeners/OnWebHook.js.map +1 -0
  20. package/dist/listeners/OnWebHookAction.js +53 -0
  21. package/dist/listeners/OnWebHookAction.js.map +1 -0
  22. package/dist/listeners/package.json +3 -0
  23. package/jest.config.js +202 -0
  24. package/jsconfig.json +8 -0
  25. package/package.json +65 -0
  26. package/src/SchemaLoader.d.ts +4 -0
  27. package/src/SchemaLoader.js +46 -0
  28. package/src/WebHookService.d.ts +11 -0
  29. package/src/WebHookService.js +275 -0
  30. package/src/config/models/WebHook.json +182 -0
  31. package/src/config/models/WebHookAction.json +85 -0
  32. package/src/config/models/WebHookConfiguration.json +66 -0
  33. package/src/config/scope.access.js +34 -0
  34. package/src/index.d.ts +2 -0
  35. package/src/index.js +2 -0
  36. package/src/listeners/OnWebHook.js +37 -0
  37. package/src/listeners/OnWebHookAction.js +56 -0
  38. package/src/listeners/package.json +3 -0
@@ -0,0 +1,182 @@
1
+ {
2
+ "$schema": "https://themost-framework.github.io/themost/models/2018/2/schema.json",
3
+ "@id": "https://universis.io/schemas/WebHook",
4
+ "name": "WebHook",
5
+ "title": "WebHooks",
6
+ "hidden": false,
7
+ "sealed": false,
8
+ "abstract": false,
9
+ "version": "1.1.0",
10
+ "fields": [
11
+ {
12
+ "@id": "https://universis.io#id",
13
+ "name": "id",
14
+ "title": "ID",
15
+ "description": "The identifier of the item.",
16
+ "type": "Guid",
17
+ "primary": true,
18
+ "readonly": true,
19
+ "value": {
20
+ "$uuid": 1
21
+ }
22
+ },
23
+ {
24
+ "@id": "http://schema.org/additionalType",
25
+ "name": "additionalType",
26
+ "title": "additionalType",
27
+ "description": "An additional type for the item, typically used for adding more specific types from external vocabularies in microdata syntax. This is a relationship between something and a class that the thing is in. In RDFa syntax, it is better to use the native RDFa syntax - the 'typeof' attribute - for multiple types. Schema.org tools may have only weaker understanding of extra types, in particular those defined externally.",
28
+ "type": "Text",
29
+ "value": "javascript:return this.model.name;",
30
+ "readonly": true
31
+ },
32
+ {
33
+ "@id": "http://schema.org/name",
34
+ "name": "name",
35
+ "title": "name",
36
+ "description": "The name of the item.",
37
+ "type": "Text"
38
+ },
39
+ {
40
+ "@id": "https://universis.io#dateCreated",
41
+ "name": "dateCreated",
42
+ "title": "dateCreated",
43
+ "description": "The date on which this item was created.",
44
+ "type": "DateTime",
45
+ "readonly": true,
46
+ "value": {
47
+ "$now": 1
48
+ }
49
+ },
50
+ {
51
+ "@id": "https://universis.io#dateModified",
52
+ "name": "dateModified",
53
+ "title": "dateModified",
54
+ "description": "The date on which this item was most recently modified.",
55
+ "type": "DateTime",
56
+ "readonly": true,
57
+ "value": {
58
+ "$now": 1
59
+ },
60
+ "calculation": {
61
+ "$now": 1
62
+ }
63
+ },
64
+ {
65
+ "@id": "https://universis.io#owner",
66
+ "name": "owner",
67
+ "title": "owner",
68
+ "description": "The owner of the item.",
69
+ "type": "User",
70
+ "editable": false,
71
+ "nullable": false,
72
+ "value": {
73
+ "$user": 1
74
+ }
75
+ },
76
+ {
77
+ "@id": "https://universis.io#emit",
78
+ "name": "emit",
79
+ "title": "Emit",
80
+ "description": "Specifies whether the webhook should be triggered automatically or not.",
81
+ "type": "Boolean",
82
+ "value": {
83
+ "$value": true
84
+ }
85
+ },
86
+ {
87
+ "@id": "https://universis.io#createdBy",
88
+ "name": "createdBy",
89
+ "title": "createdBy",
90
+ "description": "Created by user.",
91
+ "type": "User",
92
+ "readonly": true,
93
+ "value": {
94
+ "$user": 1
95
+ }
96
+ },
97
+ {
98
+ "@id": "https://universis.io#modifiedBy",
99
+ "name": "modifiedBy",
100
+ "title": "modifiedBy",
101
+ "description": "Last modified by user.",
102
+ "type": "User",
103
+ "readonly": true,
104
+ "value": {
105
+ "$user": 1
106
+ },
107
+ "calculation": {
108
+ "$user": 1
109
+ }
110
+ },
111
+ {
112
+ "@id": "https://universis.io#webHookAction",
113
+ "name": "action",
114
+ "title": "action",
115
+ "description": "Reference to WebHookAction entity that defines the scope of the webhook.",
116
+ "type": "WebHookAction",
117
+ "mapping": {
118
+ "parentModel": "WebHookAction",
119
+ "parentField": "name"
120
+ }
121
+ },
122
+ {
123
+ "@id": "https://universis.io#active",
124
+ "name": "active",
125
+ "title": "Active",
126
+ "description": "Specifies whether the webhook is active or not.",
127
+ "type": "Boolean",
128
+ "nullable": false,
129
+ "value": {
130
+ "$value": true
131
+ }
132
+ },
133
+ {
134
+ "@id": "https://universis.io#webHookConfig",
135
+ "name": "config",
136
+ "title": "WebHook endpoint configuration",
137
+ "description": "Configuration settings for the webhook endpoint e.g. authentication, custom headers etc.",
138
+ "type": "Json",
139
+ "additionalType": "WebHookConfiguration"
140
+ },
141
+ {
142
+ "@id": "https://universis.io#lastResponse",
143
+ "name": "lastResponse",
144
+ "title": "Last Response",
145
+ "description": "Details of the last response received from the webhook endpoint.",
146
+ "type": "Json"
147
+ }
148
+ ],
149
+ "privileges": [
150
+ {
151
+ "mask": 15,
152
+ "type": "global"
153
+ },
154
+ {
155
+ "mask": 15,
156
+ "type": "global",
157
+ "account": "Administrators"
158
+ },
159
+ {
160
+ "mask": 1,
161
+ "type": "self",
162
+ "filter": "owner eq me()",
163
+ "scope": [
164
+ "webhooks:read"
165
+ ]
166
+ },
167
+ {
168
+ "mask": 14,
169
+ "type": "self",
170
+ "filter": "owner eq me()",
171
+ "scope": [
172
+ "webhooks:write"
173
+ ]
174
+ }
175
+ ],
176
+ "constraints": [
177
+ ],
178
+ "seed": [
179
+ ],
180
+ "eventListeners": [
181
+ ]
182
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "$schema": "https://themost-framework.github.io/themost/models/2018/2/schema.json",
3
+ "@id": "https://universis.io/schemas/WebHookAction",
4
+ "name": "WebHookAction",
5
+ "title": "WebHookActions",
6
+ "hidden": false,
7
+ "sealed": false,
8
+ "abstract": false,
9
+ "implements": "Thing",
10
+ "version": "1.1.0",
11
+ "fields": [
12
+ {
13
+ "@id": "http://schema.org/name",
14
+ "name": "name",
15
+ "title": "name",
16
+ "description": "The name of the item.",
17
+ "type": "Text",
18
+ "nullable": false
19
+ },
20
+ {
21
+ "@id": "http://schema.org/about",
22
+ "name": "about",
23
+ "type": "Text",
24
+ "title": "About",
25
+ "description": "The name of the entity type to which the webhook applies",
26
+ "nullable": false
27
+ },
28
+ {
29
+ "@id": "https://universis.io#state",
30
+ "name": "state",
31
+ "type": "Integer",
32
+ "title": "Event Types",
33
+ "description": "The type of event that triggers the webhook (e.g., insert, update, delete)",
34
+ "nullable": false
35
+ },
36
+ {
37
+ "@id": "https://universis.io#filter",
38
+ "name": "filter",
39
+ "type": "Text",
40
+ "title": "Filter",
41
+ "description": "Specifies when the webhook should be executed according to the current state of an object. The expression should follow OData $filter query option e.g. studentStatus ne 'active'",
42
+ "nullable": true
43
+ },
44
+ {
45
+ "@id": "https://universis.io#when",
46
+ "name": "when",
47
+ "type": "Text",
48
+ "title": "When",
49
+ "description": "An optional filter expression to further refine when the webhook is triggered according to the previous state of an object. The expression should follow OData $filter query option e.g. studentStatus eq 'active'",
50
+ "nullable": true
51
+ }
52
+ ],
53
+ "privileges": [
54
+ {
55
+ "mask": 15,
56
+ "type": "global"
57
+ },
58
+ {
59
+ "mask": 1,
60
+ "type": "global",
61
+ "account": "*"
62
+ },
63
+ {
64
+ "mask": 15,
65
+ "type": "global",
66
+ "account": "Administrators"
67
+ }
68
+ ],
69
+ "constraints": [
70
+ {
71
+ "type": "unique",
72
+ "@help": "Each item name must be unique because it is used as a reference e.g. create_user or delete_user etc.",
73
+ "fields": [
74
+ "name"
75
+ ]
76
+ }
77
+ ],
78
+ "seed": [
79
+ ],
80
+ "eventListeners": [
81
+ {
82
+ "type": "./listeners/OnWebHookAction"
83
+ }
84
+ ]
85
+ }
@@ -0,0 +1,66 @@
1
+ {
2
+ "$schema": "https://themost-framework.github.io/themost/models/2018/2/schema.json",
3
+ "@id": "https://universis.io/schemas/WebHookConfiguration",
4
+ "name": "WebHookConfiguration",
5
+ "title": "WebHookConfigurations",
6
+ "hidden": true,
7
+ "sealed": true,
8
+ "abstract": true,
9
+ "version": "1.1.0",
10
+ "fields": [
11
+ {
12
+ "@id": "https://universis.io#url",
13
+ "name": "url",
14
+ "title": "URL",
15
+ "description": "The URL to which the webhook payloads will be delivered",
16
+ "type": "URL",
17
+ "nullable": false
18
+ },
19
+ {
20
+ "@id": "https://universis.io#contentType",
21
+ "name": "contentType",
22
+ "title": "Content Type",
23
+ "description": "The content type of the payload sent to the webhook URL (e.g., application/json)",
24
+ "type": "Text",
25
+ "nullable": false,
26
+ "value": {
27
+ "$value": "application/json"
28
+ }
29
+ },
30
+ {
31
+ "@id": "https://universis.io#insecure",
32
+ "name": "insecure",
33
+ "title": "Insecure",
34
+ "description": "Indicates whether to skip SSL certificate verification when sending requests to the webhook URL",
35
+ "type": "Boolean",
36
+ "nullable": false,
37
+ "value": {
38
+ "$value": false
39
+ }
40
+ },
41
+ {
42
+ "@id": "https://universis.io#secret",
43
+ "name": "secret",
44
+ "title": "Secret",
45
+ "description": "An optional secret key used to sign the payloads sent to the webhook URL for verification purposes. The signature is included in the 'X-Signature' header of the request.",
46
+ "type": "Text"
47
+ }
48
+ ],
49
+ "privileges": [
50
+ {
51
+ "mask": 15,
52
+ "type": "global"
53
+ },
54
+ {
55
+ "mask": 15,
56
+ "type": "global",
57
+ "account": "Administrators"
58
+ }
59
+ ],
60
+ "constraints": [
61
+ ],
62
+ "seed": [
63
+ ],
64
+ "eventListeners": [
65
+ ]
66
+ }
@@ -0,0 +1,34 @@
1
+ const WebHookScopeAccessElements = [
2
+ {
3
+ 'scope': [
4
+ 'webhooks:read',
5
+ ],
6
+ 'resource': '/api/WebHookActions/?',
7
+ 'access': [
8
+ 'read'
9
+ ]
10
+ },
11
+ {
12
+ 'scope': [
13
+ 'webhooks:read',
14
+ ],
15
+ 'resource': '/api/WebHooks/?',
16
+ 'access': [
17
+ 'read'
18
+ ]
19
+ },
20
+ {
21
+ 'scope': [
22
+ 'webhooks:write',
23
+ ],
24
+ 'resource': '/api/WebHooks/?',
25
+ 'access': [
26
+ 'read',
27
+ 'write'
28
+ ]
29
+ }
30
+ ];
31
+
32
+ export {
33
+ WebHookScopeAccessElements
34
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './SchemaLoader';
2
+ export * from './WebHookService';
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './SchemaLoader';
2
+ export * from './WebHookService';
@@ -0,0 +1,37 @@
1
+ import {WebHookService} from '../WebHookService';
2
+
3
+ /**
4
+ * A generic web hook listener for insert or update operations to any data model
5
+ * @param {import('@themost/data').DataEventArgs} event
6
+ * @param {Function} callback
7
+ */
8
+ function afterSave(event, callback) {
9
+ return afterEvent(event, callback);
10
+ }
11
+ /**
12
+ * @param {import('@themost/data').DataEventArgs} event
13
+ * @param {Function} callback
14
+ */
15
+ function afterEvent(event, callback) {
16
+ const {context} = event.model;
17
+ const service = context.application.getService(WebHookService);
18
+ if (service) {
19
+ service.emit(event);
20
+ }
21
+ return callback();
22
+ }
23
+
24
+ /**
25
+ * A generic web hook for remove operations to any data model
26
+ * @param {import('@themost/data').DataEventArgs} event
27
+ * @param {Function} callback
28
+ */
29
+ function afterRemove(event, callback) {
30
+
31
+ return afterEvent(event, callback);
32
+ }
33
+
34
+ export {
35
+ afterSave,
36
+ afterRemove
37
+ }
@@ -0,0 +1,56 @@
1
+ import {DataObjectState, SchemaLoaderStrategy} from '@themost/data';
2
+ import path from 'path';
3
+ /**
4
+ * After save listener for OneWebHookAction
5
+ * @param {import('@themost/data').DataEventArgs} event
6
+ * @param {Function} callback
7
+ */
8
+ function afterSave(event, callback) {
9
+ if (event.state === DataObjectState.Insert || event.state === DataObjectState.Update) {
10
+ // change the underlying model definition
11
+ const { context } = event.model;
12
+ const schemaLoader = context.getConfiguration().getStrategy(SchemaLoaderStrategy);
13
+ const { about } = event.target;
14
+ if (about) {
15
+ /**
16
+ * @type {import('@themost/common').DataModelProperties}
17
+ */
18
+ const schema = schemaLoader.getModelDefinition(about);
19
+ if (schema) {
20
+ // try to find of previous state listener should be included in the list of event listeners
21
+ schema.eventListeners = schema.eventListeners || [];
22
+ const index = schema.eventListeners.findIndex((item) => {
23
+ return item.type === '@themost/data#previous-state-listener';
24
+ });
25
+ if (index < 0) {
26
+ // insert previous state listener at the beginning of the list
27
+ schema.eventListeners.unshift({
28
+ type: '@themost/data/previous-state-listener'
29
+ });
30
+ }
31
+ const type = path.resolve(__dirname, './OnWebHook');
32
+ const id = '@universis/webhooks/listeners/OnWebHook';
33
+ // try to find if web hook listener should be included in the list of event listeners
34
+ const webHookIndex = schema.eventListeners.findIndex((item) => {
35
+ return item['@id'] === id;
36
+ });
37
+ if (webHookIndex < 0) {
38
+ // add web hook listener at the end of the list
39
+ schema.eventListeners.push({
40
+ '@id': id,
41
+ type
42
+ });
43
+ }
44
+ const service = context.application.getService(function WebHookService() {});
45
+ service.logger.info(`A new web hook action with name "${event.target.name || 'unknown'}" has been registered for model "${about}"`);
46
+ // reset model definition
47
+ schemaLoader.setModelDefinition(schema);
48
+ }
49
+ }
50
+ return callback();
51
+ }
52
+ }
53
+
54
+ export {
55
+ afterSave
56
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "private": true
3
+ }