@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.
- package/LICENSE +21 -0
- package/README.md +97 -0
- package/dist/index.cjs +2557 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2324 -0
- package/dist/index.d.ts +2324 -0
- package/dist/index.mjs +2529 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +73 -0
package/dist/index.d.cts
ADDED
|
@@ -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 };
|