hookwright 1.1.0 → 1.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.
Files changed (3) hide show
  1. package/README.md +16 -1
  2. package/dist/cli.js +566 -303
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -24,7 +24,7 @@ var init_package = __esm({
24
24
  "package.json"() {
25
25
  package_default = {
26
26
  name: "hookwright",
27
- version: "1.1.0",
27
+ version: "1.2.0",
28
28
  description: "Build real, signed e-commerce webhooks from a live Shopify catalogue \u2014 interactive terminal UI, no backend",
29
29
  keywords: [
30
30
  "webhook",
@@ -71,11 +71,11 @@ var init_package = __esm({
71
71
  });
72
72
 
73
73
  // src/cli.jsx
74
- import React15 from "react";
74
+ import React16 from "react";
75
75
  import { render } from "ink";
76
76
 
77
77
  // src/ui/App.jsx
78
- import React14, { useState as useState8 } from "react";
78
+ import React15, { useState as useState8 } from "react";
79
79
  import { useApp as useApp2 } from "ink";
80
80
 
81
81
  // src/ui/screens/Home.jsx
@@ -331,8 +331,8 @@ function Home({ config, onPick, onQuit }) {
331
331
  const ready = canSend(config);
332
332
  const shop = config.shopify.shop;
333
333
  const options = [
334
- { label: "Setup".padEnd(18) + (ready ? "Shopify and webhook destination" : "connect Shopify and set the webhook URL"), value: "setup" },
335
334
  { label: "Integrations".padEnd(18) + "build and send a provider webhook", value: "integrations" },
335
+ { label: "Setup".padEnd(18) + (ready ? "Shopify and webhook destination" : "connect Shopify and set the webhook URL"), value: "setup" },
336
336
  { label: "History".padEnd(18) + "review or re-send a saved payload", value: "history" },
337
337
  { label: "Doctor".padEnd(18) + "check credentials and connectivity", value: "doctor" },
338
338
  { label: "Clear".padEnd(18) + "remove cached data", value: "clear" },
@@ -407,6 +407,16 @@ function cartPermalink(domain, items) {
407
407
  function money2(value) {
408
408
  return Math.round(Number(value) * 100) / 100;
409
409
  }
410
+ function normalizeCollection(collection) {
411
+ return {
412
+ id: String(collection.id),
413
+ title: collection.title,
414
+ handle: collection.handle,
415
+ kind: collection.kind,
416
+ image: collection.image?.src ?? "",
417
+ productsCount: collection.products_count ?? null
418
+ };
419
+ }
410
420
 
411
421
  // src/providers/cashfree-occ.mjs
412
422
  var GATE_PATH = "type";
@@ -757,15 +767,18 @@ var razorpay_magic_default = {
757
767
  // src/providers/nitro.mjs
758
768
  import crypto3 from "node:crypto";
759
769
  var EVENTS = [
760
- { eventName: "view", type: "nitro_view", label: "Page View" },
761
- { eventName: "category_view", type: "nitro_category_view", label: "Category View" },
762
- { eventName: "product_view", type: "nitro_product_view", label: "Product View" },
763
- { eventName: "addtocart", type: "nitro_addtocart", label: "Add To Cart" },
764
- { eventName: "removefromcart", type: "nitro_removefromcart", label: "Remove From Cart" },
765
- { eventName: "checkout", type: "nitro_checkout", label: "Checkout" },
766
- { eventName: "orders/create", type: "nitro_orders_create", label: "Order Created" },
767
- { eventName: "orders/updated", type: "nitro_orders_updated", label: "Order Updated" }
770
+ { eventName: "view", type: "nitro_view", label: "Page View", selection: "none", subject: "a page, no product" },
771
+ { eventName: "category_view", type: "nitro_category_view", label: "Category View", selection: "collection", subject: "one collection" },
772
+ { eventName: "product_view", type: "nitro_product_view", label: "Product View", selection: "product", subject: "one product" },
773
+ { eventName: "addtocart", type: "nitro_addtocart", label: "Add To Cart", selection: "cart", subject: "cart contents" },
774
+ { eventName: "removefromcart", type: "nitro_removefromcart", label: "Remove From Cart", selection: "cart", subject: "cart contents" },
775
+ { eventName: "checkout", type: "nitro_checkout", label: "Checkout", selection: "cart", subject: "cart contents" },
776
+ { eventName: "orders/create", type: "nitro_orders_create", label: "Order Created", selection: "cart", subject: "ordered items" },
777
+ { eventName: "orders/updated", type: "nitro_orders_updated", label: "Order Updated", selection: "cart", subject: "ordered items" }
768
778
  ];
779
+ function selectionFor(eventName) {
780
+ return EVENTS.find((e) => e.eventName === eventName)?.selection ?? "cart";
781
+ }
769
782
  var DEFAULT_EVENT = "addtocart";
770
783
  var COMMON_FIELDS = [
771
784
  { source: "eventName", target: "\xABgate\xBB", required: true, note: "must match the schema exactly" },
@@ -783,8 +796,9 @@ var FIELD_MAPS = {
783
796
  category_view: [
784
797
  ...COMMON_FIELDS,
785
798
  ...PAGE_FIELDS,
786
- { source: "eventVal.resource_id", target: "eventVal.resource_id", required: true },
799
+ { source: "eventVal.resource_id", target: "eventVal.resource_id", required: true, note: "the collection id" },
787
800
  { source: "eventVal.resource", target: "eventVal.resource" },
801
+ { source: "eventVal.title", target: "collection name", required: true },
788
802
  { source: "eventVal.domain", target: "eventVal.domain" }
789
803
  ],
790
804
  product_view: [
@@ -848,6 +862,17 @@ var EDITABLE = {
848
862
  { group: "Page", path: "eventVal.l", label: "Location URL" },
849
863
  { group: "Page", path: "eventVal._ss", label: "Session id" }
850
864
  ],
865
+ collection: [
866
+ { group: "Collection", path: "eventVal.resource_id", label: "Collection id" },
867
+ { group: "Collection", path: "eventVal.title", label: "Collection name" },
868
+ { group: "Collection", path: "eventVal.l", label: "Collection URL" }
869
+ ],
870
+ product: [
871
+ { group: "Product", path: "eventVal.resource_id", label: "Product id" },
872
+ { group: "Product", path: "eventVal.title", label: "Product title" },
873
+ { group: "Product", path: "eventVal.price", label: "Price", type: "number" },
874
+ { group: "Product", path: "eventVal.image", label: "Image URL" }
875
+ ],
851
876
  cart: [
852
877
  { group: "Cart", path: "eventVal.cart_value", label: "Cart value", type: "number" },
853
878
  { group: "Cart", path: "eventVal.init_cart", label: "Init cart" },
@@ -866,7 +891,8 @@ var EDITABLE = {
866
891
  function editableFieldsFor(eventName) {
867
892
  const e = EDITABLE;
868
893
  if (eventName === "view") return [...e.common, ...e.page];
869
- if (eventName === "category_view" || eventName === "product_view") return [...e.common, ...e.page];
894
+ if (eventName === "category_view") return [...e.common, ...e.page, ...e.collection];
895
+ if (eventName === "product_view") return [...e.common, ...e.page, ...e.product];
870
896
  if (eventName === "addtocart" || eventName === "removefromcart") return [...e.common, ...e.cart];
871
897
  if (eventName === "checkout") return [...e.common, ...e.cart];
872
898
  if (eventName.startsWith("orders/")) return [...e.common, ...e.order];
@@ -919,17 +945,22 @@ function buildPayload3(ctx) {
919
945
  let eventVal;
920
946
  switch (eventName) {
921
947
  case "view":
922
- eventVal = { ...page, page: "home", l: `https://${domain}`, customer };
948
+ eventVal = { page: "home", h: domain, l: `https://${domain}`, _ss: session, domain, customer };
923
949
  break;
924
- case "category_view":
950
+ case "category_view": {
951
+ const collection = ctx.collection;
925
952
  eventVal = {
926
953
  ...page,
954
+ page: "collection",
927
955
  resource: "collection",
928
- resource_id: String(first?.product?.id ?? ""),
929
- l: `https://${domain}/collections/all`,
956
+ resource_id: String(collection?.id ?? ""),
957
+ title: collection?.title,
958
+ image: collection?.image || void 0,
959
+ l: collection?.handle ? `https://${domain}/collections/${collection.handle}` : `https://${domain}/collections/all`,
930
960
  customer
931
961
  };
932
962
  break;
963
+ }
933
964
  case "product_view":
934
965
  eventVal = {
935
966
  ...page,
@@ -1029,6 +1060,7 @@ var nitro_default = {
1029
1060
  fieldMapFor: (eventName) => FIELD_MAPS[eventName] ?? FIELD_MAPS[DEFAULT_EVENT],
1030
1061
  editableFields: editableFields3,
1031
1062
  editableFieldsFor,
1063
+ selectionFor,
1032
1064
  buildPayload: buildPayload3,
1033
1065
  sign: sign3,
1034
1066
  webhookUrl: webhookUrl3,
@@ -1143,8 +1175,8 @@ function Integrations({ config, onPick, onBack, onSetup }) {
1143
1175
  }
1144
1176
 
1145
1177
  // src/ui/screens/Build.jsx
1146
- import React7, { useEffect, useState } from "react";
1147
- import { Box as Box7, Text as Text7, useApp, useInput as useInput3 } from "ink";
1178
+ import React8, { useEffect, useState } from "react";
1179
+ import { Box as Box8, Text as Text8, useApp, useInput as useInput3 } from "ink";
1148
1180
  import { Spinner, Select as Select4, MultiSelect, TextInput, ConfirmInput, Alert, Badge } from "@inkjs/ui";
1149
1181
 
1150
1182
  // src/ui/components/CheckList.jsx
@@ -1195,6 +1227,40 @@ function FieldTable({ coverage: coverage2, limit }) {
1195
1227
  ] });
1196
1228
  }
1197
1229
 
1230
+ // src/ui/components/CommandBar.jsx
1231
+ import React7 from "react";
1232
+ import { Box as Box7, Text as Text7 } from "ink";
1233
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1234
+ function CommandBar({ commands, width: width2 = 78 }) {
1235
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
1236
+ /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: "\u2500".repeat(width2) }),
1237
+ /* @__PURE__ */ jsx7(Box7, { flexWrap: "wrap", children: commands.map((c2, i) => /* @__PURE__ */ jsxs7(Box7, { marginRight: 2, children: [
1238
+ /* @__PURE__ */ jsx7(Text7, { bold: true, color: c2.disabled ? palette.dim : c2.active ? palette.ok : palette.accent, children: c2.key }),
1239
+ /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: ` ${c2.label}` }),
1240
+ i < commands.length - 1 ? /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: " \xB7" }) : null
1241
+ ] }, c2.key)) })
1242
+ ] });
1243
+ }
1244
+ function StatusRow({ label, ok, warn, value, detail, labelWidth = 12 }) {
1245
+ const colour = ok === void 0 ? palette.dim : ok ? palette.ok : warn ? palette.warn : palette.bad;
1246
+ const mark = ok === void 0 ? " " : ok ? "\u2714" : warn ? "\u25B2" : "\u2716";
1247
+ return /* @__PURE__ */ jsxs7(Box7, { children: [
1248
+ /* @__PURE__ */ jsx7(Text7, { color: colour, children: ` ${mark} ` }),
1249
+ /* @__PURE__ */ jsx7(Text7, { bold: true, children: String(label).padEnd(labelWidth) }),
1250
+ /* @__PURE__ */ jsx7(Text7, { color: colour, children: value }),
1251
+ detail ? /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: ` ${detail}` }) : null
1252
+ ] });
1253
+ }
1254
+ function Panel({ title, hint, children }) {
1255
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
1256
+ /* @__PURE__ */ jsxs7(Box7, { children: [
1257
+ /* @__PURE__ */ jsx7(Text7, { bold: true, color: palette.heading, children: title }),
1258
+ hint ? /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: ` ${hint}` }) : null
1259
+ ] }),
1260
+ /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: palette.dim, paddingX: 1, children })
1261
+ ] });
1262
+ }
1263
+
1198
1264
  // src/errors.mjs
