my pkgs monorepo
1#!/usr/bin/env node
2/**
3 * Simulate Ko-fi webhook POSTs against your local dev server.
4 *
5 * Usage:
6 * KOFI_VERIFICATION_TOKEN=your-token node scripts/simulate-webhook.mjs [type] [name] [tier]
7 *
8 * Types: Donation | Subscription | Commission | "Shop Order"
9 *
10 * Examples:
11 * node scripts/simulate-webhook.mjs Donation "Jo Example"
12 * node scripts/simulate-webhook.mjs Subscription "Alice" "Lunar Contributors"
13 * node scripts/simulate-webhook.mjs Commission "Bob"
14 * node scripts/simulate-webhook.mjs "Shop Order" "Carol"
15 */
16
17const token = process.env.KOFI_VERIFICATION_TOKEN ?? 'test-token';
18const type = process.argv[2] ?? 'Donation';
19const name = process.argv[3] ?? 'Jo Example';
20const tier = process.argv[4] ?? (type === 'Subscription' ? 'Lunar Contributors' : null);
21const url = process.argv[5] ?? 'http://localhost:5173/webhook';
22
23const isSubscription = type === 'Subscription';
24
25const payload = {
26 verification_token: token,
27 message_id: crypto.randomUUID(),
28 timestamp: new Date().toISOString(),
29 type,
30 is_public: true,
31 from_name: name,
32 message: 'Simulated webhook event',
33 amount: '3.00',
34 url: 'https://ko-fi.com/Home/CoffeeShop?txid=test',
35 email: 'test@example.com',
36 currency: 'GBP',
37 is_subscription_payment: isSubscription,
38 is_first_subscription_payment: isSubscription,
39 kofi_transaction_id: crypto.randomUUID(),
40 shop_items: type === 'Shop Order' ? [{ id: 'item-1', name: 'Test Item' }] : null,
41 tier_name: tier ?? null,
42 shipping: null
43};
44
45const body = new URLSearchParams({ data: JSON.stringify(payload) });
46
47console.log(`→ POST ${url}`);
48console.log(` type: ${type}`);
49console.log(` from_name: ${name}`);
50if (tier) console.log(` tier_name: ${tier}`);
51console.log();
52
53const res = await fetch(url, {
54 method: 'POST',
55 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
56 body
57});
58
59console.log(`Status: ${res.status} ${res.statusText}`);
60if (res.status !== 200) {
61 console.log('Body:', await res.text());
62}