@better-auth/core 1.6.5 → 1.6.7
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/dist/api/index.mjs +29 -3
- package/dist/context/global.mjs +1 -1
- package/dist/db/adapter/factory.mjs +1 -1
- package/dist/instrumentation/api.mjs +12 -0
- package/dist/instrumentation/noop.mjs +42 -0
- package/dist/instrumentation/pure.index.d.mts +7 -0
- package/dist/instrumentation/pure.index.mjs +7 -0
- package/dist/instrumentation/tracer.mjs +6 -3
- package/dist/oauth2/index.d.mts +2 -2
- package/dist/oauth2/index.mjs +2 -2
- package/dist/oauth2/utils.d.mts +10 -1
- package/dist/oauth2/utils.mjs +13 -1
- package/dist/social-providers/apple.d.mts +11 -2
- package/dist/social-providers/apple.mjs +7 -1
- package/dist/social-providers/atlassian.mjs +1 -1
- package/dist/social-providers/cognito.d.mts +1 -1
- package/dist/social-providers/cognito.mjs +3 -2
- package/dist/social-providers/facebook.d.mts +1 -1
- package/dist/social-providers/facebook.mjs +7 -0
- package/dist/social-providers/figma.mjs +1 -1
- package/dist/social-providers/google.d.mts +1 -1
- package/dist/social-providers/google.mjs +3 -2
- package/dist/social-providers/microsoft-entra-id.d.mts +2 -2
- package/dist/social-providers/microsoft-entra-id.mjs +6 -1
- package/dist/social-providers/paybin.mjs +1 -1
- package/dist/social-providers/paypal.mjs +1 -1
- package/dist/social-providers/salesforce.mjs +1 -1
- package/dist/utils/async.d.mts +22 -0
- package/dist/utils/async.mjs +32 -0
- package/dist/utils/host.d.mts +147 -0
- package/dist/utils/host.mjs +291 -0
- package/dist/utils/is-api-error.d.mts +6 -0
- package/dist/utils/is-api-error.mjs +8 -0
- package/package.json +10 -1
- package/src/api/index.ts +39 -5
- package/src/instrumentation/api.ts +17 -0
- package/src/instrumentation/noop.ts +74 -0
- package/src/instrumentation/pure.index.ts +31 -0
- package/src/instrumentation/tracer.ts +8 -3
- package/src/oauth2/index.ts +5 -1
- package/src/oauth2/utils.ts +13 -0
- package/src/social-providers/apple.ts +10 -2
- package/src/social-providers/cognito.ts +3 -2
- package/src/social-providers/facebook.ts +10 -1
- package/src/social-providers/google.ts +3 -2
- package/src/social-providers/microsoft-entra-id.ts +13 -3
- package/src/utils/async.ts +53 -0
- package/src/utils/host.ts +401 -0
- package/src/utils/is-api-error.ts +10 -0
package/dist/api/index.mjs
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
import { runWithEndpointContext } from "../context/endpoint-context.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { isAPIError } from "../utils/is-api-error.mjs";
|
|
3
|
+
import { createEndpoint, createMiddleware, kAPIErrorHeaderSymbol } from "better-call";
|
|
3
4
|
//#region src/api/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* Better-call's createEndpoint re-throws APIError without exposing the headers
|
|
7
|
+
* accumulated on ctx.responseHeaders (e.g. Set-Cookie from deleteSessionCookie
|
|
8
|
+
* before throw). Attach them to the error via kAPIErrorHeaderSymbol — matching
|
|
9
|
+
* better-call's createMiddleware contract so the outer pipeline can merge them
|
|
10
|
+
* into the response.
|
|
11
|
+
*/
|
|
12
|
+
function attachResponseHeadersToAPIError(responseHeaders, e) {
|
|
13
|
+
if (!isAPIError(e) || !responseHeaders) return;
|
|
14
|
+
Object.defineProperty(e, kAPIErrorHeaderSymbol, {
|
|
15
|
+
enumerable: false,
|
|
16
|
+
configurable: true,
|
|
17
|
+
value: responseHeaders,
|
|
18
|
+
writable: false
|
|
19
|
+
});
|
|
20
|
+
}
|
|
4
21
|
const optionsMiddleware = createMiddleware(async () => {
|
|
5
22
|
/**
|
|
6
23
|
* This will be passed on the instance of
|
|
@@ -17,14 +34,23 @@ function createAuthEndpoint(pathOrOptions, handlerOrOptions, handlerOrNever) {
|
|
|
17
34
|
const path = typeof pathOrOptions === "string" ? pathOrOptions : void 0;
|
|
18
35
|
const options = typeof handlerOrOptions === "object" ? handlerOrOptions : pathOrOptions;
|
|
19
36
|
const handler = typeof handlerOrOptions === "function" ? handlerOrOptions : handlerOrNever;
|
|
37
|
+
const wrapped = async (ctx) => {
|
|
38
|
+
const runtimeCtx = ctx;
|
|
39
|
+
try {
|
|
40
|
+
return await runWithEndpointContext(ctx, () => handler(ctx));
|
|
41
|
+
} catch (e) {
|
|
42
|
+
attachResponseHeadersToAPIError(runtimeCtx.responseHeaders, e);
|
|
43
|
+
throw e;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
20
46
|
if (path) return createEndpoint(path, {
|
|
21
47
|
...options,
|
|
22
48
|
use: [...options?.use || [], ...use]
|
|
23
|
-
},
|
|
49
|
+
}, wrapped);
|
|
24
50
|
return createEndpoint({
|
|
25
51
|
...options,
|
|
26
52
|
use: [...options?.use || [], ...use]
|
|
27
|
-
},
|
|
53
|
+
}, wrapped);
|
|
28
54
|
}
|
|
29
55
|
//#endregion
|
|
30
56
|
export { createAuthEndpoint, createAuthMiddleware, optionsMiddleware };
|
package/dist/context/global.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { BetterAuthError } from "../../error/index.mjs";
|
|
1
2
|
import { getAuthTables } from "../get-tables.mjs";
|
|
2
3
|
import { getColorDepth } from "../../env/color-depth.mjs";
|
|
3
4
|
import { TTY_COLORS, createLogger } from "../../env/logger.mjs";
|
|
4
|
-
import { BetterAuthError } from "../../error/index.mjs";
|
|
5
5
|
import { ATTR_DB_COLLECTION_NAME, ATTR_DB_OPERATION_NAME } from "../../instrumentation/attributes.mjs";
|
|
6
6
|
import { withSpan } from "../../instrumentation/tracer.mjs";
|
|
7
7
|
import { safeJSONParse } from "../../utils/json.mjs";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { noopOpenTelemetryAPI } from "./noop.mjs";
|
|
2
|
+
//#region src/instrumentation/api.ts
|
|
3
|
+
let openTelemetryAPIPromise;
|
|
4
|
+
let openTelemetryAPI;
|
|
5
|
+
function getOpenTelemetryAPI() {
|
|
6
|
+
if (!openTelemetryAPIPromise) openTelemetryAPIPromise = import("@opentelemetry/api").then((mod) => {
|
|
7
|
+
openTelemetryAPI = mod;
|
|
8
|
+
}).catch(() => void 0);
|
|
9
|
+
return openTelemetryAPI ?? noopOpenTelemetryAPI;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { getOpenTelemetryAPI };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/instrumentation/noop.ts
|
|
2
|
+
function createNoopSpan() {
|
|
3
|
+
const span = {
|
|
4
|
+
end() {},
|
|
5
|
+
setAttribute(_key, _value) {},
|
|
6
|
+
setStatus(_status) {},
|
|
7
|
+
recordException(_exception) {},
|
|
8
|
+
updateName(_name) {
|
|
9
|
+
return span;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
return span;
|
|
13
|
+
}
|
|
14
|
+
function createNoopTracer(noopSpan) {
|
|
15
|
+
function startActiveSpan(_name, ...rest) {
|
|
16
|
+
const fn = rest[rest.length - 1];
|
|
17
|
+
return fn(noopSpan);
|
|
18
|
+
}
|
|
19
|
+
return { startActiveSpan };
|
|
20
|
+
}
|
|
21
|
+
function createNoopTraceAPI() {
|
|
22
|
+
const noopTracer = createNoopTracer(createNoopSpan());
|
|
23
|
+
return {
|
|
24
|
+
getTracer(_name, _version) {
|
|
25
|
+
return noopTracer;
|
|
26
|
+
},
|
|
27
|
+
getActiveSpan() {}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function createNoopOpenTelemetryAPI() {
|
|
31
|
+
return {
|
|
32
|
+
SpanStatusCode: {
|
|
33
|
+
UNSET: 0,
|
|
34
|
+
OK: 1,
|
|
35
|
+
ERROR: 2
|
|
36
|
+
},
|
|
37
|
+
trace: createNoopTraceAPI()
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const noopOpenTelemetryAPI = createNoopOpenTelemetryAPI();
|
|
41
|
+
//#endregion
|
|
42
|
+
export { noopOpenTelemetryAPI };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ATTR_CONTEXT, ATTR_DB_COLLECTION_NAME, ATTR_DB_OPERATION_NAME, ATTR_HOOK_TYPE, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_HTTP_ROUTE, ATTR_OPERATION_ID } from "./attributes.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/instrumentation/pure.index.d.ts
|
|
4
|
+
declare function withSpan<T>(name: string, attributes: Record<string, string | number | boolean>, fn: () => T): T;
|
|
5
|
+
declare function withSpan<T>(name: string, attributes: Record<string, string | number | boolean>, fn: () => Promise<T>): Promise<T>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { ATTR_CONTEXT, ATTR_DB_COLLECTION_NAME, ATTR_DB_OPERATION_NAME, ATTR_HOOK_TYPE, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_HTTP_ROUTE, ATTR_OPERATION_ID, withSpan };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ATTR_CONTEXT, ATTR_DB_COLLECTION_NAME, ATTR_DB_OPERATION_NAME, ATTR_HOOK_TYPE, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_HTTP_ROUTE, ATTR_OPERATION_ID } from "./attributes.mjs";
|
|
2
|
+
//#region src/instrumentation/pure.index.ts
|
|
3
|
+
function withSpan(_name, _attributes, fn) {
|
|
4
|
+
return fn();
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
export { ATTR_CONTEXT, ATTR_DB_COLLECTION_NAME, ATTR_DB_OPERATION_NAME, ATTR_HOOK_TYPE, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_HTTP_ROUTE, ATTR_OPERATION_ID, withSpan };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ATTR_HTTP_RESPONSE_STATUS_CODE } from "./attributes.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { getOpenTelemetryAPI } from "./api.mjs";
|
|
3
3
|
//#region src/instrumentation/tracer.ts
|
|
4
|
-
const
|
|
4
|
+
const INSTRUMENTATION_SCOPE = "better-auth";
|
|
5
|
+
const INSTRUMENTATION_VERSION = "1.6.7";
|
|
5
6
|
/**
|
|
6
7
|
* Better-auth uses `throw ctx.redirect(url)` for flow control (e.g. OAuth
|
|
7
8
|
* callbacks). These are APIErrors with 3xx status codes and should not be
|
|
@@ -15,6 +16,7 @@ function isRedirectError(err) {
|
|
|
15
16
|
return false;
|
|
16
17
|
}
|
|
17
18
|
function endSpanWithError(span, err) {
|
|
19
|
+
const { SpanStatusCode } = getOpenTelemetryAPI();
|
|
18
20
|
if (isRedirectError(err)) {
|
|
19
21
|
span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, err.statusCode);
|
|
20
22
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
@@ -28,7 +30,8 @@ function endSpanWithError(span, err) {
|
|
|
28
30
|
span.end();
|
|
29
31
|
}
|
|
30
32
|
function withSpan(name, attributes, fn) {
|
|
31
|
-
|
|
33
|
+
const { trace } = getOpenTelemetryAPI();
|
|
34
|
+
return trace.getTracer(INSTRUMENTATION_SCOPE, INSTRUMENTATION_VERSION).startActiveSpan(name, { attributes }, (span) => {
|
|
32
35
|
try {
|
|
33
36
|
const result = fn();
|
|
34
37
|
if (result instanceof Promise) return result.then((value) => {
|
package/dist/oauth2/index.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import { OAuth2Tokens, OAuth2UserInfo, OAuthProvider, ProviderOptions } from "./
|
|
|
2
2
|
import { clientCredentialsToken, clientCredentialsTokenRequest, createClientCredentialsTokenRequest } from "./client-credentials-token.mjs";
|
|
3
3
|
import { createAuthorizationURL } from "./create-authorization-url.mjs";
|
|
4
4
|
import { createRefreshAccessTokenRequest, refreshAccessToken, refreshAccessTokenRequest } from "./refresh-access-token.mjs";
|
|
5
|
-
import { generateCodeChallenge, getOAuth2Tokens } from "./utils.mjs";
|
|
5
|
+
import { generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId } from "./utils.mjs";
|
|
6
6
|
import { authorizationCodeRequest, createAuthorizationCodeRequest, validateAuthorizationCode, validateToken } from "./validate-authorization-code.mjs";
|
|
7
7
|
import { getJwks, verifyAccessToken, verifyJwsAccessToken } from "./verify.mjs";
|
|
8
|
-
export { type OAuth2Tokens, type OAuth2UserInfo, type OAuthProvider, type ProviderOptions, authorizationCodeRequest, clientCredentialsToken, clientCredentialsTokenRequest, createAuthorizationCodeRequest, createAuthorizationURL, createClientCredentialsTokenRequest, createRefreshAccessTokenRequest, generateCodeChallenge, getJwks, getOAuth2Tokens, refreshAccessToken, refreshAccessTokenRequest, validateAuthorizationCode, validateToken, verifyAccessToken, verifyJwsAccessToken };
|
|
8
|
+
export { type OAuth2Tokens, type OAuth2UserInfo, type OAuthProvider, type ProviderOptions, authorizationCodeRequest, clientCredentialsToken, clientCredentialsTokenRequest, createAuthorizationCodeRequest, createAuthorizationURL, createClientCredentialsTokenRequest, createRefreshAccessTokenRequest, generateCodeChallenge, getJwks, getOAuth2Tokens, getPrimaryClientId, refreshAccessToken, refreshAccessTokenRequest, validateAuthorizationCode, validateToken, verifyAccessToken, verifyJwsAccessToken };
|
package/dist/oauth2/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { clientCredentialsToken, clientCredentialsTokenRequest, createClientCredentialsTokenRequest } from "./client-credentials-token.mjs";
|
|
2
|
-
import { generateCodeChallenge, getOAuth2Tokens } from "./utils.mjs";
|
|
2
|
+
import { generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId } from "./utils.mjs";
|
|
3
3
|
import { createAuthorizationURL } from "./create-authorization-url.mjs";
|
|
4
4
|
import { createRefreshAccessTokenRequest, refreshAccessToken, refreshAccessTokenRequest } from "./refresh-access-token.mjs";
|
|
5
5
|
import { authorizationCodeRequest, createAuthorizationCodeRequest, validateAuthorizationCode, validateToken } from "./validate-authorization-code.mjs";
|
|
6
6
|
import { getJwks, verifyAccessToken, verifyJwsAccessToken } from "./verify.mjs";
|
|
7
|
-
export { authorizationCodeRequest, clientCredentialsToken, clientCredentialsTokenRequest, createAuthorizationCodeRequest, createAuthorizationURL, createClientCredentialsTokenRequest, createRefreshAccessTokenRequest, generateCodeChallenge, getJwks, getOAuth2Tokens, refreshAccessToken, refreshAccessTokenRequest, validateAuthorizationCode, validateToken, verifyAccessToken, verifyJwsAccessToken };
|
|
7
|
+
export { authorizationCodeRequest, clientCredentialsToken, clientCredentialsTokenRequest, createAuthorizationCodeRequest, createAuthorizationURL, createClientCredentialsTokenRequest, createRefreshAccessTokenRequest, generateCodeChallenge, getJwks, getOAuth2Tokens, getPrimaryClientId, refreshAccessToken, refreshAccessTokenRequest, validateAuthorizationCode, validateToken, verifyAccessToken, verifyJwsAccessToken };
|
package/dist/oauth2/utils.d.mts
CHANGED
|
@@ -2,6 +2,15 @@ import { OAuth2Tokens } from "./oauth-provider.mjs";
|
|
|
2
2
|
|
|
3
3
|
//#region src/oauth2/utils.d.ts
|
|
4
4
|
declare function getOAuth2Tokens(data: Record<string, any>): OAuth2Tokens;
|
|
5
|
+
/**
|
|
6
|
+
* Return the provider's primary Client ID: the single string, or the entry at
|
|
7
|
+
* array index 0 for the cross-platform form used by ID token audience
|
|
8
|
+
* verification. Index 0 is the designated primary and pairs with
|
|
9
|
+
* `clientSecret` for the authorization code flow; later array entries are
|
|
10
|
+
* only used as additional accepted audiences. Returns `undefined` when the
|
|
11
|
+
* primary value is missing or an empty string.
|
|
12
|
+
*/
|
|
13
|
+
declare function getPrimaryClientId(clientId: unknown): string | undefined;
|
|
5
14
|
declare function generateCodeChallenge(codeVerifier: string): Promise<string>;
|
|
6
15
|
//#endregion
|
|
7
|
-
export { generateCodeChallenge, getOAuth2Tokens };
|
|
16
|
+
export { generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId };
|
package/dist/oauth2/utils.mjs
CHANGED
|
@@ -16,10 +16,22 @@ function getOAuth2Tokens(data) {
|
|
|
16
16
|
raw: data
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Return the provider's primary Client ID: the single string, or the entry at
|
|
21
|
+
* array index 0 for the cross-platform form used by ID token audience
|
|
22
|
+
* verification. Index 0 is the designated primary and pairs with
|
|
23
|
+
* `clientSecret` for the authorization code flow; later array entries are
|
|
24
|
+
* only used as additional accepted audiences. Returns `undefined` when the
|
|
25
|
+
* primary value is missing or an empty string.
|
|
26
|
+
*/
|
|
27
|
+
function getPrimaryClientId(clientId) {
|
|
28
|
+
const value = Array.isArray(clientId) ? clientId[0] : clientId;
|
|
29
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
30
|
+
}
|
|
19
31
|
async function generateCodeChallenge(codeVerifier) {
|
|
20
32
|
const data = new TextEncoder().encode(codeVerifier);
|
|
21
33
|
const hash = await crypto.subtle.digest("SHA-256", data);
|
|
22
34
|
return base64Url.encode(new Uint8Array(hash), { padding: false });
|
|
23
35
|
}
|
|
24
36
|
//#endregion
|
|
25
|
-
export { generateCodeChallenge, getOAuth2Tokens };
|
|
37
|
+
export { generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId };
|
|
@@ -60,7 +60,7 @@ interface AppleNonConformUser {
|
|
|
60
60
|
email: string;
|
|
61
61
|
}
|
|
62
62
|
interface AppleOptions extends ProviderOptions<AppleProfile> {
|
|
63
|
-
clientId: string;
|
|
63
|
+
clientId: string | string[];
|
|
64
64
|
appBundleIdentifier?: string | undefined;
|
|
65
65
|
audience?: (string | string[]) | undefined;
|
|
66
66
|
}
|
|
@@ -93,7 +93,16 @@ declare const apple: (options: AppleOptions) => {
|
|
|
93
93
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
94
94
|
getUserInfo(token: OAuth2Tokens & {
|
|
95
95
|
user?: {
|
|
96
|
-
name
|
|
96
|
+
name?
|
|
97
|
+
/**
|
|
98
|
+
* An Integer value that indicates whether the user appears to be a real
|
|
99
|
+
* person. Use the value of this claim to mitigate fraud. The possible
|
|
100
|
+
* values are: 0 (or Unsupported), 1 (or Unknown), 2 (or LikelyReal). For
|
|
101
|
+
* more information, see ASUserDetectionStatus. This claim is present only
|
|
102
|
+
* in iOS 14 and later, macOS 11 and later, watchOS 7 and later, tvOS 14
|
|
103
|
+
* and later. The claim isn’t present or supported for web-based apps.
|
|
104
|
+
*/
|
|
105
|
+
: {
|
|
97
106
|
firstName?: string;
|
|
98
107
|
lastName?: string;
|
|
99
108
|
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { APIError } from "../error/index.mjs";
|
|
1
|
+
import { APIError, BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
|
+
import { getPrimaryClientId } from "../oauth2/utils.mjs";
|
|
2
4
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
3
5
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
4
6
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
@@ -11,6 +13,10 @@ const apple = (options) => {
|
|
|
11
13
|
id: "apple",
|
|
12
14
|
name: "Apple",
|
|
13
15
|
async createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
16
|
+
if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
|
|
17
|
+
logger.error("Client ID and client secret are required for Apple. Make sure to provide them in the options.");
|
|
18
|
+
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
19
|
+
}
|
|
14
20
|
const _scope = options.disableDefaultScope ? [] : ["email", "name"];
|
|
15
21
|
if (options.scope) _scope.push(...options.scope);
|
|
16
22
|
if (scopes) _scope.push(...scopes);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { logger } from "../env/logger.mjs";
|
|
2
1
|
import { BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
3
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
4
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
5
5
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
@@ -19,7 +19,7 @@ interface CognitoProfile {
|
|
|
19
19
|
[key: string]: any;
|
|
20
20
|
}
|
|
21
21
|
interface CognitoOptions extends ProviderOptions<CognitoProfile> {
|
|
22
|
-
clientId: string;
|
|
22
|
+
clientId: string | string[];
|
|
23
23
|
/**
|
|
24
24
|
* The Cognito domain (e.g., "your-app.auth.us-east-1.amazoncognito.com")
|
|
25
25
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { logger } from "../env/logger.mjs";
|
|
2
1
|
import { APIError, BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
|
+
import { getPrimaryClientId } from "../oauth2/utils.mjs";
|
|
3
4
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
5
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
5
6
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
@@ -19,7 +20,7 @@ const cognito = (options) => {
|
|
|
19
20
|
id: "cognito",
|
|
20
21
|
name: "Cognito",
|
|
21
22
|
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
|
22
|
-
if (!options.clientId) {
|
|
23
|
+
if (!getPrimaryClientId(options.clientId)) {
|
|
23
24
|
logger.error("ClientId is required for Amazon Cognito. Make sure to provide them in the options.");
|
|
24
25
|
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
25
26
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
|
+
import { getPrimaryClientId } from "../oauth2/utils.mjs";
|
|
1
4
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
2
5
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
3
6
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
@@ -9,6 +12,10 @@ const facebook = (options) => {
|
|
|
9
12
|
id: "facebook",
|
|
10
13
|
name: "Facebook",
|
|
11
14
|
async createAuthorizationURL({ state, scopes, redirectURI, loginHint }) {
|
|
15
|
+
if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
|
|
16
|
+
logger.error("Client ID and client secret are required for Facebook. Make sure to provide them in the options.");
|
|
17
|
+
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
18
|
+
}
|
|
12
19
|
const _scopes = options.disableDefaultScope ? [] : ["email", "public_profile"];
|
|
13
20
|
if (options.scope) _scopes.push(...options.scope);
|
|
14
21
|
if (scopes) _scopes.push(...scopes);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { logger } from "../env/logger.mjs";
|
|
2
1
|
import { BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
3
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
4
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
5
5
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { logger } from "../env/logger.mjs";
|
|
2
1
|
import { APIError, BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
|
+
import { getPrimaryClientId } from "../oauth2/utils.mjs";
|
|
3
4
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
5
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
5
6
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
@@ -11,7 +12,7 @@ const google = (options) => {
|
|
|
11
12
|
id: "google",
|
|
12
13
|
name: "Google",
|
|
13
14
|
async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI, loginHint, display }) {
|
|
14
|
-
if (!options.clientId || !options.clientSecret) {
|
|
15
|
+
if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
|
|
15
16
|
logger.error("Client Id and Client Secret is required for Google. Make sure to provide them in the options.");
|
|
16
17
|
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
17
18
|
}
|
|
@@ -104,7 +104,7 @@ interface MicrosoftEntraIDProfile extends Record<string, any> {
|
|
|
104
104
|
given_name: string;
|
|
105
105
|
}
|
|
106
106
|
interface MicrosoftOptions extends ProviderOptions<MicrosoftEntraIDProfile> {
|
|
107
|
-
clientId: string;
|
|
107
|
+
clientId: string | string[];
|
|
108
108
|
/**
|
|
109
109
|
* The tenant ID of the Microsoft account
|
|
110
110
|
* @default "common"
|
|
@@ -151,7 +151,7 @@ declare const microsoft: (options: MicrosoftOptions) => {
|
|
|
151
151
|
user?: {
|
|
152
152
|
name?: {
|
|
153
153
|
firstName?: string;
|
|
154
|
-
lastName
|
|
154
|
+
lastName? /** The primary username that represents the user */: string;
|
|
155
155
|
};
|
|
156
156
|
email?: string;
|
|
157
157
|
} | undefined;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { APIError, BetterAuthError } from "../error/index.mjs";
|
|
1
2
|
import { logger } from "../env/logger.mjs";
|
|
2
|
-
import {
|
|
3
|
+
import { getPrimaryClientId } from "../oauth2/utils.mjs";
|
|
3
4
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
5
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
5
6
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
@@ -16,6 +17,10 @@ const microsoft = (options) => {
|
|
|
16
17
|
id: "microsoft",
|
|
17
18
|
name: "Microsoft EntraID",
|
|
18
19
|
createAuthorizationURL(data) {
|
|
20
|
+
if (!getPrimaryClientId(options.clientId)) {
|
|
21
|
+
logger.error("Client Id is required for Microsoft Entra ID. Make sure to provide it in the options.");
|
|
22
|
+
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
23
|
+
}
|
|
19
24
|
const scopes = options.disableDefaultScope ? [] : [
|
|
20
25
|
"openid",
|
|
21
26
|
"profile",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { logger } from "../env/logger.mjs";
|
|
2
1
|
import { BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
3
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
4
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
5
5
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { logger } from "../env/logger.mjs";
|
|
2
1
|
import { BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
3
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
4
|
import { base64 } from "@better-auth/utils/base64";
|
|
5
5
|
import { betterFetch } from "@better-fetch/fetch";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { logger } from "../env/logger.mjs";
|
|
2
1
|
import { BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
import { logger } from "../env/logger.mjs";
|
|
3
3
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
4
4
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
5
5
|
import { validateAuthorizationCode } from "../oauth2/validate-authorization-code.mjs";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Awaitable } from "../types/helper.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/async.d.ts
|
|
4
|
+
interface MapConcurrentOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Max in-flight mappers. Non-integer values are floored, then clamped
|
|
7
|
+
* to the range `[1, items.length]`. `NaN` falls back to 1.
|
|
8
|
+
*/
|
|
9
|
+
concurrency: number;
|
|
10
|
+
/**
|
|
11
|
+
* Rejects with `signal.reason` when aborted. In-flight mappers keep
|
|
12
|
+
* running but their results are not returned.
|
|
13
|
+
*/
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Run an async mapper over items with bounded concurrency.
|
|
18
|
+
* Preserves input order in the result. Fails fast on the first rejection.
|
|
19
|
+
*/
|
|
20
|
+
declare function mapConcurrent<T, R>(items: readonly T[], fn: (item: T, index: number) => Awaitable<R>, options: MapConcurrentOptions): Promise<R[]>;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { MapConcurrentOptions, mapConcurrent };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/utils/async.ts
|
|
2
|
+
/**
|
|
3
|
+
* Run an async mapper over items with bounded concurrency.
|
|
4
|
+
* Preserves input order in the result. Fails fast on the first rejection.
|
|
5
|
+
*/
|
|
6
|
+
async function mapConcurrent(items, fn, options) {
|
|
7
|
+
const n = items.length;
|
|
8
|
+
if (n === 0) return [];
|
|
9
|
+
const { signal } = options;
|
|
10
|
+
if (signal?.aborted) throw signal.reason;
|
|
11
|
+
const raw = Math.floor(options.concurrency);
|
|
12
|
+
const width = Math.min(n, raw >= 1 ? raw : 1);
|
|
13
|
+
const results = new Array(n);
|
|
14
|
+
let idx = 0;
|
|
15
|
+
let failed = false;
|
|
16
|
+
const worker = async () => {
|
|
17
|
+
while (!failed && idx < n) {
|
|
18
|
+
if (signal?.aborted) throw signal.reason;
|
|
19
|
+
const i = idx++;
|
|
20
|
+
try {
|
|
21
|
+
results[i] = await fn(items[i], i);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
failed = true;
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
await Promise.all(Array.from({ length: width }, worker));
|
|
29
|
+
return results;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { mapConcurrent };
|