1199
1265
  var ForgeError = class extends Error {
1200
1266
  constructor(message, { hint, cause } = {}) {
@@ -1344,6 +1410,20 @@ var ShopifyClient = class {
1344
1410
  const { json } = await this.request("/products/count.json");
1345
1411
  return json?.count ?? 0;
1346
1412
  }
1413
+ /**
1414
+ * Collections, from both endpoints Shopify splits them across: custom
1415
+ * (manually curated) and smart (rule based). Either can back a category page.
1416
+ */
1417
+ async collections({ limit = 50, title } = {}) {
1418
+ const [custom, smart] = await Promise.all([
1419
+ this.request("/custom_collections.json", { query: { limit, title } }).catch(() => ({ json: null })),
1420
+ this.request("/smart_collections.json", { query: { limit, title } }).catch(() => ({ json: null }))
1421
+ ]);
1422
+ return [
1423
+ ...(custom.json?.custom_collections ?? []).map((c2) => ({ ...c2, kind: "custom" })),
1424
+ ...(smart.json?.smart_collections ?? []).map((c2) => ({ ...c2, kind: "smart" }))
1425
+ ];
1426
+ }
1347
1427
  };
1348
1428
  function normalizeDomain(domain) {
1349
1429
  return String(domain).trim().replace(/^https?:\/\//, "").replace(/\/.*$/, "").toLowerCase();
@@ -1369,6 +1449,11 @@ async function fetchCatalogue(cfg, { search, pages = 1, limit = 50 } = {}) {
1369
1449
  const raw = await client.products({ title: search, pages, limit });
1370
1450
  return raw.map(normalizeProduct).filter((p) => p.variants.length);
1371
1451
  }
1452
+ async function fetchCollections(cfg, { search, limit = 50 } = {}) {
1453
+ const client = new ShopifyClient(cfg.shopify);
1454
+ const raw = await client.collections({ title: search, limit });
1455
+ return raw.map(normalizeCollection);
1456
+ }
1372
1457
  function autoSelect(products, count = 1) {
1373
1458
  return products.slice(0, count).map((product) => ({
1374
1459
  product,
@@ -1774,7 +1859,7 @@ function loadPayload(file) {
1774
1859
  }
1775
1860
 
1776
1861
  // src/core/build.mjs
1777
- function draftPayload({ cfg, providerId = "cashfree-occ", items, discount = 0, phone, eventName }) {
1862
+ function draftPayload({ cfg, providerId = "cashfree-occ", items, discount = 0, phone, eventName, collection }) {
1778
1863
  const provider = getProvider(providerId);
1779
1864
  const event = eventName ?? provider.defaultEvent;
1780
1865
  const resolvedPhone = phone ?? cfg.customer.phone;
@@ -1784,6 +1869,7 @@ function draftPayload({ cfg, providerId = "cashfree-occ", items, discount = 0, p
1784
1869
  items,
1785
1870
  discount,
1786
1871
  eventName: event,
1872
+ collection,
1787
1873
  phone: parsed.ok ? parsed.value : String(resolvedPhone ?? "")
1788
1874
  });
1789
1875
  const editable = provider.editableFieldsFor ? provider.editableFieldsFor(event) : provider.editableFields;
@@ -1799,14 +1885,16 @@ function applyEdits(payload, fields, edits) {
1799
1885
  }
1800
1886
  return payload;
1801
1887
  }
1802
- async function buildPayload4({ cfg, providerId = "cashfree-occ", items, discount = 0, phone, checkImageUrls = true, payload: prebuilt, eventName }) {
1803
- if (!items?.length) throw new ConfigError("no products selected");
1888
+ async function buildPayload4({ cfg, providerId = "cashfree-occ", items = [], discount = 0, phone, checkImageUrls = true, payload: prebuilt, eventName, collection }) {
1889
+ const provider0 = getProvider(providerId);
1890
+ const needsItems = !provider0.selectionFor || ["cart", "product"].includes(provider0.selectionFor(eventName ?? provider0.defaultEvent));
1891
+ if (needsItems && !items.length) throw new ConfigError("no products selected");
1804
1892
  const provider = getProvider(providerId);
1805
1893
  const resolvedPhone = phone ?? cfg.customer.phone;
1806
1894
  const parsed = toE164(resolvedPhone, cfg.customer.countryCode);
1807
1895
  if (!parsed.ok) throw new ConfigError(`phone is unusable: ${parsed.reason}`);
1808
1896
  const event = eventName ?? provider.defaultEvent;
1809
- const payload = prebuilt ?? provider.buildPayload({ config: cfg, items, discount, phone: parsed.value, eventName: event });
1897
+ const payload = prebuilt ?? provider.buildPayload({ config: cfg, items, discount, phone: parsed.value, eventName: event, collection });
1810
1898
  const body = JSON.stringify(payload);
1811
1899
  const report = await runAll({ payload, body, provider, config: cfg, checkImageUrls, eventName: event });
1812
1900
  const summary = provider.summarize ? provider.summarize(payload) : {};
@@ -2002,10 +2090,11 @@ async function copy(text, { allowOsc52 = true } = {}) {
2002
2090
  }
2003
2091
 
2004
2092
  // src/ui/screens/Build.jsx
2005
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2093
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
2006
2094
  var STEP = {
2007
2095
  EVENT: "event",
2008
2096
  LOADING: "loading",
2097
+ COLLECTION: "collection",
2009
2098
  PICK: "pick",
2010
2099
  VARIANT: "variant",
2011
2100
  QUANTITY: "quantity",
@@ -2026,6 +2115,8 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2026
2115
  const [eventName, setEventName] = useState(provider.defaultEvent);
2027
2116
  const [step, setStep] = useState(multiEvent ? STEP.EVENT : STEP.LOADING);
2028
2117
  const [products, setProducts] = useState([]);
2118
+ const [collections, setCollections] = useState([]);
2119
+ const [collection, setCollection] = useState(null);
2029
2120
  const [chosen, setChosen] = useState([]);
2030
2121
  const [cursor, setCursor] = useState(0);
2031
2122
  const [items, setItems] = useState([]);
@@ -2037,19 +2128,98 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2037
2128
  const [copied, setCopied] = useState(null);
2038
2129
  const [request, setRequest] = useState(null);
2039
2130
  const [curl, setCurl] = useState("");
2040
- const [showPayload, setShowPayload] = useState(false);
2131
+ const [panel, setPanel] = useState(null);
2041
2132
  const [sendResult, setSendResult] = useState(null);
2042
2133
  const [error, setError] = useState(null);
2134
+ const goBack = () => {
2135
+ switch (step) {
2136
+ case STEP.EVENT:
2137
+ return onDone();
2138
+ case STEP.PICK:
2139
+ case STEP.COLLECTION:
2140
+ return multiEvent ? setStep(STEP.EVENT) : onDone();
2141
+ case STEP.VARIANT:
2142
+ if (cursor === 0) return setStep(STEP.PICK);
2143
+ setItems(items.slice(0, -1));
2144
+ return stepInto(cursor - 1);
2145
+ case STEP.QUANTITY:
2146
+ if (chosen[cursor]?.variants.length > 1) return setStep(STEP.VARIANT);
2147
+ if (cursor === 0) return setStep(STEP.PICK);
2148
+ setItems(items.slice(0, -1));
2149
+ return stepInto(cursor - 1);
2150
+ case STEP.DISCOUNT: {
2151
+ if (selection === "none") return multiEvent ? setStep(STEP.EVENT) : onDone();
2152
+ if (selection === "collection") return setStep(STEP.COLLECTION);
2153
+ const last = chosen.length - 1;
2154
+ setItems(items.slice(0, -1));
2155
+ return stepInto(last);
2156
+ }
2157
+ case STEP.MODE:
2158
+ return setStep(STEP.DISCOUNT);
2159
+ case STEP.FIELDS:
2160
+ if (fieldIndex === 0) return setStep(STEP.MODE);
2161
+ return setFieldIndex(fieldIndex - 1);
2162
+ case STEP.REPORT:
2163
+ return setStep(STEP.MODE);
2164
+ case STEP.RESULT:
2165
+ case STEP.ERROR:
2166
+ return onDone();
2167
+ default:
2168
+ return onDone();
2169
+ }
2170
+ };
2171
+ const stepInto = (index) => {
2172
+ setCursor(index);
2173
+ const product = chosen[index];
2174
+ if (!product) return setStep(STEP.PICK);
2175
+ if (product.variants.length > 1) return setStep(STEP.VARIANT);
2176
+ setPendingVariant(product.variants[0]);
2177
+ setStep(STEP.QUANTITY);
2178
+ };
2043
2179
  useInput3((input, key) => {
2044
- if (key.escape) onDone();
2180
+ if (key.escape) return goBack();
2045
2181
  if ((step === STEP.RESULT || step === STEP.ERROR) && (key.return || input === "q")) onDone();
2046
- if (step === STEP.REPORT && input === "p") setShowPayload((v) => !v);
2047
- if (step === STEP.REPORT && input === "c" && curl) copy(curl).then((r) => setCopied({ ...r, what: "curl" }));
2048
- if (step === STEP.REPORT && input === "j" && built) copy(built.body).then((r) => setCopied({ ...r, what: "payload JSON" }));
2182
+ if (step !== STEP.REPORT) return;
2183
+ const toggle = (name) => setPanel((v) => v === name ? null : name);
2184
+ if (input === "p") toggle("payload");
2185
+ if (input === "f") toggle("fields");
2186
+ if (input === "v") toggle("checks");
2187
+ if (input === "r") toggle("request");
2188
+ if (input === "u") toggle("curl");
2189
+ if (input === "c" && curl) copy(curl).then((r) => setCopied({ ...r, what: "curl" }));
2190
+ if (input === "j" && built) copy(built.body).then((r) => setCopied({ ...r, what: "payload JSON" }));
2191
+ if ((input === "s" || key.return) && built?.report.ok) doSend();
2049
2192
  });
2193
+ const selection = provider.selectionFor ? provider.selectionFor(eventName) : "cart";
2050
2194
  useEffect(() => {
2051
2195
  if (step === STEP.EVENT) return;
2052
2196
  let alive = true;
2197
+ if (selection === "none") {
2198
+ startReview(0);
2199
+ return () => {
2200
+ alive = false;
2201
+ };
2202
+ }
2203
+ if (selection === "collection") {
2204
+ fetchCollections(config).then((list) => {
2205
+ if (!alive) return;
2206
+ if (!list.length) {
2207
+ setError({ message: "this store has no collections", hint: "create one in Shopify, or pick a different event" });
2208
+ setStep(STEP.ERROR);
2209
+ return;
2210
+ }
2211
+ setCollections(list);
2212
+ setStep(STEP.COLLECTION);
2213
+ }).catch((err) => {
2214
+ if (alive) {
2215
+ setError({ message: err.message, hint: err.hint });
2216
+ setStep(STEP.ERROR);
2217
+ }
2218
+ });
2219
+ return () => {
2220
+ alive = false;
2221
+ };
2222
+ }
2053
2223
  fetchCatalogue(config).then((list) => {
2054
2224
  if (!alive) return;
2055
2225
  if (!list.length) {
@@ -2067,11 +2237,12 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2067
2237
  return () => {
2068
2238
  alive = false;
2069
2239
  };
2070
- }, [step === STEP.EVENT]);
2240
+ }, [step === STEP.EVENT, eventName]);
2071
2241
  const advance = (nextItems, nextCursor) => {
2072
2242
  if (nextCursor >= chosen.length) {
2073
2243
  setItems(nextItems);
2074
- setStep(STEP.DISCOUNT);
2244
+ if (selection === "cart") setStep(STEP.DISCOUNT);
2245
+ else startReview(0, collection, nextItems);
2075
2246
  return;
2076
2247
  }
2077
2248
  setItems(nextItems);
@@ -2084,6 +2255,24 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2084
2255
  setStep(STEP.QUANTITY);
2085
2256
  }
2086
2257
  };
2258
+ const onSingleProductPicked = (id) => {
2259
+ const product = products.find((p) => p.id === id);
2260
+ if (!product) return;
2261
+ setChosen([product]);
2262
+ setCursor(0);
2263
+ setItems([]);
2264
+ if (product.variants.length > 1) setStep(STEP.VARIANT);
2265
+ else {
2266
+ setPendingVariant(product.variants[0]);
2267
+ setStep(STEP.QUANTITY);
2268
+ }
2269
+ };
2270
+ const onCollectionPicked = (id) => {
2271
+ const picked = collections.find((c2) => c2.id === id);
2272
+ if (!picked) return;
2273
+ setCollection(picked);
2274
+ startReview(0, picked);
2275
+ };
2087
2276
  const onProductsPicked = (ids) => {
2088
2277
  const picked = ids.map((id) => products.find((p) => p.id === id)).filter(Boolean);
2089
2278
  if (!picked.length) return;
@@ -2108,10 +2297,16 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2108
2297
  const nextItems = [...items, { product, variant: pendingVariant, quantity: qty }];
2109
2298
  advance(nextItems, cursor + 1);
2110
2299
  };
2111
- const onDiscount = (raw) => {
2112
- const discount = Math.max(0, Number.parseFloat(raw) || 0);
2300
+ const startReview = (discount, chosenCollection = collection, chosenItems = items) => {
2113
2301
  try {
2114
- const next = draftPayload({ cfg: config, providerId, items, discount, eventName });
2302
+ const next = draftPayload({
2303
+ cfg: config,
2304
+ providerId,
2305
+ items: chosenItems,
2306
+ discount,
2307
+ eventName,
2308
+ collection: chosenCollection
2309
+ });
2115
2310
  setDraft({ ...next, discount });
2116
2311
  setStep(STEP.MODE);
2117
2312
  } catch (err) {
@@ -2119,9 +2314,10 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2119
2314
  setStep(STEP.ERROR);
2120
2315
  }
2121
2316
  };
2317
+ const onDiscount = (raw) => startReview(Math.max(0, Number.parseFloat(raw) || 0));
2122
2318
  const finalise = (payload) => {
2123
2319
  setStep(STEP.BUILDING);
2124
- buildPayload4({ cfg: config, providerId, items, discount: draft.discount, payload, eventName }).then(async (result) => {
2320
+ buildPayload4({ cfg: config, providerId, items, discount: draft.discount, payload, eventName, collection }).then(async (result) => {
2125
2321
  setBuilt(result);
2126
2322
  let req = null;
2127
2323
  let command = "";
@@ -2170,8 +2366,9 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2170
2366
  };
2171
2367
  const store = config.shopify.domain;
2172
2368
  const currency = config.defaults.currency;
2173
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2174
- /* @__PURE__ */ jsx7(
2369
+ const coverageMissing = built ? built.report.coverage.filter((c2) => c2.status === "MISSING").length : 0;
2370
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2371
+ /* @__PURE__ */ jsx8(
2175
2372
  Header,
2176
2373
  {
2177
2374
  title: "Build payload",
@@ -2179,9 +2376,9 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2179
2376
  right: store
2180
2377
  }
2181
2378
  ),
2182
- step === STEP.EVENT && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2183
- /* @__PURE__ */ jsx7(Text7, { children: "Which event do you want to send?" }),
2184
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(
2379
+ step === STEP.EVENT && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2380
+ /* @__PURE__ */ jsx8(Text8, { children: "Which event do you want to send?" }),
2381
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(
2185
2382
  Select4,
2186
2383
  {
2187
2384
  visibleOptionCount: provider.events.length,
@@ -2193,13 +2390,41 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2193
2390
  }
2194
2391
  ) })
2195
2392
  ] }),
2196
- step === STEP.LOADING && /* @__PURE__ */ jsx7(Spinner, { label: `fetching live products from ${store}\u2026` }),
2197
- step === STEP.PICK && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2198
- /* @__PURE__ */ jsxs7(Text7, { children: [
2199
- `Select the products in the abandoned cart `,
2200
- /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: "(space toggles \xB7 enter confirms)" })
2393
+ step === STEP.LOADING && /* @__PURE__ */ jsx8(Spinner, { label: `fetching live products from ${store}\u2026` }),
2394
+ step === STEP.COLLECTION && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2395
+ /* @__PURE__ */ jsx8(Text8, { children: "Which collection was viewed?" }),
2396
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(
2397
+ Select4,
2398
+ {
2399
+ visibleOptionCount: 10,
2400
+ options: collections.map((c2) => ({
2401
+ label: `${truncate(c2.title, 40).padEnd(41)} ${c2.productsCount != null ? `${c2.productsCount} products` : c2.kind}`,
2402
+ value: c2.id
2403
+ })),
2404
+ onChange: onCollectionPicked
2405
+ }
2406
+ ) })
2407
+ ] }),
2408
+ step === STEP.PICK && selection === "product" && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2409
+ /* @__PURE__ */ jsx8(Text8, { children: "Which product was viewed?" }),
2410
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(
2411
+ Select4,
2412
+ {
2413
+ visibleOptionCount: 10,
2414
+ options: products.map((p) => ({
2415
+ label: `${truncate(p.title, 44).padEnd(45)} ${money(p.variants[0]?.price, currency)}`,
2416
+ value: p.id
2417
+ })),
2418
+ onChange: onSingleProductPicked
2419
+ }
2420
+ ) })
2421
+ ] }),
2422
+ step === STEP.PICK && selection !== "product" && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2423
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2424
+ `Select the products in the cart `,
2425
+ /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: "(space toggles \xB7 enter confirms)" })
2201
2426
  ] }),
