@meltwater/conversations-api-services 1.2.1 → 1.2.2

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.
@@ -565,6 +565,84 @@ async function retweetWithComment(token, text, attachment, logger) {
565
565
  let query = 'https://api.twitter.com/2/tweets';
566
566
  return publishTweet(token, payload, query, false, logger);
567
567
  }
568
+
569
+ /**
570
+ * Normalizes Twitter API responses to ensure consistent structure across v1.1 and v2
571
+ * This is critical for backward compatibility - consumers expect certain fields to exist
572
+ *
573
+ * @param {Object} response - The response object to normalize
574
+ * @param {string} responseType - Type of response: 'dm' for direct messages, 'tweet' for tweets
575
+ * @param {Object} logger - Logger instance for debugging
576
+ * @param {Object} fullResponse - Full API response including includes (for extracting author_id from expansions)
577
+ * @returns {Object} Normalized response with consistent field structure
578
+ */
579
+ function normalizeTwitterResponse(response, responseType, logger) {
580
+ let fullResponse = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
581
+ if (!response || !response.data) {
582
+ return response;
583
+ }
584
+ (0, _loggerHelpers.loggerDebug)(logger, `Normalizing Twitter API response (${responseType})`, {
585
+ beforeNormalization: JSON.stringify(response.data)
586
+ });
587
+
588
+ // Handle Twitter API v2 Direct Message responses
589
+ // v2 DM structure: { dm_event_id, dm_conversation_id }
590
+ // v1.1 expected structure: { id, author_id }
591
+ if (responseType === 'dm' && response.data.dm_event_id) {
592
+ const normalizedData = {
593
+ ...response.data,
594
+ // Add v1.1-compatible fields for backward compatibility
595
+ id: response.data.dm_event_id,
596
+ // Note: author_id is intentionally not set here. The caller (twitterApi.client.js)
597
+ // will set the correct author_id from the original document since dm_conversation_id
598
+ // doesn't reliably indicate the sender (it's just "user1-user2" format)
599
+ author_id: null
600
+ };
601
+ (0, _loggerHelpers.loggerInfo)(logger, `Normalized Twitter API v2 DM response to v1.1 format`, {
602
+ dm_event_id: response.data.dm_event_id,
603
+ normalized_id: normalizedData.id,
604
+ dm_conversation_id: response.data.dm_conversation_id,
605
+ normalized_author_id: normalizedData.author_id
606
+ });
607
+ return {
608
+ ...response,
609
+ data: normalizedData
610
+ };
611
+ }
612
+
613
+ // Handle Twitter API v2 Tweet responses
614
+ // v2 has 'id' field but author_id is in expansions (includes.users)
615
+ if (responseType === 'tweet' && response.data.id) {
616
+ const normalizedData = {
617
+ ...response.data
618
+ };
619
+
620
+ // If author_id is missing but we have includes.users from expansions
621
+ if (!normalizedData.author_id && fullResponse?.includes?.users?.[0]?.id) {
622
+ normalizedData.author_id = fullResponse.includes.users[0].id;
623
+ (0, _loggerHelpers.loggerInfo)(logger, `Added author_id to tweet response from expansions`, {
624
+ tweet_id: normalizedData.id,
625
+ author_id: normalizedData.author_id
626
+ });
627
+ } else if (normalizedData.author_id) {
628
+ (0, _loggerHelpers.loggerDebug)(logger, `Twitter v2 tweet response already has 'author_id'`, {
629
+ id: response.data.id,
630
+ author_id: normalizedData.author_id
631
+ });
632
+ } else {
633
+ (0, _loggerHelpers.loggerWarn)(logger, `Twitter v2 tweet response missing author_id and no expansions available`, {
634
+ id: response.data.id,
635
+ hasIncludes: !!fullResponse?.includes,
636
+ hasUsers: !!fullResponse?.includes?.users
637
+ });
638
+ }
639
+ return {
640
+ ...response,
641
+ data: normalizedData
642
+ };
643
+ }
644
+ return response;
645
+ }
568
646
  async function publishTweet(token, payload, query, isDirectMessage, logger) {
569
647
  try {
570
648
  let nativeResponse = await postRequest({
@@ -599,7 +677,12 @@ async function publishTweet(token, payload, query, isDirectMessage, logger) {
599
677
  (0, _loggerHelpers.loggerDebug)(logger, `Twitter the data response is`, {
600
678
  response: JSON.stringify(response)
601
679
  });
602
- return response;
680
+
681
+ // Normalize the response to ensure backward compatibility with v1.1 structure
682
+ // Pass full nativeResponse to extract author_id from expansions if needed
683
+ const normalizedResponse = normalizeTwitterResponse(response, 'tweet', logger, nativeResponse.data // Full response with includes.users for author_id
684
+ );
685
+ return normalizedResponse;
603
686
  } catch (err) {
604
687
  (0, _loggerHelpers.loggerError)(logger, `Twitter publish exception details`, err);
605
688
  throw err;
@@ -628,7 +711,11 @@ async function publishDirectMessage(token, payload, query, logger) {
628
711
  (0, _loggerHelpers.loggerDebug)(logger, `Twitter DM response is`, {
629
712
  response: JSON.stringify(response)
630
713
  });
631
- return response;
714
+
715
+ // Normalize the response to ensure backward compatibility with v1.1 structure
716
+ // This is CRITICAL - v2 DM responses have dm_event_id instead of id
717
+ const normalizedResponse = normalizeTwitterResponse(response, 'dm', logger);
718
+ return normalizedResponse;
632
719
  } catch (err) {
633
720
  (0, _loggerHelpers.loggerError)(logger, `Twitter DM exception details`, err);
634
721
  throw err;
@@ -31,8 +31,7 @@ var TwitterNative = _interopRequireWildcard(require("./http/twitter.native.js"))
31
31
  var InstagramNative = _interopRequireWildcard(require("./http/instagram.native.js"));
32
32
  var ThreadsNative = _interopRequireWildcard(require("./http/threads.native.js"));
33
33
  var AssetManagerClient = _interopRequireWildcard(require("./http/assetManager.client.js"));
34
- function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
35
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
34
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
36
35
  const DocumentHelperFunctions = {
37
36
  ...messageHelpers,
38
37
  ...applicationTagFunctions,
@@ -541,6 +541,84 @@ export async function retweetWithComment(token, text, attachment, logger) {
541
541
  let query = 'https://api.twitter.com/2/tweets';
542
542
  return publishTweet(token, payload, query, false, logger);
543
543
  }
544
+
545
+ /**
546
+ * Normalizes Twitter API responses to ensure consistent structure across v1.1 and v2
547
+ * This is critical for backward compatibility - consumers expect certain fields to exist
548
+ *
549
+ * @param {Object} response - The response object to normalize
550
+ * @param {string} responseType - Type of response: 'dm' for direct messages, 'tweet' for tweets
551
+ * @param {Object} logger - Logger instance for debugging
552
+ * @param {Object} fullResponse - Full API response including includes (for extracting author_id from expansions)
553
+ * @returns {Object} Normalized response with consistent field structure
554
+ */
555
+ function normalizeTwitterResponse(response, responseType, logger) {
556
+ let fullResponse = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
557
+ if (!response || !response.data) {
558
+ return response;
559
+ }
560
+ loggerDebug(logger, `Normalizing Twitter API response (${responseType})`, {
561
+ beforeNormalization: JSON.stringify(response.data)
562
+ });
563
+
564
+ // Handle Twitter API v2 Direct Message responses
565
+ // v2 DM structure: { dm_event_id, dm_conversation_id }
566
+ // v1.1 expected structure: { id, author_id }
567
+ if (responseType === 'dm' && response.data.dm_event_id) {
568
+ const normalizedData = {
569
+ ...response.data,
570
+ // Add v1.1-compatible fields for backward compatibility
571
+ id: response.data.dm_event_id,
572
+ // Note: author_id is intentionally not set here. The caller (twitterApi.client.js)
573
+ // will set the correct author_id from the original document since dm_conversation_id
574
+ // doesn't reliably indicate the sender (it's just "user1-user2" format)
575
+ author_id: null
576
+ };
577
+ loggerInfo(logger, `Normalized Twitter API v2 DM response to v1.1 format`, {
578
+ dm_event_id: response.data.dm_event_id,
579
+ normalized_id: normalizedData.id,
580
+ dm_conversation_id: response.data.dm_conversation_id,
581
+ normalized_author_id: normalizedData.author_id
582
+ });
583
+ return {
584
+ ...response,
585
+ data: normalizedData
586
+ };
587
+ }
588
+
589
+ // Handle Twitter API v2 Tweet responses
590
+ // v2 has 'id' field but author_id is in expansions (includes.users)
591
+ if (responseType === 'tweet' && response.data.id) {
592
+ const normalizedData = {
593
+ ...response.data
594
+ };
595
+
596
+ // If author_id is missing but we have includes.users from expansions
597
+ if (!normalizedData.author_id && fullResponse?.includes?.users?.[0]?.id) {
598
+ normalizedData.author_id = fullResponse.includes.users[0].id;
599
+ loggerInfo(logger, `Added author_id to tweet response from expansions`, {
600
+ tweet_id: normalizedData.id,
601
+ author_id: normalizedData.author_id
602
+ });
603
+ } else if (normalizedData.author_id) {
604
+ loggerDebug(logger, `Twitter v2 tweet response already has 'author_id'`, {
605
+ id: response.data.id,
606
+ author_id: normalizedData.author_id
607
+ });
608
+ } else {
609
+ loggerWarn(logger, `Twitter v2 tweet response missing author_id and no expansions available`, {
610
+ id: response.data.id,
611
+ hasIncludes: !!fullResponse?.includes,
612
+ hasUsers: !!fullResponse?.includes?.users
613
+ });
614
+ }
615
+ return {
616
+ ...response,
617
+ data: normalizedData
618
+ };
619
+ }
620
+ return response;
621
+ }
544
622
  async function publishTweet(token, payload, query, isDirectMessage, logger) {
545
623
  try {
546
624
  let nativeResponse = await postRequest({
@@ -575,7 +653,12 @@ async function publishTweet(token, payload, query, isDirectMessage, logger) {
575
653
  loggerDebug(logger, `Twitter the data response is`, {
576
654
  response: JSON.stringify(response)
577
655
  });
578
- return response;
656
+
657
+ // Normalize the response to ensure backward compatibility with v1.1 structure
658
+ // Pass full nativeResponse to extract author_id from expansions if needed
659
+ const normalizedResponse = normalizeTwitterResponse(response, 'tweet', logger, nativeResponse.data // Full response with includes.users for author_id
660
+ );
661
+ return normalizedResponse;
579
662
  } catch (err) {
580
663
  loggerError(logger, `Twitter publish exception details`, err);
581
664
  throw err;
@@ -604,7 +687,11 @@ async function publishDirectMessage(token, payload, query, logger) {
604
687
  loggerDebug(logger, `Twitter DM response is`, {
605
688
  response: JSON.stringify(response)
606
689
  });
607
- return response;
690
+
691
+ // Normalize the response to ensure backward compatibility with v1.1 structure
692
+ // This is CRITICAL - v2 DM responses have dm_event_id instead of id
693
+ const normalizedResponse = normalizeTwitterResponse(response, 'dm', logger);
694
+ return normalizedResponse;
608
695
  } catch (err) {
609
696
  loggerError(logger, `Twitter DM exception details`, err);
610
697
  throw err;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meltwater/conversations-api-services",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Repository to contain all conversations api services shared across our services",
5
5
  "main": "dist/cjs/data-access/index.js",
6
6
  "module": "dist/esm/data-access/index.js",
@@ -28,10 +28,6 @@
28
28
  "keywords": [],
29
29
  "author": "",
30
30
  "license": "ISC",
31
- "publishConfig": {
32
- "registry": "https://registry.npmjs.org/",
33
- "access": "public"
34
- },
35
31
  "bugs": {
36
32
  "url": "https://github.com/meltwater/conversations-api-services/issues"
37
33
  },
@@ -693,6 +693,111 @@ export async function retweetWithComment(token, text, attachment, logger) {
693
693
  return publishTweet(token, payload, query, false, logger);
694
694
  }
695
695
 
696
+ /**
697
+ * Normalizes Twitter API responses to ensure consistent structure across v1.1 and v2
698
+ * This is critical for backward compatibility - consumers expect certain fields to exist
699
+ *
700
+ * @param {Object} response - The response object to normalize
701
+ * @param {string} responseType - Type of response: 'dm' for direct messages, 'tweet' for tweets
702
+ * @param {Object} logger - Logger instance for debugging
703
+ * @param {Object} fullResponse - Full API response including includes (for extracting author_id from expansions)
704
+ * @returns {Object} Normalized response with consistent field structure
705
+ */
706
+ function normalizeTwitterResponse(
707
+ response,
708
+ responseType,
709
+ logger,
710
+ fullResponse = null
711
+ ) {
712
+ if (!response || !response.data) {
713
+ return response;
714
+ }
715
+
716
+ loggerDebug(logger, `Normalizing Twitter API response (${responseType})`, {
717
+ beforeNormalization: JSON.stringify(response.data),
718
+ });
719
+
720
+ // Handle Twitter API v2 Direct Message responses
721
+ // v2 DM structure: { dm_event_id, dm_conversation_id }
722
+ // v1.1 expected structure: { id, author_id }
723
+ if (responseType === 'dm' && response.data.dm_event_id) {
724
+ const normalizedData = {
725
+ ...response.data,
726
+ // Add v1.1-compatible fields for backward compatibility
727
+ id: response.data.dm_event_id,
728
+ // Note: author_id is intentionally not set here. The caller (twitterApi.client.js)
729
+ // will set the correct author_id from the original document since dm_conversation_id
730
+ // doesn't reliably indicate the sender (it's just "user1-user2" format)
731
+ author_id: null,
732
+ };
733
+
734
+ loggerInfo(
735
+ logger,
736
+ `Normalized Twitter API v2 DM response to v1.1 format`,
737
+ {
738
+ dm_event_id: response.data.dm_event_id,
739
+ normalized_id: normalizedData.id,
740
+ dm_conversation_id: response.data.dm_conversation_id,
741
+ normalized_author_id: normalizedData.author_id,
742
+ }
743
+ );
744
+
745
+ return {
746
+ ...response,
747
+ data: normalizedData,
748
+ };
749
+ }
750
+
751
+ // Handle Twitter API v2 Tweet responses
752
+ // v2 has 'id' field but author_id is in expansions (includes.users)
753
+ if (responseType === 'tweet' && response.data.id) {
754
+ const normalizedData = { ...response.data };
755
+
756
+ // If author_id is missing but we have includes.users from expansions
757
+ if (
758
+ !normalizedData.author_id &&
759
+ fullResponse?.includes?.users?.[0]?.id
760
+ ) {
761
+ normalizedData.author_id = fullResponse.includes.users[0].id;
762
+
763
+ loggerInfo(
764
+ logger,
765
+ `Added author_id to tweet response from expansions`,
766
+ {
767
+ tweet_id: normalizedData.id,
768
+ author_id: normalizedData.author_id,
769
+ }
770
+ );
771
+ } else if (normalizedData.author_id) {
772
+ loggerDebug(
773
+ logger,
774
+ `Twitter v2 tweet response already has 'author_id'`,
775
+ {
776
+ id: response.data.id,
777
+ author_id: normalizedData.author_id,
778
+ }
779
+ );
780
+ } else {
781
+ loggerWarn(
782
+ logger,
783
+ `Twitter v2 tweet response missing author_id and no expansions available`,
784
+ {
785
+ id: response.data.id,
786
+ hasIncludes: !!fullResponse?.includes,
787
+ hasUsers: !!fullResponse?.includes?.users,
788
+ }
789
+ );
790
+ }
791
+
792
+ return {
793
+ ...response,
794
+ data: normalizedData,
795
+ };
796
+ }
797
+
798
+ return response;
799
+ }
800
+
696
801
  async function publishTweet(token, payload, query, isDirectMessage, logger) {
697
802
  try {
698
803
  let nativeResponse = await postRequest({
@@ -735,10 +840,21 @@ async function publishTweet(token, payload, query, isDirectMessage, logger) {
735
840
  statusCode: nativeResponse.statusCode,
736
841
  statusMessage: nativeResponse.message,
737
842
  };
843
+
738
844
  loggerDebug(logger, `Twitter the data response is`, {
739
845
  response: JSON.stringify(response),
740
846
  });
741
- return response;
847
+
848
+ // Normalize the response to ensure backward compatibility with v1.1 structure
849
+ // Pass full nativeResponse to extract author_id from expansions if needed
850
+ const normalizedResponse = normalizeTwitterResponse(
851
+ response,
852
+ 'tweet',
853
+ logger,
854
+ nativeResponse.data // Full response with includes.users for author_id
855
+ );
856
+
857
+ return normalizedResponse;
742
858
  } catch (err) {
743
859
  loggerError(logger, `Twitter publish exception details`, err);
744
860
  throw err;
@@ -773,10 +889,20 @@ async function publishDirectMessage(token, payload, query, logger) {
773
889
  statusCode: nativeResponse.statusCode,
774
890
  statusMessage: nativeResponse.message,
775
891
  };
892
+
776
893
  loggerDebug(logger, `Twitter DM response is`, {
777
894
  response: JSON.stringify(response),
778
895
  });
779
- return response;
896
+
897
+ // Normalize the response to ensure backward compatibility with v1.1 structure
898
+ // This is CRITICAL - v2 DM responses have dm_event_id instead of id
899
+ const normalizedResponse = normalizeTwitterResponse(
900
+ response,
901
+ 'dm',
902
+ logger
903
+ );
904
+
905
+ return normalizedResponse;
780
906
  } catch (err) {
781
907
  loggerError(logger, `Twitter DM exception details`, err);
782
908
  throw err;
@@ -1,22 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Script to rebuild and re-link conversations-api-services for testing with engage-conversations-api
4
-
5
- set -e
6
-
7
- echo "🔨 Building conversations-api-services..."
8
- npm run build
9
-
10
- echo "🔗 Creating npm link..."
11
- npm link
12
-
13
- echo "🔗 Linking in engage-conversations-api..."
14
- cd ../engage-conversations-api
15
- npm link @meltwater/conversations-api-services
16
-
17
- echo "✅ Successfully linked conversations-api-services for testing!"
18
- echo ""
19
- echo "📋 To unlink when done testing:"
20
- echo " cd ../engage-conversations-api"
21
- echo " npm unlink @meltwater/conversations-api-services"
22
- echo " npm install"