@feelflow/ffid-sdk 0.1.0 → 0.2.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.
@@ -0,0 +1,298 @@
1
+ /**
2
+ * FFID Webhook SDK Constants
3
+ *
4
+ * Header names, signature version, and default configuration values.
5
+ * These must match the server-side constants in src/lib/webhooks/types.ts.
6
+ */
7
+ /** HTTP header for webhook signature: "t={timestamp},v1={hex_hmac}" */
8
+ declare const FFID_WEBHOOK_SIGNATURE_HEADER = "X-FFID-Signature";
9
+ /** HTTP header for webhook timestamp (Unix seconds) */
10
+ declare const FFID_WEBHOOK_TIMESTAMP_HEADER = "X-FFID-Timestamp";
11
+ /** HTTP header for webhook event ID (UUID) */
12
+ declare const FFID_WEBHOOK_EVENT_ID_HEADER = "X-FFID-Event-ID";
13
+ /** Signature algorithm version prefix */
14
+ declare const FFID_WEBHOOK_SIGNATURE_VERSION = "v1";
15
+ /** Default timestamp tolerance in seconds (5 minutes) */
16
+ declare const DEFAULT_TOLERANCE_SECONDS = 300;
17
+
18
+ /**
19
+ * FFID Webhook SDK Error Classes
20
+ *
21
+ * Structured errors for signature verification failures.
22
+ */
23
+ /** Base error for all webhook SDK errors */
24
+ declare class FFIDWebhookError extends Error {
25
+ constructor(message: string);
26
+ }
27
+ /** Thrown when the webhook signature does not match */
28
+ declare class FFIDWebhookSignatureError extends FFIDWebhookError {
29
+ constructor(message?: string);
30
+ }
31
+ /** Thrown when the webhook timestamp is outside the tolerance window */
32
+ declare class FFIDWebhookTimestampError extends FFIDWebhookError {
33
+ constructor(message?: string);
34
+ }
35
+ /** Thrown when the webhook payload cannot be parsed as JSON */
36
+ declare class FFIDWebhookPayloadError extends FFIDWebhookError {
37
+ constructor(message?: string);
38
+ }
39
+
40
+ /**
41
+ * FFID Webhook SDK Type Definitions
42
+ *
43
+ * Types for receiving and verifying FeelFlow ID webhook events.
44
+ * Used by external services to handle real-time event notifications.
45
+ */
46
+ /** All supported webhook event types */
47
+ type FFIDWebhookEventType = 'subscription.created' | 'subscription.updated' | 'subscription.canceled' | 'subscription.trial_ending' | 'subscription.payment_failed' | 'user.created' | 'user.updated' | 'user.deleted' | 'user.deletion_requested' | 'organization.created' | 'organization.updated' | 'organization.member.added' | 'organization.member.removed' | 'organization.member.role_changed' | 'legal.document.updated' | 'legal.agreement.required' | 'system.maintenance.scheduled' | 'system.maintenance.started' | 'system.maintenance.completed' | 'announcement.published' | 'test.ping';
48
+ interface FFIDSubscriptionCreatedPayload {
49
+ subscriptionId: string;
50
+ organizationId?: string;
51
+ plan?: string;
52
+ status?: string;
53
+ }
54
+ interface FFIDSubscriptionUpdatedPayload {
55
+ subscriptionId: string;
56
+ organizationId?: string;
57
+ plan?: string;
58
+ previousPlan?: string;
59
+ status?: string;
60
+ }
61
+ interface FFIDSubscriptionCanceledPayload {
62
+ subscriptionId: string;
63
+ organizationId?: string;
64
+ reason?: string;
65
+ cancelAt?: string;
66
+ }
67
+ interface FFIDSubscriptionTrialEndingPayload {
68
+ subscriptionId: string;
69
+ organizationId?: string;
70
+ trialEndDate: string;
71
+ }
72
+ interface FFIDSubscriptionPaymentFailedPayload {
73
+ subscriptionId: string;
74
+ organizationId?: string;
75
+ failureReason?: string;
76
+ attemptCount?: number;
77
+ }
78
+ interface FFIDUserCreatedPayload {
79
+ userId: string;
80
+ email?: string;
81
+ displayName?: string;
82
+ }
83
+ interface FFIDUserUpdatedPayload {
84
+ userId: string;
85
+ displayName?: string;
86
+ updatedFields?: string[];
87
+ }
88
+ interface FFIDUserDeletedPayload {
89
+ userId: string;
90
+ }
91
+ interface FFIDUserDeletionRequestedPayload {
92
+ userId: string;
93
+ requestId?: string;
94
+ scheduledDeletionDate?: string;
95
+ }
96
+ interface FFIDOrganizationCreatedPayload {
97
+ organizationId: string;
98
+ name?: string;
99
+ slug?: string;
100
+ }
101
+ interface FFIDOrganizationUpdatedPayload {
102
+ organizationId: string;
103
+ slug?: string;
104
+ updatedFields?: string[];
105
+ }
106
+ interface FFIDOrganizationMemberAddedPayload {
107
+ organizationId: string;
108
+ userId: string;
109
+ role?: string;
110
+ }
111
+ interface FFIDOrganizationMemberRemovedPayload {
112
+ organizationId: string;
113
+ userId: string;
114
+ }
115
+ interface FFIDOrganizationMemberRoleChangedPayload {
116
+ organizationId: string;
117
+ userId: string;
118
+ previousRole?: string;
119
+ newRole?: string;
120
+ }
121
+ interface FFIDLegalDocumentUpdatedPayload {
122
+ documentId: string;
123
+ documentType?: string;
124
+ version?: string;
125
+ }
126
+ interface FFIDLegalAgreementRequiredPayload {
127
+ documentId: string;
128
+ documentType?: string;
129
+ documentTitle?: string;
130
+ }
131
+ interface FFIDSystemMaintenancePayload {
132
+ maintenanceId?: string;
133
+ scheduledAt?: string;
134
+ estimatedDuration?: string;
135
+ description?: string;
136
+ }
137
+ interface FFIDAnnouncementPublishedPayload {
138
+ announcementId: string;
139
+ type: string;
140
+ title: string;
141
+ content: string;
142
+ scheduledAt?: string | null;
143
+ durationMinutes?: number | null;
144
+ affectedServices?: string[];
145
+ channels?: string[];
146
+ publishedAt?: string | null;
147
+ }
148
+ interface FFIDTestPingPayload {
149
+ message?: string;
150
+ }
151
+ /** Maps event type strings to their typed payloads */
152
+ interface FFIDWebhookEventMap {
153
+ 'subscription.created': FFIDSubscriptionCreatedPayload;
154
+ 'subscription.updated': FFIDSubscriptionUpdatedPayload;
155
+ 'subscription.canceled': FFIDSubscriptionCanceledPayload;
156
+ 'subscription.trial_ending': FFIDSubscriptionTrialEndingPayload;
157
+ 'subscription.payment_failed': FFIDSubscriptionPaymentFailedPayload;
158
+ 'user.created': FFIDUserCreatedPayload;
159
+ 'user.updated': FFIDUserUpdatedPayload;
160
+ 'user.deleted': FFIDUserDeletedPayload;
161
+ 'user.deletion_requested': FFIDUserDeletionRequestedPayload;
162
+ 'organization.created': FFIDOrganizationCreatedPayload;
163
+ 'organization.updated': FFIDOrganizationUpdatedPayload;
164
+ 'organization.member.added': FFIDOrganizationMemberAddedPayload;
165
+ 'organization.member.removed': FFIDOrganizationMemberRemovedPayload;
166
+ 'organization.member.role_changed': FFIDOrganizationMemberRoleChangedPayload;
167
+ 'legal.document.updated': FFIDLegalDocumentUpdatedPayload;
168
+ 'legal.agreement.required': FFIDLegalAgreementRequiredPayload;
169
+ 'system.maintenance.scheduled': FFIDSystemMaintenancePayload;
170
+ 'system.maintenance.started': FFIDSystemMaintenancePayload;
171
+ 'system.maintenance.completed': FFIDSystemMaintenancePayload;
172
+ 'announcement.published': FFIDAnnouncementPublishedPayload;
173
+ 'test.ping': FFIDTestPingPayload;
174
+ }
175
+ /** A webhook event envelope with typed payload */
176
+ interface FFIDWebhookEvent<T extends FFIDWebhookEventType = FFIDWebhookEventType> {
177
+ id: string;
178
+ type: T;
179
+ createdAt: string;
180
+ data: T extends keyof FFIDWebhookEventMap ? FFIDWebhookEventMap[T] : Record<string, unknown>;
181
+ }
182
+ /** Configuration for the webhook handler */
183
+ interface FFIDWebhookHandlerConfig {
184
+ /** Webhook endpoint secret used for signature verification */
185
+ secret: string;
186
+ /** Maximum age of webhook timestamp in seconds (default: 300) */
187
+ toleranceSeconds?: number;
188
+ /** Custom logger */
189
+ logger?: FFIDWebhookLogger;
190
+ }
191
+ /** Logger interface for webhook SDK */
192
+ interface FFIDWebhookLogger {
193
+ debug: (...args: unknown[]) => void;
194
+ info: (...args: unknown[]) => void;
195
+ warn: (...args: unknown[]) => void;
196
+ error: (...args: unknown[]) => void;
197
+ }
198
+ /** Event handler callback type */
199
+ type FFIDWebhookEventHandler<T extends FFIDWebhookEventType = FFIDWebhookEventType> = (event: FFIDWebhookEvent<T>) => void | Promise<void>;
200
+
201
+ /**
202
+ * FFID Webhook Signature Verification
203
+ *
204
+ * HMAC-SHA256 signature parsing and verification for incoming webhook events.
205
+ * Compatible with the server-side signing implementation (src/lib/webhooks/signing.ts).
206
+ *
207
+ * Signature format: t={timestamp},v1={hex_hmac}
208
+ * Signed content: {timestamp}.{body}
209
+ */
210
+
211
+ /**
212
+ * Parse a signature header into timestamp and signature components.
213
+ *
214
+ * @param header - Raw signature header value (e.g. "t=1234567890,v1=abcdef...")
215
+ * @returns Parsed components, or null if the header is malformed
216
+ */
217
+ declare function parseSignatureHeader(header: string): {
218
+ timestamp: number;
219
+ signature: string;
220
+ } | null;
221
+ /**
222
+ * Compute HMAC-SHA256 for a webhook payload.
223
+ *
224
+ * @param secret - Webhook endpoint secret
225
+ * @param timestamp - Unix timestamp in seconds
226
+ * @param body - Raw request body string
227
+ * @returns Hex-encoded HMAC-SHA256 signature
228
+ */
229
+ declare function computeSignature(secret: string, timestamp: number, body: string): string;
230
+ /**
231
+ * Verify a webhook signature and timestamp, then parse the event body.
232
+ *
233
+ * @param rawBody - Raw request body string
234
+ * @param signatureHeader - Value of the X-FFID-Signature header
235
+ * @param secret - Webhook endpoint secret
236
+ * @param toleranceSeconds - Maximum age of timestamp (default: 300s)
237
+ * @returns Parsed webhook event
238
+ * @throws {FFIDWebhookSignatureError} If the header is malformed or signature is invalid
239
+ * @throws {FFIDWebhookTimestampError} If the timestamp is outside the tolerance window
240
+ */
241
+ declare function verifyWebhookSignature(rawBody: string, signatureHeader: string, secret: string, toleranceSeconds?: number): FFIDWebhookEvent;
242
+
243
+ /**
244
+ * FFID Webhook Handler
245
+ *
246
+ * Factory function for creating a webhook event handler with typed event
247
+ * registration, signature verification, and framework integrations.
248
+ *
249
+ * @example
250
+ * ```typescript
251
+ * import { createFFIDWebhookHandler } from '@feelflow/ffid-sdk/webhooks'
252
+ *
253
+ * const webhooks = createFFIDWebhookHandler({
254
+ * secret: process.env.FFID_WEBHOOK_SECRET!,
255
+ * })
256
+ *
257
+ * webhooks.on('subscription.created', (event) => {
258
+ * console.log('New subscription:', event.data.subscriptionId)
259
+ * })
260
+ *
261
+ * // Next.js App Router
262
+ * export const POST = webhooks.nextHandler()
263
+ * ```
264
+ */
265
+
266
+ /**
267
+ * Creates an FFID webhook event handler.
268
+ *
269
+ * @param config - Handler configuration (secret is required)
270
+ * @returns Webhook handler instance with event registration and framework helpers
271
+ */
272
+ declare function createFFIDWebhookHandler(config: FFIDWebhookHandlerConfig): {
273
+ /** Register a handler for a specific event type */
274
+ on: <T extends FFIDWebhookEventType>(eventType: T, handler: FFIDWebhookEventHandler<T>) => void;
275
+ /** Register a handler that receives all events */
276
+ onAll: (handler: FFIDWebhookEventHandler) => void;
277
+ /** Unregister a handler for a specific event type */
278
+ off: <T extends FFIDWebhookEventType>(eventType: T, handler: FFIDWebhookEventHandler<T>) => void;
279
+ /** Verify signature and dispatch event (core method) */
280
+ handleEvent: (rawBody: string, signatureHeader: string) => Promise<FFIDWebhookEvent>;
281
+ /** Process webhook from raw body + headers object */
282
+ handleRaw: (rawBody: string, headers: Record<string, string | undefined>) => Promise<FFIDWebhookEvent>;
283
+ /** Express/Connect middleware */
284
+ expressMiddleware: () => (req: {
285
+ body: unknown;
286
+ headers: Record<string, string | string[] | undefined>;
287
+ }, res: {
288
+ status: (code: number) => {
289
+ json: (body: unknown) => void;
290
+ };
291
+ }, next: () => void) => void;
292
+ /** Next.js App Router route handler */
293
+ nextHandler: () => (request: Request) => Promise<Response>;
294
+ };
295
+ /** Type of the FFID Webhook handler */
296
+ type FFIDWebhookHandler = ReturnType<typeof createFFIDWebhookHandler>;
297
+
298
+ export { DEFAULT_TOLERANCE_SECONDS, type FFIDLegalAgreementRequiredPayload, type FFIDLegalDocumentUpdatedPayload, type FFIDOrganizationCreatedPayload, type FFIDOrganizationMemberAddedPayload, type FFIDOrganizationMemberRemovedPayload, type FFIDOrganizationMemberRoleChangedPayload, type FFIDOrganizationUpdatedPayload, type FFIDSubscriptionCanceledPayload, type FFIDSubscriptionCreatedPayload, type FFIDSubscriptionPaymentFailedPayload, type FFIDSubscriptionTrialEndingPayload, type FFIDSubscriptionUpdatedPayload, type FFIDSystemMaintenancePayload, type FFIDTestPingPayload, type FFIDUserCreatedPayload, type FFIDUserDeletedPayload, type FFIDUserDeletionRequestedPayload, type FFIDUserUpdatedPayload, FFIDWebhookError, type FFIDWebhookEvent, type FFIDWebhookEventHandler, type FFIDWebhookEventMap, type FFIDWebhookEventType, type FFIDWebhookHandler, type FFIDWebhookHandlerConfig, type FFIDWebhookLogger, FFIDWebhookPayloadError, FFIDWebhookSignatureError, FFIDWebhookTimestampError, FFID_WEBHOOK_EVENT_ID_HEADER, FFID_WEBHOOK_SIGNATURE_HEADER, FFID_WEBHOOK_SIGNATURE_VERSION, FFID_WEBHOOK_TIMESTAMP_HEADER, computeSignature, createFFIDWebhookHandler, parseSignatureHeader, verifyWebhookSignature };
@@ -0,0 +1,298 @@
1
+ /**
2
+ * FFID Webhook SDK Constants
3
+ *
4
+ * Header names, signature version, and default configuration values.
5
+ * These must match the server-side constants in src/lib/webhooks/types.ts.
6
+ */
7
+ /** HTTP header for webhook signature: "t={timestamp},v1={hex_hmac}" */
8
+ declare const FFID_WEBHOOK_SIGNATURE_HEADER = "X-FFID-Signature";
9
+ /** HTTP header for webhook timestamp (Unix seconds) */
10
+ declare const FFID_WEBHOOK_TIMESTAMP_HEADER = "X-FFID-Timestamp";
11
+ /** HTTP header for webhook event ID (UUID) */
12
+ declare const FFID_WEBHOOK_EVENT_ID_HEADER = "X-FFID-Event-ID";
13
+ /** Signature algorithm version prefix */
14
+ declare const FFID_WEBHOOK_SIGNATURE_VERSION = "v1";
15
+ /** Default timestamp tolerance in seconds (5 minutes) */
16
+ declare const DEFAULT_TOLERANCE_SECONDS = 300;
17
+
18
+ /**
19
+ * FFID Webhook SDK Error Classes
20
+ *
21
+ * Structured errors for signature verification failures.
22
+ */
23
+ /** Base error for all webhook SDK errors */
24
+ declare class FFIDWebhookError extends Error {
25
+ constructor(message: string);
26
+ }
27
+ /** Thrown when the webhook signature does not match */
28
+ declare class FFIDWebhookSignatureError extends FFIDWebhookError {
29
+ constructor(message?: string);
30
+ }
31
+ /** Thrown when the webhook timestamp is outside the tolerance window */
32
+ declare class FFIDWebhookTimestampError extends FFIDWebhookError {
33
+ constructor(message?: string);
34
+ }
35
+ /** Thrown when the webhook payload cannot be parsed as JSON */
36
+ declare class FFIDWebhookPayloadError extends FFIDWebhookError {
37
+ constructor(message?: string);
38
+ }
39
+
40
+ /**
41
+ * FFID Webhook SDK Type Definitions
42
+ *
43
+ * Types for receiving and verifying FeelFlow ID webhook events.
44
+ * Used by external services to handle real-time event notifications.
45
+ */
46
+ /** All supported webhook event types */
47
+ type FFIDWebhookEventType = 'subscription.created' | 'subscription.updated' | 'subscription.canceled' | 'subscription.trial_ending' | 'subscription.payment_failed' | 'user.created' | 'user.updated' | 'user.deleted' | 'user.deletion_requested' | 'organization.created' | 'organization.updated' | 'organization.member.added' | 'organization.member.removed' | 'organization.member.role_changed' | 'legal.document.updated' | 'legal.agreement.required' | 'system.maintenance.scheduled' | 'system.maintenance.started' | 'system.maintenance.completed' | 'announcement.published' | 'test.ping';
48
+ interface FFIDSubscriptionCreatedPayload {
49
+ subscriptionId: string;
50
+ organizationId?: string;
51
+ plan?: string;
52
+ status?: string;
53
+ }
54
+ interface FFIDSubscriptionUpdatedPayload {
55
+ subscriptionId: string;
56
+ organizationId?: string;
57
+ plan?: string;
58
+ previousPlan?: string;
59
+ status?: string;
60
+ }
61
+ interface FFIDSubscriptionCanceledPayload {
62
+ subscriptionId: string;
63
+ organizationId?: string;
64
+ reason?: string;
65
+ cancelAt?: string;
66
+ }
67
+ interface FFIDSubscriptionTrialEndingPayload {
68
+ subscriptionId: string;
69
+ organizationId?: string;
70
+ trialEndDate: string;
71
+ }
72
+ interface FFIDSubscriptionPaymentFailedPayload {
73
+ subscriptionId: string;
74
+ organizationId?: string;
75
+ failureReason?: string;
76
+ attemptCount?: number;
77
+ }
78
+ interface FFIDUserCreatedPayload {
79
+ userId: string;
80
+ email?: string;
81
+ displayName?: string;
82
+ }
83
+ interface FFIDUserUpdatedPayload {
84
+ userId: string;
85
+ displayName?: string;
86
+ updatedFields?: string[];
87
+ }
88
+ interface FFIDUserDeletedPayload {
89
+ userId: string;
90
+ }
91
+ interface FFIDUserDeletionRequestedPayload {
92
+ userId: string;
93
+ requestId?: string;
94
+ scheduledDeletionDate?: string;
95
+ }
96
+ interface FFIDOrganizationCreatedPayload {
97
+ organizationId: string;
98
+ name?: string;
99
+ slug?: string;
100
+ }
101
+ interface FFIDOrganizationUpdatedPayload {
102
+ organizationId: string;
103
+ slug?: string;
104
+ updatedFields?: string[];
105
+ }
106
+ interface FFIDOrganizationMemberAddedPayload {
107
+ organizationId: string;
108
+ userId: string;
109
+ role?: string;
110
+ }
111
+ interface FFIDOrganizationMemberRemovedPayload {
112
+ organizationId: string;
113
+ userId: string;
114
+ }
115
+ interface FFIDOrganizationMemberRoleChangedPayload {
116
+ organizationId: string;
117
+ userId: string;
118
+ previousRole?: string;
119
+ newRole?: string;
120
+ }
121
+ interface FFIDLegalDocumentUpdatedPayload {
122
+ documentId: string;
123
+ documentType?: string;
124
+ version?: string;
125
+ }
126
+ interface FFIDLegalAgreementRequiredPayload {
127
+ documentId: string;
128
+ documentType?: string;
129
+ documentTitle?: string;
130
+ }
131
+ interface FFIDSystemMaintenancePayload {
132
+ maintenanceId?: string;
133
+ scheduledAt?: string;
134
+ estimatedDuration?: string;
135
+ description?: string;
136
+ }
137
+ interface FFIDAnnouncementPublishedPayload {
138
+ announcementId: string;
139
+ type: string;
140
+ title: string;
141
+ content: string;
142
+ scheduledAt?: string | null;
143
+ durationMinutes?: number | null;
144
+ affectedServices?: string[];
145
+ channels?: string[];
146
+ publishedAt?: string | null;
147
+ }
148
+ interface FFIDTestPingPayload {
149
+ message?: string;
150
+ }
151
+ /** Maps event type strings to their typed payloads */
152
+ interface FFIDWebhookEventMap {
153
+ 'subscription.created': FFIDSubscriptionCreatedPayload;
154
+ 'subscription.updated': FFIDSubscriptionUpdatedPayload;
155
+ 'subscription.canceled': FFIDSubscriptionCanceledPayload;
156
+ 'subscription.trial_ending': FFIDSubscriptionTrialEndingPayload;
157
+ 'subscription.payment_failed': FFIDSubscriptionPaymentFailedPayload;
158
+ 'user.created': FFIDUserCreatedPayload;
159
+ 'user.updated': FFIDUserUpdatedPayload;
160
+ 'user.deleted': FFIDUserDeletedPayload;
161
+ 'user.deletion_requested': FFIDUserDeletionRequestedPayload;
162
+ 'organization.created': FFIDOrganizationCreatedPayload;
163
+ 'organization.updated': FFIDOrganizationUpdatedPayload;
164
+ 'organization.member.added': FFIDOrganizationMemberAddedPayload;
165
+ 'organization.member.removed': FFIDOrganizationMemberRemovedPayload;
166
+ 'organization.member.role_changed': FFIDOrganizationMemberRoleChangedPayload;
167
+ 'legal.document.updated': FFIDLegalDocumentUpdatedPayload;
168
+ 'legal.agreement.required': FFIDLegalAgreementRequiredPayload;
169
+ 'system.maintenance.scheduled': FFIDSystemMaintenancePayload;
170
+ 'system.maintenance.started': FFIDSystemMaintenancePayload;
171
+ 'system.maintenance.completed': FFIDSystemMaintenancePayload;
172
+ 'announcement.published': FFIDAnnouncementPublishedPayload;
173
+ 'test.ping': FFIDTestPingPayload;
174
+ }
175
+ /** A webhook event envelope with typed payload */
176
+ interface FFIDWebhookEvent<T extends FFIDWebhookEventType = FFIDWebhookEventType> {
177
+ id: string;
178
+ type: T;
179
+ createdAt: string;
180
+ data: T extends keyof FFIDWebhookEventMap ? FFIDWebhookEventMap[T] : Record<string, unknown>;
181
+ }
182
+ /** Configuration for the webhook handler */
183
+ interface FFIDWebhookHandlerConfig {
184
+ /** Webhook endpoint secret used for signature verification */
185
+ secret: string;
186
+ /** Maximum age of webhook timestamp in seconds (default: 300) */
187
+ toleranceSeconds?: number;
188
+ /** Custom logger */
189
+ logger?: FFIDWebhookLogger;
190
+ }
191
+ /** Logger interface for webhook SDK */
192
+ interface FFIDWebhookLogger {
193
+ debug: (...args: unknown[]) => void;
194
+ info: (...args: unknown[]) => void;
195
+ warn: (...args: unknown[]) => void;
196
+ error: (...args: unknown[]) => void;
197
+ }
198
+ /** Event handler callback type */
199
+ type FFIDWebhookEventHandler<T extends FFIDWebhookEventType = FFIDWebhookEventType> = (event: FFIDWebhookEvent<T>) => void | Promise<void>;
200
+
201
+ /**
202
+ * FFID Webhook Signature Verification
203
+ *
204
+ * HMAC-SHA256 signature parsing and verification for incoming webhook events.
205
+ * Compatible with the server-side signing implementation (src/lib/webhooks/signing.ts).
206
+ *
207
+ * Signature format: t={timestamp},v1={hex_hmac}
208
+ * Signed content: {timestamp}.{body}
209
+ */
210
+
211
+ /**
212
+ * Parse a signature header into timestamp and signature components.
213
+ *
214
+ * @param header - Raw signature header value (e.g. "t=1234567890,v1=abcdef...")
215
+ * @returns Parsed components, or null if the header is malformed
216
+ */
217
+ declare function parseSignatureHeader(header: string): {
218
+ timestamp: number;
219
+ signature: string;
220
+ } | null;
221
+ /**
222
+ * Compute HMAC-SHA256 for a webhook payload.
223
+ *
224
+ * @param secret - Webhook endpoint secret
225
+ * @param timestamp - Unix timestamp in seconds
226
+ * @param body - Raw request body string
227
+ * @returns Hex-encoded HMAC-SHA256 signature
228
+ */
229
+ declare function computeSignature(secret: string, timestamp: number, body: string): string;
230
+ /**
231
+ * Verify a webhook signature and timestamp, then parse the event body.
232
+ *
233
+ * @param rawBody - Raw request body string
234
+ * @param signatureHeader - Value of the X-FFID-Signature header
235
+ * @param secret - Webhook endpoint secret
236
+ * @param toleranceSeconds - Maximum age of timestamp (default: 300s)
237
+ * @returns Parsed webhook event
238
+ * @throws {FFIDWebhookSignatureError} If the header is malformed or signature is invalid
239
+ * @throws {FFIDWebhookTimestampError} If the timestamp is outside the tolerance window
240
+ */
241
+ declare function verifyWebhookSignature(rawBody: string, signatureHeader: string, secret: string, toleranceSeconds?: number): FFIDWebhookEvent;
242
+
243
+ /**
244
+ * FFID Webhook Handler
245
+ *
246
+ * Factory function for creating a webhook event handler with typed event
247
+ * registration, signature verification, and framework integrations.
248
+ *
249
+ * @example
250
+ * ```typescript
251
+ * import { createFFIDWebhookHandler } from '@feelflow/ffid-sdk/webhooks'
252
+ *
253
+ * const webhooks = createFFIDWebhookHandler({
254
+ * secret: process.env.FFID_WEBHOOK_SECRET!,
255
+ * })
256
+ *
257
+ * webhooks.on('subscription.created', (event) => {
258
+ * console.log('New subscription:', event.data.subscriptionId)
259
+ * })
260
+ *
261
+ * // Next.js App Router
262
+ * export const POST = webhooks.nextHandler()
263
+ * ```
264
+ */
265
+
266
+ /**
267
+ * Creates an FFID webhook event handler.
268
+ *
269
+ * @param config - Handler configuration (secret is required)
270
+ * @returns Webhook handler instance with event registration and framework helpers
271
+ */
272
+ declare function createFFIDWebhookHandler(config: FFIDWebhookHandlerConfig): {
273
+ /** Register a handler for a specific event type */
274
+ on: <T extends FFIDWebhookEventType>(eventType: T, handler: FFIDWebhookEventHandler<T>) => void;
275
+ /** Register a handler that receives all events */
276
+ onAll: (handler: FFIDWebhookEventHandler) => void;
277
+ /** Unregister a handler for a specific event type */
278
+ off: <T extends FFIDWebhookEventType>(eventType: T, handler: FFIDWebhookEventHandler<T>) => void;
279
+ /** Verify signature and dispatch event (core method) */
280
+ handleEvent: (rawBody: string, signatureHeader: string) => Promise<FFIDWebhookEvent>;
281
+ /** Process webhook from raw body + headers object */
282
+ handleRaw: (rawBody: string, headers: Record<string, string | undefined>) => Promise<FFIDWebhookEvent>;
283
+ /** Express/Connect middleware */
284
+ expressMiddleware: () => (req: {
285
+ body: unknown;
286
+ headers: Record<string, string | string[] | undefined>;
287
+ }, res: {
288
+ status: (code: number) => {
289
+ json: (body: unknown) => void;
290
+ };
291
+ }, next: () => void) => void;
292
+ /** Next.js App Router route handler */
293
+ nextHandler: () => (request: Request) => Promise<Response>;
294
+ };
295
+ /** Type of the FFID Webhook handler */
296
+ type FFIDWebhookHandler = ReturnType<typeof createFFIDWebhookHandler>;
297
+
298
+ export { DEFAULT_TOLERANCE_SECONDS, type FFIDLegalAgreementRequiredPayload, type FFIDLegalDocumentUpdatedPayload, type FFIDOrganizationCreatedPayload, type FFIDOrganizationMemberAddedPayload, type FFIDOrganizationMemberRemovedPayload, type FFIDOrganizationMemberRoleChangedPayload, type FFIDOrganizationUpdatedPayload, type FFIDSubscriptionCanceledPayload, type FFIDSubscriptionCreatedPayload, type FFIDSubscriptionPaymentFailedPayload, type FFIDSubscriptionTrialEndingPayload, type FFIDSubscriptionUpdatedPayload, type FFIDSystemMaintenancePayload, type FFIDTestPingPayload, type FFIDUserCreatedPayload, type FFIDUserDeletedPayload, type FFIDUserDeletionRequestedPayload, type FFIDUserUpdatedPayload, FFIDWebhookError, type FFIDWebhookEvent, type FFIDWebhookEventHandler, type FFIDWebhookEventMap, type FFIDWebhookEventType, type FFIDWebhookHandler, type FFIDWebhookHandlerConfig, type FFIDWebhookLogger, FFIDWebhookPayloadError, FFIDWebhookSignatureError, FFIDWebhookTimestampError, FFID_WEBHOOK_EVENT_ID_HEADER, FFID_WEBHOOK_SIGNATURE_HEADER, FFID_WEBHOOK_SIGNATURE_VERSION, FFID_WEBHOOK_TIMESTAMP_HEADER, computeSignature, createFFIDWebhookHandler, parseSignatureHeader, verifyWebhookSignature };