mirror of
https://github.com/better-auth/better-auth.git
synced 2026-10-20 20:26:55 -05:00
fix(organization): typecheck node exceeds the maximum length (#5372)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
parent
bae3cdf09b
commit
4b5f637bf0
@@ -6,7 +6,9 @@
|
||||
"typecheck": "tsc --project tsconfig.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@better-auth/sso": "workspace:*",
|
||||
"@better-auth/stripe": "workspace:*",
|
||||
"better-auth": "workspace:*",
|
||||
"better-sqlite3": "^12.4.1"
|
||||
"stripe": "^18.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
import { betterAuth } from "better-auth";
|
||||
import {
|
||||
bearer,
|
||||
admin,
|
||||
multiSession,
|
||||
organization,
|
||||
twoFactor,
|
||||
oneTap,
|
||||
oAuthProxy,
|
||||
openAPI,
|
||||
customSession,
|
||||
deviceAuthorization,
|
||||
lastLoginMethod,
|
||||
} from "better-auth/plugins";
|
||||
import { nextCookies } from "better-auth/next-js";
|
||||
import { passkey } from "better-auth/plugins/passkey";
|
||||
import { stripe } from "@better-auth/stripe";
|
||||
import { sso } from "@better-auth/sso";
|
||||
import { Stripe } from "stripe";
|
||||
|
||||
export const auth = betterAuth({
|
||||
appName: "Better Auth Demo",
|
||||
plugins: [
|
||||
organization({}),
|
||||
twoFactor({}),
|
||||
passkey(),
|
||||
openAPI(),
|
||||
bearer(),
|
||||
admin({ adminUserIds: ["EXD5zjob2SD6CBWcEQ6OpLRHcyoUbnaB"] }),
|
||||
multiSession(),
|
||||
oAuthProxy(),
|
||||
nextCookies(),
|
||||
oneTap(),
|
||||
customSession(async (session) => {
|
||||
return {
|
||||
...session,
|
||||
user: {
|
||||
...session.user,
|
||||
dd: "test",
|
||||
},
|
||||
};
|
||||
}),
|
||||
stripe({
|
||||
stripeClient: new Stripe(process.env.STRIPE_KEY || "sk_test_"),
|
||||
stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
|
||||
subscription: {
|
||||
enabled: true,
|
||||
allowReTrialsForDifferentPlans: true,
|
||||
plans: () => {
|
||||
const PRO_PRICE_ID = {
|
||||
default:
|
||||
process.env.STRIPE_PRO_PRICE_ID ??
|
||||
"price_1RoxnRHmTADgihIt4y8c0lVE",
|
||||
annual:
|
||||
process.env.STRIPE_PRO_ANNUAL_PRICE_ID ??
|
||||
"price_1RoxnoHmTADgihItzFvVP8KT",
|
||||
};
|
||||
const PLUS_PRICE_ID = {
|
||||
default:
|
||||
process.env.STRIPE_PLUS_PRICE_ID ??
|
||||
"price_1RoxnJHmTADgihIthZTLmrPn",
|
||||
annual:
|
||||
process.env.STRIPE_PLUS_ANNUAL_PRICE_ID ??
|
||||
"price_1Roxo5HmTADgihItEbJu5llL",
|
||||
};
|
||||
|
||||
return [
|
||||
{
|
||||
name: "Plus",
|
||||
priceId: PLUS_PRICE_ID.default,
|
||||
annualDiscountPriceId: PLUS_PRICE_ID.annual,
|
||||
freeTrial: {
|
||||
days: 7,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Pro",
|
||||
priceId: PRO_PRICE_ID.default,
|
||||
annualDiscountPriceId: PRO_PRICE_ID.annual,
|
||||
freeTrial: {
|
||||
days: 7,
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
}),
|
||||
sso({
|
||||
defaultSSO: [
|
||||
{
|
||||
domain: "http://localhost:3000",
|
||||
providerId: "sso",
|
||||
samlConfig: {
|
||||
issuer: "http://localhost:3000/api/auth/sso/saml2/sp/metadata",
|
||||
entryPoint:
|
||||
"https://dummyidp.com/apps/app_01k16v4vb5yytywqjjvv2b3435",
|
||||
cert: `-----BEGIN CERTIFICATE-----
|
||||
MIIDBzCCAe+gAwIBAgIUCLBK4f75EXEe4gyroYnVaqLoSp4wDQYJKoZIhvcNAQEL
|
||||
BQAwEzERMA8GA1UEAwwIZHVtbXlpZHAwHhcNMjQwNTEzMjE1NDE2WhcNMzQwNTEx
|
||||
MjE1NDE2WjATMREwDwYDVQQDDAhkdW1teWlkcDCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAKhmgQmWb8NvGhz952XY4SlJlpWIK72RilhOZS9frDYhqWVJ
|
||||
HsGH9Z7sSzrM/0+YvCyEWuZV9gpMeIaHZxEPDqW3RJ7KG51fn/s/qFvwctf+CZDj
|
||||
yfGDzYs+XIgf7p56U48EmYeWpB/aUW64gSbnPqrtWmVFBisOfIx5aY3NubtTsn+g
|
||||
0XbdX0L57+NgSvPQHXh/GPXA7xCIWm54G5kqjozxbKEFA0DS3yb6oHRQWHqIAM/7
|
||||
mJMdUVZNIV1q7c2JIgAl23uDWq+2KTE2R5liP/KjvjwKonVKtTqGqX6ei25rsTHO
|
||||
aDpBH/LdQK2txgsm7R7+IThWNvUI0TttrmwBqyMCAwEAAaNTMFEwHQYDVR0OBBYE
|
||||
FD142gxIAJMhpgMkgpzmRNoW9XbEMB8GA1UdIwQYMBaAFD142gxIAJMhpgMkgpzm
|
||||
RNoW9XbEMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADQd6k6z
|
||||
FIc20GfGHY5C2MFwyGOmP5/UG/JiTq7Zky28G6D0NA0je+GztzXx7VYDfCfHxLcm
|
||||
2k5t9nYhb9kVawiLUUDVF6s+yZUXA4gUA3KoTWh1/oRxR3ggW7dKYm9fsNOdQAbx
|
||||
UUkzp7HLZ45ZlpKUS0hO7es+fPyF5KVw0g0SrtQWwWucnQMAQE9m+B0aOf+92y7J
|
||||
QkdgdR8Gd/XZ4NZfoOnKV7A1utT4rWxYCgICeRTHx9tly5OhPW4hQr5qOpngcsJ9
|
||||
vhr86IjznQXhfj3hql5lA3VbHW04ro37ROIkh2bShDq5dwJJHpYCGrF3MQv8S3m+
|
||||
jzGhYL6m9gFTm/8=
|
||||
-----END CERTIFICATE-----`,
|
||||
spMetadata: {
|
||||
metadata: `
|
||||
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="http://localhost:3000/api/auth/sso/saml2/sp/metadata">
|
||||
<md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<md:KeyDescriptor use="signing">
|
||||
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIE3jCCAsYCCQDE5FzoAkixzzANBgkqhkiG9w0BAQsFADAxMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHRmxvcmlkYTEQMA4GA1UEBwwHT3JsYW5kbzAeFw0yMzExMTkxMjUyMTVaFw0zMzExMTYxMjUyMTVaMDExCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdGbG9yaWRhMRAwDgYDVQQHDAdPcmxhbmRvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2ELJsLZs4yBH7a2U5pA7xw+Oiut7b/ROKh2BqSTKRbEG4xy7WwljT02Mh7GTjLvswtZSUObWFO5v14HNORa3+J9JT2DH+9F+FJ770HX8a3cKYBNQt3xP4IeUyjI3QWzrGtkYPwSZ74tDpAUtuqPAxtoCaZXFDtX6lvCJDqiPnfxRZrKkepYWINSwu4DRpg6KoiPWRCYTsEcCzImInzlACdM97jpG1gLGA6a4dmjalQbRtvC56N0Z56gIhYq2F5JdzB2a10pqoIY8ggXZGIJS9I++8mmdTj6So5pPxLwnCYUhwDew1/DMbi9xIwYozs9pEtHCTn1l34jldDwTziVAxGQZO7QUuoMl997zqcPS7pVWRnfz5odKuytLvQDA0lRVfzOxtqbM3qVhoLT2iDmnuEtlZzgfbt4WEuT2538qxZJkFRpZQIrTj3ybqmWAv36Cp49dfeMwaqjhfX7/mVfbsPMSC653DSZBB+n+Uz0FC3QhH+vIdNhXNAQ5tBseHUR6pXiMnLtI/WVbMvpvFwK2faFTcx1oaP/Qk6yCq66tJvPbnatT9qGF8rdBJmAk9aBdQTI+hAh5mDtDweCrgVL+Tm/+Q85hSl4HGzH/LhLVS478tZVX+o+0yorZ35LCW3e4v8iX+1VEGSdg2ooOWtbSSXK2cYZr8ilyUQp0KueenR0CAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAsonAahruWuHlYbDNQVD0ryhL/b+ttKKqVeT87XYDkvVhlSSSVAKcCwK/UU6z8Ty9dODUkd93Qsbof8fGMlXeYCtDHMRanvWLtk4wVkAMyNkDYHzJ1FbO7v44ZBbqNzSLy2kosbRELlcz+P3/42xumlDqAw/k13tWUdlLDxb0pd8R5yBev6HkIdJBIWtKmUuI+e8F/yTNf5kY7HO1p0NeKdVeZw4Ydw33+BwVxVNmhIxzdP5ZFQv0XRFWhCMo/6RLEepCvWUp/T1WRFqgwAdURaQrvvfpjO/Ls+neht1SWDeP8RRgsDrXIc3gZfaD8q4liIDTZ6HsFi7FmLbZatU8jJ4pCstxQLCvmix+1zF6Fwa9V5OApSTbVqBOsDZbJxeAoSzy5Wx28wufAZT4Kc/OaViXPV5o/ordPs4EYKgd/eNFCgIsZYXe75rYXqnieAIfJEGddsLBpqlgLkwvf5KVS4QNqqX+2YubP63y+3sICq2ScdhO3LZs3nlqQ/SgMiJnCBbDUDZ9GGgJNJVVytcSz5IDQHeflrq/zTt1c4q1DO3CS7mimAnTCjetERRQ3mgY/2hRiuCDFj3Cy7QMjFs3vBsbWrjNWlqyveFmHDRkq34Om7eA2jl3LZ5u7vSm0/ylp/vtoysMjwEmw/0NA3hZPTG3OJxcvFcXBsz0SiFcd1U=</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</md:KeyDescriptor>
|
||||
<md:KeyDescriptor use="encryption">
|
||||
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIE3jCCAsYCCQDE5FzoAkixzzANBgkqhkiG9w0BAQsFADAxMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHRmxvcmlkYTEQMA4GA1UEBwwHT3JsYW5kbzAeFw0yMzExMTkxMjUyMTVaFw0zMzExMTYxMjUyMTVaMDExCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdGbG9yaWRhMRAwDgYDVQQHDAdPcmxhbmRvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2ELJsLZs4yBH7a2U5pA7xw+Oiut7b/ROKh2BqSTKRbEG4xy7WwljT02Mh7GTjLvswtZSUObWFO5v14HNORa3+J9JT2DH+9F+FJ770HX8a3cKYBNQt3xP4IeUyjI3QWzrGtkYPwSZ74tDpAUtuqPAxtoCaZXFDtX6lvCJDqiPnfxRZrKkepYWINSwu4DRpg6KoiPWRCYTsEcCzImInzlACdM97jpG1gLGA6a4dmjalQbRtvC56N0Z56gIhYq2F5JdzB2a10pqoIY8ggXZGIJS9I++8mmdTj6So5pPxLwnCYUhwDew1/DMbi9xIwYozs9pEtHCTn1l34jldDwTziVAxGQZO7QUuoMl997zqcPS7pVWRnfz5odKuytLvQDA0lRVfzOxtqbM3qVhoLT2iDmnuEtlZzgfbt4WEuT2538qxZJkFRpZQIrTj3ybqmWAv36Cp49dfeMwaqjhfX7/mVfbsPMSC653DSZBB+n+Uz0FC3QhH+vIdNhXNAQ5tBseHUR6pXiMnLtI/WVbMvpvFwK2faFTcx1oaP/Qk6yCq66tJvPbnatT9qGF8rdBJmAk9aBdQTI+hAh5mDtDweCrgVL+Tm/+Q85hSl4HGzH/LhLVS478tZVX+o+0yorZ35LCW3e4v8iX+1VEGSdg2ooOWtbSSXK2cYZr8ilyUQp0KueenR0CAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAsonAahruWuHlYbDNQVD0ryhL/b+ttKKqVeT87XYDkvVhlSSSVAKcCwK/UU6z8Ty9dODUkd93Qsbof8fGMlXeYCtDHMRanvWLtk4wVkAMyNkDYHzJ1FbO7v44ZBbqNzSLy2kosbRELlcz+P3/42xumlDqAw/k13tWUdlLDxb0pd8R5yBev6HkIdJBIWtKmUuI+e8F/yTNf5kY7HO1p0NeKdVeZw4Ydw33+BwVxVNmhIxzdP5ZFQv0XRFWhCMo/6RLEepCvWUp/T1WRFqgwAdURaQrvvfpjO/Ls+neht1SWDeP8RRgsDrXIc3gZfaD8q4liIDTZ6HsFi7FmLbZatU8jJ4pCstxQLCvmix+1zF6Fwa9V5OApSTbVqBOsDZbJxeAoSzy5Wx28wufAZT4Kc/OaViXPV5o/ordPs4EYKgd/eNFCgIsZYXe75rYXqnieAIfJEGddsLBpqlgLkwvf5KVS4QNqqX+2YubP63y+3sICq2ScdhO3LZs3nlqQ/SgMiJnCBbDUDZ9GGgJNJVVytcSz5IDQHeflrq/zTt1c4q1DO3CS7mimAnTCjetERRQ3mgY/2hRiuCDFj3Cy7QMjFs3vBsbWrjNWlqyveFmHDRkq34Om7eA2jl3LZ5u7vSm0/ylp/vtoysMjwEmw/0NA3hZPTG3OJxcvFcXBsz0SiFcd1U=</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</md:KeyDescriptor>
|
||||
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:3000/api/auth/sso/saml2/sp/sls"/>
|
||||
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
|
||||
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:3000/api/auth/sso/saml2/sp/acs/sso" index="1"/>
|
||||
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:3000/api/auth/sso/saml2/sp/acs/sso" index="1"/>
|
||||
</md:SPSSODescriptor>
|
||||
<md:Organization>
|
||||
<md:OrganizationName xml:lang="en-US">Organization Name</md:OrganizationName>
|
||||
<md:OrganizationDisplayName xml:lang="en-US">Organization DisplayName</md:OrganizationDisplayName>
|
||||
<md:OrganizationURL xml:lang="en-US">http://localhost:3000/</md:OrganizationURL>
|
||||
</md:Organization>
|
||||
<md:ContactPerson contactType="technical">
|
||||
<md:GivenName>Technical Contact Name</md:GivenName>
|
||||
<md:EmailAddress>technical_contact@gmail.com</md:EmailAddress>
|
||||
</md:ContactPerson>
|
||||
<md:ContactPerson contactType="support">
|
||||
<md:GivenName>Support Contact Name</md:GivenName>
|
||||
<md:EmailAddress>support_contact@gmail.com</md:EmailAddress>
|
||||
</md:ContactPerson>
|
||||
</md:EntityDescriptor>
|
||||
`,
|
||||
},
|
||||
idpMetadata: {
|
||||
entityURL:
|
||||
"https://dummyidp.com/apps/app_01k16v4vb5yytywqjjvv2b3435/metadata",
|
||||
entityID:
|
||||
"https://dummyidp.com/apps/app_01k16v4vb5yytywqjjvv2b3435",
|
||||
redirectURL:
|
||||
"https://dummyidp.com/apps/app_01k16v4vb5yytywqjjvv2b3435/sso",
|
||||
singleSignOnService: [
|
||||
{
|
||||
Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
|
||||
Location:
|
||||
"https://dummyidp.com/apps/app_01k16v4vb5yytywqjjvv2b3435/sso",
|
||||
},
|
||||
],
|
||||
cert: `-----BEGIN CERTIFICATE-----
|
||||
MIIDBzCCAe+gAwIBAgIUCLBK4f75EXEe4gyroYnVaqLoSp4wDQYJKoZIhvcNAQEL
|
||||
BQAwEzERMA8GA1UEAwwIZHVtbXlpZHAwHhcNMjQwNTEzMjE1NDE2WhcNMzQwNTEx
|
||||
MjE1NDE2WjATMREwDwYDVQQDDAhkdW1teWlkcDCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAKhmgQmWb8NvGhz952XY4SlJlpWIK72RilhOZS9frDYhqWVJ
|
||||
HsGH9Z7sSzrM/0+YvCyEWuZV9gpMeIaHZxEPDqW3RJ7KG51fn/s/qFvwctf+CZDj
|
||||
yfGDzYs+XIgf7p56U48EmYeWpB/aUW64gSbnPqrtWmVFBisOfIx5aY3NubtTsn+g
|
||||
0XbdX0L57+NgSvPQHXh/GPXA7xCIWm54G5kqjozxbKEFA0DS3yb6oHRQWHqIAM/7
|
||||
mJMdUVZNIV1q7c2JIgAl23uDWq+2KTE2R5liP/KjvjwKonVKtTqGqX6ei25rsTHO
|
||||
aDpBH/LdQK2txgsm7R7+IThWNvUI0TttrmwBqyMCAwEAAaNTMFEwHQYDVR0OBBYE
|
||||
FD142gxIAJMhpgMkgpzmRNoW9XbEMB8GA1UdIwQYMBaAFD142gxIAJMhpgMkgpzm
|
||||
RNoW9XbEMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADQd6k6z
|
||||
FIc20GfGHY5C2MFwyGOmP5/UG/JiTq7Zky28G6D0NA0je+GztzXx7VYDfCfHxLcm
|
||||
2k5t9nYhb9kVawiLUUDVF6s+yZUXA4gUA3KoTWh1/oRxR3ggW7dKYm9fsNOdQAbx
|
||||
UUkzp7HLZ45ZlpKUS0hO7es+fPyF5KVw0g0SrtQWwWucnQMAQE9m+B0aOf+92y7J
|
||||
QkdgdR8Gd/XZ4NZfoOnKV7A1utT4rWxYCgICeRTHx9tly5OhPW4hQr5qOpngcsJ9
|
||||
vhr86IjznQXhfj3hql5lA3VbHW04ro37ROIkh2bShDq5dwJJHpYCGrF3MQv8S3m+
|
||||
jzGhYL6m9gFTm/8=
|
||||
-----END CERTIFICATE-----`,
|
||||
},
|
||||
callbackUrl: "/dashboard",
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
deviceAuthorization({
|
||||
expiresIn: "3min",
|
||||
interval: "5s",
|
||||
}),
|
||||
lastLoginMethod(),
|
||||
],
|
||||
});
|
||||
|
||||
auth.api
|
||||
.createOrganization({
|
||||
body: {
|
||||
name: "My Org",
|
||||
slug: "my-org",
|
||||
},
|
||||
})
|
||||
.catch();
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from "better-call";
|
||||
import type { BetterAuthOptions } from "@better-auth/core";
|
||||
import type { UnionToIntersection } from "../types/helper";
|
||||
import { originCheckMiddleware } from "./middlewares/origin-check";
|
||||
import { originCheckMiddleware } from "./middlewares";
|
||||
import {
|
||||
callbackOAuth,
|
||||
forgetPassword,
|
||||
@@ -37,9 +37,9 @@ import {
|
||||
requestPasswordReset,
|
||||
requestPasswordResetCallback,
|
||||
} from "./routes";
|
||||
import { ok } from "./routes/ok";
|
||||
import { signUpEmail } from "./routes/sign-up";
|
||||
import { error } from "./routes/error";
|
||||
import { ok } from "./routes";
|
||||
import { signUpEmail } from "./routes";
|
||||
import { error } from "./routes";
|
||||
import { type InternalLogger, logger } from "@better-auth/core/env";
|
||||
import type { BetterAuthPlugin } from "@better-auth/core";
|
||||
import { onRequestRateLimit } from "./rate-limiter";
|
||||
|
||||
@@ -21,7 +21,7 @@ function getVenderBaseURL() {
|
||||
return vercel || netlify || render || aws || google || azure;
|
||||
}
|
||||
|
||||
interface OAuthProxyOptions {
|
||||
export interface OAuthProxyOptions {
|
||||
/**
|
||||
* The current URL of the application.
|
||||
* The plugin will attempt to infer the current URL from your environment
|
||||
|
||||
@@ -81,13 +81,13 @@ function getTypeFromZodType(zodType: z.ZodType<any>) {
|
||||
return allowedType.has(type) ? (type as AllowedType) : "string";
|
||||
}
|
||||
|
||||
type FieldSchema = {
|
||||
export type FieldSchema = {
|
||||
type: DBFieldType;
|
||||
default?: DBFieldAttributeConfig["defaultValue"] | "Generated at runtime";
|
||||
readOnly?: boolean;
|
||||
};
|
||||
|
||||
type OpenAPIModelSchema = {
|
||||
export type OpenAPIModelSchema = {
|
||||
type: "object";
|
||||
properties: Record<string, FieldSchema>;
|
||||
required?: string[];
|
||||
|
||||
@@ -6,6 +6,8 @@ import type { LiteralString } from "../../types/helper";
|
||||
import { APIError } from "../../api";
|
||||
import { createAuthEndpoint } from "@better-auth/core/api";
|
||||
|
||||
export type { FieldSchema, Path, OpenAPIModelSchema } from "./generator";
|
||||
|
||||
type ScalarTheme =
|
||||
| "alternate"
|
||||
| "default"
|
||||
|
||||
@@ -10,7 +10,7 @@ import type {
|
||||
import type { Prettify } from "../../types/helper";
|
||||
import { type AccessControl, type Role } from "../access";
|
||||
import type { BetterAuthClientPlugin } from "@better-auth/core";
|
||||
import { organization } from "./organization";
|
||||
import { type OrganizationPlugin } from "./organization";
|
||||
import { useAuthQuery } from "../../client";
|
||||
import {
|
||||
defaultStatements,
|
||||
@@ -129,29 +129,27 @@ export const organizationClient = <CO extends OrganizationClientOptions>(
|
||||
type Schema = CO["schema"];
|
||||
return {
|
||||
id: "organization",
|
||||
$InferServerPlugin: {} as ReturnType<
|
||||
typeof organization<{
|
||||
ac: CO["ac"] extends AccessControl
|
||||
? CO["ac"]
|
||||
: AccessControl<DefaultStatements>;
|
||||
roles: CO["roles"] extends Record<string, Role>
|
||||
? CO["roles"]
|
||||
: {
|
||||
admin: Role;
|
||||
member: Role;
|
||||
owner: Role;
|
||||
};
|
||||
teams: {
|
||||
enabled: CO["teams"] extends { enabled: true } ? true : false;
|
||||
};
|
||||
schema: Schema;
|
||||
dynamicAccessControl: {
|
||||
enabled: CO["dynamicAccessControl"] extends { enabled: true }
|
||||
? true
|
||||
: false;
|
||||
};
|
||||
}>
|
||||
>,
|
||||
$InferServerPlugin: {} as OrganizationPlugin<{
|
||||
ac: CO["ac"] extends AccessControl
|
||||
? CO["ac"]
|
||||
: AccessControl<DefaultStatements>;
|
||||
roles: CO["roles"] extends Record<string, Role>
|
||||
? CO["roles"]
|
||||
: {
|
||||
admin: Role;
|
||||
member: Role;
|
||||
owner: Role;
|
||||
};
|
||||
teams: {
|
||||
enabled: CO["teams"] extends { enabled: true } ? true : false;
|
||||
};
|
||||
schema: Schema;
|
||||
dynamicAccessControl: {
|
||||
enabled: CO["dynamicAccessControl"] extends { enabled: true }
|
||||
? true
|
||||
: false;
|
||||
};
|
||||
}>,
|
||||
getActions: ($fetch, _$store, co) => ({
|
||||
$Infer: {
|
||||
ActiveOrganization: {} as OrganizationReturn,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { APIError } from "better-call";
|
||||
import * as z from "zod";
|
||||
import type { BetterAuthPluginDBSchema } from "@better-auth/core/db";
|
||||
import { createAuthEndpoint } from "@better-auth/core/api";
|
||||
import { getSessionFromCtx } from "../../api/routes";
|
||||
import { getSessionFromCtx } from "../../api";
|
||||
import type { BetterAuthPlugin } from "@better-auth/core";
|
||||
import { shimContext } from "../../utils/shim";
|
||||
import { type AccessControl } from "../access";
|
||||
@@ -50,6 +50,7 @@ import type {
|
||||
InferInvitation,
|
||||
InferMember,
|
||||
InferOrganization,
|
||||
OrganizationSchema,
|
||||
Team,
|
||||
TeamMember,
|
||||
} from "./schema";
|
||||
@@ -70,6 +71,211 @@ export function parseRoles(roles: string | string[]): string {
|
||||
return Array.isArray(roles) ? roles.join(",") : roles;
|
||||
}
|
||||
|
||||
export type DynamicAccessControlEndpoints<O extends OrganizationOptions> = {
|
||||
createOrgRole: ReturnType<typeof createOrgRole<O>>;
|
||||
deleteOrgRole: ReturnType<typeof deleteOrgRole<O>>;
|
||||
listOrgRoles: ReturnType<typeof listOrgRoles<O>>;
|
||||
getOrgRole: ReturnType<typeof getOrgRole<O>>;
|
||||
updateOrgRole: ReturnType<typeof updateOrgRole<O>>;
|
||||
};
|
||||
|
||||
export type TeamEndpoints<O extends OrganizationOptions> = {
|
||||
createTeam: ReturnType<typeof createTeam<O>>;
|
||||
listOrganizationTeams: ReturnType<typeof listOrganizationTeams<O>>;
|
||||
removeTeam: ReturnType<typeof removeTeam<O>>;
|
||||
updateTeam: ReturnType<typeof updateTeam<O>>;
|
||||
setActiveTeam: ReturnType<typeof setActiveTeam<O>>;
|
||||
listUserTeams: ReturnType<typeof listUserTeams<O>>;
|
||||
listTeamMembers: ReturnType<typeof listTeamMembers<O>>;
|
||||
addTeamMember: ReturnType<typeof addTeamMember<O>>;
|
||||
removeTeamMember: ReturnType<typeof removeTeamMember<O>>;
|
||||
};
|
||||
|
||||
export type OrganizationEndpoints<O extends OrganizationOptions> = {
|
||||
createOrganization: ReturnType<typeof createOrganization<O>>;
|
||||
updateOrganization: ReturnType<typeof updateOrganization<O>>;
|
||||
deleteOrganization: ReturnType<typeof deleteOrganization<O>>;
|
||||
setActiveOrganization: ReturnType<typeof setActiveOrganization<O>>;
|
||||
getFullOrganization: ReturnType<typeof getFullOrganization<O>>;
|
||||
listOrganizations: ReturnType<typeof listOrganizations<O>>;
|
||||
createInvitation: ReturnType<typeof createInvitation<O>>;
|
||||
cancelInvitation: ReturnType<typeof cancelInvitation<O>>;
|
||||
acceptInvitation: ReturnType<typeof acceptInvitation<O>>;
|
||||
getInvitation: ReturnType<typeof getInvitation<O>>;
|
||||
rejectInvitation: ReturnType<typeof rejectInvitation<O>>;
|
||||
listInvitations: ReturnType<typeof listInvitations<O>>;
|
||||
getActiveMember: ReturnType<typeof getActiveMember<O>>;
|
||||
checkOrganizationSlug: ReturnType<typeof checkOrganizationSlug<O>>;
|
||||
addMember: ReturnType<typeof addMember<O>>;
|
||||
removeMember: ReturnType<typeof removeMember<O>>;
|
||||
updateMemberRole: ReturnType<typeof updateMemberRole<O>>;
|
||||
leaveOrganization: ReturnType<typeof leaveOrganization<O>>;
|
||||
listUserInvitations: ReturnType<typeof listUserInvitations<O>>;
|
||||
listMembers: ReturnType<typeof listMembers<O>>;
|
||||
getActiveMemberRole: ReturnType<typeof getActiveMemberRole<O>>;
|
||||
hasPermission: ReturnType<typeof createHasPermission<O>>;
|
||||
};
|
||||
|
||||
const createHasPermission = <O extends OrganizationOptions>(options: O) => {
|
||||
type DefaultStatements = typeof defaultStatements;
|
||||
type Statements = O["ac"] extends AccessControl<infer S>
|
||||
? S
|
||||
: DefaultStatements;
|
||||
type PermissionType = {
|
||||
[key in keyof Statements]?: Array<
|
||||
Statements[key] extends readonly unknown[]
|
||||
? Statements[key][number]
|
||||
: never
|
||||
>;
|
||||
};
|
||||
type PermissionExclusive =
|
||||
| {
|
||||
/**
|
||||
* @deprecated Use `permissions` instead
|
||||
*/
|
||||
permission: PermissionType;
|
||||
permissions?: never;
|
||||
}
|
||||
| {
|
||||
permissions: PermissionType;
|
||||
permission?: never;
|
||||
};
|
||||
|
||||
return createAuthEndpoint(
|
||||
"/organization/has-permission",
|
||||
{
|
||||
method: "POST",
|
||||
requireHeaders: true,
|
||||
body: z
|
||||
.object({
|
||||
organizationId: z.string().optional(),
|
||||
})
|
||||
.and(
|
||||
z.union([
|
||||
z.object({
|
||||
permission: z.record(z.string(), z.array(z.string())),
|
||||
permissions: z.undefined(),
|
||||
}),
|
||||
z.object({
|
||||
permission: z.undefined(),
|
||||
permissions: z.record(z.string(), z.array(z.string())),
|
||||
}),
|
||||
]),
|
||||
),
|
||||
use: [orgSessionMiddleware],
|
||||
metadata: {
|
||||
$Infer: {
|
||||
body: {} as PermissionExclusive & {
|
||||
organizationId?: string;
|
||||
},
|
||||
},
|
||||
openapi: {
|
||||
description: "Check if the user has permission",
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
permission: {
|
||||
type: "object",
|
||||
description: "The permission to check",
|
||||
deprecated: true,
|
||||
},
|
||||
permissions: {
|
||||
type: "object",
|
||||
description: "The permission to check",
|
||||
},
|
||||
},
|
||||
required: ["permissions"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
"200": {
|
||||
description: "Success",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
error: {
|
||||
type: "string",
|
||||
},
|
||||
success: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
required: ["success"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async (ctx) => {
|
||||
const activeOrganizationId =
|
||||
ctx.body.organizationId ||
|
||||
ctx.context.session.session.activeOrganizationId;
|
||||
if (!activeOrganizationId) {
|
||||
throw new APIError("BAD_REQUEST", {
|
||||
message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION,
|
||||
});
|
||||
}
|
||||
const adapter = getOrgAdapter<O>(ctx.context, options);
|
||||
const member = await adapter.findMemberByOrgId({
|
||||
userId: ctx.context.session.user.id,
|
||||
organizationId: activeOrganizationId,
|
||||
});
|
||||
if (!member) {
|
||||
throw new APIError("UNAUTHORIZED", {
|
||||
message:
|
||||
ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION,
|
||||
});
|
||||
}
|
||||
const result = await hasPermission(
|
||||
{
|
||||
role: member.role,
|
||||
options: options || {},
|
||||
permissions: (ctx.body.permissions ?? ctx.body.permission) as any,
|
||||
organizationId: activeOrganizationId,
|
||||
},
|
||||
ctx,
|
||||
);
|
||||
|
||||
return ctx.json({
|
||||
error: null,
|
||||
success: result,
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export type OrganizationPlugin<O extends OrganizationOptions> = {
|
||||
id: "organization";
|
||||
endpoints: OrganizationEndpoints<O> &
|
||||
(O extends { teams: { enabled: true } } ? TeamEndpoints<O> : {}) &
|
||||
(O extends { dynamicAccessControl: { enabled: true } }
|
||||
? DynamicAccessControlEndpoints<O>
|
||||
: {});
|
||||
schema: OrganizationSchema<O>;
|
||||
$Infer: {
|
||||
Organization: InferOrganization<O>;
|
||||
Invitation: InferInvitation<O>;
|
||||
Member: InferMember<O>;
|
||||
Team: O["teams"] extends { enabled: true } ? Team : any;
|
||||
TeamMember: O["teams"] extends { enabled: true } ? TeamMember : any;
|
||||
ActiveOrganization: Awaited<
|
||||
ReturnType<ReturnType<typeof getFullOrganization<O>>>
|
||||
>;
|
||||
};
|
||||
$ERROR_CODES: typeof ORGANIZATION_ERROR_CODES;
|
||||
options: O;
|
||||
};
|
||||
|
||||
/**
|
||||
* Organization plugin for Better Auth. Organization allows you to create teams, members,
|
||||
* and manage access control for your users.
|
||||
@@ -77,15 +283,106 @@ export function parseRoles(roles: string | string[]): string {
|
||||
* @example
|
||||
* ```ts
|
||||
* const auth = betterAuth({
|
||||
* plugins: [
|
||||
* organization({
|
||||
* allowUserToCreateOrganization: true,
|
||||
* }),
|
||||
* ],
|
||||
* plugins: [
|
||||
* organization({
|
||||
* allowUserToCreateOrganization: true,
|
||||
* }),
|
||||
* ],
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export const organization = <O extends OrganizationOptions>(options?: O) => {
|
||||
export function organization<
|
||||
O extends OrganizationOptions & {
|
||||
teams: { enabled: true };
|
||||
},
|
||||
>(
|
||||
options?: O,
|
||||
): {
|
||||
id: "organization";
|
||||
endpoints: OrganizationEndpoints<O> & TeamEndpoints<O>;
|
||||
schema: OrganizationSchema<O>;
|
||||
$Infer: {
|
||||
Organization: InferOrganization<O>;
|
||||
Invitation: InferInvitation<O>;
|
||||
Member: InferMember<O>;
|
||||
Team: O["teams"] extends { enabled: true } ? Team : any;
|
||||
TeamMember: O["teams"] extends { enabled: true } ? TeamMember : any;
|
||||
ActiveOrganization: Awaited<
|
||||
ReturnType<ReturnType<typeof getFullOrganization<O>>>
|
||||
>;
|
||||
};
|
||||
$ERROR_CODES: typeof ORGANIZATION_ERROR_CODES;
|
||||
options: O;
|
||||
};
|
||||
export function organization<
|
||||
O extends OrganizationOptions & {
|
||||
teams: { enabled: true };
|
||||
dynamicAccessControl: { enabled: true };
|
||||
},
|
||||
>(
|
||||
options?: O,
|
||||
): {
|
||||
id: "organization";
|
||||
endpoints: OrganizationEndpoints<O> &
|
||||
TeamEndpoints<O> &
|
||||
DynamicAccessControlEndpoints<O>;
|
||||
schema: OrganizationSchema<O>;
|
||||
$Infer: {
|
||||
Organization: InferOrganization<O>;
|
||||
Invitation: InferInvitation<O>;
|
||||
Member: InferMember<O>;
|
||||
Team: O["teams"] extends { enabled: true } ? Team : any;
|
||||
TeamMember: O["teams"] extends { enabled: true } ? TeamMember : any;
|
||||
ActiveOrganization: Awaited<
|
||||
ReturnType<ReturnType<typeof getFullOrganization<O>>>
|
||||
>;
|
||||
};
|
||||
$ERROR_CODES: typeof ORGANIZATION_ERROR_CODES;
|
||||
options: O;
|
||||
};
|
||||
export function organization<
|
||||
O extends OrganizationOptions & {
|
||||
dynamicAccessControl: { enabled: true };
|
||||
},
|
||||
>(
|
||||
options?: O,
|
||||
): {
|
||||
id: "organization";
|
||||
endpoints: OrganizationEndpoints<O> & DynamicAccessControlEndpoints<O>;
|
||||
schema: OrganizationSchema<O>;
|
||||
$Infer: {
|
||||
Organization: InferOrganization<O>;
|
||||
Invitation: InferInvitation<O>;
|
||||
Member: InferMember<O>;
|
||||
Team: O["teams"] extends { enabled: true } ? Team : any;
|
||||
TeamMember: O["teams"] extends { enabled: true } ? TeamMember : any;
|
||||
ActiveOrganization: Awaited<
|
||||
ReturnType<ReturnType<typeof getFullOrganization<O>>>
|
||||
>;
|
||||
};
|
||||
$ERROR_CODES: typeof ORGANIZATION_ERROR_CODES;
|
||||
options: O;
|
||||
};
|
||||
export function organization<O extends OrganizationOptions>(
|
||||
options?: O,
|
||||
): {
|
||||
id: "organization";
|
||||
endpoints: OrganizationEndpoints<O>;
|
||||
schema: OrganizationSchema<O>;
|
||||
$Infer: {
|
||||
Organization: InferOrganization<O>;
|
||||
Invitation: InferInvitation<O>;
|
||||
Member: InferMember<O>;
|
||||
Team: O["teams"] extends { enabled: true } ? Team : any;
|
||||
TeamMember: O["teams"] extends { enabled: true } ? TeamMember : any;
|
||||
ActiveOrganization: Awaited<
|
||||
ReturnType<ReturnType<typeof getFullOrganization<O>>>
|
||||
>;
|
||||
};
|
||||
$ERROR_CODES: typeof ORGANIZATION_ERROR_CODES;
|
||||
options: O;
|
||||
};
|
||||
export function organization<O extends OrganizationOptions>(options?: O): any {
|
||||
let endpoints = {
|
||||
/**
|
||||
* ### Endpoint
|
||||
@@ -857,153 +1154,11 @@ export const organization = <O extends OrganizationOptions>(options?: O) => {
|
||||
},
|
||||
});
|
||||
|
||||
type DefaultStatements = typeof defaultStatements;
|
||||
type Statements = O["ac"] extends AccessControl<infer S>
|
||||
? S
|
||||
: DefaultStatements;
|
||||
type PermissionType = {
|
||||
[key in keyof Statements]?: Array<
|
||||
Statements[key] extends readonly unknown[]
|
||||
? Statements[key][number]
|
||||
: never
|
||||
>;
|
||||
};
|
||||
type PermissionExclusive =
|
||||
| {
|
||||
/**
|
||||
* @deprecated Use `permissions` instead
|
||||
*/
|
||||
permission: PermissionType;
|
||||
permissions?: never;
|
||||
}
|
||||
| {
|
||||
permissions: PermissionType;
|
||||
permission?: never;
|
||||
};
|
||||
|
||||
type OrganizationEndpoints = (O["dynamicAccessControl"] extends {
|
||||
enabled: true;
|
||||
}
|
||||
? typeof dynamicAccessControlEndpoints
|
||||
: {}) &
|
||||
(O["teams"] extends { enabled: true } ? typeof teamEndpoints : {}) &
|
||||
typeof endpoints;
|
||||
|
||||
return {
|
||||
id: "organization",
|
||||
endpoints: {
|
||||
...(api as OrganizationEndpoints),
|
||||
hasPermission: createAuthEndpoint(
|
||||
"/organization/has-permission",
|
||||
{
|
||||
method: "POST",
|
||||
requireHeaders: true,
|
||||
body: z
|
||||
.object({
|
||||
organizationId: z.string().optional(),
|
||||
})
|
||||
.and(
|
||||
z.union([
|
||||
z.object({
|
||||
permission: z.record(z.string(), z.array(z.string())),
|
||||
permissions: z.undefined(),
|
||||
}),
|
||||
z.object({
|
||||
permission: z.undefined(),
|
||||
permissions: z.record(z.string(), z.array(z.string())),
|
||||
}),
|
||||
]),
|
||||
),
|
||||
use: [orgSessionMiddleware],
|
||||
metadata: {
|
||||
$Infer: {
|
||||
body: {} as PermissionExclusive & {
|
||||
organizationId?: string;
|
||||
},
|
||||
},
|
||||
openapi: {
|
||||
description: "Check if the user has permission",
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
permission: {
|
||||
type: "object",
|
||||
description: "The permission to check",
|
||||
deprecated: true,
|
||||
},
|
||||
permissions: {
|
||||
type: "object",
|
||||
description: "The permission to check",
|
||||
},
|
||||
},
|
||||
required: ["permissions"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
"200": {
|
||||
description: "Success",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
error: {
|
||||
type: "string",
|
||||
},
|
||||
success: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
required: ["success"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async (ctx) => {
|
||||
const activeOrganizationId =
|
||||
ctx.body.organizationId ||
|
||||
ctx.context.session.session.activeOrganizationId;
|
||||
if (!activeOrganizationId) {
|
||||
throw new APIError("BAD_REQUEST", {
|
||||
message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION,
|
||||
});
|
||||
}
|
||||
const adapter = getOrgAdapter<O>(ctx.context, options);
|
||||
const member = await adapter.findMemberByOrgId({
|
||||
userId: ctx.context.session.user.id,
|
||||
organizationId: activeOrganizationId,
|
||||
});
|
||||
if (!member) {
|
||||
throw new APIError("UNAUTHORIZED", {
|
||||
message:
|
||||
ORGANIZATION_ERROR_CODES.USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION,
|
||||
});
|
||||
}
|
||||
const result = await hasPermission(
|
||||
{
|
||||
role: member.role,
|
||||
options: options || {},
|
||||
permissions: (ctx.body.permissions ?? ctx.body.permission) as any,
|
||||
organizationId: activeOrganizationId,
|
||||
},
|
||||
ctx,
|
||||
);
|
||||
|
||||
return ctx.json({
|
||||
error: null,
|
||||
success: result,
|
||||
});
|
||||
},
|
||||
),
|
||||
...(api as unknown as OrganizationEndpoints<O>),
|
||||
hasPermission: createHasPermission(options as O),
|
||||
},
|
||||
schema: {
|
||||
...(schema as BetterAuthPluginDBSchema),
|
||||
@@ -1057,4 +1212,4 @@ export const organization = <O extends OrganizationOptions>(options?: O) => {
|
||||
$ERROR_CODES: ORGANIZATION_ERROR_CODES,
|
||||
options: options as O,
|
||||
} satisfies BetterAuthPlugin;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,6 +4,516 @@ import type { OrganizationOptions } from "./types";
|
||||
import type { InferAdditionalFieldsFromPluginOptions } from "../../db";
|
||||
import type { Prettify } from "better-call";
|
||||
|
||||
// TODO: we need a better way to define plugin schema and endpoints
|
||||
export type OrganizationSchema<O extends OrganizationOptions> =
|
||||
O["dynamicAccessControl"] extends { enabled: true }
|
||||
? {
|
||||
organizationRole: {
|
||||
modelName: O["schema"] extends {
|
||||
organizationRole: { modelName: infer M };
|
||||
}
|
||||
? M extends string
|
||||
? M
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
fields: {
|
||||
organizationId: {
|
||||
type: "string";
|
||||
required: true;
|
||||
references: {
|
||||
model: "organization";
|
||||
field: "id";
|
||||
};
|
||||
fieldName?: O["schema"] extends {
|
||||
organizationRole: {
|
||||
fields: { organizationId: infer F };
|
||||
};
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
role: {
|
||||
type: "string";
|
||||
required: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
organizationRole: {
|
||||
fields: { role: infer F };
|
||||
};
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
permission: {
|
||||
type: "string";
|
||||
required: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
organizationRole: {
|
||||
fields: { permission: infer F };
|
||||
};
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
createdAt: {
|
||||
type: "date";
|
||||
required: true;
|
||||
defaultValue: Date;
|
||||
fieldName?: O["schema"] extends {
|
||||
organizationRole: {
|
||||
fields: { createdAt: infer F };
|
||||
};
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
updatedAt: {
|
||||
type: "date";
|
||||
required: false;
|
||||
fieldName?: O["schema"] extends {
|
||||
organizationRole: {
|
||||
fields: { updatedAt: infer F };
|
||||
};
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
} & (O["schema"] extends {
|
||||
organizationRole: { additionalFields: infer F };
|
||||
}
|
||||
? F
|
||||
: {});
|
||||
};
|
||||
}
|
||||
: {} & (O["teams"] extends { enabled: true }
|
||||
? {
|
||||
team: {
|
||||
modelName: O["schema"] extends { team: { modelName: infer M } }
|
||||
? M extends string
|
||||
? M
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
fields: {
|
||||
name: {
|
||||
type: "string";
|
||||
required: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
team: { fields: { name: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
organizationId: {
|
||||
type: "string";
|
||||
required: true;
|
||||
references: {
|
||||
model: "organization";
|
||||
field: "id";
|
||||
};
|
||||
fieldName?: O["schema"] extends {
|
||||
team: { fields: { organizationId: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
createdAt: {
|
||||
type: "date";
|
||||
required: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
team: { fields: { createdAt: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
updatedAt: {
|
||||
type: "date";
|
||||
required: false;
|
||||
fieldName?: O["schema"] extends {
|
||||
team: { fields: { updatedAt: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
} & (O["schema"] extends { team: { additionalFields: infer F } }
|
||||
? F
|
||||
: {});
|
||||
};
|
||||
teamMember: {
|
||||
modelName: O["schema"] extends {
|
||||
teamMember: { modelName: infer M };
|
||||
}
|
||||
? M extends string
|
||||
? M
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
fields: {
|
||||
teamId: {
|
||||
type: "string";
|
||||
required: true;
|
||||
references: {
|
||||
model: "team";
|
||||
field: "id";
|
||||
};
|
||||
fieldName?: O["schema"] extends {
|
||||
teamMember: { fields: { teamId: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
userId: {
|
||||
type: "string";
|
||||
required: true;
|
||||
references: {
|
||||
model: "user";
|
||||
field: "id";
|
||||
};
|
||||
fieldName?: O["schema"] extends {
|
||||
teamMember: { fields: { userId: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
createdAt: {
|
||||
type: "date";
|
||||
required: false;
|
||||
fieldName?: O["schema"] extends {
|
||||
teamMember: { fields: { createdAt: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
: {}) & {
|
||||
organization: {
|
||||
modelName: O["schema"] extends {
|
||||
organization: { modelName: infer M };
|
||||
}
|
||||
? M extends string
|
||||
? M
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
fields: {
|
||||
name: {
|
||||
type: "string";
|
||||
required: true;
|
||||
sortable: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
organization: { fields: { name: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
slug: {
|
||||
type: "string";
|
||||
required: true;
|
||||
unique: true;
|
||||
sortable: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
organization: { fields: { slug: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
logo: {
|
||||
type: "string";
|
||||
required: false;
|
||||
fieldName?: O["schema"] extends {
|
||||
organization: { fields: { logo: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
createdAt: {
|
||||
type: "date";
|
||||
required: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
organization: { fields: { createdAt: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
updatedAt: {
|
||||
type: "date";
|
||||
required: false;
|
||||
fieldName?: O["schema"] extends {
|
||||
organization: { fields: { updatedAt: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
};
|
||||
};
|
||||
member: {
|
||||
modelName: O["schema"] extends { member: { modelName: infer M } }
|
||||
? M extends string
|
||||
? M
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
fields: {
|
||||
organizationId: {
|
||||
type: "string";
|
||||
required: true;
|
||||
references: {
|
||||
model: "organization";
|
||||
field: "id";
|
||||
};
|
||||
fieldName?: O["schema"] extends {
|
||||
member: { fields: { organizationId: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
userId: {
|
||||
type: "string";
|
||||
required: true;
|
||||
references: {
|
||||
model: "user";
|
||||
field: "id";
|
||||
};
|
||||
fieldName?: O["schema"] extends {
|
||||
member: { fields: { userId: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
role: {
|
||||
type: "string";
|
||||
required: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
member: { fields: { role: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
defaultValue: "member";
|
||||
};
|
||||
createdAt: {
|
||||
type: "date";
|
||||
required: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
member: { fields: { createdAt: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
} & (O["schema"] extends { member: { additionalFields: infer F } }
|
||||
? F
|
||||
: {});
|
||||
};
|
||||
invitation: {
|
||||
modelName: O["schema"] extends {
|
||||
invitation: { modelName: infer M };
|
||||
}
|
||||
? M
|
||||
: string | undefined;
|
||||
fields: {
|
||||
organizationId: {
|
||||
type: "string";
|
||||
required: true;
|
||||
references: {
|
||||
model: "organization";
|
||||
field: "id";
|
||||
};
|
||||
fieldName?: O["schema"] extends {
|
||||
invitation: { fields: { organizationId: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
email: {
|
||||
type: "string";
|
||||
required: true;
|
||||
sortable: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
invitation: { fields: { email: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
role: {
|
||||
type: "string";
|
||||
required: true;
|
||||
sortable: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
invitation: { fields: { role: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
status: {
|
||||
type: "string";
|
||||
required: true;
|
||||
sortable: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
invitation: { fields: { status: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
defaultValue: "pending";
|
||||
};
|
||||
expiresAt: {
|
||||
type: "date";
|
||||
required: false;
|
||||
fieldName?: O["schema"] extends {
|
||||
invitation: { fields: { expiresAt: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
createdAt: {
|
||||
type: "date";
|
||||
required: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
invitation: { fields: { createdAt: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
defaultValue: Date;
|
||||
};
|
||||
inviterId: {
|
||||
type: "string";
|
||||
required: true;
|
||||
references: {
|
||||
model: "user";
|
||||
field: "id";
|
||||
};
|
||||
fieldName?: O["schema"] extends {
|
||||
invitation: { fields: { inviterId: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
} & (O["schema"] extends {
|
||||
invitation: { additionalFields: infer F };
|
||||
}
|
||||
? F
|
||||
: {}) &
|
||||
O extends { teams: { enabled: true } }
|
||||
? {
|
||||
teamId: {
|
||||
type: "string";
|
||||
required: false;
|
||||
sortable: true;
|
||||
fieldName?: O["schema"] extends {
|
||||
invitation: { fields: { teamId: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
}
|
||||
: {};
|
||||
};
|
||||
session: {
|
||||
fields: {
|
||||
activeOrganizationId: {
|
||||
type: "string";
|
||||
required: false;
|
||||
fieldName?: O["schema"] extends {
|
||||
session: { fields: { activeOrganizationId: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
} & O["teams"] extends { enabled: true }
|
||||
? {
|
||||
activeTeamId: {
|
||||
type: "string";
|
||||
required: false;
|
||||
};
|
||||
activeOrganizationId: {
|
||||
type: "string";
|
||||
required: false;
|
||||
fieldName?: O["schema"] extends {
|
||||
session: { fields: { activeOrganizationId: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
}
|
||||
: {
|
||||
activeOrganizationId: {
|
||||
type: "string";
|
||||
required: false;
|
||||
fieldName?: O["schema"] extends {
|
||||
session: { fields: { activeOrganizationId: infer F } };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: string | undefined;
|
||||
};
|
||||
} & (O["schema"] extends {
|
||||
session: { additionalFields: infer F };
|
||||
}
|
||||
? F extends string
|
||||
? F
|
||||
: string | undefined
|
||||
: {});
|
||||
};
|
||||
};
|
||||
|
||||
export const role = z.string();
|
||||
export const invitationStatus = z
|
||||
.enum(["pending", "accepted", "rejected", "canceled"])
|
||||
|
||||
@@ -44,7 +44,7 @@ describe("general types", async (it) => {
|
||||
twoFactorEnabled: boolean | undefined | null;
|
||||
}>();
|
||||
|
||||
expectTypeOf<typeof auth.$Infer.Session.session>().toEqualTypeOf<{
|
||||
expectTypeOf<typeof auth.$Infer.Session.session>().toMatchObjectType<{
|
||||
id: string;
|
||||
userId: string;
|
||||
expiresAt: Date;
|
||||
|
||||
@@ -4,7 +4,6 @@ import type {
|
||||
DBFieldType,
|
||||
DBPrimitive,
|
||||
BetterAuthDBSchema,
|
||||
DBPreservedModels,
|
||||
} from "./type";
|
||||
import type { BetterAuthPluginDBSchema } from "./plugin";
|
||||
export type { BetterAuthPluginDBSchema } from "./plugin";
|
||||
@@ -23,7 +22,7 @@ export type {
|
||||
DBPrimitive,
|
||||
BetterAuthDBSchema,
|
||||
DBPreservedModels,
|
||||
};
|
||||
} from "./type";
|
||||
|
||||
/**
|
||||
* @deprecated Backport for 1.3.x, we will remove this in 1.4.x
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {
|
||||
DBFieldAttribute,
|
||||
DBPreservedModels,
|
||||
SecondaryStorage,
|
||||
} from "../db/type";
|
||||
} from "../db";
|
||||
import type { Account, RateLimit, Session, User, Verification } from "../db";
|
||||
import type { Database as BunDatabase } from "bun:sqlite";
|
||||
import type { DatabaseSync } from "node:sqlite";
|
||||
@@ -15,7 +15,7 @@ import type { SocialProviderList, SocialProviders } from "../social-providers";
|
||||
import type { Logger } from "../env";
|
||||
import type { AuthContext, GenericEndpointContext } from "./context";
|
||||
import type { AuthMiddleware } from "../api";
|
||||
import type { BetterAuthPlugin } from "..";
|
||||
import type { BetterAuthPlugin } from "./plugin";
|
||||
|
||||
type KyselyDatabaseType = "postgres" | "mysql" | "sqlite" | "mssql";
|
||||
type OmitId<T extends { id: unknown }> = Omit<T, "id">;
|
||||
|
||||
Generated
+14
-6
@@ -352,7 +352,7 @@ importers:
|
||||
version: 12.23.12(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
geist:
|
||||
specifier: ^1.4.2
|
||||
version: 1.4.2(next@16.0.0-beta.0(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(sass@1.90.0))
|
||||
version: 1.4.2(next@16.0.0-beta.0(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(sass@1.90.0))
|
||||
input-otp:
|
||||
specifier: ^1.4.2
|
||||
version: 1.4.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
@@ -608,7 +608,7 @@ importers:
|
||||
version: 15.8.3(@oramacloud/client@2.1.4)(@tanstack/react-router@1.131.27(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(algoliasearch@5.36.0)(lucide-react@0.542.0(react@19.2.0))(next@16.0.0-beta.0(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(sass@1.90.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(tailwindcss@4.1.13)
|
||||
geist:
|
||||
specifier: ^1.4.2
|
||||
version: 1.4.2(next@16.0.0-beta.0(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(sass@1.90.0))
|
||||
version: 1.4.2(next@16.0.0-beta.0(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(sass@1.90.0))
|
||||
gray-matter:
|
||||
specifier: ^4.0.3
|
||||
version: 4.0.3
|
||||
@@ -839,12 +839,18 @@ importers:
|
||||
|
||||
e2e/smoke/test/fixtures/tsconfig-decelration:
|
||||
dependencies:
|
||||
'@better-auth/sso':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../../packages/sso
|
||||
'@better-auth/stripe':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../../packages/stripe
|
||||
better-auth:
|
||||
specifier: workspace:*
|
||||
version: link:../../../../../packages/better-auth
|
||||
better-sqlite3:
|
||||
specifier: ^12.4.1
|
||||
version: 12.4.1
|
||||
stripe:
|
||||
specifier: ^18.5.0
|
||||
version: 18.5.0(@types/node@24.7.2)
|
||||
|
||||
e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types:
|
||||
dependencies:
|
||||
@@ -17523,7 +17529,9 @@ snapshots:
|
||||
metro-runtime: 0.83.3
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
optional: true
|
||||
|
||||
'@react-native/normalize-colors@0.74.89': {}
|
||||
@@ -21641,7 +21649,7 @@ snapshots:
|
||||
|
||||
function-bind@1.1.2: {}
|
||||
|
||||
geist@1.4.2(next@16.0.0-beta.0(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(sass@1.90.0)):
|
||||
geist@1.4.2(next@16.0.0-beta.0(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(sass@1.90.0)):
|
||||
dependencies:
|
||||
next: 16.0.0-beta.0(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(sass@1.90.0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user