hookwright 1.8.0 → 1.10.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 (2) hide show
  1. package/dist/cli.js +164 -50
  2. 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.8.0",
27
+ version: "1.10.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",
@@ -1142,7 +1142,6 @@ var EVENTS2 = [
1142
1142
  { eventName: "collection_page_viewed", type: "shopflo_collection_page_viewed", label: "Collection Page View", selection: "collection", subject: "one collection", envelope: "data" },
1143
1143
  { eventName: "product_page_viewed", type: "shopflo_product_page_viewed", label: "Product Page View", selection: "product", subject: "one product", envelope: "data" },
1144
1144
  { eventName: "added_to_cart_ui", type: "shopflo_added_to_cart", label: "Added To Cart", selection: "cart", subject: "cart contents", envelope: "root" },
1145
- { eventName: "checkout_clicked", type: "shopflo_checkout_clicked", label: "Checkout Clicked", selection: "cart", subject: "cart contents", envelope: "root" },
1146
1145
  { eventName: "checkout_abandoned", type: "shopflo_checkout_abandoned", label: "Abandoned Checkout", selection: "cart", subject: "cart contents", envelope: "root" },
1147
1146
  { eventName: "order_completed", type: "shopflo_order_completed", label: "Order Completed", selection: "cart", subject: "ordered items", envelope: "root" }
1148
1147
  ];
@@ -1156,7 +1155,13 @@ function selectionFor2(eventName) {
1156
1155
  }
1157
1156
  var COMMON_FIELDS2 = [
1158
1157
  { source: "event_name / eventName", target: "\xABgate\xBB", required: true, note: "the schema matches EITHER spelling" },
1159
- { source: "customer.phone / user_data.phone", target: "phone", required: true, note: "missing phone is rejected on every event" }
1158
+ { source: "customer.phone / user_data.phone", target: "customer.phone", required: true, note: "missing phone is rejected on every event" },
1159
+ { source: "customer.first_name / user_data.firstName", target: "customer.firstName" },
1160
+ { source: "customer.last_name / user_data.lastName", target: "customer.lastName" },
1161
+ { source: "\u2014 (first + last)", target: "customer.fullName", note: "built by the consumer, not sent" },
1162
+ { source: "customer.email / user_data.email", target: "customer.email" },
1163
+ { source: "channel", target: "channel" },
1164
+ { source: "timestamp / created_at", target: "eventTime" }
1160
1165
  ];
