@carlonicora/nextjs-jsonapi 6.29.1 → 6.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BlockNoteEditor-K4HWQLPJ.js → BlockNoteEditor-ICGGCW6N.js} +24 -24
- package/dist/{BlockNoteEditor-K4HWQLPJ.js.map → BlockNoteEditor-ICGGCW6N.js.map} +1 -1
- package/dist/{BlockNoteEditor-TDX2RC7I.mjs → BlockNoteEditor-O4E67ECL.mjs} +4 -4
- package/dist/{BlockNoteViewer-76CKL6W5.mjs → BlockNoteViewer-BNZEXGVT.mjs} +2 -2
- package/dist/{BlockNoteViewer-B25WKYQP.js → BlockNoteViewer-YONLBNXW.js} +3 -3
- package/dist/{BlockNoteViewer-B25WKYQP.js.map → BlockNoteViewer-YONLBNXW.js.map} +1 -1
- package/dist/billing/index.js +465 -465
- package/dist/billing/index.mjs +3 -3
- package/dist/{chunk-77JC2UCF.js → chunk-5XP5G45B.js} +23 -10
- package/dist/chunk-5XP5G45B.js.map +1 -0
- package/dist/{chunk-OVSR72CZ.mjs → chunk-BT3VFB3I.mjs} +333 -299
- package/dist/chunk-BT3VFB3I.mjs.map +1 -0
- package/dist/{chunk-7MGXQIEP.mjs → chunk-FDKAVSZ6.mjs} +2 -2
- package/dist/{chunk-FJUKLVVX.mjs → chunk-HNK2O6YE.mjs} +23 -10
- package/dist/chunk-HNK2O6YE.mjs.map +1 -0
- package/dist/{chunk-M7YK5CCE.mjs → chunk-JL6XL5NK.mjs} +9 -2
- package/dist/chunk-JL6XL5NK.mjs.map +1 -0
- package/dist/{chunk-QI4SCGPB.js → chunk-M7FA63QE.js} +803 -769
- package/dist/chunk-M7FA63QE.js.map +1 -0
- package/dist/{chunk-F3EVYBMA.js → chunk-NQL2NDKH.js} +4 -4
- package/dist/{chunk-F3EVYBMA.js.map → chunk-NQL2NDKH.js.map} +1 -1
- package/dist/{chunk-ONU4WCDG.js → chunk-Q5SMFSE4.js} +11 -4
- package/dist/chunk-Q5SMFSE4.js.map +1 -0
- package/dist/client/index.js +4 -4
- package/dist/client/index.mjs +3 -3
- package/dist/components/forms/CommonEditorButtons.d.ts.map +1 -1
- package/dist/components/index.js +4 -4
- package/dist/components/index.mjs +3 -3
- package/dist/contexts/index.js +4 -4
- package/dist/contexts/index.mjs +3 -3
- package/dist/core/index.js +2 -2
- package/dist/core/index.mjs +1 -1
- package/dist/email-automations/index.js +105 -105
- package/dist/email-automations/index.mjs +3 -3
- package/dist/features/analytics/index.js +114 -114
- package/dist/features/analytics/index.mjs +3 -3
- package/dist/features/analytics/server.js +4 -4
- package/dist/features/analytics/server.mjs +2 -2
- package/dist/features/auth/components/GdprConsentSection.d.ts +2 -1
- package/dist/features/auth/components/GdprConsentSection.d.ts.map +1 -1
- package/dist/features/auth/components/forms/Login.d.ts.map +1 -1
- package/dist/features/auth/components/forms/Register.d.ts.map +1 -1
- package/dist/features/auth/data/auth.service.d.ts +8 -3
- package/dist/features/auth/data/auth.service.d.ts.map +1 -1
- package/dist/features/auth/data/pending-registration.d.ts +2 -0
- package/dist/features/auth/data/pending-registration.d.ts.map +1 -1
- package/dist/features/auth/data/pending-registration.interface.d.ts +1 -0
- package/dist/features/auth/data/pending-registration.interface.d.ts.map +1 -1
- package/dist/features/auth/hooks/useCompleteLogin.d.ts +9 -0
- package/dist/features/auth/hooks/useCompleteLogin.d.ts.map +1 -0
- package/dist/features/blog/index.js +129 -129
- package/dist/features/blog/index.mjs +3 -3
- package/dist/features/blog/server.js +7 -7
- package/dist/features/blog/server.mjs +1 -1
- package/dist/features/help/index.js +37 -37
- package/dist/features/help/index.mjs +3 -3
- package/dist/features/tokenusage/index.js +114 -114
- package/dist/features/tokenusage/index.mjs +3 -3
- package/dist/index.js +3 -3
- package/dist/index.mjs +2 -2
- package/dist/login/config.d.ts +3 -0
- package/dist/login/config.d.ts.map +1 -1
- package/dist/login/index.d.ts +1 -1
- package/dist/login/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +2 -2
- package/messages/en.json +1 -0
- package/messages/it.json +1 -0
- package/package.json +1 -1
- package/src/components/forms/CommonEditorButtons.tsx +16 -2
- package/src/features/auth/components/GdprConsentSection.tsx +3 -1
- package/src/features/auth/components/forms/Login.tsx +4 -32
- package/src/features/auth/components/forms/Register.tsx +66 -36
- package/src/features/auth/data/__tests__/auth.oauth-completion.spec.ts +44 -0
- package/src/features/auth/data/__tests__/pending-registration.spec.ts +8 -0
- package/src/features/auth/data/auth.service.ts +21 -15
- package/src/features/auth/data/pending-registration.interface.ts +1 -0
- package/src/features/auth/data/pending-registration.ts +6 -0
- package/src/features/auth/hooks/__tests__/useCompleteLogin.spec.tsx +85 -0
- package/src/features/auth/hooks/useCompleteLogin.ts +47 -0
- package/src/login/__tests__/config.spec.ts +21 -0
- package/src/login/config.ts +8 -0
- package/src/login/index.ts +1 -0
- package/dist/chunk-77JC2UCF.js.map +0 -1
- package/dist/chunk-FJUKLVVX.mjs.map +0 -1
- package/dist/chunk-M7YK5CCE.mjs.map +0 -1
- package/dist/chunk-ONU4WCDG.js.map +0 -1
- package/dist/chunk-OVSR72CZ.mjs.map +0 -1
- package/dist/chunk-QI4SCGPB.js.map +0 -1
- /package/dist/{BlockNoteEditor-TDX2RC7I.mjs.map → BlockNoteEditor-O4E67ECL.mjs.map} +0 -0
- /package/dist/{BlockNoteViewer-76CKL6W5.mjs.map → BlockNoteViewer-BNZEXGVT.mjs.map} +0 -0
- /package/dist/{chunk-7MGXQIEP.mjs.map → chunk-FDKAVSZ6.mjs.map} +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
2
|
+
import { Modules } from "../../../../core";
|
|
3
|
+
import { ApiRequestDataTypeInterface } from "../../../../core/interfaces/ApiRequestDataTypeInterface";
|
|
4
|
+
import { ModuleRegistry } from "../../../../core/registry/ModuleRegistry";
|
|
5
|
+
import { Auth } from "../auth";
|
|
6
|
+
|
|
7
|
+
// Auth.createJsonApi() reads Modules.Auth.name through the real ModuleRegistry,
|
|
8
|
+
// so it must be registered (same pattern as auth.spec.ts).
|
|
9
|
+
const registerIfAbsent = (key: string, module: ApiRequestDataTypeInterface) => {
|
|
10
|
+
try {
|
|
11
|
+
ModuleRegistry.get(key as any);
|
|
12
|
+
} catch {
|
|
13
|
+
ModuleRegistry.register(key, module);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
beforeAll(() => {
|
|
18
|
+
registerIfAbsent("Auth", { name: "auth", model: Auth } as any);
|
|
19
|
+
registerIfAbsent("User", { name: "users", model: class {} } as any);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe("Auth.createJsonApi() for the OAuth completion", () => {
|
|
23
|
+
it("an OAuth completion body carries the pending id and the given consent", () => {
|
|
24
|
+
const body = new Auth().createJsonApi({
|
|
25
|
+
id: "p1",
|
|
26
|
+
termsAcceptedAt: "2026-11-09T00:00:00.000Z",
|
|
27
|
+
marketingConsent: false,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect(body).toEqual({
|
|
31
|
+
data: {
|
|
32
|
+
type: Modules.Auth.name,
|
|
33
|
+
id: "p1",
|
|
34
|
+
attributes: { termsAcceptedAt: "2026-11-09T00:00:00.000Z", marketingConsent: false },
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("an invite completion sends no consent attributes", () => {
|
|
40
|
+
const body = new Auth().createJsonApi({ id: "p1" });
|
|
41
|
+
|
|
42
|
+
expect(body).toEqual({ data: { type: Modules.Auth.name, id: "p1", attributes: {} } });
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -16,6 +16,7 @@ describe("PendingRegistration.rehydrate()", () => {
|
|
|
16
16
|
provider: "discord",
|
|
17
17
|
hasPass: true,
|
|
18
18
|
emailInUse: true,
|
|
19
|
+
hasInvite: true,
|
|
19
20
|
});
|
|
20
21
|
|
|
21
22
|
expect(pending.id).toBe("pending-1");
|
|
@@ -25,6 +26,7 @@ describe("PendingRegistration.rehydrate()", () => {
|
|
|
25
26
|
expect(pending.provider).toBe("discord");
|
|
26
27
|
expect(pending.hasPass).toBe(true);
|
|
27
28
|
expect(pending.emailInUse).toBe(true);
|
|
29
|
+
expect(pending.hasInvite).toBe(true);
|
|
28
30
|
});
|
|
29
31
|
|
|
30
32
|
it("leaves avatar undefined and defaults hasPass/emailInUse to false when absent", () => {
|
|
@@ -34,4 +36,10 @@ describe("PendingRegistration.rehydrate()", () => {
|
|
|
34
36
|
expect(pending.hasPass).toBe(false);
|
|
35
37
|
expect(pending.emailInUse).toBe(false);
|
|
36
38
|
});
|
|
39
|
+
|
|
40
|
+
it("PendingRegistration rehydrates hasInvite with a false default", () => {
|
|
41
|
+
expect(hydrate({ name: "Aria", email: "aria@example.com", provider: "google" }).hasInvite).toBe(false);
|
|
42
|
+
expect(hydrate({ name: "Aria", hasInvite: null }).hasInvite).toBe(false);
|
|
43
|
+
expect(hydrate({ name: "Aria", hasInvite: true }).hasInvite).toBe(true);
|
|
44
|
+
});
|
|
37
45
|
});
|
|
@@ -195,24 +195,30 @@ export class AuthService extends AbstractService {
|
|
|
195
195
|
});
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Completes an OAuth sign-up waiting for consent. A sign-up with a usable
|
|
200
|
+
* waitlist invite sends no consent: the server copies it from the waitlist.
|
|
201
|
+
* Throws an Error with message `"<status>:<message>"` on failure.
|
|
202
|
+
*/
|
|
198
203
|
static async completeOAuthRegistration(params: {
|
|
199
204
|
pendingId: string;
|
|
200
|
-
termsAcceptedAt
|
|
201
|
-
marketingConsent
|
|
202
|
-
marketingConsentAt
|
|
205
|
+
termsAcceptedAt?: string;
|
|
206
|
+
marketingConsent?: boolean;
|
|
207
|
+
marketingConsentAt?: string | null;
|
|
203
208
|
}): Promise<{ code: string }> {
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
209
|
+
const input: AuthInput = {
|
|
210
|
+
id: params.pendingId,
|
|
211
|
+
termsAcceptedAt: params.termsAcceptedAt,
|
|
212
|
+
marketingConsent: params.marketingConsent,
|
|
213
|
+
marketingConsentAt: params.marketingConsentAt,
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
return this.callApi<{ code: string }>({
|
|
217
|
+
type: Modules.Auth,
|
|
218
|
+
method: HttpMethod.POST,
|
|
219
|
+
endpoint: new EndpointCreator({ endpoint: Modules.Auth, id: "oauth", childEndpoint: "complete" }).generate(),
|
|
220
|
+
input: input,
|
|
221
|
+
suppressGlobalError: true,
|
|
212
222
|
});
|
|
213
|
-
|
|
214
|
-
if (!response.ok) throw new Error(response.error);
|
|
215
|
-
|
|
216
|
-
return response.data as unknown as { code: string };
|
|
217
223
|
}
|
|
218
224
|
}
|
|
@@ -8,6 +8,7 @@ export class PendingRegistration extends AbstractApiData implements PendingRegis
|
|
|
8
8
|
private _provider?: string;
|
|
9
9
|
private _hasPass?: boolean;
|
|
10
10
|
private _emailInUse?: boolean;
|
|
11
|
+
private _hasInvite?: boolean;
|
|
11
12
|
|
|
12
13
|
get name(): string {
|
|
13
14
|
return this._name ?? "";
|
|
@@ -33,6 +34,10 @@ export class PendingRegistration extends AbstractApiData implements PendingRegis
|
|
|
33
34
|
return this._emailInUse ?? false;
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
get hasInvite(): boolean {
|
|
38
|
+
return this._hasInvite ?? false;
|
|
39
|
+
}
|
|
40
|
+
|
|
36
41
|
rehydrate(data: JsonApiHydratedDataInterface): this {
|
|
37
42
|
super.rehydrate(data);
|
|
38
43
|
this._name = data.jsonApi.attributes.name;
|
|
@@ -41,6 +46,7 @@ export class PendingRegistration extends AbstractApiData implements PendingRegis
|
|
|
41
46
|
this._provider = data.jsonApi.attributes.provider;
|
|
42
47
|
this._hasPass = data.jsonApi.attributes.hasPass ?? false;
|
|
43
48
|
this._emailInUse = data.jsonApi.attributes.emailInUse ?? false;
|
|
49
|
+
this._hasInvite = data.jsonApi.attributes.hasInvite ?? false;
|
|
44
50
|
return this;
|
|
45
51
|
}
|
|
46
52
|
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react";
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { AuthComponent } from "../../enums";
|
|
4
|
+
import { useCompleteLogin } from "../useCompleteLogin";
|
|
5
|
+
|
|
6
|
+
const mocks = vi.hoisted(() => ({
|
|
7
|
+
setUser: vi.fn(),
|
|
8
|
+
setComponentType: vi.fn(),
|
|
9
|
+
setPendingTwoFactor: vi.fn(),
|
|
10
|
+
i18nRouter: { replace: vi.fn(), push: vi.fn() },
|
|
11
|
+
nativeRouter: { replace: vi.fn(), push: vi.fn() },
|
|
12
|
+
search: { value: "" },
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
vi.mock(
|
|
16
|
+
"../../../user/contexts",
|
|
17
|
+
() => new Proxy({ useCurrentUserContext: () => ({ setUser: mocks.setUser }) }, { has: () => true }),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
vi.mock(
|
|
21
|
+
"../../contexts",
|
|
22
|
+
() =>
|
|
23
|
+
new Proxy(
|
|
24
|
+
{
|
|
25
|
+
useAuthContext: () => ({
|
|
26
|
+
setComponentType: mocks.setComponentType,
|
|
27
|
+
setPendingTwoFactor: mocks.setPendingTwoFactor,
|
|
28
|
+
}),
|
|
29
|
+
},
|
|
30
|
+
{ has: () => true },
|
|
31
|
+
),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
vi.mock(
|
|
35
|
+
"../../../../hooks",
|
|
36
|
+
() =>
|
|
37
|
+
new Proxy(
|
|
38
|
+
{
|
|
39
|
+
usePageUrlGenerator:
|
|
40
|
+
() =>
|
|
41
|
+
({ page }: { page: string }) =>
|
|
42
|
+
page,
|
|
43
|
+
useI18nRouter: () => mocks.i18nRouter,
|
|
44
|
+
},
|
|
45
|
+
{ has: () => true },
|
|
46
|
+
),
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
vi.mock("next/navigation", () => ({
|
|
50
|
+
useRouter: () => mocks.nativeRouter,
|
|
51
|
+
useSearchParams: () => new URLSearchParams(mocks.search.value),
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
describe("useCompleteLogin", () => {
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
vi.clearAllMocks();
|
|
57
|
+
mocks.search.value = "";
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("a user response sets the user and goes home", () => {
|
|
61
|
+
const { result } = renderHook(() => useCompleteLogin());
|
|
62
|
+
const user = { id: "u1" } as any;
|
|
63
|
+
result.current(user);
|
|
64
|
+
expect(mocks.setUser).toHaveBeenCalledWith(user);
|
|
65
|
+
expect(mocks.i18nRouter.replace).toHaveBeenCalledWith("/");
|
|
66
|
+
expect(mocks.nativeRouter.replace).not.toHaveBeenCalled();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("a callbackUrl wins over home", () => {
|
|
70
|
+
mocks.search.value = "callbackUrl=/it/campaigns";
|
|
71
|
+
const { result } = renderHook(() => useCompleteLogin());
|
|
72
|
+
result.current({ id: "u1" } as any);
|
|
73
|
+
expect(mocks.nativeRouter.replace).toHaveBeenCalledWith("/it/campaigns");
|
|
74
|
+
expect(mocks.i18nRouter.replace).not.toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("a two-factor challenge opens the challenge", () => {
|
|
78
|
+
const { result } = renderHook(() => useCompleteLogin());
|
|
79
|
+
const challenge = { pendingToken: "p" } as any;
|
|
80
|
+
result.current(challenge);
|
|
81
|
+
expect(mocks.setPendingTwoFactor).toHaveBeenCalledWith(challenge);
|
|
82
|
+
expect(mocks.setComponentType).toHaveBeenCalledWith(AuthComponent.TwoFactorChallenge);
|
|
83
|
+
expect(mocks.setUser).not.toHaveBeenCalled();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useRouter, useSearchParams } from "next/navigation";
|
|
4
|
+
import { useCallback } from "react";
|
|
5
|
+
import { useI18nRouter, usePageUrlGenerator } from "../../../hooks";
|
|
6
|
+
import { UserInterface } from "../../user";
|
|
7
|
+
import { useCurrentUserContext } from "../../user/contexts";
|
|
8
|
+
import { useAuthContext } from "../contexts";
|
|
9
|
+
import { TwoFactorChallengeInterface } from "../data/two-factor-challenge.interface";
|
|
10
|
+
import { AuthComponent } from "../enums";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Post-login handling shared by Login and the invite sign-up in Register:
|
|
14
|
+
* opens the two-factor challenge when one is pending, otherwise stores the
|
|
15
|
+
* user and redirects to the callback URL or home.
|
|
16
|
+
*/
|
|
17
|
+
export function useCompleteLogin(): (response: UserInterface | TwoFactorChallengeInterface) => void {
|
|
18
|
+
const { setUser } = useCurrentUserContext<UserInterface>();
|
|
19
|
+
const { setComponentType, setPendingTwoFactor } = useAuthContext();
|
|
20
|
+
const generateUrl = usePageUrlGenerator();
|
|
21
|
+
const i18nRouter = useI18nRouter();
|
|
22
|
+
const nativeRouter = useRouter(); // For URLs that already include locale
|
|
23
|
+
const searchParams = useSearchParams();
|
|
24
|
+
const callbackUrl = searchParams.get("callbackUrl");
|
|
25
|
+
|
|
26
|
+
return useCallback(
|
|
27
|
+
(response: UserInterface | TwoFactorChallengeInterface) => {
|
|
28
|
+
// Check if 2FA is required (response is TwoFactorChallengeInterface)
|
|
29
|
+
if ("pendingToken" in response) {
|
|
30
|
+
setPendingTwoFactor(response as TwoFactorChallengeInterface);
|
|
31
|
+
setComponentType(AuthComponent.TwoFactorChallenge);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setUser(response as UserInterface);
|
|
36
|
+
|
|
37
|
+
// Use native router for callbackUrl since it already includes the locale prefix
|
|
38
|
+
// Use i18n router for normal navigation which adds locale automatically
|
|
39
|
+
if (callbackUrl) {
|
|
40
|
+
nativeRouter.replace(callbackUrl);
|
|
41
|
+
} else {
|
|
42
|
+
i18nRouter.replace(generateUrl({ page: `/` }));
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
[setUser, setComponentType, setPendingTwoFactor, generateUrl, i18nRouter, nativeRouter, callbackUrl],
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { configureLogin, isCompanyNameRequired } from "../index";
|
|
3
|
+
|
|
4
|
+
describe("login config — requireCompanyName", () => {
|
|
5
|
+
it("isCompanyNameRequired defaults to true", () => {
|
|
6
|
+
configureLogin({});
|
|
7
|
+
expect(isCompanyNameRequired()).toBe(true);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("requireCompanyName false hides the company field", () => {
|
|
11
|
+
configureLogin({ requireCompanyName: false });
|
|
12
|
+
expect(isCompanyNameRequired()).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("a later configureLogin without the option restores the default", () => {
|
|
16
|
+
configureLogin({ requireCompanyName: false });
|
|
17
|
+
expect(isCompanyNameRequired()).toBe(false);
|
|
18
|
+
configureLogin({});
|
|
19
|
+
expect(isCompanyNameRequired()).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
});
|
package/src/login/config.ts
CHANGED
|
@@ -3,6 +3,7 @@ let _useGoogleAuth: boolean = false;
|
|
|
3
3
|
let _useInternalAuth: boolean = true;
|
|
4
4
|
let _allowRegistration: boolean = true;
|
|
5
5
|
let _registrationMode: "open" | "closed" | "waitlist" = "open";
|
|
6
|
+
let _requireCompanyName: boolean = true;
|
|
6
7
|
|
|
7
8
|
export type RegistrationMode = "open" | "closed" | "waitlist";
|
|
8
9
|
|
|
@@ -12,6 +13,8 @@ export interface LoginConfig {
|
|
|
12
13
|
useInternalAuth?: boolean;
|
|
13
14
|
allowRegistration?: boolean;
|
|
14
15
|
registrationMode?: RegistrationMode;
|
|
16
|
+
/** Show and require the company name on sign-up. Default `true`. */
|
|
17
|
+
requireCompanyName?: boolean;
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
export function configureLogin(params: LoginConfig): void {
|
|
@@ -20,6 +23,7 @@ export function configureLogin(params: LoginConfig): void {
|
|
|
20
23
|
_useInternalAuth = params.useInternalAuth ?? true;
|
|
21
24
|
_allowRegistration = params.allowRegistration ?? true;
|
|
22
25
|
_registrationMode = params.registrationMode ?? "open";
|
|
26
|
+
_requireCompanyName = params.requireCompanyName ?? true;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
export function isDiscordAuthEnabled(): boolean {
|
|
@@ -41,3 +45,7 @@ export function isRegistrationAllowed(): boolean {
|
|
|
41
45
|
export function getRegistrationMode(): RegistrationMode {
|
|
42
46
|
return _registrationMode;
|
|
43
47
|
}
|
|
48
|
+
|
|
49
|
+
export function isCompanyNameRequired(): boolean {
|
|
50
|
+
return _requireCompanyName;
|
|
51
|
+
}
|