@mhubcloud/tms_core 1.7.6 → 2.0.0-beta.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.
Files changed (43) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.cjs +87 -0
  3. package/.prettierignore +3 -0
  4. package/.prettierrc +10 -0
  5. package/.vscode/extensions.json +12 -0
  6. package/.vscode/settings.json +52 -0
  7. package/index.js +1 -0
  8. package/{lib → js/lib}/defaultPublisher.js +26 -24
  9. package/js/lib/utils.js +349 -0
  10. package/js/publishers/AffiliatePort.js +78 -0
  11. package/{publishers → js/publishers}/CJ.js +7 -5
  12. package/{publishers → js/publishers}/Facebook.js +6 -4
  13. package/{publishers → js/publishers}/GoogleAnalytics4.js +8 -6
  14. package/js/publishers/HttpPublisher.js +64 -0
  15. package/{publishers → js/publishers}/Piano.js +6 -4
  16. package/{publishers → js/publishers}/UniversalAnalytics.js +7 -5
  17. package/package.json +46 -29
  18. package/releasePlan.md +3 -0
  19. package/src/defaultPublisher.ts +132 -0
  20. package/src/index.ts +25 -0
  21. package/src/publishers/affiliatePort.ts +69 -0
  22. package/src/publishers/cj.ts +67 -0
  23. package/src/publishers/facebook.ts +49 -0
  24. package/src/publishers/googleAnalytics4.ts +60 -0
  25. package/src/publishers/piano.ts +71 -0
  26. package/src/publishers/universalAnalytics.ts +63 -0
  27. package/src/types/EventHubMessage.ts +8 -0
  28. package/src/types/EventPublisher.ts +9 -0
  29. package/src/types/PlatformPublisher.ts +19 -0
  30. package/src/types/UtilTypes.ts +1 -0
  31. package/src/types/global.d.ts +3 -0
  32. package/src/utils/utils.ts +358 -0
  33. package/tests/AffiliatePort.js +107 -85
  34. package/tests/CJ.js +144 -119
  35. package/tests/Facebook.js +124 -103
  36. package/tests/GoogleAnalytics4.js +82 -74
  37. package/tests/Piano.js +112 -99
  38. package/tests/UniversalAnalytics.js +90 -77
  39. package/tests/testUtils.js +7 -0
  40. package/tsconfig.eslint.json +43 -0
  41. package/tsconfig.json +26 -0
  42. package/lib/utils.js +0 -307
  43. package/publishers/AffiliatePort.js +0 -61