1161
1166
  var BROWSING_FIELDS = [
1162
1167
  { source: "uiData.pageUrl / data.page_url", target: "page.url" },
@@ -1167,15 +1172,20 @@ var BROWSING_FIELDS = [
1167
1172
  { source: "session_id", target: "sessionId" }
1168
1173
  ];
1169
1174
  var CART_FIELDS = [
1170
- { source: "line_items[].title", target: "cart.productName", required: true, note: "the first PAID line wins; freebies rank last" },
1171
- { source: "line_items[].product_image", target: "cart.image" },
1175
+ { source: "line_items[].title", target: "cart.productDetails", required: true, note: "the first PAID line wins; freebies rank last" },
1176
+ { source: "line_items[].title", target: "cart.productName", note: 'the featured line alone, without the "and N more"' },
1177
+ { source: "line_items[].image", target: "cart.image", note: "looked up from product_id when the line has none" },
1178
+ { source: "\u2014 (store domain + handle)", target: "cart.productUrl", note: "resolved, not sent" },
1179
+ { source: "\u2014 (store domain + line ids)", target: "cartLink", note: "resolved, not sent" },
1180
+ { source: "\u2014 (company shopify integration)", target: "storeUrl", note: "resolved, not sent" },
1172
1181
  { source: "line_items[].price", target: "\u2014 (ranking only)", note: "a zero price marks the line a freebie" },
1173
- { source: "line_items[].quantity", target: "cart.quantity" },
1174
- { source: "total_price", target: "pricing.totalPrice" },
1175
- { source: "subtotal_price", target: "pricing.subtotal" },
1176
- { source: "total_discount", target: "pricing.totalDiscount" },
1177
- { source: "currency", target: "pricing.currency" },
1178
- { source: "note_attributes[shopflo_checkout_url]", target: "checkoutUrl", note: "checkout_abandoned puts the link here, not in token_id" }
1182
+ { source: "line_items[].quantity", target: "cart.quantity", note: "summed across the cart" },
1183
+ { source: "line_items[]", target: "cart.itemCount", note: "the line count, not the quantity" },
1184
+ { source: "total_price", target: "total_price", note: "the body is stored as sent" },
1185
+ { source: "subtotal_price", target: "subtotal_price" },
1186
+ { source: "total_discount", target: "total_discount" },
1187
+ { source: "currency", target: "currency" },
1188
+ { source: "abandoned_checkout_url", target: "checkoutUrl", required: true, note: "token_id is a bare uuid, only usable once built into a link" }
1179
1189
  ];
1180
1190
  var FIELD_MAPS2 = {
1181
1191
  store_page_view: [...COMMON_FIELDS2, ...BROWSING_FIELDS],
@@ -1186,10 +1196,11 @@ var FIELD_MAPS2 = {
1186
1196
  { source: "data.product_name", target: "product.name" },
1187
1197
  { source: "data.product_image", target: "product.image" },
1188
1198
  { source: "data.product_url", target: "product.url" },
1189
- { source: "data.product_price", target: "product.price" }
1199
+ { source: "data.product_price", target: "product.price" },
1200
+ { source: "data.product_compare_at_price", target: "product.compareAtPrice" },
1201
+ { source: "data.product_type", target: "product.type" }
1190
1202
  ],
1191
1203
  added_to_cart_ui: [...COMMON_FIELDS2, ...CART_FIELDS],
1192
- checkout_clicked: [...COMMON_FIELDS2, ...CART_FIELDS],
1193
1204
  checkout_abandoned: [...COMMON_FIELDS2, ...CART_FIELDS],
1194
1205
  order_completed: [
1195
1206
  ...COMMON_FIELDS2,
@@ -1197,6 +1208,8 @@ var FIELD_MAPS2 = {
1197
1208
  { source: "order_id", target: "order.id" },
1198
1209
  { source: "order_name", target: "order.name" },
1199
1210
  { source: "payment_mode", target: "order.paymentMode" },
1211
+ { source: "total_shipping", target: "order.totalShipping" },
1212
+ { source: "total_tax", target: "order.totalTax" },
1200
1213
  { source: "total_payable", target: "order.totalPayable" }
1201
1214
  ]
1202
1215
  };
@@ -1244,7 +1257,7 @@ function editableFieldsFor2(eventName) {
1244
1257
  }
1245
1258
  var editableFields4 = editableFieldsFor2(DEFAULT_EVENT2);
1246
1259
  function buildPayload4(ctx) {
1247
- const { config, items, phone, collection } = ctx;
1260
+ const { config, items, phone, collection, live } = ctx;
1248
1261
  const eventName = ctx.eventName ?? DEFAULT_EVENT2;
1249
1262
  const def = eventDef(eventName);
1250
1263
  const now = ctx.now ?? /* @__PURE__ */ new Date();
@@ -1263,7 +1276,7 @@ function buildPayload4(ctx) {
1263
1276
  pageUrl: `https://${domain}/`,
1264
1277
  pageTitle: config.shopify.shop?.name ?? domain,
1265
1278
  landingPageUrl: `https://${domain}/`,
1266
- referrerPageUrl: ""
1279
+ referrerPageUrl: ctx.referrer ?? "https://www.google.com/"
1267
1280
  },
1268
1281
  clientData: { brandUrl: `https://${domain}` }
1269
1282
  },
@@ -1280,7 +1293,7 @@ function buildPayload4(ctx) {
1280
1293
  page_url: isProduct ? `https://${domain}/products/${first?.product?.handle ?? ""}` : `https://${domain}/collections/${collection?.handle ?? "all"}`,
1281
1294
  page_title: isProduct ? first?.product?.title : collection?.title,
1282
1295
  landing_page_url: `https://${domain}/`,
1283
- referrer_page_url: "",
1296
+ referrer_page_url: ctx.referrer ?? "https://www.google.com/",
1284
1297
  ...isProduct ? {
1285
1298
  product_name: first?.product?.title,
1286
1299
  product_image: imageForVariant(first?.product, first?.variant),
@@ -1300,26 +1313,47 @@ function buildPayload4(ctx) {
1300
1313
  title: product.title,
1301
1314
  price: money2(variant?.price ?? 0).toFixed(2),
1302
1315
  quantity,
1303
- product_image: imageForVariant(product, variant)
1316
+ image: imageForVariant(product, variant)
1304
1317
  }));
1305
1318
  const subtotal = money2(lineItems.reduce((sum, li) => sum + Number(li.price) * li.quantity, 0));
1306
1319
  const discount = money2(Math.min(ctx.discount ?? 0, subtotal));
1307
1320
  const total = money2(subtotal - discount);
1308
- const checkoutUrl = cartPermalink(domain, (items ?? []).map(({ variant, quantity }) => ({ variantId: variant?.id, quantity })));
1321
+ const checkoutUrl = live?.kind === "checkout" && live.url ? live.url : cartPermalink(domain, (items ?? []).map(({ variant, quantity }) => ({ variantId: variant?.id, quantity })));
1309
1322
  return {
1310
1323
  event_name: eventName,
1311
1324
  session_id: ctx.sessionId ?? `sf-${now.getTime()}`,
1312
- token_id: checkoutUrl,
1325
+ token_id: `sf-${now.getTime()}`,
1326
+ abandoned_checkout_url: checkoutUrl,
1313
1327
  source: "shopflo",
1314
1328
  channel: "web",
1315
1329
  email: cust.email,
1316
1330
  phone,
1317
1331
  created_at: now.toISOString(),
1318
- // checkout_abandoned carries the recovery link here; the consumer prefers it
1332
+ // the live note_attributes carry utm and the landing page, never a checkout url
1319
1333
  note_attributes: [
1320
1334
  { name: "landing_page", value: `/products/${items?.[0]?.product?.handle ?? ""}` },
1321
- { name: "shopflo_checkout_url", value: checkoutUrl }
1335
+ { name: "utm_source", value: "ig" },
1336
+ { name: "customer_type", value: "NEW" }
1322
1337
  ],
1338
+ utm_params: {
1339
+ utm_source: "ig",
1340
+ utm_medium: "Instagram_Feed",
1341
+ utm_campaign: "hookwright",
1342
+ utm_content: "hookwright",
1343
+ utm_term: "0",
1344
+ landing_page: `/products/${items?.[0]?.product?.handle ?? ""}`,
1345
+ landing_page_url: `https://${domain}/products/${items?.[0]?.product?.handle ?? ""}`
1346
+ },
1347
+ shipping_address: {
1348
+ city: "Bangalore",
1349
+ province: "Karnataka",
1350
+ province_code: "KA",
1351
+ zip: "560024",
1352
+ country: "India",
1353
+ country_code: "IN",
1354
+ phone,
1355
+ email: cust.email
1356
+ },
1323
1357
  line_items: lineItems,
1324
1358
  customer: { uid: "sf-user", first_name: cust.firstName, last_name: cust.lastName, email: cust.email, phone },
1325
1359
  currency,
@@ -1327,12 +1361,13 @@ function buildPayload4(ctx) {
1327
1361
  total_discount: discount,
1328
1362
  total_price: total,
1329
1363
  ...eventName === "order_completed" ? {
1330
- order_id: ctx.orderId ?? Math.floor(now.getTime() / 1e3),
1331
- order_name: ctx.orderName ?? `#${String(now.getTime()).slice(-5)}`,
1364
+ // a real order id is what the receiver would look up
1365
+ order_id: live?.kind === "order" ? live.id : ctx.orderId ?? Math.floor(now.getTime() / 1e3),
1366
+ order_name: live?.kind === "order" ? live.name : ctx.orderName ?? `#${String(now.getTime()).slice(-5)}`,
1332
1367
  payment_mode: "prepaid",
1333
1368
  total_shipping: 0,
1334
1369
  total_tax: 0,
1335
- total_payable: total
1370
+ total_payable: live?.kind === "order" ? Number(live.price) : total
1336
1371
  } : {},
1337
1372
  timestamp: now.getTime()
1338
1373
  };
@@ -1348,7 +1383,7 @@ function webhookSecret4(config) {
1348
1383
  }
1349
1384
  function storeOf(payload) {
1350
1385
  const brandUrl = payload?.eventPayload?.clientData?.brandUrl;
1351
- const candidate = brandUrl ?? payload?.token_id;
1386
+ const candidate = brandUrl ?? payload?.utm_params?.landing_page_url ?? payload?.data?.page_url;
1352
1387
  if (!candidate) return void 0;
1353
1388
  try {
1354
1389
  return new URL(candidate).host;
@@ -1482,12 +1517,25 @@ function nationalNumber(raw, regionCode) {
1482
1517
  // src/providers/flexype.mjs
1483
1518
  var GATE_PATH3 = "event_type";
1484
1519
  var GATE_VALUE2 = "ABANDONED_CHECKOUT";
1520
+ var EVENTS3 = [
1521
+ { eventName: "ABANDONED_CHECKOUT", type: "flexype_abandoned_checkout", label: "Abandoned Checkout", selection: "cart", subject: "cart contents" },
1522
+ { eventName: "COLLECTION_VIEWED", type: "flexype_collection_viewed", label: "Collection Viewed", selection: "collection", subject: "one collection" },
1523
+ { eventName: "PRODUCT_VIEWED", type: "flexype_product_viewed", label: "Product Viewed", selection: "product", subject: "one product" }
1524
+ ];
1525
+ var DEFAULT_EVENT3 = GATE_VALUE2;
1526
+ var eventDef2 = (eventName) => EVENTS3.find((e) => e.eventName === eventName) ?? EVENTS3[0];
1527
+ function eventFromPayload3(payload) {
1528
+ return payload?.event_type;
1529
+ }
1530
+ function selectionFor3(eventName) {
1531
+ return eventDef2(eventName).selection;
1532
+ }
1485
1533
  var fieldMap5 = [
1486
1534
  { source: "event_type", target: "\xABgate\xBB", required: true, note: "must be ABANDONED_CHECKOUT or the event is dropped" },
1487
1535
  { source: "payload.user.phone_with_dial_code", target: "phone", required: true, note: "falls back to dial_code + phone" },
1488
1536
  { source: "payload.user.first_name", target: "customer.firstName" },
1489
1537
  { source: "payload.user.last_name", target: "customer.lastName" },
1490
- { source: "payload.user.full_name", target: "customer.name" },
1538
+ { source: "payload.user.full_name", target: "customer.fullName", note: "falls back to first + last name" },
1491
1539
  { source: "payload.user.email", target: "customer.email" },
1492
1540
  { source: "payload.checkout_url", target: "checkoutUrl", required: true },
1493
1541
  { source: "payload.session_id", target: "sessionId" },
@@ -1496,7 +1544,8 @@ var fieldMap5 = [
1496
1544
  { source: "payload.cart_items[].image", target: "cart.image" },
1497
1545
  { source: "payload.cart_items[].total_price", target: "pricing.totalPrice", note: "summed across the cart" },
1498
1546
  { source: "payload.cart_items[].total_discount", target: "pricing.totalDiscount", note: "summed across the cart" },
1499
- { source: "payload.cart_items[].quantity", target: "cart.quantity" },
1547
+ { source: "payload.cart_items[].quantity", target: "cart.quantity", note: "summed across the cart" },
1548
+ { source: "payload.cart_items[]", target: "cart.itemCount", note: "the line count, not the quantity" },
1500
1549
  { source: "payload.coupons[0].code", target: "pricing.couponCode" },
1501
1550
  { source: "payload.checkout_context.presentment_currency", target: "pricing.currency" },
1502
1551
  { source: "payload.checkout_context.presentment_country", target: "phone region" },
@@ -1504,6 +1553,9 @@ var fieldMap5 = [
1504
1553
  { source: "payload.metadata.landing_page", target: "attribution.landingPage" },
1505
1554
  { source: "store.shopify_domain", target: "storeUrl" },
1506
1555
  { source: "store.name", target: "store.name" },
1556
+ { source: "store.main_domain", target: "store.mainDomain" },
1557
+ { source: "payload.checkout_context.store_country", target: "store.country" },
1558
+ { source: "payload.metadata.orig_referer", target: "attribution.referrer" },
1507
1559
  { source: "event_id", target: "eventId" },
1508
1560
  { source: "event_time", target: "eventTime" }
1509
1561
  ];
@@ -1524,12 +1576,64 @@ var editableFields5 = [
1524
1576
  { group: "Attribution", path: "payload.metadata.landing_page", label: "Landing page", optional: true }
1525
1577
  ];
1526
1578
  function buildPayload5(ctx) {
1527
- const { config, items, phone } = ctx;
1579
+ const { config, items, phone, live, collection } = ctx;
1580
+ const eventName = ctx.eventName ?? DEFAULT_EVENT3;
1528
1581
  const now = ctx.now ?? /* @__PURE__ */ new Date();
1529
1582
  const currency = ctx.currency || config.defaults.currency;
1530
1583
  const domain = config.shopify.domain;
1531
1584
  const cust = config.customer;
1532
1585
  const { dialCode, national } = splitPhone(phone, cust.countryCode);
1586
+ const envelope = {
1587
+ event_id: `fx-${now.getTime()}`,
1588
+ event_type: eventName,
1589
+ event_time: now.toISOString(),
1590
+ store: {
1591
+ id: 1,
1592
+ name: config.shopify.shop?.name ?? config.shopify.domain,
1593
+ shopify_domain: config.shopify.domain,
1594
+ main_domain: config.shopify.domain
1595
+ }
1596
+ };
1597
+ const user = {
1598
+ email: config.customer.email,
1599
+ full_name: `${config.customer.firstName} ${config.customer.lastName}`.trim(),
1600
+ first_name: config.customer.firstName,
1601
+ last_name: config.customer.lastName,
1602
+ dial_code: splitPhone(phone, config.customer.countryCode).dialCode,
1603
+ phone: splitPhone(phone, config.customer.countryCode).national,
1604
+ phone_with_dial_code: phone
1605
+ };
1606
+ if (eventName === "COLLECTION_VIEWED") {
1607
+ return {
1608
+ ...envelope,
1609
+ payload: {
1610
+ user,
1611
+ collection_viewed: {
1612
+ collection_id: Number(collection?.id) || 0,
1613
+ name: collection?.title ?? "",
1614
+ handle: collection?.handle ?? "",
1615
+ image: collection?.image?.src ?? "",
1616
+ timestamp: now.toISOString()
1617
+ }
1618
+ }
1619
+ };
1620
+ }
1621
+ if (eventName === "PRODUCT_VIEWED") {
1622
+ const first = items?.[0];
1623
+ return {
1624
+ ...envelope,
1625
+ payload: {
1626
+ user,
1627
+ product_viewed: {
1628
+ product_id: Number(first?.product?.id) || 0,
1629
+ title: first?.product?.title ?? "",
1630
+ handle: first?.product?.handle ?? "",
1631
+ image: imageForVariant(first?.product, first?.variant) ?? "",
1632
+ timestamp: now.toISOString()
1633
+ }
1634
+ }
1635
+ };
1636
+ }
1533
1637
  const cartItems = (items ?? []).map(({ product, variant, quantity }) => {
1534
1638
  const unit = money2(variant?.price ?? 0);
1535
1639
  return {
@@ -1544,7 +1648,7 @@ function buildPayload5(ctx) {
1544
1648
  sku: variant?.sku || null
1545
1649
  };
1546
1650
  });
1547
- const checkoutUrl = cartPermalink(domain, (items ?? []).map(({ variant, quantity }) => ({ variantId: variant?.id, quantity })));
1651
+ const checkoutUrl = live?.kind === "checkout" && live.url ? live.url : cartPermalink(domain, (items ?? []).map(({ variant, quantity }) => ({ variantId: variant?.id, quantity })));
1548
1652
  const utm = Object.entries(config.defaults.utm ?? {}).map(([name, value]) => ({ name, value }));
1549
1653
  return {
1550
1654
  event_id: `fx-${now.getTime()}`,
@@ -1579,8 +1683,8 @@ function buildPayload5(ctx) {
1579
1683
  coupons: ctx.couponCode ? [{ code: ctx.couponCode }] : [],
1580
1684
  metadata: {
1581
1685
  landing_page: `https://${domain}/products/${items?.[0]?.product?.handle ?? ""}`,
1582
- orig_referer: "",
1583
- referer_host: "",
1686
+ orig_referer: ctx.referrer ?? "https://www.google.com/",
1687
+ referer_host: "www.google.com",
1584
1688
  utm
1585
1689
  }
1586
1690
  }
@@ -1621,6 +1725,11 @@ var flexype_default = {
1621
1725
  urlKey: "flexype",
1622
1726
  label: "FlexyPe",
1623
1727
  eventType: "flexype_abandoned_checkout",
1728
+ events: EVENTS3,
1729
+ defaultEvent: DEFAULT_EVENT3,
1730
+ gateFor: (eventName) => ({ path: GATE_PATH3, value: eventName }),
1731
+ selectionFor: selectionFor3,
1732
+ eventFromPayload: eventFromPayload3,
1624
1733
  gate: { path: GATE_PATH3, value: GATE_VALUE2 },
1625
1734
  signatureScheme: "static shared secret in the header (no body signature)",
1626
1735
  signatureHeader: "x-flexype-authorization",
@@ -1636,7 +1745,7 @@ var flexype_default = {
1636
1745
  // src/providers/return-prime.mjs
1637
1746
  var STATUSES = ["requested", "approved", "received", "inspected", "rejected"];
1638
1747
  var titleCase = (v) => v.charAt(0).toUpperCase() + v.slice(1);
1639
- var EVENTS3 = ["return", "exchange"].flatMap(
1748
+ var EVENTS4 = ["return", "exchange"].flatMap(
1640
1749
  (requestType) => STATUSES.map((status) => ({
1641
1750
  eventName: `${requestType}_${status}`,
1642
1751
  requestType,
@@ -1647,15 +1756,15 @@ var EVENTS3 = ["return", "exchange"].flatMap(
1647
1756
  subject: requestType === "exchange" ? "the returned product and its replacement" : "the returned product"
1648
1757
  }))
1649
1758
  );
1650
- var DEFAULT_EVENT3 = "return_requested";
1651
- var eventDef2 = (eventName) => EVENTS3.find((e) => e.eventName === eventName) ?? EVENTS3.find((e) => e.eventName === DEFAULT_EVENT3);
1652
- function eventFromPayload3(payload) {
1759
+ var DEFAULT_EVENT4 = "return_requested";
1760
+ var eventDef3 = (eventName) => EVENTS4.find((e) => e.eventName === eventName) ?? EVENTS4.find((e) => e.eventName === DEFAULT_EVENT4);
1761
+ function eventFromPayload4(payload) {
1653
1762
  const request = payload?.request ?? payload ?? {};
1654
1763
  if (!request.request_type || !request.status) return void 0;
1655
1764
  return `${request.request_type}_${request.status}`;
1656
1765
  }
1657
- function selectionFor3(eventName) {
1658
- return eventDef2(eventName).selection;
1766
+ function selectionFor4(eventName) {
1767
+ return eventDef3(eventName).selection;
1659
1768
  }
1660
1769
  var COMMON_FIELDS3 = [
1661
1770
  { source: "request_type", target: "\xABgate\xBB + requestType", required: true, note: "return or exchange" },
@@ -1681,10 +1790,10 @@ var EXCHANGE_FIELDS = [
1681
1790
  ];
1682
1791
  var fieldMap6 = COMMON_FIELDS3;
1683
1792
  function fieldMapFor(eventName) {
1684
- return eventDef2(eventName).requestType === "exchange" ? [...COMMON_FIELDS3, ...EXCHANGE_FIELDS] : COMMON_FIELDS3;
1793
+ return eventDef3(eventName).requestType === "exchange" ? [...COMMON_FIELDS3, ...EXCHANGE_FIELDS] : COMMON_FIELDS3;
1685
1794
  }
1686
1795
  function editableFieldsFor3(eventName) {
1687
- const def = eventDef2(eventName);
1796
+ const def = eventDef3(eventName);
1688
1797
  const p = (path6) => def.envelope === "root" ? path6 : `request.${path6}`;
1689
1798
  return [
1690
1799
  { group: "Request", path: p("request_number"), label: "Request number" },
@@ -1703,14 +1812,14 @@ function editableFieldsFor3(eventName) {
1703
1812
  { group: "Pricing", path: p("line_items.0.presentment_price.currency"), label: "Currency" }
1704
1813
  ];
1705
1814
  }
1706
- var editableFields6 = editableFieldsFor3(DEFAULT_EVENT3);
1815
+ var editableFields6 = editableFieldsFor3(DEFAULT_EVENT4);
1707
1816
  function statusBlock(reached, at, comment = null) {
1708
1817
  return { status: reached, comment, created_at: reached ? at : null };
1709
1818
  }
1710
1819
  function buildPayload6(ctx) {
1711
1820
  const { config, items, phone } = ctx;
1712
- const eventName = ctx.eventName ?? DEFAULT_EVENT3;
1713
- const def = eventDef2(eventName);
1821
+ const eventName = ctx.eventName ?? DEFAULT_EVENT4;
1822
+ const def = eventDef3(eventName);
1714
1823
  const now = ctx.now ?? /* @__PURE__ */ new Date();
1715
1824
  const currency = ctx.currency || config.defaults.currency;
1716
1825
  const cust = config.customer;
@@ -1912,19 +2021,19 @@ var return_prime_default = {
1912
2021
  id: "return-prime",
1913
2022
  urlKey: "return_prime",
1914
2023
  label: "Return Prime",
1915
- events: EVENTS3,
1916
- defaultEvent: DEFAULT_EVENT3,
2024
+ events: EVENTS4,
2025
+ defaultEvent: DEFAULT_EVENT4,
1917
2026
  eventType: "return_prime_return_requested",
1918
2027
  gate: { path: "request.request_type", value: "return" },
1919
- gateFor: (eventName) => ({ path: "request.status", value: eventDef2(eventName).status }),
2028
+ gateFor: (eventName) => ({ path: "request.status", value: eventDef3(eventName).status }),
1920
2029
  signatureScheme: "none documented \u2014 every request is accepted",
1921
2030
  signatureHeader: null,
1922
2031
  fieldMap: fieldMap6,
1923
2032
  fieldMapFor,
1924
2033
  editableFields: editableFields6,
1925
2034
  editableFieldsFor: editableFieldsFor3,
1926
- selectionFor: selectionFor3,
1927
- eventFromPayload: eventFromPayload3,
2035
+ selectionFor: selectionFor4,
2036
+ eventFromPayload: eventFromPayload4,
1928
2037
  buildPayload: buildPayload6,
1929
2038
  sign: sign6,
1930
2039
  webhookUrl: webhookUrl6,
@@ -3008,7 +3117,11 @@ async function buildPayload8({ cfg, providerId = "cashfree-occ", items = [], dis
3008
3117
 
3009
3118
  // src/shopify/live.mjs
3010
3119
  var LIVE_EVENTS = {
3011
- nitro: /* @__PURE__ */ new Set(["checkout", "orders/create", "orders/updated"])
3120
+ nitro: /* @__PURE__ */ new Set(["checkout", "orders/create", "orders/updated"]),
3121
+ // shopflo's recovery link and order id are looked up the same way
3122
+ shopflo: /* @__PURE__ */ new Set(["checkout_abandoned", "checkout_clicked", "order_completed"]),
3123
+ // flexype sends one event and it is a recovery link
3124
+ flexype: /* @__PURE__ */ new Set(["ABANDONED_CHECKOUT"])
3012
3125
  };
3013
3126
  function needsLive(providerId, eventName) {
3014
3127
  return LIVE_EVENTS[providerId]?.has(eventName) ?? false;
@@ -3090,8 +3203,9 @@ async function liveOrder({ config, items = [], phone, client = clientFor(config)
3090
3203
  async function resolveLive({ config, providerId, eventName, items, phone, client }) {
3091
3204
  if (!needsLive(providerId, eventName)) return null;
3092
3205
  if (!config?.shopify?.domain || !config?.shopify?.accessToken) return null;
3093
- if (eventName === "checkout") return await liveCheckout({ config, items, ...client ? { client } : {} });
3094
- return await liveOrder({ config, items, phone, ...client ? { client } : {} });
3206
+ const wantsOrder = eventName === "orders/create" || eventName === "orders/updated" || eventName === "order_completed";
3207
+ if (wantsOrder) return await liveOrder({ config, items, phone, ...client ? { client } : {} });
3208
+ return await liveCheckout({ config, items, ...client ? { client } : {} });
3095
3209
  }
3096
3210
 
3097
3211
  // src/core/send.mjs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hookwright",
3
- "version": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "description": "Build real, signed e-commerce webhooks from a live Shopify catalogue — interactive terminal UI, no backend",
5
5
  "keywords": [
6
6
  "webhook",