@better-auth/infra 0.3.7 → 0.4.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/CHANGELOG.md +24 -0
- package/README.md +12 -1
- package/dist/client.d.mts +7 -2
- package/dist/client.mjs +4 -14
- package/dist/{constants-AfApXLhx.mjs → constants-CcJHk5SE.mjs} +1 -1
- package/dist/{crypto--3ycICW4.mjs → crypto-CAdWFWEz.mjs} +3 -3
- package/dist/email.d.mts +11 -0
- package/dist/email.mjs +2 -2
- package/dist/{dash-client-DXuu2ctl.d.mts → identify-client-options-RI-JiXQx.d.mts} +16 -1
- package/dist/index.d.mts +256 -569
- package/dist/index.mjs +2116 -306
- package/dist/native.d.mts +7 -2
- package/dist/native.mjs +5 -15
- package/dist/{pow-retry-Dy1D-TKx.mjs → pow-retry-DZhZiYd_.mjs} +17 -2
- package/dist/saml-policy-BTVLoTyS.mjs +12 -0
- package/dist/types-B673lCib.d.mts +673 -0
- package/package.json +5 -4
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
import { BetterAuthPlugin, GenericEndpointContext } from "better-auth";
|
|
2
|
+
import { createFetch } from "@better-fetch/fetch";
|
|
3
|
+
import { APIError as APIError$1, Endpoint, EndpointOptions } from "better-call";
|
|
4
|
+
|
|
5
|
+
//#region src/identification.d.ts
|
|
6
|
+
interface IPLocation {
|
|
7
|
+
lat: number;
|
|
8
|
+
lng: number;
|
|
9
|
+
city: string | null;
|
|
10
|
+
region: string | null;
|
|
11
|
+
postalCode: string | null;
|
|
12
|
+
country: {
|
|
13
|
+
code: string;
|
|
14
|
+
name: string;
|
|
15
|
+
} | null;
|
|
16
|
+
timezone: string | null;
|
|
17
|
+
}
|
|
18
|
+
interface Identification {
|
|
19
|
+
visitorId: string;
|
|
20
|
+
requestId: string;
|
|
21
|
+
timestamp: number;
|
|
22
|
+
url: string;
|
|
23
|
+
ip: string | null;
|
|
24
|
+
location: IPLocation | null;
|
|
25
|
+
browser: {
|
|
26
|
+
name: string | null;
|
|
27
|
+
version: string | null;
|
|
28
|
+
os: string | null;
|
|
29
|
+
osVersion: string | null;
|
|
30
|
+
device: string | null;
|
|
31
|
+
userAgent: string | null;
|
|
32
|
+
};
|
|
33
|
+
confidence: number;
|
|
34
|
+
incognito: boolean;
|
|
35
|
+
bot: "notDetected" | "detected" | "unknown";
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/sentinel/security.d.ts
|
|
39
|
+
type SecurityAction = "log" | "block" | "challenge";
|
|
40
|
+
interface ThresholdConfig {
|
|
41
|
+
challenge?: number;
|
|
42
|
+
block?: number;
|
|
43
|
+
}
|
|
44
|
+
interface SecurityOptions {
|
|
45
|
+
unknownDeviceNotification?: boolean;
|
|
46
|
+
credentialStuffing?: {
|
|
47
|
+
enabled: boolean;
|
|
48
|
+
action?: SecurityAction;
|
|
49
|
+
thresholds?: ThresholdConfig;
|
|
50
|
+
windowSeconds?: number;
|
|
51
|
+
cooldownSeconds?: number;
|
|
52
|
+
};
|
|
53
|
+
impossibleTravel?: {
|
|
54
|
+
enabled: boolean;
|
|
55
|
+
maxSpeedKmh?: number;
|
|
56
|
+
action?: SecurityAction;
|
|
57
|
+
};
|
|
58
|
+
geoBlocking?: {
|
|
59
|
+
allowList?: string[];
|
|
60
|
+
denyList?: string[];
|
|
61
|
+
action?: "block" | "challenge";
|
|
62
|
+
};
|
|
63
|
+
botBlocking?: boolean | {
|
|
64
|
+
action: SecurityAction;
|
|
65
|
+
};
|
|
66
|
+
suspiciousIpBlocking?: boolean | {
|
|
67
|
+
action: SecurityAction;
|
|
68
|
+
};
|
|
69
|
+
velocity?: {
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
thresholds?: ThresholdConfig;
|
|
72
|
+
maxSignupsPerVisitor?: number;
|
|
73
|
+
maxPasswordResetsPerIp?: number;
|
|
74
|
+
maxSignInsPerIp?: number;
|
|
75
|
+
windowSeconds?: number;
|
|
76
|
+
action?: SecurityAction;
|
|
77
|
+
};
|
|
78
|
+
freeTrialAbuse?: {
|
|
79
|
+
enabled: boolean;
|
|
80
|
+
thresholds?: ThresholdConfig;
|
|
81
|
+
maxAccountsPerVisitor?: number;
|
|
82
|
+
action?: SecurityAction;
|
|
83
|
+
};
|
|
84
|
+
compromisedPassword?: {
|
|
85
|
+
enabled: boolean;
|
|
86
|
+
action?: SecurityAction;
|
|
87
|
+
minBreachCount?: number;
|
|
88
|
+
};
|
|
89
|
+
emailValidation?: {
|
|
90
|
+
enabled?: boolean;
|
|
91
|
+
strictness?: "low" | "medium" | "high";
|
|
92
|
+
action?: SecurityAction;
|
|
93
|
+
domainAllowlist?: string[];
|
|
94
|
+
};
|
|
95
|
+
emailNormalization?: {
|
|
96
|
+
enabled?: boolean;
|
|
97
|
+
};
|
|
98
|
+
staleUsers?: {
|
|
99
|
+
enabled: boolean;
|
|
100
|
+
staleDays?: number;
|
|
101
|
+
action?: SecurityAction;
|
|
102
|
+
notifyUser?: boolean;
|
|
103
|
+
notifyAdmin?: boolean;
|
|
104
|
+
adminEmail?: string;
|
|
105
|
+
};
|
|
106
|
+
challengeDifficulty?: number;
|
|
107
|
+
}
|
|
108
|
+
interface SecurityVerdict {
|
|
109
|
+
action: "allow" | "challenge" | "block";
|
|
110
|
+
challenge?: string;
|
|
111
|
+
reason?: string;
|
|
112
|
+
details?: Record<string, unknown>;
|
|
113
|
+
/** Set when the request included a valid, consumed PoW solution. */
|
|
114
|
+
powVerified?: boolean;
|
|
115
|
+
}
|
|
116
|
+
interface CredentialStuffingResult {
|
|
117
|
+
blocked: boolean;
|
|
118
|
+
challenged?: boolean;
|
|
119
|
+
challenge?: string;
|
|
120
|
+
reason?: string;
|
|
121
|
+
details?: Record<string, unknown>;
|
|
122
|
+
}
|
|
123
|
+
interface ImpossibleTravelResult {
|
|
124
|
+
isImpossible: boolean;
|
|
125
|
+
action?: "allow" | "challenge" | "block";
|
|
126
|
+
challenged?: boolean;
|
|
127
|
+
challenge?: string;
|
|
128
|
+
powVerified?: boolean;
|
|
129
|
+
distance?: number;
|
|
130
|
+
timeElapsedHours?: number;
|
|
131
|
+
speedRequired?: number;
|
|
132
|
+
from?: {
|
|
133
|
+
city: string | null;
|
|
134
|
+
country: string | null;
|
|
135
|
+
} | null;
|
|
136
|
+
to?: {
|
|
137
|
+
city: string | null;
|
|
138
|
+
country: string | null;
|
|
139
|
+
} | null;
|
|
140
|
+
}
|
|
141
|
+
interface CompromisedPasswordResult {
|
|
142
|
+
compromised: boolean;
|
|
143
|
+
breachCount?: number;
|
|
144
|
+
action?: SecurityAction;
|
|
145
|
+
}
|
|
146
|
+
interface StaleUserResult {
|
|
147
|
+
isStale: boolean;
|
|
148
|
+
daysSinceLastActive?: number;
|
|
149
|
+
staleDays?: number;
|
|
150
|
+
lastActiveAt?: string | null;
|
|
151
|
+
action?: SecurityAction;
|
|
152
|
+
notifyUser?: boolean;
|
|
153
|
+
notifyAdmin?: boolean;
|
|
154
|
+
}
|
|
155
|
+
interface SecurityEvent {
|
|
156
|
+
type: SecurityEventType;
|
|
157
|
+
timestamp: number;
|
|
158
|
+
userId: string | null;
|
|
159
|
+
visitorId: string | null;
|
|
160
|
+
ip: string | null;
|
|
161
|
+
country: string | null;
|
|
162
|
+
details: Record<string, unknown>;
|
|
163
|
+
action: "logged" | "blocked" | "challenged";
|
|
164
|
+
}
|
|
165
|
+
type SecurityEventType = "unknown_device" | "credential_stuffing" | "impossible_travel" | "geo_blocked" | "bot_blocked" | "suspicious_ip_detected" | "velocity_exceeded" | "free_trial_abuse" | "compromised_password" | "stale_account_reactivation";
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/sentinel/sentinel.d.ts
|
|
168
|
+
declare const sentinel: (options?: SentinelOptions) => {
|
|
169
|
+
id: "sentinel";
|
|
170
|
+
init(ctx: import("better-auth").AuthContext): {
|
|
171
|
+
options: {
|
|
172
|
+
emailValidation: {
|
|
173
|
+
enabled?: boolean;
|
|
174
|
+
strictness?: "low" | "medium" | "high";
|
|
175
|
+
action?: SecurityAction;
|
|
176
|
+
domainAllowlist?: string[];
|
|
177
|
+
} | undefined;
|
|
178
|
+
emailNormalization: {
|
|
179
|
+
enabled?: boolean;
|
|
180
|
+
} | undefined;
|
|
181
|
+
databaseHooks: {
|
|
182
|
+
user: {
|
|
183
|
+
create: {
|
|
184
|
+
before(user: {
|
|
185
|
+
id: string;
|
|
186
|
+
createdAt: Date;
|
|
187
|
+
updatedAt: Date;
|
|
188
|
+
email: string;
|
|
189
|
+
emailVerified: boolean;
|
|
190
|
+
name: string;
|
|
191
|
+
image?: string | null | undefined;
|
|
192
|
+
} & Record<string, unknown>, ctx: import("better-auth").GenericEndpointContext | null): Promise<{
|
|
193
|
+
data: {
|
|
194
|
+
email: string;
|
|
195
|
+
id: string;
|
|
196
|
+
createdAt: Date;
|
|
197
|
+
updatedAt: Date;
|
|
198
|
+
emailVerified: boolean;
|
|
199
|
+
name: string;
|
|
200
|
+
image?: string | null | undefined;
|
|
201
|
+
};
|
|
202
|
+
} | undefined>;
|
|
203
|
+
after(user: {
|
|
204
|
+
id: string;
|
|
205
|
+
createdAt: Date;
|
|
206
|
+
updatedAt: Date;
|
|
207
|
+
email: string;
|
|
208
|
+
emailVerified: boolean;
|
|
209
|
+
name: string;
|
|
210
|
+
image?: string | null | undefined;
|
|
211
|
+
} & Record<string, unknown>, ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
|
|
212
|
+
};
|
|
213
|
+
update: {
|
|
214
|
+
before(user: Partial<{
|
|
215
|
+
id: string;
|
|
216
|
+
createdAt: Date;
|
|
217
|
+
updatedAt: Date;
|
|
218
|
+
email: string;
|
|
219
|
+
emailVerified: boolean;
|
|
220
|
+
name: string;
|
|
221
|
+
image?: string | null | undefined;
|
|
222
|
+
}> & Record<string, unknown>, ctx: import("better-auth").GenericEndpointContext | null): Promise<{
|
|
223
|
+
data: {
|
|
224
|
+
email: string;
|
|
225
|
+
id?: string | undefined;
|
|
226
|
+
createdAt?: Date | undefined;
|
|
227
|
+
updatedAt?: Date | undefined;
|
|
228
|
+
emailVerified?: boolean | undefined;
|
|
229
|
+
name?: string | undefined;
|
|
230
|
+
image?: string | null | undefined;
|
|
231
|
+
};
|
|
232
|
+
} | undefined>;
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
session: {
|
|
236
|
+
create: {
|
|
237
|
+
before(session: {
|
|
238
|
+
id: string;
|
|
239
|
+
createdAt: Date;
|
|
240
|
+
updatedAt: Date;
|
|
241
|
+
userId: string;
|
|
242
|
+
expiresAt: Date;
|
|
243
|
+
token: string;
|
|
244
|
+
ipAddress?: string | null | undefined;
|
|
245
|
+
userAgent?: string | null | undefined;
|
|
246
|
+
} & Record<string, unknown>, ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
|
|
247
|
+
after(session: {
|
|
248
|
+
id: string;
|
|
249
|
+
createdAt: Date;
|
|
250
|
+
updatedAt: Date;
|
|
251
|
+
userId: string;
|
|
252
|
+
expiresAt: Date;
|
|
253
|
+
token: string;
|
|
254
|
+
ipAddress?: string | null | undefined;
|
|
255
|
+
userAgent?: string | null | undefined;
|
|
256
|
+
} & Record<string, unknown>, ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
|
|
257
|
+
};
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
hooks: {
|
|
263
|
+
before: ({
|
|
264
|
+
matcher: (context: Pick<import("better-auth").HookEndpointContext, "path">) => boolean;
|
|
265
|
+
handler: (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
266
|
+
context: {
|
|
267
|
+
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
268
|
+
path: string;
|
|
269
|
+
body: any;
|
|
270
|
+
query: Record<string, any> | undefined;
|
|
271
|
+
params: Record<string, any> & string;
|
|
272
|
+
request: Request | undefined;
|
|
273
|
+
headers: Headers | undefined;
|
|
274
|
+
setHeader: ((key: string, value: string) => void) & ((key: string, value: string) => void);
|
|
275
|
+
setStatus: (status: import("better-call").Status) => void;
|
|
276
|
+
getHeader: ((key: string) => string | null) & ((key: string) => string | null);
|
|
277
|
+
getCookie: (key: string, prefix?: import("better-call").CookiePrefixOptions) => string | null;
|
|
278
|
+
getSignedCookie: (key: string, secret: string, prefix?: import("better-call").CookiePrefixOptions) => Promise<string | null | false>;
|
|
279
|
+
setCookie: (key: string, value: string, options?: import("better-call").CookieOptions) => string;
|
|
280
|
+
setSignedCookie: (key: string, value: string, secret: string, options?: import("better-call").CookieOptions) => Promise<string>;
|
|
281
|
+
responseHeaders: Headers;
|
|
282
|
+
json: (<R extends Record<string, any> | null>(json: R, routerResponse?: {
|
|
283
|
+
status?: number;
|
|
284
|
+
headers?: Record<string, string>;
|
|
285
|
+
response?: Response;
|
|
286
|
+
body?: Record<string, string>;
|
|
287
|
+
} | Response) => Promise<R>) & (<R extends Record<string, any> | null>(json: R, routerResponse?: {
|
|
288
|
+
status?: number;
|
|
289
|
+
headers?: Record<string, string>;
|
|
290
|
+
response?: Response;
|
|
291
|
+
} | Response) => Promise<R>);
|
|
292
|
+
context: {
|
|
293
|
+
[x: string]: any;
|
|
294
|
+
} & {
|
|
295
|
+
returned?: unknown | undefined;
|
|
296
|
+
responseHeaders?: Headers | undefined;
|
|
297
|
+
getPlugin: <ID extends import("better-auth").BetterAuthPluginRegistryIdentifier | import("better-auth").LiteralString, PluginOptions extends never>(pluginId: ID) => (ID extends keyof import("better-auth").BetterAuthPluginRegistry<unknown, unknown> ? import("better-auth").BetterAuthPluginRegistry<import("better-auth").BetterAuthOptions, PluginOptions>[ID] extends {
|
|
298
|
+
creator: infer C;
|
|
299
|
+
} ? C extends ((...args: any[]) => infer R) ? R : never : never : BetterAuthPlugin) | null;
|
|
300
|
+
hasPlugin: <ID extends import("better-auth").BetterAuthPluginRegistryIdentifier | import("better-auth").LiteralString>(pluginId: ID) => ID extends never ? true : boolean;
|
|
301
|
+
appName: string;
|
|
302
|
+
baseURL: string;
|
|
303
|
+
version: string;
|
|
304
|
+
options: import("better-auth").BetterAuthOptions;
|
|
305
|
+
trustedOrigins: string[];
|
|
306
|
+
trustedProviders: string[];
|
|
307
|
+
isTrustedOrigin: (url: string, settings?: {
|
|
308
|
+
allowRelativePaths: boolean;
|
|
309
|
+
}) => boolean;
|
|
310
|
+
oauthConfig: {
|
|
311
|
+
skipStateCookieCheck?: boolean | undefined;
|
|
312
|
+
storeStateStrategy: "database" | "cookie";
|
|
313
|
+
};
|
|
314
|
+
newSession: {
|
|
315
|
+
session: {
|
|
316
|
+
id: string;
|
|
317
|
+
createdAt: Date;
|
|
318
|
+
updatedAt: Date;
|
|
319
|
+
userId: string;
|
|
320
|
+
expiresAt: Date;
|
|
321
|
+
token: string;
|
|
322
|
+
ipAddress?: string | null | undefined;
|
|
323
|
+
userAgent?: string | null | undefined;
|
|
324
|
+
} & Record<string, any>;
|
|
325
|
+
user: {
|
|
326
|
+
id: string;
|
|
327
|
+
createdAt: Date;
|
|
328
|
+
updatedAt: Date;
|
|
329
|
+
email: string;
|
|
330
|
+
emailVerified: boolean;
|
|
331
|
+
name: string;
|
|
332
|
+
image?: string | null | undefined;
|
|
333
|
+
} & Record<string, any>;
|
|
334
|
+
} | null;
|
|
335
|
+
session: {
|
|
336
|
+
session: {
|
|
337
|
+
id: string;
|
|
338
|
+
createdAt: Date;
|
|
339
|
+
updatedAt: Date;
|
|
340
|
+
userId: string;
|
|
341
|
+
expiresAt: Date;
|
|
342
|
+
token: string;
|
|
343
|
+
ipAddress?: string | null | undefined;
|
|
344
|
+
userAgent?: string | null | undefined;
|
|
345
|
+
} & Record<string, any>;
|
|
346
|
+
user: {
|
|
347
|
+
id: string;
|
|
348
|
+
createdAt: Date;
|
|
349
|
+
updatedAt: Date;
|
|
350
|
+
email: string;
|
|
351
|
+
emailVerified: boolean;
|
|
352
|
+
name: string;
|
|
353
|
+
image?: string | null | undefined;
|
|
354
|
+
} & Record<string, any>;
|
|
355
|
+
} | null;
|
|
356
|
+
setNewSession: (session: {
|
|
357
|
+
session: {
|
|
358
|
+
id: string;
|
|
359
|
+
createdAt: Date;
|
|
360
|
+
updatedAt: Date;
|
|
361
|
+
userId: string;
|
|
362
|
+
expiresAt: Date;
|
|
363
|
+
token: string;
|
|
364
|
+
ipAddress?: string | null | undefined;
|
|
365
|
+
userAgent?: string | null | undefined;
|
|
366
|
+
} & Record<string, any>;
|
|
367
|
+
user: {
|
|
368
|
+
id: string;
|
|
369
|
+
createdAt: Date;
|
|
370
|
+
updatedAt: Date;
|
|
371
|
+
email: string;
|
|
372
|
+
emailVerified: boolean;
|
|
373
|
+
name: string;
|
|
374
|
+
image?: string | null | undefined;
|
|
375
|
+
} & Record<string, any>;
|
|
376
|
+
} | null) => void;
|
|
377
|
+
socialProviders: import("better-auth").OAuthProvider[];
|
|
378
|
+
authCookies: import("better-auth").BetterAuthCookies;
|
|
379
|
+
logger: ReturnType<(options?: import("better-auth").Logger | undefined) => import("better-auth").InternalLogger>;
|
|
380
|
+
rateLimit: {
|
|
381
|
+
enabled: boolean;
|
|
382
|
+
window: number;
|
|
383
|
+
max: number;
|
|
384
|
+
storage: "memory" | "database" | "secondary-storage";
|
|
385
|
+
} & Omit<import("better-auth").BetterAuthRateLimitOptions, "enabled" | "window" | "max" | "storage">;
|
|
386
|
+
adapter: import("better-auth").DBAdapter<import("better-auth").BetterAuthOptions>;
|
|
387
|
+
internalAdapter: import("better-auth").InternalAdapter<import("better-auth").BetterAuthOptions>;
|
|
388
|
+
createAuthCookie: (cookieName: string, overrideAttributes?: Partial<import("better-call").CookieOptions> | undefined) => import("better-auth").BetterAuthCookie;
|
|
389
|
+
secret: string;
|
|
390
|
+
secretConfig: string | import("better-auth").SecretConfig;
|
|
391
|
+
sessionConfig: {
|
|
392
|
+
updateAge: number;
|
|
393
|
+
expiresIn: number;
|
|
394
|
+
freshAge: number;
|
|
395
|
+
cookieRefreshCache: false | {
|
|
396
|
+
enabled: true;
|
|
397
|
+
updateAge: number;
|
|
398
|
+
};
|
|
399
|
+
};
|
|
400
|
+
generateId: (options: {
|
|
401
|
+
model: import("better-auth").ModelNames;
|
|
402
|
+
size?: number | undefined;
|
|
403
|
+
}) => string | false;
|
|
404
|
+
secondaryStorage: import("better-auth").SecondaryStorage | undefined;
|
|
405
|
+
password: {
|
|
406
|
+
hash: (password: string) => Promise<string>;
|
|
407
|
+
verify: (data: {
|
|
408
|
+
password: string;
|
|
409
|
+
hash: string;
|
|
410
|
+
}) => Promise<boolean>;
|
|
411
|
+
config: {
|
|
412
|
+
minPasswordLength: number;
|
|
413
|
+
maxPasswordLength: number;
|
|
414
|
+
};
|
|
415
|
+
checkPassword: (userId: string, ctx: import("better-auth").GenericEndpointContext<import("better-auth").BetterAuthOptions>) => Promise<boolean>;
|
|
416
|
+
};
|
|
417
|
+
tables: import("better-auth").BetterAuthDBSchema;
|
|
418
|
+
runMigrations: () => Promise<void>;
|
|
419
|
+
publishTelemetry: (event: {
|
|
420
|
+
type: string;
|
|
421
|
+
anonymousId?: string | undefined;
|
|
422
|
+
payload: Record<string, any>;
|
|
423
|
+
}) => Promise<void>;
|
|
424
|
+
skipOriginCheck: boolean | string[];
|
|
425
|
+
skipCSRFCheck: boolean;
|
|
426
|
+
runInBackground: (promise: Promise<unknown>) => void;
|
|
427
|
+
runInBackgroundOrAwait: (promise: Promise<unknown> | void) => import("better-auth").Awaitable<unknown>;
|
|
428
|
+
};
|
|
429
|
+
redirect: (url: string) => import("better-call").APIError;
|
|
430
|
+
error: (status: ("OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "REQUEST_TIMEOUT" | "CONFLICT" | "GONE" | "LENGTH_REQUIRED" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "URI_TOO_LONG" | "UNSUPPORTED_MEDIA_TYPE" | "RANGE_NOT_SATISFIABLE" | "EXPECTATION_FAILED" | "I'M_A_TEAPOT" | "MISDIRECTED_REQUEST" | "UNPROCESSABLE_ENTITY" | "LOCKED" | "FAILED_DEPENDENCY" | "TOO_EARLY" | "UPGRADE_REQUIRED" | "PRECONDITION_REQUIRED" | "TOO_MANY_REQUESTS" | "REQUEST_HEADER_FIELDS_TOO_LARGE" | "UNAVAILABLE_FOR_LEGAL_REASONS" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "HTTP_VERSION_NOT_SUPPORTED" | "VARIANT_ALSO_NEGOTIATES" | "INSUFFICIENT_STORAGE" | "LOOP_DETECTED" | "NOT_EXTENDED" | "NETWORK_AUTHENTICATION_REQUIRED") | import("better-call").Status, body?: {
|
|
431
|
+
message?: string;
|
|
432
|
+
code?: string;
|
|
433
|
+
} & Record<string, any>, headers?: HeadersInit) => import("better-call").APIError;
|
|
434
|
+
};
|
|
435
|
+
} | undefined>;
|
|
436
|
+
} | {
|
|
437
|
+
matcher: (ctx: import("better-auth").HookEndpointContext) => boolean;
|
|
438
|
+
handler: (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>;
|
|
439
|
+
})[];
|
|
440
|
+
after: {
|
|
441
|
+
matcher: (ctx: import("better-auth").HookEndpointContext) => boolean;
|
|
442
|
+
handler: (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>;
|
|
443
|
+
}[];
|
|
444
|
+
};
|
|
445
|
+
};
|
|
446
|
+
//#endregion
|
|
447
|
+
//#region src/types.d.ts
|
|
448
|
+
/**
|
|
449
|
+
* Retry/backoff for identify HTTP calls.
|
|
450
|
+
*/
|
|
451
|
+
interface KvRetryOptions {
|
|
452
|
+
/**
|
|
453
|
+
* Max retry index after a thrown failure. `0` = single attempt.
|
|
454
|
+
* @default 2
|
|
455
|
+
*/
|
|
456
|
+
attempts?: number;
|
|
457
|
+
/**
|
|
458
|
+
* Base delay (ms) before the first retry.
|
|
459
|
+
* @default 400
|
|
460
|
+
*/
|
|
461
|
+
baseDelay?: number;
|
|
462
|
+
/**
|
|
463
|
+
* Cap for exponential retry delay (ms).
|
|
464
|
+
* @default 600
|
|
465
|
+
*/
|
|
466
|
+
maxDelay?: number;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Resolved {@link KvRetryOptions} with defaults applied.
|
|
470
|
+
*/
|
|
471
|
+
type KvRetryOptionsResolved = Required<KvRetryOptions>;
|
|
472
|
+
/**
|
|
473
|
+
* Dash API HTTP client options.
|
|
474
|
+
*/
|
|
475
|
+
interface ApiOptions {
|
|
476
|
+
/**
|
|
477
|
+
* Timeout for Dash API HTTP requests (milliseconds).
|
|
478
|
+
* @default 3000
|
|
479
|
+
*/
|
|
480
|
+
timeout?: number;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Resolved {@link ApiOptions} with defaults applied.
|
|
484
|
+
*/
|
|
485
|
+
type ApiOptionsResolved = Required<ApiOptions>;
|
|
486
|
+
/**
|
|
487
|
+
* KV HTTP client options.
|
|
488
|
+
*/
|
|
489
|
+
interface KvOptions {
|
|
490
|
+
/**
|
|
491
|
+
* Timeout for KV HTTP requests (milliseconds).
|
|
492
|
+
* @default 1000
|
|
493
|
+
*/
|
|
494
|
+
timeout?: number;
|
|
495
|
+
/**
|
|
496
|
+
* Retry/backoff for KV identify lookups.
|
|
497
|
+
* @default { attempts: 2, baseDelay: 400, maxDelay: 600 }
|
|
498
|
+
*/
|
|
499
|
+
retry?: KvRetryOptions;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Resolved {@link KvOptions} with defaults applied.
|
|
503
|
+
*/
|
|
504
|
+
interface KvOptionsResolved {
|
|
505
|
+
timeout: number;
|
|
506
|
+
retry: KvRetryOptionsResolved;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Shared connection options used by infra plugins.
|
|
510
|
+
*/
|
|
511
|
+
interface InfraPluginConnectionOptions {
|
|
512
|
+
/**
|
|
513
|
+
* The URL of the Better Auth Dash API
|
|
514
|
+
* @default "https://dash.better-auth.com"
|
|
515
|
+
*/
|
|
516
|
+
apiUrl?: string;
|
|
517
|
+
/**
|
|
518
|
+
* The URL of the KV storage service
|
|
519
|
+
* @default "https://kv.better-auth.com"
|
|
520
|
+
*/
|
|
521
|
+
kvUrl?: string;
|
|
522
|
+
/**
|
|
523
|
+
* Your Better Auth Dash API key
|
|
524
|
+
* @default process.env.BETTER_AUTH_API_KEY
|
|
525
|
+
*/
|
|
526
|
+
apiKey?: string;
|
|
527
|
+
/**
|
|
528
|
+
* Dash API HTTP client options.
|
|
529
|
+
*/
|
|
530
|
+
apiOptions?: ApiOptions;
|
|
531
|
+
/**
|
|
532
|
+
* KV HTTP client options.
|
|
533
|
+
*/
|
|
534
|
+
kvOptions?: KvOptions;
|
|
535
|
+
/**
|
|
536
|
+
* Timeout for Dash API HTTP requests (milliseconds).
|
|
537
|
+
* @default 3000
|
|
538
|
+
* @deprecated Use `apiOptions.timeout` instead.
|
|
539
|
+
*/
|
|
540
|
+
apiTimeout?: number;
|
|
541
|
+
/**
|
|
542
|
+
* Timeout for KV HTTP requests (milliseconds).
|
|
543
|
+
* @default 1000
|
|
544
|
+
* @deprecated Use `kvOptions.timeout` instead.
|
|
545
|
+
*/
|
|
546
|
+
kvTimeout?: number;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Configuration options for the dash plugin.
|
|
550
|
+
*/
|
|
551
|
+
interface DashOptions extends InfraPluginConnectionOptions {
|
|
552
|
+
/**
|
|
553
|
+
* User activity tracking configuration
|
|
554
|
+
*/
|
|
555
|
+
activityTracking?: {
|
|
556
|
+
/**
|
|
557
|
+
* Whether to enable user activity tracking
|
|
558
|
+
*
|
|
559
|
+
* This requires a database schema change to the user table.
|
|
560
|
+
* @default false
|
|
561
|
+
*/
|
|
562
|
+
enabled?: boolean;
|
|
563
|
+
/**
|
|
564
|
+
* Interval in milliseconds to update lastActiveAt for active users
|
|
565
|
+
* Set to 0 to disable interval-based tracking
|
|
566
|
+
* @default 300000 (5 minutes)
|
|
567
|
+
*/
|
|
568
|
+
updateInterval?: number;
|
|
569
|
+
};
|
|
570
|
+
/**
|
|
571
|
+
* Opt into the 1.7+ managed directory-sync control plane.
|
|
572
|
+
*
|
|
573
|
+
* Enable together with `scim({ managedConnections })` when the dashboard
|
|
574
|
+
* should reserve and manage SCIM connections. This does not replace or
|
|
575
|
+
* disable legacy pre-1.7 SCIM provider APIs.
|
|
576
|
+
*/
|
|
577
|
+
managedDirectorySync?: {
|
|
578
|
+
/**
|
|
579
|
+
* Whether to enable managed directory-sync reservation tables/APIs.
|
|
580
|
+
*
|
|
581
|
+
* Adds `directorySyncConnection` and
|
|
582
|
+
* `directorySyncMembershipProvenance` via plugin schema.
|
|
583
|
+
* @default false
|
|
584
|
+
*/
|
|
585
|
+
enabled?: boolean;
|
|
586
|
+
/**
|
|
587
|
+
* Install SSO `resolveUser` / `guardProviderMutation` for directory
|
|
588
|
+
* pairing. Required only when creating paired directories. Needs
|
|
589
|
+
* `sso({})` (or richer options) so callbacks can be installed.
|
|
590
|
+
* @default true
|
|
591
|
+
*/
|
|
592
|
+
ssoPairing?: boolean;
|
|
593
|
+
/**
|
|
594
|
+
* SCIM → organization membership projection.
|
|
595
|
+
*
|
|
596
|
+
* When enabled, dash installs SCIM `projection.reconcileUser` so
|
|
597
|
+
* provisioned users are projected into organization memberships.
|
|
598
|
+
*/
|
|
599
|
+
membershipProjection?: {
|
|
600
|
+
/**
|
|
601
|
+
* Whether to install membership projection.
|
|
602
|
+
* @default true
|
|
603
|
+
*/
|
|
604
|
+
enabled?: boolean;
|
|
605
|
+
/**
|
|
606
|
+
* Role assigned when projection creates organization memberships.
|
|
607
|
+
* @default "member"
|
|
608
|
+
*/
|
|
609
|
+
role?: string;
|
|
610
|
+
};
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Configuration options for the sentinel plugin.
|
|
615
|
+
*/
|
|
616
|
+
interface SentinelOptions extends InfraPluginConnectionOptions {
|
|
617
|
+
/**
|
|
618
|
+
* Security features configuration
|
|
619
|
+
*/
|
|
620
|
+
security?: SecurityOptions;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Internal connection options with required fields resolved.
|
|
624
|
+
*/
|
|
625
|
+
interface InfraPluginConnectionOptionsInternal extends Omit<InfraPluginConnectionOptions, "apiOptions" | "kvOptions" | "apiTimeout" | "kvTimeout"> {
|
|
626
|
+
apiUrl: string;
|
|
627
|
+
kvUrl: string;
|
|
628
|
+
apiKey: string;
|
|
629
|
+
apiOptions: ApiOptionsResolved;
|
|
630
|
+
kvOptions: KvOptionsResolved;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Internal options with required fields resolved
|
|
634
|
+
*/
|
|
635
|
+
interface DashOptionsInternal extends Omit<DashOptions, keyof InfraPluginConnectionOptions>, InfraPluginConnectionOptionsInternal {
|
|
636
|
+
/**
|
|
637
|
+
* Shared Dash HTTP client from {@link createAPI}; injected by {@link dash} when wiring endpoints.
|
|
638
|
+
*
|
|
639
|
+
* @internal
|
|
640
|
+
*/
|
|
641
|
+
$api: ReturnType<typeof import("@better-fetch/fetch").createFetch>;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Resolved dash options from {@link resolveDashOptions} / plugin-stored config; excludes injected `$api`.
|
|
645
|
+
*/
|
|
646
|
+
type DashOptionsResolved = Omit<DashOptionsInternal, "$api">;
|
|
647
|
+
/**
|
|
648
|
+
* Internal sentinel options with required fields resolved.
|
|
649
|
+
*/
|
|
650
|
+
interface SentinelOptionsInternal extends Omit<SentinelOptions, keyof InfraPluginConnectionOptions>, InfraPluginConnectionOptionsInternal {}
|
|
651
|
+
/**
|
|
652
|
+
* Location/geo data used across events, audit logs, and request context.
|
|
653
|
+
*/
|
|
654
|
+
interface LocationData {
|
|
655
|
+
ipAddress?: string | null;
|
|
656
|
+
city?: string | null;
|
|
657
|
+
country?: string | null;
|
|
658
|
+
countryCode?: string | null;
|
|
659
|
+
}
|
|
660
|
+
/** @deprecated Use LocationData instead */
|
|
661
|
+
type LocationDataContext = LocationData;
|
|
662
|
+
type InfraEndpointContext = (GenericEndpointContext & {
|
|
663
|
+
context: {
|
|
664
|
+
identification?: Identification | null | undefined;
|
|
665
|
+
visitorId: string | null;
|
|
666
|
+
requestId: string | null;
|
|
667
|
+
ip: string | null;
|
|
668
|
+
untrustedVisitorId: string | null;
|
|
669
|
+
location: LocationData | undefined;
|
|
670
|
+
};
|
|
671
|
+
}) | undefined;
|
|
672
|
+
//#endregion
|
|
673
|
+
export { ImpossibleTravelResult as C, SecurityVerdict as D, SecurityOptions as E, StaleUserResult as O, CredentialStuffingResult as S, SecurityEventType as T, LocationDataContext as _, DashOptionsInternal as a, sentinel as b, EndpointOptions as c, InfraPluginConnectionOptionsInternal as d, KvOptions as f, LocationData as g, KvRetryOptionsResolved as h, DashOptions as i, ThresholdConfig as k, InfraEndpointContext as l, KvRetryOptions as m, ApiOptions as n, DashOptionsResolved as o, KvOptionsResolved as p, ApiOptionsResolved as r, Endpoint as s, APIError$1 as t, InfraPluginConnectionOptions as u, SentinelOptions as v, SecurityEvent as w, CompromisedPasswordResult as x, SentinelOptionsInternal as y };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/infra",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Dashboard and analytics plugin for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
},
|
|
63
63
|
"homepage": "https://better-auth.com",
|
|
64
64
|
"devDependencies": {
|
|
65
|
+
"@better-auth/kysely-adapter": "1.7.0-rc.1",
|
|
65
66
|
"@better-auth/scim": "1.7.0-rc.1",
|
|
66
67
|
"@better-auth/sso": "1.7.0-rc.1",
|
|
67
68
|
"@infra/mocks": "0.0.0",
|
|
@@ -74,14 +75,14 @@
|
|
|
74
75
|
"msw": "^2.14.6",
|
|
75
76
|
"tsdown": "^0.22.0",
|
|
76
77
|
"typescript": "^5.9.2",
|
|
77
|
-
"zod": "
|
|
78
|
+
"zod": "4.3.6"
|
|
78
79
|
},
|
|
79
80
|
"dependencies": {
|
|
80
81
|
"@better-auth/utils": "^0.4.2",
|
|
81
82
|
"@better-fetch/fetch": "1.3.1",
|
|
82
83
|
"better-call": "1.3.7",
|
|
83
|
-
"jose": "^6.
|
|
84
|
-
"libphonenumber-js": "^1.13.
|
|
84
|
+
"jose": "^6.2.4",
|
|
85
|
+
"libphonenumber-js": "^1.13.9"
|
|
85
86
|
},
|
|
86
87
|
"peerDependencies": {
|
|
87
88
|
"better-auth": ">=1.4.0",
|