2202
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(
2427
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(
2203
2428
  MultiSelect,
2204
2429
  {
2205
2430
  visibleOptionCount: 10,
@@ -2211,12 +2436,12 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2211
2436
  }
2212
2437
  ) })
2213
2438
  ] }),
2214
- step === STEP.VARIANT && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2215
- /* @__PURE__ */ jsxs7(Text7, { children: [
2439
+ step === STEP.VARIANT && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2440
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2216
2441
  `Variant for `,
2217
- /* @__PURE__ */ jsx7(Text7, { bold: true, color: palette.accent, children: chosen[cursor]?.title })
2442
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: palette.accent, children: chosen[cursor]?.title })
2218
2443
  ] }),
2219
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(
2444
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(
2220
2445
  Select4,
2221
2446
  {
2222
2447
  visibleOptionCount: 8,
@@ -2229,33 +2454,33 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2229
2454
  `variant-${cursor}`
2230
2455
  ) })
2231
2456
  ] }),
2232
- step === STEP.QUANTITY && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2233
- /* @__PURE__ */ jsxs7(Text7, { children: [
2457
+ step === STEP.QUANTITY && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2458
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2234
2459
  `Quantity for `,
2235
- /* @__PURE__ */ jsx7(Text7, { bold: true, color: palette.accent, children: chosen[cursor]?.title }),
2236
- /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: pendingVariant?.title ? ` \xB7 ${pendingVariant.title}` : "" })
2460
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: palette.accent, children: chosen[cursor]?.title }),
2461
+ /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: pendingVariant?.title ? ` \xB7 ${pendingVariant.title}` : "" })
2237
2462
  ] }),
2238
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
2239
- /* @__PURE__ */ jsx7(Text7, { color: palette.accent, children: "\u276F " }),
2240
- /* @__PURE__ */ jsx7(TextInput, { defaultValue: "1", placeholder: "1", onSubmit: onQuantity }, `qty-${cursor}`)
2463
+ /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
2464
+ /* @__PURE__ */ jsx8(Text8, { color: palette.accent, children: "\u276F " }),
2465
+ /* @__PURE__ */ jsx8(TextInput, { defaultValue: "1", placeholder: "1", onSubmit: onQuantity }, `qty-${cursor}`)
2241
2466
  ] })
2242
2467
  ] }),
2243
- step === STEP.DISCOUNT && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2244
- /* @__PURE__ */ jsxs7(Text7, { children: [
2468
+ step === STEP.DISCOUNT && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2469
+ /* @__PURE__ */ jsxs8(Text8, { children: [
2245
2470
  `Cart discount in ${currency} `,
2246
- /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: "(0 for none)" })
2471
+ /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: "(0 for none)" })
2247
2472
  ] }),
2248
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
2249
- /* @__PURE__ */ jsx7(Text7, { color: palette.accent, children: "\u276F " }),
2250
- /* @__PURE__ */ jsx7(TextInput, { defaultValue: "0", placeholder: "0", onSubmit: onDiscount })
2473
+ /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
2474
+ /* @__PURE__ */ jsx8(Text8, { color: palette.accent, children: "\u276F " }),
2475
+ /* @__PURE__ */ jsx8(TextInput, { defaultValue: "0", placeholder: "0", onSubmit: onDiscount })
2251
2476
  ] })
2252
2477
  ] }),
2253
- step === STEP.MODE && draft && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2254
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: palette.accent, paddingX: 1, marginBottom: 1, children: [
2255
- /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: `${draft.fields.length} fields have been filled in from Shopify and your profile.` }),
2256
- /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: "Review them one by one, or accept the suggestions as they are." })
2478
+ step === STEP.MODE && draft && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2479
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: palette.accent, paddingX: 1, marginBottom: 1, children: [
2480
+ /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: `${draft.fields.length} fields have been filled in from Shopify and your profile.` }),
2481
+ /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: "Review them one by one, or accept the suggestions as they are." })
2257
2482
  ] }),
2258
- /* @__PURE__ */ jsx7(
2483
+ /* @__PURE__ */ jsx8(
2259
2484
  Select4,
2260
2485
  {
2261
2486
  options: [
@@ -2266,7 +2491,7 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2266
2491
  }
2267
2492
  )
2268
2493
  ] }),
