@01.software/cli 0.2.0-dev.260310.cf511cb → 0.3.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/dist/index.js +521 -141
- package/dist/index.js.map +1 -1
- package/package.json +7 -4
package/dist/index.js
CHANGED
|
@@ -5,11 +5,24 @@ import { createRequire } from "module";
|
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
|
|
7
7
|
// src/lib/client.ts
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
CollectionClient,
|
|
10
|
+
OrderApi,
|
|
11
|
+
CartApi,
|
|
12
|
+
ProductApi,
|
|
13
|
+
parseApiKey
|
|
14
|
+
} from "@01.software/sdk";
|
|
9
15
|
import pc from "picocolors";
|
|
10
16
|
|
|
11
17
|
// src/lib/credentials.ts
|
|
12
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
existsSync,
|
|
20
|
+
mkdirSync,
|
|
21
|
+
readFileSync,
|
|
22
|
+
writeFileSync,
|
|
23
|
+
unlinkSync,
|
|
24
|
+
appendFileSync
|
|
25
|
+
} from "fs";
|
|
13
26
|
import { join } from "path";
|
|
14
27
|
import { homedir } from "os";
|
|
15
28
|
var DIR_NAME = ".01software";
|
|
@@ -27,8 +40,14 @@ function saveCredentials(creds) {
|
|
|
27
40
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
28
41
|
}
|
|
29
42
|
const filePath = getCredentialsPath();
|
|
30
|
-
const data = {
|
|
31
|
-
|
|
43
|
+
const data = {
|
|
44
|
+
...creds,
|
|
45
|
+
storedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
46
|
+
};
|
|
47
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2), {
|
|
48
|
+
encoding: "utf-8",
|
|
49
|
+
mode: 384
|
|
50
|
+
});
|
|
32
51
|
}
|
|
33
52
|
function deleteCredentials() {
|
|
34
53
|
const filePath = getCredentialsPath();
|
|
@@ -48,8 +67,14 @@ function saveLocalCredentials(creds) {
|
|
|
48
67
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
49
68
|
}
|
|
50
69
|
const filePath = getLocalCredentialsPath();
|
|
51
|
-
const data = {
|
|
52
|
-
|
|
70
|
+
const data = {
|
|
71
|
+
...creds,
|
|
72
|
+
storedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
73
|
+
};
|
|
74
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2), {
|
|
75
|
+
encoding: "utf-8",
|
|
76
|
+
mode: 384
|
|
77
|
+
});
|
|
53
78
|
ensureGitignore();
|
|
54
79
|
}
|
|
55
80
|
function saveTenantList(tenants) {
|
|
@@ -58,7 +83,10 @@ function saveTenantList(tenants) {
|
|
|
58
83
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
59
84
|
}
|
|
60
85
|
const filePath = join(homedir(), DIR_NAME, TENANTS_FILE);
|
|
61
|
-
writeFileSync(filePath, JSON.stringify(tenants, null, 2), {
|
|
86
|
+
writeFileSync(filePath, JSON.stringify(tenants, null, 2), {
|
|
87
|
+
encoding: "utf-8",
|
|
88
|
+
mode: 384
|
|
89
|
+
});
|
|
62
90
|
}
|
|
63
91
|
function loadTenantList() {
|
|
64
92
|
const filePath = join(homedir(), DIR_NAME, TENANTS_FILE);
|
|
@@ -111,8 +139,12 @@ function resolveClient(apiKeyFlag) {
|
|
|
111
139
|
clientKey = parsed.clientKey;
|
|
112
140
|
secretKey = parsed.secretKey;
|
|
113
141
|
} catch {
|
|
114
|
-
console.error(
|
|
115
|
-
|
|
142
|
+
console.error(
|
|
143
|
+
pc.red(
|
|
144
|
+
'Invalid --api-key value. Expected Base64-encoded "clientKey:secretKey".'
|
|
145
|
+
)
|
|
146
|
+
);
|
|
147
|
+
process.exit(2);
|
|
116
148
|
}
|
|
117
149
|
} else {
|
|
118
150
|
clientKey = process.env.SOFTWARE_CLIENT_KEY;
|
|
@@ -139,14 +171,16 @@ function resolveClient(apiKeyFlag) {
|
|
|
139
171
|
'Run "01 login" to authenticate via browser,\nor set SOFTWARE_CLIENT_KEY and SOFTWARE_SECRET_KEY environment variables,\nor use the --api-key <base64> flag.'
|
|
140
172
|
)
|
|
141
173
|
);
|
|
142
|
-
process.exit(
|
|
174
|
+
process.exit(2);
|
|
143
175
|
}
|
|
144
176
|
const apiOpts = { clientKey, secretKey };
|
|
145
177
|
return {
|
|
146
178
|
collections: new CollectionClient(clientKey, secretKey),
|
|
147
179
|
api: new OrderApi(apiOpts),
|
|
148
180
|
cart: new CartApi(apiOpts),
|
|
149
|
-
product: new ProductApi(apiOpts)
|
|
181
|
+
product: new ProductApi(apiOpts),
|
|
182
|
+
clientKey,
|
|
183
|
+
secretKey
|
|
150
184
|
};
|
|
151
185
|
}
|
|
152
186
|
|
|
@@ -163,13 +197,22 @@ function printTable(data) {
|
|
|
163
197
|
}
|
|
164
198
|
const keys = Object.keys(data[0]);
|
|
165
199
|
const widths = keys.map(
|
|
166
|
-
(k) => Math.max(
|
|
200
|
+
(k) => Math.max(
|
|
201
|
+
k.length,
|
|
202
|
+
...data.map(
|
|
203
|
+
(row) => String(row[k] ?? "").length
|
|
204
|
+
)
|
|
205
|
+
)
|
|
167
206
|
);
|
|
168
207
|
console.log(keys.map((k, i) => k.padEnd(widths[i])).join(" "));
|
|
169
208
|
console.log(keys.map((_, i) => "-".repeat(widths[i])).join(" "));
|
|
170
209
|
for (const row of data) {
|
|
171
210
|
console.log(
|
|
172
|
-
keys.map(
|
|
211
|
+
keys.map(
|
|
212
|
+
(k, i) => String(row[k] ?? "").padEnd(
|
|
213
|
+
widths[i]
|
|
214
|
+
)
|
|
215
|
+
).join(" ")
|
|
173
216
|
);
|
|
174
217
|
}
|
|
175
218
|
} else if (data && typeof data === "object") {
|
|
@@ -183,13 +226,31 @@ function printTable(data) {
|
|
|
183
226
|
console.log(String(data));
|
|
184
227
|
}
|
|
185
228
|
}
|
|
229
|
+
function printNdjson(data) {
|
|
230
|
+
if (Array.isArray(data)) {
|
|
231
|
+
data.forEach((item) => console.log(JSON.stringify(item)));
|
|
232
|
+
} else if (data && typeof data === "object" && "docs" in data) {
|
|
233
|
+
const { docs, ...meta } = data;
|
|
234
|
+
docs.forEach((doc) => console.log(JSON.stringify(doc)));
|
|
235
|
+
if (Object.keys(meta).length > 0)
|
|
236
|
+
console.log(JSON.stringify({ _meta: meta }));
|
|
237
|
+
} else {
|
|
238
|
+
console.log(JSON.stringify(data));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
186
241
|
function printResult(data, format) {
|
|
187
|
-
if (format === "
|
|
242
|
+
if (format === "ndjson") {
|
|
243
|
+
printNdjson(data);
|
|
244
|
+
} else if (format === "table") {
|
|
188
245
|
if (data && typeof data === "object" && "docs" in data) {
|
|
189
246
|
const resp = data;
|
|
190
247
|
printTable(resp.docs);
|
|
191
|
-
console.log(
|
|
192
|
-
|
|
248
|
+
console.log(
|
|
249
|
+
pc2.dim(
|
|
250
|
+
`
|
|
251
|
+
${resp.totalDocs} total | page ${resp.page}/${resp.totalPages}`
|
|
252
|
+
)
|
|
253
|
+
);
|
|
193
254
|
return;
|
|
194
255
|
}
|
|
195
256
|
printTable(data);
|
|
@@ -197,6 +258,26 @@ ${resp.totalDocs} total | page ${resp.page}/${resp.totalPages}`));
|
|
|
197
258
|
printJson(data);
|
|
198
259
|
}
|
|
199
260
|
}
|
|
261
|
+
function getExitCode(error) {
|
|
262
|
+
if (!error || typeof error !== "object") return 1;
|
|
263
|
+
const err = error;
|
|
264
|
+
if (err.name === "ConfigError") return 2;
|
|
265
|
+
if (err.name === "ValidationError") return 3;
|
|
266
|
+
if (err.name === "NetworkError" || err.name === "TimeoutError") return 4;
|
|
267
|
+
if (err.name === "GoneError") return 5;
|
|
268
|
+
if (err.name === "UsageLimitError") return 6;
|
|
269
|
+
const s = err.status;
|
|
270
|
+
if (s === 401) return 2;
|
|
271
|
+
if (s === 400 || s === 422) return 3;
|
|
272
|
+
if (s === 408 || s === 503) return 4;
|
|
273
|
+
if (s === 404) return 5;
|
|
274
|
+
if (s === 429) return 6;
|
|
275
|
+
return 1;
|
|
276
|
+
}
|
|
277
|
+
function exitWithError(error) {
|
|
278
|
+
printError(error);
|
|
279
|
+
process.exit(getExitCode(error));
|
|
280
|
+
}
|
|
200
281
|
function printError(error) {
|
|
201
282
|
if (error && typeof error === "object" && "message" in error) {
|
|
202
283
|
const err = error;
|
|
@@ -221,12 +302,12 @@ function parseJson(value, label) {
|
|
|
221
302
|
const parsed = JSON.parse(value);
|
|
222
303
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
223
304
|
console.error(pc3.red(`--${label} must be a JSON object.`));
|
|
224
|
-
process.exit(
|
|
305
|
+
process.exit(3);
|
|
225
306
|
}
|
|
226
307
|
return parsed;
|
|
227
308
|
} catch {
|
|
228
309
|
console.error(pc3.red(`Invalid JSON for --${label}: ${value}`));
|
|
229
|
-
process.exit(
|
|
310
|
+
process.exit(3);
|
|
230
311
|
}
|
|
231
312
|
}
|
|
232
313
|
function parseJsonArray(value, label) {
|
|
@@ -234,12 +315,12 @@ function parseJsonArray(value, label) {
|
|
|
234
315
|
const parsed = JSON.parse(value);
|
|
235
316
|
if (!Array.isArray(parsed)) {
|
|
236
317
|
console.error(pc3.red(`--${label} must be a JSON array.`));
|
|
237
|
-
process.exit(
|
|
318
|
+
process.exit(3);
|
|
238
319
|
}
|
|
239
320
|
return parsed;
|
|
240
321
|
} catch {
|
|
241
322
|
console.error(pc3.red(`Invalid JSON for --${label}: ${value}`));
|
|
242
|
-
process.exit(
|
|
323
|
+
process.exit(3);
|
|
243
324
|
}
|
|
244
325
|
}
|
|
245
326
|
|
|
@@ -264,7 +345,11 @@ function parseSelect(input) {
|
|
|
264
345
|
return Object.fromEntries(input.split(",").map((f) => [f.trim(), true]));
|
|
265
346
|
}
|
|
266
347
|
function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
267
|
-
program2.command("query <collection>").description("Query documents from a collection").option("--where <json>", "Filter conditions (JSON)").option("--limit <n>", "Max results", (v) => parseInt(v, 10)).option("--page <n>", "Page number", (v) => parseInt(v, 10)).option("--sort <field>", "Sort field (prefix with - for descending)").option(
|
|
348
|
+
program2.command("query <collection>").description("Query documents from a collection").option("--where <json>", "Filter conditions (JSON)").option("--limit <n>", "Max results", (v) => parseInt(v, 10)).option("--page <n>", "Page number", (v) => parseInt(v, 10)).option("--sort <field>", "Sort field (prefix with - for descending)").option(
|
|
349
|
+
"--depth <n>",
|
|
350
|
+
"Relationship depth (0 = no population)",
|
|
351
|
+
(v) => parseInt(v, 10)
|
|
352
|
+
).option("--select <fields>", "Comma-separated fields to select").action(async (collection, opts) => {
|
|
268
353
|
try {
|
|
269
354
|
const col = validateCollection(collection);
|
|
270
355
|
const client = getClient2();
|
|
@@ -278,11 +363,14 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
278
363
|
const result = await client.collections.from(col).find(options);
|
|
279
364
|
printResult(result, getFormat2());
|
|
280
365
|
} catch (e) {
|
|
281
|
-
|
|
282
|
-
process.exit(1);
|
|
366
|
+
exitWithError(e);
|
|
283
367
|
}
|
|
284
368
|
});
|
|
285
|
-
program2.command("get <collection> <id>").description("Get a document by ID").option(
|
|
369
|
+
program2.command("get <collection> <id>").description("Get a document by ID").option(
|
|
370
|
+
"--depth <n>",
|
|
371
|
+
"Relationship depth (0 = no population)",
|
|
372
|
+
(v) => parseInt(v, 10)
|
|
373
|
+
).option("--select <fields>", "Comma-separated fields to select").action(async (collection, id, opts) => {
|
|
286
374
|
try {
|
|
287
375
|
const col = validateCollection(collection);
|
|
288
376
|
const client = getClient2();
|
|
@@ -292,15 +380,27 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
292
380
|
const result = await client.collections.from(col).findById(id, options);
|
|
293
381
|
printResult(result, getFormat2());
|
|
294
382
|
} catch (e) {
|
|
295
|
-
|
|
296
|
-
process.exit(1);
|
|
383
|
+
exitWithError(e);
|
|
297
384
|
}
|
|
298
385
|
});
|
|
299
|
-
program2.command("create <collection>").description("Create a new document").requiredOption("--data <json>", "Document data (JSON)").option("--file <path>", "File to upload (for upload collections)").action(async (collection, opts) => {
|
|
386
|
+
program2.command("create <collection>").description("Create a new document").requiredOption("--data <json>", "Document data (JSON)").option("--file <path>", "File to upload (for upload collections)").option("--dry-run", "Validate inputs without executing").action(async (collection, opts) => {
|
|
300
387
|
try {
|
|
301
388
|
const col = validateCollection(collection);
|
|
302
|
-
const client = getClient2();
|
|
303
389
|
const data = parseJson(opts.data, "data");
|
|
390
|
+
if (opts.dryRun) {
|
|
391
|
+
printResult(
|
|
392
|
+
{
|
|
393
|
+
dryRun: true,
|
|
394
|
+
valid: true,
|
|
395
|
+
action: "create",
|
|
396
|
+
collection: col,
|
|
397
|
+
data
|
|
398
|
+
},
|
|
399
|
+
getFormat2()
|
|
400
|
+
);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const client = getClient2();
|
|
304
404
|
let fileOpts;
|
|
305
405
|
if (opts.file) {
|
|
306
406
|
const { blob, filename } = readFileAsBlob(opts.file);
|
|
@@ -309,15 +409,28 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
309
409
|
const result = await client.collections.from(col).create(data, fileOpts);
|
|
310
410
|
printResult(result, getFormat2());
|
|
311
411
|
} catch (e) {
|
|
312
|
-
|
|
313
|
-
process.exit(1);
|
|
412
|
+
exitWithError(e);
|
|
314
413
|
}
|
|
315
414
|
});
|
|
316
|
-
program2.command("update <collection> <id>").description("Update a document by ID").requiredOption("--data <json>", "Document data (JSON)").option("--file <path>", "File to upload (for upload collections)").action(async (collection, id, opts) => {
|
|
415
|
+
program2.command("update <collection> <id>").description("Update a document by ID").requiredOption("--data <json>", "Document data (JSON)").option("--file <path>", "File to upload (for upload collections)").option("--dry-run", "Validate inputs without executing").action(async (collection, id, opts) => {
|
|
317
416
|
try {
|
|
318
417
|
const col = validateCollection(collection);
|
|
319
|
-
const client = getClient2();
|
|
320
418
|
const data = parseJson(opts.data, "data");
|
|
419
|
+
if (opts.dryRun) {
|
|
420
|
+
printResult(
|
|
421
|
+
{
|
|
422
|
+
dryRun: true,
|
|
423
|
+
valid: true,
|
|
424
|
+
action: "update",
|
|
425
|
+
collection: col,
|
|
426
|
+
id,
|
|
427
|
+
data
|
|
428
|
+
},
|
|
429
|
+
getFormat2()
|
|
430
|
+
);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
const client = getClient2();
|
|
321
434
|
let fileOpts;
|
|
322
435
|
if (opts.file) {
|
|
323
436
|
const { blob, filename } = readFileAsBlob(opts.file);
|
|
@@ -326,44 +439,80 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
326
439
|
const result = await client.collections.from(col).update(id, data, fileOpts);
|
|
327
440
|
printResult(result, getFormat2());
|
|
328
441
|
} catch (e) {
|
|
329
|
-
|
|
330
|
-
process.exit(1);
|
|
442
|
+
exitWithError(e);
|
|
331
443
|
}
|
|
332
444
|
});
|
|
333
|
-
program2.command("delete <collection> <id>").description("Delete a document by ID").action(async (collection, id) => {
|
|
445
|
+
program2.command("delete <collection> <id>").description("Delete a document by ID").option("--dry-run", "Validate inputs without executing").action(async (collection, id, opts) => {
|
|
334
446
|
try {
|
|
335
447
|
const col = validateCollection(collection);
|
|
448
|
+
if (opts.dryRun) {
|
|
449
|
+
printResult(
|
|
450
|
+
{
|
|
451
|
+
dryRun: true,
|
|
452
|
+
valid: true,
|
|
453
|
+
action: "delete",
|
|
454
|
+
collection: col,
|
|
455
|
+
id
|
|
456
|
+
},
|
|
457
|
+
getFormat2()
|
|
458
|
+
);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
336
461
|
const client = getClient2();
|
|
337
462
|
const result = await client.collections.from(col).remove(id);
|
|
338
463
|
printResult(result, getFormat2());
|
|
339
464
|
} catch (e) {
|
|
340
|
-
|
|
341
|
-
process.exit(1);
|
|
465
|
+
exitWithError(e);
|
|
342
466
|
}
|
|
343
467
|
});
|
|
344
|
-
program2.command("update-many <collection>").description("Update multiple documents matching a filter").requiredOption("--where <json>", "Filter conditions (JSON)").requiredOption("--data <json>", "Update data (JSON)").action(async (collection, opts) => {
|
|
468
|
+
program2.command("update-many <collection>").description("Update multiple documents matching a filter").requiredOption("--where <json>", "Filter conditions (JSON)").requiredOption("--data <json>", "Update data (JSON)").option("--dry-run", "Validate inputs without executing").action(async (collection, opts) => {
|
|
345
469
|
try {
|
|
346
470
|
const col = validateCollection(collection);
|
|
347
|
-
const client = getClient2();
|
|
348
471
|
const where = parseJson(opts.where, "where");
|
|
349
472
|
const data = parseJson(opts.data, "data");
|
|
473
|
+
if (opts.dryRun) {
|
|
474
|
+
printResult(
|
|
475
|
+
{
|
|
476
|
+
dryRun: true,
|
|
477
|
+
valid: true,
|
|
478
|
+
action: "update-many",
|
|
479
|
+
collection: col,
|
|
480
|
+
where,
|
|
481
|
+
data
|
|
482
|
+
},
|
|
483
|
+
getFormat2()
|
|
484
|
+
);
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const client = getClient2();
|
|
350
488
|
const result = await client.collections.from(col).updateMany(where, data);
|
|
351
489
|
printResult(result, getFormat2());
|
|
352
490
|
} catch (e) {
|
|
353
|
-
|
|
354
|
-
process.exit(1);
|
|
491
|
+
exitWithError(e);
|
|
355
492
|
}
|
|
356
493
|
});
|
|
357
|
-
program2.command("delete-many <collection>").description("Delete multiple documents matching a filter").requiredOption("--where <json>", "Filter conditions (JSON)").action(async (collection, opts) => {
|
|
494
|
+
program2.command("delete-many <collection>").description("Delete multiple documents matching a filter").requiredOption("--where <json>", "Filter conditions (JSON)").option("--dry-run", "Validate inputs without executing").action(async (collection, opts) => {
|
|
358
495
|
try {
|
|
359
496
|
const col = validateCollection(collection);
|
|
360
|
-
const client = getClient2();
|
|
361
497
|
const where = parseJson(opts.where, "where");
|
|
498
|
+
if (opts.dryRun) {
|
|
499
|
+
printResult(
|
|
500
|
+
{
|
|
501
|
+
dryRun: true,
|
|
502
|
+
valid: true,
|
|
503
|
+
action: "delete-many",
|
|
504
|
+
collection: col,
|
|
505
|
+
where
|
|
506
|
+
},
|
|
507
|
+
getFormat2()
|
|
508
|
+
);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const client = getClient2();
|
|
362
512
|
const result = await client.collections.from(col).removeMany(where);
|
|
363
513
|
printResult(result, getFormat2());
|
|
364
514
|
} catch (e) {
|
|
365
|
-
|
|
366
|
-
process.exit(1);
|
|
515
|
+
exitWithError(e);
|
|
367
516
|
}
|
|
368
517
|
});
|
|
369
518
|
}
|
|
@@ -371,10 +520,14 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
371
520
|
// src/commands/order.ts
|
|
372
521
|
function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
373
522
|
const order = program2.command("order").description("Order management");
|
|
374
|
-
order.command("create").description("Create a new order").option("--payment-id <id>", "Payment ID").requiredOption("--order-number <num>", "Order number").requiredOption("--email <email>", "Customer email").option("--customer <id>", "Customer ID").option("--name <name>", "Customer name").option("--phone <phone>", "Customer phone").requiredOption("--shipping-address <json>", "Shipping address (JSON)").requiredOption("--products <json>", "Order products array (JSON)").requiredOption("--total-amount <n>", "Total amount", parseFloat).action(async (opts) => {
|
|
523
|
+
order.command("create").description("Create a new order").option("--payment-id <id>", "Payment ID").requiredOption("--order-number <num>", "Order number").requiredOption("--email <email>", "Customer email").option("--customer <id>", "Customer ID").option("--name <name>", "Customer name").option("--phone <phone>", "Customer phone").requiredOption("--shipping-address <json>", "Shipping address (JSON)").requiredOption("--products <json>", "Order products array (JSON)").requiredOption("--total-amount <n>", "Total amount", parseFloat).option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
375
524
|
try {
|
|
376
|
-
const
|
|
377
|
-
|
|
525
|
+
const shippingAddress = parseJson(
|
|
526
|
+
opts.shippingAddress,
|
|
527
|
+
"shipping-address"
|
|
528
|
+
);
|
|
529
|
+
const orderProducts = parseJsonArray(opts.products, "products");
|
|
530
|
+
const data = {
|
|
378
531
|
paymentId: opts.paymentId,
|
|
379
532
|
orderNumber: opts.orderNumber,
|
|
380
533
|
customerSnapshot: {
|
|
@@ -383,14 +536,25 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
|
383
536
|
phone: opts.phone
|
|
384
537
|
},
|
|
385
538
|
customer: opts.customer,
|
|
386
|
-
shippingAddress
|
|
387
|
-
orderProducts
|
|
539
|
+
shippingAddress,
|
|
540
|
+
orderProducts,
|
|
388
541
|
totalAmount: opts.totalAmount
|
|
542
|
+
};
|
|
543
|
+
if (opts.dryRun) {
|
|
544
|
+
printResult(
|
|
545
|
+
{ dryRun: true, valid: true, action: "order create", data },
|
|
546
|
+
getFormat2()
|
|
547
|
+
);
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
const client = getClient2();
|
|
551
|
+
const result = await client.api.createOrder({
|
|
552
|
+
...data,
|
|
553
|
+
orderProducts
|
|
389
554
|
});
|
|
390
555
|
printResult(result, getFormat2());
|
|
391
556
|
} catch (e) {
|
|
392
|
-
|
|
393
|
-
process.exit(1);
|
|
557
|
+
exitWithError(e);
|
|
394
558
|
}
|
|
395
559
|
});
|
|
396
560
|
order.command("get <orderNumber>").description("Get an order by order number").action(async (orderNumber) => {
|
|
@@ -399,51 +563,76 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
|
399
563
|
const result = await client.api.getOrder({ orderNumber });
|
|
400
564
|
printResult(result, getFormat2());
|
|
401
565
|
} catch (e) {
|
|
402
|
-
|
|
403
|
-
process.exit(1);
|
|
566
|
+
exitWithError(e);
|
|
404
567
|
}
|
|
405
568
|
});
|
|
406
|
-
order.command("update <orderNumber>").description("Update order status").requiredOption("--status <status>", "New status").action(async (orderNumber, opts) => {
|
|
569
|
+
order.command("update <orderNumber>").description("Update order status").requiredOption("--status <status>", "New status").option("--dry-run", "Validate inputs without executing").action(async (orderNumber, opts) => {
|
|
407
570
|
try {
|
|
571
|
+
const data = { orderNumber, status: opts.status };
|
|
572
|
+
if (opts.dryRun) {
|
|
573
|
+
printResult(
|
|
574
|
+
{ dryRun: true, valid: true, action: "order update", data },
|
|
575
|
+
getFormat2()
|
|
576
|
+
);
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
408
579
|
const client = getClient2();
|
|
409
|
-
const result = await client.api.updateOrder(
|
|
410
|
-
orderNumber,
|
|
411
|
-
status: opts.status
|
|
412
|
-
});
|
|
580
|
+
const result = await client.api.updateOrder(data);
|
|
413
581
|
printResult(result, getFormat2());
|
|
414
582
|
} catch (e) {
|
|
415
|
-
|
|
416
|
-
process.exit(1);
|
|
583
|
+
exitWithError(e);
|
|
417
584
|
}
|
|
418
585
|
});
|
|
419
|
-
order.command("checkout").description("Convert a cart to an order").requiredOption("--cart-id <id>", "Cart ID").
|
|
586
|
+
order.command("checkout").description("Convert a cart to an order").requiredOption("--cart-id <id>", "Cart ID").option("--payment-id <id>", "Payment ID (optional for free orders)").requiredOption("--order-number <num>", "Order number").requiredOption("--customer <json>", "Customer snapshot (JSON)").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
420
587
|
try {
|
|
421
|
-
const
|
|
422
|
-
const
|
|
588
|
+
const customerSnapshot = parseJson(opts.customer, "customer");
|
|
589
|
+
const data = {
|
|
423
590
|
cartId: opts.cartId,
|
|
424
591
|
paymentId: opts.paymentId,
|
|
425
592
|
orderNumber: opts.orderNumber,
|
|
426
|
-
customerSnapshot
|
|
593
|
+
customerSnapshot
|
|
594
|
+
};
|
|
595
|
+
if (opts.dryRun) {
|
|
596
|
+
printResult(
|
|
597
|
+
{ dryRun: true, valid: true, action: "order checkout", data },
|
|
598
|
+
getFormat2()
|
|
599
|
+
);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
const client = getClient2();
|
|
603
|
+
const result = await client.api.checkout({
|
|
604
|
+
...data,
|
|
605
|
+
customerSnapshot
|
|
427
606
|
});
|
|
428
607
|
printResult(result, getFormat2());
|
|
429
608
|
} catch (e) {
|
|
430
|
-
|
|
431
|
-
process.exit(1);
|
|
609
|
+
exitWithError(e);
|
|
432
610
|
}
|
|
433
611
|
});
|
|
434
|
-
order.command("fulfill <orderNumber>").description("Create a fulfillment for an order").requiredOption("--items <json>", "Fulfillment items array (JSON)").option("--carrier <name>", "Shipping carrier").option("--tracking-number <num>", "Tracking number").action(async (orderNumber, opts) => {
|
|
612
|
+
order.command("fulfill <orderNumber>").description("Create a fulfillment for an order").requiredOption("--items <json>", "Fulfillment items array (JSON)").option("--carrier <name>", "Shipping carrier").option("--tracking-number <num>", "Tracking number").option("--dry-run", "Validate inputs without executing").action(async (orderNumber, opts) => {
|
|
435
613
|
try {
|
|
436
|
-
const
|
|
437
|
-
const
|
|
614
|
+
const items = parseJsonArray(opts.items, "items");
|
|
615
|
+
const data = {
|
|
438
616
|
orderNumber,
|
|
439
|
-
items
|
|
617
|
+
items,
|
|
440
618
|
carrier: opts.carrier,
|
|
441
619
|
trackingNumber: opts.trackingNumber
|
|
620
|
+
};
|
|
621
|
+
if (opts.dryRun) {
|
|
622
|
+
printResult(
|
|
623
|
+
{ dryRun: true, valid: true, action: "order fulfill", data },
|
|
624
|
+
getFormat2()
|
|
625
|
+
);
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
const client = getClient2();
|
|
629
|
+
const result = await client.api.createFulfillment({
|
|
630
|
+
...data,
|
|
631
|
+
items
|
|
442
632
|
});
|
|
443
633
|
printResult(result, getFormat2());
|
|
444
634
|
} catch (e) {
|
|
445
|
-
|
|
446
|
-
process.exit(1);
|
|
635
|
+
exitWithError(e);
|
|
447
636
|
}
|
|
448
637
|
});
|
|
449
638
|
}
|
|
@@ -451,51 +640,83 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
|
451
640
|
// src/commands/return.ts
|
|
452
641
|
function registerReturnCommands(program2, getClient2, getFormat2) {
|
|
453
642
|
const ret = program2.command("return").description("Return management");
|
|
454
|
-
ret.command("create <orderNumber>").description("Create a return request").requiredOption("--products <json>", "Return products array (JSON)").requiredOption("--refund-amount <n>", "Refund amount", parseFloat).option(
|
|
643
|
+
ret.command("create <orderNumber>").description("Create a return request").requiredOption("--products <json>", "Return products array (JSON)").requiredOption("--refund-amount <n>", "Refund amount", parseFloat).option(
|
|
644
|
+
"--reason <reason>",
|
|
645
|
+
"Return reason (change_of_mind, defective, wrong_delivery, damaged, other)"
|
|
646
|
+
).option("--reason-detail <text>", "Detailed reason").option("--dry-run", "Validate inputs without executing").action(async (orderNumber, opts) => {
|
|
455
647
|
try {
|
|
456
|
-
const
|
|
457
|
-
const
|
|
648
|
+
const returnProducts = parseJsonArray(opts.products, "products");
|
|
649
|
+
const data = {
|
|
458
650
|
orderNumber,
|
|
459
|
-
returnProducts
|
|
651
|
+
returnProducts,
|
|
460
652
|
refundAmount: opts.refundAmount,
|
|
461
653
|
reason: opts.reason,
|
|
462
654
|
reasonDetail: opts.reasonDetail
|
|
655
|
+
};
|
|
656
|
+
if (opts.dryRun) {
|
|
657
|
+
printResult(
|
|
658
|
+
{ dryRun: true, valid: true, action: "return create", data },
|
|
659
|
+
getFormat2()
|
|
660
|
+
);
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
const client = getClient2();
|
|
664
|
+
const result = await client.api.createReturn({
|
|
665
|
+
...data,
|
|
666
|
+
returnProducts
|
|
463
667
|
});
|
|
464
668
|
printResult(result, getFormat2());
|
|
465
669
|
} catch (e) {
|
|
466
|
-
|
|
467
|
-
process.exit(1);
|
|
670
|
+
exitWithError(e);
|
|
468
671
|
}
|
|
469
672
|
});
|
|
470
|
-
ret.command("update <returnId>").description("Update return status").requiredOption(
|
|
673
|
+
ret.command("update <returnId>").description("Update return status").requiredOption(
|
|
674
|
+
"--status <status>",
|
|
675
|
+
"New status (processing, approved, rejected, completed)"
|
|
676
|
+
).option("--dry-run", "Validate inputs without executing").action(async (returnId, opts) => {
|
|
471
677
|
try {
|
|
678
|
+
const data = { returnId, status: opts.status };
|
|
679
|
+
if (opts.dryRun) {
|
|
680
|
+
printResult(
|
|
681
|
+
{ dryRun: true, valid: true, action: "return update", data },
|
|
682
|
+
getFormat2()
|
|
683
|
+
);
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
472
686
|
const client = getClient2();
|
|
473
|
-
const result = await client.api.updateReturn(
|
|
474
|
-
returnId,
|
|
475
|
-
status: opts.status
|
|
476
|
-
});
|
|
687
|
+
const result = await client.api.updateReturn(data);
|
|
477
688
|
printResult(result, getFormat2());
|
|
478
689
|
} catch (e) {
|
|
479
|
-
|
|
480
|
-
process.exit(1);
|
|
690
|
+
exitWithError(e);
|
|
481
691
|
}
|
|
482
692
|
});
|
|
483
|
-
ret.command("refund <orderNumber>").description("Return with refund").requiredOption("--products <json>", "Return products array (JSON)").requiredOption("--refund-amount <n>", "Refund amount", parseFloat).requiredOption("--payment-id <id>", "Payment ID").option("--reason <reason>", "Return reason").option("--reason-detail <text>", "Detailed reason").option("--refund-receipt-url <url>", "Refund receipt URL").action(async (orderNumber, opts) => {
|
|
693
|
+
ret.command("refund <orderNumber>").description("Return with refund").requiredOption("--products <json>", "Return products array (JSON)").requiredOption("--refund-amount <n>", "Refund amount", parseFloat).requiredOption("--payment-id <id>", "Payment ID").option("--reason <reason>", "Return reason").option("--reason-detail <text>", "Detailed reason").option("--refund-receipt-url <url>", "Refund receipt URL").option("--dry-run", "Validate inputs without executing").action(async (orderNumber, opts) => {
|
|
484
694
|
try {
|
|
485
|
-
const
|
|
486
|
-
const
|
|
695
|
+
const returnProducts = parseJsonArray(opts.products, "products");
|
|
696
|
+
const data = {
|
|
487
697
|
orderNumber,
|
|
488
|
-
returnProducts
|
|
698
|
+
returnProducts,
|
|
489
699
|
refundAmount: opts.refundAmount,
|
|
490
700
|
paymentId: opts.paymentId,
|
|
491
701
|
reason: opts.reason,
|
|
492
702
|
reasonDetail: opts.reasonDetail,
|
|
493
703
|
refundReceiptUrl: opts.refundReceiptUrl
|
|
704
|
+
};
|
|
705
|
+
if (opts.dryRun) {
|
|
706
|
+
printResult(
|
|
707
|
+
{ dryRun: true, valid: true, action: "return refund", data },
|
|
708
|
+
getFormat2()
|
|
709
|
+
);
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
const client = getClient2();
|
|
713
|
+
const result = await client.api.returnWithRefund({
|
|
714
|
+
...data,
|
|
715
|
+
returnProducts
|
|
494
716
|
});
|
|
495
717
|
printResult(result, getFormat2());
|
|
496
718
|
} catch (e) {
|
|
497
|
-
|
|
498
|
-
process.exit(1);
|
|
719
|
+
exitWithError(e);
|
|
499
720
|
}
|
|
500
721
|
});
|
|
501
722
|
}
|
|
@@ -503,43 +724,73 @@ function registerReturnCommands(program2, getClient2, getFormat2) {
|
|
|
503
724
|
// src/commands/cart.ts
|
|
504
725
|
function registerCartCommands(program2, getClient2, getFormat2) {
|
|
505
726
|
const cart = program2.command("cart").description("Cart management");
|
|
506
|
-
cart.command("add <cartId>").description("Add an item to cart").requiredOption("--product <id>", "Product ID").requiredOption("--variant <id>", "Variant ID").requiredOption("--option <id>", "Option ID").requiredOption(
|
|
727
|
+
cart.command("add <cartId>").description("Add an item to cart").requiredOption("--product <id>", "Product ID").requiredOption("--variant <id>", "Variant ID").requiredOption("--option <id>", "Option ID").requiredOption(
|
|
728
|
+
"--quantity <n>",
|
|
729
|
+
"Quantity",
|
|
730
|
+
(v) => parseInt(v, 10)
|
|
731
|
+
).option("--dry-run", "Validate inputs without executing").action(async (cartId, opts) => {
|
|
507
732
|
try {
|
|
508
|
-
const
|
|
509
|
-
const result = await client.cart.addItem({
|
|
733
|
+
const data = {
|
|
510
734
|
cartId,
|
|
511
735
|
product: opts.product,
|
|
512
736
|
variant: opts.variant,
|
|
513
737
|
option: opts.option,
|
|
514
738
|
quantity: opts.quantity
|
|
515
|
-
}
|
|
739
|
+
};
|
|
740
|
+
if (opts.dryRun) {
|
|
741
|
+
printResult(
|
|
742
|
+
{ dryRun: true, valid: true, action: "cart add", data },
|
|
743
|
+
getFormat2()
|
|
744
|
+
);
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
const client = getClient2();
|
|
748
|
+
const result = await client.cart.addItem(data);
|
|
516
749
|
printResult(result, getFormat2());
|
|
517
750
|
} catch (e) {
|
|
518
|
-
|
|
519
|
-
process.exit(1);
|
|
751
|
+
exitWithError(e);
|
|
520
752
|
}
|
|
521
753
|
});
|
|
522
|
-
cart.command("update <cartItemId>").description("Update cart item quantity").requiredOption(
|
|
754
|
+
cart.command("update <cartItemId>").description("Update cart item quantity").requiredOption(
|
|
755
|
+
"--quantity <n>",
|
|
756
|
+
"New quantity",
|
|
757
|
+
(v) => parseInt(v, 10)
|
|
758
|
+
).option("--dry-run", "Validate inputs without executing").action(async (cartItemId, opts) => {
|
|
523
759
|
try {
|
|
760
|
+
const data = { cartItemId, quantity: opts.quantity };
|
|
761
|
+
if (opts.dryRun) {
|
|
762
|
+
printResult(
|
|
763
|
+
{ dryRun: true, valid: true, action: "cart update", data },
|
|
764
|
+
getFormat2()
|
|
765
|
+
);
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
524
768
|
const client = getClient2();
|
|
525
|
-
const result = await client.cart.updateItem(
|
|
526
|
-
cartItemId,
|
|
527
|
-
quantity: opts.quantity
|
|
528
|
-
});
|
|
769
|
+
const result = await client.cart.updateItem(data);
|
|
529
770
|
printResult(result, getFormat2());
|
|
530
771
|
} catch (e) {
|
|
531
|
-
|
|
532
|
-
process.exit(1);
|
|
772
|
+
exitWithError(e);
|
|
533
773
|
}
|
|
534
774
|
});
|
|
535
|
-
cart.command("remove <cartItemId>").description("Remove an item from cart").action(async (cartItemId) => {
|
|
775
|
+
cart.command("remove <cartItemId>").description("Remove an item from cart").option("--dry-run", "Validate inputs without executing").action(async (cartItemId, opts) => {
|
|
536
776
|
try {
|
|
777
|
+
if (opts.dryRun) {
|
|
778
|
+
printResult(
|
|
779
|
+
{
|
|
780
|
+
dryRun: true,
|
|
781
|
+
valid: true,
|
|
782
|
+
action: "cart remove",
|
|
783
|
+
data: { cartItemId }
|
|
784
|
+
},
|
|
785
|
+
getFormat2()
|
|
786
|
+
);
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
537
789
|
const client = getClient2();
|
|
538
790
|
const result = await client.cart.removeItem({ cartItemId });
|
|
539
791
|
printResult(result, getFormat2());
|
|
540
792
|
} catch (e) {
|
|
541
|
-
|
|
542
|
-
process.exit(1);
|
|
793
|
+
exitWithError(e);
|
|
543
794
|
}
|
|
544
795
|
});
|
|
545
796
|
}
|
|
@@ -547,15 +798,17 @@ function registerCartCommands(program2, getClient2, getFormat2) {
|
|
|
547
798
|
// src/commands/stock.ts
|
|
548
799
|
function registerStockCommands(program2, getClient2, getFormat2) {
|
|
549
800
|
const stock = program2.command("stock").description("Stock management");
|
|
550
|
-
stock.command("check").description("Check stock availability").requiredOption(
|
|
801
|
+
stock.command("check").description("Check stock availability").requiredOption(
|
|
802
|
+
"--items <json>",
|
|
803
|
+
"Items to check (JSON array of { optionId, quantity })"
|
|
804
|
+
).action(async (opts) => {
|
|
551
805
|
try {
|
|
552
806
|
const client = getClient2();
|
|
553
807
|
const items = parseJsonArray(opts.items, "items");
|
|
554
808
|
const result = await client.product.stockCheck({ items });
|
|
555
809
|
printResult(result, getFormat2());
|
|
556
810
|
} catch (e) {
|
|
557
|
-
|
|
558
|
-
process.exit(1);
|
|
811
|
+
exitWithError(e);
|
|
559
812
|
}
|
|
560
813
|
});
|
|
561
814
|
}
|
|
@@ -563,19 +816,29 @@ function registerStockCommands(program2, getClient2, getFormat2) {
|
|
|
563
816
|
// src/commands/transaction.ts
|
|
564
817
|
function registerTransactionCommands(program2, getClient2, getFormat2) {
|
|
565
818
|
const tx = program2.command("transaction").description("Transaction management");
|
|
566
|
-
tx.command("update").description("Update transaction status").requiredOption("--payment-id <id>", "Payment ID").requiredOption(
|
|
819
|
+
tx.command("update").description("Update transaction status").requiredOption("--payment-id <id>", "Payment ID").requiredOption(
|
|
820
|
+
"--status <status>",
|
|
821
|
+
"New status (pending, paid, failed, canceled)"
|
|
822
|
+
).requiredOption("--payment-method <method>", "Payment method").requiredOption("--receipt-url <url>", "Receipt URL").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
567
823
|
try {
|
|
568
|
-
const
|
|
569
|
-
const result = await client.api.updateTransaction({
|
|
824
|
+
const data = {
|
|
570
825
|
paymentId: opts.paymentId,
|
|
571
826
|
status: opts.status,
|
|
572
827
|
paymentMethod: opts.paymentMethod,
|
|
573
828
|
receiptUrl: opts.receiptUrl
|
|
574
|
-
}
|
|
829
|
+
};
|
|
830
|
+
if (opts.dryRun) {
|
|
831
|
+
printResult(
|
|
832
|
+
{ dryRun: true, valid: true, action: "transaction update", data },
|
|
833
|
+
getFormat2()
|
|
834
|
+
);
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
const client = getClient2();
|
|
838
|
+
const result = await client.api.updateTransaction(data);
|
|
575
839
|
printResult(result, getFormat2());
|
|
576
840
|
} catch (e) {
|
|
577
|
-
|
|
578
|
-
process.exit(1);
|
|
841
|
+
exitWithError(e);
|
|
579
842
|
}
|
|
580
843
|
});
|
|
581
844
|
}
|
|
@@ -595,8 +858,12 @@ function escapeHtml(s) {
|
|
|
595
858
|
function openBrowser(url) {
|
|
596
859
|
const os = platform();
|
|
597
860
|
const onError = () => {
|
|
598
|
-
console.log(
|
|
599
|
-
|
|
861
|
+
console.log(
|
|
862
|
+
pc4.yellow(
|
|
863
|
+
`Could not open browser automatically. Open this URL manually:
|
|
864
|
+
${url}`
|
|
865
|
+
)
|
|
866
|
+
);
|
|
600
867
|
};
|
|
601
868
|
if (os === "win32") {
|
|
602
869
|
exec(`start "" "${url}"`, (err) => {
|
|
@@ -628,7 +895,7 @@ var ERROR_HTML = (msg) => `<!DOCTYPE html>
|
|
|
628
895
|
<style>${PAGE_STYLE}</style>
|
|
629
896
|
</head><body><div class="card"><div class="icon err">!</div><h1>Authentication failed</h1><p>${escapeHtml(msg)}</p></div></body></html>`;
|
|
630
897
|
function startAuthServer(options) {
|
|
631
|
-
return new Promise((
|
|
898
|
+
return new Promise((resolve2, reject) => {
|
|
632
899
|
const server = createServer((req, res) => {
|
|
633
900
|
if (!req.url) {
|
|
634
901
|
res.writeHead(400).end();
|
|
@@ -649,19 +916,19 @@ function startAuthServer(options) {
|
|
|
649
916
|
if (error) {
|
|
650
917
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }).end(ERROR_HTML(error));
|
|
651
918
|
console.error(pc4.red(`Login failed: ${error}`));
|
|
652
|
-
cleanup(
|
|
919
|
+
cleanup(2);
|
|
653
920
|
return;
|
|
654
921
|
}
|
|
655
922
|
if (receivedState !== options.state) {
|
|
656
923
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }).end(ERROR_HTML("State mismatch \u2014 possible CSRF attack."));
|
|
657
924
|
console.error(pc4.red("Login failed: state mismatch."));
|
|
658
|
-
cleanup(
|
|
925
|
+
cleanup(2);
|
|
659
926
|
return;
|
|
660
927
|
}
|
|
661
928
|
if (!clientKey || !secretKey || !tenant) {
|
|
662
929
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }).end(ERROR_HTML("Missing credentials in callback."));
|
|
663
930
|
console.error(pc4.red("Login failed: missing credentials."));
|
|
664
|
-
cleanup(
|
|
931
|
+
cleanup(2);
|
|
665
932
|
return;
|
|
666
933
|
}
|
|
667
934
|
options.saveFn({
|
|
@@ -703,10 +970,12 @@ Logged in successfully!`));
|
|
|
703
970
|
return;
|
|
704
971
|
}
|
|
705
972
|
timeout = setTimeout(() => {
|
|
706
|
-
console.error(
|
|
707
|
-
|
|
973
|
+
console.error(
|
|
974
|
+
pc4.red("\nLogin timed out (3 minutes). Please try again.")
|
|
975
|
+
);
|
|
976
|
+
cleanup(4);
|
|
708
977
|
}, TIMEOUT_MS);
|
|
709
|
-
|
|
978
|
+
resolve2({ port: addr.port, cleanup });
|
|
710
979
|
});
|
|
711
980
|
server.on("error", (err) => {
|
|
712
981
|
reject(err);
|
|
@@ -731,8 +1000,12 @@ function registerAuthCommands(program2) {
|
|
|
731
1000
|
${loginUrl}`));
|
|
732
1001
|
openBrowser(loginUrl);
|
|
733
1002
|
} catch (err) {
|
|
734
|
-
console.error(
|
|
735
|
-
|
|
1003
|
+
console.error(
|
|
1004
|
+
pc4.red(
|
|
1005
|
+
`Server error: ${err instanceof Error ? err.message : String(err)}`
|
|
1006
|
+
)
|
|
1007
|
+
);
|
|
1008
|
+
process.exit(4);
|
|
736
1009
|
}
|
|
737
1010
|
});
|
|
738
1011
|
program2.command("logout").description("Remove stored credentials").action(() => {
|
|
@@ -757,7 +1030,9 @@ ${loginUrl}`));
|
|
|
757
1030
|
console.log(`Tenant: ${pc4.bold(creds.tenantName)}${scope}`);
|
|
758
1031
|
console.log(`Client Key: ${pc4.dim(masked)}`);
|
|
759
1032
|
console.log(`Stored at: ${pc4.dim(creds.storedAt)}`);
|
|
760
|
-
console.log(
|
|
1033
|
+
console.log(
|
|
1034
|
+
`File: ${pc4.dim(isLocal ? getLocalCredentialsPath() : getCredentialsPath())}`
|
|
1035
|
+
);
|
|
761
1036
|
});
|
|
762
1037
|
const tenant = program2.command("tenant").description("Manage tenant switching");
|
|
763
1038
|
tenant.command("list").description("Show cached tenant list").action(() => {
|
|
@@ -786,13 +1061,17 @@ ${loginUrl}`));
|
|
|
786
1061
|
const tenants = loadTenantList();
|
|
787
1062
|
if (!tenants || tenants.length === 0) {
|
|
788
1063
|
console.error(pc4.red('No cached tenants. Run "01 login" first.'));
|
|
789
|
-
process.exit(
|
|
1064
|
+
process.exit(2);
|
|
790
1065
|
}
|
|
791
|
-
const match = tenants.find(
|
|
1066
|
+
const match = tenants.find(
|
|
1067
|
+
(t) => t.name.toLowerCase() === name.toLowerCase()
|
|
1068
|
+
);
|
|
792
1069
|
if (!match) {
|
|
793
1070
|
console.error(pc4.red(`Tenant "${name}" not found in cache.`));
|
|
794
|
-
console.error(
|
|
795
|
-
|
|
1071
|
+
console.error(
|
|
1072
|
+
pc4.dim(`Available: ${tenants.map((t) => t.name).join(", ")}`)
|
|
1073
|
+
);
|
|
1074
|
+
process.exit(3);
|
|
796
1075
|
}
|
|
797
1076
|
const state = randomBytes(32).toString("hex");
|
|
798
1077
|
const isLocal = !!opts.local;
|
|
@@ -802,10 +1081,14 @@ ${loginUrl}`));
|
|
|
802
1081
|
saveFn: (creds) => {
|
|
803
1082
|
if (isLocal) {
|
|
804
1083
|
saveLocalCredentials(creds);
|
|
805
|
-
console.log(
|
|
1084
|
+
console.log(
|
|
1085
|
+
pc4.dim(`Credentials saved to ${getLocalCredentialsPath()}`)
|
|
1086
|
+
);
|
|
806
1087
|
} else {
|
|
807
1088
|
saveCredentials(creds);
|
|
808
|
-
console.log(
|
|
1089
|
+
console.log(
|
|
1090
|
+
pc4.dim(`Credentials saved to ${getCredentialsPath()}`)
|
|
1091
|
+
);
|
|
809
1092
|
}
|
|
810
1093
|
}
|
|
811
1094
|
});
|
|
@@ -820,22 +1103,117 @@ ${loginUrl}`));
|
|
|
820
1103
|
${loginUrl}`));
|
|
821
1104
|
openBrowser(loginUrl);
|
|
822
1105
|
} catch (err) {
|
|
823
|
-
console.error(
|
|
824
|
-
|
|
1106
|
+
console.error(
|
|
1107
|
+
pc4.red(
|
|
1108
|
+
`Server error: ${err instanceof Error ? err.message : String(err)}`
|
|
1109
|
+
)
|
|
1110
|
+
);
|
|
1111
|
+
process.exit(4);
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// src/commands/schema.ts
|
|
1117
|
+
import { COLLECTIONS as COLLECTIONS2 } from "@01.software/sdk";
|
|
1118
|
+
function getApiUrl() {
|
|
1119
|
+
return (process.env.SOFTWARE_API_URL || process.env.NEXT_PUBLIC_SOFTWARE_API_URL || "https://api.01.software").replace(/\/$/, "");
|
|
1120
|
+
}
|
|
1121
|
+
function registerSchemaCommands(program2, getClient2, getFormat2) {
|
|
1122
|
+
const schema = program2.command("schema").description("Collection schema introspection");
|
|
1123
|
+
schema.command("list").description("List available collections").action(() => {
|
|
1124
|
+
printResult(COLLECTIONS2, getFormat2());
|
|
1125
|
+
});
|
|
1126
|
+
schema.command("show <collection>").description("Show collection field schema").action(async (collection) => {
|
|
1127
|
+
try {
|
|
1128
|
+
if (!COLLECTIONS2.includes(collection)) {
|
|
1129
|
+
const normalized = collection.replace(/-/g, "").toLowerCase();
|
|
1130
|
+
const suggestions = COLLECTIONS2.filter((c) => {
|
|
1131
|
+
const cn = c.replace(/-/g, "").toLowerCase();
|
|
1132
|
+
return cn.startsWith(normalized) || normalized.startsWith(cn) || normalized.length >= 3 && cn.includes(normalized);
|
|
1133
|
+
}).slice(0, 5);
|
|
1134
|
+
const hint = suggestions.length > 0 ? `Did you mean: ${suggestions.join(", ")}?` : 'Run "01 schema list" for available collections.';
|
|
1135
|
+
throw new Error(`Unknown collection "${collection}". ${hint}`);
|
|
1136
|
+
}
|
|
1137
|
+
const client = getClient2();
|
|
1138
|
+
const { createServerToken } = await import("@01.software/sdk/auth");
|
|
1139
|
+
const token = await createServerToken(
|
|
1140
|
+
client.clientKey,
|
|
1141
|
+
client.secretKey
|
|
1142
|
+
);
|
|
1143
|
+
const baseUrl = getApiUrl();
|
|
1144
|
+
const url = `${baseUrl}/api/tenants/schema/${encodeURIComponent(collection)}`;
|
|
1145
|
+
const response = await fetch(url, {
|
|
1146
|
+
headers: {
|
|
1147
|
+
"X-Client-Key": client.clientKey,
|
|
1148
|
+
Authorization: `Bearer ${token}`
|
|
1149
|
+
}
|
|
1150
|
+
});
|
|
1151
|
+
if (!response.ok) {
|
|
1152
|
+
const body = await response.json().catch(() => ({ error: response.statusText }));
|
|
1153
|
+
const err = new Error(
|
|
1154
|
+
body.error || `HTTP ${response.status}`
|
|
1155
|
+
);
|
|
1156
|
+
Object.assign(err, { status: response.status });
|
|
1157
|
+
throw err;
|
|
1158
|
+
}
|
|
1159
|
+
const result = await response.json();
|
|
1160
|
+
printResult(result, getFormat2());
|
|
1161
|
+
} catch (e) {
|
|
1162
|
+
exitWithError(e);
|
|
825
1163
|
}
|
|
826
1164
|
});
|
|
827
1165
|
}
|
|
828
1166
|
|
|
1167
|
+
// src/commands/mcp.ts
|
|
1168
|
+
import { resolve, dirname } from "path";
|
|
1169
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1170
|
+
import { spawn } from "child_process";
|
|
1171
|
+
import { fileURLToPath } from "url";
|
|
1172
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
1173
|
+
function findStdioEntry() {
|
|
1174
|
+
for (const depth of ["../../../..", "../../.."]) {
|
|
1175
|
+
const candidate = resolve(__dirname, depth, "apps/mcp/.xmcp/stdio.js");
|
|
1176
|
+
if (existsSync2(candidate)) return candidate;
|
|
1177
|
+
}
|
|
1178
|
+
return null;
|
|
1179
|
+
}
|
|
1180
|
+
function registerMcpCommands(program2) {
|
|
1181
|
+
program2.command("mcp").description("Start MCP server over stdio").action(() => {
|
|
1182
|
+
const client = resolveClient(program2.opts().apiKey);
|
|
1183
|
+
const stdioEntry = findStdioEntry();
|
|
1184
|
+
if (!stdioEntry) {
|
|
1185
|
+
exitWithError(
|
|
1186
|
+
new Error(
|
|
1187
|
+
"MCP server not found. Ensure apps/mcp is built (pnpm --filter mcp build)."
|
|
1188
|
+
)
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
const child = spawn(process.execPath, [stdioEntry], {
|
|
1192
|
+
env: {
|
|
1193
|
+
...process.env,
|
|
1194
|
+
SOFTWARE_CLIENT_KEY: client.clientKey,
|
|
1195
|
+
SOFTWARE_SECRET_KEY: client.secretKey
|
|
1196
|
+
},
|
|
1197
|
+
stdio: ["inherit", "inherit", "inherit"]
|
|
1198
|
+
});
|
|
1199
|
+
child.on("error", (err) => {
|
|
1200
|
+
exitWithError(new Error(`Failed to start MCP server: ${err.message}`));
|
|
1201
|
+
});
|
|
1202
|
+
child.on("exit", (code) => {
|
|
1203
|
+
process.exit(code ?? 0);
|
|
1204
|
+
});
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
|
|
829
1208
|
// src/index.ts
|
|
830
1209
|
var require2 = createRequire(import.meta.url);
|
|
831
1210
|
var { version } = require2("../package.json");
|
|
832
1211
|
process.on("unhandledRejection", (err) => {
|
|
833
|
-
|
|
834
|
-
process.exit(1);
|
|
1212
|
+
exitWithError(err);
|
|
835
1213
|
});
|
|
836
1214
|
var program = new Command();
|
|
837
|
-
program.name("01").description("CLI for the 01.software platform").version(version).option("--api-key <base64>", "Base64-encoded API key (clientKey:secretKey)").option("--format <format>", "Output format: json
|
|
838
|
-
var getFormat = () => program.opts().format;
|
|
1215
|
+
program.name("01").description("CLI for the 01.software platform").version(version).option("--api-key <base64>", "Base64-encoded API key (clientKey:secretKey)").option("--format <format>", "Output format: json, table, or ndjson");
|
|
1216
|
+
var getFormat = () => program.opts().format ?? process.env.OUTPUT_FORMAT ?? "json";
|
|
839
1217
|
var getClient = () => resolveClient(program.opts().apiKey);
|
|
840
1218
|
registerCrudCommands(program, getClient, getFormat);
|
|
841
1219
|
registerOrderCommands(program, getClient, getFormat);
|
|
@@ -843,6 +1221,8 @@ registerReturnCommands(program, getClient, getFormat);
|
|
|
843
1221
|
registerCartCommands(program, getClient, getFormat);
|
|
844
1222
|
registerStockCommands(program, getClient, getFormat);
|
|
845
1223
|
registerTransactionCommands(program, getClient, getFormat);
|
|
1224
|
+
registerSchemaCommands(program, getClient, getFormat);
|
|
1225
|
+
registerMcpCommands(program);
|
|
846
1226
|
registerAuthCommands(program);
|
|
847
1227
|
program.parse();
|
|
848
1228
|
//# sourceMappingURL=index.js.map
|