zudoku 0.3.1-dev.13 → 0.3.1-dev.14

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.
Files changed (70) hide show
  1. package/dist/lib/authentication/authentication.d.ts +1 -0
  2. package/dist/lib/authentication/components/CallbackHandler.d.ts +3 -0
  3. package/dist/lib/authentication/components/CallbackHandler.js +33 -0
  4. package/dist/lib/authentication/components/CallbackHandler.js.map +1 -0
  5. package/dist/lib/authentication/providers/openid.d.ts +3 -3
  6. package/dist/lib/authentication/providers/openid.js +20 -20
  7. package/dist/lib/authentication/providers/openid.js.map +1 -1
  8. package/dist/lib/components/Header.js +1 -1
  9. package/dist/lib/components/Header.js.map +1 -1
  10. package/dist/lib/components/Layout.js +5 -1
  11. package/dist/lib/components/Layout.js.map +1 -1
  12. package/dist/lib/components/context/ZudokuProvider.js +1 -3
  13. package/dist/lib/components/context/ZudokuProvider.js.map +1 -1
  14. package/dist/lib/core/DevPortalContext.d.ts +1 -4
  15. package/dist/lib/core/DevPortalContext.js +2 -2
  16. package/dist/lib/core/DevPortalContext.js.map +1 -1
  17. package/dist/lib/core/plugins.d.ts +2 -4
  18. package/dist/lib/core/plugins.js.map +1 -1
  19. package/lib/{AuthenticationPlugin-CH5NSVOu.js → AuthenticationPlugin-owbEUimP.js} +3 -3
  20. package/lib/{AuthenticationPlugin-CH5NSVOu.js.map → AuthenticationPlugin-owbEUimP.js.map} +1 -1
  21. package/lib/{CategoryHeading-z15xh7Jb.js → CategoryHeading-DnPprxtD.js} +2 -2
  22. package/lib/{CategoryHeading-z15xh7Jb.js.map → CategoryHeading-DnPprxtD.js.map} +1 -1
  23. package/lib/{Combination-DTfV-c98.js → Combination-DruV0zX_.js} +3 -3
  24. package/lib/{Combination-DTfV-c98.js.map → Combination-DruV0zX_.js.map} +1 -1
  25. package/lib/ErrorPage-PUg985n_.js +18 -0
  26. package/lib/ErrorPage-PUg985n_.js.map +1 -0
  27. package/lib/{Input-CzXNm7xb.js → Input-CBfi9Yjc.js} +4 -4
  28. package/lib/{Input-CzXNm7xb.js.map → Input-CBfi9Yjc.js.map} +1 -1
  29. package/lib/{Markdown-CEccPMI_.js → Markdown-Chb9VIBv.js} +2 -2
  30. package/lib/{Markdown-CEccPMI_.js.map → Markdown-Chb9VIBv.js.map} +1 -1
  31. package/lib/{MdxPage-CnqOoqvp.js → MdxPage-CIBHMwTd.js} +5 -5
  32. package/lib/{MdxPage-CnqOoqvp.js.map → MdxPage-CIBHMwTd.js.map} +1 -1
  33. package/lib/{OperationList-CYyaboNz.js → OperationList-BzC9sQKY.js} +23 -22
  34. package/lib/{OperationList-CYyaboNz.js.map → OperationList-BzC9sQKY.js.map} +1 -1
  35. package/lib/{Route-C3Jb0axy.js → Route-BGRXEhFQ.js} +3 -3
  36. package/lib/{Route-C3Jb0axy.js.map → Route-BGRXEhFQ.js.map} +1 -1
  37. package/lib/{SlotletProvider-ByLSCZQa.js → SlotletProvider-Dq80og6-.js} +4 -4
  38. package/lib/{SlotletProvider-ByLSCZQa.js.map → SlotletProvider-Dq80og6-.js.map} +1 -1
  39. package/lib/{Spinner-BT_AYFrA.js → Spinner-BxpiCVtl.js} +3 -3
  40. package/lib/{Spinner-BT_AYFrA.js.map → Spinner-BxpiCVtl.js.map} +1 -1
  41. package/lib/{ZudokuContext-BIZ8zHbZ.js → ZudokuContext-BQ45UjcB.js} +2 -2
  42. package/lib/{ZudokuContext-BIZ8zHbZ.js.map → ZudokuContext-BQ45UjcB.js.map} +1 -1
  43. package/lib/{index-Dz4LyXZI.js → index-CKQG-w6R.js} +3 -3
  44. package/lib/{index-Dz4LyXZI.js.map → index-CKQG-w6R.js.map} +1 -1
  45. package/lib/{index-B1he6g8N.js → index-DHMNxrEi.js} +453 -464
  46. package/lib/index-DHMNxrEi.js.map +1 -0
  47. package/lib/{index-7kcHaXD6.js → index-Yjb2PyPF.js} +4 -4
  48. package/lib/{index-7kcHaXD6.js.map → index-Yjb2PyPF.js.map} +1 -1
  49. package/lib/{utils-Bh4upQ0e.js → utils-pDHePxa0.js} +3 -3
  50. package/lib/{utils-Bh4upQ0e.js.map → utils-pDHePxa0.js.map} +1 -1
  51. package/lib/zudoku.auth-clerk.js +1 -1
  52. package/lib/zudoku.auth-openid.js +465 -413
  53. package/lib/zudoku.auth-openid.js.map +1 -1
  54. package/lib/zudoku.components.js +274 -277
  55. package/lib/zudoku.components.js.map +1 -1
  56. package/lib/zudoku.plugin-api-keys.js +6 -6
  57. package/lib/zudoku.plugin-custom-page.js +1 -1
  58. package/lib/zudoku.plugin-markdown.js +1 -1
  59. package/lib/zudoku.plugin-openapi.js +7 -6
  60. package/lib/zudoku.plugin-openapi.js.map +1 -1
  61. package/package.json +1 -1
  62. package/src/lib/authentication/authentication.ts +1 -0
  63. package/src/lib/authentication/components/CallbackHandler.tsx +54 -0
  64. package/src/lib/authentication/providers/openid.tsx +20 -24
  65. package/src/lib/components/Header.tsx +1 -2
  66. package/src/lib/components/Layout.tsx +6 -1
  67. package/src/lib/components/context/ZudokuProvider.tsx +1 -4
  68. package/src/lib/core/DevPortalContext.ts +2 -7
  69. package/src/lib/core/plugins.ts +1 -2
  70. package/lib/index-B1he6g8N.js.map +0 -1
