@vinitngr/serper-v 1.0.1 → 1.0.5

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 (3) hide show
  1. package/SKILL.md +16 -12
  2. package/dist/index.js +115 -28
  3. package/package.json +3 -2
package/SKILL.md CHANGED
@@ -1,23 +1,27 @@
1
1
  ---
2
2
  name: serper
3
- description: Real-time search (news, places, organic, scholar) via Serper API.
3
+ description: Professional search (news, places, maps, reviews, scholar, patents) and bulk scraping via Serper API.
4
4
  ---
5
5
 
6
6
  # Serper Search
7
7
 
8
8
  ## Usage
9
9
  ```bash
10
- serperV search --query "Term" --type [type] --limit 10
10
+ serperV search -q "Apple Inc" -t search --tbs qdr:h --page 3
11
+ serperV scrape -u "https://site1.com, https://site2.com"
11
12
  ```
12
- - **Auth**: `serperV auth <key>` (saves to `~/.vinit/credentials.json`) or `export SERPER_API_KEY=key`.
13
- - **Types**: `search` (default), `news`, `places`, `images`, `scholar`, `videos`, `shopping`.
13
+
14
+ - **All Types**: `search`, `places`, `maps`, `news`, `shopping`, `scholar`, `patents`.
15
+ - **Date Range (`--tbs`)**: `qdr:h` (hour), `qdr:d` (day), `qdr:w` (week), `qdr:m` (month), `qdr:y` (year).
14
16
  - **Flags**:
15
- - `-q` / `--query`: Search term.
16
- - `-t` / `--type`: Endpoint (news, images, etc.).
17
- - `-l` / `--limit`: Number of results (max 100).
18
- - `-g` / `--gl`: Country code (e.g., `in`, `us`).
19
- - `-h` / `--hl`: Language code (e.g., `en`, `hi`).
20
- - `-p` / `--page`: Pagination number.
17
+ - `-q` / `--query`: Search query (autocorrect enabled by default).
18
+ - `-u` / `--url`: One or more URLs (comma-separated).
19
+ - `-t` / `--type`: Endpoint (Default: `search`).
20
+ - `-l` / `--limit`: Number of results.
21
+ - `-g` / `--gl`: Country code.
22
+ - `-h` / `--hl`: Language code.
23
+ - `-p` / `--page`: Specific result page.
21
24
 
