@shaivpidadi/trends-js 1.0.0 → 1.0.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.
package/README.md CHANGED
@@ -46,8 +46,26 @@ const result = await GoogleTrendsApi.dailyTrends({
46
46
 
47
47
  // Result structure:
48
48
  // {
49
- // allTrendingStories: Array<...>,
50
- // summary: string[]
49
+ // allTrendingStories: Array<{
50
+ // title: string,
51
+ // traffic: string,
52
+ // image?: {
53
+ // newsUrl: string,
54
+ // source: string,
55
+ // imageUrl: string
56
+ // },
57
+ // articles: Array<{
58
+ // title: string,
59
+ // url: string,
60
+ // source: string,
61
+ // time: string,
62
+ // snippet: string
63
+ // }>,
64
+ // shareUrl: string,
65
+ // startTime: number, // Unix timestamp
66
+ // endTime?: number // Unix timestamp (optional)
67
+ // }>,
68
+ // summary: Array<...>
51
69
  // }
52
70
  ```
53
71
 
@@ -63,8 +81,26 @@ const result = await GoogleTrendsApi.realTimeTrends({
63
81
 
64
82
  // Result structure:
65
83
  // {
66
- // allTrendingStories: Array<...>,
67
- // summary: string[]
84
+ // allTrendingStories: Array<{
85
+ // title: string,
86
+ // traffic: string,
87
+ // image?: {
88
+ // newsUrl: string,
89
+ // source: string,
90
+ // imageUrl: string
91
+ // },
92
+ // articles: Array<{
93
+ // title: string,
94
+ // url: string,
95
+ // source: string,
96
+ // time: string,
97
+ // snippet: string
98
+ // }>,
99
+ // shareUrl: string,
100
+ // startTime: number, // Unix timestamp
101
+ // endTime?: number // Unix timestamp (optional)
102
+ // }>,
103
+ // summary: Array<...>
68
104
  // }
69
105
  ```
70
106
 
@@ -2,12 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.extractJsonFromResponse = void 0;
4
4
  const GoogleTrendsError_js_1 = require("../errors/GoogleTrendsError.js");
5
- // For future refrence and update: from google trends page rpc call response,
5
+ // For future reference and update: from google trends page rpc call response,
6
6
  // 0 "twitter down" The main trending search term.
7
- // 1 null Unused (reserved for future Google Trends data).
7
+ // 1 null OR [newsUrl, source, imageUrl, [articles...]] Image/article data (often null in current API responses).
8
8
  // 2 "US" Country code (where the trend is happening).
9
- // 3 [1741599600] Unix timestamp (represents when the search started trending).
10
- // 4 null Unused (reserved for future data).
9
+ // 3 [1741599600] Unix timestamp array - first element is when the trend started.
10
+ // 4 null OR [1741602000] Unix timestamp array - trend end time (if available).
11
11
  // 5 null Unused (reserved for future data).
12
12
  // 6 500000 Search volume index (estimated search interest for the term).
13
13
  // 7 null Unused (reserved for future data).
@@ -41,6 +41,48 @@ const extractJsonFromResponse = (text) => {
41
41
  }
42
42
  };
43
43
  exports.extractJsonFromResponse = extractJsonFromResponse;
44
+ const extractArticles = (item) => {
45
+ const imageData = item[1];
46
+ if (!imageData || !Array.isArray(imageData))
47
+ return [];
48
+ if (imageData.length <= 3)
49
+ return [];
50
+ const articlesArray = imageData[3];
51
+ if (!Array.isArray(articlesArray))
52
+ return [];
53
+ return articlesArray
54
+ .filter((article) => Array.isArray(article) && article.length >= 5)
55
+ .map((article) => ({
56
+ title: String(article[0] || ''),
57
+ url: String(article[1] || ''),
58
+ source: String(article[2] || ''),
59
+ time: String(article[3] || ''),
60
+ snippet: String(article[4] || ''),
61
+ }));
62
+ };
63
+ const extractTimestamp = (item, index) => {
64
+ const timeArray = item[index];
65
+ if (!Array.isArray(timeArray))
66
+ return undefined;
67
+ if (timeArray.length === 0)
68
+ return undefined;
69
+ const timestamp = timeArray[0];
70
+ if (typeof timestamp !== 'number')
71
+ return undefined;
72
+ return timestamp;
73
+ };
74
+ const extractImage = (item) => {
75
+ const imageData = item[1];
76
+ if (!imageData || !Array.isArray(imageData))
77
+ return undefined;
78
+ if (imageData.length < 3)
79
+ return undefined;
80
+ return {
81
+ newsUrl: String(imageData[0] || ''),
82
+ source: String(imageData[1] || ''),
83
+ imageUrl: String(imageData[2] || ''),
84
+ };
85
+ };
44
86
  const updateResponseObject = (data) => {
45
87
  if (!Array.isArray(data)) {
46
88
  throw new GoogleTrendsError_js_1.ParseError('Invalid data format: expected array');
@@ -49,30 +91,26 @@ const updateResponseObject = (data) => {
49
91
  const summary = [];
50
92
  data.forEach((item) => {
51
93
  if (Array.isArray(item)) {
94
+ const articles = extractArticles(item);
95
+ const startTime = extractTimestamp(item, 3) ?? 0;
96
+ const endTime = extractTimestamp(item, 4);
97
+ const image = extractImage(item);
52
98
  const story = {
53
99
  title: String(item[0] || ''),
54
100
  traffic: String(item[6] || '0'),
55
- articles: Array.isArray(item[9]) ? item[9].map((article) => ({
56
- title: String(article[0] || ''),
57
- url: String(article[1] || ''),
58
- source: String(article[2] || ''),
59
- time: String(article[3] || ''),
60
- snippet: String(article[4] || '')
61
- })) : [],
62
- shareUrl: String(item[12] || '')
101
+ articles: articles,
102
+ shareUrl: String(item[12] || ''),
103
+ startTime,
104
+ ...(endTime && { endTime }),
105
+ ...(image && { image }),
63
106
  };
64
- if (item[1]) {
65
- story.image = {
66
- newsUrl: String(item[1][0] || ''),
67
- source: String(item[1][1] || ''),
68
- imageUrl: String(item[1][2] || '')
69
- };
70
- }
71
107
  allTrendingStories.push(story);
72
108
  summary.push({
73
109
  title: story.title,
74
110
  traffic: story.traffic,
75
- articles: story.articles
111
+ articles: story.articles,
112
+ startTime,
113
+ ...(endTime && { endTime }),
76
114
  });
77
115
  }
78
116
  });
@@ -152,6 +152,10 @@ class GoogleTrendsApi {
152
152
  }
153
153
  //
154
154
  async interestByRegion({ keyword, startTime = new Date('2004-01-01'), endTime = new Date(), geo = 'US', resolution = 'REGION', hl = 'en-US', timezone = new Date().getTimezoneOffset(), category = 0 }) {
155
+ const keywordValue = Array.isArray(keyword) ? keyword[0] : keyword;
156
+ if (!keywordValue || keywordValue.trim() === '') {
157
+ return { error: new GoogleTrendsError_js_1.InvalidRequestError('Keyword is required') };
158
+ }
155
159
  const formatDate = (date) => {
156
160
  return date.toISOString().split('T')[0];
157
161
  };
@@ -1,10 +1,10 @@
1
1
  import { ParseError } from '../errors/GoogleTrendsError.js';
2
- // For future refrence and update: from google trends page rpc call response,
2
+ // For future reference and update: from google trends page rpc call response,
3
3
  // 0 "twitter down" The main trending search term.
4
- // 1 null Unused (reserved for future Google Trends data).
4
+ // 1 null OR [newsUrl, source, imageUrl, [articles...]] Image/article data (often null in current API responses).
5
5
  // 2 "US" Country code (where the trend is happening).
6
- // 3 [1741599600] Unix timestamp (represents when the search started trending).
7
- // 4 null Unused (reserved for future data).
6
+ // 3 [1741599600] Unix timestamp array - first element is when the trend started.
7
+ // 4 null OR [1741602000] Unix timestamp array - trend end time (if available).
8
8
  // 5 null Unused (reserved for future data).
9
9
  // 6 500000 Search volume index (estimated search interest for the term).
10
10
  // 7 null Unused (reserved for future data).
@@ -37,6 +37,48 @@ export const extractJsonFromResponse = (text) => {
37
37
  throw new ParseError('Failed to parse response');
38
38
  }
39
39
  };
40
+ const extractArticles = (item) => {
41
+ const imageData = item[1];
42
+ if (!imageData || !Array.isArray(imageData))
43
+ return [];
44
+ if (imageData.length <= 3)
45
+ return [];
46
+ const articlesArray = imageData[3];
47
+ if (!Array.isArray(articlesArray))
48
+ return [];
49
+ return articlesArray
50
+ .filter((article) => Array.isArray(article) && article.length >= 5)
51
+ .map((article) => ({
52
+ title: String(article[0] || ''),
53
+ url: String(article[1] || ''),
54
+ source: String(article[2] || ''),
55
+ time: String(article[3] || ''),
56
+ snippet: String(article[4] || ''),
57
+ }));
58
+ };
59
+ const extractTimestamp = (item, index) => {
60
+ const timeArray = item[index];
61
+ if (!Array.isArray(timeArray))
62
+ return undefined;
63
+ if (timeArray.length === 0)
64
+ return undefined;
65
+ const timestamp = timeArray[0];
66
+ if (typeof timestamp !== 'number')
67
+ return undefined;
68
+ return timestamp;
69
+ };
70
+ const extractImage = (item) => {
71
+ const imageData = item[1];
72
+ if (!imageData || !Array.isArray(imageData))
73
+ return undefined;
74
+ if (imageData.length < 3)
75
+ return undefined;
76
+ return {
77
+ newsUrl: String(imageData[0] || ''),
78
+ source: String(imageData[1] || ''),
79
+ imageUrl: String(imageData[2] || ''),
80
+ };
81
+ };
40
82
  const updateResponseObject = (data) => {
41
83
  if (!Array.isArray(data)) {
42
84
  throw new ParseError('Invalid data format: expected array');
@@ -45,30 +87,26 @@ const updateResponseObject = (data) => {
45
87
  const summary = [];
46
88
  data.forEach((item) => {
47
89
  if (Array.isArray(item)) {
90
+ const articles = extractArticles(item);
91
+ const startTime = extractTimestamp(item, 3) ?? 0;
92
+ const endTime = extractTimestamp(item, 4);
93
+ const image = extractImage(item);
48
94
  const story = {
49
95
  title: String(item[0] || ''),
50
96
  traffic: String(item[6] || '0'),
51
- articles: Array.isArray(item[9]) ? item[9].map((article) => ({
52
- title: String(article[0] || ''),
53
- url: String(article[1] || ''),
54
- source: String(article[2] || ''),
55
- time: String(article[3] || ''),
56
- snippet: String(article[4] || '')
57
- })) : [],
58
- shareUrl: String(item[12] || '')
97
+ articles: articles,
98
+ shareUrl: String(item[12] || ''),
99
+ startTime,
100
+ ...(endTime && { endTime }),
101
+ ...(image && { image }),
59
102
  };
60
- if (item[1]) {
61
- story.image = {
62
- newsUrl: String(item[1][0] || ''),
63
- source: String(item[1][1] || ''),
64
- imageUrl: String(item[1][2] || '')
65
- };
66
- }
67
103
  allTrendingStories.push(story);
68
104
  summary.push({
69
105
  title: story.title,
70
106
  traffic: story.traffic,
71
- articles: story.articles
107
+ articles: story.articles,
108
+ startTime,
109
+ ...(endTime && { endTime }),
72
110
  });
73
111
  }
74
112
  });
@@ -149,6 +149,10 @@ export class GoogleTrendsApi {
149
149
  }
150
150
  //
151
151
  async interestByRegion({ keyword, startTime = new Date('2004-01-01'), endTime = new Date(), geo = 'US', resolution = 'REGION', hl = 'en-US', timezone = new Date().getTimezoneOffset(), category = 0 }) {
152
+ const keywordValue = Array.isArray(keyword) ? keyword[0] : keyword;
153
+ if (!keywordValue || keywordValue.trim() === '') {
154
+ return { error: new InvalidRequestError('Keyword is required') };
155
+ }
152
156
  const formatDate = (date) => {
153
157
  return date.toISOString().split('T')[0];
154
158
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shaivpidadi/trends-js",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Google Trends API for Node.js",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -42,7 +42,7 @@
42
42
  "devDependencies": {
43
43
  "@types/jest": "^29.5.0",
44
44
  "@types/node": "^20.0.0",
45
- "jest": "^29.5.0",
45
+ "jest": "^29.7.0",
46
46
  "ts-jest": "^29.1.0",
47
47
  "typescript": "^5.0.0"
48
48
  }