frontpage-host 0.1.21 → 0.1.22
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/AGENTS.md +3 -2
- package/dist/bin.js +4 -1
- package/dist/commands/modules.js +13 -1
- package/dist/commands/people.js +29 -1
- package/dist/commands/routines.d.ts +1 -0
- package/dist/commands/routines.js +156 -0
- package/dist/commands/shop.js +95 -49
- package/dist/completions/generate.js +12 -11
- package/dist/http/client.js +1 -1
- package/dist/modules/commands.d.ts +3 -2
- package/dist/modules/commands.js +21 -89
- package/dist/modules/oauth.d.ts +2 -2
- package/dist/modules/oauth.js +7 -101
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +62 -29
- package/dist/routines-parse.d.ts +7 -0
- package/dist/routines-parse.js +78 -0
- package/llms.txt +3 -2
- package/package.json +1 -1
package/dist/commands/shop.js
CHANGED
|
@@ -5,7 +5,7 @@ import { assertNoUnknownFlags, hasFlag, takeFlag } from "../argv.js";
|
|
|
5
5
|
import { emitErr, emitOk, emitUsage, isJson, requireYesOrTty } from "../runtime.js";
|
|
6
6
|
import { openBrowser, resolveOpenUrl } from "../modules/oauth.js";
|
|
7
7
|
import { SHOP_ID_RE, VARIANT_ID_RE } from "./shop-ids.js";
|
|
8
|
-
const USAGE = "Usage: frontpage
|
|
8
|
+
const USAGE = "Usage: frontpage store items|variants|categories|settings|orders|payments|connect|status|disconnect|import … [--site <slug>] [--json]";
|
|
9
9
|
const CONNECT_FINISH = "Open the Frontpage URL while logged in, finish Stripe in the browser, then re-run status. This CLI cannot complete OAuth.";
|
|
10
10
|
const CENTS_HINT = "$49.99 is 4999";
|
|
11
11
|
function takeAll(work, name) {
|
|
@@ -22,10 +22,10 @@ function requireShopId(work, label = "Item id", opts) {
|
|
|
22
22
|
const positional = work.find((a) => !a.startsWith("-"));
|
|
23
23
|
const raw = fromFlag ?? (positional ? work.splice(work.indexOf(positional), 1)[0] : undefined);
|
|
24
24
|
if (!raw) {
|
|
25
|
-
throw new CliHttpError(`${label} is required. Run: frontpage help
|
|
25
|
+
throw new CliHttpError(`${label} is required. Run: frontpage help store`, EXIT_USAGE, 0, "bad_request");
|
|
26
26
|
}
|
|
27
27
|
if (!SHOP_ID_RE.test(raw)) {
|
|
28
|
-
throw new CliHttpError("Item
|
|
28
|
+
throw new CliHttpError("Item id must be kebab-case, like camp-hat (2–40 letters, numbers, or hyphens).", EXIT_USAGE, 0, "bad_request");
|
|
29
29
|
}
|
|
30
30
|
return raw;
|
|
31
31
|
}
|
|
@@ -36,7 +36,7 @@ function requireVariantId(raw, required = true) {
|
|
|
36
36
|
throw new CliHttpError("Variant id is required. Use --variant m or --id m.", EXIT_USAGE, 0, "bad_request");
|
|
37
37
|
}
|
|
38
38
|
if (!VARIANT_ID_RE.test(raw)) {
|
|
39
|
-
throw new CliHttpError("
|
|
39
|
+
throw new CliHttpError("Version id must be kebab-case, like s, m, or camp-hat-m.", EXIT_USAGE, 0, "bad_request");
|
|
40
40
|
}
|
|
41
41
|
return raw;
|
|
42
42
|
}
|
|
@@ -45,7 +45,7 @@ function requireLedgerId(work, kind) {
|
|
|
45
45
|
const positional = work.find((a) => !a.startsWith("-"));
|
|
46
46
|
const raw = fromFlag ?? (positional ? work.splice(work.indexOf(positional), 1)[0] : undefined);
|
|
47
47
|
if (!raw || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(raw)) {
|
|
48
|
-
throw new CliHttpError(`${kind}
|
|
48
|
+
throw new CliHttpError(`${kind} id must be a UUID. Run: frontpage store ${kind.toLowerCase()}s list`, EXIT_USAGE, 0, "bad_request");
|
|
49
49
|
}
|
|
50
50
|
return raw;
|
|
51
51
|
}
|
|
@@ -146,7 +146,7 @@ function printItem(row) {
|
|
|
146
146
|
const bits = [
|
|
147
147
|
row.checkout ?? "",
|
|
148
148
|
row.amount ?? "",
|
|
149
|
-
prices.length ? prices.join(",") : "",
|
|
149
|
+
prices.length ? `${prices.join(",")} cents` : "",
|
|
150
150
|
stocks.length ? `stock ${stocks.join(",")}` : "",
|
|
151
151
|
row.active === false ? "inactive" : "active",
|
|
152
152
|
row.categories?.length ? row.categories.join(",") : "",
|
|
@@ -172,7 +172,7 @@ export async function runShop(args) {
|
|
|
172
172
|
const listWork = sub === "list" ? work : rest.slice(1);
|
|
173
173
|
const archived = hasFlag(listWork, "--archived");
|
|
174
174
|
const category = takeFlag(listWork, "--category");
|
|
175
|
-
assertNoUnknownFlags(listWork, "
|
|
175
|
+
assertNoUnknownFlags(listWork, "store");
|
|
176
176
|
const qs = new URLSearchParams();
|
|
177
177
|
if (archived)
|
|
178
178
|
qs.set("archived", "1");
|
|
@@ -186,7 +186,7 @@ export async function runShop(args) {
|
|
|
186
186
|
}
|
|
187
187
|
const rows = data.items ?? [];
|
|
188
188
|
if (rows.length === 0) {
|
|
189
|
-
console.log(
|
|
189
|
+
console.log(category ? "No products in that category." : "No products in this store.");
|
|
190
190
|
return EXIT_OK;
|
|
191
191
|
}
|
|
192
192
|
for (const row of rows)
|
|
@@ -195,7 +195,7 @@ export async function runShop(args) {
|
|
|
195
195
|
}
|
|
196
196
|
if (sub === "get") {
|
|
197
197
|
const itemId = requireShopId(work);
|
|
198
|
-
assertNoUnknownFlags(work, "
|
|
198
|
+
assertNoUnknownFlags(work, "store");
|
|
199
199
|
const data = await v1Get(`${base}/items/${encodeURIComponent(itemId)}`);
|
|
200
200
|
if (isJson()) {
|
|
201
201
|
emitOk("shop", data);
|
|
@@ -207,7 +207,7 @@ export async function runShop(args) {
|
|
|
207
207
|
const stock = v.stock == null ? "unlimited" : String(v.stock);
|
|
208
208
|
const off = v.active === false ? " inactive" : "";
|
|
209
209
|
const archived = v.archivedAt ? " archived" : "";
|
|
210
|
-
console.log(` ${v.variantId} ${v.priceCents}${sale} stock ${stock}${off}${archived}`);
|
|
210
|
+
console.log(` ${v.variantId} ${v.priceCents} cents${sale} stock ${stock}${off}${archived}`);
|
|
211
211
|
}
|
|
212
212
|
return EXIT_OK;
|
|
213
213
|
}
|
|
@@ -226,12 +226,11 @@ export async function runShop(args) {
|
|
|
226
226
|
const categories = parseCsv(takeFlag(work, "--categories"));
|
|
227
227
|
const priceCents = parseCentsFlag(takeFlag(work, "--price-cents"), "priceCents");
|
|
228
228
|
const discountCents = parseCentsFlag(takeFlag(work, "--discount-cents"), "discountPriceCents");
|
|
229
|
-
const shippingCents = parseCentsFlag(takeFlag(work, "--shipping-cents"), "shippingCents");
|
|
230
229
|
const stockRaw = takeFlag(work, "--stock");
|
|
231
230
|
const variantId = takeFlag(work, "--variant-id") ?? takeFlag(work, "--variant");
|
|
232
231
|
const options = parseOptions(takeAll(work, "--option"));
|
|
233
232
|
const images = parseUrls(work);
|
|
234
|
-
assertNoUnknownFlags(work, "
|
|
233
|
+
assertNoUnknownFlags(work, "store");
|
|
235
234
|
const body = file ? await readJsonFile(file) : {};
|
|
236
235
|
if (itemId)
|
|
237
236
|
body.itemId = itemId;
|
|
@@ -253,8 +252,6 @@ export async function runShop(args) {
|
|
|
253
252
|
body.categories = categories;
|
|
254
253
|
if (images.length)
|
|
255
254
|
body.images = images;
|
|
256
|
-
if (body.checkout == null)
|
|
257
|
-
body.checkout = "cart";
|
|
258
255
|
if (body.amount == null)
|
|
259
256
|
body.amount = "fixed";
|
|
260
257
|
if (!Array.isArray(body.variants) && priceCents !== undefined) {
|
|
@@ -265,13 +262,12 @@ export async function runShop(args) {
|
|
|
265
262
|
...(options ? { options } : {}),
|
|
266
263
|
priceCents,
|
|
267
264
|
...(discountCents !== undefined ? { discountPriceCents: discountCents } : {}),
|
|
268
|
-
...(shippingCents !== undefined ? { shippingCents } : {}),
|
|
269
265
|
...(stock !== undefined ? { stock } : {}),
|
|
270
266
|
},
|
|
271
267
|
];
|
|
272
268
|
}
|
|
273
269
|
if (typeof body.itemId !== "string" || !SHOP_ID_RE.test(body.itemId)) {
|
|
274
|
-
throw new CliHttpError("Usage: frontpage
|
|
270
|
+
throw new CliHttpError("Item id must be kebab-case, like camp-hat (2–40 letters, numbers, or hyphens). Usage: frontpage store items create camp-hat --title \"Camp hat\" --price-cents 4999", EXIT_USAGE, 0, "bad_request");
|
|
275
271
|
}
|
|
276
272
|
const data = await v1Post(`${base}/items`, body);
|
|
277
273
|
if (isJson()) {
|
|
@@ -292,7 +288,7 @@ export async function runShop(args) {
|
|
|
292
288
|
const active = parseBoolFlag(takeFlag(work, "--active"), "active");
|
|
293
289
|
const categories = parseCsv(takeFlag(work, "--categories"));
|
|
294
290
|
const images = parseUrls(work);
|
|
295
|
-
assertNoUnknownFlags(work, "
|
|
291
|
+
assertNoUnknownFlags(work, "store");
|
|
296
292
|
const body = {};
|
|
297
293
|
if (title !== undefined)
|
|
298
294
|
body.title = title;
|
|
@@ -325,7 +321,7 @@ export async function runShop(args) {
|
|
|
325
321
|
}
|
|
326
322
|
if (sub === "archive") {
|
|
327
323
|
const itemId = requireShopId(work);
|
|
328
|
-
assertNoUnknownFlags(work, "
|
|
324
|
+
assertNoUnknownFlags(work, "store");
|
|
329
325
|
const data = await v1Post(`${base}/items/${encodeURIComponent(itemId)}/archive`, {});
|
|
330
326
|
if (isJson()) {
|
|
331
327
|
emitOk("shop", data);
|
|
@@ -338,7 +334,7 @@ export async function runShop(args) {
|
|
|
338
334
|
const itemId = requireShopId(work);
|
|
339
335
|
const off = hasFlag(work, "--off");
|
|
340
336
|
const active = off ? false : parseBoolFlag(takeFlag(work, "--active"), "active");
|
|
341
|
-
assertNoUnknownFlags(work, "
|
|
337
|
+
assertNoUnknownFlags(work, "store");
|
|
342
338
|
const data = await v1Post(`${base}/items/${encodeURIComponent(itemId)}/activate`, { active: active ?? true });
|
|
343
339
|
if (isJson()) {
|
|
344
340
|
emitOk("shop", data);
|
|
@@ -350,7 +346,7 @@ export async function runShop(args) {
|
|
|
350
346
|
if (sub === "images") {
|
|
351
347
|
const itemId = requireShopId(work);
|
|
352
348
|
const urls = parseUrls(work);
|
|
353
|
-
assertNoUnknownFlags(work, "
|
|
349
|
+
assertNoUnknownFlags(work, "store");
|
|
354
350
|
const data = await v1Put(`${base}/items/${encodeURIComponent(itemId)}/images`, { images: urls });
|
|
355
351
|
if (isJson()) {
|
|
356
352
|
emitOk("shop", data);
|
|
@@ -365,7 +361,7 @@ export async function runShop(args) {
|
|
|
365
361
|
const addRaw = takeFlag(work, "--add");
|
|
366
362
|
const removeRaw = takeFlag(work, "--remove");
|
|
367
363
|
const setRaw = takeFlag(work, "--set");
|
|
368
|
-
assertNoUnknownFlags(work, "
|
|
364
|
+
assertNoUnknownFlags(work, "store");
|
|
369
365
|
const present = [addRaw, removeRaw, setRaw].filter((v) => v !== undefined).length;
|
|
370
366
|
if (present !== 1) {
|
|
371
367
|
throw new CliHttpError("Pass either --add 5, --remove 5, or --set 20. --add / --remove become signed delta.", EXIT_USAGE, 0, "bad_request");
|
|
@@ -416,13 +412,12 @@ export async function runShop(args) {
|
|
|
416
412
|
const variantId = requireVariantId(takeFlag(work, "--id") ?? takeFlag(work, "--variant"));
|
|
417
413
|
const priceCents = parseCentsFlag(takeFlag(work, "--price-cents"), "priceCents");
|
|
418
414
|
const discountCents = parseCentsFlag(takeFlag(work, "--discount-cents"), "discountPriceCents");
|
|
419
|
-
const shippingCents = parseCentsFlag(takeFlag(work, "--shipping-cents"), "shippingCents");
|
|
420
415
|
const stockRaw = takeFlag(work, "--stock");
|
|
421
416
|
const options = parseOptions(takeAll(work, "--option"));
|
|
422
417
|
const active = parseBoolFlag(takeFlag(work, "--active"), "active");
|
|
423
|
-
assertNoUnknownFlags(work, "
|
|
418
|
+
assertNoUnknownFlags(work, "store");
|
|
424
419
|
if (priceCents === undefined) {
|
|
425
|
-
throw new CliHttpError("Usage: frontpage
|
|
420
|
+
throw new CliHttpError("Usage: frontpage store variants add <itemId> --id m --price-cents 4999", EXIT_USAGE, 0, "bad_request");
|
|
426
421
|
}
|
|
427
422
|
const stock = stockRaw === undefined ? undefined : stockRaw === "unlimited" ? null : parseCountFlag(stockRaw, "stock");
|
|
428
423
|
const data = await v1Post(`${base}/items/${encodeURIComponent(itemId)}/variants`, {
|
|
@@ -430,7 +425,6 @@ export async function runShop(args) {
|
|
|
430
425
|
options,
|
|
431
426
|
priceCents,
|
|
432
427
|
discountPriceCents: discountCents,
|
|
433
|
-
shippingCents,
|
|
434
428
|
stock,
|
|
435
429
|
active,
|
|
436
430
|
});
|
|
@@ -446,18 +440,15 @@ export async function runShop(args) {
|
|
|
446
440
|
const variantId = requireVariantId(takeFlag(work, "--id") ?? takeFlag(work, "--variant"));
|
|
447
441
|
const priceCents = parseCentsFlag(takeFlag(work, "--price-cents"), "priceCents");
|
|
448
442
|
const discountCents = parseCentsFlag(takeFlag(work, "--discount-cents"), "discountPriceCents");
|
|
449
|
-
const shippingCents = parseCentsFlag(takeFlag(work, "--shipping-cents"), "shippingCents");
|
|
450
443
|
const stockRaw = takeFlag(work, "--stock");
|
|
451
444
|
const options = parseOptions(takeAll(work, "--option"));
|
|
452
445
|
const active = parseBoolFlag(takeFlag(work, "--active"), "active");
|
|
453
|
-
assertNoUnknownFlags(work, "
|
|
446
|
+
assertNoUnknownFlags(work, "store");
|
|
454
447
|
const body = {};
|
|
455
448
|
if (priceCents !== undefined)
|
|
456
449
|
body.priceCents = priceCents;
|
|
457
450
|
if (discountCents !== undefined)
|
|
458
451
|
body.discountPriceCents = discountCents;
|
|
459
|
-
if (shippingCents !== undefined)
|
|
460
|
-
body.shippingCents = shippingCents;
|
|
461
452
|
if (stockRaw !== undefined)
|
|
462
453
|
body.stock = stockRaw === "unlimited" ? null : parseCountFlag(stockRaw, "stock");
|
|
463
454
|
if (options)
|
|
@@ -478,7 +469,7 @@ export async function runShop(args) {
|
|
|
478
469
|
if (sub === "archive") {
|
|
479
470
|
const itemId = requireShopId(work, "Item id", { allowIdFlag: false });
|
|
480
471
|
const variantId = requireVariantId(takeFlag(work, "--id") ?? takeFlag(work, "--variant"));
|
|
481
|
-
assertNoUnknownFlags(work, "
|
|
472
|
+
assertNoUnknownFlags(work, "store");
|
|
482
473
|
const data = await v1Post(`${base}/items/${encodeURIComponent(itemId)}/variants/${encodeURIComponent(variantId)}/archive`, {});
|
|
483
474
|
if (isJson()) {
|
|
484
475
|
emitOk("shop", data);
|
|
@@ -495,7 +486,7 @@ export async function runShop(args) {
|
|
|
495
486
|
if (!sub || sub === "list" || sub.startsWith("-")) {
|
|
496
487
|
const listWork = sub === "list" ? work : rest.slice(1);
|
|
497
488
|
const archived = hasFlag(listWork, "--archived");
|
|
498
|
-
assertNoUnknownFlags(listWork, "
|
|
489
|
+
assertNoUnknownFlags(listWork, "store");
|
|
499
490
|
const qs = archived ? "?archived=1" : "";
|
|
500
491
|
const data = await v1Get(`${base}/categories${qs}`);
|
|
501
492
|
if (isJson()) {
|
|
@@ -517,9 +508,9 @@ export async function runShop(args) {
|
|
|
517
508
|
if (slug && work.includes(slug))
|
|
518
509
|
work.splice(work.indexOf(slug), 1);
|
|
519
510
|
const label = takeFlag(work, "--label") ?? takeFlag(work, "--title");
|
|
520
|
-
assertNoUnknownFlags(work, "
|
|
511
|
+
assertNoUnknownFlags(work, "store");
|
|
521
512
|
if (!slug || !SHOP_ID_RE.test(slug) || !label) {
|
|
522
|
-
throw new CliHttpError("Usage: frontpage
|
|
513
|
+
throw new CliHttpError("Usage: frontpage store categories create hats --label Hats", EXIT_USAGE, 0, "bad_request");
|
|
523
514
|
}
|
|
524
515
|
const data = await v1Post(`${base}/categories`, {
|
|
525
516
|
slug,
|
|
@@ -535,9 +526,9 @@ export async function runShop(args) {
|
|
|
535
526
|
if (sub === "rename") {
|
|
536
527
|
const slug = requireShopId(work, "Category slug");
|
|
537
528
|
const label = takeFlag(work, "--label") ?? takeFlag(work, "--title");
|
|
538
|
-
assertNoUnknownFlags(work, "
|
|
529
|
+
assertNoUnknownFlags(work, "store");
|
|
539
530
|
if (!label) {
|
|
540
|
-
throw new CliHttpError("Usage: frontpage
|
|
531
|
+
throw new CliHttpError("Usage: frontpage store categories rename hats --label Hats", EXIT_USAGE, 0, "bad_request");
|
|
541
532
|
}
|
|
542
533
|
const data = await v1Patch(`${base}/categories/${encodeURIComponent(slug)}`, { label });
|
|
543
534
|
if (isJson()) {
|
|
@@ -549,7 +540,7 @@ export async function runShop(args) {
|
|
|
549
540
|
}
|
|
550
541
|
if (sub === "archive") {
|
|
551
542
|
const slug = requireShopId(work, "Category slug");
|
|
552
|
-
assertNoUnknownFlags(work, "
|
|
543
|
+
assertNoUnknownFlags(work, "store");
|
|
553
544
|
const data = await v1Post(`${base}/categories/${encodeURIComponent(slug)}/archive`, {});
|
|
554
545
|
if (isJson()) {
|
|
555
546
|
emitOk("shop", data);
|
|
@@ -564,7 +555,7 @@ export async function runShop(args) {
|
|
|
564
555
|
const sub = rest[1] ?? "get";
|
|
565
556
|
const work = rest.slice(2);
|
|
566
557
|
if (sub === "get") {
|
|
567
|
-
assertNoUnknownFlags(work, "
|
|
558
|
+
assertNoUnknownFlags(work, "store");
|
|
568
559
|
const data = await v1Get(`${base}/settings`);
|
|
569
560
|
if (isJson()) {
|
|
570
561
|
emitOk("shop", data);
|
|
@@ -573,19 +564,31 @@ export async function runShop(args) {
|
|
|
573
564
|
const s = data.settings ?? {};
|
|
574
565
|
const fee = (s.checkoutFee ?? {});
|
|
575
566
|
const fulfill = (s.fulfillment ?? {});
|
|
576
|
-
const
|
|
577
|
-
|
|
567
|
+
const methods = [
|
|
568
|
+
fulfill.pickupEnabled ? "pickup" : null,
|
|
569
|
+
fulfill.shippingEnabled ? "delivery" : null,
|
|
570
|
+
].filter(Boolean);
|
|
571
|
+
const fulfillText = methods.length > 0 ? methods.join("+") : fulfill.shipping ?? "(no fulfillment)";
|
|
572
|
+
const checkoutText = s.storeCheckout === "instant" ? "pay-now" : "cart";
|
|
573
|
+
const feeText = fee.enabled ? `service-fee ${fee.cents ?? 0}` : "service-fee off";
|
|
574
|
+
console.log(`${s.currency ?? "(no currency)"} ${fulfillText} ${checkoutText} ${feeText}`);
|
|
578
575
|
return EXIT_OK;
|
|
579
576
|
}
|
|
580
577
|
if (sub === "set-fulfillment") {
|
|
581
578
|
const mode = takeFlag(work, "--mode") ?? takeFlag(work, "--shipping");
|
|
579
|
+
const pickupOn = takeBoolish(work, "--pickup", "pickupEnabled");
|
|
580
|
+
const deliveryOn = takeBoolish(work, "--delivery", "shippingEnabled");
|
|
581
|
+
const pickupLocationName = takeFlag(work, "--pickup-location");
|
|
582
|
+
const pickupAddress = takeFlag(work, "--pickup-address");
|
|
583
|
+
const pickupHours = takeFlag(work, "--pickup-hours");
|
|
584
|
+
const pickupInstructions = takeFlag(work, "--pickup-instructions");
|
|
582
585
|
const flatCents = parseCentsFlag(takeFlag(work, "--flat-cents"), "flatRateCents");
|
|
583
586
|
const ratesRaw = takeFlag(work, "--country-rates");
|
|
584
587
|
const restOn = takeBoolish(work, "--rest-of-world", "restOfWorldEnabled");
|
|
585
588
|
const restCents = parseCentsFlag(takeFlag(work, "--rest-cents"), "restOfWorldCents");
|
|
586
589
|
const freeOn = takeBoolish(work, "--free-over", "freeShippingOverEnabled");
|
|
587
590
|
const freeCents = parseCentsFlag(takeFlag(work, "--free-over-cents"), "freeShippingOverCents");
|
|
588
|
-
assertNoUnknownFlags(work, "
|
|
591
|
+
assertNoUnknownFlags(work, "store");
|
|
589
592
|
let countryRates;
|
|
590
593
|
if (ratesRaw) {
|
|
591
594
|
try {
|
|
@@ -597,6 +600,12 @@ export async function runShop(args) {
|
|
|
597
600
|
}
|
|
598
601
|
const data = await v1Post(`${base}/settings/fulfillment`, {
|
|
599
602
|
shipping: mode,
|
|
603
|
+
...(pickupOn !== undefined ? { pickupEnabled: pickupOn } : {}),
|
|
604
|
+
...(deliveryOn !== undefined ? { shippingEnabled: deliveryOn } : {}),
|
|
605
|
+
...(pickupLocationName !== undefined ? { pickupLocationName } : {}),
|
|
606
|
+
...(pickupAddress !== undefined ? { pickupAddress } : {}),
|
|
607
|
+
...(pickupHours !== undefined ? { pickupHours } : {}),
|
|
608
|
+
...(pickupInstructions !== undefined ? { pickupInstructions } : {}),
|
|
600
609
|
flatRateCents: flatCents,
|
|
601
610
|
countryRates,
|
|
602
611
|
restOfWorldEnabled: restOn,
|
|
@@ -612,9 +621,9 @@ export async function runShop(args) {
|
|
|
612
621
|
}
|
|
613
622
|
if (sub === "set-currency") {
|
|
614
623
|
const currency = takeFlag(work, "--currency");
|
|
615
|
-
assertNoUnknownFlags(work, "
|
|
624
|
+
assertNoUnknownFlags(work, "store");
|
|
616
625
|
if (!currency) {
|
|
617
|
-
throw new CliHttpError("Usage: frontpage
|
|
626
|
+
throw new CliHttpError("Usage: frontpage store settings set-currency --currency usd (any Stripe presentment code such as usd or jpy)", EXIT_USAGE, 0, "bad_request");
|
|
618
627
|
}
|
|
619
628
|
const data = await v1Post(`${base}/settings/currency`, { currency });
|
|
620
629
|
if (isJson())
|
|
@@ -623,10 +632,23 @@ export async function runShop(args) {
|
|
|
623
632
|
console.log("Currency saved.");
|
|
624
633
|
return EXIT_OK;
|
|
625
634
|
}
|
|
635
|
+
if (sub === "set-checkout") {
|
|
636
|
+
const checkout = takeFlag(work, "--mode") ?? takeFlag(work, "--checkout");
|
|
637
|
+
assertNoUnknownFlags(work, "store");
|
|
638
|
+
if (checkout !== "cart" && checkout !== "instant") {
|
|
639
|
+
throw new CliHttpError("Usage: frontpage store settings set-checkout --mode cart|instant", EXIT_USAGE, 0, "bad_request");
|
|
640
|
+
}
|
|
641
|
+
const data = await v1Post(`${base}/settings/checkout`, { checkout });
|
|
642
|
+
if (isJson())
|
|
643
|
+
emitOk("shop", data);
|
|
644
|
+
else
|
|
645
|
+
console.log(checkout === "instant" ? "Checkout is Pay now." : "Checkout is add to cart.");
|
|
646
|
+
return EXIT_OK;
|
|
647
|
+
}
|
|
626
648
|
if (sub === "set-checkout-fee") {
|
|
627
649
|
const off = hasFlag(work, "--off");
|
|
628
650
|
const cents = parseCentsFlag(takeFlag(work, "--cents"), "checkoutFeeCents");
|
|
629
|
-
assertNoUnknownFlags(work, "
|
|
651
|
+
assertNoUnknownFlags(work, "store");
|
|
630
652
|
const data = await v1Post(`${base}/settings/checkout-fee`, {
|
|
631
653
|
enabled: off ? false : true,
|
|
632
654
|
cents,
|
|
@@ -634,7 +656,7 @@ export async function runShop(args) {
|
|
|
634
656
|
if (isJson())
|
|
635
657
|
emitOk("shop", data);
|
|
636
658
|
else
|
|
637
|
-
console.log(off ? "
|
|
659
|
+
console.log(off ? "Service fee off." : "Service fee saved.");
|
|
638
660
|
return EXIT_OK;
|
|
639
661
|
}
|
|
640
662
|
return emitUsage("shop", USAGE);
|
|
@@ -642,7 +664,7 @@ export async function runShop(args) {
|
|
|
642
664
|
if (group === "connect") {
|
|
643
665
|
const work = rest.slice(1);
|
|
644
666
|
const noOpen = hasFlag(work, "--no-open");
|
|
645
|
-
assertNoUnknownFlags(work, "
|
|
667
|
+
assertNoUnknownFlags(work, "store");
|
|
646
668
|
const data = await v1Post(`${base}/connect`, { action: "connect" });
|
|
647
669
|
const already = data.alreadyConnected === true;
|
|
648
670
|
if (isJson()) {
|
|
@@ -663,7 +685,7 @@ export async function runShop(args) {
|
|
|
663
685
|
}
|
|
664
686
|
if (group === "status") {
|
|
665
687
|
const work = rest.slice(1);
|
|
666
|
-
assertNoUnknownFlags(work, "
|
|
688
|
+
assertNoUnknownFlags(work, "store");
|
|
667
689
|
const data = await v1Get(`${base}/connect`);
|
|
668
690
|
if (isJson()) {
|
|
669
691
|
emitOk("shop", data);
|
|
@@ -682,7 +704,7 @@ export async function runShop(args) {
|
|
|
682
704
|
}
|
|
683
705
|
if (group === "disconnect") {
|
|
684
706
|
const work = rest.slice(1);
|
|
685
|
-
assertNoUnknownFlags(work, "
|
|
707
|
+
assertNoUnknownFlags(work, "store");
|
|
686
708
|
const refuse = requireYesOrTty("disconnect the store (shared Stripe account with payments)");
|
|
687
709
|
if (refuse)
|
|
688
710
|
return emitUsage("shop", refuse);
|
|
@@ -694,12 +716,36 @@ export async function runShop(args) {
|
|
|
694
716
|
console.log(typeof data.message === "string" ? data.message : "Disconnected.");
|
|
695
717
|
return EXIT_OK;
|
|
696
718
|
}
|
|
719
|
+
if (group === "import") {
|
|
720
|
+
const work = rest.slice(1);
|
|
721
|
+
assertNoUnknownFlags(work, "store");
|
|
722
|
+
const data = await v1Post(`${base}/import`, {});
|
|
723
|
+
if (isJson()) {
|
|
724
|
+
emitOk("shop", data);
|
|
725
|
+
return EXIT_OK;
|
|
726
|
+
}
|
|
727
|
+
const imported = data.imported ?? [];
|
|
728
|
+
const skipped = data.skipped ?? [];
|
|
729
|
+
const failed = data.failed ?? [];
|
|
730
|
+
if (imported.length === 0 && skipped.length === 0 && failed.length === 0) {
|
|
731
|
+
console.log("No src/content/products files to import.");
|
|
732
|
+
return EXIT_OK;
|
|
733
|
+
}
|
|
734
|
+
for (const row of imported)
|
|
735
|
+
console.log(`imported ${row.itemId} ${row.title}`);
|
|
736
|
+
for (const row of skipped)
|
|
737
|
+
console.log(`skipped ${row.itemId} already in Store`);
|
|
738
|
+
for (const row of failed)
|
|
739
|
+
console.log(`failed ${row.path} ${row.reason}`);
|
|
740
|
+
console.log(`${imported.length} imported ${skipped.length} skipped ${failed.length} failed`);
|
|
741
|
+
return EXIT_OK;
|
|
742
|
+
}
|
|
697
743
|
if (group === "orders" || group === "payments") {
|
|
698
744
|
const noun = group;
|
|
699
745
|
const sub = rest[1] ?? "list";
|
|
700
746
|
const work = rest.slice(2);
|
|
701
747
|
if (sub === "list") {
|
|
702
|
-
assertNoUnknownFlags(work, "
|
|
748
|
+
assertNoUnknownFlags(work, "store");
|
|
703
749
|
const data = await v1Get(`${base}/${noun}`);
|
|
704
750
|
if (isJson()) {
|
|
705
751
|
emitOk("shop", data);
|
|
@@ -717,7 +763,7 @@ export async function runShop(args) {
|
|
|
717
763
|
}
|
|
718
764
|
if (sub === "get") {
|
|
719
765
|
const id = requireLedgerId(work, noun === "orders" ? "Order" : "Payment");
|
|
720
|
-
assertNoUnknownFlags(work, "
|
|
766
|
+
assertNoUnknownFlags(work, "store");
|
|
721
767
|
const data = await v1Get(`${base}/${noun}/${encodeURIComponent(id)}`);
|
|
722
768
|
if (isJson()) {
|
|
723
769
|
emitOk("shop", data);
|
|
@@ -26,6 +26,8 @@ _frontpage_completions() {
|
|
|
26
26
|
articles) COMPREPLY=( $(compgen -W "list content create-section create-article set-draft" -- "\${cur}") ) ;;
|
|
27
27
|
analytics) COMPREPLY=( $(compgen -W "dashboard summary query funnel timeseries compare sql" -- "\${cur}") ) ;;
|
|
28
28
|
people) COMPREPLY=( $(compgen -W "list get add set note rm-note follow-up hide unhide" -- "\${cur}") ) ;;
|
|
29
|
+
routines) COMPREPLY=( $(compgen -W "list get add set pause resume rm run runs" -- "\${cur}") ) ;;
|
|
30
|
+
store) COMPREPLY=( $(compgen -W "items variants categories settings orders payments connect status disconnect import" -- "\${cur}") ) ;;
|
|
29
31
|
modules)
|
|
30
32
|
if [[ \${COMP_CWORD} -ge 3 && \${COMP_WORDS[2]} == google_reviews ]]; then
|
|
31
33
|
COMPREPLY=( $(compgen -W "docs request-setup enable disable archive config connect resolve status list-reviews hide show set-stars set-sort set-weight reset-weights write-review-url refresh disconnect" -- "\${cur}") )
|
|
@@ -33,12 +35,10 @@ _frontpage_completions() {
|
|
|
33
35
|
COMPREPLY=( $(compgen -W "docs request-setup enable disable archive config get set destinations connect-destination remove-destination disconnect-destination attach-destination detach-destination request-destination-setup" -- "\${cur}") )
|
|
34
36
|
elif [[ \${COMP_CWORD} -ge 3 && (\${COMP_WORDS[2]} == callbar || \${COMP_WORDS[2]} == booking || \${COMP_WORDS[2]} == signups) ]]; then
|
|
35
37
|
COMPREPLY=( $(compgen -W "docs request-setup enable disable archive config get set" -- "\${cur}") )
|
|
36
|
-
elif [[ \${COMP_CWORD} -ge 3 &&
|
|
38
|
+
elif [[ \${COMP_CWORD} -ge 3 && \${COMP_WORDS[2]} == payments ]]; then
|
|
37
39
|
COMPREPLY=( $(compgen -W "docs request-setup enable disable archive config status connect disconnect" -- "\${cur}") )
|
|
38
|
-
elif [[ \${COMP_CWORD} -ge 3 && \${COMP_WORDS[2]} == ordering ]]; then
|
|
39
|
-
COMPREPLY=( $(compgen -W "docs request-setup enable disable archive config status connect disconnect sync" -- "\${cur}") )
|
|
40
40
|
else
|
|
41
|
-
COMPREPLY=( $(compgen -W "list docs request-setup enable disable archive config callbar forms booking signups payments
|
|
41
|
+
COMPREPLY=( $(compgen -W "list docs request-setup enable disable archive config callbar forms booking signups payments articles google_reviews" -- "\${cur}") )
|
|
42
42
|
fi
|
|
43
43
|
;;
|
|
44
44
|
extensions) COMPREPLY=( $(compgen -W "list docs enable disable config" -- "\${cur}") ) ;;
|
|
@@ -71,6 +71,8 @@ _frontpage() {
|
|
|
71
71
|
seo|settings) _values 'subcommand' get set ;;
|
|
72
72
|
analytics) _values 'subcommand' dashboard summary query funnel timeseries compare sql ;;
|
|
73
73
|
people) _values 'subcommand' list get add set note rm-note follow-up hide unhide ;;
|
|
74
|
+
routines) _values 'subcommand' list get add set pause resume rm run runs ;;
|
|
75
|
+
store) _values 'subcommand' items variants categories settings orders payments connect status disconnect import ;;
|
|
74
76
|
modules)
|
|
75
77
|
if [[ $words[2] == google_reviews ]]; then
|
|
76
78
|
_values 'subcommand' docs request-setup enable disable archive config connect resolve status list-reviews hide show set-stars set-sort set-weight reset-weights write-review-url refresh disconnect
|
|
@@ -78,12 +80,10 @@ _frontpage() {
|
|
|
78
80
|
_values 'subcommand' docs request-setup enable disable archive config get set destinations connect-destination remove-destination disconnect-destination attach-destination detach-destination request-destination-setup
|
|
79
81
|
elif [[ $words[2] == callbar || $words[2] == booking || $words[2] == signups ]]; then
|
|
80
82
|
_values 'subcommand' docs request-setup enable disable archive config get set
|
|
81
|
-
elif [[ $words[2] == payments
|
|
83
|
+
elif [[ $words[2] == payments ]]; then
|
|
82
84
|
_values 'subcommand' docs request-setup enable disable archive config status connect disconnect
|
|
83
|
-
elif [[ $words[2] == ordering ]]; then
|
|
84
|
-
_values 'subcommand' docs request-setup enable disable archive config status connect disconnect sync
|
|
85
85
|
else
|
|
86
|
-
_values 'subcommand' list docs request-setup enable disable archive config callbar forms booking signups payments
|
|
86
|
+
_values 'subcommand' list docs request-setup enable disable archive config callbar forms booking signups payments articles google_reviews
|
|
87
87
|
fi
|
|
88
88
|
;;
|
|
89
89
|
extensions) _values 'subcommand' list docs enable disable config ;;
|
|
@@ -109,12 +109,13 @@ export function generateFishCompletion() {
|
|
|
109
109
|
`complete -c frontpage -n "__fish_seen_subcommand_from seo settings" -a "get set"`,
|
|
110
110
|
`complete -c frontpage -n "__fish_seen_subcommand_from analytics" -a "dashboard summary query funnel timeseries compare sql"`,
|
|
111
111
|
`complete -c frontpage -n "__fish_seen_subcommand_from people" -a "list get add set note rm-note follow-up hide unhide"`,
|
|
112
|
-
`complete -c frontpage -n "__fish_seen_subcommand_from
|
|
112
|
+
`complete -c frontpage -n "__fish_seen_subcommand_from routines" -a "list get add set pause resume rm run runs"`,
|
|
113
|
+
`complete -c frontpage -n "__fish_seen_subcommand_from store" -a "items variants categories settings orders payments connect status disconnect import"`,
|
|
114
|
+
`complete -c frontpage -n "__fish_seen_subcommand_from modules" -a "list docs request-setup enable disable archive config callbar forms booking signups payments articles google_reviews"`,
|
|
113
115
|
`complete -c frontpage -n "__fish_seen_subcommand_from modules; and __fish_seen_subcommand_from google_reviews" -a "connect resolve status list-reviews hide show set-stars set-sort set-weight reset-weights write-review-url refresh disconnect"`,
|
|
114
116
|
`complete -c frontpage -n "__fish_seen_subcommand_from modules; and __fish_seen_subcommand_from forms" -a "get set destinations connect-destination remove-destination disconnect-destination attach-destination detach-destination request-destination-setup"`,
|
|
115
117
|
`complete -c frontpage -n "__fish_seen_subcommand_from modules; and __fish_seen_subcommand_from callbar booking signups" -a "get set"`,
|
|
116
|
-
`complete -c frontpage -n "__fish_seen_subcommand_from modules; and __fish_seen_subcommand_from payments
|
|
117
|
-
`complete -c frontpage -n "__fish_seen_subcommand_from modules; and __fish_seen_subcommand_from ordering" -a "status connect disconnect sync"`,
|
|
118
|
+
`complete -c frontpage -n "__fish_seen_subcommand_from modules; and __fish_seen_subcommand_from payments" -a "status connect disconnect"`,
|
|
118
119
|
`complete -c frontpage -n "__fish_seen_subcommand_from extensions" -a "list docs enable disable config"`,
|
|
119
120
|
`complete -c frontpage -l site -d "Site subdomain slug"`,
|
|
120
121
|
];
|
package/dist/http/client.js
CHANGED
|
@@ -51,7 +51,7 @@ export function httpErrorFromV1(status, parsed, fallbackMessage) {
|
|
|
51
51
|
if (lower === "not found." || lower === "not found") {
|
|
52
52
|
return new CliHttpError("API not available (is PUBLIC_CLI_ENABLED on for this environment?).", EXIT_UNEXPECTED, status, code, requestId);
|
|
53
53
|
}
|
|
54
|
-
return new CliHttpError(message,
|
|
54
|
+
return new CliHttpError(message, EXIT_USAGE, status, code, requestId);
|
|
55
55
|
}
|
|
56
56
|
return new CliHttpError(message, EXIT_UNEXPECTED, status, code, requestId);
|
|
57
57
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* §CLI-MOD-FW — per-key CLI registry (usage printer + help --json).
|
|
3
3
|
* Instagram is not documented here. Google reviews extras ship in Phase 1.
|
|
4
4
|
*/
|
|
5
|
-
export declare const DOCUMENTED_MODULE_KEYS: readonly ["callbar", "forms", "booking", "signups", "
|
|
5
|
+
export declare const DOCUMENTED_MODULE_KEYS: readonly ["callbar", "forms", "booking", "signups", "articles", "google_reviews"];
|
|
6
6
|
export type DocumentedModuleKey = (typeof DOCUMENTED_MODULE_KEYS)[number];
|
|
7
7
|
export declare const GENERIC_MODULE_VERBS: readonly ["list", "ls", "docs", "doc", "request-setup", "request_setup", "enable", "disable", "archive", "config"];
|
|
8
8
|
export type ModuleCommandDef = {
|
|
@@ -19,10 +19,11 @@ export declare const MODULE_COMMANDS: readonly ModuleCommandDef[];
|
|
|
19
19
|
export declare const GOOGLE_REVIEWS_CLI_ACTIONS: readonly ["connect", "resolve", "status", "list-reviews", "hide", "show", "set-stars", "set-sort", "set-weight", "reset-weights", "write-review-url", "refresh", "disconnect"];
|
|
20
20
|
export declare const TYPED_CONFIG_CLI_ACTIONS: readonly ["get", "set"];
|
|
21
21
|
export declare const STRIPE_OAUTH_CLI_ACTIONS: readonly ["status", "connect", "disconnect"];
|
|
22
|
-
export declare const ORDERING_OAUTH_CLI_ACTIONS: readonly ["status", "connect", "disconnect", "sync"];
|
|
23
22
|
export declare function isCliModuleAction(key: DocumentedModuleKey, action: string): boolean;
|
|
24
23
|
export declare function isDocumentedModuleKey(raw: string): raw is DocumentedModuleKey;
|
|
25
24
|
export declare function isGenericModuleVerb(raw: string): boolean;
|
|
26
25
|
export declare function moduleCommand(key: DocumentedModuleKey): ModuleCommandDef;
|
|
26
|
+
export declare function formatShopIsNotAModule(): string;
|
|
27
|
+
export declare function formatPaymentsIsNotAModule(): string;
|
|
27
28
|
export declare function formatModuleUsage(key: DocumentedModuleKey): string;
|
|
28
29
|
export declare function formatModulesIndex(): string;
|