hookwright 1.0.0 → 1.1.1
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/README.md +34 -8
- package/dist/cli.js +1154 -345
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ hookwright # interactive UI — starts in the setup wizard on first
|
|
|
38
38
|
| Setup | asks for |
|
|
39
39
|
|---|---|
|
|
40
40
|
| **Shopify** | store domain + Admin API access token (needs `read_products`). Verifies immediately and picks up currency, country, province and contact details from the store record |
|
|
41
|
-
| **Webhook** |
|
|
41
|
+
| **Webhook** | one destination URL + signing secret **per integration** — Cashfree, Razorpay Magic and Nitro each get their own |
|
|
42
42
|
| **Customer** | the shopper the abandoned cart belongs to |
|
|
43
43
|
| **Defaults** | currency, platform |
|
|
44
44
|
|
|
@@ -50,14 +50,31 @@ Then **Integrations → Cashfree One Click Checkout** builds the payload:
|
|
|
50
50
|
2. Variant and quantity per product
|
|
51
51
|
3. Cart discount
|
|
52
52
|
4. Either accept the suggested values, or **review every field** — each one is pre-filled with the generated suggestion, enter accepts it, typing replaces it
|
|
53
|
-
5. Pre-flight report,
|
|
53
|
+
5. Pre-flight report — every check, the full field coverage table, the signed request and the complete payload
|
|
54
|
+
6. A **ready-to-paste `curl` is copied to your clipboard** automatically, then send
|
|
55
|
+
|
|
56
|
+
The report page is a compact status board with a command bar — `s` send · `c` copy curl · `j` copy json · `u` curl · `p` payload · `f` fields · `v` checks · `r` request. Panels are collapsed by default, so you see the verdict first and the detail only when you ask for it.
|
|
57
|
+
|
|
58
|
+
`esc` walks back one step at a time through the whole flow (report → mode → discount → quantity → variant → products → event), and only leaves the integration from the first step.
|
|
59
|
+
|
|
60
|
+
### The curl is built for pasting
|
|
61
|
+
|
|
62
|
+
The command is emitted in the exact shape Postman itself exports — `curl --location --request POST` with unindented `--header` / `--data` lines — and the body is inlined, never `@file`. Drop it straight into **Postman → Import → Raw text**, a colleague's terminal, or a bug report.
|
|
63
|
+
|
|
64
|
+
Single quotes inside product titles (`Levi's 501`) are escaped, and the signature travels with the exact body it signs, so a pasted command verifies precisely as the original request would.
|
|
65
|
+
|
|
66
|
+
Two things keep this honest: a test that executes the generated command verbatim against a receiver doing real HMAC verification, and a test that runs it through **`curl-to-postmanv2`** — the same parser Postman uses for Raw-text import — asserting the URL, method, every header and a byte-identical body all survive.
|
|
67
|
+
|
|
68
|
+
In the report screen: `c` re-copies the curl · `j` copies the raw payload JSON · `p` toggles the full payload view.
|
|
54
69
|
|
|
55
70
|
## Headless usage
|
|
56
71
|
|
|
57
72
|
Every command works without a TTY, for CI or scripting:
|
|
58
73
|
|
|
59
74
|
```bash
|
|
60
|
-
hookwright build --items 2
|
|
75
|
+
hookwright build --items 2 # cashfree-occ by default
|
|
76
|
+
hookwright build --provider razorpay-magic --items 2
|
|
77
|
+
hookwright build --provider nitro --event orders/create
|
|
61
78
|
hookwright build --search "cold brew" # only products matching a title
|
|
62
79
|
hookwright build --items 3 --discount 250 --send
|
|
63
80
|
hookwright send --dry-run # print the request + curl, send nothing
|
|
@@ -78,6 +95,7 @@ A generated payload is useless if the receiver silently drops it, so every build
|
|
|
78
95
|
- **Phone** — parsed to E.164 using the shipping `country_code`, the same way the consumer does.
|
|
79
96
|
- **Phone allow-list** — refuses to build for a number that isn't an approved test handset, so a live shopper can never be messaged by a test run.
|
|
80
97
|
- **Product images** — every `image_url` is `HEAD`-checked; unreachable images fail the build.
|
|
98
|
+
- **Endpoint exists** — before a signed payload is handed over, the destination is verified: the hostname must resolve, something must accept a TCP connection on the port, and the path must not 404. A typo'd host is caught here instead of looking like a silent delivery failure. The probe is `OPTIONS`, falling back to `HEAD` — **never a POST and never a body**, so it cannot create data on the receiving system. Timeouts and servers that reject `OPTIONS` warn rather than block. Skip with `--no-endpoint-check`, override with `--force`.
|
|
81
99
|
- **Field coverage** — a table of every field the consumer reads, what it maps to, and its value. Missing required fields are flagged in red.
|
|
82
100
|
|
|
83
101
|
Sending is also blocked when the target looks like production, unless `--force`.
|
|
@@ -94,18 +112,26 @@ Override both locations with `HOOKWRIGHT_HOME`, or point at one config with `--c
|
|
|
94
112
|
|
|
95
113
|
## Providers
|
|
96
114
|
|
|
97
|
-
| provider | signature | headers |
|
|
98
|
-
|
|
99
|
-
| `cashfree-occ` | base64 HMAC-SHA256 over `timestamp + body` | `x-webhook-signature`, `x-webhook-timestamp` |
|
|
115
|
+
| provider | signature | headers | events |
|
|
116
|
+
|---|---|---|---|
|
|
117
|
+
| `cashfree-occ` | base64 HMAC-SHA256 over `timestamp + body` | `x-webhook-signature`, `x-webhook-timestamp` | abandoned checkout |
|
|
118
|
+
| `razorpay-magic` | hex HMAC-SHA256 over the body | `x-razorpay-signature` | abandoned checkout |
|
|
119
|
+
| `nitro` | static bearer token, no body signature | `authorization` | 8 — page view, category view, product view, add to cart, remove from cart, checkout, order created, order updated |
|
|
120
|
+
|
|
121
|
+
Each provider owns its gate, signature scheme, field map, payload shape and summary, so nothing is assumed across them:
|
|
122
|
+
|
|
123
|
+
- **Cashfree OCC** nests everything under `data`; currency is read from `line_items[0]`, not the root.
|
|
124
|
+
- **Razorpay Magic** is root-level, uses capitalised shipping keys (`Shipping_address.Address1`) and sends `line_items_total` as a **string in paise** — matching [Razorpay's abandoned cart webhook docs](https://razorpay.com/docs/payments/magic-checkout/abandoned-cart/). Its gate is "non-empty `abandoned_checkout_url`" rather than an exact value.
|
|
125
|
+
- **Nitro** keys off `eventName` and requires `eventVal.customer.phone` on *every* event, parsed against root `country`. Choose the event with `--event`, or from the menu in the UI.
|
|
100
126
|
|
|
101
|
-
Adding one is a single file in `src/providers/` exporting `buildPayload`, `sign`, `webhookUrl`, a `gate` and a `fieldMap` — see [docs/cashfree-occ.md](docs/cashfree-occ.md).
|
|
127
|
+
Adding one is a single file in `src/providers/` exporting `buildPayload`, `sign`, `webhookUrl`, `summarize`, a `gate` and a `fieldMap` — see [docs/cashfree-occ.md](docs/cashfree-occ.md).
|
|
102
128
|
|
|
103
129
|
## Development
|
|
104
130
|
|
|
105
131
|
```bash
|
|
106
132
|
npm install
|
|
107
133
|
npm run dev # esbuild watch
|
|
108
|
-
npm test #
|
|
134
|
+
npm test # 179 tests, no network required
|
|
109
135
|
npm start # build + run
|
|
110
136
|
```
|
|
111
137
|
|