2269
- step === STEP.FIELDS && draft && /* @__PURE__ */ jsx7(
2494
+ step === STEP.FIELDS && draft && /* @__PURE__ */ jsx8(
2270
2495
  FieldPrompt,
2271
2496
  {
2272
2497
  field: draft.fields[fieldIndex],
@@ -2276,38 +2501,79 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2276
2501
  onSubmit: onFieldSubmit
2277
2502
  }
2278
2503
  ),
2279
- step === STEP.BUILDING && /* @__PURE__ */ jsx7(Spinner, { label: "assembling payload, verifying images and signature fidelity\u2026" }),
2280
- (step === STEP.REPORT || step === STEP.CONFIRM) && built && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2281
- /* @__PURE__ */ jsx7(Summary, { built, currency }),
2282
- /* @__PURE__ */ jsx7(Section, { title: "Pre-flight", children: /* @__PURE__ */ jsx7(CheckList, { checks: built.report.checks }) }),
2283
- /* @__PURE__ */ jsx7(Section, { title: "Field coverage", children: /* @__PURE__ */ jsx7(FieldTable, { coverage: built.report.coverage }) }),
2284
- /* @__PURE__ */ jsx7(Section, { title: "Request", children: /* @__PURE__ */ jsx7(RequestPreview, { request, bytes: built.body.length }) }),
2285
- curl ? /* @__PURE__ */ jsx7(Section, { title: "curl \u2014 paste straight into Postman (Import \u2192 Raw text)", children: /* @__PURE__ */ jsx7(Box7, { borderStyle: "round", borderColor: palette.accent, paddingX: 1, flexDirection: "column", children: /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: curl }) }) }) : null,
2286
- showPayload ? /* @__PURE__ */ jsx7(Section, { title: "Payload", children: /* @__PURE__ */ jsx7(Box7, { borderStyle: "round", borderColor: palette.dim, paddingX: 1, flexDirection: "column", children: /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: JSON.stringify(built.payload, null, 2) }) }) }) : null,
2287
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: copied?.ok ? /* @__PURE__ */ jsx7(Text7, { color: palette.ok, children: `\u2714 ${copied.what} copied to clipboard via ${copied.via}` }) : /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: `saved to ${built.file} \xB7 press c to copy the curl` }) }),
2288
- /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: "c copies the curl \xB7 j copies the payload JSON \xB7 p toggles the full payload" }) }),
2289
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: built.report.ok ? /* @__PURE__ */ jsx7(Alert, { variant: "success", children: "payload is valid \u2014 the event will pass the schema gate and signature check" }) : /* @__PURE__ */ jsx7(Alert, { variant: "error", children: `blocking: ${built.report.blocking.map((b) => b.name).join(", ")}` }) }),
2290
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
2291
- /* @__PURE__ */ jsx7(Text7, { children: "Send it to the endpoint now? " }),
2292
- /* @__PURE__ */ jsx7(
2293
- ConfirmInput,
2504
+ step === STEP.BUILDING && /* @__PURE__ */ jsx8(Spinner, { label: "assembling payload, verifying images and signature fidelity\u2026" }),
2505
+ (step === STEP.REPORT || step === STEP.CONFIRM) && built && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2506
+ /* @__PURE__ */ jsx8(Summary, { built, currency }),
2507
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
2508
+ /* @__PURE__ */ jsx8(
2509
+ StatusRow,
2510
+ {
2511
+ label: "Pre-flight",
2512
+ ok: built.report.ok,
2513
+ value: built.report.ok ? `${built.report.checks.length} checks passed` : `${built.report.blocking.length} blocking`,
2514
+ detail: built.report.ok ? "" : built.report.blocking.map((b) => b.name).join(", ")
2515
+ }
2516
+ ),
2517
+ /* @__PURE__ */ jsx8(
2518
+ StatusRow,
2519
+ {
2520
+ label: "Coverage",
2521
+ ok: coverageMissing === 0,
2522
+ value: `${built.report.coverage.length - coverageMissing} of ${built.report.coverage.length} fields resolved`,
2523
+ detail: coverageMissing ? "missing fields render blank in templates" : ""
2524
+ }
2525
+ ),
2526
+ /* @__PURE__ */ jsx8(
2527
+ StatusRow,
2528
+ {
2529
+ label: "Request",
2530
+ ok: Boolean(request),
2531
+ value: request ? `POST \xB7 ${built.body.length} bytes` : "no destination configured",
2532
+ detail: request ? truncate(request.url, 44) : "Setup \u2192 Webhook"
2533
+ }
2534
+ ),
2535
+ /* @__PURE__ */ jsx8(
2536
+ StatusRow,
2294
2537
  {
2295
- isDisabled: !built.report.ok,
2296
- onConfirm: doSend,
2297
- onCancel: () => onDone()
2538
+ label: "Clipboard",
2539
+ ok: copied?.ok,
2540
+ warn: !copied?.ok,
2541
+ value: copied?.ok ? `${copied.what} copied` : "not copied",
2542
+ detail: copied?.ok ? `via ${copied.via}` : "press c"
2298
2543
  }
2299
2544
  )
2300
2545
  ] }),
2301
- !built.report.ok && /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: " sending is disabled while pre-flight fails \u2014 fix the payload, or use the CLI with --force" })
2546
+ panel === "checks" && /* @__PURE__ */ jsx8(Panel, { title: "Pre-flight checks", children: /* @__PURE__ */ jsx8(CheckList, { checks: built.report.checks }) }),
2547
+ panel === "fields" && /* @__PURE__ */ jsx8(Panel, { title: "Field coverage", hint: "what the receiver will read", children: /* @__PURE__ */ jsx8(FieldTable, { coverage: built.report.coverage }) }),
2548
+ panel === "request" && /* @__PURE__ */ jsx8(Panel, { title: "Request", children: /* @__PURE__ */ jsx8(RequestPreview, { request, bytes: built.body.length }) }),
2549
+ panel === "curl" && curl && /* @__PURE__ */ jsx8(Panel, { title: "curl", hint: "Postman \u2192 Import \u2192 Raw text", children: /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: curl }) }),
2550
+ panel === "payload" && /* @__PURE__ */ jsx8(Panel, { title: "Payload", hint: `${built.body.length} bytes`, children: /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: JSON.stringify(built.payload, null, 2) }) }),
2551
+ !built.report.ok && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Alert, { variant: "error", children: `cannot send \u2014 ${built.report.blocking.map((b) => b.detail).join("; ")}` }) }),
2552
+ /* @__PURE__ */ jsx8(
2553
+ CommandBar,
2554
+ {
2555
+ commands: [
2556
+ { key: "s", label: "send", disabled: !built.report.ok },
2557
+ { key: "c", label: "copy curl" },
2558
+ { key: "j", label: "copy json" },
2559
+ { key: "u", label: "curl", active: panel === "curl" },
2560
+ { key: "p", label: "payload", active: panel === "payload" },
2561
+ { key: "f", label: "fields", active: panel === "fields" },
2562
+ { key: "v", label: "checks", active: panel === "checks" },
2563
+ { key: "r", label: "request", active: panel === "request" },
2564
+ { key: "esc", label: "back" }
2565
+ ]
2566
+ }
2567
+ )
2302
2568
  ] }),
2303
- step === STEP.SENDING && /* @__PURE__ */ jsx7(Spinner, { label: "signing and POSTing the webhook\u2026" }),
2304
- step === STEP.RESULT && sendResult && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2305
- /* @__PURE__ */ jsxs7(Box7, { marginBottom: 1, children: [
2306
- sendResult.ok ? /* @__PURE__ */ jsx7(Badge, { color: "green", children: `HTTP ${sendResult.status}` }) : /* @__PURE__ */ jsx7(Badge, { color: "red", children: sendResult.error ? "FAILED" : `HTTP ${sendResult.status}` }),
2307
- /* @__PURE__ */ jsx7(Text7, { children: " " }),
2308
- /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: sendResult.error ?? explainStatus(sendResult.status) })
2569
+ step === STEP.SENDING && /* @__PURE__ */ jsx8(Spinner, { label: "signing and POSTing the webhook\u2026" }),
2570
+ step === STEP.RESULT && sendResult && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2571
+ /* @__PURE__ */ jsxs8(Box8, { marginBottom: 1, children: [
2572
+ sendResult.ok ? /* @__PURE__ */ jsx8(Badge, { color: "green", children: `HTTP ${sendResult.status}` }) : /* @__PURE__ */ jsx8(Badge, { color: "red", children: sendResult.error ? "FAILED" : `HTTP ${sendResult.status}` }),
2573
+ /* @__PURE__ */ jsx8(Text8, { children: " " }),
2574
+ /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: sendResult.error ?? explainStatus(sendResult.status) })
2309
2575
  ] }),
2310
- /* @__PURE__ */ jsx7(
2576
+ /* @__PURE__ */ jsx8(
2311
2577
  KeyValue,
2312
2578
  {
2313
2579
  rows: [
@@ -2320,22 +2586,22 @@ function Build({ config, providerId = "cashfree-occ", onDone }) {
2320
2586
  ]
2321
2587
  }
2322
2588
  ),
2323
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
2324
- /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: "reproduce:" }),
2325
- /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: sendResult.curl })
2589
+ /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
2590
+ /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: "reproduce:" }),
2591
+ /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: sendResult.curl })
2326
2592
  ] }),
2327
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: "press enter to return to the menu" }) })
2593
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: "press enter to return to the menu" }) })
2328
2594
  ] }),
2329
- step === STEP.ERROR && error && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2330
- /* @__PURE__ */ jsx7(Alert, { variant: "error", children: error.message }),
2331
- error.hint ? /* @__PURE__ */ jsx7(Text7, { color: palette.warn, children: ` ${error.hint}` }) : null,
2332
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: "press enter to return to the menu" }) })
2595
+ step === STEP.ERROR && error && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2596
+ /* @__PURE__ */ jsx8(Alert, { variant: "error", children: error.message }),
2597
+ error.hint ? /* @__PURE__ */ jsx8(Text8, { color: palette.warn, children: ` ${error.hint}` }) : null,
2598
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: "press enter to return to the menu" }) })
2333
2599
  ] })
2334
2600
  ] });
2335
2601
  }
2336
2602
  function RequestPreview({ request, bytes: bytes2 }) {
2337
- if (!request) return /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: " destination not configured" });
2338
- return /* @__PURE__ */ jsx7(
2603
+ if (!request) return /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: " destination not configured" });
2604
+ return /* @__PURE__ */ jsx8(
2339
2605
  KeyValue,
2340
2606
  {
2341
2607
  keyWidth: 22,
@@ -2350,20 +2616,20 @@ function RequestPreview({ request, bytes: bytes2 }) {
2350
2616
  }
2351
2617
  function FieldPrompt({ field, index, total, value, onSubmit }) {
2352
2618
  const filled = Math.round(index / total * 30);
2353
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2354
- /* @__PURE__ */ jsxs7(Box7, { children: [
2355
- /* @__PURE__ */ jsx7(Text7, { color: palette.accent, children: "\u2588".repeat(filled) }),
2356
- /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: "\u2591".repeat(30 - filled) }),
2357
- /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: ` ${index + 1}/${total} ${field.group}` })
2619
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2620
+ /* @__PURE__ */ jsxs8(Box8, { children: [
2621
+ /* @__PURE__ */ jsx8(Text8, { color: palette.accent, children: "\u2588".repeat(filled) }),
2622
+ /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: "\u2591".repeat(30 - filled) }),
2623
+ /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: ` ${index + 1}/${total} ${field.group}` })
2358
2624
  ] }),
2359
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
2360
- /* @__PURE__ */ jsx7(Text7, { bold: true, color: palette.heading, children: field.label }),
2361
- field.hint ? /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: ` ${field.hint}` }) : null,
2362
- field.optional ? /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: " optional" }) : null
2625
+ /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
2626
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: palette.heading, children: field.label }),
2627
+ field.hint ? /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: ` ${field.hint}` }) : null,
2628
+ field.optional ? /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: " optional" }) : null
2363
2629
  ] }),