@@ -0,0 +1,78 @@
1
+ const fetch = require('node-fetch');
2
+ const utils = require('../lib/utils');
3
+ const SOURCE = 'f_AffiliatePort';
4
+
5
+ module.exports = {
6
+ /**
7
+ * Processed data comming from EventHub to data for further processing
8
+ * @param {Object} data The data comming from EventHub
9
+ * @returns {Object} Data for further processing
10
+ */
11
+ parse: function parse(data, context) {
12
+ // ConsumerBase.cs:ConsumeOneEventAsync
13
+ data.enqueuedAt = context.test ? 1600000000000 : Date.now();
14
+ return data;
15
+ },
16
+
17
+ /**
18
+ * Publishes data to AffiliatePort
19
+ * @param {{id: string, access_token: string}} config Publisher configuration
20
+ * @param {Object} data Data in publisher-friendly format to be published
21
+ * @param {string} event for which is it triggered
22
+ */
23
+ publish: async function publish(log, config, data, event) {
24
+ data = utils.removeUndefined(data);
25
+ const requestOptions: PlatformRequestOptions = {
26
+ method: 'GET',
27
+ };
28
+
29
+ for (let product of data.products) {
30
+ // https://tracking.affiliateclub.cz/aff_lsr?offer_id=OFFER_ID&adv_sub=TID_SUB_ID&amount=AMOUNT&transaction_id=TRANSACTION_ID&adv_sub2=CATEGORY&adv_sub3=MASTER_TYPE
31
+ const url =
32
+ 'https://tracking.affiliateclub.cz/aff_lsr?offer_id=' +
33
+ encodeURIComponent(config.offerId) +
34
+ '&adv_sub=TID_' +
35
+ data.orderId +
36
+ '&amount=' +
37
+ product.quantity * product.price +
38
+ '&transaction_id=' +
39
+ data.transactionID +
40
+ '&adv_sub2=' +
41
+ product.category +
42
+ '&adv_sub3=' +
43
+ product.masterType;
44
+
45
+ const resp = await fetch(url, reqOpts);
46
+
47
+ if (process.env.PUBLISHER_TESTURL) {
48
+ try {
49
+ utils.prepareTestRequestHeaders(reqOpts.headers, url, reqOpts, resp);
50
+ await fetch(process.env.PUBLISHER_TESTURL + query, reqOpts);
51
+ } catch {}
52
+ }
53
+
54
+ await utils.handleResponse(resp, event);
55
+
56
+ log(`AffiliatePort - ${event} - sent`);
57
+ }
58
+ },
59
+
60
+ /**
61
+ * Validates an object against given schema
62
+ * @param {Object} data An object to validate.
63
+ * @param {string} schema Name of the schema. That's name of a file with `.schema.json` extension in `customizable/schemas` subfolder of current publisher folder
64
+ * @returns {boolean} Validation result, true if successful, false if unsuccessfull (in which case more info is written to console)
65
+ */
66
+ validate: function validate(data, schema) {
67
+ if (!schema) {
68
+ throw new Error('Schema parameters not provided');
69
+ }
70
+ if (schema.includes('/')) {
71
+ throw new Error(
72
+ 'Schema must be provided as schema name, not schema path',
73
+ );
74
+ }
75
+ // More validation done by utils.validate
76
+ return utils.validate(data, SOURCE, schema);
77
+ },
78
+ };
@@ -6,24 +6,26 @@ module.exports = {
6
6
  /**
7
7
  * Processed data comming from EventHub to data for further processing
8
8
  * @param {Object} data The data comming from EventHub
9
+ * @param {FunctionContext} test Azure Function context.test
9
10
  * @returns {Object} Data for further processing
10
11
  */
11
- parse: function parse(data, context) {
12
+ parse: function parse(data, test) {
12
13
  //ConsumerBase.cs:ConsumeOneEventAsync
13
- data.enqueuedAt = context.test ? 1600000000000 : Date.now();
14
+ data.enqueuedAt = test ? 1600000000000 : Date.now();
14
15
  return data;
15
16
  },
16
17
 
17
18
  /**
18
19
  * Publishes data to Facebook
20
+ * @param {FunctionContext} log Azure Function context.log.warn
19
21
  * @param {{cid: string|number, type: string|number}} config Publisher configuration
20
22
  * @param {Object} data Data in publisher-friendly format to be published
21
23
  * @returns {*} Data returned by platform, if possible JSON-deserialized (otherwise as string)
22
24
  * @param {string} event for which is it triggered
23
25
  */
24
- publish: async function publish(config, data, event) {
26
+ publish: async function publish(log, config, data, event) {
25
27
  if(!data.cjevent){
26
- console.log(`CJ - ${event} - skipped because CJEVENT is missing`);
28
+ log(`CJ - ${event} - skipped because CJEVENT is missing`);
27
29
  return false;
28
30
  }
29
31
 
@@ -48,7 +50,7 @@ module.exports = {
48
50
 
49
51
  await utils.handleResponse(resp, event);
50
52
 
51
- console.log(`CJ - ${event} - sent`);
53
+ log(`CJ - ${event} - sent`);
52
54
  },
53
55
 
54
56
  /**
@@ -6,21 +6,23 @@ module.exports = {
6
6
  /**
7
7
  * Processed data comming from EventHub to data for further processing
8
8
  * @param {Object} data The data comming from EventHub
9
+ * @param {FunctionContext} test Azure Function context.test
9
10
  * @returns {Object} Data for further processing
10
11
  */
11
- parse: function parse(data, context) {
12
+ parse: function parse(data, test) {
12
13
  //ConsumerBase.cs:ConsumeOneEventAsync
13
- data.enqueuedAt = context.test ? 1600000000000 : Date.now();
14
+ data.enqueuedAt = test ? 1600000000000 : Date.now();
14
15
  return data;
15
16
  },
16
17
 
17
18
  /**
18
19
  * Publishes data to Facebook
20
+ * @param {FunctionContext} log Azure Function context.log.warn
19
21
  * @param {{id: string, access_token: string}} config Publisher configuration
20
22
  * @param {Object} data Data in publisher-friendly format to be published
21
23
  * @param {string} event for which is it triggered
22
24
  */
23
- publish: async function publish(config, data, event) {
25
+ publish: async function publish(log, config, data, event) {
24
26
  data = utils.removeUndefined(data);
25
27
  const reqOpts = {
26
28
  method: "post",
@@ -44,7 +46,7 @@ module.exports = {
44
46
 
45
47
  await utils.handleResponse(resp, event);
46
48
 
47
- console.log(`Facebook - ${event} - sent`);
49
+ log(`Facebook - ${event} - sent`);
48
50
  },
49
51
 
50
52
  /**
@@ -8,20 +8,22 @@ module.exports = {
8
8
  /**
9
9
  * Processed data comming from EventHub to data for further processing
10
10
  * @param {Object} data The data comming from EventHub
11
- * @returns {object} Data for further processing
11
+ * @param {FunctionContext} test Azure Function context.test
12
+ * @returns {Object} Data for further processing
12
13
  */
13
- parse: function parse(data, context) {
14
+ parse: function parse(data, test) {
14
15
  //ConsumerBase.cs:ConsumeOneEventAsync
15
- data.enqueuedAt = context.test ? 1600000000000 : Date.now();
16
+ data.enqueuedAt = test ? 1600000000000 : Date.now();
16
17
  return data;
17
18
  },
18
19
 
19
20
  /**
20
21
  * Publishes data to Google Analytics
22
+ * @param {FunctionContext} log Azure Function context.log.warn
21
23
  * @param {{tid: string}} config Publisher configuration
22
24
  * @param {{action: string, ti: string, [key:string]: string|number|boolean}} data Data in publisher-friendly format to be published
23
25
  */
24
- publish: async function publish(config, data, event) {
26
+ publish: async function publish(log, config, data, event) {
25
27
  data = utils.removeUndefined(data);
26
28
  data.v = 2;
27
29
  data.seg = 1;
@@ -52,11 +54,11 @@ module.exports = {
52
54
  utils.prepareTestRequestHeaders(reqOpts.headers, reqOpts.hostname + reqOpts.path , reqOpts);
53
55
  await fetch(process.env.PUBLISHER_TESTURL, reqOpts);
54
56
  } catch(exception) {
55
- console.log(exception);
57
+ warn(exception);
56
58
  }
57
59
  }
58
60
 
59
- console.log(`GoogleAnalytics4 - ${event} - sent`);
61
+ log(`GoogleAnalytics4 - ${event} - sent`);
60
62
  },
61
63
 
62
64
  /**
@@ -0,0 +1,64 @@
1
+ const fetch = require('node-fetch');
2
+ const utils = require("../lib/utils");
3
+ const SOURCE = "f_HttpPublisher";
4
+
5
+ module.exports = {
6
+ /**
7
+ * Processed data comming from EventHub to data for further processing
8
+ * @param {Object} data The data comming from EventHub
9
+ * @param {FunctionContext} test Azure Function context.test
10
+ * @returns {Object} Data for further processing
11
+ */
12
+ parse: function parse(data, test) {
13
+ //ConsumerBase.cs:ConsumeOneEventAsync
14
+ data.enqueuedAt = test ? 1600000000000 : Date.now();
15
+ return data;
16
+ },
17
+
18
+ /**
19
+ * Publishes data to provided URL
20
+ * @param {FunctionContext} log Azure Function context.log.warn
21
+ * @param {string} event Required: event for which is it triggered
22
+ * @param {string} url Required: Request URL with query parameters
23
+ * @param {string} platform Required: Name of the plaform to which request is sent
24
+ * @param {string} method Required: Request method - GET|POST|PUT...
25
+ * @param {Object} headers Optional: Object of request headers
26
+ * @param {Object} body Optional: Non-strigifed request body object
27
+ *
28
+ */
29
+ publish: async function publish(log, event, platform, url, method, headers = {}, body = {}) {
30
+ const reqOpts = {
31
+ method: method,
32
+ headers: headers
33
+ };
34
+ if(method == "POST"){
35
+ reqOpts.body = JSON.stringify(body);
36
+ }
37
+
38
+ const resp = await fetch(url, reqOpts);
39
+
40
+ if (process.env.PUBLISHER_TESTURL) {
41
+ try {
42
+ utils.prepareTestRequestHeaders(reqOpts.headers, url, reqOpts, resp);
43
+ await fetch(process.env.PUBLISHER_TESTURL, reqOpts);
44
+ } catch { }
45
+ }
46
+
47
+ await utils.handleResponse(resp, event);
48
+
49
+ log(`${platform} - ${event} - sent`);
50
+ },
51
+
52
+ /**
53
+ * Validates an object against given schema
54
+ * @param {Object} data An object to validate.
55
+ * @param {string} schema Name of the schema. That's name of a file with `.schema.json` extension in `customizable/schemas` subfolder of current publisher folder
56
+ * @returns {boolean} Validation result, true if successful, false if unsuccessfull (in which case more info is written to console)
57
+ */
58
+ validate: function validate(data, schema) {
59
+ if (!schema) throw new Error("Schema parameters not provided");
60
+ if (schema.indexOf("/") >= 0) throw new Error("Schema must be provided as schema name, not schema path");
61
+ //More validation done by utils.validate
62
+ return utils.validate(data, SOURCE, schema);
63
+ }
64
+ };
@@ -6,22 +6,24 @@ module.exports = {
6
6
  /**
7
7
  * Processed data comming from EventHub to data for further processing
8
8
  * @param {Object} data The data comming from EventHub
9
+ * @param {FunctionContext} test Azure Function context.test
9
10
  * @returns {Object} Data for further processing
10
11
  */
11
- parse: function parse(data, context) {
12
+ parse: function parse(data, test) {
12
13
  //ConsumerBase.cs:ConsumeOneEventAsync
13
- data.enqueuedAt = context.test ? 1600000000000 : Date.now();
14
+ data.enqueuedAt = test ? 1600000000000 : Date.now();
14
15
  return data;
15
16
  },
16
17
 
17
18
  /**
18
19
  * Publishes data to Piano
20
+ * @param {FunctionContext} log Azure Function context.log.warn
19
21
  * @param {{collectionDomain: string, siteId: string|number}} config Publisher configuration
20
22
  * @param {{pianoData: {events: {name: string, data: {[key: string]: any}}[]}, aux: {visitorId: string, ref: string, userAgent?: string, referer?: string, forwardedFor?: string}}} data Data in publisher-friendly format to be published
21
23
  * @returns {*} Data returned by platform, if possible JSON-deserialized (otherwise as string)
22
24
  * @param {string} event for which is it triggered
23
25
  */
24
- publish: async function publish(config, data, event) {
26
+ publish: async function publish(log, config, data, event) {
25
27
  data = utils.removeUndefined(data);
26
28
  let dt = "";
27
29
  //https://developers.atinternet-solutions.com/piano-analytics-tagging-en/event-tagging-piano-analytics-en/events-pattern-en/#post-request_5
@@ -48,7 +50,7 @@ module.exports = {
48
50
 
49
51
  await utils.handleResponse(resp, event);
50
52
 
51
- console.log(`Piano Analytics - ${event} - sent`);
53
+ log(`Piano Analytics - ${event} - sent`);
52
54
  },
53
55
 
54
56
  /**
@@ -8,20 +8,22 @@ module.exports = {
8
8
  /**
9
9
  * Processed data comming from EventHub to data for further processing
10
10
  * @param {Object} data The data comming from EventHub
11
- * @returns {object} Data for further processing
11
+ * @param {FunctionContext} test Azure Function context.test
12
+ * @returns {Object} Data for further processing
12
13
  */
13
- parse: function parse(data, context) {
14
+ parse: function parse(data, test) {
14
15
  //ConsumerBase.cs:ConsumeOneEventAsync
15
- data.enqueuedAt = context.test ? 1600000000000 : Date.now();
16
+ data.enqueuedAt = test ? 1600000000000 : Date.now();
16
17
  return data;
17
18
  },
18
19
 
19
20
  /**
20
21
  * Publishes data to Google Analytics
22
+ * @param {FunctionContext} log Azure Function context.log.warn
21
23
  * @param {{tid: string}} config Publisher configuration
22
24
  * @param {{action: string, ti: string, [key:string]: string|number|boolean}} data Data in publisher-friendly format to be published
23
25
  */
24
- publish: async function publish(config, data, event) {
26
+ publish: async function publish(log, config, data, event) {
25
27
  data = utils.removeUndefined(data);
26
28
  //https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide#event
27
29
  const url = "https://www.google-analytics.com/collect";
@@ -55,7 +57,7 @@ module.exports = {
55
57
 
56
58
  await utils.handleResponse(resp);
57
59
 
58
- console.log(`Universal Analytics - ${event} - sent`);
60
+ log(`Universal Analytics - ${event} - sent`);
59
61
  },
60
62
 
61
63
  /**
package/package.json CHANGED
@@ -1,29 +1,46 @@
1
- {
2
- "name": "@mhubcloud/tms_core",
3
- "version": "1.7.6",
4
- "description": "Core function for mHub Cloud TMS publishers",
5
- "homepage": "https://mhubcloud.com/",
6
- "license": "Apache 2.0",
7
- "email": "info@crossmasters.com",
8
- "author": "Jan Brzobohatý",
9
- "main": "index.js",
10
- "keywords": [
11
- "mHub Cloud",
12
- "TMS",
13
- "tag management system",
14
- "backend measurement",
15
- "server side measurement",
16
- "conversion API"
17
- ],
18
- "scripts": {
19
- "test": "mocha ./tests/*.js --timeout 10000 "
20
- },
21
- "dependencies": {
22
- "ajv": "^8.8.2",
23
- "applicationinsights": "^2.2.0",
24
- "node-fetch": "^2.6.7"
25
- },
26
- "devDependencies": {
27
- "mocha": "^10.0.0"
28
- }
29
- }
1
+ {
2
+ "name": "@mhubcloud/tms_core",
3
+ "version": "2.0.0-beta.0",
4
+ "description": "Core function for mHub Cloud TMS publishers",
5
+ "homepage": "https://mhubcloud.com/",
6
+ "license": "Apache 2.0",
7
+ "email": "info@crossmasters.com",
8
+ "author": "Jan Brzobohatý",
9
+ "main": "index.js",
10
+ "keywords": [
11
+ "mHub Cloud",
12
+ "TMS",
13
+ "tag management system",
14
+ "backend measurement",
15
+ "server side measurement",
16
+ "conversion API"
17
+ ],
18
+ "dependencies": {
19
+ "ajv": "^8.12.0",
20
+ "applicationinsights": "^2.6.0",
21
+ "node-fetch": "^2.6.11"
22
+ },
23
+ "devDependencies": {
24
+ "@azure/functions": "^3.5.1",
25
+ "@tsconfig/recommended": "^1.0.2",
26
+ "@types/node": "^18.16.14",
27
+ "@types/node-fetch": "^2.6.4",
28
+ "@typescript-eslint/eslint-plugin": "^5.59.7",
29
+ "@typescript-eslint/parser": "^5.59.7",
30
+ "eslint": "^8.41.0",
31
+ "eslint-config-prettier": "^8.8.0",
32
+ "eslint-import-resolver-typescript": "^3.5.5",
33
+ "eslint-plugin-import": "^2.27.5",
34
+ "eslint-plugin-prettier": "^4.2.1",
35
+ "mocha": "^10.2.0",
36
+ "prettier": "^2.8.8",
37
+ "ts-node": "^10.9.1",
38
+ "tsup": "^6.7.0",
39
+ "typescript": "^4.9.5"
40
+ },
41
+ "scripts": {
42
+ "dev": "ts-node index.ts",
43
+ "build": "tsup ./src/index.ts --format cjs --target node18",
44
+ "test": "mocha ./tests/*.js --timeout 10000 "
45
+ }
46
+ }
package/releasePlan.md ADDED
@@ -0,0 +1,3 @@
1
+ To test after release:
2
+ - Zkontrolovat event_time posílaný do FB, že chodí ve správném formátu a že obsahuje správný údaj.
3
+ - Když použiju utils.log tak to do appinsights zaloguje dvakrát? Máme totiž podezření, že ano.
@@ -0,0 +1,132 @@
1
+ import { Context, Logger } from '@azure/functions';
2
+ import { Telemetry } from 'applicationinsights/out/Declarations/Contracts';
3
+ import { EventHubMessage } from './types/EventHubMessage';
4
+ import { EventPublisher } from './types/EventPublisher';
5
+ import { PlatformPublisher } from './types/PlatformPublisher';
6
+ import { TypeSafeObject } from './types/UtilTypes';
7
+ import * as utils from './utils/utils';
8
+
9
+ /**
10
+ * Implements the Azure Function, called for set of events received via Event Hub
11
+ * @deprecated Udelat novou metodu, ktera bude spravne a bude inicializovat classu
12
+ * @param azureFunctionContext Azure Function Context
13
+ * @param eventHubMessages Array of messages received from Event Hub
14
+ * @param source Name of the publisher (it's folder name in which it's implemented)
15
+ * @param platformPublisher Publisher implementation instance (from <publisher>/publisher.js)
16
+ * @param trigger
17
+ */
18
+ export async function defaultPublisher(
19
+ azureFunctionContext: Context,
20
+ eventHubMessages: EventHubMessage[],
21
+ source: string,
22
+ platformPublisher: PlatformPublisher,
23
+ trigger: (a: unknown) => EventPublisher[],
24
+ ) {
25
+ const processMessagePromises = [];
26
+ for (const message of eventHubMessages) {
27
+ processMessagePromises.push(
28
+ processMessage(
29
+ message,
30
+ azureFunctionContext.log,
31
+ platformPublisher,
32
+ trigger,
33
+ ),
34
+ );
35
+ }
36
+ const results = await Promise.allSettled(processMessagePromises);
37
+ // ? musi nahoru probublat, ze aspon neco selhalo a to je to, co bude triggerovat nasledujici error. Error pro konkretniho publishera musi byt primo v processMessage v loopu. Hodnotu pro typ publishera vezmeme z platformBublisher.SOURCE
38
+ for (const result of results) {
39
+ if (result.status === 'rejected') {
40
+ utils.logException(
41
+ azureFunctionContext.log,
42
+ new Error(result.reason as Error['message']),
43
+ );
44
+ }
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Processes single message from EventHub
50
+ * @param message A message received from EventHub
51
+ * @param log Azure Function context.log
52
+ * @param source Name of the publisher (it's folder name in which it's implemented)
53
+ * @param platfromPublisher Publisher implementation instance (from <publisher>/publisher.js)
54
+ * @param trigger Publisher-specific trigger function (from <publisher>/customizable/trigger.js)
55
+ * @returns Returns false if at least one publisher failed or in case of other failed requirements
56
+ */
57
+ async function processMessage(
58
+ message: EventHubMessage,
59
+ log: Logger,
60
+ platfromPublisher: PlatformPublisher,
61
+ trigger: (a: object) => EventPublisher[],
62
+ ) {
63
+ // TODO Je potreba otestovat, ze se to nerozbije, kdyz jsme prestali prepisovat enqueuedAt na Date.now()
64
+ const logProperties: Telemetry['properties'] = {
65
+ source: platfromPublisher.source,
66
+ data: JSON.stringify(message),
67
+ };
68
+ const publishers = trigger(message);
69
+ if (!publishers.length) {
70
+ utils.log(
71
+ log,
72
+ 1,
73
+ 'Message excluded by filter (no publishers determined)',
74
+ logProperties,
75
+ );
76
+ return false;
77
+ }
78
+ let publishedAny = false;
79
+ let failedToPublishAll = false;
80
+ for (const eventPublisher of publishers) {
81
+ const mapped = await eventPublisher.map(message);
82
+
83
+ const res = await publishMessage(
84
+ log,
85
+ mapped,
86
+ eventPublisher.config,
87
+ platfromPublisher,
88
+ message.event.code + (message.event.name ? '/' + message.event.name : ''),
89
+ );
90
+ if (res) {
91
+ publishedAny = true;
92
+ } else {
93
+ utils.logException(
94
+ log,
95
+ new Error(
96
+ `The message has not been published. Source: ${platfromPublisher.source}`,
97
+ ),
98
+ );
99
+ failedToPublishAll = true;
100
+ }
101
+ }
102
+ if (!publishedAny) {
103
+ utils.logException(
104
+ log,
105
+ new Error(
106
+ 'The message has not been published to any publisher configuration',
107
+ ),
108
+ );
109
+ return false;
110
+ }
111
+ // Returns false
112
+ return !failedToPublishAll;
113
+ }
114
+
115
+ /**
116
+ * Publishes a message to configured publisher
117
+ * @param log Azure Function context.log
118
+ * @param mapped Mapped message data
119
+ * @param config Platform-specific platform publisher configuration
120
+ * @param platformPublisher Publisher implementation instance (from <publisher>/publisher.js)
121
+ * @param event Event for which logic was triggered
122
+ */
123
+ async function publishMessage(
124
+ log: Logger,
125
+ mapped: TypeSafeObject,
126
+ config: TypeSafeObject,
127
+ platformPublisher: PlatformPublisher,
128
+ event: string,
129
+ ) {
130
+ await platformPublisher.publish(log, config, mapped, event);
131
+ return true;
132
+ }
package/src/index.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { defaultPublisher } from './defaultPublisher';
2
+ import { affiliatePort } from './publishers/affiliatePort';
3
+ import { cj } from './publishers/cj';
4
+ import { facebook } from './publishers/facebook';
5
+ import { googleAnalytics4 } from './publishers/googleAnalytics4';
6
+ import { piano } from './publishers/piano';
7
+ import { universalAnalytics } from './publishers/universalAnalytics';
8
+ import * as utils from './utils/utils';
9
+
10
+ export const publisher = {
11
+ // eslint-disable-next-line @typescript-eslint/naming-convention
12
+ Facebook: facebook,
13
+ // eslint-disable-next-line @typescript-eslint/naming-convention
14
+ CJ: cj,
15
+ // eslint-disable-next-line @typescript-eslint/naming-convention
16
+ GoogleAnalytics4: googleAnalytics4,
17
+ // eslint-disable-next-line @typescript-eslint/naming-convention
18
+ UniversalAnalytics: universalAnalytics,
19
+ // eslint-disable-next-line @typescript-eslint/naming-convention
20
+ Piano: piano,
21
+ // eslint-disable-next-line @typescript-eslint/naming-convention
22
+ AffiliatePort: affiliatePort,
23
+ };
24
+
25
+ export { utils, defaultPublisher as DefaultPublisher };
@@ -0,0 +1,69 @@
1
+ import * as utils from './../utils/utils';
2
+ import {
3
+ PlatformPublisher,
4
+ PlatformRequestOptions,
5
+ } from '../types/PlatformPublisher';
6
+
7
+ interface Product {
8
+ orderId: string;
9
+ quantity: number;
10
+ price: number;
11
+ category: string;
12
+ masterType: string;
13
+ }
14
+
15
+ interface AffiliatePortData {
16
+ products: Product[];
17
+ orderId: string;
18
+ transactionID: string;
19
+ [x: string]: unknown;
20
+ }
21
+
22
+ export const affiliatePort: PlatformPublisher = {
23
+ source: 'AffiliatePort',
24
+ /**
25
+ * Publishes data to AffiliatePort
26
+ * @param log zure Function context.log
27
+ * @param config Publisher configuration
28
+ * @param data Data in publisher-friendly format to be published
29
+ * @param event Event for which the function is triggered
30
+ */
31
+ async publish(log, config, data, event) {
32
+ if (
33
+ (data as AffiliatePortData).products instanceof Array &&
34
+ (typeof config.offerId === 'string' || typeof config.offerId === 'number')
35
+ ) {
36
+ const affiliatePortData = utils.removeUndefined(
37
+ data,
38
+ ) as AffiliatePortData;
39
+
40
+ const requestOptions: PlatformRequestOptions = {
41
+ method: 'GET',
42
+ };
43
+
44
+ const baseUrl = 'https://tracking.affiliateclub.cz/aff_lsr';
45
+
46
+ for (const product of affiliatePortData.products) {
47
+ // https://tracking.affiliateclub.cz/aff_lsr?offer_id=OFFER_ID&adv_sub=TID_SUB_ID&amount=AMOUNT&transaction_id=TRANSACTION_ID&adv_sub2=CATEGORY&adv_sub3=MASTER_TYPE
48
+ const query = `?offer_id=${encodeURIComponent(
49
+ config.offerId,
50
+ )}&adv_sub=TID_${affiliatePortData.orderId}&amount=${
51
+ product.quantity * product.price
52
+ }&transaction_id=${affiliatePortData.transactionID}&adv_sub2=${
53
+ product.category
54
+ }&adv_sub3=${product.masterType}`;
55
+
56
+ await utils.handlePlatformRequest({
57
+ source: this.source,
58
+ baseUrl,
59
+ query,
60
+ requestOptions,
61
+ event,
62
+ logger: log,
63
+ });
64
+ }
65
+ } else {
66
+ throw new Error('Invalid config for platform ' + this.source);
67
+ }
68
+ },
69
+ };