@vinitngr/serper-v 1.0.1 → 1.0.3

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 +14 -8
  2. package/dist/index.js +110 -25
  3. package/package.json +3 -2
package/SKILL.md CHANGED
@@ -1,23 +1,29 @@
1
1
  ---
2
2
  name: serper
3
- description: Real-time search (news, places, organic, scholar) via Serper API.
3
+ description: Advanced search (organic, places, news, 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 --query "Term" --type [type] --limit 10 --tbs qdr:h
11
+ serperV scrape --url "url1, url2"
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
+ - **Types**: `search` (default), `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
+ - `-q` / `--query`: Search query.
18
+ - `-u` / `--url`: Comma-separated URLs for bulk scraping.
19
+ - `-t` / `--type`: Endpoint selection.
17
20
  - `-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`).
21
+ - `-g` / `--gl`: Country code.
22
+ - `-h` / `--hl`: Language code.
20
23
  - `-p` / `--page`: Pagination number.
21
24
 
22
25
  ## Installation
23
26
  `npm install -g @vinitngr/serper-v --force`
27
+
28
+ ## Auth
29
+ `serperV auth <key>` (saves to `~/.vinit/credentials.json`) or `export SERPER_API_KEY=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,25 +97,112 @@ 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.4.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 content (one or more URLs)
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
  }
@@ -114,7 +212,12 @@ else if (command === 'search') {
114
212
  res.on('data', (chunk) => body += chunk);
115
213
  res.on('end', () => {
116
214
  if (res.statusCode === 200) {
117
- process.stdout.write(JSON.stringify(JSON.parse(body), null, 2) + '\n');
215
+ try {
216
+ process.stdout.write(JSON.stringify(JSON.parse(body), null, 2) + '\n');
217
+ }
218
+ catch (e) {
219
+ process.stdout.write(body + '\n');
220
+ }
118
221
  }
119
222
  else {
120
223
  const errorMsg = res.statusCode === 401 || res.statusCode === 403
@@ -134,21 +237,3 @@ else if (command === 'search') {
134
237
  req.write(data);
135
238
  req.end();
136
239
  }
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.3",
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",