2364
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
2365
- /* @__PURE__ */ jsx7(Text7, { color: palette.accent, children: "\u276F " }),
2366
- /* @__PURE__ */ jsx7(
2630
+ /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
2631
+ /* @__PURE__ */ jsx8(Text8, { color: palette.accent, children: "\u276F " }),
2632
+ /* @__PURE__ */ jsx8(
2367
2633
  TextInput,
2368
2634
  {
2369
2635
  defaultValue: value == null ? "" : String(value),
@@ -2373,32 +2639,29 @@ function FieldPrompt({ field, index, total, value, onSubmit }) {
2373
2639
  field.path
2374
2640
  )
2375
2641
  ] }),
2376
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: "enter accepts the suggestion \xB7 edit the text to change it" }) })
2642
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: "enter accepts the suggestion \xB7 edit the text to change it \xB7 esc goes back a field" }) })
2377
2643
  ] });
2378
2644
  }
2379
2645
  function Summary({ built, currency }) {
2380
- const d = built.payload.data;
2381
- return /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: palette.ok, paddingX: 1, children: /* @__PURE__ */ jsx7(
2382
- KeyValue,
2383
- {
2384
- rows: [
2385
- ["type", built.payload.type],
2386
- ["store", d.store_url],
2387
- ["customer", `${d.customer.shipping_address.customer_name} \xB7 ${d.phone}`],
2388
- ["items", d.line_items.map((i) => `${truncate(i.name, 28)} \xD7${i.quantity}`).join(", ")],
2389
- ["total", `${money(d.total_price, d.line_items[0]?.currency ?? currency)} (was ${money(d.original_total_price)} \xB7 discount ${money(d.total_discount)})`],
2390
- ["checkout", truncate(d.abandoned_checkout_url, 58)],
2391
- ["saved", built.file]
2392
- ]
2393
- }
2394
- ) });
2646
+ const s = built.summary ?? (built.provider.summarize ? built.provider.summarize(built.payload) : {});
2647
+ const rows = [
2648
+ ["provider", built.provider.label],
2649
+ ["event", s.event ?? "\u2014"],
2650
+ ["store", s.store ?? "\u2014"],
2651
+ ["customer", s.customer || "\u2014"],
2652
+ ["items", s.items || "\u2014"],
2653
+ ["total", s.total == null ? "\u2014" : `${money(s.total, s.currency ?? currency)}${s.extra ? ` (${s.extra})` : ""}`]
2654
+ ];
2655
+ if (s.link) rows.push(["link", truncate(s.link, 58)]);
2656
+ rows.push(["saved", built.file]);
2657
+ return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: palette.ok, paddingX: 1, children: /* @__PURE__ */ jsx8(KeyValue, { rows }) });
2395
2658
  }
2396
2659
 
2397
2660
  // src/ui/screens/Configure.jsx
2398
- import React8, { useState as useState2 } from "react";
2399
- import { Box as Box8, Text as Text8, useInput as useInput4 } from "ink";
2661
+ import React9, { useState as useState2 } from "react";
2662
+ import { Box as Box9, Text as Text9, useInput as useInput4 } from "ink";
2400
2663
  import { Spinner as Spinner2, TextInput as TextInput2, PasswordInput, Select as Select5, Alert as Alert2 } from "@inkjs/ui";
2401
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
2664
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
2402
2665
  var FIELDS = [
2403
2666
  { group: "Customer", key: "customer.firstName", label: "First name", placeholder: "Test" },
2404
2667
  { group: "Customer", key: "customer.lastName", label: "Last name", placeholder: "Shopper" },
@@ -2473,9 +2736,9 @@ function Configure({ config, section: initialSection, onDone }) {
2473
2736
  });
2474
2737
  };
2475
2738
  if (!section) {
2476
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2477
- /* @__PURE__ */ jsx8(Header, { title: "Configure", subtitle: "pick what you want to change", right: "esc to go back" }),
2478
- /* @__PURE__ */ jsx8(
2739
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2740
+ /* @__PURE__ */ jsx9(Header, { title: "Configure", subtitle: "pick what you want to change", right: "esc to go back" }),
2741
+ /* @__PURE__ */ jsx9(
2479
2742
  Select5,
2480
2743
  {
2481
2744
  visibleOptionCount: 8,
@@ -2492,29 +2755,29 @@ function Configure({ config, section: initialSection, onDone }) {
2492
2755
  ] });
2493
2756
  }
2494
2757
  if (phase === "verifying") {
2495
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2496
- /* @__PURE__ */ jsx8(Header, { title: "Configure", subtitle: "verifying credentials" }),
2497
- /* @__PURE__ */ jsx8(Spinner2, { label: "contacting Shopify\u2026" })
2758
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2759
+ /* @__PURE__ */ jsx9(Header, { title: "Configure", subtitle: "verifying credentials" }),
2760
+ /* @__PURE__ */ jsx9(Spinner2, { label: "contacting Shopify\u2026" })
2498
2761
  ] });
2499
2762
  }
2500
2763
  if (phase === "done") {
2501
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2502
- /* @__PURE__ */ jsx8(Header, { title: "Configure", subtitle: "saved" }),
2503
- /* @__PURE__ */ jsx8(Alert2, { variant: verifyMsg?.ok ? "success" : "warning", children: verifyMsg?.text ?? "saved" }),
2504
- verifyMsg?.hint ? /* @__PURE__ */ jsx8(Text8, { color: palette.warn, children: ` ${verifyMsg.hint}` }) : null,
2505
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: `config written to ${verifyMsg?.file} (chmod 600)` }) }),
2506
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: "press enter to return to the menu" }) })
2764
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2765
+ /* @__PURE__ */ jsx9(Header, { title: "Configure", subtitle: "saved" }),
2766
+ /* @__PURE__ */ jsx9(Alert2, { variant: verifyMsg?.ok ? "success" : "warning", children: verifyMsg?.text ?? "saved" }),
2767
+ verifyMsg?.hint ? /* @__PURE__ */ jsx9(Text9, { color: palette.warn, children: ` ${verifyMsg.hint}` }) : null,
2768
+ /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: `config written to ${verifyMsg?.file} (chmod 600)` }) }),
2769
+ /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: "press enter to return to the menu" }) })
2507
2770
  ] });
2508
2771
  }
2509
2772
  const current = get(draft, field.key) ?? "";
2510
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2511
- /* @__PURE__ */ jsx8(Header, { title: "Configure", subtitle: `${field.group} \xB7 step ${index + 1} of ${fields.length}`, right: "esc to cancel" }),
2512
- /* @__PURE__ */ jsx8(Progress, { index, total: fields.length }),
2513
- /* @__PURE__ */ jsxs8(Section, { title: field.label, children: [
2514
- field.hint ? /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: ` ${field.hint}` }) : null,
2515
- /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
2516
- /* @__PURE__ */ jsx8(Text8, { color: palette.accent, children: `${glyph.pointer} ` }),
2517
- field.type === "select" ? /* @__PURE__ */ jsx8(
2773
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2774
+ /* @__PURE__ */ jsx9(Header, { title: "Configure", subtitle: `${field.group} \xB7 step ${index + 1} of ${fields.length}`, right: "esc to cancel" }),
2775
+ /* @__PURE__ */ jsx9(Progress, { index, total: fields.length }),
2776
+ /* @__PURE__ */ jsxs9(Section, { title: field.label, children: [
2777
+ field.hint ? /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: ` ${field.hint}` }) : null,
2778
+ /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
2779
+ /* @__PURE__ */ jsx9(Text9, { color: palette.accent, children: `${glyph.pointer} ` }),
2780
+ field.type === "select" ? /* @__PURE__ */ jsx9(
2518
2781
  Select5,
2519
2782
  {
2520
2783
  options: field.options,
@@ -2522,7 +2785,7 @@ function Configure({ config, section: initialSection, onDone }) {
2522
2785
  onChange: commit
2523
2786
  },
2524
2787
  field.key
2525
- ) : field.secret ? /* @__PURE__ */ jsx8(PasswordInput, { placeholder: current ? mask(current) : "\u2022\u2022\u2022\u2022\u2022\u2022", onSubmit: (v) => commit(v || current) }, field.key) : /* @__PURE__ */ jsx8(
2788
+ ) : field.secret ? /* @__PURE__ */ jsx9(PasswordInput, { placeholder: current ? mask(current) : "\u2022\u2022\u2022\u2022\u2022\u2022", onSubmit: (v) => commit(v || current) }, field.key) : /* @__PURE__ */ jsx9(
2526
2789
  TextInput2,
2527
2790
  {
2528
2791
  defaultValue: current,
@@ -2537,18 +2800,18 @@ function Configure({ config, section: initialSection, onDone }) {
2537
2800
  }
2538
2801
  function Progress({ index, total }) {
2539
2802
  const filled = Math.round(index / total * 30);
2540
- return /* @__PURE__ */ jsxs8(Box8, { children: [
2541
- /* @__PURE__ */ jsx8(Text8, { color: palette.accent, children: "\u2588".repeat(filled) }),
2542
- /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: "\u2591".repeat(30 - filled) }),
2543
- /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: ` ${index}/${total}` })
2803
+ return /* @__PURE__ */ jsxs9(Box9, { children: [
2804
+ /* @__PURE__ */ jsx9(Text9, { color: palette.accent, children: "\u2588".repeat(filled) }),
2805
+ /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: "\u2591".repeat(30 - filled) }),
2806
+ /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: ` ${index}/${total}` })
2544
2807
  ] });
2545
2808
  }
2546
2809
 
2547
2810
  // src/ui/screens/ConnectShopify.jsx
2548
- import React9, { useState as useState3 } from "react";
2549
- import { Box as Box9, Text as Text9, useInput as useInput5 } from "ink";
2811
+ import React10, { useState as useState3 } from "react";
2812
+ import { Box as Box10, Text as Text10, useInput as useInput5 } from "ink";
2550
2813
  import { Spinner as Spinner3, TextInput as TextInput3, PasswordInput as PasswordInput2, Alert as Alert3, Badge as Badge2 } from "@inkjs/ui";
2551
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
2814
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
2552
2815
  var STEP2 = { DOMAIN: "domain", TOKEN: "token", VERIFY: "verify", DONE: "done", FAILED: "failed" };
2553
2816
  function ConnectShopify({ config, onDone }) {
2554
2817
  const [draft] = useState3(() => structuredClone(config));
@@ -2579,13 +2842,13 @@ function ConnectShopify({ config, onDone }) {
2579
2842
  setStep(STEP2.FAILED);
2580
2843
  });
2581
2844
  };
2582
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2583
- /* @__PURE__ */ jsx9(Header, { title: "Connect Shopify", subtitle: "the catalogue every payload is built from", right: "esc to cancel" }),
2584
- step === STEP2.DOMAIN && /* @__PURE__ */ jsxs9(Section, { title: "Store domain", children: [
2585
- /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: " the myshopify.com domain, not your custom domain" }),
2586
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
2587
- /* @__PURE__ */ jsx9(Text9, { color: palette.accent, children: `${glyph.pointer} ` }),
2588
- /* @__PURE__ */ jsx9(
2845
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
2846
+ /* @__PURE__ */ jsx10(Header, { title: "Connect Shopify", subtitle: "the catalogue every payload is built from", right: "esc to cancel" }),
2847
+ step === STEP2.DOMAIN && /* @__PURE__ */ jsxs10(Section, { title: "Store domain", children: [
2848
+ /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: " the myshopify.com domain, not your custom domain" }),
2849
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
2850
+ /* @__PURE__ */ jsx10(Text10, { color: palette.accent, children: `${glyph.pointer} ` }),
2851
+ /* @__PURE__ */ jsx10(
2589
2852
  TextInput3,
2590
2853
  {
2591
2854
  defaultValue: draft.shopify.domain,
@@ -2595,12 +2858,12 @@ function ConnectShopify({ config, onDone }) {
2595
2858
  )
2596
2859
  ] })
2597
2860
  ] }),
