@shaivpidadi/trends-js 0.0.0-beta.8 → 1.0.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.
- package/README.md +6 -3
- package/dist/cjs/constants.d.ts +2 -2
- package/dist/cjs/constants.js +7 -7
- package/dist/cjs/errors/GoogleTrendsError.d.ts +1 -1
- package/dist/cjs/helpers/format.d.ts +1 -1
- package/dist/cjs/helpers/format.js +7 -7
- package/dist/cjs/helpers/googleTrendsAPI.d.ts +7 -3
- package/dist/cjs/helpers/googleTrendsAPI.js +132 -65
- package/dist/cjs/index.d.ts +26 -16
- package/dist/cjs/index.js +4 -3
- package/dist/cjs/package.json +1 -0
- package/dist/esm/constants.d.ts +2 -2
- package/dist/esm/constants.js +1 -1
- package/dist/esm/errors/GoogleTrendsError.d.ts +1 -1
- package/dist/esm/helpers/format.d.ts +1 -1
- package/dist/esm/helpers/format.js +1 -1
- package/dist/esm/helpers/googleTrendsAPI.d.ts +7 -3
- package/dist/esm/helpers/googleTrendsAPI.js +104 -37
- package/dist/esm/index.d.ts +26 -16
- package/dist/esm/index.js +2 -1
- package/dist/esm/package.json +1 -0
- package/package.json +13 -7
package/README.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
A TypeScript library for interacting with the Google Trends API. This package provides a simple and type-safe way to access Google Trends data programmatically.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Showcase
|
|
4
|
+
|
|
5
|
+
### EliteTimesNews.com — Built with `@shaivpidadi/trends-js`
|
|
6
|
+
**URL:** https://elitetimesnews.com
|
|
7
|
+
**What it uses:** `dailyTrends()` (US, en) to power the home page “Daily Trending” rail, refreshed on a schedule.
|
|
4
8
|
|
|
5
|
-
A TypeScript library for interacting with the Google Trends API. This package provides a simple and type-safe way to access Google Trends data programmatically.
|
|
6
9
|
|
|
7
10
|
## Installation
|
|
8
11
|
|
package/dist/cjs/constants.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { GoogleTrendsEndpoints } from './types/enums';
|
|
2
|
-
import { GoogleTrendsMapper } from './types';
|
|
1
|
+
import { GoogleTrendsEndpoints } from './types/enums.js';
|
|
2
|
+
import { GoogleTrendsMapper } from './types/index.js';
|
|
3
3
|
export declare const GOOGLE_TRENDS_MAPPER: Record<GoogleTrendsEndpoints, GoogleTrendsMapper>;
|
package/dist/cjs/constants.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GOOGLE_TRENDS_MAPPER = void 0;
|
|
4
|
-
const
|
|
4
|
+
const enums_js_1 = require("./types/enums.js");
|
|
5
5
|
const GOOGLE_TRENDS_BASE_URL = 'trends.google.com';
|
|
6
6
|
exports.GOOGLE_TRENDS_MAPPER = {
|
|
7
|
-
[
|
|
7
|
+
[enums_js_1.GoogleTrendsEndpoints.dailyTrends]: {
|
|
8
8
|
path: '/_/TrendsUi/data/batchexecute',
|
|
9
9
|
method: 'POST',
|
|
10
10
|
host: GOOGLE_TRENDS_BASE_URL,
|
|
@@ -13,7 +13,7 @@ exports.GOOGLE_TRENDS_MAPPER = {
|
|
|
13
13
|
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
|
|
14
14
|
},
|
|
15
15
|
},
|
|
16
|
-
[
|
|
16
|
+
[enums_js_1.GoogleTrendsEndpoints.autocomplete]: {
|
|
17
17
|
path: '/trends/api/autocomplete',
|
|
18
18
|
method: 'GET',
|
|
19
19
|
host: GOOGLE_TRENDS_BASE_URL,
|
|
@@ -22,28 +22,28 @@ exports.GOOGLE_TRENDS_MAPPER = {
|
|
|
22
22
|
accept: 'application/json, text/plain, */*',
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
|
-
[
|
|
25
|
+
[enums_js_1.GoogleTrendsEndpoints.explore]: {
|
|
26
26
|
path: '/trends/api/explore',
|
|
27
27
|
method: 'POST',
|
|
28
28
|
host: GOOGLE_TRENDS_BASE_URL,
|
|
29
29
|
url: `https://${GOOGLE_TRENDS_BASE_URL}/trends/api/explore`,
|
|
30
30
|
headers: {},
|
|
31
31
|
},
|
|
32
|
-
[
|
|
32
|
+
[enums_js_1.GoogleTrendsEndpoints.interestByRegion]: {
|
|
33
33
|
path: '/trends/api/widgetdata/comparedgeo',
|
|
34
34
|
method: 'GET',
|
|
35
35
|
host: GOOGLE_TRENDS_BASE_URL,
|
|
36
36
|
url: `https://${GOOGLE_TRENDS_BASE_URL}/trends/api/widgetdata/comparedgeo`,
|
|
37
37
|
headers: {},
|
|
38
38
|
},
|
|
39
|
-
[
|
|
39
|
+
[enums_js_1.GoogleTrendsEndpoints.relatedTopics]: {
|
|
40
40
|
path: '/trends/api/widgetdata/relatedtopics',
|
|
41
41
|
method: 'GET',
|
|
42
42
|
host: GOOGLE_TRENDS_BASE_URL,
|
|
43
43
|
url: `https://${GOOGLE_TRENDS_BASE_URL}/trends/api/widgetdata/relatedtopics`,
|
|
44
44
|
headers: {},
|
|
45
45
|
},
|
|
46
|
-
[
|
|
46
|
+
[enums_js_1.GoogleTrendsEndpoints.relatedQueries]: {
|
|
47
47
|
path: '/trends/api/widgetdata/relatedqueries',
|
|
48
48
|
method: 'GET',
|
|
49
49
|
host: GOOGLE_TRENDS_BASE_URL,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { DailyTrendingTopics } from '../types';
|
|
1
|
+
import { DailyTrendingTopics } from '../types/index.js';
|
|
2
2
|
export declare const extractJsonFromResponse: (text: string) => DailyTrendingTopics | null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.extractJsonFromResponse = void 0;
|
|
4
|
-
const
|
|
4
|
+
const GoogleTrendsError_js_1 = require("../errors/GoogleTrendsError.js");
|
|
5
5
|
// For future refrence and update: from google trends page rpc call response,
|
|
6
6
|
// 0 "twitter down" The main trending search term.
|
|
7
7
|
// 1 null Unused (reserved for future Google Trends data).
|
|
@@ -21,29 +21,29 @@ const extractJsonFromResponse = (text) => {
|
|
|
21
21
|
try {
|
|
22
22
|
const parsedResponse = JSON.parse(cleanedText);
|
|
23
23
|
if (!Array.isArray(parsedResponse) || parsedResponse.length === 0) {
|
|
24
|
-
throw new
|
|
24
|
+
throw new GoogleTrendsError_js_1.ParseError('Invalid response format: empty array');
|
|
25
25
|
}
|
|
26
26
|
const nestedJsonString = parsedResponse[0][2];
|
|
27
27
|
if (!nestedJsonString) {
|
|
28
|
-
throw new
|
|
28
|
+
throw new GoogleTrendsError_js_1.ParseError('Invalid response format: missing nested JSON');
|
|
29
29
|
}
|
|
30
30
|
const data = JSON.parse(nestedJsonString);
|
|
31
31
|
if (!data || !Array.isArray(data) || data.length < 2) {
|
|
32
|
-
throw new
|
|
32
|
+
throw new GoogleTrendsError_js_1.ParseError('Invalid response format: missing data array');
|
|
33
33
|
}
|
|
34
34
|
return updateResponseObject(data[1]);
|
|
35
35
|
}
|
|
36
36
|
catch (e) {
|
|
37
|
-
if (e instanceof
|
|
37
|
+
if (e instanceof GoogleTrendsError_js_1.ParseError) {
|
|
38
38
|
throw e;
|
|
39
39
|
}
|
|
40
|
-
throw new
|
|
40
|
+
throw new GoogleTrendsError_js_1.ParseError('Failed to parse response');
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
exports.extractJsonFromResponse = extractJsonFromResponse;
|
|
44
44
|
const updateResponseObject = (data) => {
|
|
45
45
|
if (!Array.isArray(data)) {
|
|
46
|
-
throw new
|
|
46
|
+
throw new GoogleTrendsError_js_1.ParseError('Invalid data format: expected array');
|
|
47
47
|
}
|
|
48
48
|
const allTrendingStories = [];
|
|
49
49
|
const summary = [];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DailyTrendingTopics, DailyTrendingTopicsOptions, RealTimeTrendsOptions, ExploreOptions, ExploreResponse, InterestByRegionOptions, InterestByRegionResponse, GoogleTrendsResponse, RelatedTopicsResponse, RelatedQueriesResponse, RelatedData } from '../types/index';
|
|
1
|
+
import { DailyTrendingTopics, DailyTrendingTopicsOptions, RealTimeTrendsOptions, ExploreOptions, ExploreResponse, InterestByRegionOptions, InterestByRegionResponse, GoogleTrendsResponse, GoogleTrendsError, RelatedTopicsResponse, RelatedQueriesResponse, RelatedData } from '../types/index.js';
|
|
2
2
|
export declare class GoogleTrendsApi {
|
|
3
3
|
/**
|
|
4
4
|
* Get autocomplete suggestions for a keyword
|
|
@@ -19,8 +19,12 @@ export declare class GoogleTrendsApi {
|
|
|
19
19
|
* @returns Promise with trending topics data
|
|
20
20
|
*/
|
|
21
21
|
realTimeTrends({ geo, trendingHours }: RealTimeTrendsOptions): Promise<GoogleTrendsResponse<DailyTrendingTopics>>;
|
|
22
|
-
explore({ keyword, geo, time, category, property, hl, }: ExploreOptions): Promise<ExploreResponse
|
|
23
|
-
|
|
22
|
+
explore({ keyword, geo, time, category, property, hl, }: ExploreOptions): Promise<ExploreResponse | {
|
|
23
|
+
error: GoogleTrendsError;
|
|
24
|
+
}>;
|
|
25
|
+
interestByRegion({ keyword, startTime, endTime, geo, resolution, hl, timezone, category }: InterestByRegionOptions): Promise<InterestByRegionResponse | {
|
|
26
|
+
error: GoogleTrendsError;
|
|
27
|
+
}>;
|
|
24
28
|
relatedTopics({ keyword, geo, time, category, property, hl, }: ExploreOptions): Promise<GoogleTrendsResponse<RelatedTopicsResponse>>;
|
|
25
29
|
relatedQueries({ keyword, geo, time, category, property, hl, }: ExploreOptions): Promise<GoogleTrendsResponse<RelatedQueriesResponse>>;
|
|
26
30
|
relatedData({ keyword, geo, time, category, property, hl, }: ExploreOptions): Promise<GoogleTrendsResponse<RelatedData>>;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GoogleTrendsApi = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
4
|
+
const enums_js_1 = require("../types/enums.js");
|
|
5
|
+
const request_js_1 = require("./request.js");
|
|
6
|
+
const format_js_1 = require("./format.js");
|
|
7
|
+
const constants_js_1 = require("../constants.js");
|
|
8
|
+
const GoogleTrendsError_js_1 = require("../errors/GoogleTrendsError.js");
|
|
9
9
|
class GoogleTrendsApi {
|
|
10
10
|
/**
|
|
11
11
|
* Get autocomplete suggestions for a keyword
|
|
@@ -18,14 +18,14 @@ class GoogleTrendsApi {
|
|
|
18
18
|
return { data: [] };
|
|
19
19
|
}
|
|
20
20
|
const options = {
|
|
21
|
-
...
|
|
21
|
+
...constants_js_1.GOOGLE_TRENDS_MAPPER[enums_js_1.GoogleTrendsEndpoints.autocomplete],
|
|
22
22
|
qs: {
|
|
23
23
|
hl,
|
|
24
24
|
tz: '240',
|
|
25
25
|
},
|
|
26
26
|
};
|
|
27
27
|
try {
|
|
28
|
-
const response = await (0,
|
|
28
|
+
const response = await (0, request_js_1.request)(`${options.url}/${encodeURIComponent(keyword)}`, options);
|
|
29
29
|
const text = await response.text();
|
|
30
30
|
// Remove the first 5 characters (JSONP wrapper) and parse
|
|
31
31
|
const data = JSON.parse(text.slice(5));
|
|
@@ -33,9 +33,9 @@ class GoogleTrendsApi {
|
|
|
33
33
|
}
|
|
34
34
|
catch (error) {
|
|
35
35
|
if (error instanceof Error) {
|
|
36
|
-
return { error: new
|
|
36
|
+
return { error: new GoogleTrendsError_js_1.NetworkError(error.message) };
|
|
37
37
|
}
|
|
38
|
-
return { error: new
|
|
38
|
+
return { error: new GoogleTrendsError_js_1.UnknownError() };
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
@@ -44,7 +44,7 @@ class GoogleTrendsApi {
|
|
|
44
44
|
* @returns Promise with trending topics data
|
|
45
45
|
*/
|
|
46
46
|
async dailyTrends({ geo = 'US', lang = 'en' }) {
|
|
47
|
-
const defaultOptions =
|
|
47
|
+
const defaultOptions = constants_js_1.GOOGLE_TRENDS_MAPPER[enums_js_1.GoogleTrendsEndpoints.dailyTrends];
|
|
48
48
|
const options = {
|
|
49
49
|
...defaultOptions,
|
|
50
50
|
body: new URLSearchParams({
|
|
@@ -53,19 +53,19 @@ class GoogleTrendsApi {
|
|
|
53
53
|
contentType: 'form'
|
|
54
54
|
};
|
|
55
55
|
try {
|
|
56
|
-
const response = await (0,
|
|
56
|
+
const response = await (0, request_js_1.request)(options.url, options);
|
|
57
57
|
const text = await response.text();
|
|
58
|
-
const trendingTopics = (0,
|
|
58
|
+
const trendingTopics = (0, format_js_1.extractJsonFromResponse)(text);
|
|
59
59
|
if (!trendingTopics) {
|
|
60
|
-
return { error: new
|
|
60
|
+
return { error: new GoogleTrendsError_js_1.ParseError() };
|
|
61
61
|
}
|
|
62
62
|
return { data: trendingTopics };
|
|
63
63
|
}
|
|
64
64
|
catch (error) {
|
|
65
65
|
if (error instanceof Error) {
|
|
66
|
-
return { error: new
|
|
66
|
+
return { error: new GoogleTrendsError_js_1.NetworkError(error.message) };
|
|
67
67
|
}
|
|
68
|
-
return { error: new
|
|
68
|
+
return { error: new GoogleTrendsError_js_1.UnknownError() };
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
@@ -74,7 +74,7 @@ class GoogleTrendsApi {
|
|
|
74
74
|
* @returns Promise with trending topics data
|
|
75
75
|
*/
|
|
76
76
|
async realTimeTrends({ geo = 'US', trendingHours = 4 }) {
|
|
77
|
-
const defaultOptions =
|
|
77
|
+
const defaultOptions = constants_js_1.GOOGLE_TRENDS_MAPPER[enums_js_1.GoogleTrendsEndpoints.dailyTrends];
|
|
78
78
|
const options = {
|
|
79
79
|
...defaultOptions,
|
|
80
80
|
body: new URLSearchParams({
|
|
@@ -83,24 +83,24 @@ class GoogleTrendsApi {
|
|
|
83
83
|
contentType: 'form'
|
|
84
84
|
};
|
|
85
85
|
try {
|
|
86
|
-
const response = await (0,
|
|
86
|
+
const response = await (0, request_js_1.request)(options.url, options);
|
|
87
87
|
const text = await response.text();
|
|
88
|
-
const trendingTopics = (0,
|
|
88
|
+
const trendingTopics = (0, format_js_1.extractJsonFromResponse)(text);
|
|
89
89
|
if (!trendingTopics) {
|
|
90
|
-
return { error: new
|
|
90
|
+
return { error: new GoogleTrendsError_js_1.ParseError() };
|
|
91
91
|
}
|
|
92
92
|
return { data: trendingTopics };
|
|
93
93
|
}
|
|
94
94
|
catch (error) {
|
|
95
95
|
if (error instanceof Error) {
|
|
96
|
-
return { error: new
|
|
96
|
+
return { error: new GoogleTrendsError_js_1.NetworkError(error.message) };
|
|
97
97
|
}
|
|
98
|
-
return { error: new
|
|
98
|
+
return { error: new GoogleTrendsError_js_1.UnknownError() };
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
async explore({ keyword, geo = 'US', time = 'now 1-d', category = 0, property = '', hl = 'en-US', }) {
|
|
102
102
|
const options = {
|
|
103
|
-
...
|
|
103
|
+
...constants_js_1.GOOGLE_TRENDS_MAPPER[enums_js_1.GoogleTrendsEndpoints.explore],
|
|
104
104
|
qs: {
|
|
105
105
|
hl,
|
|
106
106
|
tz: '240',
|
|
@@ -119,28 +119,35 @@ class GoogleTrendsApi {
|
|
|
119
119
|
contentType: 'form'
|
|
120
120
|
};
|
|
121
121
|
try {
|
|
122
|
-
const response = await (0,
|
|
122
|
+
const response = await (0, request_js_1.request)(options.url, options);
|
|
123
123
|
const text = await response.text();
|
|
124
124
|
// Check if response is HTML (error page)
|
|
125
125
|
if (text.includes('<html') || text.includes('<!DOCTYPE')) {
|
|
126
|
-
|
|
127
|
-
return { widgets: [] };
|
|
126
|
+
return { error: new GoogleTrendsError_js_1.ParseError('Explore request returned HTML instead of JSON') };
|
|
128
127
|
}
|
|
129
128
|
// Try to parse as JSON
|
|
130
129
|
try {
|
|
131
130
|
// Remove the first 5 characters (JSONP wrapper) and parse
|
|
132
131
|
const data = JSON.parse(text.slice(5));
|
|
133
|
-
|
|
132
|
+
// Extract widgets from the response
|
|
133
|
+
if (data && Array.isArray(data) && data.length > 0) {
|
|
134
|
+
const widgets = data[0] || [];
|
|
135
|
+
return { widgets };
|
|
136
|
+
}
|
|
137
|
+
return { widgets: [] };
|
|
134
138
|
}
|
|
135
139
|
catch (parseError) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
if (parseError instanceof Error) {
|
|
141
|
+
return { error: new GoogleTrendsError_js_1.ParseError(`Failed to parse explore response as JSON: ${parseError.message}`) };
|
|
142
|
+
}
|
|
143
|
+
return { error: new GoogleTrendsError_js_1.ParseError('Failed to parse explore response as JSON') };
|
|
139
144
|
}
|
|
140
145
|
}
|
|
141
146
|
catch (error) {
|
|
142
|
-
|
|
143
|
-
|
|
147
|
+
if (error instanceof Error) {
|
|
148
|
+
return { error: new GoogleTrendsError_js_1.NetworkError(`Explore request failed: ${error.message}`) };
|
|
149
|
+
}
|
|
150
|
+
return { error: new GoogleTrendsError_js_1.UnknownError('Explore request failed') };
|
|
144
151
|
}
|
|
145
152
|
}
|
|
146
153
|
//
|
|
@@ -172,12 +179,15 @@ class GoogleTrendsApi {
|
|
|
172
179
|
category,
|
|
173
180
|
hl
|
|
174
181
|
});
|
|
182
|
+
if ('error' in exploreResponse) {
|
|
183
|
+
return { error: exploreResponse.error };
|
|
184
|
+
}
|
|
175
185
|
const widget = exploreResponse.widgets.find(w => w.id === 'GEO_MAP');
|
|
176
186
|
if (!widget) {
|
|
177
|
-
return {
|
|
187
|
+
return { error: new GoogleTrendsError_js_1.ParseError('No GEO_MAP widget found in explore response') };
|
|
178
188
|
}
|
|
179
189
|
const options = {
|
|
180
|
-
...
|
|
190
|
+
...constants_js_1.GOOGLE_TRENDS_MAPPER[enums_js_1.GoogleTrendsEndpoints.interestByRegion],
|
|
181
191
|
qs: {
|
|
182
192
|
hl,
|
|
183
193
|
tz: timezone.toString(),
|
|
@@ -209,59 +219,116 @@ class GoogleTrendsApi {
|
|
|
209
219
|
}
|
|
210
220
|
};
|
|
211
221
|
try {
|
|
212
|
-
const response = await (0,
|
|
222
|
+
const response = await (0, request_js_1.request)(options.url, options);
|
|
213
223
|
const text = await response.text();
|
|
214
224
|
// Remove the first 5 characters (JSONP wrapper) and parse
|
|
215
225
|
const data = JSON.parse(text.slice(5));
|
|
216
226
|
return data;
|
|
217
227
|
}
|
|
218
228
|
catch (error) {
|
|
219
|
-
|
|
229
|
+
if (error instanceof Error) {
|
|
230
|
+
return { error: new GoogleTrendsError_js_1.ParseError(`Failed to parse interest by region response: ${error.message}`) };
|
|
231
|
+
}
|
|
232
|
+
return { error: new GoogleTrendsError_js_1.ParseError('Failed to parse interest by region response') };
|
|
220
233
|
}
|
|
221
234
|
}
|
|
222
235
|
async relatedTopics({ keyword, geo = 'US', time = 'now 1-d', category = 0, property = '', hl = 'en-US', }) {
|
|
223
236
|
try {
|
|
224
237
|
// Validate keyword
|
|
225
238
|
if (!keyword || keyword.trim() === '') {
|
|
226
|
-
return { error: new
|
|
239
|
+
return { error: new GoogleTrendsError_js_1.InvalidRequestError('Keyword is required') };
|
|
227
240
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
241
|
+
// Step 1: Call explore to get widget data and token
|
|
242
|
+
const exploreResponse = await this.explore({
|
|
243
|
+
keyword,
|
|
244
|
+
geo,
|
|
245
|
+
time,
|
|
246
|
+
category,
|
|
247
|
+
property,
|
|
248
|
+
hl
|
|
249
|
+
});
|
|
250
|
+
if ('error' in exploreResponse) {
|
|
251
|
+
return { error: exploreResponse.error };
|
|
231
252
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
253
|
+
if (!exploreResponse.widgets || exploreResponse.widgets.length === 0) {
|
|
254
|
+
return { error: new GoogleTrendsError_js_1.ParseError('No widgets found in explore response. This might be due to Google blocking the request, invalid parameters, or network issues.') };
|
|
255
|
+
}
|
|
256
|
+
// Step 2: Find the related topics widget or use any available widget
|
|
257
|
+
const relatedTopicsWidget = exploreResponse.widgets.find(widget => widget.id === 'RELATED_TOPICS' ||
|
|
258
|
+
widget.request?.restriction?.complexKeywordsRestriction?.keyword?.[0]?.value === keyword) || exploreResponse.widgets[0]; // Fallback to first widget if no specific one found
|
|
259
|
+
if (!relatedTopicsWidget) {
|
|
260
|
+
return { error: new GoogleTrendsError_js_1.ParseError('No related topics widget found in explore response') };
|
|
261
|
+
}
|
|
262
|
+
// Step 3: Call the related topics API with or without token
|
|
263
|
+
const options = {
|
|
264
|
+
...constants_js_1.GOOGLE_TRENDS_MAPPER[enums_js_1.GoogleTrendsEndpoints.relatedTopics],
|
|
265
|
+
qs: {
|
|
266
|
+
hl,
|
|
267
|
+
tz: '240',
|
|
268
|
+
req: JSON.stringify({
|
|
269
|
+
restriction: {
|
|
270
|
+
geo: { country: geo },
|
|
271
|
+
time: time,
|
|
272
|
+
originalTimeRangeForExploreUrl: time,
|
|
273
|
+
complexKeywordsRestriction: {
|
|
274
|
+
keyword: [{
|
|
275
|
+
type: 'BROAD',
|
|
276
|
+
value: keyword
|
|
277
|
+
}]
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
keywordType: 'ENTITY',
|
|
281
|
+
metric: ['TOP', 'RISING'],
|
|
282
|
+
trendinessSettings: {
|
|
283
|
+
compareTime: time
|
|
284
|
+
},
|
|
285
|
+
requestOptions: {
|
|
286
|
+
property: property,
|
|
287
|
+
backend: 'CM',
|
|
288
|
+
category: category
|
|
289
|
+
},
|
|
290
|
+
language: hl.split('-')[0],
|
|
291
|
+
userCountryCode: geo,
|
|
292
|
+
userConfig: {
|
|
293
|
+
userType: 'USER_TYPE_LEGIT_USER'
|
|
294
|
+
}
|
|
295
|
+
}),
|
|
296
|
+
...(relatedTopicsWidget.token && { token: relatedTopicsWidget.token })
|
|
250
297
|
}
|
|
251
298
|
};
|
|
299
|
+
const response = await (0, request_js_1.request)(options.url, options);
|
|
300
|
+
const text = await response.text();
|
|
301
|
+
// Parse the response
|
|
302
|
+
try {
|
|
303
|
+
const data = JSON.parse(text.slice(5));
|
|
304
|
+
// Return the data in the expected format
|
|
305
|
+
return {
|
|
306
|
+
data: {
|
|
307
|
+
default: {
|
|
308
|
+
rankedList: data.default?.rankedList || []
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
catch (parseError) {
|
|
314
|
+
if (parseError instanceof Error) {
|
|
315
|
+
return { error: new GoogleTrendsError_js_1.ParseError(`Failed to parse related topics response: ${parseError.message}`) };
|
|
316
|
+
}
|
|
317
|
+
return { error: new GoogleTrendsError_js_1.ParseError('Failed to parse related topics response') };
|
|
318
|
+
}
|
|
252
319
|
}
|
|
253
320
|
catch (error) {
|
|
254
321
|
if (error instanceof Error) {
|
|
255
|
-
return { error: new
|
|
322
|
+
return { error: new GoogleTrendsError_js_1.NetworkError(error.message) };
|
|
256
323
|
}
|
|
257
|
-
return { error: new
|
|
324
|
+
return { error: new GoogleTrendsError_js_1.UnknownError() };
|
|
258
325
|
}
|
|
259
326
|
}
|
|
260
327
|
async relatedQueries({ keyword, geo = 'US', time = 'now 1-d', category = 0, property = '', hl = 'en-US', }) {
|
|
261
328
|
try {
|
|
262
329
|
// Validate keyword
|
|
263
330
|
if (!keyword || keyword.trim() === '') {
|
|
264
|
-
return { error: new
|
|
331
|
+
return { error: new GoogleTrendsError_js_1.ParseError() };
|
|
265
332
|
}
|
|
266
333
|
const autocompleteResult = await this.autocomplete(keyword, hl);
|
|
267
334
|
if (autocompleteResult.error) {
|
|
@@ -286,16 +353,16 @@ class GoogleTrendsApi {
|
|
|
286
353
|
}
|
|
287
354
|
catch (error) {
|
|
288
355
|
if (error instanceof Error) {
|
|
289
|
-
return { error: new
|
|
356
|
+
return { error: new GoogleTrendsError_js_1.NetworkError(error.message) };
|
|
290
357
|
}
|
|
291
|
-
return { error: new
|
|
358
|
+
return { error: new GoogleTrendsError_js_1.UnknownError() };
|
|
292
359
|
}
|
|
293
360
|
}
|
|
294
361
|
async relatedData({ keyword, geo = 'US', time = 'now 1-d', category = 0, property = '', hl = 'en-US', }) {
|
|
295
362
|
try {
|
|
296
363
|
// Validate keyword
|
|
297
364
|
if (!keyword || keyword.trim() === '') {
|
|
298
|
-
return { error: new
|
|
365
|
+
return { error: new GoogleTrendsError_js_1.ParseError() };
|
|
299
366
|
}
|
|
300
367
|
const autocompleteResult = await this.autocomplete(keyword, hl);
|
|
301
368
|
if (autocompleteResult.error) {
|
|
@@ -329,9 +396,9 @@ class GoogleTrendsApi {
|
|
|
329
396
|
}
|
|
330
397
|
catch (error) {
|
|
331
398
|
if (error instanceof Error) {
|
|
332
|
-
return { error: new
|
|
399
|
+
return { error: new GoogleTrendsError_js_1.NetworkError(error.message) };
|
|
333
400
|
}
|
|
334
|
-
return { error: new
|
|
401
|
+
return { error: new GoogleTrendsError_js_1.UnknownError() };
|
|
335
402
|
}
|
|
336
403
|
}
|
|
337
404
|
}
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export declare const
|
|
1
|
+
import { GoogleTrendsApi } from './helpers/googleTrendsAPI.js';
|
|
2
|
+
export declare const dailyTrends: ({ geo, lang }: import("./types/index.js").DailyTrendingTopicsOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").DailyTrendingTopics>>;
|
|
3
|
+
export declare const realTimeTrends: ({ geo, trendingHours }: import("./types/index.js").RealTimeTrendsOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").DailyTrendingTopics>>;
|
|
4
|
+
export declare const autocomplete: (keyword: string, hl?: string) => Promise<import("./types/index.js").GoogleTrendsResponse<string[]>>;
|
|
5
|
+
export declare const explore: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").ExploreResponse | {
|
|
6
|
+
error: import("./types/index.js").GoogleTrendsError;
|
|
7
|
+
}>;
|
|
8
|
+
export declare const interestByRegion: ({ keyword, startTime, endTime, geo, resolution, hl, timezone, category }: import("./types/index.js").InterestByRegionOptions) => Promise<import("./types/index.js").InterestByRegionResponse | {
|
|
9
|
+
error: import("./types/index.js").GoogleTrendsError;
|
|
10
|
+
}>;
|
|
11
|
+
export declare const relatedTopics: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedTopicsResponse>>;
|
|
12
|
+
export declare const relatedQueries: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedQueriesResponse>>;
|
|
13
|
+
export declare const relatedData: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedData>>;
|
|
14
|
+
export { GoogleTrendsApi };
|
|
9
15
|
declare const _default: {
|
|
10
|
-
dailyTrends: ({ geo, lang }: import("./types").DailyTrendingTopicsOptions) => Promise<import("./types").GoogleTrendsResponse<import("./types").DailyTrendingTopics>>;
|
|
11
|
-
realTimeTrends: ({ geo, trendingHours }: import("./types").RealTimeTrendsOptions) => Promise<import("./types").GoogleTrendsResponse<import("./types").DailyTrendingTopics>>;
|
|
12
|
-
autocomplete: (keyword: string, hl?: string) => Promise<import("./types").GoogleTrendsResponse<string[]>>;
|
|
13
|
-
explore: ({ keyword, geo, time, category, property, hl, }: import("./types").ExploreOptions) => Promise<import("./types").ExploreResponse
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
dailyTrends: ({ geo, lang }: import("./types/index.js").DailyTrendingTopicsOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").DailyTrendingTopics>>;
|
|
17
|
+
realTimeTrends: ({ geo, trendingHours }: import("./types/index.js").RealTimeTrendsOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").DailyTrendingTopics>>;
|
|
18
|
+
autocomplete: (keyword: string, hl?: string) => Promise<import("./types/index.js").GoogleTrendsResponse<string[]>>;
|
|
19
|
+
explore: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").ExploreResponse | {
|
|
20
|
+
error: import("./types/index.js").GoogleTrendsError;
|
|
21
|
+
}>;
|
|
22
|
+
interestByRegion: ({ keyword, startTime, endTime, geo, resolution, hl, timezone, category }: import("./types/index.js").InterestByRegionOptions) => Promise<import("./types/index.js").InterestByRegionResponse | {
|
|
23
|
+
error: import("./types/index.js").GoogleTrendsError;
|
|
24
|
+
}>;
|
|
25
|
+
relatedTopics: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedTopicsResponse>>;
|
|
26
|
+
relatedQueries: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedQueriesResponse>>;
|
|
27
|
+
relatedData: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedData>>;
|
|
18
28
|
};
|
|
19
29
|
export default _default;
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.relatedData = exports.relatedQueries = exports.relatedTopics = exports.interestByRegion = exports.explore = exports.autocomplete = exports.realTimeTrends = exports.dailyTrends = void 0;
|
|
4
|
-
const
|
|
5
|
-
|
|
3
|
+
exports.GoogleTrendsApi = exports.relatedData = exports.relatedQueries = exports.relatedTopics = exports.interestByRegion = exports.explore = exports.autocomplete = exports.realTimeTrends = exports.dailyTrends = void 0;
|
|
4
|
+
const googleTrendsAPI_js_1 = require("./helpers/googleTrendsAPI.js");
|
|
5
|
+
Object.defineProperty(exports, "GoogleTrendsApi", { enumerable: true, get: function () { return googleTrendsAPI_js_1.GoogleTrendsApi; } });
|
|
6
|
+
const api = new googleTrendsAPI_js_1.GoogleTrendsApi();
|
|
6
7
|
exports.dailyTrends = api.dailyTrends.bind(api);
|
|
7
8
|
exports.realTimeTrends = api.realTimeTrends.bind(api);
|
|
8
9
|
exports.autocomplete = api.autocomplete.bind(api);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
package/dist/esm/constants.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { GoogleTrendsEndpoints } from './types/enums';
|
|
2
|
-
import { GoogleTrendsMapper } from './types';
|
|
1
|
+
import { GoogleTrendsEndpoints } from './types/enums.js';
|
|
2
|
+
import { GoogleTrendsMapper } from './types/index.js';
|
|
3
3
|
export declare const GOOGLE_TRENDS_MAPPER: Record<GoogleTrendsEndpoints, GoogleTrendsMapper>;
|
package/dist/esm/constants.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { DailyTrendingTopics } from '../types';
|
|
1
|
+
import { DailyTrendingTopics } from '../types/index.js';
|
|
2
2
|
export declare const extractJsonFromResponse: (text: string) => DailyTrendingTopics | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ParseError } from '../errors/GoogleTrendsError';
|
|
1
|
+
import { ParseError } from '../errors/GoogleTrendsError.js';
|
|
2
2
|
// For future refrence and update: from google trends page rpc call response,
|
|
3
3
|
// 0 "twitter down" The main trending search term.
|
|
4
4
|
// 1 null Unused (reserved for future Google Trends data).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DailyTrendingTopics, DailyTrendingTopicsOptions, RealTimeTrendsOptions, ExploreOptions, ExploreResponse, InterestByRegionOptions, InterestByRegionResponse, GoogleTrendsResponse, RelatedTopicsResponse, RelatedQueriesResponse, RelatedData } from '../types/index';
|
|
1
|
+
import { DailyTrendingTopics, DailyTrendingTopicsOptions, RealTimeTrendsOptions, ExploreOptions, ExploreResponse, InterestByRegionOptions, InterestByRegionResponse, GoogleTrendsResponse, GoogleTrendsError, RelatedTopicsResponse, RelatedQueriesResponse, RelatedData } from '../types/index.js';
|
|
2
2
|
export declare class GoogleTrendsApi {
|
|
3
3
|
/**
|
|
4
4
|
* Get autocomplete suggestions for a keyword
|
|
@@ -19,8 +19,12 @@ export declare class GoogleTrendsApi {
|
|
|
19
19
|
* @returns Promise with trending topics data
|
|
20
20
|
*/
|
|
21
21
|
realTimeTrends({ geo, trendingHours }: RealTimeTrendsOptions): Promise<GoogleTrendsResponse<DailyTrendingTopics>>;
|
|
22
|
-
explore({ keyword, geo, time, category, property, hl, }: ExploreOptions): Promise<ExploreResponse
|
|
23
|
-
|
|
22
|
+
explore({ keyword, geo, time, category, property, hl, }: ExploreOptions): Promise<ExploreResponse | {
|
|
23
|
+
error: GoogleTrendsError;
|
|
24
|
+
}>;
|
|
25
|
+
interestByRegion({ keyword, startTime, endTime, geo, resolution, hl, timezone, category }: InterestByRegionOptions): Promise<InterestByRegionResponse | {
|
|
26
|
+
error: GoogleTrendsError;
|
|
27
|
+
}>;
|
|
24
28
|
relatedTopics({ keyword, geo, time, category, property, hl, }: ExploreOptions): Promise<GoogleTrendsResponse<RelatedTopicsResponse>>;
|
|
25
29
|
relatedQueries({ keyword, geo, time, category, property, hl, }: ExploreOptions): Promise<GoogleTrendsResponse<RelatedQueriesResponse>>;
|
|
26
30
|
relatedData({ keyword, geo, time, category, property, hl, }: ExploreOptions): Promise<GoogleTrendsResponse<RelatedData>>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { GoogleTrendsEndpoints } from '../types/enums';
|
|
2
|
-
import { request } from './request';
|
|
3
|
-
import { extractJsonFromResponse } from './format';
|
|
4
|
-
import { GOOGLE_TRENDS_MAPPER } from '../constants';
|
|
5
|
-
import { NetworkError, ParseError, UnknownError, } from '../errors/GoogleTrendsError';
|
|
1
|
+
import { GoogleTrendsEndpoints } from '../types/enums.js';
|
|
2
|
+
import { request } from './request.js';
|
|
3
|
+
import { extractJsonFromResponse } from './format.js';
|
|
4
|
+
import { GOOGLE_TRENDS_MAPPER } from '../constants.js';
|
|
5
|
+
import { InvalidRequestError, NetworkError, ParseError, UnknownError, } from '../errors/GoogleTrendsError.js';
|
|
6
6
|
export class GoogleTrendsApi {
|
|
7
7
|
/**
|
|
8
8
|
* Get autocomplete suggestions for a keyword
|
|
@@ -120,24 +120,31 @@ export class GoogleTrendsApi {
|
|
|
120
120
|
const text = await response.text();
|
|
121
121
|
// Check if response is HTML (error page)
|
|
122
122
|
if (text.includes('<html') || text.includes('<!DOCTYPE')) {
|
|
123
|
-
|
|
124
|
-
return { widgets: [] };
|
|
123
|
+
return { error: new ParseError('Explore request returned HTML instead of JSON') };
|
|
125
124
|
}
|
|
126
125
|
// Try to parse as JSON
|
|
127
126
|
try {
|
|
128
127
|
// Remove the first 5 characters (JSONP wrapper) and parse
|
|
129
128
|
const data = JSON.parse(text.slice(5));
|
|
130
|
-
|
|
129
|
+
// Extract widgets from the response
|
|
130
|
+
if (data && Array.isArray(data) && data.length > 0) {
|
|
131
|
+
const widgets = data[0] || [];
|
|
132
|
+
return { widgets };
|
|
133
|
+
}
|
|
134
|
+
return { widgets: [] };
|
|
131
135
|
}
|
|
132
136
|
catch (parseError) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
137
|
+
if (parseError instanceof Error) {
|
|
138
|
+
return { error: new ParseError(`Failed to parse explore response as JSON: ${parseError.message}`) };
|
|
139
|
+
}
|
|
140
|
+
return { error: new ParseError('Failed to parse explore response as JSON') };
|
|
136
141
|
}
|
|
137
142
|
}
|
|
138
143
|
catch (error) {
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
if (error instanceof Error) {
|
|
145
|
+
return { error: new NetworkError(`Explore request failed: ${error.message}`) };
|
|
146
|
+
}
|
|
147
|
+
return { error: new UnknownError('Explore request failed') };
|
|
141
148
|
}
|
|
142
149
|
}
|
|
143
150
|
//
|
|
@@ -169,9 +176,12 @@ export class GoogleTrendsApi {
|
|
|
169
176
|
category,
|
|
170
177
|
hl
|
|
171
178
|
});
|
|
179
|
+
if ('error' in exploreResponse) {
|
|
180
|
+
return { error: exploreResponse.error };
|
|
181
|
+
}
|
|
172
182
|
const widget = exploreResponse.widgets.find(w => w.id === 'GEO_MAP');
|
|
173
183
|
if (!widget) {
|
|
174
|
-
return {
|
|
184
|
+
return { error: new ParseError('No GEO_MAP widget found in explore response') };
|
|
175
185
|
}
|
|
176
186
|
const options = {
|
|
177
187
|
...GOOGLE_TRENDS_MAPPER[GoogleTrendsEndpoints.interestByRegion],
|
|
@@ -213,39 +223,96 @@ export class GoogleTrendsApi {
|
|
|
213
223
|
return data;
|
|
214
224
|
}
|
|
215
225
|
catch (error) {
|
|
216
|
-
|
|
226
|
+
if (error instanceof Error) {
|
|
227
|
+
return { error: new ParseError(`Failed to parse interest by region response: ${error.message}`) };
|
|
228
|
+
}
|
|
229
|
+
return { error: new ParseError('Failed to parse interest by region response') };
|
|
217
230
|
}
|
|
218
231
|
}
|
|
219
232
|
async relatedTopics({ keyword, geo = 'US', time = 'now 1-d', category = 0, property = '', hl = 'en-US', }) {
|
|
220
233
|
try {
|
|
221
234
|
// Validate keyword
|
|
222
235
|
if (!keyword || keyword.trim() === '') {
|
|
223
|
-
return { error: new
|
|
236
|
+
return { error: new InvalidRequestError('Keyword is required') };
|
|
224
237
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
238
|
+
// Step 1: Call explore to get widget data and token
|
|
239
|
+
const exploreResponse = await this.explore({
|
|
240
|
+
keyword,
|
|
241
|
+
geo,
|
|
242
|
+
time,
|
|
243
|
+
category,
|
|
244
|
+
property,
|
|
245
|
+
hl
|
|
246
|
+
});
|
|
247
|
+
if ('error' in exploreResponse) {
|
|
248
|
+
return { error: exploreResponse.error };
|
|
228
249
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
250
|
+
if (!exploreResponse.widgets || exploreResponse.widgets.length === 0) {
|
|
251
|
+
return { error: new ParseError('No widgets found in explore response. This might be due to Google blocking the request, invalid parameters, or network issues.') };
|
|
252
|
+
}
|
|
253
|
+
// Step 2: Find the related topics widget or use any available widget
|
|
254
|
+
const relatedTopicsWidget = exploreResponse.widgets.find(widget => widget.id === 'RELATED_TOPICS' ||
|
|
255
|
+
widget.request?.restriction?.complexKeywordsRestriction?.keyword?.[0]?.value === keyword) || exploreResponse.widgets[0]; // Fallback to first widget if no specific one found
|
|
256
|
+
if (!relatedTopicsWidget) {
|
|
257
|
+
return { error: new ParseError('No related topics widget found in explore response') };
|
|
258
|
+
}
|
|
259
|
+
// Step 3: Call the related topics API with or without token
|
|
260
|
+
const options = {
|
|
261
|
+
...GOOGLE_TRENDS_MAPPER[GoogleTrendsEndpoints.relatedTopics],
|
|
262
|
+
qs: {
|
|
263
|
+
hl,
|
|
264
|
+
tz: '240',
|
|
265
|
+
req: JSON.stringify({
|
|
266
|
+
restriction: {
|
|
267
|
+
geo: { country: geo },
|
|
268
|
+
time: time,
|
|
269
|
+
originalTimeRangeForExploreUrl: time,
|
|
270
|
+
complexKeywordsRestriction: {
|
|
271
|
+
keyword: [{
|
|
272
|
+
type: 'BROAD',
|
|
273
|
+
value: keyword
|
|
274
|
+
}]
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
keywordType: 'ENTITY',
|
|
278
|
+
metric: ['TOP', 'RISING'],
|
|
279
|
+
trendinessSettings: {
|
|
280
|
+
compareTime: time
|
|
281
|
+
},
|
|
282
|
+
requestOptions: {
|
|
283
|
+
property: property,
|
|
284
|
+
backend: 'CM',
|
|
285
|
+
category: category
|
|
286
|
+
},
|
|
287
|
+
language: hl.split('-')[0],
|
|
288
|
+
userCountryCode: geo,
|
|
289
|
+
userConfig: {
|
|
290
|
+
userType: 'USER_TYPE_LEGIT_USER'
|
|
291
|
+
}
|
|
292
|
+
}),
|
|
293
|
+
...(relatedTopicsWidget.token && { token: relatedTopicsWidget.token })
|
|
247
294
|
}
|
|
248
295
|
};
|
|
296
|
+
const response = await request(options.url, options);
|
|
297
|
+
const text = await response.text();
|
|
298
|
+
// Parse the response
|
|
299
|
+
try {
|
|
300
|
+
const data = JSON.parse(text.slice(5));
|
|
301
|
+
// Return the data in the expected format
|
|
302
|
+
return {
|
|
303
|
+
data: {
|
|
304
|
+
default: {
|
|
305
|
+
rankedList: data.default?.rankedList || []
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
catch (parseError) {
|
|
311
|
+
if (parseError instanceof Error) {
|
|
312
|
+
return { error: new ParseError(`Failed to parse related topics response: ${parseError.message}`) };
|
|
313
|
+
}
|
|
314
|
+
return { error: new ParseError('Failed to parse related topics response') };
|
|
315
|
+
}
|
|
249
316
|
}
|
|
250
317
|
catch (error) {
|
|
251
318
|
if (error instanceof Error) {
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export declare const
|
|
1
|
+
import { GoogleTrendsApi } from './helpers/googleTrendsAPI.js';
|
|
2
|
+
export declare const dailyTrends: ({ geo, lang }: import("./types/index.js").DailyTrendingTopicsOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").DailyTrendingTopics>>;
|
|
3
|
+
export declare const realTimeTrends: ({ geo, trendingHours }: import("./types/index.js").RealTimeTrendsOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").DailyTrendingTopics>>;
|
|
4
|
+
export declare const autocomplete: (keyword: string, hl?: string) => Promise<import("./types/index.js").GoogleTrendsResponse<string[]>>;
|
|
5
|
+
export declare const explore: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").ExploreResponse | {
|
|
6
|
+
error: import("./types/index.js").GoogleTrendsError;
|
|
7
|
+
}>;
|
|
8
|
+
export declare const interestByRegion: ({ keyword, startTime, endTime, geo, resolution, hl, timezone, category }: import("./types/index.js").InterestByRegionOptions) => Promise<import("./types/index.js").InterestByRegionResponse | {
|
|
9
|
+
error: import("./types/index.js").GoogleTrendsError;
|
|
10
|
+
}>;
|
|
11
|
+
export declare const relatedTopics: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedTopicsResponse>>;
|
|
12
|
+
export declare const relatedQueries: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedQueriesResponse>>;
|
|
13
|
+
export declare const relatedData: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedData>>;
|
|
14
|
+
export { GoogleTrendsApi };
|
|
9
15
|
declare const _default: {
|
|
10
|
-
dailyTrends: ({ geo, lang }: import("./types").DailyTrendingTopicsOptions) => Promise<import("./types").GoogleTrendsResponse<import("./types").DailyTrendingTopics>>;
|
|
11
|
-
realTimeTrends: ({ geo, trendingHours }: import("./types").RealTimeTrendsOptions) => Promise<import("./types").GoogleTrendsResponse<import("./types").DailyTrendingTopics>>;
|
|
12
|
-
autocomplete: (keyword: string, hl?: string) => Promise<import("./types").GoogleTrendsResponse<string[]>>;
|
|
13
|
-
explore: ({ keyword, geo, time, category, property, hl, }: import("./types").ExploreOptions) => Promise<import("./types").ExploreResponse
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
dailyTrends: ({ geo, lang }: import("./types/index.js").DailyTrendingTopicsOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").DailyTrendingTopics>>;
|
|
17
|
+
realTimeTrends: ({ geo, trendingHours }: import("./types/index.js").RealTimeTrendsOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").DailyTrendingTopics>>;
|
|
18
|
+
autocomplete: (keyword: string, hl?: string) => Promise<import("./types/index.js").GoogleTrendsResponse<string[]>>;
|
|
19
|
+
explore: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").ExploreResponse | {
|
|
20
|
+
error: import("./types/index.js").GoogleTrendsError;
|
|
21
|
+
}>;
|
|
22
|
+
interestByRegion: ({ keyword, startTime, endTime, geo, resolution, hl, timezone, category }: import("./types/index.js").InterestByRegionOptions) => Promise<import("./types/index.js").InterestByRegionResponse | {
|
|
23
|
+
error: import("./types/index.js").GoogleTrendsError;
|
|
24
|
+
}>;
|
|
25
|
+
relatedTopics: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedTopicsResponse>>;
|
|
26
|
+
relatedQueries: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedQueriesResponse>>;
|
|
27
|
+
relatedData: ({ keyword, geo, time, category, property, hl, }: import("./types/index.js").ExploreOptions) => Promise<import("./types/index.js").GoogleTrendsResponse<import("./types/index.js").RelatedData>>;
|
|
18
28
|
};
|
|
19
29
|
export default _default;
|
package/dist/esm/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GoogleTrendsApi } from './helpers/googleTrendsAPI';
|
|
1
|
+
import { GoogleTrendsApi } from './helpers/googleTrendsAPI.js';
|
|
2
2
|
const api = new GoogleTrendsApi();
|
|
3
3
|
export const dailyTrends = api.dailyTrends.bind(api);
|
|
4
4
|
export const realTimeTrends = api.realTimeTrends.bind(api);
|
|
@@ -8,6 +8,7 @@ export const interestByRegion = api.interestByRegion.bind(api);
|
|
|
8
8
|
export const relatedTopics = api.relatedTopics.bind(api);
|
|
9
9
|
export const relatedQueries = api.relatedQueries.bind(api);
|
|
10
10
|
export const relatedData = api.relatedData.bind(api);
|
|
11
|
+
export { GoogleTrendsApi };
|
|
11
12
|
// Default export for CommonJS compatibility
|
|
12
13
|
export default {
|
|
13
14
|
dailyTrends,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
package/package.json
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shaivpidadi/trends-js",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Google Trends API for Node.js",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
7
|
-
"types": "./dist/
|
|
7
|
+
"types": "./dist/cjs/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"import":
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/esm/index.d.ts",
|
|
12
|
+
"default": "./dist/esm/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/cjs/index.d.ts",
|
|
16
|
+
"default": "./dist/cjs/index.js"
|
|
17
|
+
}
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
"files": [
|
|
16
21
|
"dist"
|
|
17
22
|
],
|
|
18
23
|
"scripts": {
|
|
19
|
-
"build": "npm run build:esm && npm run build:cjs",
|
|
24
|
+
"build": "npm run build:esm && npm run build:cjs && npm run build:pkg",
|
|
20
25
|
"build:esm": "tsc -p tsconfig.json --outDir dist/esm",
|
|
21
|
-
"build:cjs": "tsc -p tsconfig.json --outDir dist/cjs --module commonjs",
|
|
26
|
+
"build:cjs": "tsc -p tsconfig.json --outDir dist/cjs --module commonjs --moduleResolution node",
|
|
27
|
+
"build:pkg": "echo '{\"type\":\"module\"}' > dist/esm/package.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
|
|
22
28
|
"test": "jest",
|
|
23
29
|
"prepare": "npm run build"
|
|
24
30
|
},
|