@better-auth/infra 0.3.6 → 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.
@@ -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.6",
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": "^4.3.6"
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.1.0",
84
- "libphonenumber-js": "^1.13.3"
84
+ "jose": "^6.2.4",
85
+ "libphonenumber-js": "^1.13.9"
85
86
  },
86
87
  "peerDependencies": {
87
88
  "better-auth": ">=1.4.0",