2598
- step === STEP2.TOKEN && /* @__PURE__ */ jsxs9(Section, { title: "Admin API access token", children: [
2599
- /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: " Shopify admin \u2192 Settings \u2192 Apps and sales channels \u2192 Develop apps" }),
2600
- /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: " the token needs the read_products scope" }),
2601
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
2602
- /* @__PURE__ */ jsx9(Text9, { color: palette.accent, children: `${glyph.pointer} ` }),
2603
- /* @__PURE__ */ jsx9(
2861
+ step === STEP2.TOKEN && /* @__PURE__ */ jsxs10(Section, { title: "Admin API access token", children: [
2862
+ /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: " Shopify admin \u2192 Settings \u2192 Apps and sales channels \u2192 Develop apps" }),
2863
+ /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: " the token needs the read_products scope" }),
2864
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
2865
+ /* @__PURE__ */ jsx10(Text10, { color: palette.accent, children: `${glyph.pointer} ` }),
2866
+ /* @__PURE__ */ jsx10(
2604
2867
  PasswordInput2,
2605
2868
  {
2606
2869
  placeholder: draft.shopify.accessToken ? mask(draft.shopify.accessToken) : "shpat_\u2026",
@@ -2609,14 +2872,14 @@ function ConnectShopify({ config, onDone }) {
2609
2872
  )
2610
2873
  ] })
2611
2874
  ] }),
2612
- step === STEP2.VERIFY && /* @__PURE__ */ jsx9(Spinner3, { label: `connecting to ${draft.shopify.domain}\u2026` }),
2613
- step === STEP2.DONE && result && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2614
- /* @__PURE__ */ jsxs9(Box9, { marginBottom: 1, children: [
2615
- /* @__PURE__ */ jsx9(Badge2, { color: "green", children: "CONNECTED" }),
2616
- /* @__PURE__ */ jsx9(Text9, { children: " " }),
2617
- /* @__PURE__ */ jsx9(Text9, { bold: true, children: result.shop?.name })
2875
+ step === STEP2.VERIFY && /* @__PURE__ */ jsx10(Spinner3, { label: `connecting to ${draft.shopify.domain}\u2026` }),
2876
+ step === STEP2.DONE && result && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
2877
+ /* @__PURE__ */ jsxs10(Box10, { marginBottom: 1, children: [
2878
+ /* @__PURE__ */ jsx10(Badge2, { color: "green", children: "CONNECTED" }),
2879
+ /* @__PURE__ */ jsx10(Text10, { children: " " }),
2880
+ /* @__PURE__ */ jsx10(Text10, { bold: true, children: result.shop?.name })
2618
2881
  ] }),
2619
- /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", borderStyle: "round", borderColor: palette.ok, paddingX: 1, children: /* @__PURE__ */ jsx9(
2882
+ /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: palette.ok, paddingX: 1, children: /* @__PURE__ */ jsx10(
2620
2883
  KeyValue,
2621
2884
  {
2622
2885
  keyWidth: 16,
@@ -2632,29 +2895,29 @@ function ConnectShopify({ config, onDone }) {
2632
2895
  ]
2633
2896
  }
2634
2897
  ) }),
2635
- result.applied.length ? /* @__PURE__ */ jsx9(Section, { title: "Picked up from the store", children: result.applied.map((line, i) => /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: ` ${glyph.tick} ${line}` }, i)) }) : null,
2636
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Alert3, { variant: "success", children: "Shopify connected \u2014 you can browse the real catalogue now" }) }),
2637
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: "press enter to continue" }) })
2898
+ result.applied.length ? /* @__PURE__ */ jsx10(Section, { title: "Picked up from the store", children: result.applied.map((line, i) => /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: ` ${glyph.tick} ${line}` }, i)) }) : null,
2899
+ /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Alert3, { variant: "success", children: "Shopify connected \u2014 you can browse the real catalogue now" }) }),
2900
+ /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: "press enter to continue" }) })
2638
2901
  ] }),
2639
- step === STEP2.FAILED && error && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2640
- /* @__PURE__ */ jsx9(Alert3, { variant: "error", children: error.message }),
2641
- error.hint ? /* @__PURE__ */ jsx9(Text9, { color: palette.warn, children: ` ${error.hint}` }) : null,
2642
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
2643
- /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: " common causes:" }),
2644
- /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: " \xB7 the token is missing the read_products scope" }),
2645
- /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: " \xB7 the token belongs to a different store" }),
2646
- /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: " \xB7 the domain is the custom domain, not the .myshopify.com one" })
2902
+ step === STEP2.FAILED && error && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
2903
+ /* @__PURE__ */ jsx10(Alert3, { variant: "error", children: error.message }),
2904
+ error.hint ? /* @__PURE__ */ jsx10(Text10, { color: palette.warn, children: ` ${error.hint}` }) : null,
2905
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
2906
+ /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: " common causes:" }),
2907
+ /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: " \xB7 the token is missing the read_products scope" }),
2908
+ /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: " \xB7 the token belongs to a different store" }),
2909
+ /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: " \xB7 the domain is the custom domain, not the .myshopify.com one" })
2647
2910
  ] }),
2648
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text9, { color: palette.dim, children: "press enter to try again" }) })
2911
+ /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: "press enter to try again" }) })
2649
2912
  ] })
2650
2913
  ] });
2651
2914
  }
2652
2915
 
2653
2916
  // src/ui/screens/Webhook.jsx
2654
- import React10, { useState as useState4 } from "react";
2655
- import { Box as Box10, Text as Text10, useInput as useInput6 } from "ink";
2917
+ import React11, { useState as useState4 } from "react";
2918
+ import { Box as Box11, Text as Text11, useInput as useInput6 } from "ink";
2656
2919
  import { Select as Select6, TextInput as TextInput4, PasswordInput as PasswordInput3, Alert as Alert4, Badge as Badge3, Spinner as Spinner4 } from "@inkjs/ui";
2657
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
2920
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
2658
2921
  var STEP3 = { PICK: "pick", URL: "url", SECRET: "secret", PROBE: "probe", DONE: "done" };
2659
2922
  function Webhook({ config, onDone }) {
2660
2923
  const [draft] = useState4(() => structuredClone(config));
@@ -2704,9 +2967,9 @@ function Webhook({ config, onDone }) {
2704
2967
  }),
2705
2968
  { label: "Back".padEnd(30), value: "__back" }
2706
2969
  ];
2707
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
2708
- /* @__PURE__ */ jsx10(Header, { title: "Webhook destinations", subtitle: "one endpoint and secret per integration", right: "esc to go back" }),
2709
- /* @__PURE__ */ jsx10(
2970
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
2971
+ /* @__PURE__ */ jsx11(Header, { title: "Webhook destinations", subtitle: "one endpoint and secret per integration", right: "esc to go back" }),
2972
+ /* @__PURE__ */ jsx11(
2710
2973
  Select6,
2711
2974
  {
2712
2975
  visibleOptionCount: options.length,
@@ -2719,17 +2982,17 @@ function Webhook({ config, onDone }) {
2719
2982
  }
2720
2983
  }
2721
2984
  ),
2722
- /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: `${glyph.dot} set globally \u2014 every build for that provider uses it` }) })
2985
+ /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { color: palette.dim, children: `${glyph.dot} set globally \u2014 every build for that provider uses it` }) })
2723
2986
  ] });
2724
2987
  }
2725
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
2726
- /* @__PURE__ */ jsx10(Header, { title: meta.label, subtitle: `signature: ${meta.signature}`, right: "esc to cancel" }),
2727
- step === STEP3.URL && /* @__PURE__ */ jsxs10(Section, { title: "Webhook URL", children: [
2728
- /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: " the full endpoint the provider would call \u2014 paste it as-is" }),
2729
- urlError ? /* @__PURE__ */ jsx10(Text10, { color: palette.bad, children: ` ${glyph.cross} ${urlError}` }) : null,
2730
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
2731
- /* @__PURE__ */ jsx10(Text10, { color: palette.accent, children: `${glyph.pointer} ` }),
2732
- /* @__PURE__ */ jsx10(
2988
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
2989
+ /* @__PURE__ */ jsx11(Header, { title: meta.label, subtitle: `signature: ${meta.signature}`, right: "esc to cancel" }),
2990
+ step === STEP3.URL && /* @__PURE__ */ jsxs11(Section, { title: "Webhook URL", children: [
2991
+ /* @__PURE__ */ jsx11(Text11, { color: palette.dim, children: " the full endpoint the provider would call \u2014 paste it as-is" }),
2992
+ urlError ? /* @__PURE__ */ jsx11(Text11, { color: palette.bad, children: ` ${glyph.cross} ${urlError}` }) : null,
2993
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
2994
+ /* @__PURE__ */ jsx11(Text11, { color: palette.accent, children: `${glyph.pointer} ` }),
2995
+ /* @__PURE__ */ jsx11(
2733
2996
  TextInput4,
2734
2997
  {
2735
2998
  defaultValue: target.webhookUrl,
@@ -2739,12 +3002,12 @@ function Webhook({ config, onDone }) {
2739
3002
  )
2740
3003
  ] })
2741
3004
  ] }),
2742
- step === STEP3.SECRET && /* @__PURE__ */ jsxs10(Section, { title: meta.id === "nitro" ? "Bearer token" : "Signing secret", children: [
2743
- /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: ` sent as ${meta.header}` }),
2744
- /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: " must match what the receiver has stored" }),
2745
- /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
2746
- /* @__PURE__ */ jsx10(Text10, { color: palette.accent, children: `${glyph.pointer} ` }),
2747
- /* @__PURE__ */ jsx10(
3005
+ step === STEP3.SECRET && /* @__PURE__ */ jsxs11(Section, { title: meta.id === "nitro" ? "Bearer token" : "Signing secret", children: [
3006
+ /* @__PURE__ */ jsx11(Text11, { color: palette.dim, children: ` sent as ${meta.header}` }),
3007
+ /* @__PURE__ */ jsx11(Text11, { color: palette.dim, children: " must match what the receiver has stored" }),
3008
+ /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
3009
+ /* @__PURE__ */ jsx11(Text11, { color: palette.accent, children: `${glyph.pointer} ` }),
3010
+ /* @__PURE__ */ jsx11(
2748
3011
  PasswordInput3,
2749
3012
  {
2750
3013
  placeholder: target.webhookSecret ? mask(target.webhookSecret) : "the signing secret\u2026",
@@ -2753,14 +3016,14 @@ function Webhook({ config, onDone }) {
2753
3016
  )
2754
3017
  ] })
2755
3018
  ] }),
