torque-webhooks 0.1.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/LICENSE +21 -0
- package/README.md +53 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.esm.js +122 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +129 -0
- package/dist/index.js.map +1 -0
- package/dist/nextjs.d.ts +25 -0
- package/dist/nextjs.esm.js +59 -0
- package/dist/nextjs.esm.js.map +1 -0
- package/dist/nextjs.js +62 -0
- package/dist/nextjs.js.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Torque
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# torque-webhooks
|
|
2
|
+
|
|
3
|
+
Merchant webhook helpers for Torque Checkout integrations.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
yarn add torque-webhooks
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Verify inbound webhooks (Torque → your server)
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { verifyWebhookSignature } from 'torque-webhooks'
|
|
15
|
+
|
|
16
|
+
const ok = verifyWebhookSignature(rawBody, request.headers.get('x-torque-signature'), secret)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Push order status (your server → Torque)
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { createTorqueWebhooksFromEnv } from 'torque-webhooks'
|
|
23
|
+
|
|
24
|
+
const webhooks = createTorqueWebhooksFromEnv()
|
|
25
|
+
|
|
26
|
+
await webhooks.pushOrderUpdate({
|
|
27
|
+
orderId: 'ord_123',
|
|
28
|
+
status: 'shipped',
|
|
29
|
+
metadata: { trackingNumber: '1Z999' },
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Uses `POST /api/webhooks/order-update` with header `x-order-webhook-secret`.
|
|
34
|
+
|
|
35
|
+
**Env:** `TORQUE_WEBHOOK_SECRET` or `ORDER_WEBHOOK_SECRET`, optional `TORQUE_BASE_URL`.
|
|
36
|
+
|
|
37
|
+
## Next.js inbound handler
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
// app/api/webhooks/torque/route.ts
|
|
41
|
+
import { handleWebhook } from 'torque-webhooks/nextjs'
|
|
42
|
+
|
|
43
|
+
export const POST = handleWebhook({
|
|
44
|
+
secret: process.env.TORQUE_WEBHOOK_SECRET,
|
|
45
|
+
onOrderCompleted: async (event) => {
|
|
46
|
+
await fulfillOrder(event.orderId!)
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## License
|
|
52
|
+
|
|
53
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export type TorqueOutboundWebhookEventType = 'order.created' | 'order.completed' | 'order.failed' | 'subscription.created' | 'subscription.cancelled';
|
|
2
|
+
/** Payload Torque may send to merchant webhook endpoints (outbound). */
|
|
3
|
+
export interface TorqueOutboundWebhookEvent {
|
|
4
|
+
type: TorqueOutboundWebhookEventType;
|
|
5
|
+
orderId?: string;
|
|
6
|
+
subscriptionId?: string;
|
|
7
|
+
data: Record<string, unknown>;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
}
|
|
10
|
+
export type OrderUpdateStatus = 'created' | 'paid' | 'shipped' | 'delivered' | 'cancelled' | 'refunded';
|
|
11
|
+
export interface PushOrderUpdateParams {
|
|
12
|
+
orderId: string;
|
|
13
|
+
status: OrderUpdateStatus;
|
|
14
|
+
customerData?: Record<string, unknown>;
|
|
15
|
+
metadata?: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
export interface TorqueWebhooksConfig {
|
|
18
|
+
/** Shared secret for POST /api/webhooks/order-update (`x-order-webhook-secret`). */
|
|
19
|
+
webhookSecret: string;
|
|
20
|
+
baseUrl?: string;
|
|
21
|
+
timeout?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare class TorqueWebhooksError extends Error {
|
|
24
|
+
code: string;
|
|
25
|
+
statusCode: number;
|
|
26
|
+
details?: Record<string, unknown>;
|
|
27
|
+
constructor(message: string, options: {
|
|
28
|
+
code: string;
|
|
29
|
+
statusCode: number;
|
|
30
|
+
details?: Record<string, unknown>;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Verify `X-Torque-Signature` (or raw hex) against HMAC-SHA256 of the **raw** webhook body.
|
|
35
|
+
* Accepts `hex`, `sha256=<hex>`, or `v1=<hex>` prefix forms.
|
|
36
|
+
*/
|
|
37
|
+
export declare function verifyWebhookSignature(rawBody: string, signatureHeader: string | null, secret: string): boolean;
|
|
38
|
+
/** Checkout-compatible alias. */
|
|
39
|
+
export declare const verifyTorqueWebhookSignature: typeof verifyWebhookSignature;
|
|
40
|
+
export declare function pushOrderUpdate(params: PushOrderUpdateParams, config: TorqueWebhooksConfig): Promise<{
|
|
41
|
+
success: boolean;
|
|
42
|
+
message?: string;
|
|
43
|
+
timestamp?: string;
|
|
44
|
+
}>;
|
|
45
|
+
export declare function createTorqueWebhooks(config: TorqueWebhooksConfig): {
|
|
46
|
+
pushOrderUpdate: (params: PushOrderUpdateParams) => Promise<{
|
|
47
|
+
success: boolean;
|
|
48
|
+
message?: string;
|
|
49
|
+
timestamp?: string;
|
|
50
|
+
}>;
|
|
51
|
+
verifyWebhookSignature: (rawBody: string, signatureHeader: string | null, secret?: string) => boolean;
|
|
52
|
+
};
|
|
53
|
+
export declare function createTorqueWebhooksFromEnv(overrides?: Partial<TorqueWebhooksConfig>): {
|
|
54
|
+
pushOrderUpdate: (params: PushOrderUpdateParams) => Promise<{
|
|
55
|
+
success: boolean;
|
|
56
|
+
message?: string;
|
|
57
|
+
timestamp?: string;
|
|
58
|
+
}>;
|
|
59
|
+
verifyWebhookSignature: (rawBody: string, signatureHeader: string | null, secret?: string) => boolean;
|
|
60
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from 'crypto';
|
|
2
|
+
|
|
3
|
+
class TorqueWebhooksError extends Error {
|
|
4
|
+
constructor(message, options) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'TorqueWebhooksError';
|
|
7
|
+
this.code = options.code;
|
|
8
|
+
this.statusCode = options.statusCode;
|
|
9
|
+
this.details = options.details;
|
|
10
|
+
Object.setPrototypeOf(this, TorqueWebhooksError.prototype);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Verify `X-Torque-Signature` (or raw hex) against HMAC-SHA256 of the **raw** webhook body.
|
|
15
|
+
* Accepts `hex`, `sha256=<hex>`, or `v1=<hex>` prefix forms.
|
|
16
|
+
*/
|
|
17
|
+
function verifyWebhookSignature(rawBody, signatureHeader, secret) {
|
|
18
|
+
if (!signatureHeader || !secret)
|
|
19
|
+
return false;
|
|
20
|
+
const expectedHex = createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex');
|
|
21
|
+
const normalized = signatureHeader.trim().replace(/^(sha256|v1)=/i, '');
|
|
22
|
+
try {
|
|
23
|
+
const a = Buffer.from(normalized, 'hex');
|
|
24
|
+
const b = Buffer.from(expectedHex, 'hex');
|
|
25
|
+
if (a.length !== b.length)
|
|
26
|
+
return false;
|
|
27
|
+
return timingSafeEqual(a, b);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Checkout-compatible alias. */
|
|
34
|
+
const verifyTorqueWebhookSignature = verifyWebhookSignature;
|
|
35
|
+
async function pushOrderUpdate(params, config) {
|
|
36
|
+
if (!params.orderId?.trim()) {
|
|
37
|
+
throw new TorqueWebhooksError('orderId is required', {
|
|
38
|
+
code: 'VALIDATION_ERROR',
|
|
39
|
+
statusCode: 400,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (!params.status) {
|
|
43
|
+
throw new TorqueWebhooksError('status is required', {
|
|
44
|
+
code: 'VALIDATION_ERROR',
|
|
45
|
+
statusCode: 400,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (!config.webhookSecret?.trim()) {
|
|
49
|
+
throw new TorqueWebhooksError('webhookSecret is required', {
|
|
50
|
+
code: 'INVALID_CONFIG',
|
|
51
|
+
statusCode: 400,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const baseUrl = (config.baseUrl || 'https://app.torque.fi').replace(/\/$/, '');
|
|
55
|
+
const timeout = config.timeout ?? 30000;
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
58
|
+
try {
|
|
59
|
+
const response = await fetch(`${baseUrl}/api/webhooks/order-update`, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
'x-order-webhook-secret': config.webhookSecret.trim(),
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify({
|
|
66
|
+
orderId: params.orderId,
|
|
67
|
+
status: params.status,
|
|
68
|
+
customerData: params.customerData,
|
|
69
|
+
metadata: params.metadata,
|
|
70
|
+
}),
|
|
71
|
+
signal: controller.signal,
|
|
72
|
+
});
|
|
73
|
+
clearTimeout(timeoutId);
|
|
74
|
+
const body = (await response.json().catch(() => ({})));
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
throw new TorqueWebhooksError(body.message || `HTTP ${response.status}`, {
|
|
77
|
+
code: typeof body.error === 'string' ? body.error : 'API_ERROR',
|
|
78
|
+
statusCode: response.status,
|
|
79
|
+
details: body.details,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
success: body.success ?? true,
|
|
84
|
+
message: body.message,
|
|
85
|
+
timestamp: body.timestamp,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
clearTimeout(timeoutId);
|
|
90
|
+
if (error instanceof TorqueWebhooksError)
|
|
91
|
+
throw error;
|
|
92
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
93
|
+
throw new TorqueWebhooksError('Request timeout', { code: 'TIMEOUT', statusCode: 408 });
|
|
94
|
+
}
|
|
95
|
+
throw new TorqueWebhooksError(error instanceof Error ? error.message : 'Request failed', {
|
|
96
|
+
code: 'NETWORK_ERROR',
|
|
97
|
+
statusCode: 500,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function createTorqueWebhooks(config) {
|
|
102
|
+
return {
|
|
103
|
+
pushOrderUpdate: (params) => pushOrderUpdate(params, config),
|
|
104
|
+
verifyWebhookSignature: (rawBody, signatureHeader, secret) => verifyWebhookSignature(rawBody, signatureHeader, secret ?? config.webhookSecret),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function createTorqueWebhooksFromEnv(overrides) {
|
|
108
|
+
const webhookSecret = process.env.TORQUE_WEBHOOK_SECRET ||
|
|
109
|
+
process.env.ORDER_WEBHOOK_SECRET ||
|
|
110
|
+
overrides?.webhookSecret;
|
|
111
|
+
if (!webhookSecret) {
|
|
112
|
+
throw new TorqueWebhooksError('TORQUE_WEBHOOK_SECRET or ORDER_WEBHOOK_SECRET environment variable is required', { code: 'MISSING_ENV_VARS', statusCode: 400 });
|
|
113
|
+
}
|
|
114
|
+
return createTorqueWebhooks({
|
|
115
|
+
webhookSecret,
|
|
116
|
+
baseUrl: process.env.TORQUE_BASE_URL || overrides?.baseUrl,
|
|
117
|
+
timeout: overrides?.timeout,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export { TorqueWebhooksError, createTorqueWebhooks, createTorqueWebhooksFromEnv, pushOrderUpdate, verifyTorqueWebhookSignature, verifyWebhookSignature };
|
|
122
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/index.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from 'crypto'\n\nexport type TorqueOutboundWebhookEventType =\n | 'order.created'\n | 'order.completed'\n | 'order.failed'\n | 'subscription.created'\n | 'subscription.cancelled'\n\n/** Payload Torque may send to merchant webhook endpoints (outbound). */\nexport interface TorqueOutboundWebhookEvent {\n type: TorqueOutboundWebhookEventType\n orderId?: string\n subscriptionId?: string\n data: Record<string, unknown>\n timestamp: number\n}\n\nexport type OrderUpdateStatus =\n | 'created'\n | 'paid'\n | 'shipped'\n | 'delivered'\n | 'cancelled'\n | 'refunded'\n\nexport interface PushOrderUpdateParams {\n orderId: string\n status: OrderUpdateStatus\n customerData?: Record<string, unknown>\n metadata?: Record<string, unknown>\n}\n\nexport interface TorqueWebhooksConfig {\n /** Shared secret for POST /api/webhooks/order-update (`x-order-webhook-secret`). */\n webhookSecret: string\n baseUrl?: string\n timeout?: number\n}\n\nexport class TorqueWebhooksError extends Error {\n code: string\n statusCode: number\n details?: Record<string, unknown>\n\n constructor(\n message: string,\n options: { code: string; statusCode: number; details?: Record<string, unknown> },\n ) {\n super(message)\n this.name = 'TorqueWebhooksError'\n this.code = options.code\n this.statusCode = options.statusCode\n this.details = options.details\n Object.setPrototypeOf(this, TorqueWebhooksError.prototype)\n }\n}\n\n/**\n * Verify `X-Torque-Signature` (or raw hex) against HMAC-SHA256 of the **raw** webhook body.\n * Accepts `hex`, `sha256=<hex>`, or `v1=<hex>` prefix forms.\n */\nexport function verifyWebhookSignature(\n rawBody: string,\n signatureHeader: string | null,\n secret: string,\n): boolean {\n if (!signatureHeader || !secret) return false\n const expectedHex = createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex')\n const normalized = signatureHeader.trim().replace(/^(sha256|v1)=/i, '')\n try {\n const a = Buffer.from(normalized, 'hex')\n const b = Buffer.from(expectedHex, 'hex')\n if (a.length !== b.length) return false\n return timingSafeEqual(a, b)\n } catch {\n return false\n }\n}\n\n/** Checkout-compatible alias. */\nexport const verifyTorqueWebhookSignature = verifyWebhookSignature\n\nexport async function pushOrderUpdate(\n params: PushOrderUpdateParams,\n config: TorqueWebhooksConfig,\n): Promise<{ success: boolean; message?: string; timestamp?: string }> {\n if (!params.orderId?.trim()) {\n throw new TorqueWebhooksError('orderId is required', {\n code: 'VALIDATION_ERROR',\n statusCode: 400,\n })\n }\n if (!params.status) {\n throw new TorqueWebhooksError('status is required', {\n code: 'VALIDATION_ERROR',\n statusCode: 400,\n })\n }\n if (!config.webhookSecret?.trim()) {\n throw new TorqueWebhooksError('webhookSecret is required', {\n code: 'INVALID_CONFIG',\n statusCode: 400,\n })\n }\n\n const baseUrl = (config.baseUrl || 'https://app.torque.fi').replace(/\\/$/, '')\n const timeout = config.timeout ?? 30_000\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(`${baseUrl}/api/webhooks/order-update`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-order-webhook-secret': config.webhookSecret.trim(),\n },\n body: JSON.stringify({\n orderId: params.orderId,\n status: params.status,\n customerData: params.customerData,\n metadata: params.metadata,\n }),\n signal: controller.signal,\n })\n\n clearTimeout(timeoutId)\n const body = (await response.json().catch(() => ({}))) as {\n success?: boolean\n message?: string\n timestamp?: string\n error?: string\n details?: Record<string, unknown>\n }\n\n if (!response.ok) {\n throw new TorqueWebhooksError(body.message || `HTTP ${response.status}`, {\n code: typeof body.error === 'string' ? body.error : 'API_ERROR',\n statusCode: response.status,\n details: body.details,\n })\n }\n\n return {\n success: body.success ?? true,\n message: body.message,\n timestamp: body.timestamp,\n }\n } catch (error) {\n clearTimeout(timeoutId)\n if (error instanceof TorqueWebhooksError) throw error\n if (error instanceof Error && error.name === 'AbortError') {\n throw new TorqueWebhooksError('Request timeout', { code: 'TIMEOUT', statusCode: 408 })\n }\n throw new TorqueWebhooksError(error instanceof Error ? error.message : 'Request failed', {\n code: 'NETWORK_ERROR',\n statusCode: 500,\n })\n }\n}\n\nexport function createTorqueWebhooks(config: TorqueWebhooksConfig) {\n return {\n pushOrderUpdate: (params: PushOrderUpdateParams) => pushOrderUpdate(params, config),\n verifyWebhookSignature: (\n rawBody: string,\n signatureHeader: string | null,\n secret?: string,\n ) => verifyWebhookSignature(rawBody, signatureHeader, secret ?? config.webhookSecret),\n }\n}\n\nexport function createTorqueWebhooksFromEnv(overrides?: Partial<TorqueWebhooksConfig>) {\n const webhookSecret =\n process.env.TORQUE_WEBHOOK_SECRET ||\n process.env.ORDER_WEBHOOK_SECRET ||\n overrides?.webhookSecret\n if (!webhookSecret) {\n throw new TorqueWebhooksError(\n 'TORQUE_WEBHOOK_SECRET or ORDER_WEBHOOK_SECRET environment variable is required',\n { code: 'MISSING_ENV_VARS', statusCode: 400 },\n )\n }\n return createTorqueWebhooks({\n webhookSecret,\n baseUrl: process.env.TORQUE_BASE_URL || overrides?.baseUrl,\n timeout: overrides?.timeout,\n })\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
class TorqueWebhooksError extends Error {
|
|
6
|
+
constructor(message, options) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'TorqueWebhooksError';
|
|
9
|
+
this.code = options.code;
|
|
10
|
+
this.statusCode = options.statusCode;
|
|
11
|
+
this.details = options.details;
|
|
12
|
+
Object.setPrototypeOf(this, TorqueWebhooksError.prototype);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Verify `X-Torque-Signature` (or raw hex) against HMAC-SHA256 of the **raw** webhook body.
|
|
17
|
+
* Accepts `hex`, `sha256=<hex>`, or `v1=<hex>` prefix forms.
|
|
18
|
+
*/
|
|
19
|
+
function verifyWebhookSignature(rawBody, signatureHeader, secret) {
|
|
20
|
+
if (!signatureHeader || !secret)
|
|
21
|
+
return false;
|
|
22
|
+
const expectedHex = crypto.createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex');
|
|
23
|
+
const normalized = signatureHeader.trim().replace(/^(sha256|v1)=/i, '');
|
|
24
|
+
try {
|
|
25
|
+
const a = Buffer.from(normalized, 'hex');
|
|
26
|
+
const b = Buffer.from(expectedHex, 'hex');
|
|
27
|
+
if (a.length !== b.length)
|
|
28
|
+
return false;
|
|
29
|
+
return crypto.timingSafeEqual(a, b);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Checkout-compatible alias. */
|
|
36
|
+
const verifyTorqueWebhookSignature = verifyWebhookSignature;
|
|
37
|
+
async function pushOrderUpdate(params, config) {
|
|
38
|
+
if (!params.orderId?.trim()) {
|
|
39
|
+
throw new TorqueWebhooksError('orderId is required', {
|
|
40
|
+
code: 'VALIDATION_ERROR',
|
|
41
|
+
statusCode: 400,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
if (!params.status) {
|
|
45
|
+
throw new TorqueWebhooksError('status is required', {
|
|
46
|
+
code: 'VALIDATION_ERROR',
|
|
47
|
+
statusCode: 400,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (!config.webhookSecret?.trim()) {
|
|
51
|
+
throw new TorqueWebhooksError('webhookSecret is required', {
|
|
52
|
+
code: 'INVALID_CONFIG',
|
|
53
|
+
statusCode: 400,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const baseUrl = (config.baseUrl || 'https://app.torque.fi').replace(/\/$/, '');
|
|
57
|
+
const timeout = config.timeout ?? 30000;
|
|
58
|
+
const controller = new AbortController();
|
|
59
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
60
|
+
try {
|
|
61
|
+
const response = await fetch(`${baseUrl}/api/webhooks/order-update`, {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
headers: {
|
|
64
|
+
'Content-Type': 'application/json',
|
|
65
|
+
'x-order-webhook-secret': config.webhookSecret.trim(),
|
|
66
|
+
},
|
|
67
|
+
body: JSON.stringify({
|
|
68
|
+
orderId: params.orderId,
|
|
69
|
+
status: params.status,
|
|
70
|
+
customerData: params.customerData,
|
|
71
|
+
metadata: params.metadata,
|
|
72
|
+
}),
|
|
73
|
+
signal: controller.signal,
|
|
74
|
+
});
|
|
75
|
+
clearTimeout(timeoutId);
|
|
76
|
+
const body = (await response.json().catch(() => ({})));
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
throw new TorqueWebhooksError(body.message || `HTTP ${response.status}`, {
|
|
79
|
+
code: typeof body.error === 'string' ? body.error : 'API_ERROR',
|
|
80
|
+
statusCode: response.status,
|
|
81
|
+
details: body.details,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
success: body.success ?? true,
|
|
86
|
+
message: body.message,
|
|
87
|
+
timestamp: body.timestamp,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
clearTimeout(timeoutId);
|
|
92
|
+
if (error instanceof TorqueWebhooksError)
|
|
93
|
+
throw error;
|
|
94
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
95
|
+
throw new TorqueWebhooksError('Request timeout', { code: 'TIMEOUT', statusCode: 408 });
|
|
96
|
+
}
|
|
97
|
+
throw new TorqueWebhooksError(error instanceof Error ? error.message : 'Request failed', {
|
|
98
|
+
code: 'NETWORK_ERROR',
|
|
99
|
+
statusCode: 500,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function createTorqueWebhooks(config) {
|
|
104
|
+
return {
|
|
105
|
+
pushOrderUpdate: (params) => pushOrderUpdate(params, config),
|
|
106
|
+
verifyWebhookSignature: (rawBody, signatureHeader, secret) => verifyWebhookSignature(rawBody, signatureHeader, secret ?? config.webhookSecret),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function createTorqueWebhooksFromEnv(overrides) {
|
|
110
|
+
const webhookSecret = process.env.TORQUE_WEBHOOK_SECRET ||
|
|
111
|
+
process.env.ORDER_WEBHOOK_SECRET ||
|
|
112
|
+
overrides?.webhookSecret;
|
|
113
|
+
if (!webhookSecret) {
|
|
114
|
+
throw new TorqueWebhooksError('TORQUE_WEBHOOK_SECRET or ORDER_WEBHOOK_SECRET environment variable is required', { code: 'MISSING_ENV_VARS', statusCode: 400 });
|
|
115
|
+
}
|
|
116
|
+
return createTorqueWebhooks({
|
|
117
|
+
webhookSecret,
|
|
118
|
+
baseUrl: process.env.TORQUE_BASE_URL || overrides?.baseUrl,
|
|
119
|
+
timeout: overrides?.timeout,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
exports.TorqueWebhooksError = TorqueWebhooksError;
|
|
124
|
+
exports.createTorqueWebhooks = createTorqueWebhooks;
|
|
125
|
+
exports.createTorqueWebhooksFromEnv = createTorqueWebhooksFromEnv;
|
|
126
|
+
exports.pushOrderUpdate = pushOrderUpdate;
|
|
127
|
+
exports.verifyTorqueWebhookSignature = verifyTorqueWebhookSignature;
|
|
128
|
+
exports.verifyWebhookSignature = verifyWebhookSignature;
|
|
129
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from 'crypto'\n\nexport type TorqueOutboundWebhookEventType =\n | 'order.created'\n | 'order.completed'\n | 'order.failed'\n | 'subscription.created'\n | 'subscription.cancelled'\n\n/** Payload Torque may send to merchant webhook endpoints (outbound). */\nexport interface TorqueOutboundWebhookEvent {\n type: TorqueOutboundWebhookEventType\n orderId?: string\n subscriptionId?: string\n data: Record<string, unknown>\n timestamp: number\n}\n\nexport type OrderUpdateStatus =\n | 'created'\n | 'paid'\n | 'shipped'\n | 'delivered'\n | 'cancelled'\n | 'refunded'\n\nexport interface PushOrderUpdateParams {\n orderId: string\n status: OrderUpdateStatus\n customerData?: Record<string, unknown>\n metadata?: Record<string, unknown>\n}\n\nexport interface TorqueWebhooksConfig {\n /** Shared secret for POST /api/webhooks/order-update (`x-order-webhook-secret`). */\n webhookSecret: string\n baseUrl?: string\n timeout?: number\n}\n\nexport class TorqueWebhooksError extends Error {\n code: string\n statusCode: number\n details?: Record<string, unknown>\n\n constructor(\n message: string,\n options: { code: string; statusCode: number; details?: Record<string, unknown> },\n ) {\n super(message)\n this.name = 'TorqueWebhooksError'\n this.code = options.code\n this.statusCode = options.statusCode\n this.details = options.details\n Object.setPrototypeOf(this, TorqueWebhooksError.prototype)\n }\n}\n\n/**\n * Verify `X-Torque-Signature` (or raw hex) against HMAC-SHA256 of the **raw** webhook body.\n * Accepts `hex`, `sha256=<hex>`, or `v1=<hex>` prefix forms.\n */\nexport function verifyWebhookSignature(\n rawBody: string,\n signatureHeader: string | null,\n secret: string,\n): boolean {\n if (!signatureHeader || !secret) return false\n const expectedHex = createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex')\n const normalized = signatureHeader.trim().replace(/^(sha256|v1)=/i, '')\n try {\n const a = Buffer.from(normalized, 'hex')\n const b = Buffer.from(expectedHex, 'hex')\n if (a.length !== b.length) return false\n return timingSafeEqual(a, b)\n } catch {\n return false\n }\n}\n\n/** Checkout-compatible alias. */\nexport const verifyTorqueWebhookSignature = verifyWebhookSignature\n\nexport async function pushOrderUpdate(\n params: PushOrderUpdateParams,\n config: TorqueWebhooksConfig,\n): Promise<{ success: boolean; message?: string; timestamp?: string }> {\n if (!params.orderId?.trim()) {\n throw new TorqueWebhooksError('orderId is required', {\n code: 'VALIDATION_ERROR',\n statusCode: 400,\n })\n }\n if (!params.status) {\n throw new TorqueWebhooksError('status is required', {\n code: 'VALIDATION_ERROR',\n statusCode: 400,\n })\n }\n if (!config.webhookSecret?.trim()) {\n throw new TorqueWebhooksError('webhookSecret is required', {\n code: 'INVALID_CONFIG',\n statusCode: 400,\n })\n }\n\n const baseUrl = (config.baseUrl || 'https://app.torque.fi').replace(/\\/$/, '')\n const timeout = config.timeout ?? 30_000\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(`${baseUrl}/api/webhooks/order-update`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-order-webhook-secret': config.webhookSecret.trim(),\n },\n body: JSON.stringify({\n orderId: params.orderId,\n status: params.status,\n customerData: params.customerData,\n metadata: params.metadata,\n }),\n signal: controller.signal,\n })\n\n clearTimeout(timeoutId)\n const body = (await response.json().catch(() => ({}))) as {\n success?: boolean\n message?: string\n timestamp?: string\n error?: string\n details?: Record<string, unknown>\n }\n\n if (!response.ok) {\n throw new TorqueWebhooksError(body.message || `HTTP ${response.status}`, {\n code: typeof body.error === 'string' ? body.error : 'API_ERROR',\n statusCode: response.status,\n details: body.details,\n })\n }\n\n return {\n success: body.success ?? true,\n message: body.message,\n timestamp: body.timestamp,\n }\n } catch (error) {\n clearTimeout(timeoutId)\n if (error instanceof TorqueWebhooksError) throw error\n if (error instanceof Error && error.name === 'AbortError') {\n throw new TorqueWebhooksError('Request timeout', { code: 'TIMEOUT', statusCode: 408 })\n }\n throw new TorqueWebhooksError(error instanceof Error ? error.message : 'Request failed', {\n code: 'NETWORK_ERROR',\n statusCode: 500,\n })\n }\n}\n\nexport function createTorqueWebhooks(config: TorqueWebhooksConfig) {\n return {\n pushOrderUpdate: (params: PushOrderUpdateParams) => pushOrderUpdate(params, config),\n verifyWebhookSignature: (\n rawBody: string,\n signatureHeader: string | null,\n secret?: string,\n ) => verifyWebhookSignature(rawBody, signatureHeader, secret ?? config.webhookSecret),\n }\n}\n\nexport function createTorqueWebhooksFromEnv(overrides?: Partial<TorqueWebhooksConfig>) {\n const webhookSecret =\n process.env.TORQUE_WEBHOOK_SECRET ||\n process.env.ORDER_WEBHOOK_SECRET ||\n overrides?.webhookSecret\n if (!webhookSecret) {\n throw new TorqueWebhooksError(\n 'TORQUE_WEBHOOK_SECRET or ORDER_WEBHOOK_SECRET environment variable is required',\n { code: 'MISSING_ENV_VARS', statusCode: 400 },\n )\n }\n return createTorqueWebhooks({\n webhookSecret,\n baseUrl: process.env.TORQUE_BASE_URL || overrides?.baseUrl,\n timeout: overrides?.timeout,\n })\n}\n"],"names":["createHmac","timingSafeEqual"],"mappings":"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"}
|
package/dist/nextjs.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Next.js webhook route helpers for merchant apps.
|
|
3
|
+
* @requires next >= 13.0.0
|
|
4
|
+
*/
|
|
5
|
+
import type { NextRequest } from 'next/server';
|
|
6
|
+
import { NextResponse } from 'next/server';
|
|
7
|
+
import { type TorqueOutboundWebhookEvent } from './index';
|
|
8
|
+
export type { TorqueOutboundWebhookEvent as WebhookEvent };
|
|
9
|
+
export interface WebhookHandlerOptions {
|
|
10
|
+
secret?: string;
|
|
11
|
+
onOrderCreated?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void;
|
|
12
|
+
onOrderCompleted?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void;
|
|
13
|
+
onOrderFailed?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void;
|
|
14
|
+
onSubscriptionCreated?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void;
|
|
15
|
+
onSubscriptionCancelled?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Next.js App Router handler for inbound Torque outbound webhooks.
|
|
19
|
+
*/
|
|
20
|
+
export declare function handleWebhook(options?: WebhookHandlerOptions): (request: NextRequest) => Promise<NextResponse<{
|
|
21
|
+
error: string;
|
|
22
|
+
}> | NextResponse<{
|
|
23
|
+
received: boolean;
|
|
24
|
+
}>>;
|
|
25
|
+
export { verifyWebhookSignature, verifyTorqueWebhookSignature } from './index';
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { verifyWebhookSignature } from './index.esm.js';
|
|
3
|
+
export { verifyTorqueWebhookSignature } from './index.esm.js';
|
|
4
|
+
import 'crypto';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Next.js webhook route helpers for merchant apps.
|
|
8
|
+
* @requires next >= 13.0.0
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Next.js App Router handler for inbound Torque outbound webhooks.
|
|
12
|
+
*/
|
|
13
|
+
function handleWebhook(options = {}) {
|
|
14
|
+
return async (request) => {
|
|
15
|
+
try {
|
|
16
|
+
const rawBody = await request.text();
|
|
17
|
+
let event;
|
|
18
|
+
try {
|
|
19
|
+
event = JSON.parse(rawBody);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 });
|
|
23
|
+
}
|
|
24
|
+
if (options.secret) {
|
|
25
|
+
const signature = request.headers.get('x-torque-signature');
|
|
26
|
+
if (!verifyWebhookSignature(rawBody, signature, options.secret)) {
|
|
27
|
+
return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
switch (event.type) {
|
|
31
|
+
case 'order.created':
|
|
32
|
+
await options.onOrderCreated?.(event);
|
|
33
|
+
break;
|
|
34
|
+
case 'order.completed':
|
|
35
|
+
await options.onOrderCompleted?.(event);
|
|
36
|
+
break;
|
|
37
|
+
case 'order.failed':
|
|
38
|
+
await options.onOrderFailed?.(event);
|
|
39
|
+
break;
|
|
40
|
+
case 'subscription.created':
|
|
41
|
+
await options.onSubscriptionCreated?.(event);
|
|
42
|
+
break;
|
|
43
|
+
case 'subscription.cancelled':
|
|
44
|
+
await options.onSubscriptionCancelled?.(event);
|
|
45
|
+
break;
|
|
46
|
+
default:
|
|
47
|
+
console.warn('Unknown webhook event type:', event.type);
|
|
48
|
+
}
|
|
49
|
+
return NextResponse.json({ received: true });
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
console.error('Webhook handler error:', error);
|
|
53
|
+
return NextResponse.json({ error: 'Webhook processing failed' }, { status: 500 });
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { handleWebhook, verifyWebhookSignature };
|
|
59
|
+
//# sourceMappingURL=nextjs.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nextjs.esm.js","sources":["../src/nextjs.ts"],"sourcesContent":["/**\n * Next.js webhook route helpers for merchant apps.\n * @requires next >= 13.0.0\n */\n\nimport type { NextRequest } from 'next/server'\nimport { NextResponse } from 'next/server'\n\nimport {\n verifyWebhookSignature,\n type TorqueOutboundWebhookEvent,\n} from './index'\n\nexport type { TorqueOutboundWebhookEvent as WebhookEvent }\n\nexport interface WebhookHandlerOptions {\n secret?: string\n onOrderCreated?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void\n onOrderCompleted?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void\n onOrderFailed?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void\n onSubscriptionCreated?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void\n onSubscriptionCancelled?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void\n}\n\n/**\n * Next.js App Router handler for inbound Torque outbound webhooks.\n */\nexport function handleWebhook(options: WebhookHandlerOptions = {}) {\n return async (request: NextRequest) => {\n try {\n const rawBody = await request.text()\n let event: TorqueOutboundWebhookEvent\n try {\n event = JSON.parse(rawBody) as TorqueOutboundWebhookEvent\n } catch {\n return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 })\n }\n\n if (options.secret) {\n const signature = request.headers.get('x-torque-signature')\n if (!verifyWebhookSignature(rawBody, signature, options.secret)) {\n return NextResponse.json({ error: 'Invalid signature' }, { status: 401 })\n }\n }\n\n switch (event.type) {\n case 'order.created':\n await options.onOrderCreated?.(event)\n break\n case 'order.completed':\n await options.onOrderCompleted?.(event)\n break\n case 'order.failed':\n await options.onOrderFailed?.(event)\n break\n case 'subscription.created':\n await options.onSubscriptionCreated?.(event)\n break\n case 'subscription.cancelled':\n await options.onSubscriptionCancelled?.(event)\n break\n default:\n console.warn('Unknown webhook event type:', (event as { type?: string }).type)\n }\n\n return NextResponse.json({ received: true })\n } catch (error) {\n console.error('Webhook handler error:', error)\n return NextResponse.json({ error: 'Webhook processing failed' }, { status: 500 })\n }\n }\n}\n\nexport { verifyWebhookSignature, verifyTorqueWebhookSignature } from './index'\n"],"names":[],"mappings":";;;;;AAAA;;;AAGG;AAqBH;;AAEG;AACG,SAAU,aAAa,CAAC,OAAA,GAAiC,EAAE,EAAA;AAC/D,IAAA,OAAO,OAAO,OAAoB,KAAI;AACpC,QAAA,IAAI;AACF,YAAA,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE;AACpC,YAAA,IAAI,KAAiC;AACrC,YAAA,IAAI;AACF,gBAAA,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA+B;YAC3D;AAAE,YAAA,MAAM;AACN,gBAAA,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACtE;AAEA,YAAA,IAAI,OAAO,CAAC,MAAM,EAAE;gBAClB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;AAC3D,gBAAA,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE;AAC/D,oBAAA,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;gBAC3E;YACF;AAEA,YAAA,QAAQ,KAAK,CAAC,IAAI;AAChB,gBAAA,KAAK,eAAe;AAClB,oBAAA,MAAM,OAAO,CAAC,cAAc,GAAG,KAAK,CAAC;oBACrC;AACF,gBAAA,KAAK,iBAAiB;AACpB,oBAAA,MAAM,OAAO,CAAC,gBAAgB,GAAG,KAAK,CAAC;oBACvC;AACF,gBAAA,KAAK,cAAc;AACjB,oBAAA,MAAM,OAAO,CAAC,aAAa,GAAG,KAAK,CAAC;oBACpC;AACF,gBAAA,KAAK,sBAAsB;AACzB,oBAAA,MAAM,OAAO,CAAC,qBAAqB,GAAG,KAAK,CAAC;oBAC5C;AACF,gBAAA,KAAK,wBAAwB;AAC3B,oBAAA,MAAM,OAAO,CAAC,uBAAuB,GAAG,KAAK,CAAC;oBAC9C;AACF,gBAAA;oBACE,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAG,KAA2B,CAAC,IAAI,CAAC;;YAGlF,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC9C;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC;AAC9C,YAAA,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,2BAA2B,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QACnF;AACF,IAAA,CAAC;AACH;;;;"}
|
package/dist/nextjs.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var server = require('next/server');
|
|
4
|
+
var index = require('./index.js');
|
|
5
|
+
require('crypto');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Next.js webhook route helpers for merchant apps.
|
|
9
|
+
* @requires next >= 13.0.0
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Next.js App Router handler for inbound Torque outbound webhooks.
|
|
13
|
+
*/
|
|
14
|
+
function handleWebhook(options = {}) {
|
|
15
|
+
return async (request) => {
|
|
16
|
+
try {
|
|
17
|
+
const rawBody = await request.text();
|
|
18
|
+
let event;
|
|
19
|
+
try {
|
|
20
|
+
event = JSON.parse(rawBody);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return server.NextResponse.json({ error: 'Invalid JSON' }, { status: 400 });
|
|
24
|
+
}
|
|
25
|
+
if (options.secret) {
|
|
26
|
+
const signature = request.headers.get('x-torque-signature');
|
|
27
|
+
if (!index.verifyWebhookSignature(rawBody, signature, options.secret)) {
|
|
28
|
+
return server.NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
switch (event.type) {
|
|
32
|
+
case 'order.created':
|
|
33
|
+
await options.onOrderCreated?.(event);
|
|
34
|
+
break;
|
|
35
|
+
case 'order.completed':
|
|
36
|
+
await options.onOrderCompleted?.(event);
|
|
37
|
+
break;
|
|
38
|
+
case 'order.failed':
|
|
39
|
+
await options.onOrderFailed?.(event);
|
|
40
|
+
break;
|
|
41
|
+
case 'subscription.created':
|
|
42
|
+
await options.onSubscriptionCreated?.(event);
|
|
43
|
+
break;
|
|
44
|
+
case 'subscription.cancelled':
|
|
45
|
+
await options.onSubscriptionCancelled?.(event);
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
console.warn('Unknown webhook event type:', event.type);
|
|
49
|
+
}
|
|
50
|
+
return server.NextResponse.json({ received: true });
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error('Webhook handler error:', error);
|
|
54
|
+
return server.NextResponse.json({ error: 'Webhook processing failed' }, { status: 500 });
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
exports.verifyTorqueWebhookSignature = index.verifyTorqueWebhookSignature;
|
|
60
|
+
exports.verifyWebhookSignature = index.verifyWebhookSignature;
|
|
61
|
+
exports.handleWebhook = handleWebhook;
|
|
62
|
+
//# sourceMappingURL=nextjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nextjs.js","sources":["../src/nextjs.ts"],"sourcesContent":["/**\n * Next.js webhook route helpers for merchant apps.\n * @requires next >= 13.0.0\n */\n\nimport type { NextRequest } from 'next/server'\nimport { NextResponse } from 'next/server'\n\nimport {\n verifyWebhookSignature,\n type TorqueOutboundWebhookEvent,\n} from './index'\n\nexport type { TorqueOutboundWebhookEvent as WebhookEvent }\n\nexport interface WebhookHandlerOptions {\n secret?: string\n onOrderCreated?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void\n onOrderCompleted?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void\n onOrderFailed?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void\n onSubscriptionCreated?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void\n onSubscriptionCancelled?: (event: TorqueOutboundWebhookEvent) => Promise<void> | void\n}\n\n/**\n * Next.js App Router handler for inbound Torque outbound webhooks.\n */\nexport function handleWebhook(options: WebhookHandlerOptions = {}) {\n return async (request: NextRequest) => {\n try {\n const rawBody = await request.text()\n let event: TorqueOutboundWebhookEvent\n try {\n event = JSON.parse(rawBody) as TorqueOutboundWebhookEvent\n } catch {\n return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 })\n }\n\n if (options.secret) {\n const signature = request.headers.get('x-torque-signature')\n if (!verifyWebhookSignature(rawBody, signature, options.secret)) {\n return NextResponse.json({ error: 'Invalid signature' }, { status: 401 })\n }\n }\n\n switch (event.type) {\n case 'order.created':\n await options.onOrderCreated?.(event)\n break\n case 'order.completed':\n await options.onOrderCompleted?.(event)\n break\n case 'order.failed':\n await options.onOrderFailed?.(event)\n break\n case 'subscription.created':\n await options.onSubscriptionCreated?.(event)\n break\n case 'subscription.cancelled':\n await options.onSubscriptionCancelled?.(event)\n break\n default:\n console.warn('Unknown webhook event type:', (event as { type?: string }).type)\n }\n\n return NextResponse.json({ received: true })\n } catch (error) {\n console.error('Webhook handler error:', error)\n return NextResponse.json({ error: 'Webhook processing failed' }, { status: 500 })\n }\n }\n}\n\nexport { verifyWebhookSignature, verifyTorqueWebhookSignature } from './index'\n"],"names":["NextResponse","verifyWebhookSignature"],"mappings":";;;;;;AAAA;;;AAGG;AAqBH;;AAEG;AACG,SAAU,aAAa,CAAC,OAAA,GAAiC,EAAE,EAAA;AAC/D,IAAA,OAAO,OAAO,OAAoB,KAAI;AACpC,QAAA,IAAI;AACF,YAAA,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE;AACpC,YAAA,IAAI,KAAiC;AACrC,YAAA,IAAI;AACF,gBAAA,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA+B;YAC3D;AAAE,YAAA,MAAM;AACN,gBAAA,OAAOA,mBAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACtE;AAEA,YAAA,IAAI,OAAO,CAAC,MAAM,EAAE;gBAClB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;AAC3D,gBAAA,IAAI,CAACC,4BAAsB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE;AAC/D,oBAAA,OAAOD,mBAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;gBAC3E;YACF;AAEA,YAAA,QAAQ,KAAK,CAAC,IAAI;AAChB,gBAAA,KAAK,eAAe;AAClB,oBAAA,MAAM,OAAO,CAAC,cAAc,GAAG,KAAK,CAAC;oBACrC;AACF,gBAAA,KAAK,iBAAiB;AACpB,oBAAA,MAAM,OAAO,CAAC,gBAAgB,GAAG,KAAK,CAAC;oBACvC;AACF,gBAAA,KAAK,cAAc;AACjB,oBAAA,MAAM,OAAO,CAAC,aAAa,GAAG,KAAK,CAAC;oBACpC;AACF,gBAAA,KAAK,sBAAsB;AACzB,oBAAA,MAAM,OAAO,CAAC,qBAAqB,GAAG,KAAK,CAAC;oBAC5C;AACF,gBAAA,KAAK,wBAAwB;AAC3B,oBAAA,MAAM,OAAO,CAAC,uBAAuB,GAAG,KAAK,CAAC;oBAC9C;AACF,gBAAA;oBACE,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAG,KAA2B,CAAC,IAAI,CAAC;;YAGlF,OAAOA,mBAAY,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC9C;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC;AAC9C,YAAA,OAAOA,mBAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,2BAA2B,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QACnF;AACF,IAAA,CAAC;AACH;;;;;;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "torque-webhooks",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Torque webhook helpers — verify inbound signatures and push order status updates",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.esm.js",
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./nextjs": {
|
|
15
|
+
"import": "./dist/nextjs.esm.js",
|
|
16
|
+
"require": "./dist/nextjs.js",
|
|
17
|
+
"types": "./dist/nextjs.d.ts"
|
|
18
|
+
},
|
|
19
|
+
"./package.json": "./package.json"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "rollup -c",
|
|
28
|
+
"dev": "rollup -c -w",
|
|
29
|
+
"clean": "rimraf dist",
|
|
30
|
+
"prepublishOnly": "yarn clean && yarn build"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"torque",
|
|
34
|
+
"webhooks",
|
|
35
|
+
"merchant",
|
|
36
|
+
"checkout",
|
|
37
|
+
"ecommerce"
|
|
38
|
+
],
|
|
39
|
+
"author": "Torque <hello@torque.fi>",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"homepage": "https://torque.fi",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/torque-fi/torque_webapp.git",
|
|
45
|
+
"directory": "packages/torque-webhooks"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@rollup/plugin-typescript": "^12.1.4",
|
|
49
|
+
"@types/node": "^20.0.0",
|
|
50
|
+
"rimraf": "^5.0.0",
|
|
51
|
+
"rollup": "^4.0.0",
|
|
52
|
+
"typescript": "^5.0.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"next": ">=13.0.0"
|
|
56
|
+
},
|
|
57
|
+
"peerDependenciesMeta": {
|
|
58
|
+
"next": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=16.0.0"
|
|
64
|
+
}
|
|
65
|
+
}
|