@mhubcloud/tms_core 3.6.0-beta.1 → 3.7.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 (2) hide show
  1. package/dist/index.js +191 -14
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -43,7 +43,8 @@ var broker_exports = {};
43
43
  __export(broker_exports, {
44
44
  dispatchEvent: () => dispatchEvent,
45
45
  logToCosmosDb: () => logToCosmosDb,
46
- resolveEvent: () => resolveEvent
46
+ resolveEvent: () => resolveEvent,
47
+ scheduleEvent: () => scheduleEvent
47
48
  });
48
49
  var import_cosmos = require("@azure/cosmos");
49
50
  var import_service_bus = require("@azure/service-bus");
@@ -105,7 +106,19 @@ function logMessage(level, message, properties) {
105
106
  function logEvent(publisher2, event, region, status, payload, id) {
106
107
  let message = "";
107
108
  if (status || status === 0) {
108
- message = status >= 200 && status < 300 ? "Event dispatched to platform" : "Event dispatch failed";
109
+ if (status >= 200 && status < 300) {
110
+ aiClient?.trackMetric({
111
+ name: `Dispatched/${publisher2}-${event}-${region}`,
112
+ value: 1
113
+ });
114
+ message = "Event dispatched to platform";
115
+ } else {
116
+ aiClient?.trackMetric({
117
+ name: `Failed/${publisher2}-${event}-${region}`,
118
+ value: 1
119
+ });
120
+ message = "Event dispatch failed";
121
+ }
109
122
  } else {
110
123
  message = "Event dispatched to platform";
111
124
  }
@@ -275,7 +288,7 @@ async function handlePlatformRequest({
275
288
  event.event,
276
289
  event.region,
277
290
  0,
278
- requestOptions.body ? JSON.stringify(requestOptions.body) : void 0,
291
+ requestOptions.method === "POST" ? JSON.stringify(requestOptions.body) : query,
279
292
  event.id
280
293
  );
281
294
  throw e;
@@ -294,7 +307,7 @@ async function handlePlatformRequest({
294
307
  event.event,
295
308
  event.region,
296
309
  rawPlatformResponse.status,
297
- requestOptions.body ? JSON.stringify(requestOptions.body) : void 0,
310
+ requestOptions.method === "POST" ? JSON.stringify(requestOptions.body) : query,
298
311
  event.id
299
312
  );
300
313
  if (!rawPlatformResponse.ok) {
@@ -458,6 +471,66 @@ async function logToCosmosDb(message) {
458
471
  logException(e);
459
472
  }
460
473
  }
474
+ async function scheduleEvent(message, queue, options) {
475
+ if (!serviceBusClient) {
476
+ if (!serviceBusConnectionString) {
477
+ throw new Error("Service Bus connection string is missing.");
478
+ }
479
+ serviceBusClient = new import_service_bus.ServiceBusClient(serviceBusConnectionString);
480
+ }
481
+ try {
482
+ let sender;
483
+ if (senders[queue]) {
484
+ sender = senders[queue];
485
+ } else {
486
+ senders[queue] = serviceBusClient.createSender(queue);
487
+ sender = senders[queue];
488
+ }
489
+ let dispatchTime;
490
+ const now = /* @__PURE__ */ new Date();
491
+ if ("timestamp" in options) {
492
+ dispatchTime = new Date(options.timestamp);
493
+ } else if ("scheduleHour" in options) {
494
+ dispatchTime = new Date(
495
+ now.getFullYear(),
496
+ now.getMonth(),
497
+ now.getDate() + (options.dayOffset ?? 0),
498
+ options.scheduleHour,
499
+ options.scheduleMinute ?? 0,
500
+ 0,
501
+ 0
502
+ );
503
+ } else if ("scheduleInterval" in options && "startHour" in options) {
504
+ const hour = now.getHours();
505
+ const nextHour = Math.ceil(hour / options.scheduleInterval) * options.scheduleInterval;
506
+ dispatchTime = new Date(
507
+ now.getFullYear(),
508
+ now.getMonth(),
509
+ now.getDate() + (options.dayOffset ?? 0),
510
+ nextHour,
511
+ options.startMinute ?? 0,
512
+ 0,
513
+ 0
514
+ );
515
+ if (nextHour >= 24) {
516
+ dispatchTime.setDate(dispatchTime.getDate() + 1);
517
+ dispatchTime.setHours(options.startHour, options.startMinute);
518
+ }
519
+ } else {
520
+ throw new Error("Invalid scheduling configuration");
521
+ }
522
+ const serviceBusMessage = {
523
+ body: message,
524
+ scheduledEnqueueTimeUtc: dispatchTime
525
+ };
526
+ await sender.sendMessages(serviceBusMessage);
527
+ return dispatchTime;
528
+ } catch (e) {
529
+ console.log(
530
+ `Scheduling message to queue ${queue} failed. Cause: ${e instanceof Error ? e.message : ""}`
531
+ );
532
+ }
533
+ }
461
534
 
462
535
  // src/defaultPublisher.ts
463
536
  async function defaultPublisher(azureFunctionContext, serviceBusMessage, source, platformPublisher, trigger) {
@@ -839,6 +912,114 @@ var googleAnalytics4 = {
839
912
  }
840
913
  };
841
914
 
915
+ // src/publishers/microsoftAds.ts
916
+ var tokenCache2;
917
+ var tokenPromise2;
918
+ var microsoftAds = {
919
+ source: "MicrosoftAds",
920
+ /**
921
+ *Publishes data to Microsoft Ads
922
+ * @param log Azure Function context.log
923
+ * @param config Publisher configuration
924
+ * @param data Data in publisher-friendly format to be published
925
+ * @param event Event for which the function is triggered
926
+ */
927
+ async publish(log2, config, data, event) {
928
+ if (typeof config.customerAccountId === "string" && typeof config.customerId === "string" && typeof config.developerToken === "string") {
929
+ if (!(data.ConversionName || data.ConversionTime || data.MicrosoftClickId)) {
930
+ logMessage(
931
+ 1,
932
+ `MicrosoftAds: excluded ${event.event} as one or more mandatory parameters were missing`
933
+ );
934
+ return;
935
+ }
936
+ const { token } = await this.getToken(config);
937
+ const body = {
938
+ // eslint-disable-next-line @typescript-eslint/naming-convention
939
+ OfflineConversions: [data]
940
+ };
941
+ const requestOptions = {
942
+ method: "POST",
943
+ body: JSON.stringify(body),
944
+ headers: {
945
+ /* eslint-disable @typescript-eslint/naming-convention */
946
+ Authorization: `Bearer ${token}`,
947
+ CustomerAccountId: config.customerAccountId,
948
+ CustomerId: config.customerId,
949
+ DeveloperToken: config.developerToken,
950
+ "Content-Type": "application/json"
951
+ /* eslint-enable */
952
+ }
953
+ };
954
+ const baseUrl = "https://campaign.api.bingads.microsoft.com/CampaignManagement/v13/OfflineConversions/Apply";
955
+ const response = await fetch(baseUrl, requestOptions);
956
+ const responseJson = await response.json();
957
+ let status = 0;
958
+ let error;
959
+ if (responseJson.PartialErrors || responseJson.Errors) {
960
+ const apiErrors = responseJson.Errors ?? responseJson.PartialErrors ?? [];
961
+ status = 500;
962
+ const message = apiErrors.reduce((acc, curr) => {
963
+ acc += curr.Message + " ";
964
+ return acc;
965
+ }, "Microsoft Ads: Error(s) processing event: ");
966
+ error = message;
967
+ } else {
968
+ status = 200;
969
+ }
970
+ logEvent(
971
+ this.source,
972
+ event.event,
973
+ event.region,
974
+ status,
975
+ requestOptions.body,
976
+ event.id
977
+ );
978
+ if (error) {
979
+ throw new Error(error);
980
+ }
981
+ } else {
982
+ throw new Error("Invalid config for platform " + this.source);
983
+ }
984
+ },
985
+ async getToken(config) {
986
+ if (tokenCache2 && tokenCache2.createdAt + 3500 * 1e3 > Date.now()) {
987
+ return tokenCache2;
988
+ }
989
+ if (!tokenPromise2) {
990
+ tokenPromise2 = (async () => {
991
+ const tokenResponse = await fetch(
992
+ `https://login.microsoftonline.com/${config.tenantId}/oauth2/v2.0/token`,
993
+ {
994
+ method: "POST",
995
+ /* eslint-disable @typescript-eslint/naming-convention */
996
+ headers: {
997
+ "Content-Type": "application/x-www-form-urlencoded"
998
+ },
999
+ body: new URLSearchParams({
1000
+ client_id: config.client.id,
1001
+ client_secret: config.client.secret,
1002
+ refresh_token: config.refreshToken,
1003
+ grant_type: "refresh_token",
1004
+ scope: "https://ads.microsoft.com/msads.manage"
1005
+ })
1006
+ /* eslint-enable */
1007
+ }
1008
+ );
1009
+ if (!tokenResponse.ok) {
1010
+ throw new Error("Access token fetch failed");
1011
+ }
1012
+ const parsedTokenResponse = await tokenResponse.json();
1013
+ const createdAt = Date.now();
1014
+ tokenCache2 = { token: parsedTokenResponse.access_token, createdAt };
1015
+ tokenPromise2 = null;
1016
+ return tokenCache2;
1017
+ })();
1018
+ }
1019
+ return tokenPromise2;
1020
+ }
1021
+ };
1022
+
842
1023
  // src/publishers/piano.ts
843
1024
  var piano = {
844
1025
  source: "Piano",
@@ -951,20 +1132,16 @@ context.log.warn = function warn(str) {
951
1132
 
952
1133
  // src/index.ts
953
1134
  var publisher = {
954
- // eslint-disable-next-line @typescript-eslint/naming-convention
955
- Facebook: facebook,
956
- // eslint-disable-next-line @typescript-eslint/naming-convention
1135
+ /* eslint-disable @typescript-eslint/naming-convention */
1136
+ AffiliatePort: affiliatePort,
957
1137
  CJ: cj,
958
- // eslint-disable-next-line @typescript-eslint/naming-convention
1138
+ Facebook: facebook,
959
1139
  GoogleAds: googleAds,
960
- // eslint-disable-next-line @typescript-eslint/naming-convention
961
1140
  GoogleAnalytics4: googleAnalytics4,
962
- // eslint-disable-next-line @typescript-eslint/naming-convention
963
- UniversalAnalytics: universalAnalytics,
964
- // eslint-disable-next-line @typescript-eslint/naming-convention
1141
+ MicrosoftAds: microsoftAds,
965
1142
  Piano: piano,
966
- // eslint-disable-next-line @typescript-eslint/naming-convention
967
- AffiliatePort: affiliatePort
1143
+ UniversalAnalytics: universalAnalytics
1144
+ /* eslint-enable */
968
1145
  };
969
1146
  // Annotate the CommonJS export names for ESM import in node:
970
1147
  0 && (module.exports = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhubcloud/tms_core",
3
- "version": "3.6.0-beta.1",
3
+ "version": "3.7.0-beta.0",
4
4
  "description": "Core function for mHub Cloud TMS publishers",
5
5
  "homepage": "https://mhubcloud.com/",
6
6
  "license": "Apache 2.0",
@@ -21,7 +21,7 @@
21
21
  "build": "tsup ./src/index.ts --format cjs --target node22"
22
22
  },
23
23
  "dependencies": {
24
- "@azure/cosmos": "^4.4.1",
24
+ "@azure/cosmos": "^4.7.0",
25
25
  "@azure/data-tables": "^13.2.2",
26
26
  "@azure/service-bus": "^7.9.5",
27
27
  "ajv": "^8.12.0",