2756
- step === STEP3.PROBE && /* @__PURE__ */ jsx10(Spinner4, { label: "checking the endpoint is reachable\u2026" }),
2757
- step === STEP3.DONE && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
2758
- /* @__PURE__ */ jsxs10(Box10, { marginBottom: 1, children: [
2759
- /* @__PURE__ */ jsx10(Badge3, { color: probe?.reachable ? "green" : "yellow", children: probe?.reachable ? "REACHABLE" : "UNVERIFIED" }),
2760
- /* @__PURE__ */ jsx10(Text10, { children: " " }),
2761
- /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: probe?.reachable ? `responded HTTP ${probe.status} to an unsigned probe` : probe?.error ?? "could not reach it \u2014 saved anyway" })
3019
+ step === STEP3.PROBE && /* @__PURE__ */ jsx11(Spinner4, { label: "checking the endpoint is reachable\u2026" }),
3020
+ step === STEP3.DONE && /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
3021
+ /* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, children: [
3022
+ /* @__PURE__ */ jsx11(Badge3, { color: probe?.reachable ? "green" : "yellow", children: probe?.reachable ? "REACHABLE" : "UNVERIFIED" }),
3023
+ /* @__PURE__ */ jsx11(Text11, { children: " " }),
3024
+ /* @__PURE__ */ jsx11(Text11, { color: palette.dim, children: probe?.reachable ? `responded HTTP ${probe.status} to an unsigned probe` : probe?.error ?? "could not reach it \u2014 saved anyway" })
2762
3025
  ] }),
2763
- /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: palette.ok, paddingX: 1, children: /* @__PURE__ */ jsx10(
3026
+ /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", borderStyle: "round", borderColor: palette.ok, paddingX: 1, children: /* @__PURE__ */ jsx11(
2764
3027
  KeyValue,
2765
3028
  {
2766
3029
  keyWidth: 10,
@@ -2771,8 +3034,8 @@ function Webhook({ config, onDone }) {
2771
3034
  ]
2772
3035
  }
2773
3036
  ) }),
2774
- !meta.available ? /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Alert4, { variant: "info", children: `saved \u2014 ${meta.label} payload generation is not implemented yet` }) }) : null,
2775
- /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { color: palette.dim, children: "press enter to configure another" }) })
3037
+ !meta.available ? /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Alert4, { variant: "info", children: `saved \u2014 ${meta.label} payload generation is not implemented yet` }) }) : null,
3038
+ /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { color: palette.dim, children: "press enter to configure another" }) })
2776
3039
  ] })
2777
3040
  ] });
2778
3041
  }
@@ -2795,10 +3058,10 @@ async function probeEndpoint(url) {
2795
3058
  }
2796
3059
 
2797
3060
  // src/ui/screens/Doctor.jsx
2798
- import React11, { useEffect as useEffect2, useState as useState5 } from "react";
2799
- import { Box as Box11, Text as Text11, useInput as useInput7 } from "ink";
3061
+ import React12, { useEffect as useEffect2, useState as useState5 } from "react";
3062
+ import { Box as Box12, Text as Text12, useInput as useInput7 } from "ink";
2800
3063
  import { Spinner as Spinner5 } from "@inkjs/ui";
2801
- import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
3064
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
2802
3065
  function Doctor({ config, onDone }) {
2803
3066
  const [checks, setChecks] = useState5(null);
2804
3067
  useInput7((input, key) => {
@@ -2811,13 +3074,13 @@ function Doctor({ config, onDone }) {
2811
3074
  alive = false;
2812
3075
  };
2813
3076
  }, []);
2814
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
2815
- /* @__PURE__ */ jsx11(Header, { title: "Doctor", subtitle: "everything the generator depends on" }),
2816
- !checks ? /* @__PURE__ */ jsx11(Spinner5, { label: "running checks\u2026" }) : /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
2817
- /* @__PURE__ */ jsx11(Section, { title: "Configuration", children: /* @__PURE__ */ jsx11(CheckList, { checks: checks.config }) }),
2818
- /* @__PURE__ */ jsx11(Section, { title: "Connectivity", children: /* @__PURE__ */ jsx11(CheckList, { checks: checks.connectivity }) }),
2819
- /* @__PURE__ */ jsx11(Section, { title: "Runtime", children: /* @__PURE__ */ jsx11(CheckList, { checks: checks.runtime }) }),
2820
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { color: palette.dim, children: "press enter to return to the menu" }) })
3077
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
3078
+ /* @__PURE__ */ jsx12(Header, { title: "Doctor", subtitle: "everything the generator depends on" }),
3079
+ !checks ? /* @__PURE__ */ jsx12(Spinner5, { label: "running checks\u2026" }) : /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
3080
+ /* @__PURE__ */ jsx12(Section, { title: "Configuration", children: /* @__PURE__ */ jsx12(CheckList, { checks: checks.config }) }),
3081
+ /* @__PURE__ */ jsx12(Section, { title: "Connectivity", children: /* @__PURE__ */ jsx12(CheckList, { checks: checks.connectivity }) }),
3082
+ /* @__PURE__ */ jsx12(Section, { title: "Runtime", children: /* @__PURE__ */ jsx12(CheckList, { checks: checks.runtime }) }),
3083
+ /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text12, { color: palette.dim, children: "press enter to return to the menu" }) })
2821
3084
  ] })
2822
3085
  ] });
2823
3086
  }
@@ -2865,10 +3128,10 @@ async function run(config) {
2865
3128
  }
2866
3129
 
2867
3130
  // src/ui/screens/History.jsx
2868
- import React12, { useState as useState6 } from "react";
2869
- import { Box as Box12, Text as Text12, useInput as useInput8 } from "ink";
3131
+ import React13, { useState as useState6 } from "react";
3132
+ import { Box as Box13, Text as Text13, useInput as useInput8 } from "ink";
2870
3133
  import { Select as Select7, Spinner as Spinner6, Badge as Badge4, Alert as Alert5, ConfirmInput as ConfirmInput2 } from "@inkjs/ui";
2871
- import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
3134
+ import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
2872
3135
  function History({ config, onDone }) {
2873
3136
  const [items] = useState6(() => listPayloads(20));
2874
3137
  const [selected, setSelected] = useState6(null);
@@ -2894,14 +3157,14 @@ function History({ config, onDone }) {
2894
3157
  });
2895
3158
  };
2896
3159
  if (!items.length) {
2897
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
2898
- /* @__PURE__ */ jsx12(Header, { title: "History", subtitle: "saved payloads" }),
2899
- /* @__PURE__ */ jsx12(Text12, { color: palette.dim, children: "nothing built yet \u2014 press esc to go back" })
3160
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
3161
+ /* @__PURE__ */ jsx13(Header, { title: "History", subtitle: "saved payloads" }),
3162
+ /* @__PURE__ */ jsx13(Text13, { color: palette.dim, children: "nothing built yet \u2014 press esc to go back" })
2900
3163
  ] });
2901
3164
  }
2902
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
2903
- /* @__PURE__ */ jsx12(Header, { title: "History", subtitle: `${items.length} saved payload${items.length === 1 ? "" : "s"}`, right: "esc to go back" }),
2904
- phase === "list" && /* @__PURE__ */ jsx12(
3165
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
3166
+ /* @__PURE__ */ jsx13(Header, { title: "History", subtitle: `${items.length} saved payload${items.length === 1 ? "" : "s"}`, right: "esc to go back" }),
3167
+ phase === "list" && /* @__PURE__ */ jsx13(
2905
3168
  Select7,
2906
3169
  {
2907
3170
  visibleOptionCount: 10,
@@ -2912,8 +3175,8 @@ function History({ config, onDone }) {
2912
3175
  onChange: onPick
2913
3176
  }
2914
3177
  ),
2915
- phase === "detail" && selected && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
2916
- /* @__PURE__ */ jsx12(Section, { title: "Payload", children: /* @__PURE__ */ jsx12(
3178
+ phase === "detail" && selected && /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
3179
+ /* @__PURE__ */ jsx13(Section, { title: "Payload", children: /* @__PURE__ */ jsx13(
2917
3180
  KeyValue,
2918
3181
  {
2919
3182
  rows: [
@@ -2927,31 +3190,31 @@ function History({ config, onDone }) {
2927
3190
  ]
2928
3191
  }
2929
3192
  ) }),
2930
- /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, children: [
2931
- /* @__PURE__ */ jsx12(Text12, { children: "Re-send this payload (it will be re-signed with a fresh timestamp)? " }),
2932
- /* @__PURE__ */ jsx12(ConfirmInput2, { onConfirm: resend, onCancel: () => setPhase("list") })
3193
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
3194
+ /* @__PURE__ */ jsx13(Text13, { children: "Re-send this payload (it will be re-signed with a fresh timestamp)? " }),
3195
+ /* @__PURE__ */ jsx13(ConfirmInput2, { onConfirm: resend, onCancel: () => setPhase("list") })
2933
3196
  ] })
2934
3197
  ] }),
2935
- phase === "sending" && /* @__PURE__ */ jsx12(Spinner6, { label: "re-signing and sending\u2026" }),
2936
- phase === "result" && result && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
2937
- /* @__PURE__ */ jsxs12(Box12, { marginBottom: 1, children: [
2938
- /* @__PURE__ */ jsx12(Badge4, { color: result.ok ? "green" : "red", children: result.error ? "FAILED" : `HTTP ${result.status}` }),
2939
- /* @__PURE__ */ jsx12(Text12, { children: " " }),
2940
- /* @__PURE__ */ jsx12(Text12, { color: palette.dim, children: result.error ?? explainStatus(result.status) })
3198
+ phase === "sending" && /* @__PURE__ */ jsx13(Spinner6, { label: "re-signing and sending\u2026" }),
3199
+ phase === "result" && result && /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
3200
+ /* @__PURE__ */ jsxs13(Box13, { marginBottom: 1, children: [
3201
+ /* @__PURE__ */ jsx13(Badge4, { color: result.ok ? "green" : "red", children: result.error ? "FAILED" : `HTTP ${result.status}` }),
3202
+ /* @__PURE__ */ jsx13(Text13, { children: " " }),
3203
+ /* @__PURE__ */ jsx13(Text13, { color: palette.dim, children: result.error ?? explainStatus(result.status) })
2941
3204
  ] }),
2942
- /* @__PURE__ */ jsx12(Text12, { color: palette.dim, children: "press enter to return" })
3205
+ /* @__PURE__ */ jsx13(Text13, { color: palette.dim, children: "press enter to return" })
2943
3206
  ] }),
2944
- phase === "error" && error && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
2945
- /* @__PURE__ */ jsx12(Alert5, { variant: "error", children: error.message }),
2946
- error.hint ? /* @__PURE__ */ jsx12(Text12, { color: palette.warn, children: ` ${error.hint}` }) : null,
2947
- /* @__PURE__ */ jsx12(Text12, { color: palette.dim, children: "press enter to return" })
3207
+ phase === "error" && error && /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
3208
+ /* @__PURE__ */ jsx13(Alert5, { variant: "error", children: error.message }),
3209
+ error.hint ? /* @__PURE__ */ jsx13(Text13, { color: palette.warn, children: ` ${error.hint}` }) : null,
3210
+ /* @__PURE__ */ jsx13(Text13, { color: palette.dim, children: "press enter to return" })
2948
3211
  ] })
2949
3212
  ] });
2950
3213
  }
2951
3214
 
2952
3215
  // src/ui/screens/Clear.jsx
2953
- import React13, { useState as useState7 } from "react";
2954
- import { Box as Box13, Text as Text13, useInput as useInput9 } from "ink";
3216
+ import React14, { useState as useState7 } from "react";
3217
+ import { Box as Box14, Text as Text14, useInput as useInput9 } from "ink";
2955
3218
  import { Select as Select8, ConfirmInput as ConfirmInput3, Alert as Alert6, Badge as Badge5 } from "@inkjs/ui";
