hookwright 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +48 -25
- 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.
|
|
27
|
+
version: "1.9.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",
|
|
@@ -1156,7 +1156,13 @@ function selectionFor2(eventName) {
|
|
|
1156
1156
|
}
|
|
1157
1157
|
var COMMON_FIELDS2 = [
|
|
1158
1158
|
{ 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" }
|
|
1159
|
+
{ source: "customer.phone / user_data.phone", target: "customer.phone", required: true, note: "missing phone is rejected on every event" },
|
|
1160
|
+
{ source: "customer.first_name / user_data.firstName", target: "customer.firstName" },
|
|
1161
|
+
{ source: "customer.last_name / user_data.lastName", target: "customer.lastName" },
|
|
1162
|
+
{ source: "\u2014 (first + last)", target: "customer.fullName", note: "built by the consumer, not sent" },
|
|
1163
|
+
{ source: "customer.email / user_data.email", target: "customer.email" },
|
|
1164
|
+
{ source: "channel", target: "channel" },
|
|
1165
|
+
{ source: "timestamp / created_at", target: "eventTime" }
|
|
1160
1166
|
];
|
|
1161
1167
|
var BROWSING_FIELDS = [
|
|
1162
1168
|
{ source: "uiData.pageUrl / data.page_url", target: "page.url" },
|
|
@@ -1170,7 +1176,8 @@ var CART_FIELDS = [
|
|
|
1170
1176
|
{ source: "line_items[].title", target: "cart.productName", required: true, note: "the first PAID line wins; freebies rank last" },
|
|
1171
1177
|
{ source: "line_items[].product_image", target: "cart.image" },
|
|
1172
1178
|
{ 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" },
|
|
1179
|
+
{ source: "line_items[].quantity", target: "cart.quantity", note: "summed across the cart" },
|
|
1180
|
+
{ source: "line_items[]", target: "cart.itemCount", note: "the line count, not the quantity" },
|
|
1174
1181
|
{ source: "total_price", target: "pricing.totalPrice" },
|
|
1175
1182
|
{ source: "subtotal_price", target: "pricing.subtotal" },
|
|
1176
1183
|
{ source: "total_discount", target: "pricing.totalDiscount" },
|
|
@@ -1186,7 +1193,9 @@ var FIELD_MAPS2 = {
|
|
|
1186
1193
|
{ source: "data.product_name", target: "product.name" },
|
|
1187
1194
|
{ source: "data.product_image", target: "product.image" },
|
|
1188
1195
|
{ source: "data.product_url", target: "product.url" },
|
|
1189
|
-
{ source: "data.product_price", target: "product.price" }
|
|
1196
|
+
{ source: "data.product_price", target: "product.price" },
|
|
1197
|
+
{ source: "data.product_compare_at_price", target: "product.compareAtPrice" },
|
|
1198
|
+
{ source: "data.product_type", target: "product.type" }
|
|
1190
1199
|
],
|
|
1191
1200
|
added_to_cart_ui: [...COMMON_FIELDS2, ...CART_FIELDS],
|
|
1192
1201
|
checkout_clicked: [...COMMON_FIELDS2, ...CART_FIELDS],
|
|
@@ -1197,6 +1206,8 @@ var FIELD_MAPS2 = {
|
|
|
1197
1206
|
{ source: "order_id", target: "order.id" },
|
|
1198
1207
|
{ source: "order_name", target: "order.name" },
|
|
1199
1208
|
{ source: "payment_mode", target: "order.paymentMode" },
|
|
1209
|
+
{ source: "total_shipping", target: "order.totalShipping" },
|
|
1210
|
+
{ source: "total_tax", target: "order.totalTax" },
|
|
1200
1211
|
{ source: "total_payable", target: "order.totalPayable" }
|
|
1201
1212
|
]
|
|
1202
1213
|
};
|
|
@@ -1244,7 +1255,7 @@ function editableFieldsFor2(eventName) {
|
|
|
1244
1255
|
}
|
|
1245
1256
|
var editableFields4 = editableFieldsFor2(DEFAULT_EVENT2);
|
|
1246
1257
|
function buildPayload4(ctx) {
|
|
1247
|
-
const { config, items, phone, collection } = ctx;
|
|
1258
|
+
const { config, items, phone, collection, live } = ctx;
|
|
1248
1259
|
const eventName = ctx.eventName ?? DEFAULT_EVENT2;
|
|
1249
1260
|
const def = eventDef(eventName);
|
|
1250
1261
|
const now = ctx.now ?? /* @__PURE__ */ new Date();
|
|
@@ -1263,7 +1274,7 @@ function buildPayload4(ctx) {
|
|
|
1263
1274
|
pageUrl: `https://${domain}/`,
|
|
1264
1275
|
pageTitle: config.shopify.shop?.name ?? domain,
|
|
1265
1276
|
landingPageUrl: `https://${domain}/`,
|
|
1266
|
-
referrerPageUrl: ""
|
|
1277
|
+
referrerPageUrl: ctx.referrer ?? "https://www.google.com/"
|
|
1267
1278
|
},
|
|
1268
1279
|
clientData: { brandUrl: `https://${domain}` }
|
|
1269
1280
|
},
|
|
@@ -1280,7 +1291,7 @@ function buildPayload4(ctx) {
|
|
|
1280
1291
|
page_url: isProduct ? `https://${domain}/products/${first?.product?.handle ?? ""}` : `https://${domain}/collections/${collection?.handle ?? "all"}`,
|
|
1281
1292
|
page_title: isProduct ? first?.product?.title : collection?.title,
|
|
1282
1293
|
landing_page_url: `https://${domain}/`,
|
|
1283
|
-
referrer_page_url: "",
|
|
1294
|
+
referrer_page_url: ctx.referrer ?? "https://www.google.com/",
|
|
1284
1295
|
...isProduct ? {
|
|
1285
1296
|
product_name: first?.product?.title,
|
|
1286
1297
|
product_image: imageForVariant(first?.product, first?.variant),
|
|
@@ -1305,7 +1316,7 @@ function buildPayload4(ctx) {
|
|
|
1305
1316
|
const subtotal = money2(lineItems.reduce((sum, li) => sum + Number(li.price) * li.quantity, 0));
|
|
1306
1317
|
const discount = money2(Math.min(ctx.discount ?? 0, subtotal));
|
|
1307
1318
|
const total = money2(subtotal - discount);
|
|
1308
|
-
const checkoutUrl = cartPermalink(domain, (items ?? []).map(({ variant, quantity }) => ({ variantId: variant?.id, quantity })));
|
|
1319
|
+
const checkoutUrl = live?.kind === "checkout" && live.url ? live.url : cartPermalink(domain, (items ?? []).map(({ variant, quantity }) => ({ variantId: variant?.id, quantity })));
|
|
1309
1320
|
return {
|
|
1310
1321
|
event_name: eventName,
|
|
1311
1322
|
session_id: ctx.sessionId ?? `sf-${now.getTime()}`,
|
|
@@ -1327,12 +1338,13 @@ function buildPayload4(ctx) {
|
|
|
1327
1338
|
total_discount: discount,
|
|
1328
1339
|
total_price: total,
|
|
1329
1340
|
...eventName === "order_completed" ? {
|
|
1330
|
-
|
|
1331
|
-
|
|
1341
|
+
// a real order id is what the receiver would look up
|
|
1342
|
+
order_id: live?.kind === "order" ? live.id : ctx.orderId ?? Math.floor(now.getTime() / 1e3),
|
|
1343
|
+
order_name: live?.kind === "order" ? live.name : ctx.orderName ?? `#${String(now.getTime()).slice(-5)}`,
|
|
1332
1344
|
payment_mode: "prepaid",
|
|
1333
1345
|
total_shipping: 0,
|
|
1334
1346
|
total_tax: 0,
|
|
1335
|
-
total_payable: total
|
|
1347
|
+
total_payable: live?.kind === "order" ? Number(live.price) : total
|
|
1336
1348
|
} : {},
|
|
1337
1349
|
timestamp: now.getTime()
|
|
1338
1350
|
};
|
|
@@ -1482,12 +1494,13 @@ function nationalNumber(raw, regionCode) {
|
|
|
1482
1494
|
// src/providers/flexype.mjs
|
|
1483
1495
|
var GATE_PATH3 = "event_type";
|
|
1484
1496
|
var GATE_VALUE2 = "ABANDONED_CHECKOUT";
|
|
1497
|
+
var DEFAULT_EVENT3 = GATE_VALUE2;
|
|
1485
1498
|
var fieldMap5 = [
|
|
1486
1499
|
{ source: "event_type", target: "\xABgate\xBB", required: true, note: "must be ABANDONED_CHECKOUT or the event is dropped" },
|
|
1487
1500
|
{ source: "payload.user.phone_with_dial_code", target: "phone", required: true, note: "falls back to dial_code + phone" },
|
|
1488
1501
|
{ source: "payload.user.first_name", target: "customer.firstName" },
|
|
1489
1502
|
{ source: "payload.user.last_name", target: "customer.lastName" },
|
|
1490
|
-
{ source: "payload.user.full_name", target: "customer.name" },
|
|
1503
|
+
{ source: "payload.user.full_name", target: "customer.fullName", note: "falls back to first + last name" },
|
|
1491
1504
|
{ source: "payload.user.email", target: "customer.email" },
|
|
1492
1505
|
{ source: "payload.checkout_url", target: "checkoutUrl", required: true },
|
|
1493
1506
|
{ source: "payload.session_id", target: "sessionId" },
|
|
@@ -1496,7 +1509,8 @@ var fieldMap5 = [
|
|
|
1496
1509
|
{ source: "payload.cart_items[].image", target: "cart.image" },
|
|
1497
1510
|
{ source: "payload.cart_items[].total_price", target: "pricing.totalPrice", note: "summed across the cart" },
|
|
1498
1511
|
{ source: "payload.cart_items[].total_discount", target: "pricing.totalDiscount", note: "summed across the cart" },
|
|
1499
|
-
{ source: "payload.cart_items[].quantity", target: "cart.quantity" },
|
|
1512
|
+
{ source: "payload.cart_items[].quantity", target: "cart.quantity", note: "summed across the cart" },
|
|
1513
|
+
{ source: "payload.cart_items[]", target: "cart.itemCount", note: "the line count, not the quantity" },
|
|
1500
1514
|
{ source: "payload.coupons[0].code", target: "pricing.couponCode" },
|
|
1501
1515
|
{ source: "payload.checkout_context.presentment_currency", target: "pricing.currency" },
|
|
1502
1516
|
{ source: "payload.checkout_context.presentment_country", target: "phone region" },
|
|
@@ -1504,6 +1518,9 @@ var fieldMap5 = [
|
|
|
1504
1518
|
{ source: "payload.metadata.landing_page", target: "attribution.landingPage" },
|
|
1505
1519
|
{ source: "store.shopify_domain", target: "storeUrl" },
|
|
1506
1520
|
{ source: "store.name", target: "store.name" },
|
|
1521
|
+
{ source: "store.main_domain", target: "store.mainDomain" },
|
|
1522
|
+
{ source: "payload.checkout_context.store_country", target: "store.country" },
|
|
1523
|
+
{ source: "payload.metadata.orig_referer", target: "attribution.referrer" },
|
|
1507
1524
|
{ source: "event_id", target: "eventId" },
|
|
1508
1525
|
{ source: "event_time", target: "eventTime" }
|
|
1509
1526
|
];
|
|
@@ -1524,7 +1541,7 @@ var editableFields5 = [
|
|
|
1524
1541
|
{ group: "Attribution", path: "payload.metadata.landing_page", label: "Landing page", optional: true }
|
|
1525
1542
|
];
|
|
1526
1543
|
function buildPayload5(ctx) {
|
|
1527
|
-
const { config, items, phone } = ctx;
|
|
1544
|
+
const { config, items, phone, live } = ctx;
|
|
1528
1545
|
const now = ctx.now ?? /* @__PURE__ */ new Date();
|
|
1529
1546
|
const currency = ctx.currency || config.defaults.currency;
|
|
1530
1547
|
const domain = config.shopify.domain;
|
|
@@ -1544,7 +1561,7 @@ function buildPayload5(ctx) {
|
|
|
1544
1561
|
sku: variant?.sku || null
|
|
1545
1562
|
};
|
|
1546
1563
|
});
|
|
1547
|
-
const checkoutUrl = cartPermalink(domain, (items ?? []).map(({ variant, quantity }) => ({ variantId: variant?.id, quantity })));
|
|
1564
|
+
const checkoutUrl = live?.kind === "checkout" && live.url ? live.url : cartPermalink(domain, (items ?? []).map(({ variant, quantity }) => ({ variantId: variant?.id, quantity })));
|
|
1548
1565
|
const utm = Object.entries(config.defaults.utm ?? {}).map(([name, value]) => ({ name, value }));
|
|
1549
1566
|
return {
|
|
1550
1567
|
event_id: `fx-${now.getTime()}`,
|
|
@@ -1579,8 +1596,8 @@ function buildPayload5(ctx) {
|
|
|
1579
1596
|
coupons: ctx.couponCode ? [{ code: ctx.couponCode }] : [],
|
|
1580
1597
|
metadata: {
|
|
1581
1598
|
landing_page: `https://${domain}/products/${items?.[0]?.product?.handle ?? ""}`,
|
|
1582
|
-
orig_referer: "",
|
|
1583
|
-
referer_host: "",
|
|
1599
|
+
orig_referer: ctx.referrer ?? "https://www.google.com/",
|
|
1600
|
+
referer_host: "www.google.com",
|
|
1584
1601
|
utm
|
|
1585
1602
|
}
|
|
1586
1603
|
}
|
|
@@ -1621,6 +1638,7 @@ var flexype_default = {
|
|
|
1621
1638
|
urlKey: "flexype",
|
|
1622
1639
|
label: "FlexyPe",
|
|
1623
1640
|
eventType: "flexype_abandoned_checkout",
|
|
1641
|
+
defaultEvent: DEFAULT_EVENT3,
|
|
1624
1642
|
gate: { path: GATE_PATH3, value: GATE_VALUE2 },
|
|
1625
1643
|
signatureScheme: "static shared secret in the header (no body signature)",
|
|
1626
1644
|
signatureHeader: "x-flexype-authorization",
|
|
@@ -1647,8 +1665,8 @@ var EVENTS3 = ["return", "exchange"].flatMap(
|
|
|
1647
1665
|
subject: requestType === "exchange" ? "the returned product and its replacement" : "the returned product"
|
|
1648
1666
|
}))
|
|
1649
1667
|
);
|
|
1650
|
-
var
|
|
1651
|
-
var eventDef2 = (eventName) => EVENTS3.find((e) => e.eventName === eventName) ?? EVENTS3.find((e) => e.eventName ===
|
|
1668
|
+
var DEFAULT_EVENT4 = "return_requested";
|
|
1669
|
+
var eventDef2 = (eventName) => EVENTS3.find((e) => e.eventName === eventName) ?? EVENTS3.find((e) => e.eventName === DEFAULT_EVENT4);
|
|
1652
1670
|
function eventFromPayload3(payload) {
|
|
1653
1671
|
const request = payload?.request ?? payload ?? {};
|
|
1654
1672
|
if (!request.request_type || !request.status) return void 0;
|
|
@@ -1703,13 +1721,13 @@ function editableFieldsFor3(eventName) {
|
|
|
1703
1721
|
{ group: "Pricing", path: p("line_items.0.presentment_price.currency"), label: "Currency" }
|
|
1704
1722
|
];
|
|
1705
1723
|
}
|
|
1706
|
-
var editableFields6 = editableFieldsFor3(
|
|
1724
|
+
var editableFields6 = editableFieldsFor3(DEFAULT_EVENT4);
|
|
1707
1725
|
function statusBlock(reached, at, comment = null) {
|
|
1708
1726
|
return { status: reached, comment, created_at: reached ? at : null };
|
|
1709
1727
|
}
|
|
1710
1728
|
function buildPayload6(ctx) {
|
|
1711
1729
|
const { config, items, phone } = ctx;
|
|
1712
|
-
const eventName = ctx.eventName ??
|
|
1730
|
+
const eventName = ctx.eventName ?? DEFAULT_EVENT4;
|
|
1713
1731
|
const def = eventDef2(eventName);
|
|
1714
1732
|
const now = ctx.now ?? /* @__PURE__ */ new Date();
|
|
1715
1733
|
const currency = ctx.currency || config.defaults.currency;
|
|
@@ -1913,7 +1931,7 @@ var return_prime_default = {
|
|
|
1913
1931
|
urlKey: "return_prime",
|
|
1914
1932
|
label: "Return Prime",
|
|
1915
1933
|
events: EVENTS3,
|
|
1916
|
-
defaultEvent:
|
|
1934
|
+
defaultEvent: DEFAULT_EVENT4,
|
|
1917
1935
|
eventType: "return_prime_return_requested",
|
|
1918
1936
|
gate: { path: "request.request_type", value: "return" },
|
|
1919
1937
|
gateFor: (eventName) => ({ path: "request.status", value: eventDef2(eventName).status }),
|
|
@@ -3008,7 +3026,11 @@ async function buildPayload8({ cfg, providerId = "cashfree-occ", items = [], dis
|
|
|
3008
3026
|
|
|
3009
3027
|
// src/shopify/live.mjs
|
|
3010
3028
|
var LIVE_EVENTS = {
|
|
3011
|
-
nitro: /* @__PURE__ */ new Set(["checkout", "orders/create", "orders/updated"])
|
|
3029
|
+
nitro: /* @__PURE__ */ new Set(["checkout", "orders/create", "orders/updated"]),
|
|
3030
|
+
// shopflo's recovery link and order id are looked up the same way
|
|
3031
|
+
shopflo: /* @__PURE__ */ new Set(["checkout_abandoned", "checkout_clicked", "order_completed"]),
|
|
3032
|
+
// flexype sends one event and it is a recovery link
|
|
3033
|
+
flexype: /* @__PURE__ */ new Set(["ABANDONED_CHECKOUT"])
|
|
3012
3034
|
};
|
|
3013
3035
|
function needsLive(providerId, eventName) {
|
|
3014
3036
|
return LIVE_EVENTS[providerId]?.has(eventName) ?? false;
|
|
@@ -3090,8 +3112,9 @@ async function liveOrder({ config, items = [], phone, client = clientFor(config)
|
|
|
3090
3112
|
async function resolveLive({ config, providerId, eventName, items, phone, client }) {
|
|
3091
3113
|
if (!needsLive(providerId, eventName)) return null;
|
|
3092
3114
|
if (!config?.shopify?.domain || !config?.shopify?.accessToken) return null;
|
|
3093
|
-
|
|
3094
|
-
return await liveOrder({ config, items, phone, ...client ? { client } : {} });
|
|
3115
|
+
const wantsOrder = eventName === "orders/create" || eventName === "orders/updated" || eventName === "order_completed";
|
|
3116
|
+
if (wantsOrder) return await liveOrder({ config, items, phone, ...client ? { client } : {} });
|
|
3117
|
+
return await liveCheckout({ config, items, ...client ? { client } : {} });
|
|
3095
3118
|
}
|
|
3096
3119
|
|
|
3097
3120
|
// src/core/send.mjs
|