@sylphx/sdk 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2089 @@
1
+ import { NextResponse, NextRequest } from 'next/server';
2
+
3
+ /**
4
+ * Sylphx Unified Middleware — State of the Art
5
+ *
6
+ * ONE middleware function handles EVERYTHING:
7
+ * - Auth routes (mounted automatically, zero manual API routes)
8
+ * - Token refresh (automatic, every request)
9
+ * - Route protection
10
+ * - Cookie management
11
+ *
12
+ * This follows Auth0 v4 / Clerk / Supabase patterns where middleware
13
+ * handles all auth concerns. Apps don't need to create any /api/auth/* routes.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // middleware.ts (or proxy.ts for Next.js 16)
18
+ * import { createSylphxMiddleware } from '@sylphx/sdk/nextjs'
19
+ *
20
+ * export default createSylphxMiddleware({
21
+ * publicRoutes: ['/', '/about', '/pricing'],
22
+ * })
23
+ *
24
+ * export const config = {
25
+ * matcher: ['/((?!_next|.*\\..*).*)', '/'],
26
+ * }
27
+ * ```
28
+ *
29
+ * That's it. No /api/auth/* routes needed.
30
+ */
31
+
32
+ interface SylphxMiddlewareConfig {
33
+ /**
34
+ * Routes that don't require authentication.
35
+ * Supports exact paths and wildcards.
36
+ *
37
+ * @example ['/', '/about', '/pricing', '/blog/*']
38
+ * @default ['/']
39
+ */
40
+ publicRoutes?: string[];
41
+ /**
42
+ * Routes that middleware should completely ignore.
43
+ * Use for webhooks, static assets, or third-party integrations.
44
+ *
45
+ * @default []
46
+ */
47
+ ignoredRoutes?: string[];
48
+ /**
49
+ * URL to redirect unauthenticated users.
50
+ * @default '/login'
51
+ */
52
+ signInUrl?: string;
53
+ /**
54
+ * URL to redirect after sign out.
55
+ * @default '/'
56
+ */
57
+ afterSignOutUrl?: string;
58
+ /**
59
+ * URL to redirect after successful sign in.
60
+ * @default '/dashboard'
61
+ */
62
+ afterSignInUrl?: string;
63
+ /**
64
+ * Auth routes prefix. Routes are mounted at:
65
+ * - {prefix}/callback — OAuth callback handler
66
+ * - {prefix}/signout — Sign out handler
67
+ *
68
+ * @default '/auth'
69
+ */
70
+ authPrefix?: string;
71
+ /**
72
+ * Enable debug logging.
73
+ * @default false
74
+ */
75
+ debug?: boolean;
76
+ /**
77
+ * Secret key for authentication.
78
+ * Override to use a programmatic key instead of SYLPHX_SECRET_KEY env var.
79
+ *
80
+ * Use case: Platform Console uses dynamically generated keys.
81
+ *
82
+ * @default process.env.SYLPHX_SECRET_KEY
83
+ */
84
+ secretKey?: string;
85
+ /**
86
+ * Platform URL for API calls.
87
+ * Override for self-hosted or same-origin deployments.
88
+ *
89
+ * @default process.env.SYLPHX_PLATFORM_URL || 'https://sylphx.com'
90
+ */
91
+ platformUrl?: string;
92
+ /**
93
+ * Callback to add custom headers/logic to responses.
94
+ * Called for every non-auth-route request after SDK processing.
95
+ *
96
+ * Use case: Add security headers, tracking cookies, etc.
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * onResponse: (response, request) => {
101
+ * response.headers.set('X-Custom-Header', 'value')
102
+ * }
103
+ * ```
104
+ */
105
+ onResponse?: (response: NextResponse, request: NextRequest) => void | Promise<void>;
106
+ }
107
+ /**
108
+ * Create Sylphx middleware — State of the Art
109
+ *
110
+ * ONE function handles everything:
111
+ * - Auth routes ({authPrefix}/callback, {authPrefix}/signout)
112
+ * - Token refresh (automatic, every request)
113
+ * - Route protection
114
+ * - Cookie management
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * // middleware.ts (or proxy.ts for Next.js 16)
119
+ * import { createSylphxMiddleware } from '@sylphx/sdk/nextjs'
120
+ *
121
+ * export default createSylphxMiddleware({
122
+ * publicRoutes: ['/', '/about', '/pricing'],
123
+ * })
124
+ *
125
+ * export const config = {
126
+ * matcher: ['/((?!_next|.*\\..*).*)', '/'],
127
+ * }
128
+ * ```
129
+ */
130
+ declare function createSylphxMiddleware(userConfig?: SylphxMiddlewareConfig): (request: NextRequest) => Promise<NextResponse>;
131
+ /**
132
+ * Create recommended matcher config
133
+ */
134
+ declare function createMatcher(): {
135
+ matcher: string[];
136
+ };
137
+ /**
138
+ * Get cookie namespace from secret key (for advanced use)
139
+ */
140
+ declare function getNamespace(secretKey: string): string;
141
+
142
+ interface components {
143
+ schemas: {
144
+ ErrorResponse: {
145
+ error: {
146
+ message: string;
147
+ code: string;
148
+ };
149
+ };
150
+ User: {
151
+ /** Format: uuid */
152
+ id: string;
153
+ /** Format: email */
154
+ email: string;
155
+ name: string | null;
156
+ /** Format: uri */
157
+ image?: string | null;
158
+ emailVerified: boolean;
159
+ };
160
+ TokenResponse: {
161
+ accessToken: string;
162
+ refreshToken: string;
163
+ /** @description Token expiry in seconds */
164
+ expiresIn: number;
165
+ user: components["schemas"]["User"];
166
+ };
167
+ /** @enum {string} */
168
+ OrgRole:
169
+ | "super_admin"
170
+ | "admin"
171
+ | "billing"
172
+ | "analytics"
173
+ | "developer"
174
+ | "viewer";
175
+ Organization: {
176
+ /** Format: uuid */
177
+ id: string;
178
+ name: string;
179
+ slug: string;
180
+ /** Format: uri */
181
+ logoUrl: string | null;
182
+ /** Format: email */
183
+ email: string | null;
184
+ /** Format: email */
185
+ billingEmail: string | null;
186
+ /** Format: date-time */
187
+ createdAt: string;
188
+ };
189
+ OrganizationMember: {
190
+ /** Format: uuid */
191
+ id: string;
192
+ /** Format: uuid */
193
+ userId: string;
194
+ /** Format: email */
195
+ email: string;
196
+ name: string | null;
197
+ /** Format: uri */
198
+ image: string | null;
199
+ role: components["schemas"]["OrgRole"];
200
+ /** Format: date-time */
201
+ joinedAt: string;
202
+ };
203
+ OrganizationInvitation: {
204
+ /** Format: uuid */
205
+ id: string;
206
+ /** Format: email */
207
+ email: string;
208
+ role: components["schemas"]["OrgRole"];
209
+ /** @enum {string} */
210
+ status: "pending" | "accepted" | "expired" | "revoked";
211
+ /** Format: uuid */
212
+ invitedById: string;
213
+ invitedByName: string | null;
214
+ /** Format: date-time */
215
+ expiresAt: string;
216
+ /** Format: date-time */
217
+ createdAt: string;
218
+ };
219
+ OrganizationMembership: {
220
+ role: components["schemas"]["OrgRole"];
221
+ /** Format: date-time */
222
+ joinedAt: string;
223
+ };
224
+ CreateOrgRequest: {
225
+ name: string;
226
+ slug?: string;
227
+ /** Format: email */
228
+ email?: string;
229
+ };
230
+ UpdateOrgRequest: {
231
+ name?: string;
232
+ slug?: string;
233
+ /** Format: uri */
234
+ logoUrl?: string | null;
235
+ /** Format: email */
236
+ email?: string | null;
237
+ /** Format: email */
238
+ billingEmail?: string | null;
239
+ };
240
+ InviteMemberRequest: {
241
+ /** Format: email */
242
+ email: string;
243
+ role: components["schemas"]["OrgRole"];
244
+ };
245
+ UpdateMemberRoleRequest: {
246
+ role: components["schemas"]["OrgRole"];
247
+ };
248
+ AcceptInvitationRequest: {
249
+ token: string;
250
+ };
251
+ OrganizationsResponse: {
252
+ organizations: components["schemas"]["Organization"][];
253
+ };
254
+ OrganizationResponse: {
255
+ organization: components["schemas"]["Organization"];
256
+ membership: components["schemas"]["OrganizationMembership"] & unknown;
257
+ };
258
+ CreateOrgResponse: {
259
+ organization: components["schemas"]["Organization"];
260
+ };
261
+ OrganizationMembersResponse: {
262
+ members: components["schemas"]["OrganizationMember"][];
263
+ };
264
+ OrganizationInvitationsResponse: {
265
+ invitations: components["schemas"]["OrganizationInvitation"][];
266
+ };
267
+ InviteMemberResponse: {
268
+ invitation: components["schemas"]["OrganizationInvitation"];
269
+ };
270
+ UpdateMemberRoleResponse: {
271
+ member: components["schemas"]["OrganizationMember"];
272
+ };
273
+ AcceptInvitationResponse: {
274
+ organization: components["schemas"]["Organization"];
275
+ };
276
+ LoginResponse:
277
+ | {
278
+ /** @enum {boolean} */
279
+ requiresTwoFactor: false;
280
+ accessToken: string;
281
+ refreshToken: string;
282
+ expiresIn: number;
283
+ user: components["schemas"]["User"];
284
+ }
285
+ | {
286
+ /** @enum {boolean} */
287
+ requiresTwoFactor: true;
288
+ /** Format: uuid */
289
+ userId: string;
290
+ /** Format: email */
291
+ email: string;
292
+ };
293
+ LoginRequest: {
294
+ /** Format: email */
295
+ email: string;
296
+ password: string;
297
+ };
298
+ RegisterResponse: {
299
+ requiresVerification: boolean;
300
+ message: string;
301
+ user: {
302
+ /** Format: uuid */
303
+ id: string;
304
+ /** Format: email */
305
+ email: string;
306
+ name: string | null;
307
+ };
308
+ };
309
+ RegisterRequest: {
310
+ name: string;
311
+ /** Format: email */
312
+ email: string;
313
+ password: string;
314
+ };
315
+ TwoFactorVerifyRequest: {
316
+ /** Format: uuid */
317
+ userId: string;
318
+ code: string;
319
+ };
320
+ SuccessResponse: {
321
+ success: boolean;
322
+ message?: string;
323
+ };
324
+ ForgotPasswordRequest: {
325
+ /** Format: email */
326
+ email: string;
327
+ };
328
+ ResetPasswordRequest: {
329
+ token: string;
330
+ password: string;
331
+ };
332
+ VerifyEmailRequest: {
333
+ token: string;
334
+ };
335
+ LogoutRequest: {
336
+ refreshToken?: string;
337
+ };
338
+ MeResponse: {
339
+ /** Format: uuid */
340
+ id: string;
341
+ /** Format: email */
342
+ email: string;
343
+ name: string | null;
344
+ /** Format: uri */
345
+ image?: string | null;
346
+ emailVerified: boolean;
347
+ twoFactorEnabled: boolean;
348
+ };
349
+ OAuthProvidersResponse: {
350
+ providers: string[];
351
+ };
352
+ UserProfile: {
353
+ /** Format: uuid */
354
+ id: string;
355
+ /** Format: email */
356
+ email: string;
357
+ name: string | null;
358
+ /** Format: uri */
359
+ image?: string | null;
360
+ emailVerified: boolean;
361
+ /** Format: date-time */
362
+ createdAt: string;
363
+ };
364
+ UpdateProfileRequest: {
365
+ name?: string;
366
+ /** Format: uri */
367
+ image?: string | null;
368
+ };
369
+ SecuritySettings: {
370
+ twoFactorEnabled: boolean;
371
+ hasPassword: boolean;
372
+ emailVerified: boolean;
373
+ };
374
+ SessionsResponse: components["schemas"]["Session"][];
375
+ Session: {
376
+ /** Format: uuid */
377
+ id: string;
378
+ isCurrent: boolean;
379
+ deviceName?: string | null;
380
+ browser?: string | null;
381
+ os?: string | null;
382
+ deviceType?: string | null;
383
+ ipAddress?: string | null;
384
+ country?: string | null;
385
+ city?: string | null;
386
+ /** Format: date-time */
387
+ lastActiveAt: string;
388
+ /** Format: date-time */
389
+ createdAt: string;
390
+ };
391
+ LoginHistoryEntry: {
392
+ /** Format: uuid */
393
+ id: string;
394
+ ipAddress?: string | null;
395
+ userAgent?: string | null;
396
+ country?: string | null;
397
+ city?: string | null;
398
+ device?: string | null;
399
+ success: boolean;
400
+ /** Format: date-time */
401
+ createdAt: string;
402
+ };
403
+ ConnectedAccount: {
404
+ provider: string;
405
+ /** Format: date-time */
406
+ connectedAt: string;
407
+ };
408
+ PlansResponse: components["schemas"]["Plan"][];
409
+ Plan: {
410
+ /** Format: uuid */
411
+ id: string;
412
+ slug: string;
413
+ name: string;
414
+ description: string | null;
415
+ features: string[];
416
+ priceMonthly: number | null;
417
+ priceAnnual: number | null;
418
+ priceLifetime: number | null;
419
+ };
420
+ Subscription: {
421
+ /** Format: uuid */
422
+ id: string;
423
+ /** Format: uuid */
424
+ userId: string;
425
+ /** Format: uuid */
426
+ planId: string;
427
+ planSlug: string;
428
+ status: string;
429
+ /** @enum {string} */
430
+ interval: "monthly" | "annual" | "lifetime";
431
+ /** Format: date-time */
432
+ currentPeriodStart: string | null;
433
+ /** Format: date-time */
434
+ currentPeriodEnd: string | null;
435
+ cancelAtPeriodEnd: boolean;
436
+ /** Format: date-time */
437
+ trialEnd: string | null;
438
+ } | null;
439
+ CheckoutResponse: {
440
+ /** Format: uri */
441
+ checkoutUrl: string | null;
442
+ sessionId: string;
443
+ };
444
+ CheckoutRequest: {
445
+ /** Format: uuid */
446
+ userId: string;
447
+ planSlug: string;
448
+ /** @enum {string} */
449
+ interval: "monthly" | "annual" | "lifetime";
450
+ /** Format: uri */
451
+ successUrl: string;
452
+ /** Format: uri */
453
+ cancelUrl: string;
454
+ };
455
+ PortalResponse: {
456
+ /** Format: uri */
457
+ portalUrl: string;
458
+ };
459
+ PortalRequest: {
460
+ /** Format: uuid */
461
+ userId: string;
462
+ /** Format: uri */
463
+ returnUrl: string;
464
+ };
465
+ BalanceResponse: {
466
+ balance: {
467
+ current: number;
468
+ currentFormatted: string;
469
+ };
470
+ status: {
471
+ level: string;
472
+ isHealthy: boolean;
473
+ isLow: boolean;
474
+ alertThreshold: number;
475
+ };
476
+ /** @enum {string} */
477
+ billingType: "prepaid" | "postpaid";
478
+ trustLevel: string;
479
+ spendingCap: number | null;
480
+ currentMonthSpend: number;
481
+ spendingCapPercent: number | null;
482
+ /** Format: date-time */
483
+ gracePeriodEndsAt: string | null;
484
+ isAdminOrg: boolean;
485
+ };
486
+ UsageResponse: {
487
+ period: {
488
+ type: string;
489
+ /** Format: date-time */
490
+ start: string;
491
+ /** Format: date-time */
492
+ end: string;
493
+ };
494
+ metrics: {
495
+ aiCostMicrodollars: number;
496
+ storageBytesUsed: number;
497
+ storageEgressBytes: number;
498
+ storageUploads: number;
499
+ dbStorageBytes: number;
500
+ dbComputeSeconds: number;
501
+ emailSentCount: number;
502
+ jobInvocationCount: number;
503
+ cronActiveCount: number;
504
+ notificationsSentCount: number;
505
+ analyticsEventCount: number;
506
+ webhookDeliveryCount: number;
507
+ errorEventCount: number;
508
+ authMau: number;
509
+ } | null;
510
+ };
511
+ BatchTrackResponse: {
512
+ success: boolean;
513
+ /** @description Number of new events tracked */
514
+ count: number;
515
+ /** @description Number of duplicate events filtered out */
516
+ deduplicated: number;
517
+ /** @description Total events in the request */
518
+ total: number;
519
+ };
520
+ BatchTrackRequest: {
521
+ events: components["schemas"]["TrackEventItem"][];
522
+ };
523
+ TrackEventItem: {
524
+ event: string;
525
+ properties?: {
526
+ [key: string]: unknown;
527
+ };
528
+ /** Format: date-time */
529
+ timestamp?: string;
530
+ destinations?: ("google_ads" | "meta" | "tiktok")[];
531
+ skipDestinations?: boolean;
532
+ conversion?: components["schemas"]["ConversionData"];
533
+ };
534
+ ConversionData: {
535
+ clickId?: string;
536
+ value?: number;
537
+ currency?: string;
538
+ orderId?: string;
539
+ /** Format: email */
540
+ userEmail?: string;
541
+ userPhone?: string;
542
+ userFirstName?: string;
543
+ userLastName?: string;
544
+ };
545
+ AnalyticsQueryResponse: {
546
+ data: {
547
+ eventName: string;
548
+ count: number;
549
+ }[];
550
+ /** @description Total count across all events */
551
+ total: number;
552
+ };
553
+ AnalyticsQueryRequest: {
554
+ /**
555
+ * Format: date-time
556
+ * @description Start of date range (ISO 8601)
557
+ */
558
+ dateFrom?: string;
559
+ /**
560
+ * Format: date-time
561
+ * @description End of date range (ISO 8601)
562
+ */
563
+ dateTo?: string;
564
+ /** @description Filter by specific event names */
565
+ events?: string[];
566
+ /**
567
+ * @description Group by time interval
568
+ * @enum {string}
569
+ */
570
+ interval?: "hour" | "day" | "week" | "month";
571
+ /**
572
+ * @description Limit results (default 100, max 1000)
573
+ * @default 100
574
+ */
575
+ limit: number;
576
+ };
577
+ JobStatusResponse: {
578
+ available: boolean;
579
+ provider: string;
580
+ };
581
+ ScheduleJobResponse: {
582
+ /** Format: uuid */
583
+ jobId?: string;
584
+ messageId?: string;
585
+ /** Format: date-time */
586
+ scheduledFor?: string | null;
587
+ };
588
+ ScheduleJobRequest: {
589
+ /** Format: uri */
590
+ callbackUrl: string;
591
+ payload?: {
592
+ [key: string]: unknown;
593
+ };
594
+ /**
595
+ * @default POST
596
+ * @enum {string}
597
+ */
598
+ method: "GET" | "POST" | "PUT" | "DELETE";
599
+ headers?: {
600
+ [key: string]: string;
601
+ };
602
+ delay?: number;
603
+ /** Format: date-time */
604
+ scheduledFor?: string;
605
+ /** @default 3 */
606
+ retries: number;
607
+ name?: string;
608
+ type?: string;
609
+ /** @default 30 */
610
+ timeout: number;
611
+ };
612
+ ListJobsResponse: {
613
+ jobs: components["schemas"]["Job"][];
614
+ total: number;
615
+ limit: number;
616
+ offset: number;
617
+ };
618
+ Job: {
619
+ /** Format: uuid */
620
+ id: string;
621
+ name: string | null;
622
+ type: string;
623
+ /** @enum {string} */
624
+ status:
625
+ | "pending"
626
+ | "queued"
627
+ | "running"
628
+ | "completed"
629
+ | "failed"
630
+ | "scheduled"
631
+ | "paused"
632
+ | "cancelled"
633
+ | "deleted";
634
+ callbackUrl: string;
635
+ payload?: {
636
+ [key: string]: unknown;
637
+ };
638
+ /** Format: date-time */
639
+ scheduledFor: string | null;
640
+ /** Format: date-time */
641
+ startedAt: string | null;
642
+ /** Format: date-time */
643
+ completedAt: string | null;
644
+ /** Format: date-time */
645
+ failedAt: string | null;
646
+ retries: number;
647
+ maxRetries: number;
648
+ lastError: string | null;
649
+ cronExpression: string | null;
650
+ /** Format: date-time */
651
+ createdAt: string;
652
+ };
653
+ ScheduleCronResponse: {
654
+ /** Format: uuid */
655
+ jobId?: string;
656
+ scheduleId: string;
657
+ cron: string;
658
+ paused: boolean;
659
+ };
660
+ ScheduleCronRequest: {
661
+ /** Format: uri */
662
+ callbackUrl: string;
663
+ cron: string;
664
+ payload?: {
665
+ [key: string]: unknown;
666
+ };
667
+ /**
668
+ * @default POST
669
+ * @enum {string}
670
+ */
671
+ method: "GET" | "POST" | "PUT" | "DELETE";
672
+ headers?: {
673
+ [key: string]: string;
674
+ };
675
+ /** @default 3 */
676
+ retries: number;
677
+ name: string;
678
+ type?: string;
679
+ /** @default false */
680
+ paused: boolean;
681
+ };
682
+ ReferralCodeResponse: {
683
+ /** @description 8-character referral code */
684
+ code: string;
685
+ /** @enum {string} */
686
+ status: "pending" | "completed" | "expired";
687
+ };
688
+ RegenerateCodeResponse: {
689
+ /** @description New 8-character referral code */
690
+ code: string;
691
+ totalReferrals: number;
692
+ completedReferrals: number;
693
+ pendingReferrals: number;
694
+ };
695
+ ReferralStatsResponse: {
696
+ /** @description Total referrals created */
697
+ totalReferrals: number;
698
+ /** @description Successfully completed referrals */
699
+ completedReferrals: number;
700
+ /** @description Pending referrals */
701
+ pendingReferrals: number;
702
+ };
703
+ RedeemReferralResponse: {
704
+ success: boolean;
705
+ /** @description Type of reward applied */
706
+ rewardType: string;
707
+ /** @description Details of reward applied to referee */
708
+ referredReward?: {
709
+ [key: string]: unknown;
710
+ };
711
+ /** @description Details of reward applied to referrer */
712
+ referrerReward?: {
713
+ [key: string]: unknown;
714
+ };
715
+ };
716
+ RedeemReferralRequest: {
717
+ /** @description Referral code to redeem */
718
+ code: string;
719
+ defaults?: components["schemas"]["ReferralRewardDefaults"];
720
+ };
721
+ /** @description Optional inline defaults for reward configuration */
722
+ ReferralRewardDefaults: {
723
+ referrerReward?: components["schemas"]["ReferralRewardConfig"];
724
+ refereeReward?: components["schemas"]["ReferralRewardConfig"] & unknown;
725
+ /** @description Whether both parties get rewarded (default: true) */
726
+ doubleReward?: boolean;
727
+ /** @description Minimum days before rewards are granted (anti-fraud) */
728
+ minimumDaysBeforeReward?: number;
729
+ };
730
+ /** @description Reward for the person who shared the code */
731
+ ReferralRewardConfig: {
732
+ /** @enum {string} */
733
+ type: "points" | "premium_trial" | "discount" | "credit";
734
+ /** @description Points to award (for type: points) */
735
+ points?: number;
736
+ /** @description Trial days to grant (for type: premium_trial) */
737
+ days?: number;
738
+ /** @description Discount percentage (for type: discount) */
739
+ discountPercent?: number;
740
+ /** @description Credit amount in cents (for type: credit) */
741
+ creditCents?: number;
742
+ };
743
+ LeaderboardResponse: {
744
+ /** @enum {string} */
745
+ period: "all" | "month" | "week";
746
+ entries: components["schemas"]["LeaderboardEntry"][];
747
+ /** @description Current user rank if authenticated */
748
+ currentUserRank: number | null;
749
+ };
750
+ LeaderboardEntry: {
751
+ /** @description Position in the leaderboard */
752
+ rank: number;
753
+ /**
754
+ * Format: uuid
755
+ * @description User ID (only revealed if current user)
756
+ */
757
+ userId: string | null;
758
+ /** @description Masked name for privacy */
759
+ displayName: string | null;
760
+ /** Format: uri */
761
+ avatarUrl: string | null;
762
+ completedReferrals: number;
763
+ totalReferrals: number;
764
+ isCurrentUser: boolean;
765
+ };
766
+ PushPreferencesResponse: {
767
+ enabled: boolean;
768
+ subscriptionCount: number;
769
+ };
770
+ RegisterPushResponse: {
771
+ success: boolean;
772
+ updated: boolean;
773
+ };
774
+ RegisterPushRequest: {
775
+ subscription: {
776
+ /** Format: uri */
777
+ endpoint: string;
778
+ keys: {
779
+ p256dh: string;
780
+ auth: string;
781
+ };
782
+ };
783
+ };
784
+ UnregisterPushRequest: {
785
+ /** Format: uri */
786
+ endpoint: string;
787
+ };
788
+ MobileConfigResponse: {
789
+ ios: boolean;
790
+ android: boolean;
791
+ anyConfigured: boolean;
792
+ };
793
+ MobilePreferencesResponse: {
794
+ enabled: boolean;
795
+ devices: components["schemas"]["MobileDevice"][];
796
+ };
797
+ MobileDevice: {
798
+ /** Format: uuid */
799
+ id: string;
800
+ /** @enum {string} */
801
+ platform: "ios" | "android";
802
+ name: string | null;
803
+ /** Format: date-time */
804
+ registeredAt: string;
805
+ /** Format: date-time */
806
+ lastUsedAt: string | null;
807
+ };
808
+ RegisterMobileDeviceResponse: {
809
+ success: boolean;
810
+ updated: boolean;
811
+ /** Format: uuid */
812
+ tokenId: string;
813
+ };
814
+ RegisterMobileDeviceRequest: {
815
+ /** @enum {string} */
816
+ platform: "ios" | "android";
817
+ token: string;
818
+ deviceId?: string;
819
+ deviceName?: string;
820
+ appVersion?: string;
821
+ osVersion?: string;
822
+ };
823
+ UnregisterMobileDeviceRequest: {
824
+ token: string;
825
+ };
826
+ InAppMessagesResponse: components["schemas"]["InAppMessage"][];
827
+ InAppMessage: {
828
+ /** Format: uuid */
829
+ id: string;
830
+ /** @enum {string|null} */
831
+ type:
832
+ | "info"
833
+ | "success"
834
+ | "warning"
835
+ | "error"
836
+ | "announcement"
837
+ | "system"
838
+ | "action"
839
+ | null;
840
+ /** @enum {string|null} */
841
+ priority: "low" | "normal" | "high" | "urgent" | null;
842
+ title: string;
843
+ body: string;
844
+ icon: string | null;
845
+ imageUrl: string | null;
846
+ actionText: string | null;
847
+ actionUrl: string | null;
848
+ secondaryActionText: string | null;
849
+ secondaryActionUrl: string | null;
850
+ metadata: {
851
+ [key: string]: unknown;
852
+ } | null;
853
+ topic: string | null;
854
+ isRead: boolean;
855
+ isDismissed: boolean;
856
+ /** Format: date-time */
857
+ readAt: string | null;
858
+ /** Format: date-time */
859
+ createdAt: string;
860
+ };
861
+ UnreadCountResponse: {
862
+ count: number;
863
+ };
864
+ MarkAllReadResponse: {
865
+ success: boolean;
866
+ markedCount: number;
867
+ };
868
+ RecordClickRequest: {
869
+ /** @enum {string} */
870
+ action: "primary" | "secondary";
871
+ };
872
+ MessagePreferencesResponse: {
873
+ enabled: boolean;
874
+ mutedTopics: string[];
875
+ highPriorityOnly: boolean;
876
+ };
877
+ UpdateMessagePreferencesRequest: {
878
+ enabled?: boolean;
879
+ mutedTopics?: string[];
880
+ highPriorityOnly?: boolean;
881
+ };
882
+ StorageFile: {
883
+ /** Format: uuid */
884
+ id: string;
885
+ filename: string;
886
+ path: string;
887
+ /** Format: uri */
888
+ url: string | null;
889
+ mimeType: string;
890
+ /** @description File size in bytes */
891
+ size: number;
892
+ metadata: {
893
+ [key: string]: unknown;
894
+ } | null;
895
+ /** Format: date-time */
896
+ createdAt: string;
897
+ };
898
+ UploadUrlResponse: {
899
+ /**
900
+ * Format: uri
901
+ * @description Endpoint URL for the upload
902
+ */
903
+ uploadEndpoint: string;
904
+ /** @description JSON payload to include in the upload request */
905
+ clientPayload: string;
906
+ /** @description Maximum file size in bytes */
907
+ maxSize: number;
908
+ /** @description List of allowed MIME types */
909
+ allowedContentTypes: string[];
910
+ /** @description Instructions for making the upload request */
911
+ instructions: {
912
+ method: string;
913
+ headers: {
914
+ [key: string]: string;
915
+ };
916
+ body: {
917
+ type: string;
918
+ payload: {
919
+ pathname: string;
920
+ clientPayload: string;
921
+ };
922
+ };
923
+ };
924
+ };
925
+ UploadUrlRequest: {
926
+ /** @description Name of the file to upload */
927
+ filename: string;
928
+ /** @description MIME type of the file */
929
+ contentType?: string;
930
+ /** @description Optional folder path within app storage */
931
+ folder?: string;
932
+ /** @description Custom metadata to attach to the file */
933
+ metadata?: {
934
+ [key: string]: unknown;
935
+ };
936
+ };
937
+ CaptureExceptionResponse: {
938
+ /**
939
+ * Format: uuid
940
+ * @description Unique event ID
941
+ */
942
+ eventId: string;
943
+ /** @description Whether this is a new unique error or a duplicate */
944
+ isNewError: boolean;
945
+ };
946
+ CaptureExceptionRequest: {
947
+ /** @description The exception to capture */
948
+ exception: {
949
+ values: components["schemas"]["MonitoringExceptionValue"][];
950
+ };
951
+ level?: components["schemas"]["MonitoringErrorLevel"];
952
+ /** @description Tags for filtering */
953
+ tags?: {
954
+ [key: string]: string;
955
+ };
956
+ /** @description Extra context data */
957
+ extra?: {
958
+ [key: string]: unknown;
959
+ };
960
+ /** @description Breadcrumbs leading up to the error */
961
+ breadcrumbs?: components["schemas"]["MonitoringBreadcrumb"][];
962
+ /** @description Current page/screen */
963
+ route?: string;
964
+ /** @description User agent */
965
+ userAgent?: string;
966
+ /** @description Custom fingerprint for grouping */
967
+ fingerprint?: string[];
968
+ /** @description Release version */
969
+ release?: string;
970
+ /** @description Environment (dev/staging/prod) */
971
+ environment?: string;
972
+ };
973
+ MonitoringExceptionValue: {
974
+ /** @description Exception type (e.g., "TypeError", "ReferenceError") */
975
+ type: string;
976
+ /** @description Exception message */
977
+ value: string;
978
+ stacktrace?: {
979
+ frames: {
980
+ filename?: string;
981
+ function?: string;
982
+ lineno?: number;
983
+ colno?: number;
984
+ in_app?: boolean;
985
+ }[];
986
+ };
987
+ };
988
+ /**
989
+ * @description Error level
990
+ * @enum {string}
991
+ */
992
+ MonitoringErrorLevel: "fatal" | "error" | "warning" | "info";
993
+ MonitoringBreadcrumb: {
994
+ type: string;
995
+ category: string;
996
+ message: string;
997
+ timestamp: string;
998
+ };
999
+ CaptureMessageResponse: {
1000
+ /**
1001
+ * Format: uuid
1002
+ * @description Unique event ID
1003
+ */
1004
+ eventId: string;
1005
+ /** @description Whether this is a new unique message or a duplicate */
1006
+ isNewError: boolean;
1007
+ };
1008
+ CaptureMessageRequest: {
1009
+ /** @description Message to capture */
1010
+ message: string;
1011
+ level?: components["schemas"]["MonitoringErrorLevel"] & unknown;
1012
+ /** @description Tags for filtering */
1013
+ tags?: {
1014
+ [key: string]: string;
1015
+ };
1016
+ /** @description Extra context data */
1017
+ extra?: {
1018
+ [key: string]: unknown;
1019
+ };
1020
+ /** @description Current page/screen */
1021
+ route?: string;
1022
+ };
1023
+ AIUsageResponse: {
1024
+ /** @enum {string} */
1025
+ period: "day" | "week" | "month";
1026
+ /** @description Total number of AI requests */
1027
+ requests: number;
1028
+ tokens: {
1029
+ /** @description Total input tokens */
1030
+ input: number;
1031
+ /** @description Total output tokens */
1032
+ output: number;
1033
+ /** @description Total tokens (input + output) */
1034
+ total: number;
1035
+ };
1036
+ cost: {
1037
+ /** @description Cost in microdollars (1/1,000,000 USD) */
1038
+ microdollars: number;
1039
+ /** @description Human-readable cost string */
1040
+ formatted: string;
1041
+ };
1042
+ /** @description Usage breakdown by model */
1043
+ byModel: {
1044
+ [key: string]: {
1045
+ requests: number;
1046
+ tokens: number;
1047
+ cost: number;
1048
+ };
1049
+ };
1050
+ /** @description Usage breakdown by request type (chat, embedding, vision) */
1051
+ byType: {
1052
+ [key: string]: {
1053
+ requests: number;
1054
+ tokens: number;
1055
+ };
1056
+ };
1057
+ };
1058
+ AIRateLimitResponse: {
1059
+ /** @description Max requests per minute (null if unlimited) */
1060
+ requestsPerMinute: number | null;
1061
+ /** @description Max requests per day (null if unlimited) */
1062
+ requestsPerDay: number | null;
1063
+ /** @description Max tokens per minute (null if unlimited) */
1064
+ tokensPerMinute: number | null;
1065
+ /** @description Max tokens per day (null if unlimited) */
1066
+ tokensPerDay: number | null;
1067
+ /** @description Max cost per day in microdollars (null if unlimited) */
1068
+ costPerDayMicrodollars: number | null;
1069
+ current: {
1070
+ /** @description Requests made in the last minute */
1071
+ requestsThisMinute: number;
1072
+ /** @description Requests made today */
1073
+ requestsToday: number;
1074
+ /** @description Tokens used in the last minute */
1075
+ tokensThisMinute: number;
1076
+ /** @description Tokens used today */
1077
+ tokensToday: number;
1078
+ /** @description Cost today in microdollars */
1079
+ costToday: number;
1080
+ };
1081
+ };
1082
+ AIModelsResponse: {
1083
+ models: components["schemas"]["AIModel"][];
1084
+ /** @description Total number of matching models */
1085
+ total: number;
1086
+ /** @description Whether more results are available */
1087
+ hasMore: boolean;
1088
+ };
1089
+ AIModel: {
1090
+ /** @description Model ID (e.g., openai/gpt-4) */
1091
+ id: string;
1092
+ /** @description Human-readable model name */
1093
+ name: string;
1094
+ /** @description Model description */
1095
+ description?: string | null;
1096
+ /** @description Model capabilities */
1097
+ capabilities: ("chat" | "vision" | "tool" | "embedding")[];
1098
+ /** @description Maximum context window size */
1099
+ contextWindow?: number;
1100
+ pricing?: {
1101
+ /** @description Cost per input token in USD */
1102
+ inputPerToken?: number;
1103
+ /** @description Cost per output token in USD */
1104
+ outputPerToken?: number;
1105
+ };
1106
+ };
1107
+ ConsentTypesResponse: components["schemas"]["ConsentType"][];
1108
+ ConsentType: {
1109
+ /** Format: uuid */
1110
+ id: string;
1111
+ slug: string;
1112
+ /** @enum {string} */
1113
+ category:
1114
+ | "necessary"
1115
+ | "analytics"
1116
+ | "marketing"
1117
+ | "preferences"
1118
+ | "functional";
1119
+ name: string;
1120
+ description: string;
1121
+ required: boolean;
1122
+ defaultEnabled: boolean;
1123
+ };
1124
+ UserConsentsResponse: components["schemas"]["UserConsent"][];
1125
+ UserConsent: {
1126
+ slug: string;
1127
+ /** @enum {string} */
1128
+ category:
1129
+ | "necessary"
1130
+ | "analytics"
1131
+ | "marketing"
1132
+ | "preferences"
1133
+ | "functional";
1134
+ name: string;
1135
+ required: boolean;
1136
+ granted: boolean;
1137
+ /** Format: date-time */
1138
+ grantedAt: string | null;
1139
+ version: number | null;
1140
+ };
1141
+ SetConsentResponse: {
1142
+ consents: {
1143
+ slug: string;
1144
+ granted: boolean;
1145
+ }[];
1146
+ };
1147
+ SetConsentRequest: {
1148
+ /**
1149
+ * Format: uuid
1150
+ * @description User ID (for logged-in users)
1151
+ */
1152
+ userId?: string;
1153
+ /** @description Anonymous ID (for non-logged-in users) */
1154
+ anonymousId?: string;
1155
+ /** @description Consents to set */
1156
+ consents: {
1157
+ /** @description Consent type slug */
1158
+ slug: string;
1159
+ /** @description Whether consent is granted */
1160
+ granted: boolean;
1161
+ }[];
1162
+ /**
1163
+ * @description Source of consent
1164
+ * @default banner
1165
+ * @enum {string}
1166
+ */
1167
+ source: "banner" | "settings" | "api";
1168
+ /** @description User agent string */
1169
+ userAgent?: string;
1170
+ };
1171
+ AcceptAllConsentRequest: {
1172
+ /**
1173
+ * Format: uuid
1174
+ * @description User ID (for logged-in users)
1175
+ */
1176
+ userId?: string;
1177
+ /** @description Anonymous ID (for non-logged-in users) */
1178
+ anonymousId?: string;
1179
+ /**
1180
+ * @description Source of consent
1181
+ * @default banner
1182
+ * @enum {string}
1183
+ */
1184
+ source: "banner" | "settings" | "api";
1185
+ /** @description User agent string */
1186
+ userAgent?: string;
1187
+ };
1188
+ DeclineOptionalConsentRequest: {
1189
+ /**
1190
+ * Format: uuid
1191
+ * @description User ID (for logged-in users)
1192
+ */
1193
+ userId?: string;
1194
+ /** @description Anonymous ID (for non-logged-in users) */
1195
+ anonymousId?: string;
1196
+ /**
1197
+ * @description Source of consent
1198
+ * @default banner
1199
+ * @enum {string}
1200
+ */
1201
+ source: "banner" | "settings" | "api";
1202
+ /** @description User agent string */
1203
+ userAgent?: string;
1204
+ };
1205
+ SendEmailResponse: {
1206
+ success: boolean;
1207
+ /** @description Email ID from provider */
1208
+ id?: string;
1209
+ };
1210
+ SendEmailRequest: {
1211
+ /**
1212
+ * Format: email
1213
+ * @description Recipient email address
1214
+ */
1215
+ to: string;
1216
+ /** @description Email subject */
1217
+ subject: string;
1218
+ /** @description Email HTML content */
1219
+ html: string;
1220
+ /** @description Plain text fallback */
1221
+ text?: string;
1222
+ /**
1223
+ * Format: email
1224
+ * @description Reply-to email address
1225
+ */
1226
+ replyTo?: string;
1227
+ };
1228
+ SendTemplatedEmailResponse: {
1229
+ success: boolean;
1230
+ /** @description Template that was sent */
1231
+ template: string;
1232
+ };
1233
+ SendTemplatedEmailRequest: {
1234
+ /**
1235
+ * @description Template type
1236
+ * @enum {string}
1237
+ */
1238
+ template:
1239
+ | "welcome"
1240
+ | "verification"
1241
+ | "password_reset"
1242
+ | "security_alert";
1243
+ /**
1244
+ * Format: email
1245
+ * @description Recipient email address
1246
+ */
1247
+ to: string;
1248
+ /** @description Template variables */
1249
+ data?: {
1250
+ [key: string]: unknown;
1251
+ };
1252
+ };
1253
+ SendToUserResponse: {
1254
+ success: boolean;
1255
+ /** @description Email ID from provider */
1256
+ id?: string;
1257
+ };
1258
+ SendToUserRequest: {
1259
+ /**
1260
+ * Format: uuid
1261
+ * @description User ID to send email to
1262
+ */
1263
+ userId: string;
1264
+ /** @description Email subject */
1265
+ subject: string;
1266
+ /** @description Email HTML content */
1267
+ html: string;
1268
+ /** @description Plain text fallback */
1269
+ text?: string;
1270
+ };
1271
+ NewsletterSubscribeResponse: {
1272
+ success: boolean;
1273
+ /** @description Human-readable result message */
1274
+ message: string;
1275
+ /** @description Whether email verification is required */
1276
+ requiresVerification: boolean;
1277
+ /** @description Whether email was already subscribed */
1278
+ alreadySubscribed: boolean;
1279
+ };
1280
+ NewsletterSubscribeRequest: {
1281
+ /**
1282
+ * Format: email
1283
+ * @description Subscriber email address
1284
+ */
1285
+ email: string;
1286
+ /**
1287
+ * @description Subscription source
1288
+ * @default website
1289
+ * @enum {string}
1290
+ */
1291
+ source: "website" | "waitlist" | "referral" | "api" | "import";
1292
+ /** @description Subscriber name */
1293
+ name?: string;
1294
+ /** @description Additional tracking metadata */
1295
+ metadata?: {
1296
+ referrer?: string;
1297
+ utmSource?: string;
1298
+ utmMedium?: string;
1299
+ utmCampaign?: string;
1300
+ referralCode?: string;
1301
+ } & {
1302
+ [key: string]: unknown;
1303
+ };
1304
+ /** @description Initial subscription preferences */
1305
+ preferences?: {
1306
+ newsletter?: boolean;
1307
+ product_updates?: boolean;
1308
+ promotions?: boolean;
1309
+ changelog?: boolean;
1310
+ security_alerts?: boolean;
1311
+ };
1312
+ };
1313
+ NewsletterVerifyResponse: {
1314
+ success: boolean;
1315
+ /** @description Human-readable result message */
1316
+ message: string;
1317
+ /**
1318
+ * Format: email
1319
+ * @description Verified email address
1320
+ */
1321
+ email: string;
1322
+ };
1323
+ NewsletterVerifyRequest: {
1324
+ /** @description Verification token from email */
1325
+ token: string;
1326
+ };
1327
+ NewsletterUnsubscribeResponse: {
1328
+ success: boolean;
1329
+ /** @description Human-readable result message */
1330
+ message: string;
1331
+ /**
1332
+ * Format: email
1333
+ * @description Unsubscribed email address
1334
+ */
1335
+ email: string;
1336
+ };
1337
+ NewsletterUnsubscribeRequest: {
1338
+ /**
1339
+ * Format: email
1340
+ * @description Email to unsubscribe
1341
+ */
1342
+ email: string;
1343
+ /** @description Unsubscribe token from email */
1344
+ token: string;
1345
+ };
1346
+ NewsletterResendVerificationResponse: {
1347
+ success: boolean;
1348
+ /** @description Human-readable result message */
1349
+ message: string;
1350
+ };
1351
+ NewsletterResendVerificationRequest: {
1352
+ /**
1353
+ * Format: email
1354
+ * @description Email to resend verification to
1355
+ */
1356
+ email: string;
1357
+ };
1358
+ NewsletterUnsubscribeInfoResponse: {
1359
+ /**
1360
+ * Format: email
1361
+ * @description Subscriber email
1362
+ */
1363
+ email: string;
1364
+ /** @description Subscriber name */
1365
+ name: string | null;
1366
+ /**
1367
+ * Format: date-time
1368
+ * @description When subscription was confirmed
1369
+ */
1370
+ subscribedAt: string | null;
1371
+ };
1372
+ NewsletterPreferences: {
1373
+ /** @description Newsletter preference */
1374
+ newsletter: boolean;
1375
+ /** @description Product updates preference */
1376
+ product_updates: boolean;
1377
+ /** @description Promotions preference */
1378
+ promotions: boolean;
1379
+ /** @description Changelog preference */
1380
+ changelog: boolean;
1381
+ /** @description Security alerts preference */
1382
+ security_alerts: boolean;
1383
+ };
1384
+ NewsletterUpdatePreferencesResponse: {
1385
+ success: boolean;
1386
+ preferences: components["schemas"]["NewsletterPreferences"] & unknown;
1387
+ };
1388
+ NewsletterUpdatePreferencesRequest: {
1389
+ /**
1390
+ * Format: email
1391
+ * @description Subscriber email
1392
+ */
1393
+ email: string;
1394
+ /** @description Preferences to update */
1395
+ preferences: {
1396
+ newsletter?: boolean;
1397
+ product_updates?: boolean;
1398
+ promotions?: boolean;
1399
+ changelog?: boolean;
1400
+ security_alerts?: boolean;
1401
+ };
1402
+ };
1403
+ WebhookConfigResponse: {
1404
+ environments: components["schemas"]["WebhookEnvironmentConfig"][];
1405
+ supportedEvents: string[];
1406
+ };
1407
+ WebhookEnvironmentConfig: {
1408
+ /** Format: uuid */
1409
+ id: string;
1410
+ name: string;
1411
+ /** Format: uri */
1412
+ webhookUrl: string | null;
1413
+ hasSecret: boolean;
1414
+ /** Format: date-time */
1415
+ updatedAt: string | null;
1416
+ };
1417
+ UpdateWebhookConfigResponse: {
1418
+ success: boolean;
1419
+ /** Format: uri */
1420
+ webhookUrl: string | null;
1421
+ secretGenerated: boolean;
1422
+ /** @description Only returned on initial setup or regeneration */
1423
+ webhookSecret?: string;
1424
+ };
1425
+ UpdateWebhookConfigRequest: {
1426
+ /** Format: uuid */
1427
+ environmentId: string;
1428
+ /** Format: uri */
1429
+ webhookUrl: string | null;
1430
+ /** @default false */
1431
+ regenerateSecret: boolean;
1432
+ };
1433
+ ListWebhookDeliveriesResponse: {
1434
+ deliveries: components["schemas"]["WebhookDelivery"][];
1435
+ total: number;
1436
+ limit: number;
1437
+ offset: number;
1438
+ };
1439
+ WebhookDelivery: {
1440
+ /** Format: uuid */
1441
+ id: string;
1442
+ event: string;
1443
+ url: string;
1444
+ /** @enum {string} */
1445
+ status: "pending" | "queued" | "delivered" | "failed";
1446
+ retryCount: number;
1447
+ responseStatus: number | null;
1448
+ error: string | null;
1449
+ /** Format: date-time */
1450
+ createdAt: string;
1451
+ /** Format: date-time */
1452
+ queuedAt: string | null;
1453
+ /** Format: date-time */
1454
+ deliveredAt: string | null;
1455
+ /** Format: date-time */
1456
+ failedAt: string | null;
1457
+ };
1458
+ ReplayDeliveryResponse: {
1459
+ success: boolean;
1460
+ /** Format: uuid */
1461
+ newDeliveryId?: string;
1462
+ messageId?: string;
1463
+ };
1464
+ WebhookStatsResponse: {
1465
+ /** @enum {string} */
1466
+ period: "day" | "week" | "month";
1467
+ totals: {
1468
+ total: number;
1469
+ delivered: number;
1470
+ failed: number;
1471
+ pending: number;
1472
+ /** @description Percentage formatted as string (e.g., "95.5%") */
1473
+ deliveryRate: string;
1474
+ };
1475
+ byEvent: {
1476
+ event: string;
1477
+ count: number;
1478
+ }[];
1479
+ byStatus: {
1480
+ /** @enum {string} */
1481
+ status: "pending" | "queued" | "delivered" | "failed";
1482
+ count: number;
1483
+ }[];
1484
+ };
1485
+ TwoFactorSetupResponse: {
1486
+ /** @description TOTP secret key */
1487
+ secret: string;
1488
+ /** @description TOTP URI for QR code generation */
1489
+ uri: string;
1490
+ /** @description Base64 encoded QR code image */
1491
+ qrCode?: string;
1492
+ };
1493
+ Security2FAVerifyResponse: {
1494
+ success: boolean;
1495
+ /** @description One-time backup codes */
1496
+ backupCodes: string[];
1497
+ };
1498
+ Security2FAVerifyRequest: {
1499
+ /** @description 6-digit TOTP code */
1500
+ code: string;
1501
+ };
1502
+ Security2FADisableResponse: {
1503
+ success: boolean;
1504
+ };
1505
+ BackupCodesResponse: {
1506
+ /** @description Remaining unused backup codes */
1507
+ codes: string[];
1508
+ /** @description Number of remaining codes */
1509
+ count: number;
1510
+ };
1511
+ BackupCodesRegenerateResponse: {
1512
+ /** @description New backup codes */
1513
+ codes: string[];
1514
+ };
1515
+ SetPasswordRequest: {
1516
+ /** @description New password */
1517
+ password: string;
1518
+ };
1519
+ EmailChangeResponse: {
1520
+ success: boolean;
1521
+ message: string;
1522
+ /**
1523
+ * Format: date-time
1524
+ * @description When the verification link expires
1525
+ */
1526
+ expiresAt: string;
1527
+ };
1528
+ EmailChangeRequest: {
1529
+ /**
1530
+ * Format: email
1531
+ * @description New email address
1532
+ */
1533
+ newEmail: string;
1534
+ };
1535
+ EmailChangeConfirmResponse: {
1536
+ success: boolean;
1537
+ /**
1538
+ * Format: email
1539
+ * @description The new email address
1540
+ */
1541
+ newEmail: string;
1542
+ };
1543
+ EmailChangeConfirmRequest: {
1544
+ /** @description Verification token from email */
1545
+ token: string;
1546
+ };
1547
+ PasskeysListResponse: {
1548
+ passkeys: components["schemas"]["Passkey"][];
1549
+ };
1550
+ Passkey: {
1551
+ /** Format: uuid */
1552
+ id: string;
1553
+ name: string | null;
1554
+ /** Format: date-time */
1555
+ createdAt: string;
1556
+ /** Format: date-time */
1557
+ lastUsedAt: string | null;
1558
+ };
1559
+ PasskeyRegistrationOptions: {
1560
+ challenge: string;
1561
+ rp: {
1562
+ name: string;
1563
+ id: string;
1564
+ };
1565
+ user: {
1566
+ id: string;
1567
+ name: string;
1568
+ displayName: string;
1569
+ };
1570
+ pubKeyCredParams: {
1571
+ /** @enum {string} */
1572
+ type: "public-key";
1573
+ alg: number;
1574
+ }[];
1575
+ timeout?: number;
1576
+ attestation?: string;
1577
+ excludeCredentials?: {
1578
+ /** @enum {string} */
1579
+ type: "public-key";
1580
+ id: string;
1581
+ }[];
1582
+ authenticatorSelection?: {
1583
+ authenticatorAttachment?: string;
1584
+ requireResidentKey?: boolean;
1585
+ residentKey?: string;
1586
+ userVerification?: string;
1587
+ };
1588
+ } & {
1589
+ [key: string]: unknown;
1590
+ };
1591
+ PasskeyRegisterVerifyResponse: {
1592
+ /** Format: uuid */
1593
+ id: string;
1594
+ name: string | null;
1595
+ /** Format: date-time */
1596
+ createdAt: string;
1597
+ };
1598
+ PasskeyRegisterVerifyRequest: {
1599
+ /** @description WebAuthn RegistrationResponseJSON */
1600
+ credential?: unknown;
1601
+ /** @description Optional device name */
1602
+ deviceName?: string;
1603
+ };
1604
+ PasskeyRenameRequest: {
1605
+ name: string;
1606
+ };
1607
+ OAuthDisconnectResponse: {
1608
+ success: boolean;
1609
+ };
1610
+ OAuthDisconnectRequest: {
1611
+ /** @description OAuth provider name (e.g., google, github) */
1612
+ provider: string;
1613
+ };
1614
+ SecurityScore: {
1615
+ /** @description Overall security score */
1616
+ score: number;
1617
+ /**
1618
+ * @description Security level
1619
+ * @enum {string}
1620
+ */
1621
+ level: "critical" | "low" | "medium" | "high" | "excellent";
1622
+ /** @description Individual security factors */
1623
+ factors: {
1624
+ name: string;
1625
+ enabled: boolean;
1626
+ weight: number;
1627
+ description: string;
1628
+ }[];
1629
+ /** @description Recommended security improvements */
1630
+ recommendations: {
1631
+ /** @enum {string} */
1632
+ priority: "high" | "medium" | "low";
1633
+ title: string;
1634
+ description: string;
1635
+ action?: string;
1636
+ }[];
1637
+ };
1638
+ ChallengeVerifyResponse: {
1639
+ verified: boolean;
1640
+ /** @enum {string} */
1641
+ method: "password" | "email" | "totp" | "backup";
1642
+ /**
1643
+ * @description Type of verification completed
1644
+ * @enum {string}
1645
+ */
1646
+ type: "identity" | "mfa";
1647
+ };
1648
+ ChallengeVerifyRequest: {
1649
+ /**
1650
+ * @description Verification method
1651
+ * @enum {string}
1652
+ */
1653
+ method: "password" | "email" | "totp" | "backup";
1654
+ /** @description Verification value (password, code, etc.) */
1655
+ value: string;
1656
+ };
1657
+ };
1658
+ responses: never;
1659
+ parameters: never;
1660
+ requestBodies: never;
1661
+ headers: never;
1662
+ pathItems: never;
1663
+ }
1664
+
1665
+ /**
1666
+ * Auth Functions
1667
+ *
1668
+ * Pure functions for authentication - no hidden state.
1669
+ * Each function takes config as the first parameter.
1670
+ *
1671
+ * Uses REST API at /api/sdk/auth/* for all operations.
1672
+ *
1673
+ * Types are derived from the OpenAPI spec (generated/api.d.ts).
1674
+ * Run `bun run generate:types:local` to regenerate after API changes.
1675
+ */
1676
+
1677
+ type TokenResponse = components['schemas']['TokenResponse'];
1678
+
1679
+ /**
1680
+ * Platform SDK Types
1681
+ *
1682
+ * Type definitions for the SDK. API types are generated from OpenAPI spec (ADR-007).
1683
+ * SDK-specific types for React layer and internal use are defined here.
1684
+ *
1685
+ * ## Type Sources (ADR-007)
1686
+ *
1687
+ * | Source | Example | When to Use |
1688
+ * |--------|---------|-------------|
1689
+ * | `generated/api.d.ts` | `LoginRequest`, `Plan` | All API request/response types |
1690
+ * | SDK modules | `SessionResult`, `FlagContext` | SDK-specific types |
1691
+ * | `types.ts` | `AppConfig`, `AIMessage` | Shared/React layer types |
1692
+ *
1693
+ * ## Naming Conventions (Generated Types)
1694
+ *
1695
+ * | Suffix | Purpose | Example |
1696
+ * |--------|---------|---------|
1697
+ * | `Request` | API request payloads | `LoginRequest`, `CheckoutRequest` |
1698
+ * | `Response` | API response payloads | `LoginResponse`, `TokenResponse` |
1699
+ * | (none) | Domain objects | `Plan`, `Subscription`, `User` |
1700
+ *
1701
+ * ## Naming Conventions (SDK Types)
1702
+ *
1703
+ * | Suffix | Purpose | Example |
1704
+ * |--------|---------|---------|
1705
+ * | `Result` | SDK function return (non-API) | `SessionResult` |
1706
+ * | `Options` | Optional function parameters | `FileUploadOptions`, `RevokeTokenOptions` |
1707
+ * | `Config` | Runtime configuration | `SylphxConfig`, `AppConfig` |
1708
+ *
1709
+ * ## Sdk* Prefix (services-context.ts)
1710
+ *
1711
+ * Types prefixed with `Sdk` (e.g., `SdkUserProfile`) are SDK internal representations
1712
+ * with Date objects instead of ISO strings. API types use strings, SDK transforms to Date.
1713
+ */
1714
+
1715
+ /**
1716
+ * Base user type for SDK operations.
1717
+ *
1718
+ * Used in:
1719
+ * - Token responses (login, refresh)
1720
+ * - Cookie data for client hydration
1721
+ * - Basic user state in React context
1722
+ *
1723
+ * For authenticated user with security fields (twoFactorEnabled),
1724
+ * see AuthUser in services-context.ts.
1725
+ */
1726
+ /**
1727
+ * User type - compatible with generated User from API
1728
+ *
1729
+ * Note: `image` is optional to match generated type.
1730
+ * Extra fields (role, createdAt) are SDK extensions for internal use.
1731
+ */
1732
+ interface User {
1733
+ id: string;
1734
+ email: string;
1735
+ name: string | null;
1736
+ image?: string | null;
1737
+ emailVerified: boolean;
1738
+ role?: string;
1739
+ createdAt?: string;
1740
+ }
1741
+ /**
1742
+ * User cookie data (JS-readable for client hydration)
1743
+ *
1744
+ * Single Source of Truth for the user cookie shape.
1745
+ * Used by both server-side (nextjs/cookies.ts) and client-side (react/storage-utils.ts).
1746
+ *
1747
+ * Note: This contains NO sensitive data.
1748
+ * Tokens are stored separately in HttpOnly cookies.
1749
+ */
1750
+ interface UserCookieData {
1751
+ user: User;
1752
+ /** Timestamp when session expires (for client-side expiry check) */
1753
+ expiresAt: number;
1754
+ }
1755
+
1756
+ /**
1757
+ * Server-side Auth Helpers for Next.js
1758
+ *
1759
+ * Use in Server Components and API Routes.
1760
+ *
1761
+ * Architecture: Cookie-Centric Single Source of Truth
1762
+ * ===================================================
1763
+ *
1764
+ * All auth state lives in cookies. The auth() function reads
1765
+ * from HttpOnly cookies and refreshes if needed.
1766
+ *
1767
+ * Cookie Structure:
1768
+ * - __sylphx_{namespace}_session — HttpOnly JWT (5 min)
1769
+ * - __sylphx_{namespace}_refresh — HttpOnly refresh token (30 days)
1770
+ * - __sylphx_{namespace}_user — JS-readable user data (5 min)
1771
+ */
1772
+
1773
+ /**
1774
+ * Configure the SDK for server-side usage
1775
+ *
1776
+ * NOTE: This is optional! The SDK auto-configures from environment variables:
1777
+ * - SYLPHX_SECRET_KEY (required)
1778
+ * - SYLPHX_PLATFORM_URL (optional, defaults to https://sylphx.com)
1779
+ *
1780
+ * Use this only if you need to override the default configuration.
1781
+ *
1782
+ * @example
1783
+ * ```ts
1784
+ * // Optional: Override default configuration
1785
+ * import { configureServer } from '@sylphx/sdk/nextjs'
1786
+ *
1787
+ * configureServer({
1788
+ * secretKey: process.env.SYLPHX_SECRET_KEY!,
1789
+ * platformUrl: 'https://custom.sylphx.com',
1790
+ * })
1791
+ * ```
1792
+ */
1793
+ declare function configureServer(config: {
1794
+ secretKey: string;
1795
+ platformUrl?: string;
1796
+ }): void;
1797
+ /**
1798
+ * Auth state returned by auth()
1799
+ */
1800
+ interface AuthResult {
1801
+ userId: string | null;
1802
+ user: User | null;
1803
+ /** Session token (for internal use only - not exposed to client) */
1804
+ sessionToken: string | null;
1805
+ }
1806
+ /**
1807
+ * Get the current auth state (memoized per request)
1808
+ *
1809
+ * This is the primary way to check authentication in Server Components.
1810
+ * It reads from HttpOnly cookies and refreshes if needed.
1811
+ *
1812
+ * @example
1813
+ * ```ts
1814
+ * // In a Server Component
1815
+ * import { auth } from '@sylphx/platform-sdk/nextjs'
1816
+ *
1817
+ * export default async function Dashboard() {
1818
+ * const { userId, user } = await auth()
1819
+ *
1820
+ * if (!userId) {
1821
+ * redirect('/login')
1822
+ * }
1823
+ *
1824
+ * return <div>Hello, {user?.name}</div>
1825
+ * }
1826
+ * ```
1827
+ */
1828
+ declare const auth: () => Promise<AuthResult>;
1829
+ /**
1830
+ * Get the current user (null if not logged in)
1831
+ *
1832
+ * @example
1833
+ * ```ts
1834
+ * import { currentUser } from '@sylphx/platform-sdk/nextjs'
1835
+ *
1836
+ * export default async function Header() {
1837
+ * const user = await currentUser()
1838
+ * if (!user) return <SignIn />
1839
+ * return <span>Hello, {user.name}</span>
1840
+ * }
1841
+ * ```
1842
+ */
1843
+ declare function currentUser(): Promise<User | null>;
1844
+ /**
1845
+ * Get the current user ID (null if not logged in)
1846
+ */
1847
+ declare function currentUserId(): Promise<string | null>;
1848
+ /**
1849
+ * Handle OAuth callback - exchange code for tokens and set cookies
1850
+ *
1851
+ * NOTE: With createSylphxMiddleware(), this is handled automatically.
1852
+ * You don't need to create manual /api/auth/* routes.
1853
+ *
1854
+ * This function is exported for advanced use cases where you need
1855
+ * custom callback handling outside of the middleware flow.
1856
+ *
1857
+ * @example
1858
+ * ```ts
1859
+ * // Using middleware (recommended - zero manual routes)
1860
+ * import { createSylphxMiddleware } from '@sylphx/sdk/nextjs'
1861
+ * export default createSylphxMiddleware({ publicRoutes: ['/', '/about'] })
1862
+ *
1863
+ * // Middleware automatically handles /auth/callback
1864
+ * ```
1865
+ */
1866
+ declare function handleCallback(code: string): Promise<User>;
1867
+ /**
1868
+ * Sign out - clear cookies and optionally revoke token
1869
+ *
1870
+ * NOTE: With createSylphxMiddleware(), signout is handled automatically
1871
+ * at /auth/signout. No manual route needed.
1872
+ *
1873
+ * This function is exported for advanced use cases.
1874
+ *
1875
+ * @example
1876
+ * ```ts
1877
+ * // Using middleware (recommended)
1878
+ * // Navigate users to /auth/signout - middleware handles everything
1879
+ * <a href="/auth/signout">Sign Out</a>
1880
+ * ```
1881
+ */
1882
+ declare function signOut(): Promise<void>;
1883
+ /**
1884
+ * Sync tokens to cookies (server action)
1885
+ *
1886
+ * NOTE: With createSylphxMiddleware(), OAuth callbacks are handled
1887
+ * automatically at /auth/callback. This function is rarely needed.
1888
+ *
1889
+ * Use only for edge cases like custom OAuth providers not going
1890
+ * through the standard flow.
1891
+ */
1892
+ declare function syncAuthToCookies(tokens: TokenResponse): Promise<void>;
1893
+ /**
1894
+ * Get authorization URL for OAuth redirect
1895
+ */
1896
+ declare function getAuthorizationUrl(options?: {
1897
+ redirectUri?: string;
1898
+ mode?: 'login' | 'signup';
1899
+ state?: string;
1900
+ appId?: string;
1901
+ }): string;
1902
+ /**
1903
+ * Get the current session token for API calls
1904
+ *
1905
+ * This is for apps that need to call third-party APIs with the session token.
1906
+ * For same-origin API calls, cookies are sent automatically.
1907
+ *
1908
+ * @example
1909
+ * ```ts
1910
+ * // In an API route that needs to call external APIs
1911
+ * import { getSessionToken } from '@sylphx/platform-sdk/nextjs'
1912
+ *
1913
+ * export async function GET() {
1914
+ * const token = await getSessionToken()
1915
+ * if (!token) {
1916
+ * return new Response('Unauthorized', { status: 401 })
1917
+ * }
1918
+ *
1919
+ * // Call third-party API
1920
+ * const response = await fetch('https://api.example.com/data', {
1921
+ * headers: { Authorization: `Bearer ${token}` }
1922
+ * })
1923
+ * // ...
1924
+ * }
1925
+ * ```
1926
+ */
1927
+ declare function getSessionToken(): Promise<string | null>;
1928
+
1929
+ /**
1930
+ * Cookie Management for Next.js — Single Source of Truth
1931
+ *
1932
+ * Architecture: Cookie-Centric Auth (Clerk Pattern)
1933
+ * ================================================
1934
+ *
1935
+ * ALL auth state lives in cookies. Zero localStorage for auth.
1936
+ *
1937
+ * Cookie Structure:
1938
+ * - __sylphx_{namespace}_session — HttpOnly JWT, 5 min (access token)
1939
+ * - __sylphx_{namespace}_refresh — HttpOnly, 30 days (refresh token)
1940
+ * - __sylphx_{namespace}_user — JS-readable, 5 min (user data for client hydration)
1941
+ *
1942
+ * Benefits:
1943
+ * 1. Single Source of Truth — no server/client state divergence
1944
+ * 2. XSS-safe — tokens never accessible to JavaScript
1945
+ * 3. Cross-tab sync — cookies shared across tabs automatically
1946
+ * 4. SSR works — auth() in Server Components reads cookies directly
1947
+ *
1948
+ * Security:
1949
+ * - Short token lifetime (5 min) like Clerk
1950
+ * - Server-side refresh in middleware
1951
+ * - SameSite=Lax for CSRF protection
1952
+ */
1953
+
1954
+ /**
1955
+ * Get cookie names for a given namespace
1956
+ *
1957
+ * Namespace is derived from the secret key environment (dev/stg/prod).
1958
+ * This prevents cookies from different environments colliding.
1959
+ *
1960
+ * @example
1961
+ * getCookieNames('sylphx_prod')
1962
+ * // Returns:
1963
+ * // {
1964
+ * // SESSION: '__sylphx_prod_session',
1965
+ * // REFRESH: '__sylphx_prod_refresh',
1966
+ * // USER: '__sylphx_prod_user',
1967
+ * // }
1968
+ */
1969
+ declare function getCookieNames(namespace: string): {
1970
+ /** HttpOnly JWT access token (5 min) */
1971
+ SESSION: string;
1972
+ /** HttpOnly refresh token (30 days) */
1973
+ REFRESH: string;
1974
+ /** JS-readable user data for client hydration (5 min) */
1975
+ USER: string;
1976
+ };
1977
+ /**
1978
+ * Session token lifetime (5 minutes like Clerk)
1979
+ */
1980
+ declare const SESSION_TOKEN_LIFETIME: number;
1981
+ /**
1982
+ * Refresh token lifetime (30 days)
1983
+ */
1984
+ declare const REFRESH_TOKEN_LIFETIME: number;
1985
+ /**
1986
+ * Cookie options for HttpOnly tokens (session, refresh)
1987
+ *
1988
+ * Security features:
1989
+ * - httpOnly: true — Not accessible via JavaScript (XSS protection)
1990
+ * - secure: true in production — Only sent over HTTPS
1991
+ * - sameSite: 'lax' — CSRF protection while allowing navigation
1992
+ */
1993
+ declare const SECURE_COOKIE_OPTIONS: {
1994
+ httpOnly: boolean;
1995
+ secure: boolean;
1996
+ sameSite: "lax";
1997
+ path: string;
1998
+ };
1999
+ /**
2000
+ * Cookie options for JS-readable user cookie
2001
+ *
2002
+ * This cookie contains only user info (no tokens) and enables:
2003
+ * - Client-side hydration without loading states
2004
+ * - Cross-tab sync via cookie visibility
2005
+ */
2006
+ declare const USER_COOKIE_OPTIONS: {
2007
+ httpOnly: boolean;
2008
+ secure: boolean;
2009
+ sameSite: "lax";
2010
+ path: string;
2011
+ };
2012
+ /**
2013
+ * Auth cookies data returned by getAuthCookies
2014
+ */
2015
+ interface AuthCookiesData {
2016
+ /** Access token from SESSION cookie (HttpOnly) */
2017
+ sessionToken: string | null;
2018
+ /** Refresh token from REFRESH cookie (HttpOnly) */
2019
+ refreshToken: string | null;
2020
+ /** User data from USER cookie (JS-readable) */
2021
+ user: User | null;
2022
+ /** Expiry timestamp from USER cookie */
2023
+ expiresAt: number | null;
2024
+ }
2025
+ /**
2026
+ * Get auth cookies from the request
2027
+ *
2028
+ * Used by auth() to read current auth state.
2029
+ */
2030
+ declare function getAuthCookies(namespace: string): Promise<AuthCookiesData>;
2031
+ /**
2032
+ * Set auth cookies from token response
2033
+ *
2034
+ * Sets all three cookies:
2035
+ * - SESSION: HttpOnly access token (5 min)
2036
+ * - REFRESH: HttpOnly refresh token (30 days)
2037
+ * - USER: JS-readable user data (5 min)
2038
+ *
2039
+ * @param namespace - Cookie namespace (e.g., 'sylphx_prod')
2040
+ * @param response - Token response from auth endpoint
2041
+ * @param options - Optional: custom expiresIn override
2042
+ */
2043
+ declare function setAuthCookies(namespace: string, response: TokenResponse, options?: {
2044
+ sessionLifetime?: number;
2045
+ }): Promise<void>;
2046
+ /**
2047
+ * Clear all auth cookies
2048
+ *
2049
+ * Call on sign out to remove all auth state.
2050
+ */
2051
+ declare function clearAuthCookies(namespace: string): Promise<void>;
2052
+ /**
2053
+ * Check if session is expired
2054
+ *
2055
+ * Uses a 30 second buffer to account for network latency.
2056
+ */
2057
+ declare function isSessionExpired(namespace: string): Promise<boolean>;
2058
+ /**
2059
+ * Check if we have a refresh token (can potentially refresh)
2060
+ */
2061
+ declare function hasRefreshToken(namespace: string): Promise<boolean>;
2062
+
2063
+ /**
2064
+ * Set auth cookies on a NextResponse (for middleware use)
2065
+ *
2066
+ * Unlike setAuthCookies() which uses next/headers, this works with NextResponse.
2067
+ * Use this in middleware where you need to modify cookies on the response.
2068
+ */
2069
+ declare function setAuthCookiesMiddleware(response: NextResponse, namespace: string, tokens: TokenResponse): void;
2070
+ /**
2071
+ * Clear auth cookies on a NextResponse (for middleware use)
2072
+ */
2073
+ declare function clearAuthCookiesMiddleware(response: NextResponse, namespace: string): void;
2074
+ /**
2075
+ * Parse user cookie value (for client-side use)
2076
+ */
2077
+ declare function parseUserCookie(value: string): UserCookieData | null;
2078
+
2079
+ /**
2080
+ * Token expiry buffer in milliseconds (30 seconds)
2081
+ *
2082
+ * Refresh tokens this many milliseconds BEFORE they expire
2083
+ * to account for network latency and clock skew.
2084
+ */
2085
+ declare const TOKEN_EXPIRY_BUFFER_MS = 30000;
2086
+ /** Session token lifetime in milliseconds (for React Query staleTime) */
2087
+ declare const SESSION_TOKEN_LIFETIME_MS: number;
2088
+
2089
+ export { type AuthCookiesData, type AuthResult, REFRESH_TOKEN_LIFETIME, SECURE_COOKIE_OPTIONS, SESSION_TOKEN_LIFETIME, SESSION_TOKEN_LIFETIME_MS, type SylphxMiddlewareConfig, TOKEN_EXPIRY_BUFFER_MS, USER_COOKIE_OPTIONS, type UserCookieData, auth, clearAuthCookies, clearAuthCookiesMiddleware, configureServer, createMatcher, createSylphxMiddleware, currentUser, currentUserId, getAuthCookies, getAuthorizationUrl, getCookieNames, getNamespace, getSessionToken, handleCallback, hasRefreshToken, isSessionExpired, parseUserCookie, setAuthCookies, setAuthCookiesMiddleware, signOut, syncAuthToCookies };