2956
3219
 
2957
3220
  // src/core/cleanup.mjs
@@ -3027,7 +3290,7 @@ var TARGETS = {
3027
3290
  };
3028
3291
 
3029
3292
  // src/ui/screens/Clear.jsx
3030
- import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
3293
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
3031
3294
  function Clear({ config, onDone }) {
3032
3295
  const [state] = useState7(() => inspect());
3033
3296
  const [choice, setChoice] = useState7(null);
@@ -3041,23 +3304,23 @@ function Clear({ config, onDone }) {
3041
3304
  setResult(outcome);
3042
3305
  };
3043
3306
  if (result) {
3044
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
3045
- /* @__PURE__ */ jsx13(Header, { title: "Clear", subtitle: "done" }),
3046
- /* @__PURE__ */ jsxs13(Box13, { marginBottom: 1, children: [
3047
- /* @__PURE__ */ jsx13(Badge5, { color: "green", children: "CLEARED" }),
3048
- /* @__PURE__ */ jsx13(Text13, { children: " " }),
3049
- /* @__PURE__ */ jsx13(Text13, { color: palette.dim, children: choice === "all" ? `${result.payloads} payload(s), ${result.logs} log, ${result.config} config file removed` : `${result.removed} item(s) removed` })
3307
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
3308
+ /* @__PURE__ */ jsx14(Header, { title: "Clear", subtitle: "done" }),
3309
+ /* @__PURE__ */ jsxs14(Box14, { marginBottom: 1, children: [
3310
+ /* @__PURE__ */ jsx14(Badge5, { color: "green", children: "CLEARED" }),
3311
+ /* @__PURE__ */ jsx14(Text14, { children: " " }),
3312
+ /* @__PURE__ */ jsx14(Text14, { color: palette.dim, children: choice === "all" ? `${result.payloads} payload(s), ${result.logs} log, ${result.config} config file removed` : `${result.removed} item(s) removed` })
3050
3313
  ] }),
3051
- choice === "all" ? /* @__PURE__ */ jsx13(Alert6, { variant: "info", children: "back to first-run state \u2014 reconnect Shopify to continue" }) : null,
3052
- /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text13, { color: palette.dim, children: "press enter to return" }) })
3314
+ choice === "all" ? /* @__PURE__ */ jsx14(Alert6, { variant: "info", children: "back to first-run state \u2014 reconnect Shopify to continue" }) : null,
3315
+ /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { color: palette.dim, children: "press enter to return" }) })
3053
3316
  ] });
3054
3317
  }
3055
3318
  if (choice) {
3056
3319
  const target = TARGETS[choice];
3057
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
3058
- /* @__PURE__ */ jsx13(Header, { title: "Clear", subtitle: target.label, right: "esc to cancel" }),
3059
- /* @__PURE__ */ jsx13(Alert6, { variant: "warning", children: `This permanently deletes ${target.description}.` }),
3060
- /* @__PURE__ */ jsx13(Section, { title: "Will be removed", children: choice === "all" ? /* @__PURE__ */ jsx13(
3320
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
3321
+ /* @__PURE__ */ jsx14(Header, { title: "Clear", subtitle: target.label, right: "esc to cancel" }),
3322
+ /* @__PURE__ */ jsx14(Alert6, { variant: "warning", children: `This permanently deletes ${target.description}.` }),
3323
+ /* @__PURE__ */ jsx14(Section, { title: "Will be removed", children: choice === "all" ? /* @__PURE__ */ jsx14(
3061
3324
  KeyValue,
3062
3325
  {
3063
3326
  keyWidth: 10,
@@ -3067,22 +3330,22 @@ function Clear({ config, onDone }) {
3067
3330
  ["config", state.config.label]
3068
3331
  ]
3069
3332
  }
3070
- ) : /* @__PURE__ */ jsx13(Text13, { color: palette.dim, children: ` ${glyph.dot} ${choice === "payloads" ? state.payloads.label : choice === "logs" ? state.logs.label : target.description}` }) }),
3071
- choice === "all" || choice === "disconnect" ? /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text13, { color: palette.warn, children: " your Shopify access token will have to be entered again" }) }) : null,
3072
- /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
3073
- /* @__PURE__ */ jsx13(Text13, { children: "Are you sure? " }),
3074
- /* @__PURE__ */ jsx13(ConfirmInput3, { defaultChoice: "cancel", onConfirm: run2, onCancel: () => setChoice(null) })
3333
+ ) : /* @__PURE__ */ jsx14(Text14, { color: palette.dim, children: ` ${glyph.dot} ${choice === "payloads" ? state.payloads.label : choice === "logs" ? state.logs.label : target.description}` }) }),
3334
+ choice === "all" || choice === "disconnect" ? /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { color: palette.warn, children: " your Shopify access token will have to be entered again" }) }) : null,
3335
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
3336
+ /* @__PURE__ */ jsx14(Text14, { children: "Are you sure? " }),
3337
+ /* @__PURE__ */ jsx14(ConfirmInput3, { defaultChoice: "cancel", onConfirm: run2, onCancel: () => setChoice(null) })
3075
3338
  ] })
3076
3339
  ] });
3077
3340
  }
3078
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
3079
- /* @__PURE__ */ jsx13(Header, { title: "Clear", subtitle: "remove locally cached data", right: "esc to go back" }),
3080
- /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginBottom: 1, paddingX: 1, children: [
3081
- /* @__PURE__ */ jsx13(Text13, { color: palette.dim, children: `${glyph.dot} ${state.payloads.label}` }),
3082
- /* @__PURE__ */ jsx13(Text13, { color: palette.dim, children: `${glyph.dot} ${state.logs.label}` }),
3083
- /* @__PURE__ */ jsx13(Text13, { color: palette.dim, children: `${glyph.dot} ${state.config.label}` })
3341
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
3342
+ /* @__PURE__ */ jsx14(Header, { title: "Clear", subtitle: "remove locally cached data", right: "esc to go back" }),
3343
+ /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginBottom: 1, paddingX: 1, children: [
3344
+ /* @__PURE__ */ jsx14(Text14, { color: palette.dim, children: `${glyph.dot} ${state.payloads.label}` }),
3345
+ /* @__PURE__ */ jsx14(Text14, { color: palette.dim, children: `${glyph.dot} ${state.logs.label}` }),
3346
+ /* @__PURE__ */ jsx14(Text14, { color: palette.dim, children: `${glyph.dot} ${state.config.label}` })
3084
3347
  ] }),
3085
- /* @__PURE__ */ jsx13(
3348
+ /* @__PURE__ */ jsx14(
3086
3349
  Select8,
3087
3350
  {
3088
3351
  visibleOptionCount: 8,
@@ -3097,7 +3360,7 @@ function Clear({ config, onDone }) {
3097
3360
  }
3098
3361
 
3099
3362
  // src/ui/App.jsx
3100
- import { jsx as jsx14 } from "react/jsx-runtime";
3363
+ import { jsx as jsx15 } from "react/jsx-runtime";
3101
3364
  function App({ config: initialConfig, initialScreen = "home" }) {
3102
3365
  const { exit } = useApp2();
3103
3366
  const [config, setConfig] = useState8(initialConfig);
@@ -3114,7 +3377,7 @@ function App({ config: initialConfig, initialScreen = "home" }) {
3114
3377
  const toIntegrations = go("integrations");
3115
3378
  switch (screen) {
3116
3379
  case "setup":
3117
- return /* @__PURE__ */ jsx14(
3380
+ return /* @__PURE__ */ jsx15(
3118
3381
  Setup,
3119
3382
  {
3120
3383
  config,
@@ -3131,7 +3394,7 @@ function App({ config: initialConfig, initialScreen = "home" }) {
3131
3394
  }
3132
3395
  );
3133
3396
  case "integrations":
3134
- return /* @__PURE__ */ jsx14(
3397
+ return /* @__PURE__ */ jsx15(
3135
3398
  Integrations,
3136
3399
  {
3137
3400
  config,
@@ -3144,21 +3407,21 @@ function App({ config: initialConfig, initialScreen = "home" }) {
3144
3407
  }
3145
3408
  );
3146
3409
  case "connect":
3147
- return /* @__PURE__ */ jsx14(ConnectShopify, { config, onDone: toSetup });
3410
+ return /* @__PURE__ */ jsx15(ConnectShopify, { config, onDone: toSetup });
3148
3411
  case "webhook":
3149
- return /* @__PURE__ */ jsx14(Webhook, { config, onDone: toSetup });
3412
+ return /* @__PURE__ */ jsx15(Webhook, { config, onDone: toSetup });
3150
3413
  case "configure":
3151
- return /* @__PURE__ */ jsx14(Configure, { config, section, onDone: toSetup });
3414
+ return /* @__PURE__ */ jsx15(Configure, { config, section, onDone: toSetup });
3152
3415
  case "build":
3153
- return /* @__PURE__ */ jsx14(Build, { config, providerId: provider, onDone: toIntegrations });
3416
+ return /* @__PURE__ */ jsx15(Build, { config, providerId: provider, onDone: toIntegrations });
3154
3417
  case "history":
3155
- return /* @__PURE__ */ jsx14(History, { config, onDone: toHome });
3418
+ return /* @__PURE__ */ jsx15(History, { config, onDone: toHome });
3156
3419
  case "doctor":
3157
- return /* @__PURE__ */ jsx14(Doctor, { config, onDone: toHome });
3420
+ return /* @__PURE__ */ jsx15(Doctor, { config, onDone: toHome });
3158
3421
  case "clear":
3159
- return /* @__PURE__ */ jsx14(Clear, { config, onDone: toHome });
3422
+ return /* @__PURE__ */ jsx15(Clear, { config, onDone: toHome });
3160
3423
  default:
3161
- return /* @__PURE__ */ jsx14(Home, { config, onPick: setScreen, onQuit: exit });
3424
+ return /* @__PURE__ */ jsx15(Home, { config, onPick: setScreen, onQuit: exit });
3162
3425
  }
3163
3426
  }
3164
3427
 
@@ -3458,7 +3721,7 @@ function printReport(built) {
3458
3721
  }
3459
3722
 
3460
3723
  // src/cli.jsx
3461
- import { jsx as jsx15 } from "react/jsx-runtime";
3724
+ import { jsx as jsx16 } from "react/jsx-runtime";
3462
3725
  var HELP = `
3463
3726
  ${c.bold("hookwright")} \u2014 generate real, signed provider webhooks from a live Shopify catalogue
3464
3727
 
@@ -3548,7 +3811,7 @@ async function main() {
3548
3811
  const config = loadConfig(args.flags.config);
3549
3812
  if (command && command !== "ui") {
3550
3813
  if (command === "configure" && process.stdin.isTTY) {
3551
- render(/* @__PURE__ */ jsx15(App, { config, initialScreen: "connect" }));
3814
+ render(/* @__PURE__ */ jsx16(App, { config, initialScreen: "connect" }));
3552
3815
  return;
3553
3816
  }
3554
3817
  const code = await headless(command, args, config);
@@ -3561,7 +3824,7 @@ async function main() {
3561
3824
  process.exitCode = 1;
3562
3825
  return;
3563
3826
  }
3564
- render(/* @__PURE__ */ jsx15(App, { config, initialScreen: "home" }));
3827
+ render(/* @__PURE__ */ jsx16(App, { config, initialScreen: "home" }));
3565
3828
  }
3566
3829
  main().catch((err) => {
3567
3830
  console.error(c.red(`