@nulvless/nulvless-js 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.
@@ -0,0 +1,2324 @@
1
+ /**
2
+ * Storage adapter interface used by the SDK to persist session tokens.
3
+ *
4
+ * All methods are async to support both synchronous storages (localStorage)
5
+ * and asynchronous ones (Cache Storage API, IndexedDB, etc.).
6
+ */
7
+ interface NulvlessStorage {
8
+ getItem(key: string): Promise<string | null>;
9
+ setItem(key: string, value: string): Promise<void>;
10
+ removeItem(key: string): Promise<void>;
11
+ }
12
+
13
+ type Language = 'en-US' | 'pt-BR';
14
+ interface Phone {
15
+ /** Country dial code — e.g. "+55" */
16
+ country_code: string;
17
+ /** Digits only, 6–18 chars */
18
+ number: string;
19
+ }
20
+ interface NulvlessError {
21
+ code: string;
22
+ message: string | string[];
23
+ status_code: number;
24
+ }
25
+ /**
26
+ * Every SDK method returns this type.
27
+ * Check `error` first — if null, `data` is guaranteed to be present.
28
+ */
29
+ type NulvlessResult<T> = {
30
+ data: T;
31
+ error: null;
32
+ } | {
33
+ data: null;
34
+ error: NulvlessError;
35
+ };
36
+ interface AuthOptions {
37
+ captcha_token?: string;
38
+ }
39
+ interface ClientOptions {
40
+ /** Returns the BCP 47 language tag sent on every request. Defaults to `'en-US'`. */
41
+ language?: () => Language;
42
+ /** Abort requests after this many milliseconds. */
43
+ timeout?: number;
44
+ /** Log request/response info to the console. */
45
+ debug?: boolean;
46
+ /**
47
+ * Extra headers merged into every request.
48
+ *
49
+ * Pass a function to resolve headers lazily per request — useful for
50
+ * forwarding values from a request-local context (CLS, AsyncLocalStorage,
51
+ * NestJS REQUEST, etc.) without rebuilding the client.
52
+ *
53
+ * @example Static headers
54
+ * ```ts
55
+ * createServerClient(url, sk, { headers: { 'x-app-version': '1.0.0' } })
56
+ * ```
57
+ *
58
+ * @example Per-request resolution (e.g. forwardUserHeaders from a CLS store)
59
+ * ```ts
60
+ * createServerClient(url, sk, {
61
+ * trackUser: true,
62
+ * headers: () => forwardUserHeaders(cls.get('req')),
63
+ * })
64
+ * ```
65
+ */
66
+ headers?: Record<string, string> | (() => Record<string, string>);
67
+ /**
68
+ * Renews the access token on a timer, ahead of expiry, instead of waiting
69
+ * for a request to find it expired. Defaults to `true`; turn it off when the
70
+ * host controls renewal itself. Browser clients only.
71
+ */
72
+ autoRefresh?: boolean;
73
+ /**
74
+ * When `true`, failed requests throw a `NulvlessException` instead of
75
+ * returning `{ data: null, error }`.
76
+ *
77
+ * Can be overridden per-request via `RequestOptions.throwErrors`.
78
+ */
79
+ throwErrors?: boolean;
80
+ /**
81
+ * Storage adapter for persisting session tokens.
82
+ *
83
+ * Defaults to `localStorage` in the browser and to a per-client in-memory
84
+ * store elsewhere (SSR, tests, workers).
85
+ *
86
+ * Use the built-in `Storage` adapters from `@nulvless/nulvless-js`:
87
+ * ```ts
88
+ * import { Storage } from '@nulvless/nulvless-js'
89
+ *
90
+ * createClient(url, key, { storage: Storage.Local })
91
+ * ```
92
+ *
93
+ * Only used by `createClient` (browser). Has no effect on `createServerClient`.
94
+ */
95
+ storage?: NulvlessStorage;
96
+ /**
97
+ * Custom storage keys for the browser session.
98
+ *
99
+ * - `token` — key for the active session token. Defaults to `nlv-<slug>-token`.
100
+ * - `accounts` — key for the multi-account store. Defaults to `nlv-<slug>-token-accounts`.
101
+ *
102
+ * Only used by `createClient` (browser).
103
+ */
104
+ storageKeys?: {
105
+ token?: string;
106
+ accounts?: string;
107
+ };
108
+ /**
109
+ * When `true`, enables multi-account support — the SDK stores all signed-in
110
+ * accounts and exposes `auth.add`, `auth.list`, `auth.remove`, and `auth.switch`.
111
+ *
112
+ * Defaults to `false`. Enable explicitly only when your app needs account switching.
113
+ *
114
+ * Only used by `createClient` (browser).
115
+ */
116
+ multiUser?: boolean;
117
+ /**
118
+ * When `true`, sends `nlv-user-tracking: "true"` on every request, signalling
119
+ * the auth service to collect device/browser fingerprint data for the session.
120
+ *
121
+ * In the browser (`createClient`), standard headers like `User-Agent`,
122
+ * `Origin`, and `Referer` are sent automatically by `fetch`.
123
+ *
124
+ * In the server (`createServerClient`), use `forwardUserHeaders(req)` via
125
+ * `options.headers` on each call to forward the real user's browser headers.
126
+ */
127
+ trackUser?: boolean;
128
+ }
129
+ /**
130
+ * Options for `createServerClient` / `NulvlessServerClient`.
131
+ * Identical to `ClientOptions` but without `storage` — session persistence
132
+ * is a browser-only concern and must not be used on the server.
133
+ */
134
+ type ServerClientOptions = Omit<ClientOptions, 'storage' | 'storageKeys'>;
135
+ /**
136
+ * Per-request options — override client-level config for a single call.
137
+ * Passed as the last argument to methods that support it.
138
+ *
139
+ * Lib-side toggles stay camelCase (`throwErrors`, `language`, `timeout`,
140
+ * `headers`). Backend-bound fields use snake_case (`redirect_uri`) so they
141
+ * pass through to the wire unchanged.
142
+ */
143
+ interface RequestOptions {
144
+ /** Override the language header for this request. */
145
+ language?: () => Language;
146
+ /**
147
+ * Override (or add) HTTP headers for this request. Merged over client-level headers.
148
+ *
149
+ * For lazy/context-resolved headers shared across all calls, use
150
+ * `ClientOptions.headers` (function form) instead.
151
+ */
152
+ headers?: Record<string, string>;
153
+ /** Override the `throwErrors` strategy for this request. */
154
+ throwErrors?: boolean;
155
+ /** Redirect URI passed as body/query param for OAuth and confirmation flows. */
156
+ redirect_uri?: string;
157
+ /** Abort this request after the given number of milliseconds. Overrides the client-level `timeout`. */
158
+ timeout?: number;
159
+ }
160
+
161
+ type QueryValue = string | number | boolean;
162
+ type QueryParams = Record<string, QueryValue | QueryValue[] | undefined>;
163
+ interface SendOptions {
164
+ query?: QueryParams;
165
+ /** Override or add headers for this request. Merged over client-level headers. */
166
+ headers?: Record<string, string>;
167
+ body?: unknown;
168
+ /** Override the language header for this request. */
169
+ language?: () => Language;
170
+ /** Override the throwErrors strategy for this request. */
171
+ throwErrors?: boolean;
172
+ /** Abort this request after the given number of milliseconds. Overrides the client-level timeout. */
173
+ timeout?: number;
174
+ /** Single-use sudo nonce, sent as the `nlv-sudo-nonce` header. */
175
+ nonce?: string | undefined;
176
+ /** Omit the `x-platform-key` header — for public endpoints that don't require it. */
177
+ skipApiKey?: boolean;
178
+ }
179
+ interface HttpClientConfig extends ClientOptions {
180
+ baseUrl: string;
181
+ apiKey: string;
182
+ /**
183
+ * Called when a request fails with a retryable auth error (401 or specific 403 codes).
184
+ * Should return a fresh access token, or `null` if refresh is not possible.
185
+ * The request is retried once with the new token.
186
+ *
187
+ * `deauthOnFailure` is `true` for 401/unauthorized (token is invalid — clear session
188
+ * and notify if refresh fails) and `false` for 403/forbidden_resource_access (token
189
+ * is valid but lacks the scope — refresh once to pick up new scopes, but never
190
+ * deauthenticate; surface the API error instead).
191
+ */
192
+ onTokenExpired?: (context: {
193
+ deauthOnFailure: boolean;
194
+ expiredToken?: string;
195
+ }) => Promise<string | null>;
196
+ }
197
+ declare class HttpClient {
198
+ private readonly config;
199
+ private onSudoRequired?;
200
+ constructor(config: HttpClientConfig);
201
+ /**
202
+ * Injected after construction to avoid circular dependency.
203
+ * Called when a request fails with `403 protected_action_denied`,
204
+ * indicating the user must enable sudo mode before retrying.
205
+ */
206
+ setOnSudoRequired(cb: () => void): void;
207
+ hasAuthorization(headers?: Record<string, string>): boolean;
208
+ get<T>(path: string, options?: Omit<SendOptions, 'body'>): Promise<NulvlessResult<T>>;
209
+ post<T>(path: string, body?: unknown, options?: Omit<SendOptions, 'body'>): Promise<NulvlessResult<T>>;
210
+ put<T>(path: string, body?: unknown, options?: Omit<SendOptions, 'body'>): Promise<NulvlessResult<T>>;
211
+ patch<T>(path: string, body?: unknown, options?: Omit<SendOptions, 'body'>): Promise<NulvlessResult<T>>;
212
+ delete<T>(path: string, options?: Omit<SendOptions, 'body'>): Promise<NulvlessResult<T>>;
213
+ /**
214
+ * Returns `true` when the error warrants a single token-refresh retry:
215
+ * - Any 401 on an authenticated request
216
+ * - 403 with `forbidden_access_waiting_accept` or `forbidden_resource_access` codes
217
+ */
218
+ private shouldRetryWithRefresh;
219
+ private send;
220
+ private buildUrl;
221
+ private buildHeaders;
222
+ private parseBody;
223
+ }
224
+
225
+ /**
226
+ * Single-use sudo nonce for step-up auth.
227
+ *
228
+ * Pass the code the user received from `auth.sessions.sudo()` to authorize a
229
+ * single sudo-protected call without elevating the whole session. Sent as the
230
+ * `nlv-sudo-nonce` header (never in the request body).
231
+ *
232
+ * Params of sudo-protected methods extend this; methods that take no other input
233
+ * accept it directly.
234
+ */
235
+ interface Nonce {
236
+ nonce?: string;
237
+ }
238
+ interface RevokeSessionParams extends Nonce {
239
+ id: string;
240
+ }
241
+ type OAuthProvider = 'google' | 'github' | 'gitlab' | 'bitbucket' | 'facebook' | 'linked_in' | 'discord' | 'twitch' | 'slack' | 'azure' | 'apple';
242
+ type UserGender = 'male' | 'female' | 'other' | 'prefer_not_to_say';
243
+ interface UserProfile {
244
+ name?: string;
245
+ biography?: string;
246
+ gender?: UserGender;
247
+ avatar_uri?: string;
248
+ /** ISO date — YYYY-MM-DD */
249
+ date_of_birth?: string;
250
+ }
251
+ interface User {
252
+ id: string;
253
+ email?: string;
254
+ phone?: Phone;
255
+ username?: string;
256
+ profile?: UserProfile;
257
+ confirmed_at?: string;
258
+ is_confirmed?: boolean;
259
+ banned_at?: string;
260
+ is_banned?: boolean;
261
+ last_sign_in_at?: string;
262
+ identities?: Identity[];
263
+ metadata?: Record<string, string | number>;
264
+ created_at?: string;
265
+ updated_at?: string;
266
+ }
267
+ /** At least one of `email`, `phone`, or `username` must be provided. */
268
+ interface SignUpParams {
269
+ email?: string;
270
+ phone?: Phone;
271
+ /** 3–30 chars: letters, numbers, dots, underscores */
272
+ username?: string;
273
+ profile?: UserProfile;
274
+ password: string;
275
+ options?: AuthOptions;
276
+ }
277
+ /** At least one of `email`, `phone`, or `username` must be provided. */
278
+ interface SignInParams {
279
+ email?: string;
280
+ phone?: Phone;
281
+ username?: string;
282
+ password: string;
283
+ options?: AuthOptions;
284
+ }
285
+ /** At least one of `email` or `phone` must be provided. */
286
+ interface SignInWithOTPParams {
287
+ email?: string;
288
+ phone?: Phone;
289
+ options?: AuthOptions;
290
+ }
291
+ /** At least one of `email`, `phone`, or `username` must be provided. */
292
+ interface LookupParams {
293
+ email?: string;
294
+ phone?: Phone;
295
+ username?: string;
296
+ options?: AuthOptions;
297
+ }
298
+ interface RefreshTokenParams {
299
+ refresh_token: string;
300
+ }
301
+ interface RecoverParams {
302
+ email: string;
303
+ options?: AuthOptions;
304
+ }
305
+ interface ResetPasswordParams {
306
+ /** Token received via the recovery link/email. */
307
+ token: string;
308
+ password: string;
309
+ }
310
+ type TokenType = 'bearer';
311
+ type AssuranceLevel = 'aal1' | 'aal2' | 'aal3';
312
+ type MFAMethod = 'totp' | 'sms_otp' | 'email_otp' | 'recovery_codes';
313
+ type ChallengeSubject = 'sign_in_with_otp' | 'verify_pending_user' | 'sign_up' | 'add_email' | 'add_phone' | 'mfa' | 'sudo';
314
+ /** Methods accepted to elevate a session to sudo. Subset of `MFAMethod`. */
315
+ type SudoMethod = 'totp' | 'email_otp' | 'sms_otp';
316
+ interface Challenge {
317
+ /** MFA method to present first to the user. */
318
+ preferred: MFAMethod;
319
+ /** Masked identifier shown to the user — e.g. "u***@example.com". */
320
+ identifier?: string;
321
+ factors: AuthMethod[];
322
+ subject: ChallengeSubject;
323
+ /** Short-lived token used to continue the challenge flow. */
324
+ token: string;
325
+ expires_in: number;
326
+ }
327
+ interface VerifyChallengeParams {
328
+ /** Short-lived token from the `Challenge` object. */
329
+ token: string;
330
+ /** OTP code, TOTP code, or recovery code entered by the user. */
331
+ code: string;
332
+ }
333
+ interface ChangeChallengeParams {
334
+ /** Short-lived token from the current `Challenge`. */
335
+ token: string;
336
+ /** MFA method to switch to. */
337
+ type: MFAMethod;
338
+ }
339
+ type AuthFactorStatus = 'configured' | 'not_configured';
340
+ interface AuthMethod {
341
+ id?: string;
342
+ /** MFA method, sign-in method, or OAuth provider. */
343
+ type: MFAMethod | SignInMethod | OAuthProvider;
344
+ name?: string;
345
+ status: AuthFactorStatus;
346
+ identifier?: string;
347
+ created_at?: string;
348
+ updated_at?: string;
349
+ }
350
+ interface AuthMethods {
351
+ sign_in: AuthMethod[];
352
+ mfas: AuthMethod[];
353
+ oauth: AuthMethod[];
354
+ }
355
+ /** Returned by `auth.factors.enroll`. Pass `token` + `code` to `auth.factors.enable`. */
356
+ interface FactorEnrollment {
357
+ type: MFAMethod;
358
+ /** Short-lived token to pass to `factors.enable`. */
359
+ token: string;
360
+ /** TOTP shared secret for manual entry. */
361
+ secret?: string;
362
+ /** TOTP provisioning URL (useful for generating a QR code). */
363
+ url?: string;
364
+ }
365
+ interface EnableFactorParams {
366
+ /** Token received from `factors.enroll`. */
367
+ token: string;
368
+ /** OTP or TOTP code to confirm enrollment. */
369
+ code: string;
370
+ }
371
+ interface EnrollFactorParams extends Nonce {
372
+ type: MFAMethod;
373
+ name?: string;
374
+ }
375
+ interface UnenrollFactorParams extends Nonce {
376
+ id: string;
377
+ }
378
+ type IdentityType = 'email' | 'phone' | 'oauth';
379
+ interface Identity {
380
+ id: string;
381
+ type: IdentityType;
382
+ provider_id?: string;
383
+ provider?: OAuthProvider;
384
+ identifier: string;
385
+ data?: Record<string, unknown>;
386
+ created_at?: string;
387
+ updated_at?: string;
388
+ }
389
+ interface AddEmailIdentityParams extends Nonce {
390
+ email: string;
391
+ }
392
+ interface AddPhoneIdentityParams extends Nonce {
393
+ phone: Phone;
394
+ }
395
+ interface UpdateIdentityParams extends Nonce {
396
+ id: string;
397
+ primary: boolean;
398
+ }
399
+ interface RemoveIdentityParams extends Nonce {
400
+ id: string;
401
+ }
402
+ interface SendOTPToUpdateEmailParams extends Nonce {
403
+ email: string;
404
+ }
405
+ interface SendOTPToUpdatePhoneParams extends Nonce {
406
+ phone: Phone;
407
+ }
408
+ type GrantStatus = 'granted' | 'invited' | 'requested' | 'blocked';
409
+ interface Role {
410
+ id: string;
411
+ name: string;
412
+ description?: string;
413
+ key: string;
414
+ context: string;
415
+ scopes: string[];
416
+ cannot_scopes?: string[];
417
+ }
418
+ interface Grant {
419
+ id: string;
420
+ status: GrantStatus;
421
+ name?: string;
422
+ email?: string;
423
+ resource: string;
424
+ granted_to?: User;
425
+ role?: Role;
426
+ scopes: string[];
427
+ cannot_scopes: string[];
428
+ created_at?: string;
429
+ updated_at?: string;
430
+ }
431
+ /** Grouped grants returned by `auth.grants.getMembers`. */
432
+ interface GrantMembers {
433
+ granted: Grant[];
434
+ invitations: Grant[];
435
+ requesteds: Grant[];
436
+ blockeds: Grant[];
437
+ }
438
+ interface Invite {
439
+ email: string;
440
+ role_id?: string;
441
+ scopes?: string[];
442
+ cannot_scopes?: string[];
443
+ }
444
+ interface InviteParams extends Nonce {
445
+ invites: Invite[];
446
+ resource: string;
447
+ message?: string;
448
+ }
449
+ interface RevokeGrantParams extends Nonce {
450
+ id: string;
451
+ }
452
+ interface BlockGrantParams extends Nonce {
453
+ id: string;
454
+ }
455
+ interface UpdateGrantParams extends Nonce {
456
+ scopes?: string[];
457
+ cannot_scopes?: string[];
458
+ }
459
+ interface LeaveGrantParams extends Nonce {
460
+ id: string;
461
+ }
462
+ interface ChangePasswordParams extends Nonce {
463
+ password: string;
464
+ new_password: string;
465
+ }
466
+ interface PlatformInfo {
467
+ id: string;
468
+ name: string;
469
+ slug: string;
470
+ }
471
+ type PaginationSort = 'asc' | 'desc';
472
+ interface Paginated<T> {
473
+ items: T[];
474
+ page?: number;
475
+ page_size?: number;
476
+ total?: number;
477
+ sort?: PaginationSort;
478
+ }
479
+ interface PaginateUsersParams {
480
+ page?: number;
481
+ page_size?: number;
482
+ sort?: PaginationSort;
483
+ id?: string;
484
+ email?: string;
485
+ username?: string;
486
+ phone?: string;
487
+ is_confirmed?: boolean;
488
+ is_banned?: boolean;
489
+ }
490
+ interface PaginateGrantsParams {
491
+ page?: number;
492
+ page_size?: number;
493
+ sort?: PaginationSort;
494
+ resource?: string;
495
+ context?: string;
496
+ granted_to_user_id?: string;
497
+ role_id?: string;
498
+ }
499
+ interface SetGrantParams {
500
+ resource: string;
501
+ granted_to_user_id: string;
502
+ role_id?: string;
503
+ scopes?: string[];
504
+ cannot_scopes?: string[];
505
+ }
506
+ interface CreateRoleParams {
507
+ name: string;
508
+ description?: string;
509
+ key: string;
510
+ context: string;
511
+ scopes: string[];
512
+ cannot_scopes?: string[];
513
+ }
514
+ interface UpdateRoleParams {
515
+ name?: string;
516
+ description?: string;
517
+ scopes?: string[];
518
+ cannot_scopes?: string[];
519
+ }
520
+ interface AdminCreateUserParams {
521
+ email?: string;
522
+ phone?: Phone;
523
+ username?: string;
524
+ profile?: UserProfile;
525
+ password?: string;
526
+ metadata?: Record<string, string | number>;
527
+ }
528
+ interface AdminUpdateUserParams {
529
+ username?: string;
530
+ profile?: UserProfile;
531
+ metadata?: Record<string, string | number | null>;
532
+ }
533
+ /**
534
+ * Returned by `signUp`, `signIn`, `verifyChallenge`, and `refreshToken`.
535
+ *
536
+ * Check in this order:
537
+ * 1. `access_token` present → authenticated.
538
+ * 2. `challenge` present → MFA/OTP step required — call `verifyChallenge`.
539
+ * 3. Only `user` present → pending confirmation (signUp only).
540
+ */
541
+ interface Authenticated {
542
+ token_type?: TokenType;
543
+ access_token?: string;
544
+ refresh_token?: string;
545
+ expires_in?: number;
546
+ user?: User;
547
+ challenge?: Challenge;
548
+ /**
549
+ * Present only when this authentication elevated the session to sudo
550
+ * (e.g. resolving a sudo challenge via `challenges.verify`).
551
+ */
552
+ sudo?: {
553
+ /** Seconds until sudo mode expires. */
554
+ expires_in: number;
555
+ };
556
+ }
557
+ type SignInMethod = 'email_password' | 'username_password' | 'phone_password' | 'email_otp' | 'sms_otp';
558
+ type ConfirmationType = 'none' | 'link' | 'otp';
559
+ type VerifyReason = 'signin_with_otp' | 'verify_after_with_link' | 'requires_otp_for_registration' | 'waiting_confirmation_link' | 'confirmation_link_resent' | 'no_confirmation_required';
560
+ interface LookupMatch {
561
+ exists: boolean;
562
+ method: SignInMethod;
563
+ allowed_methods: SignInMethod[];
564
+ confirmation_type: ConfirmationType;
565
+ reason?: VerifyReason;
566
+ }
567
+ /**
568
+ * Returned by `lookup`.
569
+ * If `challenge` is present, proceed to `verifyChallenge`.
570
+ */
571
+ interface LookupResult {
572
+ lookup: LookupMatch;
573
+ challenge?: Challenge;
574
+ }
575
+ type SignOutScope = 'global' | 'local' | 'others';
576
+ interface VerifyParams {
577
+ resource?: string;
578
+ scopes?: string[];
579
+ roles?: string[];
580
+ reject_assurance_level_error?: boolean;
581
+ }
582
+ interface Verified {
583
+ user: {
584
+ id: string;
585
+ };
586
+ session: {
587
+ id: string;
588
+ amr: Array<{
589
+ method: string;
590
+ timestamp?: number;
591
+ }>;
592
+ scopes: string[];
593
+ assurance_level: AssuranceLevel;
594
+ /** Whether sudo mode is currently active for the session. */
595
+ sudo?: boolean;
596
+ /** Date-time until sudo mode expires. Null/absent when not elevated. */
597
+ sudo_expires_at?: string | null;
598
+ };
599
+ }
600
+ interface SessionFingerPrint {
601
+ hash?: string;
602
+ ip?: string;
603
+ browser?: {
604
+ name?: string;
605
+ version?: string;
606
+ };
607
+ engine?: {
608
+ name?: string;
609
+ version?: string;
610
+ };
611
+ cpu?: {
612
+ architecture?: string;
613
+ };
614
+ os?: {
615
+ name?: string;
616
+ version?: string;
617
+ };
618
+ device?: {
619
+ name?: string;
620
+ type?: string;
621
+ };
622
+ location?: {
623
+ country?: string;
624
+ region?: string;
625
+ timezone?: string;
626
+ city?: string;
627
+ position?: {
628
+ lat?: number;
629
+ lng?: number;
630
+ };
631
+ };
632
+ }
633
+ interface Session {
634
+ id: string;
635
+ finger_print?: SessionFingerPrint;
636
+ amr: Array<{
637
+ method: string;
638
+ timestamp?: number;
639
+ }>;
640
+ scopes: string[];
641
+ aal: AssuranceLevel;
642
+ invalidated: boolean;
643
+ is_current_session: boolean;
644
+ created_at: string;
645
+ updated_at: string;
646
+ expires_at: string;
647
+ sudo_expires_at?: string | null;
648
+ }
649
+ type OAuthAppType = 'public' | 'confidential';
650
+ type OAuthAppTokenEndpointAuthMethod = 'none' | 'client_secret_basic' | 'client_secret_post';
651
+ type OAuthAppGrantType = 'authorization_code' | 'refresh_token';
652
+ /** A registered third-party application (OAuth client) of the project. */
653
+ interface OAuthApp {
654
+ id: string;
655
+ client_id: string;
656
+ client_type: OAuthAppType;
657
+ token_endpoint_auth_method: OAuthAppTokenEndpointAuthMethod;
658
+ redirect_uris: string[];
659
+ grant_types: OAuthAppGrantType[];
660
+ client_name?: string;
661
+ client_uri?: string;
662
+ logo_uri?: string;
663
+ /** Only present right after create/regenerate (confidential apps). */
664
+ client_secret?: string;
665
+ created_at?: string;
666
+ updated_at?: string;
667
+ }
668
+ interface RegisterOAuthAppParams {
669
+ client_type: OAuthAppType;
670
+ token_endpoint_auth_method: OAuthAppTokenEndpointAuthMethod;
671
+ redirect_uris: string[];
672
+ grant_types: OAuthAppGrantType[];
673
+ client_name?: string;
674
+ client_uri?: string;
675
+ logo_uri?: string;
676
+ }
677
+ /** `client_type` is immutable; the secret rotates via `regenerateSecret`. */
678
+ interface UpdateOAuthAppParams {
679
+ token_endpoint_auth_method?: OAuthAppTokenEndpointAuthMethod;
680
+ redirect_uris?: string[];
681
+ grant_types?: OAuthAppGrantType[];
682
+ client_name?: string;
683
+ client_uri?: string;
684
+ logo_uri?: string;
685
+ }
686
+ /** Query parameters for the `/oauth/authorize` redirect (PKCE required, S256). */
687
+ interface OAuthAuthorizeParams {
688
+ client_id: string;
689
+ redirect_uri: string;
690
+ code_challenge: string;
691
+ code_challenge_method: 'S256';
692
+ response_type?: 'code';
693
+ scope?: string;
694
+ state?: string;
695
+ resource?: string;
696
+ nonce?: string;
697
+ }
698
+ interface ExchangeOAuthCodeParams {
699
+ code: string;
700
+ code_verifier: string;
701
+ redirect_uri?: string;
702
+ client_id?: string;
703
+ /** Only for confidential clients. */
704
+ client_secret?: string;
705
+ resource?: string;
706
+ }
707
+ interface RefreshOAuthTokenParams {
708
+ refresh_token: string;
709
+ client_id?: string;
710
+ /** Only for confidential clients. */
711
+ client_secret?: string;
712
+ }
713
+ interface OAuthTokenResponse {
714
+ access_token: string;
715
+ token_type: string;
716
+ expires_in: number;
717
+ refresh_token?: string;
718
+ scope: string;
719
+ id_token?: string;
720
+ }
721
+ interface OAuthAuthorization {
722
+ client: {
723
+ id: string;
724
+ name?: string;
725
+ logo_uri?: string;
726
+ uri?: string;
727
+ };
728
+ scope: string[];
729
+ auto_approved: boolean;
730
+ redirect?: {
731
+ uri: string;
732
+ };
733
+ }
734
+ type OAuthConsentAction = 'approve' | 'deny';
735
+ interface OAuthConsentResult {
736
+ redirect: {
737
+ uri: string;
738
+ };
739
+ }
740
+ interface OAuthUserInfo {
741
+ sub: string;
742
+ email?: string;
743
+ email_verified?: boolean;
744
+ name?: string;
745
+ picture?: string;
746
+ preferred_username?: string;
747
+ phone_number?: string;
748
+ phone_number_verified?: boolean;
749
+ }
750
+ /** An app the authenticated user has authorized. */
751
+ interface OAuthUserGrant {
752
+ client: {
753
+ id: string;
754
+ name?: string;
755
+ logo_uri?: string;
756
+ uri?: string;
757
+ };
758
+ scopes: string[];
759
+ granted_at: string;
760
+ }
761
+ interface OAuthDiscovery {
762
+ issuer: string;
763
+ authorization_endpoint: string;
764
+ token_endpoint: string;
765
+ userinfo_endpoint: string;
766
+ jwks_uri: string;
767
+ registration_endpoint: string;
768
+ response_types_supported: string[];
769
+ subject_types_supported: string[];
770
+ id_token_signing_alg_values_supported: string[];
771
+ scopes_supported: string[];
772
+ token_endpoint_auth_methods_supported: string[];
773
+ grant_types_supported: string[];
774
+ code_challenge_methods_supported: string[];
775
+ }
776
+ interface OAuthJWKS {
777
+ keys: Array<Record<string, unknown>>;
778
+ }
779
+
780
+ interface StoredSession {
781
+ access_token: string;
782
+ refresh_token?: string;
783
+ /** Unix timestamp (ms) when the access token expires. */
784
+ expires_at: number;
785
+ token_type: string;
786
+ /** Full user object from the auth response, when provided by the server. */
787
+ user?: User;
788
+ }
789
+
790
+ type RefreshFn = (refresh_token: string) => Promise<NulvlessResult<Authenticated>>;
791
+ type TokenRefreshedCb = (auth: Authenticated) => void;
792
+ /** Receives the session that could not be recovered (null when none was stored). */
793
+ type UnauthorizedCb = (session: StoredSession | null) => void;
794
+ declare class SessionManager {
795
+ private readonly storage;
796
+ private refreshFn?;
797
+ private onTokenRefreshed?;
798
+ private onUnauthorized?;
799
+ private readonly sessionKey;
800
+ private readonly lockName;
801
+ private inFlight;
802
+ private ticker;
803
+ private onVisibilityChange;
804
+ constructor(storage: NulvlessStorage, sessionKey: string);
805
+ /**
806
+ * Injected by `AuthClient` after construction to avoid circular dependency.
807
+ * Called automatically when the access token is about to expire.
808
+ */
809
+ setRefreshFn(fn: RefreshFn): void;
810
+ /** Called after a successful automatic token refresh. */
811
+ setOnTokenRefreshed(cb: TokenRefreshedCb): void;
812
+ /**
813
+ * Called when the SDK cannot recover the session:
814
+ * - no refresh token present, or
815
+ * - the refresh request was refused by the server.
816
+ */
817
+ setOnUnauthorized(cb: UnauthorizedCb): void;
818
+ save(auth: Authenticated): Promise<void>;
819
+ get(): Promise<StoredSession | null>;
820
+ clear(): Promise<void>;
821
+ private expiresSoon;
822
+ private refresh;
823
+ private runExclusiveRefresh;
824
+ private refreshHoldingLock;
825
+ private callRefreshFn;
826
+ /**
827
+ * Forces a token refresh regardless of expiry.
828
+ * Used for reactive refresh after a 401/403 response.
829
+ *
830
+ * Returns the new access token, or `null` if refresh fails.
831
+ *
832
+ * `deauthOnFailure` (default `true`) controls side effects when the refresh
833
+ * itself is refused: clearing the stored session and invoking `onUnauthorized`.
834
+ * Pass `false` for soft refreshes (e.g. 403/forbidden_resource_access) where
835
+ * the session must remain intact so the caller can surface the API error.
836
+ */
837
+ forceRefresh(options?: {
838
+ deauthOnFailure?: boolean;
839
+ expiredToken?: string;
840
+ }): Promise<string | null>;
841
+ /**
842
+ * Returns a valid access token, refreshing it automatically if it is
843
+ * expired or about to expire (within the refresh margin).
844
+ *
845
+ * Returns `null` when there is no session or the refresh fails.
846
+ */
847
+ getValidToken(): Promise<string | null>;
848
+ startAutoRefresh(): void;
849
+ stopAutoRefresh(): void;
850
+ private tick;
851
+ }
852
+
853
+ type BearerResolution = {
854
+ ok: true;
855
+ headers: Record<string, string>;
856
+ } | {
857
+ ok: false;
858
+ error: NulvlessError;
859
+ };
860
+ declare abstract class AuthSubClient {
861
+ protected readonly http: HttpClient;
862
+ protected readonly getToken: () => Promise<string | null>;
863
+ constructor(http: HttpClient, getToken: () => Promise<string | null>);
864
+ protected bearer(options?: RequestOptions): Promise<BearerResolution>;
865
+ }
866
+
867
+ /**
868
+ * MFA factor management.
869
+ *
870
+ * Available on both `createClient` (browser) and `createServerClient` (server).
871
+ *
872
+ * All methods require authentication. Pass `options.headers.Authorization` on
873
+ * the server, or rely on the configured storage for automatic token injection.
874
+ */
875
+ declare class FactorsClient extends AuthSubClient {
876
+ /**
877
+ * Lists all configured MFA factors for the authenticated user.
878
+ */
879
+ list(options?: RequestOptions): Promise<NulvlessResult<AuthMethod[]>>;
880
+ /**
881
+ * Returns the user's recovery codes.
882
+ *
883
+ * Requires sudo: `MANAGE_MFA`.
884
+ */
885
+ getRecoveryCodes(params?: Nonce, options?: RequestOptions): Promise<NulvlessResult<{
886
+ codes: string[];
887
+ }>>;
888
+ /**
889
+ * Deletes (invalidates) the user's recovery codes.
890
+ *
891
+ * Requires sudo: `MANAGE_MFA`.
892
+ */
893
+ deleteRecoveryCodes(params?: Nonce, options?: RequestOptions): Promise<NulvlessResult<null>>;
894
+ /**
895
+ * Begins enrolling a new MFA factor. Returns credentials needed to configure
896
+ * the factor on the user's device.
897
+ *
898
+ * For TOTP: use `secret` for manual entry or `url` to generate a QR code.
899
+ *
900
+ * After the user configures their device, call `enable` with the `token` and
901
+ * the first OTP code to activate the factor.
902
+ *
903
+ * Requires sudo: `MANAGE_MFA`.
904
+ *
905
+ * @example
906
+ * const { data } = await nulvless.auth.factors.enroll({ type: 'totp', name: 'My Authenticator' })
907
+ * // data.url → QR code provisioning URL
908
+ * // data.secret → manual entry secret
909
+ * // data.token → pass to factors.enable
910
+ */
911
+ enroll(params: EnrollFactorParams, options?: RequestOptions): Promise<NulvlessResult<FactorEnrollment>>;
912
+ /**
913
+ * Activates a pending factor enrollment by confirming the first OTP code.
914
+ *
915
+ * Pass the `token` from `enroll` and the code generated by the user's device.
916
+ */
917
+ enable(params: EnableFactorParams, options?: RequestOptions): Promise<NulvlessResult<null>>;
918
+ /**
919
+ * Unenrolls (removes) an MFA factor by its ID.
920
+ *
921
+ * Use `factors.list()` to retrieve the factor `id` before calling this.
922
+ * Returns the removed factor.
923
+ *
924
+ * Requires sudo: `MANAGE_MFA`.
925
+ *
926
+ * @example
927
+ * const { data: factors } = await nulvless.auth.factors.list()
928
+ * const totp = factors?.find(f => f.type === 'totp')
929
+ * if (totp?.id) await nulvless.auth.factors.unenroll({ id: totp.id })
930
+ */
931
+ unenroll(params: UnenrollFactorParams, options?: RequestOptions): Promise<NulvlessResult<AuthMethod>>;
932
+ }
933
+
934
+ /**
935
+ * Current-user management.
936
+ *
937
+ * Available on both `createClient` (browser) and `createServerClient` (server).
938
+ *
939
+ * All methods require authentication. Pass `options.headers.Authorization` on
940
+ * the server, or rely on the configured storage for automatic token injection.
941
+ */
942
+ declare class UsersClient extends AuthSubClient {
943
+ /**
944
+ * Returns the authenticated user's full profile.
945
+ */
946
+ me(options?: RequestOptions): Promise<NulvlessResult<User>>;
947
+ /**
948
+ * Updates the authenticated user's profile fields.
949
+ *
950
+ * Omit fields to leave them unchanged.
951
+ */
952
+ update(params: {
953
+ username?: string;
954
+ profile?: UserProfile;
955
+ }, options?: RequestOptions): Promise<NulvlessResult<User>>;
956
+ /**
957
+ * Lists all identities (email, phone, OAuth) linked to the authenticated user.
958
+ *
959
+ * @param type Filter by identity type: `'email'`, `'phone'`, or `'oauth'`.
960
+ */
961
+ getIdentities(type?: IdentityType, options?: RequestOptions): Promise<NulvlessResult<Identity[]>>;
962
+ /**
963
+ * Initiates adding a new email identity. Sends an OTP to the provided address.
964
+ *
965
+ * Complete the flow with `verifyIdentity`.
966
+ *
967
+ * Requires sudo: `MANAGE_IDENTITIES`.
968
+ */
969
+ addEmailIdentity(params: AddEmailIdentityParams, options?: RequestOptions): Promise<NulvlessResult<Challenge>>;
970
+ /**
971
+ * Initiates adding a new phone identity. Sends an OTP to the provided number.
972
+ *
973
+ * Complete the flow with `verifyIdentity`.
974
+ *
975
+ * Requires sudo: `MANAGE_IDENTITIES`.
976
+ */
977
+ addPhoneIdentity(params: AddPhoneIdentityParams, options?: RequestOptions): Promise<NulvlessResult<Challenge>>;
978
+ /**
979
+ * Confirms an identity addition by submitting the OTP received via
980
+ * `addEmailIdentity` or `addPhoneIdentity`.
981
+ */
982
+ verifyIdentity(params: VerifyChallengeParams, options?: RequestOptions): Promise<NulvlessResult<User>>;
983
+ /**
984
+ * Updates an identity — currently used to set an identity as primary.
985
+ *
986
+ * Requires sudo: `MANAGE_IDENTITIES`.
987
+ */
988
+ updateIdentity(params: UpdateIdentityParams, options?: RequestOptions): Promise<NulvlessResult<User>>;
989
+ /**
990
+ * Unlinks (removes) an identity from the authenticated user.
991
+ *
992
+ * Requires sudo: `MANAGE_IDENTITIES`.
993
+ */
994
+ removeIdentity(params: RemoveIdentityParams, options?: RequestOptions): Promise<NulvlessResult<Identity>>;
995
+ /**
996
+ * Sends an OTP to the new email address to initiate an email change.
997
+ *
998
+ * Complete the flow with `confirmEmailUpdate`.
999
+ *
1000
+ * Requires sudo: `MANAGE_CREDENTIALS`.
1001
+ */
1002
+ sendOTPToUpdateEmail(params: SendOTPToUpdateEmailParams, options?: RequestOptions): Promise<NulvlessResult<{
1003
+ token: string;
1004
+ }>>;
1005
+ /**
1006
+ * Confirms an email change by submitting the OTP received via `sendOTPToUpdateEmail`.
1007
+ */
1008
+ confirmEmailUpdate(params: VerifyChallengeParams, options?: RequestOptions): Promise<NulvlessResult<User>>;
1009
+ /**
1010
+ * Sends an OTP to the new phone number to initiate a phone change.
1011
+ *
1012
+ * Complete the flow with `confirmPhoneUpdate`.
1013
+ *
1014
+ * Requires sudo: `MANAGE_CREDENTIALS`.
1015
+ */
1016
+ sendOTPToUpdatePhone(params: SendOTPToUpdatePhoneParams, options?: RequestOptions): Promise<NulvlessResult<{
1017
+ token: string;
1018
+ }>>;
1019
+ /**
1020
+ * Confirms a phone change by submitting the OTP received via `sendOTPToUpdatePhone`.
1021
+ */
1022
+ confirmPhoneUpdate(params: VerifyChallengeParams, options?: RequestOptions): Promise<NulvlessResult<User>>;
1023
+ }
1024
+
1025
+ /**
1026
+ * Active session management for the authenticated user.
1027
+ *
1028
+ * Available on both `createClient` (browser) and `createServerClient` (server).
1029
+ *
1030
+ * All methods require authentication. Pass `options.headers.Authorization` on
1031
+ * the server, or rely on the configured storage for automatic token injection.
1032
+ */
1033
+ declare class SessionsClient extends AuthSubClient {
1034
+ private readonly persist;
1035
+ constructor(http: HttpClient, getToken: () => Promise<string | null>, persist: (result: NulvlessResult<Authenticated>) => Promise<NulvlessResult<Authenticated>>);
1036
+ /**
1037
+ * Returns all active sessions for the authenticated user across all devices.
1038
+ * The current session is marked with `is_current_session: true`.
1039
+ */
1040
+ list(options?: RequestOptions): Promise<NulvlessResult<Session[]>>;
1041
+ /**
1042
+ * Revokes (invalidates) a specific session by its ID.
1043
+ *
1044
+ * Use `auth.getSession()` to get the current session ID.
1045
+ *
1046
+ * Requires sudo: `MANAGE_SESSIONS`.
1047
+ */
1048
+ revoke(params: RevokeSessionParams, options?: RequestOptions): Promise<NulvlessResult<null>>;
1049
+ /**
1050
+ * Starts a sudo elevation by requesting a verification challenge.
1051
+ *
1052
+ * The available methods are derived from what the user has (TOTP if active,
1053
+ * email OTP, SMS OTP). Pass `method` to request a specific one; if omitted and
1054
+ * the user has a single method it is emitted automatically, otherwise an empty
1055
+ * challenge is returned so the user can pick which one to send.
1056
+ *
1057
+ * Prompt the user for the code, then call `sudoVerify({ code })` to complete
1058
+ * the elevation. The verify response carries `sudo.expires_in` (seconds until
1059
+ * sudo mode expires) alongside the refreshed session tokens.
1060
+ *
1061
+ * @example
1062
+ * const { data } = await nulvless.auth.sessions.sudo() // or sudo('email_otp')
1063
+ * // prompt the user for the code, then call sudoVerify({ code })
1064
+ */
1065
+ sudo(method?: SudoMethod, options?: RequestOptions): Promise<NulvlessResult<{
1066
+ challenge: Challenge;
1067
+ }>>;
1068
+ /**
1069
+ * Completes a sudo elevation started by `sudo()`. Submit the `code` the user
1070
+ * received (or read from their authenticator) — the pending sudo challenge is
1071
+ * resolved by the current session, so no challenge token is needed.
1072
+ *
1073
+ * On success the session is re-issued with sudo mode active and stored
1074
+ * automatically; `data.sudo.expires_in` carries the seconds until it expires.
1075
+ *
1076
+ * @example
1077
+ * const { data } = await nulvless.auth.sessions.sudoVerify({ code })
1078
+ * // data.sudo?.expires_in → 300
1079
+ */
1080
+ sudoVerify(params: {
1081
+ code: string;
1082
+ }, options?: RequestOptions): Promise<NulvlessResult<Authenticated>>;
1083
+ /**
1084
+ * Verifies that sudo mode is currently active for the session.
1085
+ *
1086
+ * Returns `204 No Content` on success. Returns an error if sudo is not active.
1087
+ *
1088
+ * @example
1089
+ * const { error } = await nulvless.auth.sessions.checkSudo()
1090
+ * if (error) {
1091
+ * // Start the sudo flow: sessions.sudo() → sessions.sudoVerify
1092
+ * }
1093
+ */
1094
+ checkSudo(params?: Nonce, options?: RequestOptions): Promise<NulvlessResult<null>>;
1095
+ }
1096
+
1097
+ /**
1098
+ * Account security operations (password).
1099
+ *
1100
+ * Available on both `createClient` (browser) and `createServerClient` (server).
1101
+ *
1102
+ * All methods require authentication. Pass `options.headers.Authorization` on
1103
+ * the server, or rely on the configured storage for automatic token injection.
1104
+ */
1105
+ declare class SecurityClient extends AuthSubClient {
1106
+ /**
1107
+ * Changes the authenticated user's password.
1108
+ *
1109
+ * @example
1110
+ * await nulvless.auth.security.changePassword({
1111
+ * password: 'current-password',
1112
+ * new_password: 'new-password',
1113
+ * })
1114
+ */
1115
+ changePassword(params: ChangePasswordParams, options?: RequestOptions): Promise<NulvlessResult<null>>;
1116
+ }
1117
+
1118
+ /**
1119
+ * Challenge lifecycle — create, inspect, switch method, and verify.
1120
+ *
1121
+ * Mirrors the `/challenges` resource. Used by MFA, OTP sign-in, sign-up
1122
+ * confirmation and step-up (sudo) flows.
1123
+ *
1124
+ * Available on both `createClient` (browser) and `createServerClient` (server).
1125
+ */
1126
+ declare class ChallengesClient extends AuthSubClient {
1127
+ private readonly persist;
1128
+ constructor(http: HttpClient, getToken: () => Promise<string | null>, persist: (result: NulvlessResult<Authenticated>) => Promise<NulvlessResult<Authenticated>>);
1129
+ /**
1130
+ * Creates a verification challenge for the given MFA method (step-up).
1131
+ *
1132
+ * Requires an authenticated session. Prompt the user for the code, then call
1133
+ * `verify({ token, code })`.
1134
+ *
1135
+ * @example
1136
+ * const { data } = await nulvless.auth.challenges.create('totp')
1137
+ */
1138
+ create(targetType: MFAMethod, options?: RequestOptions): Promise<NulvlessResult<{
1139
+ challenge: Challenge;
1140
+ }>>;
1141
+ /**
1142
+ * Retrieves the current state of a challenge by its token.
1143
+ */
1144
+ get(token: string, options?: RequestOptions): Promise<NulvlessResult<Challenge>>;
1145
+ /**
1146
+ * Switches the preferred MFA method for an ongoing challenge.
1147
+ *
1148
+ * @example
1149
+ * const { data } = await nulvless.auth.challenges.change({ token, type: 'totp' })
1150
+ */
1151
+ change(params: ChangeChallengeParams, options?: RequestOptions): Promise<NulvlessResult<{
1152
+ challenge: Challenge;
1153
+ }>>;
1154
+ /**
1155
+ * Verifies a challenge by submitting the token and the code entered by the user.
1156
+ *
1157
+ * Used for OTP sign-in, MFA verification after `signIn`, and sign-up
1158
+ * confirmation. Session is stored automatically when the response contains an
1159
+ * access token.
1160
+ */
1161
+ verify(params: VerifyChallengeParams, options?: RequestOptions): Promise<NulvlessResult<Authenticated>>;
1162
+ }
1163
+
1164
+ /**
1165
+ * Grant management for the authenticated user.
1166
+ *
1167
+ * Available on `createServerClient` only (requires private key `sk_`).
1168
+ *
1169
+ * All methods require authentication. Pass `options.headers.Authorization` to
1170
+ * forward the user's bearer token on each server-side call.
1171
+ */
1172
+ declare class GrantsClient extends AuthSubClient {
1173
+ /**
1174
+ * Returns all grants granted to the authenticated user, optionally
1175
+ * filtered by context.
1176
+ */
1177
+ list(context?: string, options?: RequestOptions): Promise<NulvlessResult<Grant[]>>;
1178
+ /**
1179
+ * Returns all grants for a given resource, grouped by status
1180
+ * (granted, invited, requested, blocked).
1181
+ *
1182
+ * The authenticated user must own or manage the resource.
1183
+ */
1184
+ getMembers(resource: string, options?: RequestOptions): Promise<NulvlessResult<GrantMembers>>;
1185
+ /**
1186
+ * Creates grant invitations for one or more users on a resource.
1187
+ *
1188
+ * Each invite sends a notification to the target email address.
1189
+ *
1190
+ * Requires sudo: `MANAGE_GRANTS`.
1191
+ *
1192
+ * @example
1193
+ * await nulvless.auth.grants.invite({
1194
+ * resource: 'project-123',
1195
+ * invites: [{ email: 'user@example.com', scopes: ['read', 'write'] }],
1196
+ * })
1197
+ */
1198
+ invite(params: InviteParams, options?: RequestOptions): Promise<NulvlessResult<Grant[]>>;
1199
+ /**
1200
+ * Returns a single grant by ID.
1201
+ */
1202
+ get(id: string, options?: RequestOptions): Promise<NulvlessResult<Grant>>;
1203
+ /**
1204
+ * Revokes (removes) a grant.
1205
+ *
1206
+ * Requires sudo: `MANAGE_GRANTS`.
1207
+ */
1208
+ revoke(params: RevokeGrantParams, options?: RequestOptions): Promise<NulvlessResult<Grant>>;
1209
+ /**
1210
+ * Accepts a pending invitation (`status: 'invited'`).
1211
+ */
1212
+ accept(id: string, options?: RequestOptions): Promise<NulvlessResult<Grant>>;
1213
+ /**
1214
+ * Cancels a pending invitation or request (`status: 'invited'` or `'requested'`).
1215
+ */
1216
+ cancel(id: string, options?: RequestOptions): Promise<NulvlessResult<Grant>>;
1217
+ /**
1218
+ * Blocks a grant.
1219
+ *
1220
+ * Requires sudo: `MANAGE_GRANTS`.
1221
+ */
1222
+ block(params: BlockGrantParams, options?: RequestOptions): Promise<NulvlessResult<Grant>>;
1223
+ /**
1224
+ * Updates the scopes of an existing grant.
1225
+ *
1226
+ * Requires sudo: `MANAGE_GRANTS`.
1227
+ */
1228
+ update(id: string, params: UpdateGrantParams, options?: RequestOptions): Promise<NulvlessResult<Grant>>;
1229
+ /**
1230
+ * Removes the authenticated user from a resource they were granted access to.
1231
+ *
1232
+ * Requires sudo: `MANAGE_GRANTS`.
1233
+ */
1234
+ leave(params: LeaveGrantParams, options?: RequestOptions): Promise<NulvlessResult<Grant>>;
1235
+ }
1236
+
1237
+ /**
1238
+ * Manages the OAuth apps the authenticated user has authorized
1239
+ * (`/user/oauth/grants`). Requires authentication (bearer token).
1240
+ */
1241
+ declare class OAuthGrantsClient extends AuthSubClient {
1242
+ /**
1243
+ * Lists the apps the authenticated user has granted access to.
1244
+ */
1245
+ list(options?: RequestOptions): Promise<NulvlessResult<OAuthUserGrant[]>>;
1246
+ /**
1247
+ * Revokes a previously granted app by its public `client_id`.
1248
+ * Also invalidates the app's active sessions for this user.
1249
+ */
1250
+ revoke(clientId: string, options?: RequestOptions): Promise<NulvlessResult<null>>;
1251
+ }
1252
+ /**
1253
+ * The project's OAuth 2.1 / OpenID Connect provider surface — the project
1254
+ * acting as an identity provider for third-party applications.
1255
+ *
1256
+ * Available with both public (`pk_`) and private (`sk_`) keys
1257
+ * (`@SetPlatformGuardRoles([PUBLIC, PRIVATE])`).
1258
+ *
1259
+ * Method scopes:
1260
+ * - `token`, `register` — platform key only (no bearer token).
1261
+ * - `getAuthorization`, `consent`, `userinfo`, and the `grants` namespace —
1262
+ * authenticated user (bearer token).
1263
+ * - `discovery`, `jwks` — public OIDC metadata (no auth).
1264
+ *
1265
+ * The `/oauth/authorize` entry point is a browser redirect (302), not a JSON
1266
+ * API — build it from `discovery().authorization_endpoint` and redirect the
1267
+ * user agent there.
1268
+ */
1269
+ declare class OAuthClient extends AuthSubClient {
1270
+ /** Apps the authenticated user has authorized — list and revoke. */
1271
+ readonly grants: OAuthGrantsClient;
1272
+ constructor(http: HttpClient, getToken: () => Promise<string | null>);
1273
+ /**
1274
+ * Builds the OAuth authorization URL and, in the browser, redirects the user
1275
+ * agent to it. On the server the URL is returned for manual handling.
1276
+ *
1277
+ * Mirrors `auth.authorize` (social sign-in): redirects automatically in the
1278
+ * browser, returns `data.url` on the server. The endpoint itself is a 302
1279
+ * redirect, so the URL is composed from the discovery `authorization_endpoint`.
1280
+ *
1281
+ * PKCE is required (RFC 7636, https://www.rfc-editor.org/rfc/rfc7636): provide
1282
+ * `code_challenge` = BASE64URL(SHA256(code_verifier)) with
1283
+ * `code_challenge_method: 'S256'`. Send the `code_verifier` later to
1284
+ * `exchangeCodeForToken`.
1285
+ *
1286
+ * @example
1287
+ * // Browser — redirects automatically
1288
+ * await nulvless.auth.oauth.authorize({ client_id, redirect_uri, code_challenge, code_challenge_method: 'S256' })
1289
+ *
1290
+ * // Server — use the returned URL
1291
+ * const { data } = await nulvless.auth.oauth.authorize(params)
1292
+ * return Response.redirect(data.url)
1293
+ */
1294
+ authorize(params: OAuthAuthorizeParams, options?: RequestOptions): Promise<NulvlessResult<{
1295
+ url: string;
1296
+ }>>;
1297
+ /**
1298
+ * Exchanges an authorization code for tokens
1299
+ * (`POST /oauth/token`, `grant_type=authorization_code`).
1300
+ *
1301
+ * Called by the relying-party app after the user is redirected back with the
1302
+ * `code`. PKCE `code_verifier` is required; `client_secret` only for
1303
+ * confidential clients. Public endpoint — no platform key.
1304
+ */
1305
+ exchangeCodeForToken(params: ExchangeOAuthCodeParams, options?: RequestOptions): Promise<NulvlessResult<OAuthTokenResponse>>;
1306
+ /**
1307
+ * Refreshes an access token using a refresh token
1308
+ * (`POST /oauth/token`, `grant_type=refresh_token`).
1309
+ *
1310
+ * `client_secret` only for confidential clients. Public endpoint — no
1311
+ * platform key.
1312
+ */
1313
+ refreshToken(params: RefreshOAuthTokenParams, options?: RequestOptions): Promise<NulvlessResult<OAuthTokenResponse>>;
1314
+ /**
1315
+ * Dynamically registers a new OAuth app (RFC 7591, `POST /oauth/register`).
1316
+ *
1317
+ * Requires the OAuth server to be enabled with dynamic client registration
1318
+ * allowed. For server-side managed registration use `admin.oauthClients`.
1319
+ */
1320
+ register(params: RegisterOAuthAppParams, options?: RequestOptions): Promise<NulvlessResult<OAuthApp>>;
1321
+ /**
1322
+ * Loads a pending authorization for the consent screen
1323
+ * (`GET /oauth/authorizations/:id`).
1324
+ *
1325
+ * Claims the authorization for the authenticated user. When a matching
1326
+ * consent already exists it is auto-approved and `redirect.uri` is returned.
1327
+ *
1328
+ * Requires authentication.
1329
+ */
1330
+ getAuthorization(authorizationId: string, options?: RequestOptions): Promise<NulvlessResult<OAuthAuthorization>>;
1331
+ /**
1332
+ * Approves or denies a pending authorization
1333
+ * (`POST /oauth/authorizations/:id/consent`).
1334
+ *
1335
+ * Returns the `redirect.uri` to send the user agent back to (carrying the
1336
+ * authorization `code` on approve, or `error=access_denied` on deny).
1337
+ *
1338
+ * Requires authentication.
1339
+ */
1340
+ consent(authorizationId: string, action: OAuthConsentAction, options?: RequestOptions): Promise<NulvlessResult<OAuthConsentResult>>;
1341
+ /**
1342
+ * Returns OIDC UserInfo claims for the access token (`GET /oauth/userinfo`).
1343
+ *
1344
+ * The access token must have been issued with the `openid` scope.
1345
+ *
1346
+ * Requires authentication.
1347
+ */
1348
+ userinfo(options?: RequestOptions): Promise<NulvlessResult<OAuthUserInfo>>;
1349
+ /**
1350
+ * Returns the OpenID Connect discovery document
1351
+ * (`GET /.well-known/openid-configuration`). Public — no auth required.
1352
+ */
1353
+ discovery(options?: RequestOptions): Promise<NulvlessResult<OAuthDiscovery>>;
1354
+ /**
1355
+ * Returns the JSON Web Key Set used to verify issued tokens
1356
+ * (`GET /.well-known/jwks.json`). Public — no auth required.
1357
+ */
1358
+ jwks(options?: RequestOptions): Promise<NulvlessResult<OAuthJWKS>>;
1359
+ }
1360
+
1361
+ /**
1362
+ * Admin operations on platform users.
1363
+ * Requires private key (`sk_`). No bearer token needed.
1364
+ */
1365
+ declare class AdminUsersClient {
1366
+ private readonly http;
1367
+ constructor(http: HttpClient);
1368
+ /**
1369
+ * Creates a new user bypassing normal sign-up flows.
1370
+ */
1371
+ create(params: AdminCreateUserParams, options?: RequestOptions): Promise<NulvlessResult<User>>;
1372
+ /**
1373
+ * Lists users with pagination and optional filters.
1374
+ */
1375
+ list(params?: PaginateUsersParams, options?: RequestOptions): Promise<NulvlessResult<Paginated<User>>>;
1376
+ /**
1377
+ * Returns a single user by ID.
1378
+ */
1379
+ get(userId: string, options?: RequestOptions): Promise<NulvlessResult<User>>;
1380
+ /**
1381
+ * Updates a user's profile fields.
1382
+ */
1383
+ update(userId: string, params: AdminUpdateUserParams, options?: RequestOptions): Promise<NulvlessResult<User>>;
1384
+ /**
1385
+ * Permanently deletes a user.
1386
+ */
1387
+ delete(userId: string, options?: RequestOptions): Promise<NulvlessResult<User>>;
1388
+ /**
1389
+ * Bans a user, preventing them from signing in.
1390
+ */
1391
+ ban(userId: string, options?: RequestOptions): Promise<NulvlessResult<User>>;
1392
+ /**
1393
+ * Lifts a ban on a user.
1394
+ */
1395
+ unban(userId: string, options?: RequestOptions): Promise<NulvlessResult<User>>;
1396
+ /**
1397
+ * Returns all active sessions for a specific user.
1398
+ */
1399
+ getSessions(userId: string, options?: RequestOptions): Promise<NulvlessResult<Session[]>>;
1400
+ /**
1401
+ * Invalidates all sessions for a specific user (signs them out everywhere).
1402
+ */
1403
+ signOutAll(userId: string, options?: RequestOptions): Promise<NulvlessResult<null>>;
1404
+ /**
1405
+ * Invalidates a specific session for a user.
1406
+ */
1407
+ revokeSession(userId: string, sessionId: string, options?: RequestOptions): Promise<NulvlessResult<Session>>;
1408
+ /**
1409
+ * Returns all configured MFA factors for a specific user.
1410
+ */
1411
+ getFactors(userId: string, options?: RequestOptions): Promise<NulvlessResult<AuthMethod[]>>;
1412
+ /**
1413
+ * Removes a specific MFA factor from a user.
1414
+ */
1415
+ removeFactor(userId: string, factorId: string, options?: RequestOptions): Promise<NulvlessResult<null>>;
1416
+ }
1417
+ /**
1418
+ * Role management. Requires private key (`sk_`). No bearer token needed.
1419
+ */
1420
+ declare class AdminRolesClient {
1421
+ private readonly http;
1422
+ constructor(http: HttpClient);
1423
+ /**
1424
+ * Returns all roles, optionally filtered by context.
1425
+ */
1426
+ list(context?: string, options?: RequestOptions): Promise<NulvlessResult<Role[]>>;
1427
+ /**
1428
+ * Creates a new role with the given scopes.
1429
+ */
1430
+ create(params: CreateRoleParams, options?: RequestOptions): Promise<NulvlessResult<Role>>;
1431
+ /**
1432
+ * Updates an existing role.
1433
+ */
1434
+ update(role_id: string, params: UpdateRoleParams, options?: RequestOptions): Promise<NulvlessResult<Role>>;
1435
+ /**
1436
+ * Deletes a role.
1437
+ */
1438
+ delete(role_id: string, options?: RequestOptions): Promise<NulvlessResult<null>>;
1439
+ }
1440
+ /**
1441
+ * Platform-level grant management.
1442
+ * Requires private key (`sk_`). No bearer token needed.
1443
+ */
1444
+ declare class AdminGrantsClient {
1445
+ private readonly http;
1446
+ constructor(http: HttpClient);
1447
+ /**
1448
+ * Lists grants with pagination and optional filters.
1449
+ */
1450
+ list(params?: PaginateGrantsParams, options?: RequestOptions): Promise<NulvlessResult<Paginated<Grant>>>;
1451
+ /**
1452
+ * Creates or upserts a grant for a user on a resource.
1453
+ */
1454
+ set(params: SetGrantParams, options?: RequestOptions): Promise<NulvlessResult<Grant>>;
1455
+ /**
1456
+ * Deletes a grant by ID.
1457
+ */
1458
+ delete(grantId: string, options?: RequestOptions): Promise<NulvlessResult<null>>;
1459
+ /**
1460
+ * Removes all grants associated with a resource.
1461
+ *
1462
+ * Use with caution — this will revoke access for all users on the resource.
1463
+ */
1464
+ deleteByResource(resource: string, options?: RequestOptions): Promise<NulvlessResult<null>>;
1465
+ }
1466
+ /**
1467
+ * Manage the project's OAuth applications (clients) — the third-party apps
1468
+ * allowed to authenticate users through the project's OAuth server.
1469
+ *
1470
+ * Requires private key (`sk_`). No bearer token needed.
1471
+ */
1472
+ declare class AdminOAuthClientsClient {
1473
+ private readonly http;
1474
+ constructor(http: HttpClient);
1475
+ /**
1476
+ * Registers a new OAuth app. For confidential apps the response includes a
1477
+ * one-time `client_secret` — store it securely, it is never returned again.
1478
+ */
1479
+ create(params: RegisterOAuthAppParams, options?: RequestOptions): Promise<NulvlessResult<OAuthApp>>;
1480
+ /**
1481
+ * Lists all registered OAuth apps.
1482
+ */
1483
+ list(options?: RequestOptions): Promise<NulvlessResult<OAuthApp[]>>;
1484
+ /**
1485
+ * Returns a single OAuth app by its internal id.
1486
+ */
1487
+ get(id: string, options?: RequestOptions): Promise<NulvlessResult<OAuthApp>>;
1488
+ /**
1489
+ * Updates an OAuth app. `client_type` is immutable and the secret rotates via
1490
+ * `regenerateSecret` — neither can be changed here.
1491
+ */
1492
+ update(id: string, params: UpdateOAuthAppParams, options?: RequestOptions): Promise<NulvlessResult<OAuthApp>>;
1493
+ /**
1494
+ * Deletes an OAuth app.
1495
+ */
1496
+ delete(id: string, options?: RequestOptions): Promise<NulvlessResult<null>>;
1497
+ /**
1498
+ * Rotates the client secret (confidential apps only). The new `client_secret`
1499
+ * is returned once — the previous one stops working immediately.
1500
+ */
1501
+ regenerateSecret(id: string, options?: RequestOptions): Promise<NulvlessResult<OAuthApp>>;
1502
+ }
1503
+ /**
1504
+ * Admin namespace — platform management operations.
1505
+ *
1506
+ * Available on `createServerClient` only (requires private key `sk_`).
1507
+ * No bearer token is required for any method in this namespace.
1508
+ *
1509
+ * Sub-namespaces:
1510
+ * - `admin.users` — create, list, update, delete users; manage sessions & factors
1511
+ * - `admin.roles` — create, list, update, delete roles
1512
+ * - `admin.grants` — set, list, delete platform grants
1513
+ * - `admin.oauthClients` — register and manage OAuth apps (clients)
1514
+ */
1515
+ declare class AdminClient {
1516
+ private readonly http;
1517
+ readonly users: AdminUsersClient;
1518
+ readonly roles: AdminRolesClient;
1519
+ readonly grants: AdminGrantsClient;
1520
+ readonly oauthClients: AdminOAuthClientsClient;
1521
+ constructor(http: HttpClient);
1522
+ /**
1523
+ * Returns basic platform information (id, name, slug).
1524
+ */
1525
+ getPlatform(options?: RequestOptions): Promise<NulvlessResult<PlatformInfo>>;
1526
+ }
1527
+
1528
+ interface AccountEntry {
1529
+ userId: string;
1530
+ access_token: string;
1531
+ /** Seconds remaining until the token expires. May be negative if already expired. */
1532
+ expires_in: number;
1533
+ refresh_token?: string;
1534
+ user?: User;
1535
+ }
1536
+
1537
+ interface AuthEvents {
1538
+ /** Emitted when a sign-in or sign-up succeeds and an access token is stored. */
1539
+ 'signed-in': Authenticated;
1540
+ /** Emitted after `signOut` succeeds. */
1541
+ 'signed-out': {
1542
+ userId?: string;
1543
+ };
1544
+ /** Emitted when the server returns a challenge (MFA/OTP) with no access token. */
1545
+ 'challenge': Authenticated;
1546
+ /** Emitted after the access token is refreshed automatically. */
1547
+ 'token-refreshed': Authenticated;
1548
+ /** Emitted when `switch()` succeeds. */
1549
+ 'account-switched': {
1550
+ userId: string;
1551
+ };
1552
+ /**
1553
+ * Emitted when the SDK cannot authenticate the user:
1554
+ * - there is no refresh token, or
1555
+ * - a refresh attempt was rejected by the server (401 / `unauthorized`).
1556
+ *
1557
+ * The payload carries the failed session (its `user` when known), so
1558
+ * multi-user callers can remove the right entry from the accounts store.
1559
+ */
1560
+ 'unauthorized': Authenticated;
1561
+ /**
1562
+ * Emitted when any request fails with `403 protected_action_denied`,
1563
+ * meaning the action requires an active sudo session.
1564
+ * Run the sudo flow (`auth.sessions.sudo()` → `auth.challenges.verify()`)
1565
+ * to activate sudo mode, then retry.
1566
+ */
1567
+ 'sudo-required': void;
1568
+ }
1569
+ type Listener<T> = T extends void ? () => void : (payload: T) => void;
1570
+ type UnsubscribeFn = () => void;
1571
+ declare class AuthEventEmitter {
1572
+ private readonly listeners;
1573
+ on<K extends keyof AuthEvents>(event: K, handler: Listener<AuthEvents[K]>): UnsubscribeFn;
1574
+ emit<K extends keyof AuthEvents>(...args: AuthEvents[K] extends void ? [event: K] : [event: K, payload: AuthEvents[K]]): void;
1575
+ removeAllListeners(event?: keyof AuthEvents): void;
1576
+ }
1577
+
1578
+ /**
1579
+ * Auth methods accessible with both public (`pk_`) and private (`sk_`) keys.
1580
+ * Corresponds to endpoints decorated with `@SetPlatformGuardRoles([PUBLIC, PRIVATE])`.
1581
+ */
1582
+ declare class AuthClient {
1583
+ protected readonly http: HttpClient;
1584
+ protected readonly session?: SessionManager | undefined;
1585
+ /** MFA factor management — enroll, enable, disable, recovery codes. */
1586
+ readonly factors: FactorsClient;
1587
+ /** Current-user management — profile, identities, credential updates. */
1588
+ readonly users: UsersClient;
1589
+ /** Active session management — list, revoke, sudo mode. */
1590
+ readonly sessions: SessionsClient;
1591
+ /** Account security — change password. */
1592
+ readonly security: SecurityClient;
1593
+ /** Challenge lifecycle — create, get, change, verify (MFA / OTP / step-up). */
1594
+ readonly challenges: ChallengesClient;
1595
+ /** OAuth server (project as OIDC provider) — token, consent, userinfo, grants, discovery. */
1596
+ readonly oauth: OAuthClient;
1597
+ protected readonly _getToken: () => Promise<string | null>;
1598
+ constructor(http: HttpClient, session?: SessionManager | undefined);
1599
+ /**
1600
+ * Returns the current active access token from storage.
1601
+ * Refreshes automatically if the token is expired or about to expire.
1602
+ * Returns `null` when there is no active session.
1603
+ */
1604
+ getAccessToken(): Promise<string | null>;
1605
+ protected persistSession(result: NulvlessResult<Authenticated>): Promise<NulvlessResult<Authenticated>>;
1606
+ /**
1607
+ * Creates a new user account.
1608
+ *
1609
+ * At least one of `email`, `phone`, or `username` must be provided.
1610
+ *
1611
+ * Check the response in this order:
1612
+ * 1. `data.access_token` → authenticated immediately — session stored automatically.
1613
+ * 2. `data.challenge` → MFA/OTP step required — call `verifyChallenge`.
1614
+ * 3. `data.user` only → pending email/phone confirmation.
1615
+ */
1616
+ signUp(params: SignUpParams, options?: RequestOptions): Promise<NulvlessResult<Authenticated>>;
1617
+ /**
1618
+ * Signs in with password (`grant_type=password`).
1619
+ *
1620
+ * At least one of `email`, `phone`, or `username` must be provided.
1621
+ *
1622
+ * Check the response in this order:
1623
+ * 1. `data.access_token` → signed in — session stored automatically.
1624
+ * 2. `data.challenge` → MFA step required — call `verifyChallenge`.
1625
+ */
1626
+ signIn(params: SignInParams, options?: RequestOptions): Promise<NulvlessResult<Authenticated>>;
1627
+ /**
1628
+ * Requests a one-time password sent to the user's email or phone.
1629
+ *
1630
+ * Returns a `Challenge` (`202 Accepted`). Pass the received code to `verifyChallenge`.
1631
+ *
1632
+ * At least one of `email` or `phone` must be provided.
1633
+ */
1634
+ signInWithOTP(params: SignInWithOTPParams, options?: RequestOptions): Promise<NulvlessResult<Challenge>>;
1635
+ /**
1636
+ * Initiates an OAuth sign-in flow for the given provider.
1637
+ *
1638
+ * In a browser environment the user is redirected automatically to the
1639
+ * authorization URL. On the server the URL is returned for manual handling.
1640
+ *
1641
+ * After the redirect, the server-side callback exchanges the code automatically
1642
+ * and redirects back to `options.redirect_uri`. For server-side code exchange, use `exchangeCodeForToken`.
1643
+ *
1644
+ * @example
1645
+ * // Browser — redirects automatically
1646
+ * await nulvless.auth.authorize('google', { redirect_uri: 'https://myapp.com/callback' })
1647
+ *
1648
+ * // Server — use the returned URL
1649
+ * const { data } = await nulvless.auth.authorize('google', { redirect_uri: 'https://myapp.com/callback' })
1650
+ * return Response.redirect(data.url)
1651
+ */
1652
+ authorize(provider: OAuthProvider, options?: RequestOptions): Promise<NulvlessResult<{
1653
+ url: string;
1654
+ provider: OAuthProvider;
1655
+ }>>;
1656
+ /**
1657
+ * Initiates an OAuth flow to connect a new provider to the authenticated user's account.
1658
+ *
1659
+ * Same behaviour as `authorize`, but for users who are already signed in — the resulting
1660
+ * provider identity is linked to the current account instead of starting a sign-in flow.
1661
+ *
1662
+ * In a browser environment the user is redirected automatically to the
1663
+ * authorization URL. On the server the URL is returned for manual handling.
1664
+ *
1665
+ * Requires authentication. Token is resolved automatically from storage
1666
+ * (browser) or from `options.headers.Authorization` (server).
1667
+ *
1668
+ * @example
1669
+ * await nulvless.auth.connect('github', { redirect_uri: 'https://myapp.com/settings/connections' })
1670
+ */
1671
+ connect(provider: OAuthProvider, options?: RequestOptions): Promise<NulvlessResult<{
1672
+ url: string;
1673
+ provider: OAuthProvider;
1674
+ }>>;
1675
+ /**
1676
+ * Signs in with an ID token issued by a third-party OAuth provider.
1677
+ *
1678
+ * Useful for mobile apps where you obtain the ID token natively (e.g. Google Sign-In SDK).
1679
+ *
1680
+ * Session is stored automatically when the response contains an access token.
1681
+ *
1682
+ * @example
1683
+ * const { data } = await nulvless.auth.signInWithIdToken('google', googleIdToken)
1684
+ */
1685
+ signInWithIdToken(provider: OAuthProvider, idToken: string, options?: RequestOptions): Promise<NulvlessResult<Authenticated>>;
1686
+ /**
1687
+ * Exchanges an OAuth authorization code for an access token
1688
+ * (`grant_type=authorization_code`).
1689
+ *
1690
+ * Must be called with `Content-Type: application/x-www-form-urlencoded`.
1691
+ * The `code` must be the authorization code received from the OAuth callback.
1692
+ *
1693
+ * Session is stored automatically when the response contains an access token.
1694
+ *
1695
+ * @example
1696
+ * const { data } = await nulvless.auth.exchangeCodeForToken('auth-code-from-callback')
1697
+ */
1698
+ exchangeCodeForToken(code: string, options?: RequestOptions): Promise<NulvlessResult<Authenticated>>;
1699
+ /**
1700
+ * Returns all sign-in methods, MFA factors, and OAuth providers configured
1701
+ * for the authenticated user on this platform.
1702
+ *
1703
+ * Requires authentication.
1704
+ */
1705
+ getMethods(options?: RequestOptions): Promise<NulvlessResult<AuthMethods>>;
1706
+ /**
1707
+ * Looks up whether an identifier exists and which sign-in method applies.
1708
+ *
1709
+ * Useful for adaptive sign-in UIs. May return a `challenge` directly
1710
+ * when the user's method is OTP-only.
1711
+ *
1712
+ * At least one of `email`, `phone`, or `username` must be provided.
1713
+ */
1714
+ lookup(params: LookupParams, options?: RequestOptions): Promise<NulvlessResult<LookupResult>>;
1715
+ /**
1716
+ * Verifies a challenge by submitting the token and the code entered by the user.
1717
+ *
1718
+ * Used for:
1719
+ * - OTP sign-in (`signInWithOTP` flow)
1720
+ * - MFA verification after `signIn`
1721
+ * - Sign-up confirmation (`signUp` challenge flow)
1722
+ *
1723
+ * Convenience alias for `auth.challenges.verify`. Session is stored
1724
+ * automatically when the response contains an access token. For the rest of
1725
+ * the challenge lifecycle (create, get, change) use `auth.challenges`.
1726
+ */
1727
+ verifyChallenge(params: VerifyChallengeParams, options?: RequestOptions): Promise<NulvlessResult<Authenticated>>;
1728
+ /**
1729
+ * Activates an account via the confirmation link sent to the user's email/phone.
1730
+ */
1731
+ activate(token: string, options?: RequestOptions): Promise<NulvlessResult<null>>;
1732
+ /**
1733
+ * Refreshes the access token using a refresh token (`grant_type=refresh_token`).
1734
+ * Session is updated automatically in storage.
1735
+ */
1736
+ refreshToken(params: RefreshTokenParams, options?: RequestOptions): Promise<NulvlessResult<Authenticated>>;
1737
+ /**
1738
+ * Sends a password-recovery email to the user.
1739
+ */
1740
+ recover(params: RecoverParams, options?: RequestOptions): Promise<NulvlessResult<null>>;
1741
+ /**
1742
+ * Resets the user's password using the token from the recovery email.
1743
+ */
1744
+ resetPassword(params: ResetPasswordParams, options?: RequestOptions): Promise<NulvlessResult<null>>;
1745
+ /**
1746
+ * Validates the current session and optionally checks a grant.
1747
+ *
1748
+ * Requires authentication. Token is resolved automatically from storage
1749
+ * (browser) or from `options.headers.Authorization` (server).
1750
+ */
1751
+ verify(grant?: VerifyParams, options?: RequestOptions): Promise<NulvlessResult<Verified>>;
1752
+ /**
1753
+ * Returns the current session details.
1754
+ *
1755
+ * Requires authentication. Token is resolved automatically from storage
1756
+ * (browser) or from `options.headers.Authorization` (server).
1757
+ */
1758
+ getSession(options?: RequestOptions): Promise<NulvlessResult<Session>>;
1759
+ /**
1760
+ * Signs out the user and clears the stored session.
1761
+ *
1762
+ * - `'local'` (default) — invalidates only the current session.
1763
+ * - `'global'` — invalidates all sessions across all devices.
1764
+ * - `'others'` — invalidates all sessions except the current one.
1765
+ *
1766
+ * Requires authentication. Token is resolved automatically from storage
1767
+ * (browser) or from `options.headers.Authorization` (server).
1768
+ */
1769
+ signOut(scope?: SignOutScope, options?: RequestOptions): Promise<NulvlessResult<null>>;
1770
+ }
1771
+ /**
1772
+ * Auth client for browser use (`createClient` / public key).
1773
+ * Extends `AuthClient` with session management and multi-account helpers.
1774
+ */
1775
+ declare class AuthBrowserClient extends AuthClient {
1776
+ private readonly accountsManager;
1777
+ private readonly emitter;
1778
+ private readonly multiUser;
1779
+ private readonly tabs;
1780
+ constructor(http: HttpClient, session: SessionManager, storage: NulvlessStorage, accountsKey: string, multiUser?: boolean, autoRefresh?: boolean);
1781
+ /**
1782
+ * Renews the access token now, sharing the attempt with any refresh already
1783
+ * in flight. Returns the new token, or `null` when the session could not be
1784
+ * recovered.
1785
+ */
1786
+ refreshSession(): Promise<string | null>;
1787
+ /** Releases the refresh timer and the cross-tab channel. */
1788
+ dispose(): void;
1789
+ /**
1790
+ * Subscribes to an auth event.
1791
+ *
1792
+ * Returns an unsubscribe function — call it to stop listening.
1793
+ *
1794
+ * @example
1795
+ * const off = nulvless.auth.on('signed-in', (session) => {
1796
+ * console.log('signed in as', session.user?.id)
1797
+ * })
1798
+ * off() // unsubscribe
1799
+ */
1800
+ on<K extends keyof AuthEvents>(event: K, handler: AuthEvents[K] extends void ? () => void : (payload: AuthEvents[K]) => void): () => void;
1801
+ protected persistSession(result: NulvlessResult<Authenticated>): Promise<NulvlessResult<Authenticated>>;
1802
+ /**
1803
+ * Returns the session currently stored in storage, or `null` if there is none.
1804
+ *
1805
+ * `expires_in` is the number of seconds remaining until expiry (may be negative
1806
+ * if the token is already expired).
1807
+ *
1808
+ * @example
1809
+ * const session = await nulvless.auth.get()
1810
+ * if (session) {
1811
+ * console.log(session.access_token, session.expires_in)
1812
+ * }
1813
+ */
1814
+ get(): Promise<Authenticated | null>;
1815
+ /**
1816
+ * Manually persists a session as the active session.
1817
+ *
1818
+ * Use this when you obtain an `Authenticated` outside the normal SDK flow
1819
+ * (e.g. server-side login, custom OAuth callback) and want the SDK to treat
1820
+ * it as the active session.
1821
+ *
1822
+ * @example
1823
+ * await nulvless.auth.set({ access_token: 'eyJ...', refresh_token: 'rt_...', expires_in: 3600 })
1824
+ */
1825
+ set(data: Authenticated): Promise<void>;
1826
+ /**
1827
+ * Adds an account to the accounts store without switching the active session.
1828
+ *
1829
+ * The account is identified by the `user.id` in the response, or by the `sub`
1830
+ * claim in the access token JWT.
1831
+ *
1832
+ * Call this after a sign-in to register additional accounts. Accounts are
1833
+ * also saved automatically whenever a sign-in / sign-up succeeds.
1834
+ *
1835
+ * @example
1836
+ * const { data } = await nulvless.auth.signIn(params)
1837
+ * // already saved automatically — or add manually:
1838
+ * await nulvless.auth.add(data)
1839
+ */
1840
+ add(auth: Authenticated): Promise<void>;
1841
+ /**
1842
+ * Switches the active session to a previously saved account.
1843
+ *
1844
+ * Returns `true` on success, `false` if the account is not found.
1845
+ *
1846
+ * @example
1847
+ * const ok = await nulvless.auth.switch('user-id-123')
1848
+ */
1849
+ switch(userId: string): Promise<boolean>;
1850
+ /**
1851
+ * Returns all accounts currently saved in the accounts store.
1852
+ *
1853
+ * @example
1854
+ * const accounts = await nulvless.auth.list()
1855
+ * // [{ userId: '...', access_token: '...', expires_in: 3540 }]
1856
+ */
1857
+ list(): Promise<AccountEntry[]>;
1858
+ /**
1859
+ * Removes a saved account from the accounts store.
1860
+ *
1861
+ * Does not affect the active session.
1862
+ *
1863
+ * @example
1864
+ * await nulvless.auth.remove('user-id-123')
1865
+ */
1866
+ remove(userId: string): Promise<void>;
1867
+ /**
1868
+ * Drops the active session without ending it on the server.
1869
+ *
1870
+ * The account stays in the accounts store, so `switch` brings it back. Use
1871
+ * this when the user leaves the authenticated area to pick or add another
1872
+ * account: with no active session the automatic refresh goes quiet instead
1873
+ * of keeping a session warm that nothing is using.
1874
+ *
1875
+ * @example
1876
+ * await nulvless.auth.deselect()
1877
+ * // later
1878
+ * await nulvless.auth.switch('user-id-123')
1879
+ */
1880
+ deselect(): Promise<void>;
1881
+ signOut(scope?: SignOutScope, options?: RequestOptions): Promise<NulvlessResult<null>>;
1882
+ }
1883
+ /**
1884
+ * Auth methods exclusive to private (`sk_`) keys.
1885
+ * Extends `AuthClient` — all public methods and sub-namespaces are available here too.
1886
+ *
1887
+ * Additional sub-namespaces:
1888
+ * - `auth.grants` — grant management (invite, revoke, accept, etc.)
1889
+ * - `auth.admin` — platform administration (users, roles, grants)
1890
+ *
1891
+ * Never use in browser code.
1892
+ */
1893
+ declare class AuthServerClient extends AuthClient {
1894
+ /** User-facing grant management — invite, accept, revoke, etc. */
1895
+ readonly grants: GrantsClient;
1896
+ /** Platform administration — manage users, roles, and grants server-side. */
1897
+ readonly admin: AdminClient;
1898
+ constructor(http: HttpClient);
1899
+ }
1900
+
1901
+ interface SendEmailParams {
1902
+ /** Recipient address. */
1903
+ to: string;
1904
+ /** Template slug — e.g. `"welcome"`, `"password-reset"`. */
1905
+ template: string;
1906
+ /** Language variant of the template. Uses platform default when omitted. */
1907
+ language?: Language;
1908
+ /** Variables injected into the template. */
1909
+ params?: Record<string, unknown>;
1910
+ }
1911
+ interface SendSMSParams {
1912
+ phone: Phone;
1913
+ /** Template slug. */
1914
+ template: string;
1915
+ /** Language variant of the template. Uses platform default when omitted. */
1916
+ language?: Language;
1917
+ /** Variables injected into the template. */
1918
+ params?: Record<string, unknown>;
1919
+ }
1920
+ type NotificationChannel = 'email' | 'sms' | 'webhook';
1921
+ type TemplateLanguage = 'en-US' | 'pt-BR';
1922
+ interface Template {
1923
+ id: string;
1924
+ name?: string;
1925
+ description?: string;
1926
+ slug: string;
1927
+ channel: NotificationChannel;
1928
+ subject?: string;
1929
+ content: string;
1930
+ url?: string;
1931
+ config?: Record<string, unknown>;
1932
+ language: TemplateLanguage;
1933
+ last_submission?: string;
1934
+ /** `true` when this is a platform-level common template, not a custom one. */
1935
+ common: boolean;
1936
+ created_at: string;
1937
+ updated_at: string;
1938
+ }
1939
+ interface CreateTemplateParams {
1940
+ slug: string;
1941
+ channel: NotificationChannel;
1942
+ content: string;
1943
+ language: TemplateLanguage;
1944
+ name?: string;
1945
+ description?: string;
1946
+ /** Email subject. Required for `email` channel. */
1947
+ subject?: string;
1948
+ /** Webhook URL. Required for `webhook` channel. */
1949
+ url?: string;
1950
+ config?: Record<string, unknown>;
1951
+ }
1952
+ interface UpdateTemplateParams {
1953
+ name?: string;
1954
+ description?: string;
1955
+ subject?: string;
1956
+ content?: string;
1957
+ url?: string;
1958
+ config?: Record<string, unknown>;
1959
+ }
1960
+ interface TemplateFilters {
1961
+ page?: number;
1962
+ page_size?: number;
1963
+ sort?: 'asc' | 'desc';
1964
+ channel?: NotificationChannel;
1965
+ language?: TemplateLanguage;
1966
+ }
1967
+ interface PaginatedTemplates {
1968
+ items: Template[];
1969
+ page?: number;
1970
+ page_size?: number;
1971
+ total?: number;
1972
+ sort?: 'asc' | 'desc';
1973
+ }
1974
+
1975
+ /**
1976
+ * Template management for the notifications service.
1977
+ *
1978
+ * Available on `createServerClient` only (requires private key).
1979
+ *
1980
+ * @example
1981
+ * const { data } = await nulvless.comms.templates.create({
1982
+ * slug: 'welcome',
1983
+ * channel: 'email',
1984
+ * language: 'en-US',
1985
+ * subject: 'Welcome!',
1986
+ * content: '<h1>Hello {{name}}</h1>',
1987
+ * })
1988
+ */
1989
+ declare class TemplatesClient {
1990
+ private readonly http;
1991
+ constructor(http: HttpClient);
1992
+ /**
1993
+ * Creates a new notification template.
1994
+ *
1995
+ * - `email` channel: `subject` required, `url` not allowed.
1996
+ * - `sms` channel: `subject` and `url` not allowed.
1997
+ * - `webhook` channel: `url` required, `subject` not allowed.
1998
+ */
1999
+ create(params: CreateTemplateParams, options?: RequestOptions): Promise<NulvlessResult<Template>>;
2000
+ /**
2001
+ * Updates an existing template.
2002
+ *
2003
+ * `language` defaults to `'en-US'` when omitted.
2004
+ *
2005
+ * @example
2006
+ * await nulvless.comms.templates.update('email', 'welcome', { subject: 'Welcome aboard!' })
2007
+ */
2008
+ update(channel: NotificationChannel, slug: string, params: UpdateTemplateParams, language?: TemplateLanguage, options?: RequestOptions): Promise<NulvlessResult<Template>>;
2009
+ /**
2010
+ * Deletes a template.
2011
+ *
2012
+ * `language` defaults to `'en-US'` when omitted.
2013
+ */
2014
+ delete(channel: NotificationChannel, slug: string, language?: TemplateLanguage, options?: RequestOptions): Promise<NulvlessResult<Template>>;
2015
+ /**
2016
+ * Returns a template by channel and slug, falling back to the common template
2017
+ * if no custom one exists.
2018
+ *
2019
+ * `language` defaults to `'en-US'` when omitted.
2020
+ *
2021
+ * The response includes `common: true` when the returned template is the
2022
+ * platform-level fallback rather than a custom override.
2023
+ */
2024
+ get(channel: NotificationChannel, slug: string, language?: TemplateLanguage, options?: RequestOptions): Promise<NulvlessResult<Template>>;
2025
+ /**
2026
+ * Returns a paginated list of templates, optionally filtered by channel and language.
2027
+ *
2028
+ * @example
2029
+ * const { data } = await nulvless.comms.templates.list({ channel: 'email', page_size: 20 })
2030
+ */
2031
+ list(filters?: TemplateFilters, options?: RequestOptions): Promise<NulvlessResult<PaginatedTemplates>>;
2032
+ }
2033
+
2034
+ declare class EmailClient {
2035
+ private readonly http;
2036
+ constructor(http: HttpClient);
2037
+ /**
2038
+ * Sends a transactional email using a pre-configured template.
2039
+ *
2040
+ * Returns `null` on success — the API responds with `200` and no body.
2041
+ *
2042
+ * @example
2043
+ * const { error } = await nulvless.comms.email.send({
2044
+ * to: 'user@example.com',
2045
+ * template: 'welcome',
2046
+ * params: { name: 'Gleisson' },
2047
+ * })
2048
+ */
2049
+ send(params: SendEmailParams, options?: RequestOptions): Promise<NulvlessResult<null>>;
2050
+ /**
2051
+ * Sends a test email to validate the platform's email provider configuration.
2052
+ *
2053
+ * Returns `null` on success.
2054
+ *
2055
+ * @example
2056
+ * const { error } = await nulvless.comms.email.test('user@example.com')
2057
+ */
2058
+ test(email: string, options?: RequestOptions): Promise<NulvlessResult<null>>;
2059
+ }
2060
+ declare class SmsClient {
2061
+ private readonly http;
2062
+ constructor(http: HttpClient);
2063
+ /**
2064
+ * Sends a transactional SMS using a pre-configured template.
2065
+ *
2066
+ * Returns `null` on success — the API responds with `200` and no body.
2067
+ *
2068
+ * @example
2069
+ * const { error } = await nulvless.comms.sms.send({
2070
+ * phone: { country_code: '+55', number: '11999999999' },
2071
+ * template: 'verification-code',
2072
+ * params: { code: '123456' },
2073
+ * })
2074
+ */
2075
+ send(params: SendSMSParams, options?: RequestOptions): Promise<NulvlessResult<null>>;
2076
+ /**
2077
+ * Sends a test SMS to validate the platform's SMS provider configuration.
2078
+ *
2079
+ * Returns `null` on success.
2080
+ *
2081
+ * @example
2082
+ * const { error } = await nulvless.comms.sms.test('user@example.com')
2083
+ */
2084
+ test(email: string, options?: RequestOptions): Promise<NulvlessResult<null>>;
2085
+ }
2086
+ declare class CommsClient {
2087
+ readonly email: EmailClient;
2088
+ readonly sms: SmsClient;
2089
+ readonly templates: TemplatesClient;
2090
+ constructor(http: HttpClient);
2091
+ }
2092
+
2093
+ /**
2094
+ * Browser client — use with a public key (`pk_...`).
2095
+ *
2096
+ * Only exposes endpoints that accept public keys.
2097
+ * Safe to instantiate in frontend code.
2098
+ */
2099
+ declare class NulvlessClient {
2100
+ readonly auth: AuthBrowserClient;
2101
+ constructor(baseUrl: string, publicKey: string, options?: ClientOptions);
2102
+ }
2103
+ /**
2104
+ * Server client — use with a private key (`sk_...`).
2105
+ *
2106
+ * Has access to everything in `NulvlessClient` plus private-only endpoints.
2107
+ * Never instantiate in browser code — the private key must stay secret.
2108
+ */
2109
+ declare class NulvlessServerClient {
2110
+ readonly auth: AuthServerClient;
2111
+ readonly comms: CommsClient;
2112
+ constructor(baseUrl: string, privateKey: string, options?: ServerClientOptions);
2113
+ }
2114
+
2115
+ /**
2116
+ * Thrown when `throwErrors: true` is set and the API returns an error response.
2117
+ *
2118
+ * Mirrors the same `{ code, message, status_code }` shape returned by default —
2119
+ * the only difference is delivery: exception vs. discriminated union.
2120
+ *
2121
+ * @example
2122
+ * import { NulvlessException } from '@nulvless/nulvless-js'
2123
+ *
2124
+ * try {
2125
+ * const { data } = await nulvless.auth.signIn({ email, password })
2126
+ * } catch (err) {
2127
+ * if (err instanceof NulvlessException) {
2128
+ * console.error(err.code, err.status_code, err.message)
2129
+ * }
2130
+ * }
2131
+ */
2132
+ declare class NulvlessException extends Error {
2133
+ readonly code: string;
2134
+ readonly status_code: number;
2135
+ constructor(message: string | string[], code: string, status_code: number);
2136
+ }
2137
+
2138
+ /** Persists in `localStorage`. Data survives page reloads and browser restarts. */
2139
+ declare class LocalStorageAdapter implements NulvlessStorage {
2140
+ getItem(key: string): Promise<string | null>;
2141
+ setItem(key: string, value: string): Promise<void>;
2142
+ removeItem(key: string): Promise<void>;
2143
+ }
2144
+
2145
+ /** Persists in `sessionStorage`. Data is cleared when the tab or browser is closed. */
2146
+ declare class SessionStorageAdapter implements NulvlessStorage {
2147
+ getItem(key: string): Promise<string | null>;
2148
+ setItem(key: string, value: string): Promise<void>;
2149
+ removeItem(key: string): Promise<void>;
2150
+ }
2151
+
2152
+ /**
2153
+ * Persists in memory (plain `Map`). Data is lost on page reload.
2154
+ *
2155
+ * Useful for SSR environments, tests, or situations where persistent
2156
+ * storage is not available or desired.
2157
+ */
2158
+ declare class MemoryStorageAdapter implements NulvlessStorage {
2159
+ private readonly store;
2160
+ getItem(key: string): Promise<string | null>;
2161
+ setItem(key: string, value: string): Promise<void>;
2162
+ removeItem(key: string): Promise<void>;
2163
+ }
2164
+
2165
+ /**
2166
+ * Persists using the browser's Cache Storage API.
2167
+ *
2168
+ * Available in modern browsers and service workers. Data survives page
2169
+ * reloads but can be cleared by the browser under storage pressure.
2170
+ *
2171
+ * Keys are mapped to fake URLs (`https://nulvless.storage/<key>`) since
2172
+ * the Cache API uses URLs as identifiers.
2173
+ */
2174
+ declare class CacheStorageAdapter implements NulvlessStorage {
2175
+ private key;
2176
+ getItem(key: string): Promise<string | null>;
2177
+ setItem(key: string, value: string): Promise<void>;
2178
+ removeItem(key: string): Promise<void>;
2179
+ }
2180
+
2181
+ /**
2182
+ * Built-in storage adapters for session persistence.
2183
+ *
2184
+ * @example
2185
+ * import { Storage } from '@nulvless/nulvless-js'
2186
+ *
2187
+ * const nulvless = createClient(url, key, {
2188
+ * storage: Storage.Local, // localStorage — survives reloads
2189
+ * storage: Storage.Session, // sessionStorage — cleared on tab close
2190
+ * storage: Storage.Memory, // in-memory — useful for SSR / tests
2191
+ * storage: Storage.Cache, // Cache Storage API — browser / service workers
2192
+ * })
2193
+ */
2194
+ declare const Storage: {
2195
+ /** `localStorage` — data survives page reloads and browser restarts. */
2196
+ readonly Local: LocalStorageAdapter;
2197
+ /** `sessionStorage` — data is cleared when the tab or browser is closed. */
2198
+ readonly Session: SessionStorageAdapter;
2199
+ /** In-memory `Map` — data is lost on page reload. Good for SSR and tests. */
2200
+ readonly Memory: MemoryStorageAdapter;
2201
+ /** Cache Storage API — survives reloads, available in service workers. */
2202
+ readonly Cache: CacheStorageAdapter;
2203
+ };
2204
+
2205
+ type NodeHeaders = Record<string, string | string[] | undefined>;
2206
+ /**
2207
+ * Extracts user browser headers from an incoming server request and returns
2208
+ * them as a plain `Record<string, string>` ready to pass via `options.headers`.
2209
+ *
2210
+ * Accepts:
2211
+ * - **Web `Request`** — Next.js App Router, Cloudflare Workers, Deno
2212
+ * - **Node.js `IncomingMessage`** — Express, Next.js Pages Router, Fastify raw
2213
+ *
2214
+ * @example
2215
+ * // Next.js App Router
2216
+ * export async function POST(request: Request) {
2217
+ * const { data } = await nulvless.auth.signIn(params, {
2218
+ * headers: forwardUserHeaders(request),
2219
+ * })
2220
+ * }
2221
+ *
2222
+ * @example
2223
+ * // Express / Next.js Pages Router
2224
+ * app.post('/login', async (req, res) => {
2225
+ * const { data } = await nulvless.auth.signIn(params, {
2226
+ * headers: forwardUserHeaders(req),
2227
+ * })
2228
+ * })
2229
+ */
2230
+ declare function forwardUserHeaders(req: Request | {
2231
+ headers: NodeHeaders;
2232
+ }): Record<string, string>;
2233
+
2234
+ /**
2235
+ * Headers that keep a response carrying auth state out of every cache.
2236
+ *
2237
+ * `no-store` alone covers HTTP/1.1; `Pragma` and `Expires` cover HTTP/1.0 caches
2238
+ * and proxies that predate it. RFC 6749 §5.1 and OpenID Connect Core §3.1.3.3
2239
+ * both require the first two on any response carrying a token.
2240
+ */
2241
+ declare const AUTH_CACHE_HEADERS: {
2242
+ readonly 'Cache-Control': "private, no-cache, no-store, must-revalidate, max-age=0";
2243
+ readonly Expires: "0";
2244
+ readonly Pragma: "no-cache";
2245
+ };
2246
+ /**
2247
+ * Marks a response as carrying auth state so no cache stores it, and returns it
2248
+ * so the call can be inlined into a `return`.
2249
+ *
2250
+ * Apply this to **your own** response whenever it sets, rotates or clears a
2251
+ * session — sign-in, refresh, sign-out. A CDN that caches such a response serves
2252
+ * one visitor's session cookie to the next, signing them in as someone else; it
2253
+ * is a failure that has happened in production on CloudFront, Vercel Edge and
2254
+ * Cloudflare. The usual protection does not apply here: shared caches are barred
2255
+ * from reusing responses to requests carrying `Authorization`, but yours is
2256
+ * authenticated by cookie, which carries no such rule.
2257
+ *
2258
+ * Accepts a Web `Response` (Next.js App Router, Workers, Deno) or a Node
2259
+ * `ServerResponse` (Express, Next.js Pages Router). Use {@link AUTH_CACHE_HEADERS}
2260
+ * directly where a framework takes a plain header map instead.
2261
+ *
2262
+ * @example
2263
+ * // Next.js App Router
2264
+ * export async function POST(request: Request) {
2265
+ * const { data } = await nulvless.auth.signIn(params, {
2266
+ * headers: forwardUserHeaders(request),
2267
+ * })
2268
+ *
2269
+ * const response = NextResponse.json({ ok: true })
2270
+ * response.cookies.set('session', data.access_token)
2271
+ *
2272
+ * return applyAuthCacheHeaders(response)
2273
+ * }
2274
+ *
2275
+ * @example
2276
+ * // Express
2277
+ * app.post('/login', async (req, res) => {
2278
+ * const { data } = await nulvless.auth.signIn(params, {
2279
+ * headers: forwardUserHeaders(req),
2280
+ * })
2281
+ *
2282
+ * applyAuthCacheHeaders(res)
2283
+ * res.cookie('session', data.access_token, { httpOnly: true, sameSite: 'lax' })
2284
+ * res.json({ ok: true })
2285
+ * })
2286
+ */
2287
+ declare function applyAuthCacheHeaders<T>(response: T): T;
2288
+
2289
+ /**
2290
+ * Creates a browser-safe client using a public key (`pk_...`).
2291
+ *
2292
+ * Exposes: `.auth`
2293
+ *
2294
+ * @example
2295
+ * import { createClient } from '@nulvless/nulvless-js'
2296
+ *
2297
+ * const nulvless = createClient('https://auth.example.com', 'pk_live_...')
2298
+ *
2299
+ * const { data, error } = await nulvless.auth.signIn({
2300
+ * email: 'user@example.com',
2301
+ * password: 'secret',
2302
+ * })
2303
+ */
2304
+ declare function createClient(url: string, publicKey: string, options?: ClientOptions): NulvlessClient;
2305
+ /**
2306
+ * Creates a server-side client using a private key (`sk_...`).
2307
+ * Never use this in browser code.
2308
+ *
2309
+ * Exposes: `.auth`, `.comms`
2310
+ *
2311
+ * @example
2312
+ * import { createServerClient } from '@nulvless/nulvless-js'
2313
+ *
2314
+ * const nulvless = createServerClient('https://api.example.com', 'sk_live_...')
2315
+ *
2316
+ * const { error } = await nulvless.comms.email.send({
2317
+ * to: 'user@example.com',
2318
+ * template: 'welcome',
2319
+ * params: { name: 'Gleisson' },
2320
+ * })
2321
+ */
2322
+ declare function createServerClient(url: string, privateKey: string, options?: ServerClientOptions): NulvlessServerClient;
2323
+
2324
+ export { AUTH_CACHE_HEADERS, type AccountEntry, type AddEmailIdentityParams, type AddPhoneIdentityParams, AdminClient, type AdminCreateUserParams, type AdminUpdateUserParams, type AssuranceLevel, AuthBrowserClient, AuthClient, AuthEventEmitter, type AuthEvents, type AuthFactorStatus, type AuthMethod, type AuthMethods, type AuthOptions, AuthServerClient, type Authenticated, type BlockGrantParams, type Challenge, type ChallengeSubject, type ChangeChallengeParams, type ChangePasswordParams, type ClientOptions, CommsClient, type ConfirmationType, type CreateRoleParams, type CreateTemplateParams, EmailClient, type EnableFactorParams, type EnrollFactorParams, type ExchangeOAuthCodeParams, type FactorEnrollment, FactorsClient, type Grant, type GrantMembers, type GrantStatus, GrantsClient, HttpClient, type Identity, type IdentityType, type Invite, type InviteParams, type Language, type LeaveGrantParams, type LookupMatch, type LookupParams, type LookupResult, type MFAMethod, type Nonce, type NotificationChannel, NulvlessClient, type NulvlessError, NulvlessException, type NulvlessResult, NulvlessServerClient, type NulvlessStorage, type OAuthApp, type OAuthAppGrantType, type OAuthAppTokenEndpointAuthMethod, type OAuthAppType, type OAuthAuthorization, type OAuthAuthorizeParams, OAuthClient, type OAuthConsentAction, type OAuthConsentResult, type OAuthDiscovery, OAuthGrantsClient, type OAuthJWKS, type OAuthProvider, type OAuthTokenResponse, type OAuthUserGrant, type OAuthUserInfo, type PaginateGrantsParams, type PaginateUsersParams, type Paginated, type PaginatedTemplates, type PaginationSort, type Phone, type PlatformInfo, type RecoverParams, type RefreshOAuthTokenParams, type RefreshTokenParams, type RegisterOAuthAppParams, type RemoveIdentityParams, type RequestOptions, type ResetPasswordParams, type RevokeGrantParams, type RevokeSessionParams, type Role, SecurityClient, type SendEmailParams, type SendOTPToUpdateEmailParams, type SendOTPToUpdatePhoneParams, type SendSMSParams, type ServerClientOptions, type Session, type SessionFingerPrint, SessionManager, SessionsClient, type SetGrantParams, type SignInMethod, type SignInParams, type SignInWithOTPParams, type SignOutScope, type SignUpParams, SmsClient, Storage, type StoredSession, type SudoMethod, type Template, type TemplateFilters, type TemplateLanguage, TemplatesClient, type TokenType, type UnenrollFactorParams, type UpdateGrantParams, type UpdateIdentityParams, type UpdateOAuthAppParams, type UpdateRoleParams, type UpdateTemplateParams, type User, type UserGender, type UserProfile, UsersClient, type Verified, type VerifyChallengeParams, type VerifyParams, type VerifyReason, applyAuthCacheHeaders, createClient, createServerClient, forwardUserHeaders };