@skillswaveca/nova-shared-libraries 4.24.0 → 4.25.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.
@@ -1,31 +1,31 @@
1
1
  export const packageInfo = [
2
2
  {
3
3
  "name": "@skillswaveca/nova-utils",
4
- "version": "4.23.0",
4
+ "version": "4.24.0",
5
5
  "description": "A collection of random utils used in nova repos",
6
6
  "docsPath": "./nova-utils/index.html"
7
7
  },
8
8
  {
9
9
  "name": "@skillswaveca/nova-router",
10
- "version": "4.23.0",
10
+ "version": "4.24.0",
11
11
  "description": "An extended Koa router that enables better validation",
12
12
  "docsPath": "./nova-router/index.html"
13
13
  },
14
14
  {
15
15
  "name": "@skillswaveca/nova-model",
16
- "version": "4.23.0",
16
+ "version": "4.24.0",
17
17
  "description": "Nova model stuff",
18
18
  "docsPath": "./nova-model/index.html"
19
19
  },
20
20
  {
21
21
  "name": "@skillswaveca/nova-middleware",
22
- "version": "4.23.0",
22
+ "version": "4.24.0",
23
23
  "description": "A collection of middleware used by nova projects",
24
24
  "docsPath": "./nova-middleware/index.html"
25
25
  },
26
26
  {
27
27
  "name": "@skillswaveca/nova-drivers",
28
- "version": "4.23.0",
28
+ "version": "4.24.0",
29
29
  "description": "Some helper drivers for AWS services",
30
30
  "docsPath": "./drivers/index.html"
31
31
  }
package/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './packages/nova-utils/src/tenant-utils.js';
2
2
  export * from './packages/nova-utils/src/logger.js';
3
3
  export * from './packages/nova-utils/src/general.js';
4
+ export * from './packages/nova-utils/src/event-definitions.js';
4
5
  export * from './packages/nova-utils/src/config.js';
5
6
  export * from './packages/nova-router/src/nova-router.js';
6
7
  export * from './packages/nova-middleware/src/oauth-middleware.js';
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "@skillswaveca/nova-shared-libraries",
4
4
  "description": "A monorepo of shared libraries for Nova projects.",
5
5
  "repository": "https://github.com/SkillsWave/nova-shared-libraries",
6
- "version": "4.24.0",
6
+ "version": "4.25.0",
7
7
  "main": "index.js",
8
8
  "license": "MIT",
9
9
  "keywords": [],
@@ -25,7 +25,8 @@
25
25
  "pino": "^9.1.0",
26
26
  "simple-oauth2": "^5.0.0",
27
27
  "uuid": "^9.0.1",
28
- "yn": "^5.0.0"
28
+ "yn": "^5.0.0",
29
+ "yup": "^1.4.0"
29
30
  },
