@usequota/nextjs 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/README.md +462 -0
- package/dist/chunk-BMI3VFWV.mjs +120 -0
- package/dist/chunk-RSPDHXC2.mjs +119 -0
- package/dist/chunk-SJ3X4KTV.mjs +117 -0
- package/dist/chunk-ZF7WJBQC.mjs +114 -0
- package/dist/errors-CmNx3kSz.d.mts +109 -0
- package/dist/errors-CmNx3kSz.d.ts +109 -0
- package/dist/errors-DVurmYT7.d.mts +109 -0
- package/dist/errors-DVurmYT7.d.ts +109 -0
- package/dist/index.d.mts +585 -0
- package/dist/index.d.ts +585 -0
- package/dist/index.js +1079 -0
- package/dist/index.mjs +968 -0
- package/dist/server.d.mts +477 -0
- package/dist/server.d.ts +477 -0
- package/dist/server.js +1068 -0
- package/dist/server.mjs +916 -0
- package/dist/styles.css +439 -0
- package/package.json +69 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import * as react from 'react';
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
import { QuotaUser } from '@usequota/types';
|
|
6
|
+
export { ChatCompletionRequest, ChatCompletionResponse, ChatMessage, CreditPackage, QuotaError as QuotaErrorResponse, QuotaMetadata, QuotaSession, QuotaUser, Tool, ToolCall } from '@usequota/types';
|
|
7
|
+
export { Q as QuotaError, a as QuotaInsufficientCreditsError, b as QuotaNotConnectedError, d as QuotaRateLimitError, c as QuotaTokenExpiredError } from './errors-CmNx3kSz.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @usequota/nextjs - Next.js middleware for OAuth callback handling
|
|
11
|
+
*
|
|
12
|
+
* This middleware handles the OAuth callback route and manages token storage.
|
|
13
|
+
* For client-side storage, tokens are stored in httpOnly cookies.
|
|
14
|
+
* For hosted storage, the link is established server-side via external_user_id.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
interface QuotaConfig {
|
|
18
|
+
/**
|
|
19
|
+
* OAuth client ID from Quota dashboard
|
|
20
|
+
*/
|
|
21
|
+
clientId: string;
|
|
22
|
+
/**
|
|
23
|
+
* OAuth client secret (keep this secure, server-side only)
|
|
24
|
+
*/
|
|
25
|
+
clientSecret: string;
|
|
26
|
+
/**
|
|
27
|
+
* Quota API base URL
|
|
28
|
+
* @default 'https://api.usequota.app'
|
|
29
|
+
*/
|
|
30
|
+
baseUrl?: string;
|
|
31
|
+
/**
|
|
32
|
+
* OAuth callback path
|
|
33
|
+
* @default '/api/quota/callback'
|
|
34
|
+
*/
|
|
35
|
+
callbackPath?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Token storage mode
|
|
38
|
+
* - 'client': Store tokens in httpOnly cookies (default)
|
|
39
|
+
* - 'hosted': Use hosted token storage (tokens stored server-side by Quota)
|
|
40
|
+
* @default 'client'
|
|
41
|
+
*/
|
|
42
|
+
storageMode?: "client" | "hosted";
|
|
43
|
+
/**
|
|
44
|
+
* Function to get external user ID for hosted mode
|
|
45
|
+
* Only required when storageMode is 'hosted'
|
|
46
|
+
*/
|
|
47
|
+
getExternalUserId?: (request: NextRequest) => string | Promise<string>;
|
|
48
|
+
/**
|
|
49
|
+
* Cookie settings
|
|
50
|
+
*/
|
|
51
|
+
cookie?: {
|
|
52
|
+
/**
|
|
53
|
+
* Cookie name prefix
|
|
54
|
+
* @default 'quota'
|
|
55
|
+
*/
|
|
56
|
+
prefix?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Cookie domain
|
|
59
|
+
*/
|
|
60
|
+
domain?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Cookie path
|
|
63
|
+
* @default '/'
|
|
64
|
+
*/
|
|
65
|
+
path?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Cookie max age in seconds
|
|
68
|
+
* @default 604800 (7 days)
|
|
69
|
+
*/
|
|
70
|
+
maxAge?: number;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Creates Next.js middleware to handle OAuth callback
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* // middleware.ts
|
|
79
|
+
* import { createQuotaMiddleware } from '@usequota/nextjs';
|
|
80
|
+
*
|
|
81
|
+
* export const middleware = createQuotaMiddleware({
|
|
82
|
+
* clientId: process.env.QUOTA_CLIENT_ID!,
|
|
83
|
+
* clientSecret: process.env.QUOTA_CLIENT_SECRET!,
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* export const config = {
|
|
87
|
+
* matcher: '/api/quota/callback',
|
|
88
|
+
* };
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare function createQuotaMiddleware(config: QuotaConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
92
|
+
|
|
93
|
+
interface QuotaContextValue {
|
|
94
|
+
/**
|
|
95
|
+
* Current authenticated user, or null if not logged in
|
|
96
|
+
*/
|
|
97
|
+
user: QuotaUser | null;
|
|
98
|
+
/**
|
|
99
|
+
* Whether the user data is currently loading
|
|
100
|
+
*/
|
|
101
|
+
isLoading: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Error that occurred during authentication or user fetch
|
|
104
|
+
*/
|
|
105
|
+
error: Error | null;
|
|
106
|
+
/**
|
|
107
|
+
* Redirects to OAuth login flow
|
|
108
|
+
*/
|
|
109
|
+
login: () => void;
|
|
110
|
+
/**
|
|
111
|
+
* Logs out the current user
|
|
112
|
+
*/
|
|
113
|
+
logout: () => Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* Refetches user data from the server
|
|
116
|
+
*/
|
|
117
|
+
refetch: () => Promise<void>;
|
|
118
|
+
}
|
|
119
|
+
declare const QuotaContext: react.Context<QuotaContextValue | null>;
|
|
120
|
+
interface QuotaProviderProps {
|
|
121
|
+
children: ReactNode;
|
|
122
|
+
/**
|
|
123
|
+
* OAuth client ID from Quota dashboard
|
|
124
|
+
*/
|
|
125
|
+
clientId: string;
|
|
126
|
+
/**
|
|
127
|
+
* Quota API base URL
|
|
128
|
+
* @default 'https://api.usequota.app'
|
|
129
|
+
*/
|
|
130
|
+
baseUrl?: string;
|
|
131
|
+
/**
|
|
132
|
+
* OAuth callback path (must match middleware config)
|
|
133
|
+
* @default '/api/quota/callback'
|
|
134
|
+
*/
|
|
135
|
+
callbackPath?: string;
|
|
136
|
+
/**
|
|
137
|
+
* Path to your Next.js API route that fetches user data
|
|
138
|
+
* @default '/api/quota/me'
|
|
139
|
+
*/
|
|
140
|
+
apiPath?: string;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* React context provider for Quota authentication
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```tsx
|
|
147
|
+
* // app/layout.tsx
|
|
148
|
+
* import { QuotaProvider } from '@usequota/nextjs';
|
|
149
|
+
*
|
|
150
|
+
* export default function RootLayout({ children }) {
|
|
151
|
+
* return (
|
|
152
|
+
* <html>
|
|
153
|
+
* <body>
|
|
154
|
+
* <QuotaProvider clientId={process.env.NEXT_PUBLIC_QUOTA_CLIENT_ID!}>
|
|
155
|
+
* {children}
|
|
156
|
+
* </QuotaProvider>
|
|
157
|
+
* </body>
|
|
158
|
+
* </html>
|
|
159
|
+
* );
|
|
160
|
+
* }
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
declare function QuotaProvider({ children, clientId, baseUrl, callbackPath, apiPath, }: QuotaProviderProps): react_jsx_runtime.JSX.Element;
|
|
164
|
+
/**
|
|
165
|
+
* Hook to access Quota authentication context
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```tsx
|
|
169
|
+
* 'use client';
|
|
170
|
+
* import { useQuota } from '@usequota/nextjs';
|
|
171
|
+
*
|
|
172
|
+
* export function MyComponent() {
|
|
173
|
+
* const { user, isLoading, login } = useQuota();
|
|
174
|
+
*
|
|
175
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
176
|
+
* if (!user) return <button onClick={login}>Sign in</button>;
|
|
177
|
+
*
|
|
178
|
+
* return <div>Welcome, {user.email}!</div>;
|
|
179
|
+
* }
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
declare function useQuota(): QuotaContextValue;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @usequota/nextjs - React hooks for Quota SDK
|
|
186
|
+
*
|
|
187
|
+
* Provides convenient hooks for accessing Quota features.
|
|
188
|
+
*/
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Hook to get the current authenticated user
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```tsx
|
|
195
|
+
* 'use client';
|
|
196
|
+
* import { useQuotaUser } from '@usequota/nextjs';
|
|
197
|
+
*
|
|
198
|
+
* export function UserProfile() {
|
|
199
|
+
* const user = useQuotaUser();
|
|
200
|
+
*
|
|
201
|
+
* if (!user) return <div>Not logged in</div>;
|
|
202
|
+
*
|
|
203
|
+
* return (
|
|
204
|
+
* <div>
|
|
205
|
+
* <p>Email: {user.email}</p>
|
|
206
|
+
* <p>Balance: {user.balance} credits</p>
|
|
207
|
+
* </div>
|
|
208
|
+
* );
|
|
209
|
+
* }
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
declare function useQuotaUser(): QuotaUser | null;
|
|
213
|
+
/**
|
|
214
|
+
* Hook to check if user is authenticated
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```tsx
|
|
218
|
+
* 'use client';
|
|
219
|
+
* import { useQuotaAuth } from '@usequota/nextjs';
|
|
220
|
+
*
|
|
221
|
+
* export function ProtectedContent() {
|
|
222
|
+
* const { isAuthenticated, isLoading, login } = useQuotaAuth();
|
|
223
|
+
*
|
|
224
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
225
|
+
* if (!isAuthenticated) return <button onClick={login}>Sign in</button>;
|
|
226
|
+
*
|
|
227
|
+
* return <div>Protected content</div>;
|
|
228
|
+
* }
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
declare function useQuotaAuth(): {
|
|
232
|
+
isAuthenticated: boolean;
|
|
233
|
+
isLoading: boolean;
|
|
234
|
+
login: () => void;
|
|
235
|
+
logout: () => Promise<void>;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Hook to get user's credit balance
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```tsx
|
|
242
|
+
* 'use client';
|
|
243
|
+
* import { useQuotaBalance } from '@usequota/nextjs';
|
|
244
|
+
*
|
|
245
|
+
* export function CreditDisplay() {
|
|
246
|
+
* const { balance, isLoading } = useQuotaBalance();
|
|
247
|
+
*
|
|
248
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
249
|
+
* if (balance === null) return <div>Not logged in</div>;
|
|
250
|
+
*
|
|
251
|
+
* return (
|
|
252
|
+
* <div>
|
|
253
|
+
* Balance: {balance} credits (${(balance / 100).toFixed(2)})
|
|
254
|
+
* </div>
|
|
255
|
+
* );
|
|
256
|
+
* }
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
declare function useQuotaBalance(): {
|
|
260
|
+
balance: number | null;
|
|
261
|
+
isLoading: boolean;
|
|
262
|
+
error: Error | null;
|
|
263
|
+
refetch: () => Promise<void>;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
interface QuotaConnectButtonProps {
|
|
267
|
+
/**
|
|
268
|
+
* Custom button content when not logged in
|
|
269
|
+
* @default 'Connect Wallet'
|
|
270
|
+
*/
|
|
271
|
+
children?: ReactNode;
|
|
272
|
+
/**
|
|
273
|
+
* Additional CSS class names for styling customization
|
|
274
|
+
*/
|
|
275
|
+
className?: string;
|
|
276
|
+
/**
|
|
277
|
+
* Callback fired when OAuth login completes successfully
|
|
278
|
+
*/
|
|
279
|
+
onSuccess?: () => void;
|
|
280
|
+
/**
|
|
281
|
+
* Callback fired when an error occurs during login
|
|
282
|
+
*/
|
|
283
|
+
onError?: (error: Error) => void;
|
|
284
|
+
/**
|
|
285
|
+
* Button variant style
|
|
286
|
+
* @default 'primary'
|
|
287
|
+
*/
|
|
288
|
+
variant?: "primary" | "secondary" | "ghost";
|
|
289
|
+
/**
|
|
290
|
+
* Show loading spinner during authentication
|
|
291
|
+
* @default true
|
|
292
|
+
*/
|
|
293
|
+
showLoadingState?: boolean;
|
|
294
|
+
/**
|
|
295
|
+
* If true, shows user info when logged in instead of hiding
|
|
296
|
+
* @default false
|
|
297
|
+
*/
|
|
298
|
+
showWhenConnected?: boolean;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* OAuth login button for Quota authentication
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```tsx
|
|
305
|
+
* // Basic usage
|
|
306
|
+
* <QuotaConnectButton />
|
|
307
|
+
*
|
|
308
|
+
* // With custom text
|
|
309
|
+
* <QuotaConnectButton>Sign in with Quota</QuotaConnectButton>
|
|
310
|
+
*
|
|
311
|
+
* // With callbacks
|
|
312
|
+
* <QuotaConnectButton
|
|
313
|
+
* onSuccess={() => console.log('Connected!')}
|
|
314
|
+
* onError={(err) => console.error(err)}
|
|
315
|
+
* />
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
declare function QuotaConnectButton({ children, className, onSuccess, onError, variant, showLoadingState, showWhenConnected, }: QuotaConnectButtonProps): react_jsx_runtime.JSX.Element | null;
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* @usequota/nextjs - QuotaBalance
|
|
322
|
+
*
|
|
323
|
+
* Display component for showing the user's credit balance.
|
|
324
|
+
* Supports both credit and dollar formatting.
|
|
325
|
+
*/
|
|
326
|
+
interface QuotaBalanceProps {
|
|
327
|
+
/**
|
|
328
|
+
* Display format for the balance
|
|
329
|
+
* - 'credits': Shows raw credit count (e.g., "1,250 credits")
|
|
330
|
+
* - 'dollars': Shows dollar equivalent (e.g., "$12.50")
|
|
331
|
+
* @default 'credits'
|
|
332
|
+
*/
|
|
333
|
+
format?: "credits" | "dollars";
|
|
334
|
+
/**
|
|
335
|
+
* Whether to show the coin/dollar icon
|
|
336
|
+
* @default true
|
|
337
|
+
*/
|
|
338
|
+
showIcon?: boolean;
|
|
339
|
+
/**
|
|
340
|
+
* Additional CSS class names for styling customization
|
|
341
|
+
*/
|
|
342
|
+
className?: string;
|
|
343
|
+
/**
|
|
344
|
+
* Label text for accessibility
|
|
345
|
+
* @default 'Credit balance'
|
|
346
|
+
*/
|
|
347
|
+
ariaLabel?: string;
|
|
348
|
+
/**
|
|
349
|
+
* Show a refresh button to manually refetch balance
|
|
350
|
+
* @default false
|
|
351
|
+
*/
|
|
352
|
+
showRefresh?: boolean;
|
|
353
|
+
/**
|
|
354
|
+
* Callback when balance is clicked (useful for linking to buy credits)
|
|
355
|
+
*/
|
|
356
|
+
onClick?: () => void;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Display component for user's Quota credit balance
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* ```tsx
|
|
363
|
+
* // Basic usage - shows credits
|
|
364
|
+
* <QuotaBalance />
|
|
365
|
+
*
|
|
366
|
+
* // Show as dollars
|
|
367
|
+
* <QuotaBalance format="dollars" />
|
|
368
|
+
*
|
|
369
|
+
* // Clickable balance
|
|
370
|
+
* <QuotaBalance onClick={() => router.push('/buy-credits')} />
|
|
371
|
+
* ```
|
|
372
|
+
*/
|
|
373
|
+
declare function QuotaBalance({ format, showIcon, className, ariaLabel, showRefresh, onClick, }: QuotaBalanceProps): react_jsx_runtime.JSX.Element;
|
|
374
|
+
|
|
375
|
+
interface QuotaBuyCreditsProps {
|
|
376
|
+
/**
|
|
377
|
+
* Specific package ID to purchase (from /v1/packages)
|
|
378
|
+
*/
|
|
379
|
+
packageId?: string;
|
|
380
|
+
/**
|
|
381
|
+
* Desired credit amount (used to auto-select best package)
|
|
382
|
+
* Ignored if packageId is provided
|
|
383
|
+
*/
|
|
384
|
+
amount?: number;
|
|
385
|
+
/**
|
|
386
|
+
* Custom button content
|
|
387
|
+
* @default 'Buy Credits'
|
|
388
|
+
*/
|
|
389
|
+
children?: ReactNode;
|
|
390
|
+
/**
|
|
391
|
+
* Additional CSS class names for styling customization
|
|
392
|
+
*/
|
|
393
|
+
className?: string;
|
|
394
|
+
/**
|
|
395
|
+
* Callback fired when checkout session is created successfully
|
|
396
|
+
*/
|
|
397
|
+
onSuccess?: () => void;
|
|
398
|
+
/**
|
|
399
|
+
* Callback fired when an error occurs
|
|
400
|
+
*/
|
|
401
|
+
onError?: (error: Error) => void;
|
|
402
|
+
/**
|
|
403
|
+
* Button variant style
|
|
404
|
+
* @default 'primary'
|
|
405
|
+
*/
|
|
406
|
+
variant?: "primary" | "secondary" | "ghost";
|
|
407
|
+
/**
|
|
408
|
+
* Path to the checkout API endpoint
|
|
409
|
+
* @default '/api/quota/checkout'
|
|
410
|
+
*/
|
|
411
|
+
checkoutPath?: string;
|
|
412
|
+
/**
|
|
413
|
+
* Disable the button
|
|
414
|
+
* @default false
|
|
415
|
+
*/
|
|
416
|
+
disabled?: boolean;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Credit purchase button that redirects to Stripe checkout
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```tsx
|
|
423
|
+
* // Basic usage - shows package selection
|
|
424
|
+
* <QuotaBuyCredits />
|
|
425
|
+
*
|
|
426
|
+
* // Specific package
|
|
427
|
+
* <QuotaBuyCredits packageId="pack_1000" />
|
|
428
|
+
*
|
|
429
|
+
* // Custom amount (finds best matching package)
|
|
430
|
+
* <QuotaBuyCredits amount={5000}>Get 5000 Credits</QuotaBuyCredits>
|
|
431
|
+
* ```
|
|
432
|
+
*/
|
|
433
|
+
declare function QuotaBuyCredits({ packageId, amount, children, className, onSuccess, onError, variant, checkoutPath, disabled, }: QuotaBuyCreditsProps): react_jsx_runtime.JSX.Element;
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* @usequota/nextjs - QuotaUserMenu
|
|
437
|
+
*
|
|
438
|
+
* Dropdown menu component showing user avatar, balance, and account actions.
|
|
439
|
+
* Uses headless UI patterns with no external dependencies.
|
|
440
|
+
*/
|
|
441
|
+
interface QuotaUserMenuProps {
|
|
442
|
+
/**
|
|
443
|
+
* Additional CSS class names for styling customization
|
|
444
|
+
*/
|
|
445
|
+
className?: string;
|
|
446
|
+
/**
|
|
447
|
+
* Callback when "Buy Credits" is clicked
|
|
448
|
+
*/
|
|
449
|
+
onBuyCredits?: () => void;
|
|
450
|
+
/**
|
|
451
|
+
* Callback when logout completes
|
|
452
|
+
*/
|
|
453
|
+
onLogout?: () => void;
|
|
454
|
+
/**
|
|
455
|
+
* Show the buy credits menu item
|
|
456
|
+
* @default true
|
|
457
|
+
*/
|
|
458
|
+
showBuyCredits?: boolean;
|
|
459
|
+
/**
|
|
460
|
+
* Custom content to render in the dropdown
|
|
461
|
+
*/
|
|
462
|
+
children?: React.ReactNode;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* User account dropdown menu with balance display
|
|
466
|
+
*
|
|
467
|
+
* @example
|
|
468
|
+
* ```tsx
|
|
469
|
+
* // Basic usage
|
|
470
|
+
* <QuotaUserMenu />
|
|
471
|
+
*
|
|
472
|
+
* // With callbacks
|
|
473
|
+
* <QuotaUserMenu
|
|
474
|
+
* onBuyCredits={() => router.push('/buy-credits')}
|
|
475
|
+
* onLogout={() => router.push('/')}
|
|
476
|
+
* />
|
|
477
|
+
*
|
|
478
|
+
* // With custom menu items
|
|
479
|
+
* <QuotaUserMenu>
|
|
480
|
+
* <button onClick={() => router.push('/settings')}>Settings</button>
|
|
481
|
+
* </QuotaUserMenu>
|
|
482
|
+
* ```
|
|
483
|
+
*/
|
|
484
|
+
declare function QuotaUserMenu({ className, onBuyCredits, onLogout, showBuyCredits, children, }: QuotaUserMenuProps): react_jsx_runtime.JSX.Element | null;
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Webhook event types sent by Quota
|
|
488
|
+
*/
|
|
489
|
+
interface WebhookEvent {
|
|
490
|
+
/** Unique event identifier */
|
|
491
|
+
id: string;
|
|
492
|
+
/** Event type */
|
|
493
|
+
type: "user.connected" | "user.disconnected" | "balance.updated" | "balance.low" | "usage.completed";
|
|
494
|
+
/** ISO 8601 timestamp when event was created */
|
|
495
|
+
created_at: string;
|
|
496
|
+
/** Event-specific data payload */
|
|
497
|
+
data: Record<string, unknown>;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Options for verifying webhook signatures
|
|
501
|
+
*/
|
|
502
|
+
interface VerifyWebhookOptions {
|
|
503
|
+
/** Raw webhook payload (string or Buffer) */
|
|
504
|
+
payload: string | Buffer;
|
|
505
|
+
/** Signature from X-Quota-Signature header */
|
|
506
|
+
signature: string;
|
|
507
|
+
/** Webhook secret from Quota dashboard */
|
|
508
|
+
secret: string;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Verify a webhook signature from Quota using HMAC-SHA256
|
|
512
|
+
*
|
|
513
|
+
* @param options - Verification options
|
|
514
|
+
* @returns true if signature is valid, false otherwise
|
|
515
|
+
*
|
|
516
|
+
* @example
|
|
517
|
+
* ```typescript
|
|
518
|
+
* const isValid = verifyWebhookSignature({
|
|
519
|
+
* payload: rawBody,
|
|
520
|
+
* signature: request.headers.get('x-quota-signature')!,
|
|
521
|
+
* secret: process.env.QUOTA_WEBHOOK_SECRET!
|
|
522
|
+
* });
|
|
523
|
+
* ```
|
|
524
|
+
*/
|
|
525
|
+
declare function verifyWebhookSignature({ payload, signature, secret, }: VerifyWebhookOptions): boolean;
|
|
526
|
+
/**
|
|
527
|
+
* Parse and verify a webhook request
|
|
528
|
+
* For use in Next.js API routes (App Router)
|
|
529
|
+
*
|
|
530
|
+
* @param req - Next.js Request object
|
|
531
|
+
* @param secret - Webhook secret from Quota dashboard
|
|
532
|
+
* @returns Parsed and verified webhook event
|
|
533
|
+
* @throws Error if signature is missing or invalid
|
|
534
|
+
*
|
|
535
|
+
* @example
|
|
536
|
+
* ```typescript
|
|
537
|
+
* // app/api/quota/webhook/route.ts
|
|
538
|
+
* export async function POST(req: Request) {
|
|
539
|
+
* try {
|
|
540
|
+
* const event = await parseWebhook(req, process.env.QUOTA_WEBHOOK_SECRET!);
|
|
541
|
+
*
|
|
542
|
+
* if (event.type === 'balance.low') {
|
|
543
|
+
* await sendLowBalanceEmail(event.data);
|
|
544
|
+
* }
|
|
545
|
+
*
|
|
546
|
+
* return Response.json({ received: true });
|
|
547
|
+
* } catch (error) {
|
|
548
|
+
* return Response.json({ error: error.message }, { status: 400 });
|
|
549
|
+
* }
|
|
550
|
+
* }
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
553
|
+
declare function parseWebhook(req: Request, secret: string): Promise<WebhookEvent>;
|
|
554
|
+
/**
|
|
555
|
+
* Create a webhook handler for Next.js App Router
|
|
556
|
+
* Automatically verifies signatures and routes events to handlers
|
|
557
|
+
*
|
|
558
|
+
* @param secret - Webhook secret from Quota dashboard
|
|
559
|
+
* @param handlers - Map of event types to handler functions
|
|
560
|
+
* @returns Next.js route handler function
|
|
561
|
+
*
|
|
562
|
+
* @example
|
|
563
|
+
* ```typescript
|
|
564
|
+
* // app/api/quota/webhook/route.ts
|
|
565
|
+
* import { createWebhookHandler } from '@usequota/nextjs';
|
|
566
|
+
*
|
|
567
|
+
* export const POST = createWebhookHandler(process.env.QUOTA_WEBHOOK_SECRET!, {
|
|
568
|
+
* 'balance.low': async (event) => {
|
|
569
|
+
* // Send email notification
|
|
570
|
+
* await sendLowBalanceEmail(event.data.user_id, event.data.current_balance);
|
|
571
|
+
* },
|
|
572
|
+
* 'user.connected': async (event) => {
|
|
573
|
+
* // Track new user connection
|
|
574
|
+
* await analytics.track('user_connected', event.data);
|
|
575
|
+
* },
|
|
576
|
+
* 'usage.completed': async (event) => {
|
|
577
|
+
* // Log usage for analytics
|
|
578
|
+
* await logUsage(event.data);
|
|
579
|
+
* }
|
|
580
|
+
* });
|
|
581
|
+
* ```
|
|
582
|
+
*/
|
|
583
|
+
declare function createWebhookHandler(secret: string, handlers: Partial<Record<WebhookEvent["type"], (event: WebhookEvent) => Promise<void>>>): (req: Request) => Promise<Response>;
|
|
584
|
+
|
|
585
|
+
export { QuotaBalance, type QuotaBalanceProps, QuotaBuyCredits, type QuotaBuyCreditsProps, type QuotaConfig, QuotaConnectButton, type QuotaConnectButtonProps, QuotaContext, type QuotaContextValue, QuotaProvider, type QuotaProviderProps, QuotaUserMenu, type QuotaUserMenuProps, type VerifyWebhookOptions, type WebhookEvent, createQuotaMiddleware, createWebhookHandler, parseWebhook, useQuota, useQuotaAuth, useQuotaBalance, useQuotaUser, verifyWebhookSignature };
|