@lukoweb/apitogo 0.1.38 → 0.1.39

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/cli/cli.js CHANGED
@@ -4121,7 +4121,7 @@ import {
4121
4121
  // package.json
4122
4122
  var package_default = {
4123
4123
  name: "@lukoweb/apitogo",
4124
- version: "0.1.38",
4124
+ version: "0.1.39",
4125
4125
  type: "module",
4126
4126
  sideEffects: [
4127
4127
  "**/*.css",
@@ -14,6 +14,7 @@ export interface AuthenticationPlugin {
14
14
  signUp({ navigate }: AuthActionContext, options?: AuthActionOptions): Promise<void>;
15
15
  signIn({ navigate }: AuthActionContext, options?: AuthActionOptions): Promise<void>;
16
16
  signOut({ navigate }: AuthActionContext): Promise<void>;
17
+ hasDistinctSignUpFlow?(): boolean;
17
18
  signRequest(request: Request): Promise<Request>;
18
19
  requestEmailVerification?({ navigate }: AuthActionContext, options?: AuthActionOptions): Promise<void>;
19
20
  getAccessToken?(): Promise<string>;
@@ -33,6 +33,7 @@ export declare class DevPortalAuthenticationProvider extends CoreAuthenticationP
33
33
  signIn(_: AuthActionContext, { redirectTo }?: AuthActionOptions): Promise<void>;
34
34
  signUp(_: AuthActionContext, { redirectTo }?: AuthActionOptions): Promise<void>;
35
35
  signOut(_: AuthActionContext): Promise<void>;
36
+ hasDistinctSignUpFlow(): boolean;
36
37
  signRequest(request: Request): Promise<Request>;
37
38
  }
38
39
  declare const devPortalAuth: AuthenticationProviderInitializer<DevPortalAuthenticationConfig>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lukoweb/apitogo",
3
- "version": "0.1.38",
3
+ "version": "0.1.39",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "**/*.css",
@@ -26,6 +26,9 @@ export interface AuthenticationPlugin {
26
26
 
27
27
  signOut({ navigate }: AuthActionContext): Promise<void>;
28
28
 
29
+ /** When false, sign-in and sign-up use the same IdP redirect; UI should not offer separate choices. */
30
+ hasDistinctSignUpFlow?(): boolean;
31
+
29
32
  signRequest(request: Request): Promise<Request>;
30
33
  requestEmailVerification?(
31
34
  { navigate }: AuthActionContext,
@@ -79,6 +79,7 @@ export const useAuth = () => {
79
79
  ...authState,
80
80
  isBackendAvailable: authState.isBackendAvailable,
81
81
  authMode: authState.authMode,
82
+ hasDistinctSignUpFlow: authentication?.hasDistinctSignUpFlow?.() ?? true,
82
83
 
83
84
  login: async (options?: AuthActionOptions) => {
84
85
  if (!isAuthEnabled) {
@@ -258,6 +258,10 @@ export class DevPortalAuthenticationProvider
258
258
  );
259
259
  }
260
260
 
261
+ hasDistinctSignUpFlow(): boolean {
262
+ return false;
263
+ }
264
+
261
265
  async signRequest(request: Request): Promise<Request> {
262
266
  return request;
263
267
  }
@@ -8,7 +8,7 @@ import {
8
8
  DialogTitle,
9
9
  } from "@lukoweb/apitogo/ui/Dialog.js";
10
10
  import { Helmet } from "@zudoku/react-helmet-async";
11
- import { use, useCallback, useEffect, useMemo } from "react";
11
+ import { use, useCallback, useEffect, useMemo, useRef } from "react";
12
12
  import {
13
13
  matchPath,
14
14
  Outlet,
@@ -31,6 +31,7 @@ type LoginDialogProps = {
31
31
  onCancel: () => void;
32
32
  onLogin: () => void;
33
33
  onRegister: () => void;
34
+ hasDistinctSignUpFlow: boolean;
34
35
  };
35
36
 
36
37
  const LoginDialog = ({
@@ -38,22 +39,33 @@ const LoginDialog = ({
38
39
  onCancel,
39
40
  onLogin,
40
41
  onRegister,
42
+ hasDistinctSignUpFlow,
41
43
  }: LoginDialogProps) => (
42
44
  <Dialog open={open} onOpenChange={(nextOpen) => !nextOpen && onCancel()}>
43
45
  <DialogContent>
44
46
  <DialogHeader>
45
47
  <DialogTitle>Login to continue</DialogTitle>
46
48
  </DialogHeader>
47
- <DialogDescription>Please login to access this page.</DialogDescription>
49
+ <DialogDescription>
50
+ {hasDistinctSignUpFlow
51
+ ? "Please login to access this page."
52
+ : "You'll be redirected to sign in or create an account."}
53
+ </DialogDescription>
48
54
  <DialogFooter>
49
55
  <Button variant="outline" onClick={onCancel}>
50
56
  Cancel
51
57
  </Button>
52
58
  <div className="w-full" />
53
- <Button variant="secondary" onClick={onRegister}>
54
- Register
55
- </Button>
56
- <Button onClick={onLogin}>Login</Button>
59
+ {hasDistinctSignUpFlow ? (
60
+ <>
61
+ <Button variant="secondary" onClick={onRegister}>
62
+ Register
63
+ </Button>
64
+ <Button onClick={onLogin}>Login</Button>
65
+ </>
66
+ ) : (
67
+ <Button onClick={onLogin}>Continue</Button>
68
+ )}
57
69
  </DialogFooter>
58
70
  </DialogContent>
59
71
  </Dialog>
@@ -155,6 +167,41 @@ export const RouteGuard = () => {
155
167
  getAuthCheck,
156
168
  ]);
157
169
 
170
+ const needsAuth = needsToSignIn || isBlocked;
171
+ const redirectTo = isBlocked
172
+ ? blocker.location.pathname + blocker.location.search
173
+ : location.pathname + location.search;
174
+ const showDialog =
175
+ auth.isBackendAvailable &&
176
+ needsAuth &&
177
+ auth.hasDistinctSignUpFlow;
178
+ const unifiedRedirectKeyRef = useRef<string | null>(null);
179
+
180
+ useEffect(() => {
181
+ if (
182
+ !auth.isBackendAvailable ||
183
+ auth.isPending ||
184
+ !needsAuth ||
185
+ auth.hasDistinctSignUpFlow
186
+ ) {
187
+ unifiedRedirectKeyRef.current = null;
188
+ return;
189
+ }
190
+
191
+ if (unifiedRedirectKeyRef.current === redirectTo) {
192
+ return;
193
+ }
194
+
195
+ unifiedRedirectKeyRef.current = redirectTo;
196
+ void auth.login({ redirectTo });
197
+ }, [
198
+ auth.isBackendAvailable,
199
+ auth.isPending,
200
+ auth.hasDistinctSignUpFlow,
201
+ needsAuth,
202
+ redirectTo,
203
+ ]);
204
+
158
205
  if (isForbidden) {
159
206
  return <ForbiddenPage />;
160
207
  }
@@ -184,16 +231,12 @@ export const RouteGuard = () => {
184
231
  return <ProductionUnlockPage />;
185
232
  }
186
233
 
187
- const showDialog = auth.isBackendAvailable && (needsToSignIn || isBlocked);
188
- const redirectTo = isBlocked
189
- ? blocker.location.pathname + blocker.location.search
190
- : location.pathname + location.search;
191
-
192
234
  return (
193
235
  <>
194
236
  {!needsToSignIn && <Outlet />}
195
237
  <LoginDialog
196
238
  open={showDialog}
239
+ hasDistinctSignUpFlow={auth.hasDistinctSignUpFlow}
197
240
  onCancel={needsToSignIn ? () => navigate(-1) : () => blocker.reset?.()}
198
241
  onLogin={() => void auth.login({ redirectTo })}
199
242
  onRegister={() => void auth.signup({ redirectTo })}
@@ -15,8 +15,14 @@ export type PlaygroundDialogProps = PropsWithChildren<PlaygroundContentProps>;
15
15
 
16
16
  const PlaygroundDialog = (props: PlaygroundDialogProps) => {
17
17
  const [open, setOpen] = useState(false);
18
- const { isAuthEnabled, login, signup, isPending, isAuthenticated } =
19
- useAuth();
18
+ const {
19
+ isAuthEnabled,
20
+ login,
21
+ signup,
22
+ isPending,
23
+ isAuthenticated,
24
+ hasDistinctSignUpFlow,
25
+ } = useAuth();
20
26
 
21
27
  return (
22
28
  <Dialog onOpenChange={(open) => setOpen(open)}>
@@ -44,7 +50,7 @@ const PlaygroundDialog = (props: PlaygroundDialogProps) => {
44
50
  <Playground
45
51
  requiresLogin={isAuthEnabled && !isAuthenticated && !isPending}
46
52
  onLogin={() => login()}
47
- onSignUp={() => signup()}
53
+ onSignUp={hasDistinctSignUpFlow ? () => signup() : undefined}
48
54
  {...props}
49
55
  />
50
56
  )}