@hexclave/tanstack-start 1.0.64 → 1.0.66
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/{admin-app-impl-Cdh1oCee.d.ts → admin-app-impl-WvWhAoAp.d.ts} +2 -2
- package/dist/{admin-app-impl-Cdh1oCee.d.ts.map → admin-app-impl-WvWhAoAp.d.ts.map} +1 -1
- package/dist/auth-page-YnM_LtbN.d.ts.map +1 -1
- package/dist/cli-auth-confirm-BW3PYpKb.d.ts.map +1 -1
- package/dist/components/api-key-dialogs.d.ts +1 -1
- package/dist/components/api-key-dialogs.js +4 -4
- package/dist/components/credential-sign-in.js +3 -3
- package/dist/components/credential-sign-up.js +5 -5
- package/dist/components/elements/sidebar-layout.js +2 -2
- package/dist/components/elements/user-avatar.js +1 -1
- package/dist/components/magic-link-sign-in.js +5 -5
- package/dist/components/message-cards/no-auth-methods-message-card.d.ts +13 -0
- package/dist/components/message-cards/no-auth-methods-message-card.d.ts.map +1 -0
- package/dist/components/message-cards/no-auth-methods-message-card.js +75 -0
- package/dist/components/message-cards/no-auth-methods-message-card.js.map +1 -0
- package/dist/components/message-cards/predefined-message-card.js +1 -1
- package/dist/components/passkey-button.js +1 -1
- package/dist/components/profile-image-editor.js +1 -1
- package/dist/components/team-icon.js +1 -1
- package/dist/components/team-switcher.js +1 -1
- package/dist/components/user-button.js +1 -1
- package/dist/components-page/account-settings/editable-text.js +1 -1
- package/dist/components-page/account-settings/email-and-auth/emails-section.js +3 -3
- package/dist/components-page/account-settings/email-and-auth/password-section.js +3 -3
- package/dist/components-page/account-settings/teams/team-creation-page.js +3 -3
- package/dist/components-page/account-settings/teams/team-member-invitation-section.js +4 -4
- package/dist/components-page/account-settings.js +3 -3
- package/dist/components-page/auth-page.js +8 -3
- package/dist/components-page/auth-page.js.map +1 -1
- package/dist/components-page/cli-auth-confirm.js +8 -2
- package/dist/components-page/cli-auth-confirm.js.map +1 -1
- package/dist/components-page/cli-auth-confirm.test.js +42 -0
- package/dist/components-page/cli-auth-confirm.test.js.map +1 -1
- package/dist/components-page/forgot-password.js +5 -5
- package/dist/components-page/hexclave-handler-client.js +1 -1
- package/dist/components-page/mfa.js +3 -3
- package/dist/components-page/oauth-callback.js +1 -1
- package/dist/components-page/onboarding.js +4 -4
- package/dist/components-page/password-reset.js +8 -8
- package/dist/components-page/team-creation.js +5 -5
- package/dist/esm/components/api-key-dialogs.d.ts +1 -1
- package/dist/esm/components/api-key-dialogs.js +4 -4
- package/dist/esm/components/credential-sign-in.js +3 -3
- package/dist/esm/components/credential-sign-up.js +5 -5
- package/dist/esm/components/elements/sidebar-layout.js +2 -2
- package/dist/esm/components/elements/user-avatar.js +1 -1
- package/dist/esm/components/magic-link-sign-in.js +5 -5
- package/dist/esm/components/message-cards/no-auth-methods-message-card.d.ts +13 -0
- package/dist/esm/components/message-cards/no-auth-methods-message-card.d.ts.map +1 -0
- package/dist/esm/components/message-cards/no-auth-methods-message-card.js +74 -0
- package/dist/esm/components/message-cards/no-auth-methods-message-card.js.map +1 -0
- package/dist/esm/components/message-cards/predefined-message-card.js +1 -1
- package/dist/esm/components/passkey-button.js +1 -1
- package/dist/esm/components/profile-image-editor.js +1 -1
- package/dist/esm/components/team-icon.js +1 -1
- package/dist/esm/components/team-switcher.js +1 -1
- package/dist/esm/components/user-button.js +1 -1
- package/dist/esm/components-page/account-settings/editable-text.js +1 -1
- package/dist/esm/components-page/account-settings/email-and-auth/emails-section.js +3 -3
- package/dist/esm/components-page/account-settings/email-and-auth/password-section.js +3 -3
- package/dist/esm/components-page/account-settings/teams/team-creation-page.js +3 -3
- package/dist/esm/components-page/account-settings/teams/team-member-invitation-section.js +4 -4
- package/dist/esm/components-page/account-settings.js +3 -3
- package/dist/esm/components-page/auth-page.d.ts.map +1 -1
- package/dist/esm/components-page/auth-page.js +8 -3
- package/dist/esm/components-page/auth-page.js.map +1 -1
- package/dist/esm/components-page/cli-auth-confirm.d.ts.map +1 -1
- package/dist/esm/components-page/cli-auth-confirm.js +8 -2
- package/dist/esm/components-page/cli-auth-confirm.js.map +1 -1
- package/dist/esm/components-page/cli-auth-confirm.test.js +42 -0
- package/dist/esm/components-page/cli-auth-confirm.test.js.map +1 -1
- package/dist/esm/components-page/forgot-password.js +5 -5
- package/dist/esm/components-page/hexclave-handler-client.js +1 -1
- package/dist/esm/components-page/mfa.js +3 -3
- package/dist/esm/components-page/oauth-callback.js +1 -1
- package/dist/esm/components-page/onboarding.js +4 -4
- package/dist/esm/components-page/password-reset.js +7 -7
- package/dist/esm/components-page/team-creation.js +5 -5
- package/dist/esm/generated/global-css.d.ts +1 -1
- package/dist/esm/generated/global-css.js +1 -1
- package/dist/esm/generated/global-css.js.map +1 -1
- package/dist/esm/generated/quetzal-translations.d.ts +2 -2
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +2 -2
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js +2 -2
- package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
- package/dist/esm/lib/hexclave-app/users/index.d.ts +1 -1
- package/dist/generated/global-css.d.ts +1 -1
- package/dist/generated/global-css.js +1 -1
- package/dist/generated/global-css.js.map +1 -1
- package/dist/generated/quetzal-translations.d.ts +1 -1
- package/dist/{hexclave-provider-Dxrf-i1f.d.ts → hexclave-provider-CN52q2zh.d.ts} +2 -2
- package/dist/{hexclave-provider-Dxrf-i1f.d.ts.map → hexclave-provider-CN52q2zh.d.ts.map} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.js +2 -2
- package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
- package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
- package/dist/providers/hexclave-provider.d.ts +1 -1
- package/dist/providers/translation-provider.d.ts +1 -1
- package/dist/{quetzal-translations-CK45_4Dm.d.ts → quetzal-translations-XeH3zQ9l.d.ts} +3 -3
- package/dist/{quetzal-translations-CK45_4Dm.d.ts.map → quetzal-translations-XeH3zQ9l.d.ts.map} +1 -1
- package/dist/{translation-provider-DQ3BJepJ.d.ts → translation-provider-WOaZXqAz.d.ts} +2 -2
- package/dist/{translation-provider-DQ3BJepJ.d.ts.map → translation-provider-WOaZXqAz.d.ts.map} +1 -1
- package/package.json +3 -3
- package/src/components/message-cards/no-auth-methods-message-card.tsx +57 -0
- package/src/components-page/auth-page.tsx +18 -1
- package/src/components-page/cli-auth-confirm.test.tsx +55 -0
- package/src/components-page/cli-auth-confirm.tsx +11 -1
package/dist/{quetzal-translations-CK45_4Dm.d.ts.map → quetzal-translations-XeH3zQ9l.d.ts.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quetzal-translations-
|
|
1
|
+
{"version":3,"file":"quetzal-translations-XeH3zQ9l.d.ts","names":[],"sources":["../src/generated/quetzal-translations.ts"],"mappings":";cAUa,WAAA,EAAW,GAAA;AAAA,cAqTX,cAAA,EAAc,GAAA,mIAAA,GAAA,66qBAAA,GAAA,usnBAAA,GAAA,iyrBAAA,GAAA,g+qBAAA,GAAA,8srBAAA,GAAA,2trBAAA,GAAA,41pBAAA,GAAA,m3eAAA,GAAA,oreAAA,GAAA,swpBAAA,GAAA,+0qBAAA,GAAA,8wbAAA,GAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as quetzalLocales } from "./quetzal-translations-
|
|
1
|
+
import { n as quetzalLocales } from "./quetzal-translations-XeH3zQ9l.js";
|
|
2
2
|
|
|
3
3
|
//#region src/providers/translation-provider.d.ts
|
|
4
4
|
declare function TranslationProvider({
|
|
@@ -12,4 +12,4 @@ declare function TranslationProvider({
|
|
|
12
12
|
}): import("react/jsx-runtime").JSX.Element;
|
|
13
13
|
//#endregion
|
|
14
14
|
export { TranslationProvider as t };
|
|
15
|
-
//# sourceMappingURL=translation-provider-
|
|
15
|
+
//# sourceMappingURL=translation-provider-WOaZXqAz.d.ts.map
|
package/dist/{translation-provider-DQ3BJepJ.d.ts.map → translation-provider-WOaZXqAz.d.ts.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translation-provider-
|
|
1
|
+
{"version":3,"file":"translation-provider-WOaZXqAz.d.ts","names":[],"sources":["../src/providers/translation-provider.tsx"],"mappings":";;;iBAQgB,mBAAA;EAAsB,IAAA;EAAM,oBAAA;EAAsB;AAAA;EAChE,IAAA,EAAM,UAAA,QAAkB,cAAA,CAAe,GAAA;EACvC,oBAAA,GAAuB,MAAA;EACvB,QAAA,EAAU,KAAA,CAAM,SAAA;AAAA,gCACjB,GAAA,CAAA,OAAA"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"//": "THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template (FOR package.json FILES, PLEASE EDIT package-template.json)",
|
|
3
3
|
"name": "@hexclave/tanstack-start",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.66",
|
|
5
5
|
"repository": "https://github.com/hexclave/hexclave",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -85,8 +85,8 @@
|
|
|
85
85
|
"tailwindcss-animate": "^1.0.7",
|
|
86
86
|
"rrweb": "^1.1.3",
|
|
87
87
|
"yup": "^1.7.1",
|
|
88
|
-
"@hexclave/shared": "1.0.
|
|
89
|
-
"@hexclave/ui": "1.0.
|
|
88
|
+
"@hexclave/shared": "1.0.66",
|
|
89
|
+
"@hexclave/ui": "1.0.66"
|
|
90
90
|
},
|
|
91
91
|
"peerDependencies": {
|
|
92
92
|
"@types/react": ">=18.0.0",
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
//===========================================
|
|
5
|
+
// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template
|
|
6
|
+
//===========================================
|
|
7
|
+
|
|
8
|
+
import { Typography } from "@hexclave/ui";
|
|
9
|
+
import { KeyRound } from "lucide-react";
|
|
10
|
+
import { useTranslation } from "../../lib/translations";
|
|
11
|
+
import { MaybeFullPage } from "../elements/maybe-full-page";
|
|
12
|
+
|
|
13
|
+
const configSnippet = `auth: {
|
|
14
|
+
password: { allowSignIn: true },
|
|
15
|
+
otp: { allowSignIn: true },
|
|
16
|
+
}`;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Shown instead of the sign-in/sign-up form when a project has no auth methods at all (no password, no
|
|
20
|
+
* OTP, no passkey, no OAuth provider). Without this, the page would look broken: there is nothing the end
|
|
21
|
+
* user can do, and the developer gets no hint about what went wrong or how to fix it.
|
|
22
|
+
*/
|
|
23
|
+
export function NoAuthMethodsMessageCard(props: {
|
|
24
|
+
fullPage?: boolean,
|
|
25
|
+
projectDisplayName?: string,
|
|
26
|
+
}) {
|
|
27
|
+
const { t } = useTranslation();
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<MaybeFullPage fullPage={!!props.fullPage}>
|
|
31
|
+
<div className='stack-scope flex flex-col items-stretch' style={{ maxWidth: '380px', flexBasis: '380px', padding: props.fullPage ? '1rem' : 0 }}>
|
|
32
|
+
<div className="flex flex-col items-center text-center">
|
|
33
|
+
<div className="mb-4 flex h-11 w-11 items-center justify-center rounded-2xl border border-black/[0.08] dark:border-white/[0.10]">
|
|
34
|
+
<KeyRound className="h-5 w-5 text-gray-500" />
|
|
35
|
+
</div>
|
|
36
|
+
<Typography type='h2'>{t("Sign-in is not available")}</Typography>
|
|
37
|
+
<Typography type='label' variant='secondary'>
|
|
38
|
+
{props.projectDisplayName == null
|
|
39
|
+
? t("This app has no authentication methods enabled, so nobody can sign in yet.")
|
|
40
|
+
: t("{projectDisplayName} has no authentication methods enabled, so nobody can sign in yet.", { projectDisplayName: props.projectDisplayName })}
|
|
41
|
+
</Typography>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div className="mt-6 rounded-xl border border-black/[0.08] p-4 text-left dark:border-white/[0.10]">
|
|
45
|
+
<Typography type='label'>{t("Are you the developer?")}</Typography>
|
|
46
|
+
<Typography type='label' variant='secondary'>
|
|
47
|
+
{t("Enable at least one sign-in method in your hexclave.config.ts:")}
|
|
48
|
+
</Typography>
|
|
49
|
+
<pre className="mt-2 overflow-x-auto rounded-lg border border-black/[0.06] p-3 font-mono text-xs leading-relaxed dark:border-white/[0.08]">{configSnippet}</pre>
|
|
50
|
+
<Typography type='label' variant='secondary'>
|
|
51
|
+
{t("Or turn one on in the Hexclave dashboard, under Auth Methods.")}
|
|
52
|
+
</Typography>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</MaybeFullPage>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
@@ -19,6 +19,7 @@ import { SeparatorWithText } from '../components/elements/separator-with-text';
|
|
|
19
19
|
import { StyledLink } from '../components/link';
|
|
20
20
|
import { KnownErrorMessageCard } from '../components/message-cards/known-error-message-card';
|
|
21
21
|
import { MessageCard } from '../components/message-cards/message-card';
|
|
22
|
+
import { NoAuthMethodsMessageCard } from '../components/message-cards/no-auth-methods-message-card';
|
|
22
23
|
import { MagicLinkSignIn } from '../components/magic-link-sign-in';
|
|
23
24
|
import { PredefinedMessageCard } from '../components/message-cards/predefined-message-card';
|
|
24
25
|
import { OAuthButtonGroup } from '../components/oauth-button-group';
|
|
@@ -137,6 +138,18 @@ function Inner(props: Props) {
|
|
|
137
138
|
const hasPasskey = (project.config.passkeyEnabled === true && props.type === "sign-in");
|
|
138
139
|
const enableSeparator = (project.config.credentialEnabled || project.config.magicLinkEnabled) && (hasOAuthProviders || hasPasskey);
|
|
139
140
|
|
|
141
|
+
// Note that we check passkeys regardless of `props.type` here (unlike `hasPasskey`); a project with only
|
|
142
|
+
// passkeys enabled can't sign up with them, but it is configured correctly, so the sign-up page should
|
|
143
|
+
// keep pointing at the sign-in page instead of claiming that the project is misconfigured.
|
|
144
|
+
const hasAnyAuthMethod = hasOAuthProviders
|
|
145
|
+
|| project.config.passkeyEnabled === true
|
|
146
|
+
|| project.config.credentialEnabled
|
|
147
|
+
|| project.config.magicLinkEnabled;
|
|
148
|
+
|
|
149
|
+
if (!hasAnyAuthMethod) {
|
|
150
|
+
return <NoAuthMethodsMessageCard fullPage={props.fullPage} projectDisplayName={'displayName' in project ? project.displayName : undefined} />;
|
|
151
|
+
}
|
|
152
|
+
|
|
140
153
|
return (
|
|
141
154
|
<MaybeFullPage fullPage={!!props.fullPage}>
|
|
142
155
|
<div className='stack-scope flex flex-col items-stretch' style={{ maxWidth: '380px', flexBasis: '380px', padding: props.fullPage ? '1rem' : 0 }}>
|
|
@@ -191,7 +204,11 @@ function Inner(props: Props) {
|
|
|
191
204
|
props.type === 'sign-up' ? <CredentialSignUp noPasswordRepeat={props.noPasswordRepeat} /> : <CredentialSignIn />
|
|
192
205
|
) : project.config.magicLinkEnabled ? (
|
|
193
206
|
<MagicLinkSignIn />
|
|
194
|
-
) : !(hasOAuthProviders || hasPasskey) ?
|
|
207
|
+
) : !(hasOAuthProviders || hasPasskey) ? (
|
|
208
|
+
// Only reachable on the sign-up page of a passkey-only project: the project is configured
|
|
209
|
+
// correctly, there is just no way to create an account with a passkey alone.
|
|
210
|
+
<Typography variant="secondary" className="text-center">{t("New accounts can't be created with the sign-in methods enabled for this app. Sign in instead.")}</Typography>
|
|
211
|
+
) : null}
|
|
195
212
|
{props.extraInfo && (
|
|
196
213
|
<div className={cn('flex flex-col items-center text-center text-sm text-gray-500', {
|
|
197
214
|
'mt-2': project.config.credentialEnabled || project.config.magicLinkEnabled,
|
|
@@ -28,11 +28,13 @@ function createAppTestDouble(options: {
|
|
|
28
28
|
signInWithTokens?: (tokens: { accessToken: string, refreshToken: string }) => Promise<void>,
|
|
29
29
|
redirectToSignIn?: (options: { replace: true }) => Promise<void>,
|
|
30
30
|
redirectToSignUp?: (options: { replace: true }) => Promise<void>,
|
|
31
|
+
redirectToOnboarding?: (options: { replace: true }) => Promise<void>,
|
|
31
32
|
}) {
|
|
32
33
|
const app = {
|
|
33
34
|
useUser: () => options.user,
|
|
34
35
|
redirectToSignIn: options.redirectToSignIn ?? vi.fn(async () => {}),
|
|
35
36
|
redirectToSignUp: options.redirectToSignUp ?? vi.fn(async () => {}),
|
|
37
|
+
redirectToOnboarding: options.redirectToOnboarding ?? vi.fn(async () => {}),
|
|
36
38
|
[hexclaveAppInternalsSymbol]: {
|
|
37
39
|
sendRequest: options.sendRequest,
|
|
38
40
|
signInWithTokens: options.signInWithTokens ?? vi.fn(async () => {}),
|
|
@@ -102,6 +104,7 @@ describe("useCliAuthConfirmation", () => {
|
|
|
102
104
|
root = null;
|
|
103
105
|
container = null;
|
|
104
106
|
vi.restoreAllMocks();
|
|
107
|
+
sessionStorage.clear();
|
|
105
108
|
window.history.replaceState({}, "", "/");
|
|
106
109
|
Reflect.set(globalThis, "IS_REACT_ACT_ENVIRONMENT", previousActEnvironment);
|
|
107
110
|
});
|
|
@@ -132,6 +135,58 @@ describe("useCliAuthConfirmation", () => {
|
|
|
132
135
|
`);
|
|
133
136
|
});
|
|
134
137
|
|
|
138
|
+
it("redirects restricted users to onboarding without completing CLI auth", async () => {
|
|
139
|
+
window.history.replaceState({}, "", "/handler/cli-auth-confirm?login_code=login-code");
|
|
140
|
+
const redirectToOnboarding = vi.fn(async (_options: { replace: true }) => {});
|
|
141
|
+
const sendRequest = vi.fn(async (_path: string, _requestOptions: RequestInit) => new Response(null, { status: 200 }));
|
|
142
|
+
const app = createAppTestDouble({
|
|
143
|
+
user: {
|
|
144
|
+
isRestricted: true,
|
|
145
|
+
isAnonymous: false,
|
|
146
|
+
currentSession: {
|
|
147
|
+
getTokens: vi.fn(async () => ({ refreshToken: "restricted-refresh-token" })),
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
sendRequest,
|
|
151
|
+
redirectToOnboarding,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
await renderWithApp(app);
|
|
155
|
+
await act(async () => {
|
|
156
|
+
getButton("authorize").click();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
expect(redirectToOnboarding).toHaveBeenCalledWith({ replace: true });
|
|
160
|
+
expect(sessionStorage.getItem("hexclave-cli-auth-confirmed")).toBe("login-code");
|
|
161
|
+
expect(sendRequest).not.toHaveBeenCalled();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("redirects anonymous users to sign-up without completing CLI auth", async () => {
|
|
165
|
+
window.history.replaceState({}, "", "/handler/cli-auth-confirm?login_code=login-code");
|
|
166
|
+
const redirectToSignUp = vi.fn(async (_options: { replace: true }) => {});
|
|
167
|
+
const sendRequest = vi.fn(async (_path: string, _requestOptions: RequestInit) => new Response(null, { status: 200 }));
|
|
168
|
+
const app = createAppTestDouble({
|
|
169
|
+
user: {
|
|
170
|
+
isRestricted: true,
|
|
171
|
+
isAnonymous: true,
|
|
172
|
+
currentSession: {
|
|
173
|
+
getTokens: vi.fn(async () => ({ refreshToken: "anonymous-refresh-token" })),
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
sendRequest,
|
|
177
|
+
redirectToSignUp,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
await renderWithApp(app);
|
|
181
|
+
await act(async () => {
|
|
182
|
+
getButton("authorize").click();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
expect(redirectToSignUp).toHaveBeenCalledWith({ replace: true });
|
|
186
|
+
expect(sessionStorage.getItem("hexclave-cli-auth-confirmed")).toBe("login-code");
|
|
187
|
+
expect(sendRequest).not.toHaveBeenCalled();
|
|
188
|
+
});
|
|
189
|
+
|
|
135
190
|
it("ignores duplicate authorize clicks before React re-renders", async () => {
|
|
136
191
|
window.history.replaceState({}, "", "/handler/cli-auth-confirm?login_code=login-code");
|
|
137
192
|
const getTokens = vi.fn(async () => ({ refreshToken: "refresh-token" }));
|
|
@@ -111,7 +111,7 @@ export function useCliAuthConfirmation(): CliAuthConfirmationState {
|
|
|
111
111
|
}, [app, loginCode, user]);
|
|
112
112
|
|
|
113
113
|
useEffect(() => {
|
|
114
|
-
if (!confirmed || !user || autoCompleteRef.current) {
|
|
114
|
+
if (!confirmed || !user || user.isRestricted || autoCompleteRef.current) {
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
117
|
autoCompleteRef.current = true;
|
|
@@ -144,6 +144,16 @@ export function useCliAuthConfirmation(): CliAuthConfirmationState {
|
|
|
144
144
|
setError(null);
|
|
145
145
|
setStatus("authorizing");
|
|
146
146
|
if (user) {
|
|
147
|
+
if (user.isRestricted) {
|
|
148
|
+
markConfirmed(loginCode);
|
|
149
|
+
setStatus("redirecting");
|
|
150
|
+
await (
|
|
151
|
+
user.isAnonymous
|
|
152
|
+
? app.redirectToSignUp({ replace: true })
|
|
153
|
+
: app.redirectToOnboarding({ replace: true })
|
|
154
|
+
);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
147
157
|
await completeWithCurrentUser();
|
|
148
158
|
clearConfirmed();
|
|
149
159
|
setStatus("success");
|