@better-auth/infra 0.4.8 → 0.4.10
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 +16 -0
- package/dist/client.d.mts +3 -3
- package/dist/client.mjs +2 -2
- package/dist/{constants-C8_UJzzu.mjs → constants-DLZKaIkd.mjs} +1 -1
- package/dist/{crypto-DRS7yhmR.mjs → crypto-Doziv2tH.mjs} +1 -1
- package/dist/email.d.mts +12 -13
- package/dist/email.mjs +1 -1
- package/dist/{identify-client-options-DgKA4Eq8.d.mts → identify-client-options-BfGftEgh.d.mts} +1 -1
- package/dist/index.d.mts +30 -18
- package/dist/index.mjs +221 -129
- package/dist/native.d.mts +3 -3
- package/dist/native.mjs +2 -2
- package/dist/{pow-retry-Di0eUKbA.mjs → pow-retry-DIkxDwZf.mjs} +1 -1
- package/dist/{types-BkUWsMpe.d.mts → types-sFD6YavS.d.mts} +2 -0
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,22 @@ All notable changes to `@better-auth/infra` are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0/).
|
|
7
7
|
|
|
8
|
+
## [0.4.10] - 2026-09-21
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`GET /dash/directory-sync/connection-count`** — Project-wide directory sync connection count (`{ count, mode }`). Managed mode counts `active` / `decommissioning` connections; legacy mode counts `scimProvider` rows. Returns 404 when directory sync is unavailable.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **Stored vs resolved auth base** — Platform-stored `baseURL` + `basePath` always rejoin (a path on stored `baseURL` no longer overrides a saved `basePath`). Request-scoped mount resolution still follows Better Auth path-in-`baseURL` via `context.baseURL` (dash config, Sentinel).
|
|
17
|
+
|
|
18
|
+
## [0.4.9] - 2026-09-09
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- **Auth base URL / path** — `GET /dash/config` reports origin + effective mount path when `baseURL` embeds a path or uses dynamic `allowedHosts`. Invitation callbacks, SSO/SCIM endpoint URLs, and Sentinel route matching use the same resolved mount.
|
|
23
|
+
|
|
8
24
|
## [0.4.8] - 2026-09-09
|
|
9
25
|
|
|
10
26
|
### Added
|
package/dist/client.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as DashGetAllAuditLogsInput, i as DashClientOptions, n as DashAuditLog, o as DashGetAuditLogsInput, r as DashAuditLogsResponse, s as dashClient, t as IdentifyClientOptions } from "./identify-client-options-
|
|
1
|
+
import { a as DashGetAllAuditLogsInput, i as DashClientOptions, n as DashAuditLog, o as DashGetAuditLogsInput, r as DashAuditLogsResponse, s as dashClient, t as IdentifyClientOptions } from "./identify-client-options-BfGftEgh.mjs";
|
|
2
2
|
import { BetterFetchPlugin } from "@better-fetch/fetch";
|
|
3
3
|
//#region src/sentinel/client.d.ts
|
|
4
4
|
interface SentinelClientOptions {
|
|
@@ -34,9 +34,9 @@ interface SentinelClientOptions {
|
|
|
34
34
|
*/
|
|
35
35
|
onChallengeFailed?: (error: Error) => void;
|
|
36
36
|
}
|
|
37
|
-
declare const sentinelClient: (options?: SentinelClientOptions) => {
|
|
37
|
+
export declare const sentinelClient: (options?: SentinelClientOptions) => {
|
|
38
38
|
id: "sentinel";
|
|
39
39
|
fetchPlugins: BetterFetchPlugin[];
|
|
40
40
|
};
|
|
41
41
|
//#endregion
|
|
42
|
-
export { type DashAuditLog, type DashAuditLogsResponse, type DashClientOptions, type DashGetAllAuditLogsInput, type DashGetAuditLogsInput, type SentinelClientOptions, dashClient
|
|
42
|
+
export { type DashAuditLog, type DashAuditLogsResponse, type DashClientOptions, type DashGetAllAuditLogsInput, type DashGetAuditLogsInput, type SentinelClientOptions, dashClient };
|
package/dist/client.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as hash, o as createKV } from "./crypto-
|
|
2
|
-
import { a as resolveSentinelClientIdentifyUrl, c as identify, i as solvePoWChallenge, l as dashClient, n as decodePoWChallenge, o as resolveIdentifyClientRetry, r as encodePoWSolution, s as generateRequestId, t as createPowRetryTimeout } from "./pow-retry-
|
|
1
|
+
import { n as hash, o as createKV } from "./crypto-Doziv2tH.mjs";
|
|
2
|
+
import { a as resolveSentinelClientIdentifyUrl, c as identify, i as solvePoWChallenge, l as dashClient, n as decodePoWChallenge, o as resolveIdentifyClientRetry, r as encodePoWSolution, s as generateRequestId, t as createPowRetryTimeout } from "./pow-retry-DIkxDwZf.mjs";
|
|
3
3
|
import { env } from "@better-auth/core/env";
|
|
4
4
|
//#region src/sentinel/fingerprint.ts
|
|
5
5
|
function murmurhash3(str, seed = 0) {
|
package/dist/email.d.mts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
/**
|
|
9
9
|
* Email template definitions with their required variables
|
|
10
10
|
*/
|
|
11
|
-
declare const EMAIL_TEMPLATES: {
|
|
11
|
+
export declare const EMAIL_TEMPLATES: {
|
|
12
12
|
readonly "verify-email": {
|
|
13
13
|
readonly variables: {
|
|
14
14
|
verificationCode?: string;
|
|
@@ -136,14 +136,14 @@ declare const EMAIL_TEMPLATES: {
|
|
|
136
136
|
};
|
|
137
137
|
};
|
|
138
138
|
};
|
|
139
|
-
type EmailTemplateId = keyof typeof EMAIL_TEMPLATES;
|
|
140
|
-
type EmailTemplateVariables<T extends EmailTemplateId> = (typeof EMAIL_TEMPLATES)[T]["variables"];
|
|
141
|
-
interface SendEmailResult {
|
|
139
|
+
export type EmailTemplateId = keyof typeof EMAIL_TEMPLATES;
|
|
140
|
+
export type EmailTemplateVariables<T extends EmailTemplateId> = (typeof EMAIL_TEMPLATES)[T]["variables"];
|
|
141
|
+
export interface SendEmailResult {
|
|
142
142
|
success: boolean;
|
|
143
143
|
messageId?: string;
|
|
144
144
|
error?: string;
|
|
145
145
|
}
|
|
146
|
-
interface EmailConfig {
|
|
146
|
+
export interface EmailConfig {
|
|
147
147
|
apiKey?: string;
|
|
148
148
|
apiUrl?: string;
|
|
149
149
|
/**
|
|
@@ -171,7 +171,7 @@ interface EmailConfig {
|
|
|
171
171
|
/**
|
|
172
172
|
* Type-safe send email options
|
|
173
173
|
*/
|
|
174
|
-
type SendEmailOptions<T extends EmailTemplateId = EmailTemplateId> = {
|
|
174
|
+
export type SendEmailOptions<T extends EmailTemplateId = EmailTemplateId> = {
|
|
175
175
|
/**
|
|
176
176
|
* The template ID to use
|
|
177
177
|
*/
|
|
@@ -192,7 +192,7 @@ type SendEmailOptions<T extends EmailTemplateId = EmailTemplateId> = {
|
|
|
192
192
|
/**
|
|
193
193
|
* Options for sending bulk emails
|
|
194
194
|
*/
|
|
195
|
-
type SendBulkEmailsOptions<T extends EmailTemplateId = EmailTemplateId> = {
|
|
195
|
+
export type SendBulkEmailsOptions<T extends EmailTemplateId = EmailTemplateId> = {
|
|
196
196
|
/**
|
|
197
197
|
* The template ID to use for all emails
|
|
198
198
|
*/
|
|
@@ -216,7 +216,7 @@ type SendBulkEmailsOptions<T extends EmailTemplateId = EmailTemplateId> = {
|
|
|
216
216
|
/**
|
|
217
217
|
* Result of a bulk email send operation
|
|
218
218
|
*/
|
|
219
|
-
interface SendBulkEmailsResult {
|
|
219
|
+
export interface SendBulkEmailsResult {
|
|
220
220
|
success: boolean;
|
|
221
221
|
failures?: Record<string, {
|
|
222
222
|
error?: string;
|
|
@@ -226,7 +226,7 @@ interface SendBulkEmailsResult {
|
|
|
226
226
|
/**
|
|
227
227
|
* Create an email sender instance
|
|
228
228
|
*/
|
|
229
|
-
declare function createEmailSender(config?: EmailConfig): {
|
|
229
|
+
export declare function createEmailSender(config?: EmailConfig): {
|
|
230
230
|
send: <T extends EmailTemplateId>(options: SendEmailOptions<T>) => Promise<SendEmailResult>;
|
|
231
231
|
sendBulk: <T extends EmailTemplateId>(options: SendBulkEmailsOptions<T>) => Promise<SendBulkEmailsResult>;
|
|
232
232
|
getTemplates: () => Promise<{
|
|
@@ -253,7 +253,7 @@ declare function createEmailSender(config?: EmailConfig): {
|
|
|
253
253
|
* });
|
|
254
254
|
* ```
|
|
255
255
|
*/
|
|
256
|
-
declare function sendEmail<T extends EmailTemplateId>(options: SendEmailOptions<T>, config?: EmailConfig): Promise<SendEmailResult>;
|
|
256
|
+
export declare function sendEmail<T extends EmailTemplateId>(options: SendEmailOptions<T>, config?: EmailConfig): Promise<SendEmailResult>;
|
|
257
257
|
/**
|
|
258
258
|
* Send bulk emails using the Better Auth dashboard's email templates.
|
|
259
259
|
*
|
|
@@ -270,6 +270,5 @@ declare function sendEmail<T extends EmailTemplateId>(options: SendEmailOptions<
|
|
|
270
270
|
* });
|
|
271
271
|
* ```
|
|
272
272
|
*/
|
|
273
|
-
declare function sendBulkEmails<T extends EmailTemplateId>(options: SendBulkEmailsOptions<T>, config?: EmailConfig): Promise<SendBulkEmailsResult>;
|
|
274
|
-
//#endregion
|
|
275
|
-
export { EMAIL_TEMPLATES, EmailConfig, EmailTemplateId, EmailTemplateVariables, SendBulkEmailsOptions, SendBulkEmailsResult, SendEmailOptions, SendEmailResult, createEmailSender, sendBulkEmails, sendEmail };
|
|
273
|
+
export declare function sendBulkEmails<T extends EmailTemplateId>(options: SendBulkEmailsOptions<T>, config?: EmailConfig): Promise<SendBulkEmailsResult>;
|
|
274
|
+
//#endregion
|
package/dist/email.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as INFRA_USER_AGENT, n as INFRA_API_URL } from "./constants-
|
|
1
|
+
import { i as INFRA_USER_AGENT, n as INFRA_API_URL } from "./constants-DLZKaIkd.mjs";
|
|
2
2
|
import { logger } from "better-auth";
|
|
3
3
|
import { env } from "@better-auth/core/env";
|
|
4
4
|
import { createFetch } from "@better-fetch/fetch";
|
package/dist/{identify-client-options-DgKA4Eq8.d.mts → identify-client-options-BfGftEgh.d.mts}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as KvRetryOptions } from "./types-
|
|
1
|
+
import { g as KvRetryOptions } from "./types-sFD6YavS.mjs";
|
|
2
2
|
import { BetterAuthClientOptions, ClientStore } from "better-auth";
|
|
3
3
|
import { BetterFetch } from "@better-fetch/fetch";
|
|
4
4
|
//#region src/dash-client.d.ts
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as SecurityOptions, C as createAuthMiddleware, D as ImpossibleTravelResult, E as CredentialStuffingResult, M as StaleUserResult, N as ThresholdConfig, O as SecurityEvent, S as asInfraContext, T as CompromisedPasswordResult, _ as KvRetryOptionsResolved, a as DashOptionsInternal, b as SentinelOptions, c as EndpointOptions, d as InfraEndpointContextValue, f as InfraPluginConnectionOptions, g as KvRetryOptions, h as KvOptionsResolved, i as DashOptions, j as SecurityVerdict, k as SecurityEventType, l as InfraAuthContext, m as KvOptions, n as ApiOptions, o as DashOptionsResolved, p as InfraPluginConnectionOptionsInternal, r as ApiOptionsResolved, s as Endpoint, t as APIError, u as InfraEndpointContext, v as LocationData, w as sentinel, x as SentinelOptionsInternal, y as LocationDataContext } from "./types-
|
|
1
|
+
import { A as SecurityOptions, C as createAuthMiddleware, D as ImpossibleTravelResult, E as CredentialStuffingResult, M as StaleUserResult, N as ThresholdConfig, O as SecurityEvent, S as asInfraContext, T as CompromisedPasswordResult, _ as KvRetryOptionsResolved, a as DashOptionsInternal, b as SentinelOptions, c as EndpointOptions, d as InfraEndpointContextValue, f as InfraPluginConnectionOptions, g as KvRetryOptions, h as KvOptionsResolved, i as DashOptions, j as SecurityVerdict, k as SecurityEventType, l as InfraAuthContext, m as KvOptions, n as ApiOptions, o as DashOptionsResolved, p as InfraPluginConnectionOptionsInternal, r as ApiOptionsResolved, s as Endpoint, t as APIError, u as InfraEndpointContext, v as LocationData, w as sentinel, x as SentinelOptionsInternal, y as LocationDataContext } from "./types-sFD6YavS.mjs";
|
|
2
2
|
import { EMAIL_TEMPLATES, EmailConfig, EmailTemplateId, EmailTemplateVariables, SendBulkEmailsOptions, SendBulkEmailsResult, SendEmailOptions, SendEmailResult, createEmailSender, sendBulkEmails, sendEmail } from "./email.mjs";
|
|
3
3
|
import { Account, AuthContext, GenericEndpointContext, Session, User } from "better-auth";
|
|
4
4
|
import z from "zod";
|
|
@@ -30,26 +30,26 @@ interface PoWSolution {
|
|
|
30
30
|
counter: number;
|
|
31
31
|
}
|
|
32
32
|
/** Default difficulty in bits (18 = ~500ms solve time) */
|
|
33
|
-
declare const DEFAULT_DIFFICULTY = 18;
|
|
33
|
+
export declare const DEFAULT_DIFFICULTY = 18;
|
|
34
34
|
/** Challenge TTL in seconds */
|
|
35
|
-
declare const CHALLENGE_TTL = 60;
|
|
35
|
+
export declare const CHALLENGE_TTL = 60;
|
|
36
36
|
/**
|
|
37
37
|
* Solve a PoW challenge (browser-compatible)
|
|
38
38
|
* This function is designed to run in a browser environment
|
|
39
39
|
*/
|
|
40
|
-
declare function solvePoWChallenge(challenge: PoWChallenge): Promise<PoWSolution>;
|
|
40
|
+
export declare function solvePoWChallenge(challenge: PoWChallenge): Promise<PoWSolution>;
|
|
41
41
|
/**
|
|
42
42
|
* Decode a base64-encoded challenge string (browser-compatible)
|
|
43
43
|
*/
|
|
44
|
-
declare function decodePoWChallenge(encoded: string): PoWChallenge | null;
|
|
44
|
+
export declare function decodePoWChallenge(encoded: string): PoWChallenge | null;
|
|
45
45
|
/**
|
|
46
46
|
* Encode a solution string (browser-compatible)
|
|
47
47
|
*/
|
|
48
|
-
declare function encodePoWSolution(solution: PoWSolution): string;
|
|
48
|
+
export declare function encodePoWSolution(solution: PoWSolution): string;
|
|
49
49
|
/**
|
|
50
50
|
* Verify a PoW solution locally (for testing purposes)
|
|
51
51
|
*/
|
|
52
|
-
declare function verifyPoWSolution(nonce: string, counter: number, difficulty: number): Promise<boolean>;
|
|
52
|
+
export declare function verifyPoWSolution(nonce: string, counter: number, difficulty: number): Promise<boolean>;
|
|
53
53
|
//#endregion
|
|
54
54
|
//#region src/sms.d.ts
|
|
55
55
|
/**
|
|
@@ -61,7 +61,7 @@ declare function verifyPoWSolution(nonce: string, counter: number, difficulty: n
|
|
|
61
61
|
/**
|
|
62
62
|
* SMS template definitions with their required variables
|
|
63
63
|
*/
|
|
64
|
-
declare const SMS_TEMPLATES: {
|
|
64
|
+
export declare const SMS_TEMPLATES: {
|
|
65
65
|
readonly "phone-verification": {
|
|
66
66
|
readonly variables: {
|
|
67
67
|
code: string;
|
|
@@ -140,7 +140,7 @@ interface SendSMSOptions {
|
|
|
140
140
|
/**
|
|
141
141
|
* Create an SMS sender instance
|
|
142
142
|
*/
|
|
143
|
-
declare function createSMSSender(config?: SMSConfig): {
|
|
143
|
+
export declare function createSMSSender(config?: SMSConfig): {
|
|
144
144
|
send: (options: SendSMSOptions) => Promise<SendSMSResult>;
|
|
145
145
|
};
|
|
146
146
|
/**
|
|
@@ -171,7 +171,7 @@ declare function createSMSSender(config?: SMSConfig): {
|
|
|
171
171
|
* });
|
|
172
172
|
* ```
|
|
173
173
|
*/
|
|
174
|
-
declare function sendSMS(options: SendSMSOptions, config?: SMSConfig): Promise<SendSMSResult>;
|
|
174
|
+
export declare function sendSMS(options: SendSMSOptions, config?: SMSConfig): Promise<SendSMSResult>;
|
|
175
175
|
//#endregion
|
|
176
176
|
//#region src/routes/auth/types.d.ts
|
|
177
177
|
type DBField = {
|
|
@@ -205,7 +205,9 @@ interface DashConfigResponse {
|
|
|
205
205
|
deleteUserEnabled: boolean;
|
|
206
206
|
modelName?: string;
|
|
207
207
|
};
|
|
208
|
-
|
|
208
|
+
/** Origin only (never the dynamic allowedHosts object). */
|
|
209
|
+
baseURL: string;
|
|
210
|
+
/** Mount path; reflects path embedded in baseURL when present. */
|
|
209
211
|
basePath: string;
|
|
210
212
|
emailVerification: {
|
|
211
213
|
sendVerificationEmailEnabled: boolean;
|
|
@@ -368,6 +370,10 @@ interface DashDirectoryRegenerateTokenResponse {
|
|
|
368
370
|
scimToken: string;
|
|
369
371
|
scimEndpoint: string;
|
|
370
372
|
}
|
|
373
|
+
interface DashDirectorySyncConnectionCountResponse {
|
|
374
|
+
count: number;
|
|
375
|
+
mode: "managed" | "legacy";
|
|
376
|
+
}
|
|
371
377
|
//#endregion
|
|
372
378
|
//#region src/events/constants.d.ts
|
|
373
379
|
declare const EVENT_TYPES: {
|
|
@@ -414,7 +420,7 @@ declare const ORGANIZATION_EVENT_TYPES: {
|
|
|
414
420
|
readonly ORGANIZATION_TEAM_MEMBER_REMOVED: "organization_team_member_removed";
|
|
415
421
|
};
|
|
416
422
|
/** All audit event type string constants (user + organization). */
|
|
417
|
-
declare const USER_EVENT_TYPES: {
|
|
423
|
+
export declare const USER_EVENT_TYPES: {
|
|
418
424
|
readonly ORGANIZATION_CREATED: "organization_created";
|
|
419
425
|
readonly ORGANIZATION_UPDATED: "organization_updated";
|
|
420
426
|
readonly ORGANIZATION_MEMBER_ADDED: "organization_member_added";
|
|
@@ -789,10 +795,10 @@ interface DashCheckUserExistsResponse {
|
|
|
789
795
|
* @param email - Raw email to normalize
|
|
790
796
|
* @param context - Auth context
|
|
791
797
|
*/
|
|
792
|
-
declare function normalizeEmail(email: string, context: AuthContext): string;
|
|
798
|
+
export declare function normalizeEmail(email: string, context: AuthContext): string;
|
|
793
799
|
//#endregion
|
|
794
800
|
//#region src/index.d.ts
|
|
795
|
-
declare const dash: <O extends DashOptions>(options?: O) => {
|
|
801
|
+
export declare const dash: <O extends DashOptions>(options?: O) => {
|
|
796
802
|
id: "dash";
|
|
797
803
|
options: DashOptionsResolved;
|
|
798
804
|
version: string;
|
|
@@ -836,7 +842,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
|
|
|
836
842
|
};
|
|
837
843
|
session: {
|
|
838
844
|
create: {
|
|
839
|
-
before(
|
|
845
|
+
before(_session: {
|
|
840
846
|
id: string;
|
|
841
847
|
createdAt: Date;
|
|
842
848
|
updatedAt: Date;
|
|
@@ -845,7 +851,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
|
|
|
845
851
|
token: string;
|
|
846
852
|
ipAddress?: string | null | undefined;
|
|
847
853
|
userAgent?: string | null | undefined;
|
|
848
|
-
} & Record<string, unknown>,
|
|
854
|
+
} & Record<string, unknown>, untypedCtx: GenericEndpointContext | null): Promise<{
|
|
849
855
|
data: {
|
|
850
856
|
loginMethod: string | null;
|
|
851
857
|
};
|
|
@@ -859,7 +865,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
|
|
|
859
865
|
token: string;
|
|
860
866
|
ipAddress?: string | null | undefined;
|
|
861
867
|
userAgent?: string | null | undefined;
|
|
862
|
-
} & Record<string, unknown>,
|
|
868
|
+
} & Record<string, unknown>, untypedCtx: GenericEndpointContext | null): Promise<void>;
|
|
863
869
|
};
|
|
864
870
|
delete: {
|
|
865
871
|
after(session: {
|
|
@@ -2195,6 +2201,12 @@ declare const dash: <O extends DashOptions>(options?: O) => {
|
|
|
2195
2201
|
}>>[];
|
|
2196
2202
|
body: import("zod").ZodObject<{}, import("zod/v4/core").$strip>;
|
|
2197
2203
|
}, DirectorySyncConnection>;
|
|
2204
|
+
countDashDirectorySyncConnections: import("better-call").StrictEndpoint<"/dash/directory-sync/connection-count", {
|
|
2205
|
+
method: "GET";
|
|
2206
|
+
use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
2207
|
+
payload: Record<string, unknown>;
|
|
2208
|
+
}>>[];
|
|
2209
|
+
}, DashDirectorySyncConnectionCountResponse>;
|
|
2198
2210
|
dashExecuteAdapter: import("better-call").StrictEndpoint<"/dash/execute-adapter", {
|
|
2199
2211
|
method: "POST";
|
|
2200
2212
|
use: import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
|
|
@@ -2339,4 +2351,4 @@ declare const dash: <O extends DashOptions>(options?: O) => {
|
|
|
2339
2351
|
} : {});
|
|
2340
2352
|
};
|
|
2341
2353
|
//#endregion
|
|
2342
|
-
export { type APIError, type ApiOptions, type ApiOptionsResolved,
|
|
2354
|
+
export { type APIError, type ApiOptions, type ApiOptionsResolved, type CompromisedPasswordResult, type CredentialStuffingResult, type DBField, type DashAddTeamMemberResponse, type DashBanManyResponse, type DashCheckUserByEmailResponse, type DashCheckUserExistsResponse, type DashCompleteInvitationResponse, type DashConfigResponse, type DashCreateOrganizationBody, type DashCreateOrganizationResponse, type DashCreateTeamResponse, type DashCreateUserResponse, type DashDeleteManyUsersResponse, type DashDirectoryCreateResponse, type DashDirectoryCredential, type DashDirectoryDeleteResponse, type DashDirectoryEvent, type DashDirectoryEventsResponse, type DashDirectoryItem, type DashDirectoryRegenerateTokenResponse, type DashDirectoryRotateCredentialResponse, type DashDirectorySyncConnectionCountResponse, type DashDirectorySyncSSOPairing, type DashExecuteAdapterCountResponse, type DashExecuteAdapterFindManyResponse, type DashExecuteAdapterFindOneResponse, type DashExecuteAdapterMutationResponse, type DashExecuteAdapterResponse, type DashExportOrganizationsResponse, type DashIdRow, type DashInviteMemberResponse, type DashMaybeSuccessResponse, type DashOptions, type DashOptionsInternal, type DashOptionsResolved, type DashOrganizationAddMemberResponse, type DashOrganizationDeleteManyResponse, type DashOrganizationDetailResponse, type DashOrganizationInvitationItem, type DashOrganizationInvitationListResponse, type DashOrganizationInvitationStatusItem, type DashOrganizationListResponse, type DashOrganizationMember, type DashOrganizationMemberListItem, type DashOrganizationMemberListResponse, type DashOrganizationMemberUser, type DashOrganizationOptionsResponse, type DashOrganizationTeamItem, type DashOrganizationTeamListResponse, type DashOrganizationUpdateMemberRoleResponse, type DashOrganizationUpdateResponse, type DashSCIMManagedConnectionEventType, type DashSCIMManagedCredentialStatus, type DashSCIMScope, type DashSendManyVerificationEmailsResponse, type DashSessionRevokeManyResponse, type DashSsoCreateProviderResponse, type DashSsoDeleteResponse, type DashSsoMarkDomainVerifiedResponse, type DashSsoProviderItem, type DashSsoProviderSummary, type DashSsoUpdateProviderResponse, type DashSsoVerificationTokenResponse, type DashSsoVerifyDomainResponse, type DashSuccessResponse, type DashTeam, type DashTeamMember, type DashTeamMemberListResponse, type DashTwoFactorBackupCodesResponse, type DashTwoFactorEnableResponse, type DashTwoFactorStatus, type DashTwoFactorTotpViewResponse, type DashUpdateTeamResponse, type DashUpdateUserResponse, type DashUserDetailsResponse, type DashUserGraphDataResponse, type DashUserListResponse, type DashUserOrganizationsResponse, type DashUserRetentionDataResponse, type DashUserStatsActivePeriod, type DashUserStatsResponse, type DashUserStatsSignUpPeriod, type DashValidateResponse, type DirectorySyncConnection, type DirectorySyncConnectionStatus, type DirectorySyncMode, EMAIL_TEMPLATES, type EmailConfig, type EmailTemplateId, type EmailTemplateVariables, type Endpoint, type EndpointOptions, type EventLocation, type EventTypesResponse, type ImpossibleTravelResult, type InfraAuthContext, type InfraEndpointContext, type InfraEndpointContextValue, type InfraPluginConnectionOptions, type InfraPluginConnectionOptionsInternal, type KvOptions, type KvOptionsResolved, type KvRetryOptions, type KvRetryOptionsResolved, type LegacyDashDirectoryCreateResponse, type LegacyDashDirectoryItem, type LocationData, type LocationDataContext, type ORGANIZATION_USER_PREVIEW_SELECT, type OrganizationUserPreview, type PoWChallenge, type PoWSolution, type SCIMPlugin, type SMSConfig, type SMSTemplateId, type SMSTemplateVariables, type SecurityEvent, type SecurityEventType, type SecurityOptions, type SecurityVerdict, type SendBulkEmailsOptions, type SendBulkEmailsResult, type SendEmailOptions, type SendEmailResult, type SendSMSOptions, type SendSMSResult, type SentinelOptions, type SentinelOptionsInternal, type StaleUserResult, type ThresholdConfig, type UserEvent, type UserEventType, type UserEventsResponse, type asInfraContext, type createAuthMiddleware, createEmailSender, sendBulkEmails, sendEmail, sentinel };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as INFRA_USER_AGENT, n as INFRA_API_URL, o as PLUGIN_VERSION, r as INFRA_KV_URL } from "./constants-
|
|
2
|
-
import { a as createAPI, n as hash$1, o as createKV, r as hmacSha256Hex } from "./crypto-
|
|
1
|
+
import { i as INFRA_USER_AGENT, n as INFRA_API_URL, o as PLUGIN_VERSION, r as INFRA_KV_URL } from "./constants-DLZKaIkd.mjs";
|
|
2
|
+
import { a as createAPI, n as hash$1, o as createKV, r as hmacSha256Hex } from "./crypto-Doziv2tH.mjs";
|
|
3
3
|
import { EMAIL_TEMPLATES, createEmailSender, sendBulkEmails, sendEmail } from "./email.mjs";
|
|
4
4
|
import { getCurrentAdapter, getCurrentAuthContext, getCurrentDBAdapterAsyncLocalStorage, runWithTransaction } from "@better-auth/core/context";
|
|
5
5
|
import { APIError, generateId, getAuthTables, logger } from "better-auth";
|
|
@@ -13,14 +13,24 @@ import z, { z as z$1 } from "zod";
|
|
|
13
13
|
import { DOMParser } from "@xmldom/xmldom";
|
|
14
14
|
import { base64Url } from "@better-auth/utils/base64";
|
|
15
15
|
import { createLocalJWKSet, jwtVerify } from "jose";
|
|
16
|
-
import { generateRandomString, symmetricEncrypt } from "better-auth/crypto";
|
|
16
|
+
import { generateRandomString, symmetricDecrypt, symmetricEncrypt } from "better-auth/crypto";
|
|
17
17
|
import { createOTP } from "@better-auth/utils/otp";
|
|
18
18
|
//#region src/options.ts
|
|
19
|
+
/** @internal */
|
|
20
|
+
function resolveApiKeys(raw) {
|
|
21
|
+
const apiKeys = (raw?.trim() || env.BETTER_AUTH_API_KEY?.trim() || "").split(",").map((k) => k.trim()).filter((k) => k.length > 0);
|
|
22
|
+
return {
|
|
23
|
+
apiKey: apiKeys[0] ?? "",
|
|
24
|
+
apiKeys
|
|
25
|
+
};
|
|
26
|
+
}
|
|
19
27
|
function resolveConnectionOptions(options) {
|
|
28
|
+
const { apiKey, apiKeys } = resolveApiKeys(options?.apiKey);
|
|
20
29
|
return {
|
|
21
30
|
apiUrl: options?.apiUrl || INFRA_API_URL,
|
|
22
31
|
kvUrl: options?.kvUrl || INFRA_KV_URL,
|
|
23
|
-
apiKey
|
|
32
|
+
apiKey,
|
|
33
|
+
apiKeys,
|
|
24
34
|
apiOptions: {
|
|
25
35
|
timeout: options?.apiOptions?.timeout ?? options?.apiTimeout ?? 3e3,
|
|
26
36
|
headers: options?.apiOptions?.headers
|
|
@@ -96,6 +106,92 @@ function resolveClientIpFromHeaders(headers, ipAddressHeaders) {
|
|
|
96
106
|
}
|
|
97
107
|
}
|
|
98
108
|
//#endregion
|
|
109
|
+
//#region ../utils/dist/url.mjs
|
|
110
|
+
/**
|
|
111
|
+
* URL helpers: normalization, SSRF-safe parsing/validation, and path/query segments.
|
|
112
|
+
*/
|
|
113
|
+
const HTTP_PROTOCOLS = ["http:", "https:"];
|
|
114
|
+
function isAllowedProtocol(protocol, allowedProtocols) {
|
|
115
|
+
return (allowedProtocols?.length ? allowedProtocols : HTTP_PROTOCOLS).includes(protocol);
|
|
116
|
+
}
|
|
117
|
+
/** Normalizes a base URL and path by trimming slashes and joining them. */
|
|
118
|
+
function normalizeUrl(base, path) {
|
|
119
|
+
return `${base.replace(/\/+$/, "")}${path ? `/${path.replace(/^\/+|\/+$/g, "")}` : ""}`;
|
|
120
|
+
}
|
|
121
|
+
function normalizePath(path) {
|
|
122
|
+
const trimmed = path.trim();
|
|
123
|
+
if (!trimmed) throw new Error("Path must be a non-empty string");
|
|
124
|
+
return `/${trimmed.replace(/^\/+|\/+$/g, "")}`;
|
|
125
|
+
}
|
|
126
|
+
/** Normalizes a base URL and path into separate parts and a joined URL. */
|
|
127
|
+
function resolveBaseUrlPath(baseURL, basePath) {
|
|
128
|
+
const cleanBase = baseURL.trim().replace(/\/+$/, "");
|
|
129
|
+
const resolvedBasePath = normalizePath(basePath);
|
|
130
|
+
return {
|
|
131
|
+
baseURL: cleanBase,
|
|
132
|
+
basePath: resolvedBasePath,
|
|
133
|
+
url: normalizeUrl(cleanBase, resolvedBasePath)
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/** Falls back when basePath is null, undefined, or blank/whitespace. */
|
|
137
|
+
function resolveProjectBasePath(basePath) {
|
|
138
|
+
return basePath?.trim() || "/api/auth";
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Split a Better Auth **already-resolved** mount URL (`ctx.context.baseURL`).
|
|
142
|
+
* Path embedded in that URL is the effective mount (BA path-in-baseURL /
|
|
143
|
+
* withPath result). `fallbackBasePath` is used only when the mount URL has no
|
|
144
|
+
* path (e.g. dynamic allowedHosts before a request sets the full URL).
|
|
145
|
+
*/
|
|
146
|
+
function resolveAuthMountBase(mountURL, fallbackBasePath) {
|
|
147
|
+
try {
|
|
148
|
+
const url = new URL(mountURL);
|
|
149
|
+
const pathname = url.pathname.replace(/\/+$/, "") || "";
|
|
150
|
+
if (pathname && pathname !== "/") return resolveBaseUrlPath(url.origin, pathname);
|
|
151
|
+
return resolveBaseUrlPath(url.origin, resolveProjectBasePath(fallbackBasePath));
|
|
152
|
+
} catch {
|
|
153
|
+
return resolveBaseUrlPath(mountURL, resolveProjectBasePath(fallbackBasePath));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function toAllowedOriginSet(allowedOrigins) {
|
|
157
|
+
const set = /* @__PURE__ */ new Set();
|
|
158
|
+
for (const raw of allowedOrigins) try {
|
|
159
|
+
const parsed = new URL(raw.trim());
|
|
160
|
+
if (isAllowedProtocol(parsed.protocol, HTTP_PROTOCOLS)) set.add(parsed.origin);
|
|
161
|
+
} catch {}
|
|
162
|
+
return set;
|
|
163
|
+
}
|
|
164
|
+
function isAllowedOrigin(origin, allowedOrigins) {
|
|
165
|
+
if (!allowedOrigins.length) return false;
|
|
166
|
+
return toAllowedOriginSet(allowedOrigins).has(origin);
|
|
167
|
+
}
|
|
168
|
+
function safeResolveUrl(raw, baseURL) {
|
|
169
|
+
const trim = raw.trim();
|
|
170
|
+
if (!trim) return null;
|
|
171
|
+
if (trim.startsWith("//") || trim.includes("\\")) return null;
|
|
172
|
+
if (/[\u0000-\u001F\u007F]/.test(trim)) return null;
|
|
173
|
+
try {
|
|
174
|
+
if (trim.startsWith("/")) return new URL(trim, baseURL);
|
|
175
|
+
return new URL(trim);
|
|
176
|
+
} catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function getSafeUniqueOrigins(urls) {
|
|
181
|
+
return [...toAllowedOriginSet(urls)];
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Returns an absolute URL only if its protocol and origin are allowed (after
|
|
185
|
+
* resolving relative paths against `baseURL`). Otherwise returns `null`.
|
|
186
|
+
*/
|
|
187
|
+
function safeUrlParse(input) {
|
|
188
|
+
if (input.raw == null || input.raw.trim() === "") return null;
|
|
189
|
+
const target = safeResolveUrl(input.raw, input.baseURL);
|
|
190
|
+
if (!target || !isAllowedProtocol(target.protocol, input.allowedProtocols)) return null;
|
|
191
|
+
if (!isAllowedOrigin(target.origin, input.allowedOrigins ?? [])) return null;
|
|
192
|
+
return target.href;
|
|
193
|
+
}
|
|
194
|
+
//#endregion
|
|
99
195
|
//#region src/events/constants.ts
|
|
100
196
|
const EVENT_TYPES = {
|
|
101
197
|
USER_CREATED: "user_created",
|
|
@@ -1256,7 +1352,7 @@ function createIdentificationMiddleware($kv, options) {
|
|
|
1256
1352
|
if (!skipIdentification) {
|
|
1257
1353
|
const extracted = extractIdentificationHeaders(ctx.request);
|
|
1258
1354
|
headerVisitorId = extracted.visitorId;
|
|
1259
|
-
requestId = extracted.requestId ?? ctx.getCookie(
|
|
1355
|
+
requestId = extracted.requestId ?? ctx.getCookie(IDENTIFICATION_COOKIE_NAME) ?? null;
|
|
1260
1356
|
}
|
|
1261
1357
|
ctx.context.requestId = requestId;
|
|
1262
1358
|
if (skipIdentification) ctx.context.identification = null;
|
|
@@ -2547,7 +2643,7 @@ const sentinel = (options) => {
|
|
|
2547
2643
|
id: "sentinel",
|
|
2548
2644
|
init(ctx) {
|
|
2549
2645
|
activityTrackingEnabled = (ctx.getPlugin("dash")?.options)?.activityTracking?.enabled === true;
|
|
2550
|
-
const basePath =
|
|
2646
|
+
const basePath = ctx.baseURL ? resolveAuthMountBase(ctx.baseURL, ctx.options.basePath).basePath : resolveProjectBasePath(ctx.options.basePath);
|
|
2551
2647
|
const ipHeaders = ctx.options.advanced?.ipAddress?.ipAddressHeaders || null;
|
|
2552
2648
|
const disableIpTracking = ctx.options.advanced?.ipAddress?.disableIpTracking === true;
|
|
2553
2649
|
/**
|
|
@@ -4197,14 +4293,14 @@ const jwtMiddleware = (options, schema, getJWT) => {
|
|
|
4197
4293
|
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
4198
4294
|
});
|
|
4199
4295
|
const apiKeyHash = payload.apiKeyHash;
|
|
4200
|
-
if (typeof apiKeyHash !== "string" ||
|
|
4296
|
+
if (typeof apiKeyHash !== "string" || options.apiKeys.length === 0) {
|
|
4201
4297
|
ctx.context.logger.warn("[Dash] API key hash is missing or invalid", {
|
|
4202
4298
|
apiKeyHash,
|
|
4203
|
-
apiKey: options.
|
|
4299
|
+
apiKey: options.apiKeys.length > 0 ? "present" : "missing"
|
|
4204
4300
|
});
|
|
4205
4301
|
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
4206
4302
|
}
|
|
4207
|
-
if (!
|
|
4303
|
+
if (!await apiKeyHashMatchesAny(apiKeyHash, options.apiKeys)) {
|
|
4208
4304
|
ctx.context.logger.warn("[Dash] API key hash mismatch");
|
|
4209
4305
|
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
4210
4306
|
}
|
|
@@ -4252,20 +4348,85 @@ const jwtValidateMiddleware = (options) => {
|
|
|
4252
4348
|
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
4253
4349
|
});
|
|
4254
4350
|
const apiKeyHash = payload.apiKeyHash;
|
|
4255
|
-
if (typeof apiKeyHash !== "string" ||
|
|
4351
|
+
if (typeof apiKeyHash !== "string" || options.apiKeys.length === 0) {
|
|
4256
4352
|
ctx.context.logger.warn("[Dash] API key hash is missing or invalid", {
|
|
4257
4353
|
apiKeyHash: typeof apiKeyHash,
|
|
4258
|
-
apiKey: options.
|
|
4354
|
+
apiKey: options.apiKeys.length > 0 ? "present" : "missing"
|
|
4259
4355
|
});
|
|
4260
4356
|
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
4261
4357
|
}
|
|
4262
|
-
if (!
|
|
4358
|
+
if (!await apiKeyHashMatchesAny(apiKeyHash, options.apiKeys)) {
|
|
4263
4359
|
ctx.context.logger.warn("[Dash] API key hash mismatch");
|
|
4264
4360
|
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
4265
4361
|
}
|
|
4266
4362
|
return { payload };
|
|
4267
4363
|
});
|
|
4268
4364
|
};
|
|
4365
|
+
async function apiKeyHashMatchesAny(apiKeyHash, apiKeys) {
|
|
4366
|
+
let matched = false;
|
|
4367
|
+
for (const key of apiKeys) if (timingSafeEqualHash(apiKeyHash, await hash(key))) matched = true;
|
|
4368
|
+
return matched;
|
|
4369
|
+
}
|
|
4370
|
+
//#endregion
|
|
4371
|
+
//#region src/lib/safe-url.ts
|
|
4372
|
+
function isSafeHttpUrl(value) {
|
|
4373
|
+
try {
|
|
4374
|
+
const url = new URL(value);
|
|
4375
|
+
return (url.protocol === "http:" || url.protocol === "https:") && url.username === "" && url.password === "";
|
|
4376
|
+
} catch {
|
|
4377
|
+
return false;
|
|
4378
|
+
}
|
|
4379
|
+
}
|
|
4380
|
+
/** http(s) absolute URL without embedded credentials. */
|
|
4381
|
+
const safeUrlSchema = z.string().trim().min(1).pipe(z.url().refine(isSafeHttpUrl, { message: "URL must be a valid http(s) URL without credentials" })).transform((value) => new URL(value).href);
|
|
4382
|
+
const optionalSafeUrlSchema = z.union([safeUrlSchema, z.literal("")]).optional();
|
|
4383
|
+
/**
|
|
4384
|
+
* Request-scoped full auth URL (origin + mount). Prefer over `options.baseURL`,
|
|
4385
|
+
* which is origin-only or a dynamic config object.
|
|
4386
|
+
* BA resolves this before endpoint handlers; missing value is a programming error.
|
|
4387
|
+
*/
|
|
4388
|
+
function getAuthBaseUrl(ctx) {
|
|
4389
|
+
const resolved = ctx.context.baseURL?.trim();
|
|
4390
|
+
if (!resolved) throw new APIError$1("INTERNAL_SERVER_ERROR", { message: "Auth base URL is not resolved for this request." });
|
|
4391
|
+
return resolved;
|
|
4392
|
+
}
|
|
4393
|
+
/** App origin for post-auth redirects (not the auth mount path). */
|
|
4394
|
+
function getAuthOrigin(ctx) {
|
|
4395
|
+
return new URL(getAuthBaseUrl(ctx)).origin;
|
|
4396
|
+
}
|
|
4397
|
+
function getAllowedAuthOrigins(ctx, extraOrigins = []) {
|
|
4398
|
+
return getSafeUniqueOrigins([
|
|
4399
|
+
getAuthBaseUrl(ctx),
|
|
4400
|
+
...ctx.context.trustedOrigins ?? [],
|
|
4401
|
+
...extraOrigins
|
|
4402
|
+
]);
|
|
4403
|
+
}
|
|
4404
|
+
/**
|
|
4405
|
+
* Resolve a redirect against the auth server's base URL and trusted origins.
|
|
4406
|
+
* Falls back when the target origin is not allowed.
|
|
4407
|
+
*/
|
|
4408
|
+
function resolveTrustedAuthRedirectUrl(ctx, raw, fallback) {
|
|
4409
|
+
return safeUrlParse({
|
|
4410
|
+
raw,
|
|
4411
|
+
baseURL: getAuthBaseUrl(ctx),
|
|
4412
|
+
allowedOrigins: getAllowedAuthOrigins(ctx)
|
|
4413
|
+
}) ?? fallback;
|
|
4414
|
+
}
|
|
4415
|
+
/** Returns a trusted redirect URL or null when the origin is not allowed. */
|
|
4416
|
+
function parseTrustedAuthRedirectUrl(ctx, raw) {
|
|
4417
|
+
return safeUrlParse({
|
|
4418
|
+
raw,
|
|
4419
|
+
baseURL: getAuthBaseUrl(ctx),
|
|
4420
|
+
allowedOrigins: getAllowedAuthOrigins(ctx)
|
|
4421
|
+
});
|
|
4422
|
+
}
|
|
4423
|
+
const TRUSTED_CALLBACK_URL_ERROR = "Callback URL must use http(s) and match the auth base URL or a trusted origin.";
|
|
4424
|
+
/** Rejects email/redirect callbacks whose origin is not on the auth allowlist. */
|
|
4425
|
+
function requireTrustedAuthCallbackUrl(ctx, raw) {
|
|
4426
|
+
const trusted = parseTrustedAuthRedirectUrl(ctx, raw);
|
|
4427
|
+
if (!trusted) throw new APIError$1("BAD_REQUEST", { message: TRUSTED_CALLBACK_URL_ERROR });
|
|
4428
|
+
return trusted;
|
|
4429
|
+
}
|
|
4269
4430
|
//#endregion
|
|
4270
4431
|
//#region ../utils/dist/semver.mjs
|
|
4271
4432
|
/**
|
|
@@ -4337,6 +4498,7 @@ const getConfig = (options) => {
|
|
|
4337
4498
|
}, async (ctx) => {
|
|
4338
4499
|
const advancedOptions = ctx.context.options.advanced;
|
|
4339
4500
|
const organizationPlugin = ctx.context.getPlugin("organization");
|
|
4501
|
+
const authBase = resolveAuthMountBase(getAuthBaseUrl(ctx), ctx.context.options.basePath);
|
|
4340
4502
|
return redactDashSettings({
|
|
4341
4503
|
version: ctx.context.version || null,
|
|
4342
4504
|
socialProviders: Object.keys(ctx.context.options.socialProviders || {}),
|
|
@@ -4406,8 +4568,8 @@ const getConfig = (options) => {
|
|
|
4406
4568
|
deleteUserEnabled: !!ctx.context.options.user?.deleteUser?.enabled,
|
|
4407
4569
|
modelName: ctx.context.options.user?.modelName
|
|
4408
4570
|
},
|
|
4409
|
-
baseURL:
|
|
4410
|
-
basePath:
|
|
4571
|
+
baseURL: authBase.baseURL,
|
|
4572
|
+
basePath: authBase.basePath,
|
|
4411
4573
|
emailVerification: { sendVerificationEmailEnabled: !!ctx.context.options.emailVerification?.sendVerificationEmail },
|
|
4412
4574
|
insights: {
|
|
4413
4575
|
hasDatabase: !!ctx.context.options.database,
|
|
@@ -4601,7 +4763,7 @@ const directorySyncClaimsSchema = z.object({
|
|
|
4601
4763
|
setupOperationId: z.string().trim().min(16).max(255).optional()
|
|
4602
4764
|
});
|
|
4603
4765
|
function getScimEndpoint$1(baseUrl) {
|
|
4604
|
-
return
|
|
4766
|
+
return normalizeUrl(baseUrl, "scim/v2");
|
|
4605
4767
|
}
|
|
4606
4768
|
function assertDirectorySyncClaims(ctx, organizationId) {
|
|
4607
4769
|
const claims = ctx.context.payload;
|
|
@@ -5503,7 +5665,7 @@ async function scimProviderExists(ctx, organizationId, providerId) {
|
|
|
5503
5665
|
}) != null;
|
|
5504
5666
|
}
|
|
5505
5667
|
function getScimEndpoint(baseUrl) {
|
|
5506
|
-
return
|
|
5668
|
+
return normalizeUrl(baseUrl, "scim/v2");
|
|
5507
5669
|
}
|
|
5508
5670
|
function resolveMode(ctx) {
|
|
5509
5671
|
return resolveDirectorySyncMode(getSCIMPlugin(ctx), isManagedDirectorySyncEnabled(ctx));
|
|
@@ -5518,6 +5680,36 @@ function isDuplicateDirectorySyncError(e) {
|
|
|
5518
5680
|
if (e instanceof Error) return /unique constraint|duplicate key|already exists|P2002/i.test(e.message);
|
|
5519
5681
|
return false;
|
|
5520
5682
|
}
|
|
5683
|
+
const countDirectorySyncConnections = (options) => {
|
|
5684
|
+
return createAuthEndpoint("/dash/directory-sync/connection-count", {
|
|
5685
|
+
method: "GET",
|
|
5686
|
+
use: [jwtMiddleware(options)]
|
|
5687
|
+
}, async (ctx) => {
|
|
5688
|
+
const mode = resolveMode(ctx);
|
|
5689
|
+
if (mode === "managed") return {
|
|
5690
|
+
count: await ctx.context.adapter.count({
|
|
5691
|
+
model: "directorySyncConnection",
|
|
5692
|
+
where: [{
|
|
5693
|
+
field: "status",
|
|
5694
|
+
value: ["active", "decommissioning"],
|
|
5695
|
+
operator: "in"
|
|
5696
|
+
}]
|
|
5697
|
+
}),
|
|
5698
|
+
mode: "managed"
|
|
5699
|
+
};
|
|
5700
|
+
if (mode === "legacy") {
|
|
5701
|
+
if (!isOrganizationEnabled(ctx)) return {
|
|
5702
|
+
count: 0,
|
|
5703
|
+
mode: "legacy"
|
|
5704
|
+
};
|
|
5705
|
+
return {
|
|
5706
|
+
count: await ctx.context.adapter.count({ model: "scimProvider" }),
|
|
5707
|
+
mode: "legacy"
|
|
5708
|
+
};
|
|
5709
|
+
}
|
|
5710
|
+
throw ctx.error("NOT_FOUND", { message: "Directory sync connection count unavailable" });
|
|
5711
|
+
});
|
|
5712
|
+
};
|
|
5521
5713
|
const listOrganizationDirectories = (options) => {
|
|
5522
5714
|
return createAuthEndpoint("/dash/organization/:id/directories", {
|
|
5523
5715
|
method: "GET",
|
|
@@ -6062,105 +6254,6 @@ function allowsPasswordlessInviteComplete(authMode) {
|
|
|
6062
6254
|
return authMode === "create_with_session";
|
|
6063
6255
|
}
|
|
6064
6256
|
//#endregion
|
|
6065
|
-
//#region ../utils/dist/url.mjs
|
|
6066
|
-
/**
|
|
6067
|
-
* URL helpers: normalization, SSRF-safe parsing/validation, and path/query segments.
|
|
6068
|
-
*/
|
|
6069
|
-
const HTTP_PROTOCOLS = ["http:", "https:"];
|
|
6070
|
-
function isAllowedProtocol(protocol, allowedProtocols) {
|
|
6071
|
-
return (allowedProtocols?.length ? allowedProtocols : HTTP_PROTOCOLS).includes(protocol);
|
|
6072
|
-
}
|
|
6073
|
-
function toAllowedOriginSet(allowedOrigins) {
|
|
6074
|
-
const set = /* @__PURE__ */ new Set();
|
|
6075
|
-
for (const raw of allowedOrigins) try {
|
|
6076
|
-
const parsed = new URL(raw.trim());
|
|
6077
|
-
if (isAllowedProtocol(parsed.protocol, HTTP_PROTOCOLS)) set.add(parsed.origin);
|
|
6078
|
-
} catch {}
|
|
6079
|
-
return set;
|
|
6080
|
-
}
|
|
6081
|
-
function isAllowedOrigin(origin, allowedOrigins) {
|
|
6082
|
-
if (!allowedOrigins.length) return false;
|
|
6083
|
-
return toAllowedOriginSet(allowedOrigins).has(origin);
|
|
6084
|
-
}
|
|
6085
|
-
function safeResolveUrl(raw, baseURL) {
|
|
6086
|
-
const trim = raw.trim();
|
|
6087
|
-
if (!trim) return null;
|
|
6088
|
-
if (trim.startsWith("//") || trim.includes("\\")) return null;
|
|
6089
|
-
if (/[\u0000-\u001F\u007F]/.test(trim)) return null;
|
|
6090
|
-
try {
|
|
6091
|
-
if (trim.startsWith("/")) return new URL(trim, baseURL);
|
|
6092
|
-
return new URL(trim);
|
|
6093
|
-
} catch {
|
|
6094
|
-
return null;
|
|
6095
|
-
}
|
|
6096
|
-
}
|
|
6097
|
-
function getSafeUniqueOrigins(urls) {
|
|
6098
|
-
return [...toAllowedOriginSet(urls)];
|
|
6099
|
-
}
|
|
6100
|
-
/**
|
|
6101
|
-
* Returns an absolute URL only if its protocol and origin are allowed (after
|
|
6102
|
-
* resolving relative paths against `baseURL`). Otherwise returns `null`.
|
|
6103
|
-
*/
|
|
6104
|
-
function safeUrlParse(input) {
|
|
6105
|
-
if (input.raw == null || input.raw.trim() === "") return null;
|
|
6106
|
-
const target = safeResolveUrl(input.raw, input.baseURL);
|
|
6107
|
-
if (!target || !isAllowedProtocol(target.protocol, input.allowedProtocols)) return null;
|
|
6108
|
-
if (!isAllowedOrigin(target.origin, input.allowedOrigins ?? [])) return null;
|
|
6109
|
-
return target.href;
|
|
6110
|
-
}
|
|
6111
|
-
//#endregion
|
|
6112
|
-
//#region src/lib/safe-url.ts
|
|
6113
|
-
function isSafeHttpUrl(value) {
|
|
6114
|
-
try {
|
|
6115
|
-
const url = new URL(value);
|
|
6116
|
-
return (url.protocol === "http:" || url.protocol === "https:") && url.username === "" && url.password === "";
|
|
6117
|
-
} catch {
|
|
6118
|
-
return false;
|
|
6119
|
-
}
|
|
6120
|
-
}
|
|
6121
|
-
/** http(s) absolute URL without embedded credentials. */
|
|
6122
|
-
const safeUrlSchema = z.string().trim().min(1).pipe(z.url().refine(isSafeHttpUrl, { message: "URL must be a valid http(s) URL without credentials" })).transform((value) => new URL(value).href);
|
|
6123
|
-
const optionalSafeUrlSchema = z.union([safeUrlSchema, z.literal("")]).optional();
|
|
6124
|
-
function getAuthBaseUrl(ctx) {
|
|
6125
|
-
const baseURL = ctx.context.options.baseURL;
|
|
6126
|
-
return typeof baseURL === "string" && baseURL.trim() ? baseURL : "/";
|
|
6127
|
-
}
|
|
6128
|
-
function getAllowedAuthOrigins(ctx, extraOrigins = []) {
|
|
6129
|
-
const baseURL = getAuthBaseUrl(ctx);
|
|
6130
|
-
const trusted = ctx.context.options.trustedOrigins;
|
|
6131
|
-
return getSafeUniqueOrigins([
|
|
6132
|
-
baseURL,
|
|
6133
|
-
...Array.isArray(trusted) ? trusted.filter((origin) => typeof origin === "string") : [],
|
|
6134
|
-
...extraOrigins
|
|
6135
|
-
]);
|
|
6136
|
-
}
|
|
6137
|
-
/**
|
|
6138
|
-
* Resolve a redirect against the auth server's base URL and trusted origins.
|
|
6139
|
-
* Falls back when the target origin is not allowed.
|
|
6140
|
-
*/
|
|
6141
|
-
function resolveTrustedAuthRedirectUrl(ctx, raw, fallback) {
|
|
6142
|
-
return safeUrlParse({
|
|
6143
|
-
raw,
|
|
6144
|
-
baseURL: getAuthBaseUrl(ctx),
|
|
6145
|
-
allowedOrigins: getAllowedAuthOrigins(ctx)
|
|
6146
|
-
}) ?? fallback;
|
|
6147
|
-
}
|
|
6148
|
-
/** Returns a trusted redirect URL or null when the origin is not allowed. */
|
|
6149
|
-
function parseTrustedAuthRedirectUrl(ctx, raw) {
|
|
6150
|
-
return safeUrlParse({
|
|
6151
|
-
raw,
|
|
6152
|
-
baseURL: getAuthBaseUrl(ctx),
|
|
6153
|
-
allowedOrigins: getAllowedAuthOrigins(ctx)
|
|
6154
|
-
});
|
|
6155
|
-
}
|
|
6156
|
-
const TRUSTED_CALLBACK_URL_ERROR = "Callback URL must use http(s) and match the auth base URL or a trusted origin.";
|
|
6157
|
-
/** Rejects email/redirect callbacks whose origin is not on the auth allowlist. */
|
|
6158
|
-
function requireTrustedAuthCallbackUrl(ctx, raw) {
|
|
6159
|
-
const trusted = parseTrustedAuthRedirectUrl(ctx, raw);
|
|
6160
|
-
if (!trusted) throw new APIError$1("BAD_REQUEST", { message: TRUSTED_CALLBACK_URL_ERROR });
|
|
6161
|
-
return trusted;
|
|
6162
|
-
}
|
|
6163
|
-
//#endregion
|
|
6164
6257
|
//#region src/routes/invitations/index.ts
|
|
6165
6258
|
async function verifyPendingInvitation(token, $api, ctx) {
|
|
6166
6259
|
const { data: invitation, error } = await $api("/api/internal/invitations/verify", {
|
|
@@ -6206,7 +6299,7 @@ async function executePlatformInvitationCompletion(ctx, $api, invitation, args)
|
|
|
6206
6299
|
user: existingUser
|
|
6207
6300
|
});
|
|
6208
6301
|
}
|
|
6209
|
-
return { redirectUrl: resolveTrustedAuthRedirectUrl(ctx, invitation.redirectUrl,
|
|
6302
|
+
return { redirectUrl: resolveTrustedAuthRedirectUrl(ctx, invitation.redirectUrl, getAuthOrigin(ctx)) };
|
|
6210
6303
|
}
|
|
6211
6304
|
if (!password && !allowsPasswordlessInviteComplete(invitation.authMode)) throw new APIError("BAD_REQUEST", { message: "Password is required to complete this invitation." });
|
|
6212
6305
|
const userPayload = {
|
|
@@ -6237,7 +6330,7 @@ async function executePlatformInvitationCompletion(ctx, $api, invitation, args)
|
|
|
6237
6330
|
user
|
|
6238
6331
|
});
|
|
6239
6332
|
}
|
|
6240
|
-
return { redirectUrl: resolveTrustedAuthRedirectUrl(ctx, invitation.redirectUrl,
|
|
6333
|
+
return { redirectUrl: resolveTrustedAuthRedirectUrl(ctx, invitation.redirectUrl, getAuthOrigin(ctx)) };
|
|
6241
6334
|
}
|
|
6242
6335
|
/**
|
|
6243
6336
|
* Accept invitation endpoint
|
|
@@ -6270,14 +6363,14 @@ const acceptInvitation = (options) => {
|
|
|
6270
6363
|
user: existingUser
|
|
6271
6364
|
});
|
|
6272
6365
|
}
|
|
6273
|
-
const redirectUrl = resolveTrustedAuthRedirectUrl(ctx, invitation.redirectUrl,
|
|
6366
|
+
const redirectUrl = resolveTrustedAuthRedirectUrl(ctx, invitation.redirectUrl, getAuthOrigin(ctx));
|
|
6274
6367
|
return ctx.redirect(redirectUrl);
|
|
6275
6368
|
}
|
|
6276
6369
|
if (usesPlatformInviteAcceptFlow(invitation.authMode)) {
|
|
6277
6370
|
const platformUrl = options.apiUrl || INFRA_API_URL;
|
|
6278
6371
|
const acceptPageUrl = new URL("/invite/accept", platformUrl);
|
|
6279
6372
|
acceptPageUrl.searchParams.set("token", token);
|
|
6280
|
-
const callbackUrl =
|
|
6373
|
+
const callbackUrl = normalizeUrl(ctx.context.baseURL, "dash/complete-invitation");
|
|
6281
6374
|
acceptPageUrl.searchParams.set("callback", callbackUrl);
|
|
6282
6375
|
return ctx.redirect(acceptPageUrl.toString());
|
|
6283
6376
|
}
|
|
@@ -6305,7 +6398,7 @@ const acceptInvitation = (options) => {
|
|
|
6305
6398
|
user
|
|
6306
6399
|
});
|
|
6307
6400
|
}
|
|
6308
|
-
const redirectUrl = resolveTrustedAuthRedirectUrl(ctx, invitation.redirectUrl,
|
|
6401
|
+
const redirectUrl = resolveTrustedAuthRedirectUrl(ctx, invitation.redirectUrl, getAuthOrigin(ctx));
|
|
6309
6402
|
return ctx.redirect(redirectUrl);
|
|
6310
6403
|
});
|
|
6311
6404
|
};
|
|
@@ -6385,7 +6478,7 @@ const completeInvitationSocial = (options) => {
|
|
|
6385
6478
|
if (sessionCookieToken) await ctx.context.internalAdapter.deleteSession(sessionCookieToken);
|
|
6386
6479
|
deleteSessionCookie(ctx);
|
|
6387
6480
|
}
|
|
6388
|
-
return ctx.redirect(resolveTrustedAuthRedirectUrl(ctx, invitation.redirectUrl,
|
|
6481
|
+
return ctx.redirect(resolveTrustedAuthRedirectUrl(ctx, invitation.redirectUrl, getAuthOrigin(ctx)));
|
|
6389
6482
|
});
|
|
6390
6483
|
};
|
|
6391
6484
|
/**
|
|
@@ -8439,7 +8532,7 @@ async function resolveSAMLConfig(samlConfig, providerId, baseURL, ctx) {
|
|
|
8439
8532
|
const ba17OrLater = isBetterAuth17OrLater(ctx.context.version);
|
|
8440
8533
|
if (saml17OrNewer && !resolvedEntryPoint) throw ctx.error("BAD_REQUEST", { message: "SAML entry point URL is required; provide entryPoint or IdP metadata with SingleSignOnService Location" });
|
|
8441
8534
|
if (ba17OrLater && !idpMetadataXml && !samlConfig.entityId?.trim()) throw ctx.error("BAD_REQUEST", { message: "IdP entity ID is required when IdP metadata XML is not provided" });
|
|
8442
|
-
const spIssuer = `${baseURL
|
|
8535
|
+
const spIssuer = `${normalizeUrl(baseURL, "sso/saml2/sp/metadata")}?providerId=${providerId}`;
|
|
8443
8536
|
const idpMetadata = idpMetadataXml ? { metadata: idpMetadataXml } : {
|
|
8444
8537
|
...ba17OrLater ? { entityID: samlConfig.entityId } : {},
|
|
8445
8538
|
...samlConfig.entryPoint ? { singleSignOnService: [{
|
|
@@ -8457,7 +8550,7 @@ async function resolveSAMLConfig(samlConfig, providerId, baseURL, ctx) {
|
|
|
8457
8550
|
entryPoint: resolvedEntryPoint,
|
|
8458
8551
|
...samlConfig.cert ? { cert: samlConfig.cert } : {}
|
|
8459
8552
|
} : {
|
|
8460
|
-
callbackUrl:
|
|
8553
|
+
callbackUrl: normalizeUrl(baseURL, `sso/saml2/sp/acs/${providerId}`),
|
|
8461
8554
|
spMetadata: {},
|
|
8462
8555
|
entryPoint: resolvedEntryPoint ?? "",
|
|
8463
8556
|
cert: samlConfig.cert ?? ""
|
|
@@ -8949,7 +9042,6 @@ const enableTwoFactor = (options) => createAuthEndpoint("/dash/enable-two-factor
|
|
|
8949
9042
|
value: userId
|
|
8950
9043
|
}]
|
|
8951
9044
|
});
|
|
8952
|
-
const { generateRandomString, symmetricEncrypt } = await import("better-auth/crypto");
|
|
8953
9045
|
const secret = generateRandomString(32);
|
|
8954
9046
|
const { backupCodes, encryptedBackupCodes } = await generateBackupCodes$1(ctx.context.secret, resolveBackupCodeOptions(twoFactorPlugin));
|
|
8955
9047
|
const encryptedSecret = await symmetricEncrypt({
|
|
@@ -9032,7 +9124,6 @@ const viewTwoFactorTotpUri = (options) => createAuthEndpoint("/dash/view-two-fac
|
|
|
9032
9124
|
if (!twoFactorRecord) throw new APIError("NOT_FOUND", { message: "Two-factor authentication not set up for this user" });
|
|
9033
9125
|
let secret = twoFactorRecord.secret;
|
|
9034
9126
|
try {
|
|
9035
|
-
const { symmetricDecrypt } = await import("better-auth/crypto");
|
|
9036
9127
|
secret = await symmetricDecrypt({
|
|
9037
9128
|
key: ctx.context.secret,
|
|
9038
9129
|
data: twoFactorRecord.secret
|
|
@@ -10883,13 +10974,13 @@ const dash = (options) => {
|
|
|
10883
10974
|
},
|
|
10884
10975
|
session: {
|
|
10885
10976
|
create: {
|
|
10886
|
-
async before(
|
|
10887
|
-
const ctx =
|
|
10977
|
+
async before(_session, untypedCtx) {
|
|
10978
|
+
const ctx = untypedCtx;
|
|
10888
10979
|
if (!ctx) return;
|
|
10889
10980
|
return { data: { loginMethod: getLoginMethod(ctx) } };
|
|
10890
10981
|
},
|
|
10891
|
-
async after(session,
|
|
10892
|
-
const ctx =
|
|
10982
|
+
async after(session, untypedCtx) {
|
|
10983
|
+
const ctx = untypedCtx;
|
|
10893
10984
|
if (!ctx || !session.userId) return;
|
|
10894
10985
|
const location = ctx.context.location;
|
|
10895
10986
|
const loginMethod = getLoginMethod(ctx) ?? void 0;
|
|
@@ -11152,6 +11243,7 @@ const dash = (options) => {
|
|
|
11152
11243
|
listDashManagedDirectoryEvents: listDirectoryEvents(settings),
|
|
11153
11244
|
decommissionDashManagedOrganizationDirectory: decommissionOrganizationDirectory(settings),
|
|
11154
11245
|
unpairDashManagedOrganizationDirectory: unpairOrganizationDirectory(settings),
|
|
11246
|
+
countDashDirectorySyncConnections: countDirectorySyncConnections(settings),
|
|
11155
11247
|
dashExecuteAdapter: executeAdapter(settings)
|
|
11156
11248
|
},
|
|
11157
11249
|
schema: {
|
package/dist/native.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as DashGetAllAuditLogsInput, i as DashClientOptions, n as DashAuditLog, o as DashGetAuditLogsInput, r as DashAuditLogsResponse, s as dashClient, t as IdentifyClientOptions } from "./identify-client-options-
|
|
1
|
+
import { a as DashGetAllAuditLogsInput, i as DashClientOptions, n as DashAuditLog, o as DashGetAuditLogsInput, r as DashAuditLogsResponse, s as dashClient, t as IdentifyClientOptions } from "./identify-client-options-BfGftEgh.mjs";
|
|
2
2
|
import { BetterAuthClientPlugin } from "better-auth";
|
|
3
3
|
//#region src/sentinel/native/client.d.ts
|
|
4
4
|
interface SentinelNativeClientOptions {
|
|
@@ -22,6 +22,6 @@ interface SentinelNativeClientOptions {
|
|
|
22
22
|
setItem: (key: string, value: string) => Promise<void>;
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
|
-
declare const sentinelNativeClient: (options?: SentinelNativeClientOptions) => BetterAuthClientPlugin;
|
|
25
|
+
export declare const sentinelNativeClient: (options?: SentinelNativeClientOptions) => BetterAuthClientPlugin;
|
|
26
26
|
//#endregion
|
|
27
|
-
export { type DashAuditLog, type DashAuditLogsResponse, type DashClientOptions, type DashGetAllAuditLogsInput, type DashGetAuditLogsInput, type SentinelNativeClientOptions, dashClient
|
|
27
|
+
export { type DashAuditLog, type DashAuditLogsResponse, type DashClientOptions, type DashGetAllAuditLogsInput, type DashGetAuditLogsInput, type SentinelNativeClientOptions, dashClient };
|
package/dist/native.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { o as createKV, t as bytesToHex } from "./crypto-
|
|
2
|
-
import { a as resolveSentinelClientIdentifyUrl, c as identify, i as solvePoWChallenge, l as dashClient, n as decodePoWChallenge, o as resolveIdentifyClientRetry, r as encodePoWSolution, t as createPowRetryTimeout } from "./pow-retry-
|
|
1
|
+
import { o as createKV, t as bytesToHex } from "./crypto-Doziv2tH.mjs";
|
|
2
|
+
import { a as resolveSentinelClientIdentifyUrl, c as identify, i as solvePoWChallenge, l as dashClient, n as decodePoWChallenge, o as resolveIdentifyClientRetry, r as encodePoWSolution, t as createPowRetryTimeout } from "./pow-retry-DIkxDwZf.mjs";
|
|
3
3
|
import { env } from "@better-auth/core/env";
|
|
4
4
|
import { Dimensions, InteractionManager, PixelRatio, Platform } from "react-native";
|
|
5
5
|
//#region src/sentinel/native/components.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as randomBytes, n as hash, t as bytesToHex } from "./crypto-
|
|
1
|
+
import { i as randomBytes, n as hash, t as bytesToHex } from "./crypto-Doziv2tH.mjs";
|
|
2
2
|
//#region src/dash-client.ts
|
|
3
3
|
function resolveDashUserId(input, options) {
|
|
4
4
|
return input.userId || options?.resolveUserId?.({
|
|
@@ -481,6 +481,8 @@ interface InfraPluginConnectionOptionsInternal extends Omit<InfraPluginConnectio
|
|
|
481
481
|
apiUrl: string;
|
|
482
482
|
kvUrl: string;
|
|
483
483
|
apiKey: string;
|
|
484
|
+
/** @internal */
|
|
485
|
+
apiKeys: string[];
|
|
484
486
|
apiOptions: ApiOptionsResolved;
|
|
485
487
|
kvOptions: KvOptionsResolved;
|
|
486
488
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/infra",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
4
4
|
"description": "Dashboard and analytics plugin for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -66,32 +66,32 @@
|
|
|
66
66
|
},
|
|
67
67
|
"homepage": "https://better-auth.com",
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@better-auth/kysely-adapter": "1.7.
|
|
70
|
-
"@better-auth/scim": "1.7.
|
|
71
|
-
"@better-auth/sso": "1.7.
|
|
69
|
+
"@better-auth/kysely-adapter": "1.7.5",
|
|
70
|
+
"@better-auth/scim": "1.7.5",
|
|
71
|
+
"@better-auth/sso": "1.7.5",
|
|
72
72
|
"@infra/mocks": "0.0.0",
|
|
73
73
|
"@infra/utils": "0.0.0",
|
|
74
74
|
"@types/bun": "latest",
|
|
75
75
|
"@types/node": "^24.12.0",
|
|
76
76
|
"@vitest/browser-playwright": "5.0.0",
|
|
77
77
|
"@vitest/coverage-istanbul": "^5.0.0",
|
|
78
|
-
"better-auth": "1.7.
|
|
79
|
-
"expo-crypto": "^57.0.
|
|
78
|
+
"better-auth": "1.7.5",
|
|
79
|
+
"expo-crypto": "^57.0.3",
|
|
80
80
|
"msw": "^2.14.6",
|
|
81
81
|
"playwright": "^1.63.0",
|
|
82
|
-
"tsdown": "^0.
|
|
82
|
+
"tsdown": "^0.23.0",
|
|
83
83
|
"typescript": "^6.0.3",
|
|
84
84
|
"vitest": "^5.0.0",
|
|
85
85
|
"zod": "4.5.4"
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
88
|
"@better-auth/utils": "^0.4.2",
|
|
89
|
-
"@better-fetch/fetch": "1.3.
|
|
89
|
+
"@better-fetch/fetch": "1.3.2",
|
|
90
90
|
"@noble/hashes": "^2.2.0",
|
|
91
91
|
"@xmldom/xmldom": "^0.9.10",
|
|
92
92
|
"better-call": "1.4.0",
|
|
93
|
-
"jose": "^6.2.
|
|
94
|
-
"libphonenumber-js": "^1.13.
|
|
93
|
+
"jose": "^6.2.12",
|
|
94
|
+
"libphonenumber-js": "^1.13.13"
|
|
95
95
|
},
|
|
96
96
|
"peerDependencies": {
|
|
97
97
|
"better-auth": ">=1.4.0",
|