@@ -1,12 +1,12 @@
1
1
  import { j as e } from "./jsx-runtime-B6kdoens.js";
2
- import { S as p, R as f } from "./SlotletProvider-ByLSCZQa.js";
3
- import { u as g, a as u, I as j, S as k, b as v, c as w, d as b, e as K, f as y } from "./Input-CzXNm7xb.js";
4
- import { b as N, L as x, O as E } from "./index-7kcHaXD6.js";
5
- import { u as h, t as A, j as S } from "./ZudokuContext-BIZ8zHbZ.js";
6
- import { B as l, p as I } from "./Combination-DTfV-c98.js";
2
+ import { S as p, R as f } from "./SlotletProvider-Dq80og6-.js";
3
+ import { u as g, a as u, I as j, S as k, b as v, c as w, d as b, e as K, f as y } from "./Input-CBfi9Yjc.js";
4
+ import { e as N, L as x, O as E } from "./index-Yjb2PyPF.js";
5
+ import { u as h, t as A, j as S } from "./ZudokuContext-BQ45UjcB.js";
6
+ import { B as l, p as I } from "./Combination-DruV0zX_.js";
7
7
  import { D as P } from "./DeveloperHint-BQSFXH01.js";
8
8
  import { useState as C } from "react";
9
- import { c as d, a as D } from "./Markdown-CEccPMI_.js";
9
+ import { c as d, a as D } from "./Markdown-Chb9VIBv.js";
10
10
  /**
11
11
  * @license lucide-react v0.378.0 - ISC
12
12
  *
@@ -1,5 +1,5 @@
1
1
  import { j as m } from "./jsx-runtime-B6kdoens.js";
2
- import { P as o } from "./Markdown-CEccPMI_.js";
2
+ import { P as o } from "./Markdown-Chb9VIBv.js";
3
3
  const l = (s) => ({
4
4
  getRoutes: () => s.map(({ path: e, element: t }) => ({
5
5
  path: e,
@@ -6,7 +6,7 @@ const u = (t, e) => Object.entries(t).flatMap(([a, r]) => {
6
6
  return {
7
7
  path: s.at(-1) === "index" ? s.slice(0, -1).join("/") : o,
8
8
  lazy: async () => {
9
- const { MdxPage: i } = await import("./MdxPage-CnqOoqvp.js"), { default: p, ...c } = await r();
9
+ const { MdxPage: i } = await import("./MdxPage-CIBHMwTd.js"), { default: p, ...c } = await r();
10
10
  return {
11
11
  element: /* @__PURE__ */ m.jsx(
12
12
  i,
@@ -1,14 +1,15 @@
1
1
  import "./jsx-runtime-B6kdoens.js";
2
- import { o as l } from "./index-B1he6g8N.js";
2
+ import { o as s } from "./index-DHMNxrEi.js";
3
3
  import "./urql-DrBfkb92.js";
4
- import "./ZudokuContext-BIZ8zHbZ.js";
4
+ import "./ZudokuContext-BQ45UjcB.js";
5
5
  import "zudoku/openapi-worker";
6
- import "./Combination-DTfV-c98.js";
7
- import "./Markdown-CEccPMI_.js";
6
+ import "./Combination-DruV0zX_.js";
7
+ import "./ErrorPage-PUg985n_.js";
8
+ import "./Markdown-Chb9VIBv.js";
8
9
  import "./joinPath-B7kNnUX4.js";
9
10
  import "./router-BiRCp01d.js";
10
- import "./index-7kcHaXD6.js";
11
+ import "./index-Yjb2PyPF.js";
11
12
  export {
12
- l as openApiPlugin
13
+ s as openApiPlugin
13
14
  };
14
15
  //# sourceMappingURL=zudoku.plugin-openapi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zudoku.plugin-openapi.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
1
+ {"version":3,"file":"zudoku.plugin-openapi.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.3.1-dev.13",
3
+ "version": "0.3.1-dev.14",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -5,6 +5,7 @@ export interface AuthenticationProvider {
5
5
  signIn(options?: { redirectTo?: string }): Promise<void>;
6
6
  signOut(): Promise<void>;
7
7
  getAccessToken(): Promise<string>;
8
+ pageLoad?(): void;
8
9
  getAuthenticationPlugin?(): DevPortalPlugin;
9
10
  }
10
11
 
@@ -0,0 +1,54 @@
1
+ import logger from "loglevel";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { useNavigate } from "react-router-dom";
4
+ import { DeveloperHint } from "../../components/DeveloperHint.js";
5
+ import { ErrorPage } from "../../components/ErrorPage.js";
6
+ import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
7
+
8
+ export function CallbackHandler({
9
+ handleCallback,
10
+ }: {
11
+ handleCallback: () => Promise<string>;
12
+ }) {
13
+ const [error, setError] = useState<Error | null>(null);
14
+ const navigate = useNavigate();
15
+ // Deal with double mount in dev mode which will break
16
+ // the OAuth flow because you can only use the code once
17
+ const didInitialize = useRef(false);
18
+
19
+ useEffect(() => {
20
+ if (didInitialize.current) {
21
+ return;
22
+ }
23
+ didInitialize.current = true;
24
+ handleCallback()
25
+ .then((redirect) => {
26
+ navigate(redirect);
27
+ })
28
+ .catch((err) => {
29
+ logger.error(err);
30
+ setError(err);
31
+ });
32
+ }, [navigate, handleCallback]);
33
+
34
+ if (error) {
35
+ return (
36
+ <ErrorPage
37
+ category="Error"
38
+ title="Authentication Error"
39
+ message={
40
+ <>
41
+ <DeveloperHint className="mb-4">
42
+ Check the configuration of your authorization provider and ensure
43
+ all settings such as the callback URL are configured correctly.
44
+ </DeveloperHint>
45
+ An error occurred while authorizing the user.
46
+ <SyntaxHighlight code={error.toString()} language="plain" />
47
+ </>
48
+ }
49
+ />
50
+ );
51
+ }
52
+
53
+ return <p>Loading...</p>;
54
+ }
@@ -1,13 +1,12 @@
1
1
  import logger from "loglevel";
2
2
  import * as oauth from "oauth4webapi";
3
- import { NavigateFunction } from "react-router-dom";
4
3
  import { OpenIDAuthenticationConfig } from "../../../config/config.js";
5
- import { CommonPlugin } from "../../core/plugins.js";
6
4
  import {
7
5
  AuthenticationProvider,
8
6
  AuthenticationProviderInitializer,
9
7
  } from "../authentication.js";
10
8
  import { AuthenticationPlugin } from "../AuthenticationPlugin.js";
9
+ import { CallbackHandler } from "../components/CallbackHandler.js";
11
10
  import { AuthorizationError, OAuthAuthorizationError } from "../errors.js";
12
11
  import { useAuthState, UserProfile } from "../state.js";
13
12
 
@@ -23,7 +22,7 @@ interface TokenState {
23
22
  class OpenIdAuthPlugin extends AuthenticationPlugin {
24
23
  constructor(
25
24
  private callbackUrlPath: string,
26
- public initialize?: CommonPlugin["initialize"],
25
+ private handleCallback: () => Promise<string>,
27
26
  ) {
28
27
  super();
29
28
  }
@@ -32,7 +31,7 @@ class OpenIdAuthPlugin extends AuthenticationPlugin {
32
31
  ...super.getRoutes(),
33
32
  {
34
33
  path: this.callbackUrlPath,
35
- element: <div />,
34
+ element: <CallbackHandler handleCallback={this.handleCallback} />,
36
35
  },
37
36
  ];
38
37
  }
@@ -279,9 +278,8 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
279
278
  // Authorization Code Grant Request & Response
280
279
  const codeVerifier = sessionStorage.getItem(CODE_VERIFIER_KEY);
281
280
  sessionStorage.removeItem(CODE_VERIFIER_KEY);
282
-
283
281
  if (!codeVerifier) {
284
- return "/";
282
+ throw new AuthorizationError("No code verifier found in state.");
285
283
  }
286
284
 
287
285
  const authServer = await this.getAuthServer();
@@ -320,7 +318,7 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
320
318
  // }
321
319
  // throw new Error(); // Handle WWW-Authenticate Challenges as needed
322
320
  // }
323
- const oauthResult = await oauth.processAuthorizationCodeOAuth2Response(
321
+ const oauthResult = await oauth.processAuthorizationCodeOpenIDResponse(
324
322
  authServer,
325
323
  this.client,
326
324
  response,
@@ -356,24 +354,22 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
356
354
  return sessionStorage.getItem("redirect-to") ?? "/";
357
355
  };
358
356
 
357
+ pageLoad(): void {
358
+ if (localStorage.getItem("auto-login")) {
359
+ localStorage.removeItem("auto-login");
360
+
361
+ // TODO: This needs to be cleaned up. We need to be able to return an
362
+ // error to the user if the authentication fails.
363
+ this.authorize({ redirectTo: window.location.pathname }).catch((err) => {
364
+ logger.error(err);
365
+ });
366
+ }
367
+ }
368
+
359
369
  getAuthenticationPlugin() {
360
- return new OpenIdAuthPlugin(
361
- this.callbackUrlPath,
362
- async (_, options: { navigate: NavigateFunction }) => {
363
- if (typeof window === "undefined") return;
364
-
365
- if (localStorage.getItem("auto-login")) {
366
- localStorage.removeItem("auto-login");
367
-
368
- await this.authorize({ redirectTo: window.location.pathname });
369
- } else if (window.location.pathname === "/oauth/callback") {
370
- const redirect = await this.handleCallback();
371
- if (redirect) {
372
- options.navigate(redirect);
373
- }
374
- }
375
- },
376
- );
370
+ // TODO: This API is a bit messy, we need to refactor auth plugins/providers
371
+ // to remove the extra layers of abstraction.
372
+ return new OpenIdAuthPlugin(this.callbackUrlPath, this.handleCallback);
377
373
  }
378
374
  }
379
375
 
@@ -1,6 +1,5 @@
1
1
  import { MoonStarIcon, SunIcon } from "lucide-react";
2
2
  import { memo } from "react";
3
-
4
3
  import { Link, useLocation } from "react-router-dom";
5
4
  import { useAuth } from "../authentication/hook.js";
6
5
  import { isProfileMenuPlugin, ProfileNavigationItem } from "../core/plugins.js";
@@ -98,7 +97,7 @@ export const Header = memo(function HeaderInner() {
98
97
  <div className="items-center justify-self-end text-sm hidden lg:flex gap-2">
99
98
  <Slotlet name="head-navigation-start" />
100
99
  {isAuthEnabled && !isAuthenticated ? (
101
- <Button onClick={() => auth.login()} asChild>
100
+ <Button variant="ghost" onClick={() => auth.login()}>
102
101
  Login
103
102
  </Button>
104
103
  ) : (
@@ -14,13 +14,18 @@ import { Spinner } from "./Spinner.js";
14
14
  export const Layout = ({ children }: { children?: ReactNode }) => {
15
15
  const location = useLocation();
16
16
  const { setActiveAnchor } = useViewportAnchor();
17
- const { meta } = useZudoku();
17
+ const { meta, authentication } = useZudoku();
18
18
 
19
19
  useScrollToAnchor();
20
20
  useScrollToTop();
21
21
 
22
22
  const previousLocationPath = useRef(location.pathname);
23
23
 
24
+ useEffect(() => {
25
+ // Initialize the authentication plugin
26
+ authentication?.pageLoad ? authentication.pageLoad() : null;
27
+ }, [authentication]);
28
+
24
29
  useEffect(() => {
25
30
  // always reset on location change
26
31
  if (location.pathname !== previousLocationPath.current) {
@@ -1,6 +1,5 @@
1
1
  import { useSuspenseQuery } from "@tanstack/react-query";
2
2
  import type { PropsWithChildren } from "react";
3
- import { useNavigate } from "react-router-dom";
4
3
  import { DevPortalContext } from "../../core/DevPortalContext.js";
5
4
  import { ZudokuReactContext } from "./ZudokuContext.js";
6
5
 
@@ -8,11 +7,9 @@ export const ZudokuProvider = ({
8
7
  children,
9
8
  context,
10
9
  }: PropsWithChildren<{ context: DevPortalContext }>) => {
11
- const navigate = useNavigate();
12
-
13
10
  useSuspenseQuery({
14
11
  queryFn: async () => {
15
- await context.initialize({ navigate });
12
+ await context.initialize();
16
13
  return true;
17
14
  },
18
15
  queryKey: ["zudoku-initialize"],
@@ -1,5 +1,4 @@
1
1
  import { QueryClient } from "@tanstack/react-query";
2
- import { NavigateFunction } from "react-router-dom";
3
2
  import type { SidebarConfig } from "../../config/validators/SidebarSchema.js";
4
3
  import { type AuthenticationProvider } from "../authentication/authentication.js";
5
4
  import type { ComponentsContextType } from "../components/context/ComponentsContext.js";
@@ -84,15 +83,11 @@ export class DevPortalContext {
84
83
  this.page = config.page;
85
84
  }
86
85
 
87
- initialize = async ({
88
- navigate,
89
- }: {
90
- navigate: NavigateFunction;
91
- }): Promise<void> => {
86
+ initialize = async (): Promise<void> => {
92
87
  await Promise.all(
93
88
  this.plugins
94
89
  .filter(needsInitialization)
95
- .map((plugin) => plugin.initialize?.(this, { navigate })),
90
+ .map((plugin) => plugin.initialize?.(this)),
96
91
  );
97
92
  };
98
93
 
@@ -1,5 +1,5 @@
1
1
  import { type ReactElement } from "react";
2
- import { NavigateFunction, type RouteObject } from "react-router-dom";
2
+ import { type RouteObject } from "react-router-dom";
3
3
  import type { Sidebar } from "../../config/validators/SidebarSchema.js";
4
4
  import { MdxComponentsType } from "../util/MdxComponents.js";
5
5
  import { DevPortalContext, type ApiIdentity } from "./DevPortalContext.js";
@@ -40,7 +40,6 @@ export type ProfileNavigationItem = {
40
40
  export interface CommonPlugin {
41
41
  initialize?: (
42
42
  context: DevPortalContext,
43
- options: { navigate: NavigateFunction },
44
43
  ) => Promise<void | boolean> | void | boolean;
45
44
  getHead?: () => ReactElement | undefined;
46
45
  getMdxComponents?: () => MdxComponentsType;