@rankwrangler/cli 0.1.2 → 0.2.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 +3 -2
- package/dist/index.js +55 -61
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -11,8 +11,9 @@ npm install -g @rankwrangler/cli
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
rw config set api-key rrk_...
|
|
15
|
+
rw products get B0DV53VS61
|
|
16
|
+
# `rankwrangler` is also supported as an alias
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
## Development
|
package/dist/index.js
CHANGED
|
@@ -11,18 +11,22 @@ const DEFAULT_MARKETPLACE_ID = 'ATVPDKIKX0DER';
|
|
|
11
11
|
const CONFIG_DIR = path.join(homedir(), '.rankwrangler');
|
|
12
12
|
const CONFIG_PATH = path.join(CONFIG_DIR, 'config.json');
|
|
13
13
|
const DEFAULT_OUTPUT_PRETTY = true;
|
|
14
|
+
const SUPPORTED_COMMANDS = new Set([
|
|
15
|
+
'products:get',
|
|
16
|
+
'api-key:status',
|
|
17
|
+
'api-key:validate',
|
|
18
|
+
'config:show',
|
|
19
|
+
'config:clear',
|
|
20
|
+
'config:set',
|
|
21
|
+
]);
|
|
14
22
|
const { positionals, values } = parseArgs({
|
|
15
23
|
args: process.argv.slice(2),
|
|
16
24
|
options: {
|
|
17
25
|
help: { type: 'boolean', short: 'h' },
|
|
18
26
|
apiKey: { type: 'string' },
|
|
19
|
-
licenseKey: { type: 'string' },
|
|
20
27
|
baseUrl: { type: 'string' },
|
|
21
|
-
url: { type: 'string' },
|
|
22
28
|
marketplace: { type: 'string', short: 'm' },
|
|
23
|
-
marketplaceId: { type: 'string' },
|
|
24
29
|
asin: { type: 'string', multiple: true },
|
|
25
|
-
asins: { type: 'string', multiple: true },
|
|
26
30
|
},
|
|
27
31
|
allowPositionals: true,
|
|
28
32
|
});
|
|
@@ -37,6 +41,10 @@ const main = async () => {
|
|
|
37
41
|
fail('UNKNOWN_COMMAND', 'Unknown command', { command: positionals.join(' ') });
|
|
38
42
|
return;
|
|
39
43
|
}
|
|
44
|
+
if (!isSupportedCommand(command)) {
|
|
45
|
+
fail('UNKNOWN_COMMAND', 'Unknown command', { command: `${command.resource} ${command.verb}` });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
40
48
|
const config = await loadConfig();
|
|
41
49
|
if (command.resource === 'config') {
|
|
42
50
|
const response = await runConfigCommand(command, config);
|
|
@@ -45,7 +53,7 @@ const main = async () => {
|
|
|
45
53
|
}
|
|
46
54
|
const apiKey = resolveApiKey(config);
|
|
47
55
|
if (!apiKey) {
|
|
48
|
-
fail('MISSING_CONFIG', '
|
|
56
|
+
fail('MISSING_CONFIG', 'API key is required. set via `config set api-key <value>`');
|
|
49
57
|
return;
|
|
50
58
|
}
|
|
51
59
|
const baseUrl = resolveBaseUrl(config);
|
|
@@ -65,11 +73,11 @@ const runApiCommand = async (command, client, config) => {
|
|
|
65
73
|
}
|
|
66
74
|
return client.getProductInfoBatch.mutate({ marketplaceId, asins });
|
|
67
75
|
}
|
|
68
|
-
if (command.resource === '
|
|
69
|
-
return client.
|
|
76
|
+
if (command.resource === 'api-key' && command.verb === 'status') {
|
|
77
|
+
return client.apiKey.status.mutate();
|
|
70
78
|
}
|
|
71
|
-
if (command.resource === '
|
|
72
|
-
return client.
|
|
79
|
+
if (command.resource === 'api-key' && command.verb === 'validate') {
|
|
80
|
+
return client.apiKey.validate.mutate();
|
|
73
81
|
}
|
|
74
82
|
fail('UNKNOWN_COMMAND', 'Unknown command', {
|
|
75
83
|
command: `${command.resource} ${command.verb}`,
|
|
@@ -108,7 +116,7 @@ const runConfigCommand = async (command, config) => {
|
|
|
108
116
|
else if (key === 'base-url') {
|
|
109
117
|
nextConfig.baseUrl = normalizeBaseUrl(value);
|
|
110
118
|
}
|
|
111
|
-
else if (key === 'marketplace'
|
|
119
|
+
else if (key === 'marketplace') {
|
|
112
120
|
nextConfig.marketplaceId = value;
|
|
113
121
|
}
|
|
114
122
|
else {
|
|
@@ -128,11 +136,7 @@ const runConfigCommand = async (command, config) => {
|
|
|
128
136
|
return null;
|
|
129
137
|
};
|
|
130
138
|
const requireMarketplaceId = (config) => {
|
|
131
|
-
const marketplaceId = values.marketplaceId ??
|
|
132
|
-
values.marketplace ??
|
|
133
|
-
config.marketplaceId ??
|
|
134
|
-
process.env.RR_MARKETPLACE_ID ??
|
|
135
|
-
DEFAULT_MARKETPLACE_ID;
|
|
139
|
+
const marketplaceId = values.marketplace ?? config.marketplaceId ?? process.env.RR_MARKETPLACE_ID ?? DEFAULT_MARKETPLACE_ID;
|
|
136
140
|
return marketplaceId;
|
|
137
141
|
};
|
|
138
142
|
const requireAsins = (commandArgs) => {
|
|
@@ -143,7 +147,7 @@ const requireAsins = (commandArgs) => {
|
|
|
143
147
|
return Array.from(new Set(candidates.map(normalizeAsin)));
|
|
144
148
|
};
|
|
145
149
|
const collectAsinCandidates = (commandArgs) => {
|
|
146
|
-
const optionAsins = [...(values.asin ?? [])
|
|
150
|
+
const optionAsins = [...(values.asin ?? [])];
|
|
147
151
|
const envAsins = process.env.RR_ASINS
|
|
148
152
|
? process.env.RR_ASINS.split(',').map(value => value.trim())
|
|
149
153
|
: [];
|
|
@@ -160,10 +164,10 @@ const normalizeAsin = (value) => {
|
|
|
160
164
|
return normalized;
|
|
161
165
|
};
|
|
162
166
|
const resolveApiKey = (config) => {
|
|
163
|
-
return values.apiKey ??
|
|
167
|
+
return values.apiKey ?? config.apiKey ?? process.env.RR_API_KEY;
|
|
164
168
|
};
|
|
165
169
|
const resolveBaseUrl = (config) => {
|
|
166
|
-
const configured = values.baseUrl ??
|
|
170
|
+
const configured = values.baseUrl ?? config.baseUrl ?? process.env.RR_API_URL;
|
|
167
171
|
return normalizeBaseUrl(configured ?? DEFAULT_API_BASE_URL);
|
|
168
172
|
};
|
|
169
173
|
const normalizeBaseUrl = (value) => {
|
|
@@ -177,32 +181,18 @@ const normalizeBaseUrl = (value) => {
|
|
|
177
181
|
};
|
|
178
182
|
const resolveCommand = (inputPositionals) => {
|
|
179
183
|
const [first, second, ...rest] = inputPositionals;
|
|
180
|
-
if (!first) {
|
|
181
|
-
return null;
|
|
182
|
-
}
|
|
183
|
-
if (first === 'get-product-info') {
|
|
184
|
-
return {
|
|
185
|
-
resource: 'products',
|
|
186
|
-
verb: 'get',
|
|
187
|
-
args: rest,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
if (first === 'get-product-info-batch') {
|
|
191
|
-
return {
|
|
192
|
-
resource: 'products',
|
|
193
|
-
verb: 'get',
|
|
194
|
-
args: rest,
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
if (!second) {
|
|
184
|
+
if (!first || !second) {
|
|
198
185
|
return null;
|
|
199
186
|
}
|
|
200
187
|
return {
|
|
201
188
|
resource: first,
|
|
202
|
-
verb:
|
|
189
|
+
verb: second,
|
|
203
190
|
args: rest,
|
|
204
191
|
};
|
|
205
192
|
};
|
|
193
|
+
const isSupportedCommand = (command) => {
|
|
194
|
+
return SUPPORTED_COMMANDS.has(`${command.resource}:${command.verb}`);
|
|
195
|
+
};
|
|
206
196
|
const loadConfig = async () => {
|
|
207
197
|
try {
|
|
208
198
|
const raw = await readFile(CONFIG_PATH, 'utf8');
|
|
@@ -275,40 +265,44 @@ const fail = (code, message, details) => {
|
|
|
275
265
|
};
|
|
276
266
|
const printUsage = () => {
|
|
277
267
|
const usage = [
|
|
278
|
-
'
|
|
279
|
-
'',
|
|
280
|
-
'Command Shape',
|
|
281
|
-
' rankwrangler <resource> <verb> [args...] [flags...]',
|
|
268
|
+
'NAME',
|
|
269
|
+
' rw, rankwrangler - RankWrangler command line interface',
|
|
282
270
|
'',
|
|
283
|
-
'
|
|
284
|
-
'
|
|
285
|
-
'
|
|
286
|
-
' - One command maps to one API capability',
|
|
271
|
+
'SYNOPSIS',
|
|
272
|
+
' rw <resource> <verb> [args...] [options]',
|
|
273
|
+
' rankwrangler <resource> <verb> [args...] [options]',
|
|
287
274
|
'',
|
|
288
|
-
'
|
|
289
|
-
' products get <ASIN...>
|
|
290
|
-
'
|
|
291
|
-
'
|
|
292
|
-
'',
|
|
293
|
-
'Config Commands',
|
|
275
|
+
'COMMANDS',
|
|
276
|
+
' products get <ASIN...>',
|
|
277
|
+
' api-key status',
|
|
278
|
+
' api-key validate',
|
|
294
279
|
' config show',
|
|
295
280
|
' config clear',
|
|
296
281
|
' config set api-key <value>',
|
|
297
282
|
' config set base-url <origin>',
|
|
298
283
|
' config set marketplace <marketplaceId>',
|
|
299
284
|
'',
|
|
300
|
-
'
|
|
301
|
-
' --
|
|
302
|
-
' --
|
|
303
|
-
|
|
304
|
-
|
|
285
|
+
'OPTIONS',
|
|
286
|
+
' -h, --help Show this help message',
|
|
287
|
+
' --apiKey <value> Override API key',
|
|
288
|
+
' --baseUrl <origin> Override API origin',
|
|
289
|
+
` -m, --marketplace <id> Override marketplace (default: ${DEFAULT_MARKETPLACE_ID})`,
|
|
305
290
|
' --asin <ASIN> Add ASIN (repeatable)',
|
|
306
|
-
' --asins <ASIN> Add ASIN (repeatable, compatibility alias)',
|
|
307
291
|
'',
|
|
308
|
-
'
|
|
309
|
-
|
|
310
|
-
'
|
|
311
|
-
'
|
|
292
|
+
'FILES',
|
|
293
|
+
` ${CONFIG_PATH} Local CLI config`,
|
|
294
|
+
'',
|
|
295
|
+
'ENVIRONMENT',
|
|
296
|
+
' RR_API_KEY API key fallback',
|
|
297
|
+
' RR_API_URL API origin fallback',
|
|
298
|
+
' RR_MARKETPLACE_ID Marketplace fallback',
|
|
299
|
+
' RR_ASIN Single ASIN fallback',
|
|
300
|
+
' RR_ASINS Comma-separated ASIN fallback',
|
|
301
|
+
'',
|
|
302
|
+
'EXAMPLES',
|
|
303
|
+
' rw config set api-key rrk_...',
|
|
304
|
+
' rw products get B0DV53VS61',
|
|
305
|
+
' rankwrangler api-key status',
|
|
312
306
|
];
|
|
313
307
|
console.log(usage.join('\n'));
|
|
314
308
|
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rankwrangler/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Official RankWrangler command line interface",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
+
"rw": "dist/index.js",
|
|
7
8
|
"rankwrangler": "dist/index.js"
|
|
8
9
|
},
|
|
9
10
|
"main": "./dist/index.js",
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
"access": "public"
|
|
20
21
|
},
|
|
21
22
|
"dependencies": {
|
|
22
|
-
"@rankwrangler/http-client": "^0.
|
|
23
|
+
"@rankwrangler/http-client": "^0.2.0"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"@types/node": "^24.3.0",
|