22
- ## Installation
23
- `npm install -g @vinitngr/serper-v --force`
25
+ ## Setup
26
+ 1. `npm install -g @vinitngr/serper-v --force`
27
+ 2. `serperV auth <api_key>`
package/dist/index.js CHANGED
@@ -18,12 +18,14 @@ function getStoredApiKey() {
18
18
  function parseArgs(args) {
19
19
  const options = {
20
20
  query: '',
21
+ url: '',
21
22
  limit: 10,
22
23
  type: 'search',
23
24
  gl: 'us',
24
25
  hl: 'en',
25
26
  page: 1,
26
- autocorrect: true
27
+ autocorrect: true,
28
+ tbs: ''
27
29
  };
28
30
  for (let i = 0; i < args.length; i++) {
29
31
  const arg = args[i];
@@ -32,6 +34,10 @@ function parseArgs(args) {
32
34
  options.query = nextArg;
33
35
  i++;
34
36
  }
37
+ else if (arg === '-u' || arg === '--url') {
38
+ options.url = nextArg;
39
+ i++;
40
+ }
35
41
  else if (arg === '-l' || arg === '--limit') {
36
42
  options.limit = parseInt(nextArg);
37
43
  i++;
@@ -56,11 +62,16 @@ function parseArgs(args) {
56
62
  options.autocorrect = nextArg === 'true';
57
63
  i++;
58
64
  }
65
+ else if (arg === '--tbs') {
66
+ options.tbs = nextArg;
67
+ i++;
68
+ }
59
69
  }
60
70
  return options;
61
71
  }
62
72
  const args = process.argv.slice(2);
63
73
  const command = args[0];
74
+ const apiKey = process.env.SERPER_API_KEY || getStoredApiKey();
64
75
  if (command === 'auth') {
65
76
  const key = args[1];
66
77
  if (!key) {
@@ -86,35 +97,128 @@ else if (command === 'search') {
86
97
  console.error('\n❌ Error: Query required. Use -q or --query\n');
87
98
  process.exit(1);
88
99
  }
89
- const apiKey = process.env.SERPER_API_KEY || getStoredApiKey();
90
100
  if (!apiKey) {
91
101
  console.error('\n❌ Error: Serper API key not found. Run: serperV auth <key>\n');
92
102
  process.exit(1);
93
103
  }
94
- const data = JSON.stringify({
104
+ const payload = {
95
105
  q: options.query,
96
106
  num: options.limit,
97
107
  gl: options.gl,
98
108
  hl: options.hl,
99
109
  page: options.page,
100
110
  autocorrect: options.autocorrect
101
- });
111
+ };
112
+ if (options.tbs)
113
+ payload.tbs = options.tbs;
114
+ makeRequest(`/${options.type}`, JSON.stringify(payload));
115
+ }
116
+ else if (command === 'scrape') {
117
+ const options = parseArgs(args.slice(1));
118
+ if (!options.url) {
119
+ console.error('\n❌ Error: URL required. Use -u or --url\n');
120
+ process.exit(1);
121
+ }
122
+ if (!apiKey) {
123
+ console.error('\n❌ Error: Serper API key not found. Run: serperV auth <key>\n');
124
+ process.exit(1);
125
+ }
126
+ const urls = options.url.split(',').map((u) => u.trim());
127
+ if (urls.length === 1) {
128
+ makeRequest('/scrape', JSON.stringify({ url: urls[0] }));
129
+ }
130
+ else {
131
+ // Bulk scraping
132
+ process.stdout.write('[\n');
133
+ const processNext = (index) => {
134
+ if (index >= urls.length) {
135
+ process.stdout.write('\n]\n');
136
+ return;
137
+ }
138
+ const data = JSON.stringify({ url: urls[index] });
139
+ const req = https.request({
140
+ hostname: 'google.serper.dev',
141
+ path: '/scrape',
142
+ method: 'POST',
143
+ headers: {
144
+ 'X-API-KEY': apiKey || '',
145
+ 'Content-Type': 'application/json',
146
+ 'Content-Length': data.length
147
+ }
148
+ }, (res) => {
149
+ let body = '';
150
+ res.on('data', (chunk) => body += chunk);
151
+ res.on('end', () => {
152
+ try {
153
+ process.stdout.write(JSON.stringify(JSON.parse(body), null, 2));
154
+ if (index < urls.length - 1)
155
+ process.stdout.write(',\n');
156
+ processNext(index + 1);
157
+ }
158
+ catch (e) {
159
+ console.error(`\n❌ Error parsing response for ${urls[index]}`);
160
+ processNext(index + 1);
161
+ }
162
+ });
163
+ });
164
+ req.on('error', (err) => {
165
+ console.error(`\n❌ Request failed for ${urls[index]}:`, err.message);
166
+ processNext(index + 1);
167
+ });
168
+ req.write(data);
169
+ req.end();
170
+ };
171
+ processNext(0);
172
+ }
173
+ }
174
+ else {
175
+ console.log(`
176
+ Optimal Serper CLI (Zero Dependencies) - v2.5.0
177
+
178
+ Usage:
179
+ serperV auth <key> Store API key
180
+ serperV search [options] Search (places, news, scholar, etc.)
181
+ serperV scrape [options] Scrape website content
182
+
183
+ Options:
184
+ -q, --query <string> Search query
185
+ -u, --url <string> URL(s) to scrape (comma-separated for bulk)
186
+ -t, --type <string> Endpoint (search, places, maps, news, shopping, scholar, patents)
187
+ -l, --limit <number> Result limit (Default 10)
188
+ -g, --gl <string> Country code (Default 'us')
189
+ -h, --hl <string> Language code (Default 'en')
190
+ -p, --page <number> Page number
191
+ -a, --autocorrect <bool>
192
+ --tbs <string> Date range (e.g. qdr:h, qdr:d, qdr:w, qdr:m, qdr:y)
193
+
194
+ Examples:
195
+ serperV search -q "Apple" --tbs qdr:h
196
+ serperV scrape -u "https://google.com, https://apple.com"
197
+ `);
198
+ }
199
+ function makeRequest(path, data) {
102
200
  const reqOptions = {
103
201
  hostname: 'google.serper.dev',
104
- path: `/${options.type}`,
202
+ path: path,
105
203
  method: 'POST',
106
204
  headers: {
107
- 'X-API-KEY': apiKey,
205
+ 'X-API-KEY': apiKey || '',
108
206
  'Content-Type': 'application/json',
109
207
  'Content-Length': data.length
110
- }
208
+ },
209
+ timeout: 30000
111
210
  };
112
211
  const req = https.request(reqOptions, (res) => {
113
212
  let body = '';
114
213
  res.on('data', (chunk) => body += chunk);
115
214
  res.on('end', () => {
116
215
  if (res.statusCode === 200) {
117
- process.stdout.write(JSON.stringify(JSON.parse(body), null, 2) + '\n');
216
+ try {
217
+ process.stdout.write(JSON.stringify(JSON.parse(body), null, 2) + '\n');
218
+ }
219
+ catch (e) {
220
+ process.stdout.write(body + '\n');
221
+ }
118
222
  }
119
223
  else {
120
224
  const errorMsg = res.statusCode === 401 || res.statusCode === 403
@@ -127,28 +231,11 @@ else if (command === 'search') {
127
231
  }
128
232
  });
129
233
  });
130
- req.on('error', (err) => {
131
- console.error('\n❌ Request failed:', err.message);
234
+ req.on('timeout', () => {
235
+ req.destroy();
236
+ console.error('\n❌ Request timed out after 30 seconds');
132
237
  process.exit(1);
133
238
  });
134
239
  req.write(data);
135
240
  req.end();
136
241
  }
137
- else {
138
- console.log(`
139
- Optimal Serper CLI (Zero Dependencies) - v2.2.0
140
-
141
- Usage:
142
- serperV auth <key> Store API key
143
- serperV search [options] Search the web
144
-
145
- Options:
146
- -q, --query <string> Search query (Required)
147
- -l, --limit <number> Result limit (Default 10)
148
- -t, --type <string> Type (search, news, places, etc.)
149
- -g, --gl <string> Country code (Default 'us')
150
- -h, --hl <string> Language code (Default 'en')
151
- -p, --page <number> Page number
152
- -a, --autocorrect <bool>
153
- `);
154
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vinitngr/serper-v",
3
- "version": "1.0.1",
3
+ "version": "1.0.5",
4
4
  "description": "Optimal Serper Search CLI for AI Agents",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -14,7 +14,8 @@
14
14
  "scripts": {
15
15
  "build": "tsc && chmod +x dist/index.js",
16
16
  "test": "echo \"Error: no test specified\" && exit 1",
17
- "test:search": "node test-serper.js"
17
+ "test:search": "node test-serper.js",
18
+ "test:all": "node test-all.js"
18
19
  },
19
20
  "keywords": [
20
21
  "serper",