30
31
  "devDependencies": {
31
32
  "@alpha-lambda/eslint-config": "^2.0.0",
@@ -3,7 +3,7 @@
3
3
  "name": "@skillswaveca/nova-drivers",
4
4
  "description": "Some helper drivers for AWS services",
5
5
  "repository": "https://github.com/SkillsWave/nova-shared-libraries",
6
- "version": "4.24.0",
6
+ "version": "4.25.0",
7
7
  "main": "index.js",
8
8
  "scripts": {
9
9
  "pre-release": "pnpm run create-index",
@@ -3,6 +3,7 @@ import { Client } from '@hubspot/api-client';
3
3
  import log from '../../nova-utils/src/logger.js';
4
4
  import { NovaDriver } from './nova-driver.js';
5
5
  import { secretsManager } from './aws/secrets-manager.js';
6
+ import { validateEvent, getEventDefinition, getEventMetadata } from '../../nova-utils/src/event-definitions.js';
6
7
 
7
8
  const HUBSPOT_USER_ATTRIBUTE_MAPPINGS = {
8
9
  firstName: 'firstname',
@@ -22,6 +23,7 @@ export class HubSpotDriver extends NovaDriver {
22
23
  * @property {Object} hubSpot
23
24
  * @property {string} hubSpot.secretName
24
25
  * @property {string} hubSpot.secretKeyId
26
+ * @property {string} hubSpot.accountId
25
27
  * @property {string} region
26
28
  * @property {string} rootEnvironmentAwsAccountId
27
29
  * @property {boolean} enabled
@@ -31,6 +33,7 @@ export class HubSpotDriver extends NovaDriver {
31
33
  this._client = null;
32
34
  this.secretName = config.hubSpot.secretName;
33
35
  this.secretKeyId = config.hubSpot.secretKeyId;
36
+ this.accountId = config.hubSpot.accountId;
34
37
  }
35
38
 
36
39
  /**
@@ -177,4 +180,47 @@ export class HubSpotDriver extends NovaDriver {
177
180
 
178
181
  await this._callHubSpot('crm.contacts.basicApi.archive', user.hubSpotContactId);
179
182
  }
183
+
184
+ /**
185
+ * Sends a custom event to HubSpot using the event definitions.
186
+ * This method validates the event data against the predefined schema before sending.
187
+ *
188
+ * @param {string} eventName - The name of the event to send
189
+ * @param {object} eventData - The event data to send
190
+ * @returns {Promise<object>} The response from HubSpot API
191
+ * @throws {Error} If validation fails or HubSpot API returns an error
192
+ */
193
+ async sendEvent(eventName, eventData) {
194
+ try {
195
+ // Validate the event exists and get its definition
196
+ const eventDefinition = getEventDefinition(eventName);
197
+ if (!eventDefinition) {
198
+ log.error({ eventName }, 'Event definition not found');
199
+ return;
200
+ }
201
+
202
+ const validatedData = await validateEvent(eventName, eventData);
203
+
204
+ const eventMetadata = await getEventMetadata(eventName, validatedData);
205
+
206
+ const response = await this._callHubSpot('events.send.basicApi.send', {
207
+ eventName: `pe${this.accountId}_${eventName}`,
208
+ properties: validatedData,
209
+ occurredAt: new Date(),
210
+ ...eventMetadata,
211
+ });
212
+
213
+ log.debug({ eventName, response }, 'Event sent to HubSpot successfully');
214
+ return response;
215
+ } catch (error) {
216
+ log.error({
217
+ eventName,
218
+ eventData,
219
+ error: error.message,
220
+ stack: error.stack
221
+ }, 'Unexpected error while sending event');
222
+
223
+ throw error;
224
+ }
225
+ }
180
226
  }
@@ -3,7 +3,7 @@
3
3
  "name": "@skillswaveca/nova-middleware",
4
4
  "description": "A collection of middleware used by nova projects",
5
5
  "repository": "https://github.com/SkillsWave/nova-shared-libraries",
6
- "version": "4.24.0",
6
+ "version": "4.25.0",
7
7
  "main": "index.js",
8
8
  "scripts": {
9
9
  "pre-release": "pnpm run create-index",
@@ -3,7 +3,7 @@
3
3
  "name": "@skillswaveca/nova-model",
4
4
  "description": "Nova model stuff",
5
5
  "repository": "https://github.com/SkillsWave/nova-shared-libraries",
6
- "version": "4.24.0",
6
+ "version": "4.25.0",
7
7
  "main": "index.js",
8
8
  "scripts": {
9
9
  "pre-release": "pnpm run create-index",
@@ -3,7 +3,7 @@
3
3
  "name": "@skillswaveca/nova-router",
4
4
  "description": "An extended Koa router that enables better validation",
5
5
  "repository": "https://github.com/SkillsWave/nova-shared-libraries",
6
- "version": "4.24.0",
6
+ "version": "4.25.0",
7
7
  "main": "index.js",
8
8
  "scripts": {
9
9
  "pre-release": "pnpm run create-index",
@@ -1,4 +1,5 @@
1
1
  export * from './src/tenant-utils.js';
2
2
  export * from './src/logger.js';
3
3
  export * from './src/general.js';
4
+ export * from './src/event-definitions.js';
4
5
  export * from './src/config.js';
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@skillswaveca/nova-utils",
3
+ "version": "4.24.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "@skillswaveca/nova-utils",
9
+ "version": "4.24.0",
10
+ "license": "UNLICENSED",
11
+ "dependencies": {
12
+ "yup": "^1.4.0"
13
+ },
14
+ "devDependencies": {}
15
+ },
16
+ "node_modules/property-expr": {
17
+ "version": "2.0.6",
18
+ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
19
+ "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA=="
20
+ },
21
+ "node_modules/tiny-case": {
22
+ "version": "1.0.3",
23
+ "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
24
+ "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
25
+ },
26
+ "node_modules/toposort": {
27
+ "version": "2.0.2",
28
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
29
+ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
30
+ },
31
+ "node_modules/type-fest": {
32
+ "version": "2.19.0",
33
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
34
+ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
35
+ "engines": {
36
+ "node": ">=12.20"
37
+ },
38
+ "funding": {
39
+ "url": "https://github.com/sponsors/sindresorhus"
40
+ }
41
+ },
42
+ "node_modules/yup": {
43
+ "version": "1.6.1",
44
+ "resolved": "https://registry.npmjs.org/yup/-/yup-1.6.1.tgz",
45
+ "integrity": "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==",
46
+ "dependencies": {
47
+ "property-expr": "^2.0.5",
48
+ "tiny-case": "^1.0.3",
49
+ "toposort": "^2.0.2",
50
+ "type-fest": "^2.19.0"
51
+ }
52
+ }
53
+ }
54
+ }
@@ -3,7 +3,7 @@
3
3
  "name": "@skillswaveca/nova-utils",
4
4
  "description": "A collection of random utils used in nova repos",
5
5
  "repository": "https://github.com/SkillsWave/nova-shared-libraries",
6
- "version": "4.24.0",
6
+ "version": "4.25.0",
7
7
  "main": "index.js",
8
8
  "scripts": {
9
9
  "pre-release": "pnpm run create-index",
@@ -14,5 +14,7 @@
14
14
  "author": "SkillsWave",
15
15
  "license": "UNLICENSED",
16
16
  "devDependencies": {},
17
- "dependencies": {}
17
+ "dependencies": {
18
+ "yup": "^1.4.0"
19
+ }
18
20
  }
@@ -0,0 +1,104 @@
1
+ import * as yup from 'yup';
2
+
3
+ /**
4
+ * HubSpot Event Definitions
5
+ *
6
+ * This module contains the schema definitions for custom events that can be sent to HubSpot.
7
+ * Each event definition includes:
8
+ * - name: The event name used in HubSpot
9
+ * - description: Human-readable description of the event
10
+ * - properties: Schema definition for event properties
11
+ * - validator: Yup validation schema for the event data
12
+ */
13
+
14
+ const testEventDefinition = {
15
+ name: 'hubspot_test_event',
16
+ description: 'Test event for HubSpot integration',
17
+ properties: {
18
+ email: {
19
+ type: 'string',
20
+ required: true,
21
+ description: 'Email address of the user',
22
+ },
23
+ },
24
+ validator: yup.object({
25
+ email: yup.string().email('Must be a valid email').required('Email is required'),
26
+ }),
27
+ getMetadata: eventData => {
28
+ return {
29
+ email: eventData.email,
30
+ };
31
+ },
32
+ };
33
+
34
+ /**
35
+ * Map of all available event definitions
36
+ * Key: event name, Value: event definition object
37
+ */
38
+ export const eventDefinitions = {
39
+ [testEventDefinition.name]: testEventDefinition,
40
+ };
41
+
42
+ /**
43
+ * Get event definition by name
44
+ * @param {string} eventName - The name of the event
45
+ * @returns {Object|null} The event definition or null if not found
46
+ */
47
+ export const getEventDefinition = eventName => {
48
+ return eventDefinitions[eventName] || null;
49
+ };
50
+
51
+ /**
52
+ * Get all available event names
53
+ * @returns {string[]} Array of event names
54
+ */
55
+ export const getEventNames = () => {
56
+ return Object.keys(eventDefinitions);
57
+ };
58
+
59
+ /**
60
+ * Validate event data against its schema
61
+ * @param {string} eventName - The name of the event
62
+ * @param {Object} eventData - The event data to validate
63
+ * @returns {Promise<Object>} The validated and transformed event data
64
+ * @throws {Error} If validation fails
65
+ */
66
+ export const validateEvent = async(eventName, eventData) => {
67
+ const eventDef = getEventDefinition(eventName);
68
+
69
+ if (!eventDef) {
70
+ return;
71
+ }
72
+
73
+ const validatedData = await eventDef.validator.validate(eventData, {
74
+ abortEarly: false,
75
+ stripUnknown: true,
76
+ });
77
+
78
+ return validatedData;
79
+ };
80
+
81
+ /**
82
+ * Check if an event name is valid
83
+ * @param {string} eventName - The name of the event
84
+ * @returns {boolean} True if the event exists, false otherwise
85
+ */
86
+ export const isValidEventName = eventName => {
87
+ return eventDefinitions.hasOwnProperty(eventName);
88
+ };
89
+
90
+ /**
91
+ * Gets any event metadata required to send the event to HubSpot.
92
+ * @param {string} eventName The name of the event
93
+ * @param {Object} eventData The custom data for the event
94
+ * @returns {Promise<Object>} The metadata for the event required to send it to HubSpot
95
+ */
96
+ export const getEventMetadata = async(eventName, eventData) => {
97
+ const eventDef = getEventDefinition(eventName);
98
+
99
+ if (!eventDef || typeof eventDef.getMetadata !== 'function') {
100
+ return {};
101
+ }
102
+
103
+ return await eventDef.getMetadata(eventData);
104
+ };