zudoku 0.3.0-dev.4 → 0.3.0-dev.6

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 (62) hide show
  1. package/dist/app/App.js +2 -1
  2. package/dist/app/App.js.map +1 -1
  3. package/dist/lib/authentication/hook.d.ts +1 -0
  4. package/dist/lib/authentication/hook.js +1 -0
  5. package/dist/lib/authentication/hook.js.map +1 -1
  6. package/dist/lib/authentication/providers/auth0.js +1 -0
  7. package/dist/lib/authentication/providers/auth0.js.map +1 -1
  8. package/dist/lib/authentication/providers/clerk.js +2 -0
  9. package/dist/lib/authentication/providers/clerk.js.map +1 -1
  10. package/dist/lib/authentication/providers/openid.js +2 -0
  11. package/dist/lib/authentication/providers/openid.js.map +1 -1
  12. package/dist/lib/authentication/state.d.ts +1 -0
  13. package/dist/lib/authentication/state.js +1 -0
  14. package/dist/lib/authentication/state.js.map +1 -1
  15. package/dist/lib/components/DevPortal.js +0 -1
  16. package/dist/lib/components/DevPortal.js.map +1 -1
  17. package/dist/lib/components/Layout.js +1 -1
  18. package/dist/lib/components/Layout.js.map +1 -1
  19. package/dist/lib/components/SyntaxHighlight.js +1 -1
  20. package/dist/lib/components/SyntaxHighlight.js.map +1 -1
  21. package/dist/lib/core/DevPortalContext.js +5 -4
  22. package/dist/lib/core/DevPortalContext.js.map +1 -1
  23. package/dist/lib/plugins/api-key/CreateApiKey.d.ts +2 -3
  24. package/dist/lib/plugins/api-key/CreateApiKey.js +1 -1
  25. package/dist/lib/plugins/api-key/CreateApiKey.js.map +1 -1
  26. package/dist/lib/plugins/api-key/SettingsApiKeys.d.ts +2 -3
  27. package/dist/lib/plugins/api-key/SettingsApiKeys.js +8 -8
  28. package/dist/lib/plugins/api-key/SettingsApiKeys.js.map +1 -1
  29. package/dist/lib/plugins/api-key/index.js +36 -9
  30. package/dist/lib/plugins/api-key/index.js.map +1 -1
  31. package/dist/lib/plugins/markdown/MdxPage.js +1 -1
  32. package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
  33. package/dist/vite/config.test.js +1 -1
  34. package/dist/vite/config.test.js.map +1 -1
  35. package/dist/vite/plugin-docs.test.js +1 -1
  36. package/dist/vite/plugin-docs.test.js.map +1 -1
  37. package/lib/{Spinner-7LezPqGn.js → Spinner-BINYpvLB.js} +568 -549
  38. package/lib/{index-DNx3xWa2.js → index-PyGcnQFX.js} +13 -12
  39. package/lib/loglevel-CoH7VSwE.js +152 -0
  40. package/lib/state-2Hu1renZ.js +313 -0
  41. package/lib/zudoku.auth-auth0.js +2 -1
  42. package/lib/zudoku.auth-clerk.js +9 -7
  43. package/lib/zudoku.auth-openid.js +442 -588
  44. package/lib/zudoku.components.js +135 -151
  45. package/lib/zudoku.plugins.js +2829 -2800
  46. package/package.json +2 -1
  47. package/src/app/App.tsx +2 -1
  48. package/src/lib/authentication/hook.ts +1 -0
  49. package/src/lib/authentication/providers/auth0.tsx +1 -0
  50. package/src/lib/authentication/providers/clerk.tsx +2 -0
  51. package/src/lib/authentication/providers/openid.tsx +2 -0
  52. package/src/lib/authentication/state.ts +2 -0
  53. package/src/lib/components/DevPortal.tsx +0 -1
  54. package/src/lib/components/Layout.tsx +1 -1
  55. package/src/lib/components/SyntaxHighlight.tsx +1 -1
  56. package/src/lib/core/DevPortalContext.ts +5 -4
  57. package/src/lib/plugins/api-key/CreateApiKey.tsx +2 -8
  58. package/src/lib/plugins/api-key/SettingsApiKeys.tsx +50 -58
  59. package/src/lib/plugins/api-key/index.tsx +53 -8
  60. package/src/lib/plugins/markdown/MdxPage.tsx +1 -1
  61. package/lib/_commonjsHelpers-BkfeUUK-.js +0 -28
  62. package/lib/state-oycsxkHz.js +0 -287
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.3.0-dev.4",
3
+ "version": "0.3.0-dev.6",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -100,6 +100,7 @@
100
100
  "slugify": "1.6.6",
101
101
  "strip-ansi": "7.1.0",
102
102
  "tailwindcss": "3.4.4",
103
+ "tiny-invariant": "1.3.3",
103
104
  "ulidx": "^2.3.0",
104
105
  "unist-util-visit": "5.0.0",
105
106
  "urql": "4.1.0",
package/src/app/App.tsx CHANGED
@@ -32,8 +32,9 @@ export default function App() {
32
32
  plugins={[
33
33
  ...configuredDocsPlugins,
34
34
  ...configuredApiPlugins,
35
- configuredApiKeysPlugin,
36
35
  configuredRedirectPlugin,
36
+ ...(configuredApiKeysPlugin ? [configuredApiKeysPlugin] : []),
37
+ ...(configuredAuthProvider ? [configuredAuthProvider] : []),
37
38
  ]}
38
39
  />
39
40
  );
@@ -8,6 +8,7 @@ export const useAuth = () => {
8
8
 
9
9
  return {
10
10
  isAuthEnabled,
11
+ isPending: authState.isPending,
11
12
  profile: authState.profile,
12
13
  isAuthenticated: authState.profile,
13
14
 
@@ -7,6 +7,7 @@ class Auth0AuthenticationProvider extends OpenIDAuthenticationProvider {
7
7
  override async logout(): Promise<void> {
8
8
  useAuthState.setState({
9
9
  isAuthenticated: false,
10
+ isPending: false,
10
11
  profile: undefined,
11
12
  });
12
13
  const as = await this.getAuthServer();
@@ -34,6 +34,7 @@ const clerkAuth: AuthenticationProviderInitializer<
34
34
  if (clerkApi.session) {
35
35
  useAuthState.setState({
36
36
  isAuthenticated: true,
37
+ isPending: false,
37
38
  profile: {
38
39
  sub: clerkApi.session.user.id,
39
40
  name: clerkApi.session.user.fullName ?? undefined,
@@ -46,6 +47,7 @@ const clerkAuth: AuthenticationProviderInitializer<
46
47
  } else {
47
48
  useAuthState.setState({
48
49
  isAuthenticated: false,
50
+ isPending: false,
49
51
  profile: undefined,
50
52
  });
51
53
  }
@@ -180,6 +180,7 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
180
180
  async logout(): Promise<void> {
181
181
  useAuthState.setState({
182
182
  isAuthenticated: false,
183
+ isPending: false,
183
184
  profile: undefined,
184
185
  });
185
186
 
@@ -293,6 +294,7 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
293
294
 
294
295
  useAuthState.setState({
295
296
  isAuthenticated: true,
297
+ isPending: false,
296
298
  profile,
297
299
  });
298
300
 
@@ -1,11 +1,13 @@
1
1
  import { create } from "zustand";
2
2
 
3
3
  export const useAuthState = create<AuthState>(() => ({
4
+ isPending: true,
4
5
  isAuthenticated: false,
5
6
  }));
6
7
 
7
8
  export interface AuthState {
8
9
  isAuthenticated: boolean;
10
+ isPending: boolean;
9
11
  profile?: UserProfile;
10
12
  }
11
13
 
@@ -1,4 +1,3 @@
1
- /* eslint-disable react/destructuring-assignment */
2
1
  import { MDXProvider } from "@mdx-js/react";
3
2
  import { QueryClientProvider } from "@tanstack/react-query";
4
3
  import { memo, Suspense, useEffect, useMemo } from "react";
@@ -48,7 +48,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
48
48
  >
49
49
  <SideNavigation />
50
50
  <main
51
- className="dark:border-white/10 translate-x-0
51
+ className="dark:border-white/10 translate-x-0 h-full
52
52
  lg:overflow-visible
53
53
  lg:peer-data-[navigation=true]:w-[calc(100%-var(--side-nav-width))]
54
54
  lg:peer-data-[navigation=true]:translate-x-[--side-nav-width] peer-data-[navigation=true]:pl-12"
@@ -67,7 +67,7 @@ export const SyntaxHighlight = ({
67
67
  disabled={isCopied}
68
68
  onClick={() => {
69
69
  setIsCopied(true);
70
- navigator.clipboard.writeText(
70
+ void navigator.clipboard.writeText(
71
71
  tokens
72
72
  .map((line) => line.map(({ content }) => content).join(""))
73
73
  .join("\n"),
@@ -85,10 +85,11 @@ export class DevPortalContext {
85
85
  }
86
86
 
87
87
  initialize = async () => {
88
- this.plugins
89
- .filter(needsInitialization)
90
- .forEach((plugin) => plugin.initialize(this));
91
- this.authentication?.initialize(this);
88
+ await Promise.all([
89
+ this.plugins
90
+ .filter(needsInitialization)
91
+ .map((plugin) => plugin.initialize(this)),
92
+ ]);
92
93
  };
93
94
 
94
95
  invalidateCache = async (key: DevPortalCacheKey[]) => {
@@ -12,17 +12,11 @@ import {
12
12
  SelectValue,
13
13
  } from "../../components/Select.js";
14
14
  import { Button } from "../../ui/Button.js";
15
- import { type ApiKeyPluginOptions, ApiKeyService } from "./index.js";
15
+ import { ApiKeyService } from "./index.js";
16
16
 
17
17
  type CreateApiKey = { description: string; expiresOn?: string };
18
18
 
19
- export const CreateApiKey = ({
20
- options,
21
- service,
22
- }: {
23
- options: ApiKeyPluginOptions;
24
- service: ApiKeyService;
25
- }) => {
19
+ export const CreateApiKey = ({ service }: { service: ApiKeyService }) => {
26
20
  const context = useDevPortal();
27
21
  const navigate = useNavigate();
28
22
  const form = useForm<CreateApiKey>({
@@ -8,21 +8,15 @@ import { useState } from "react";
8
8
  import { Link } from "react-router-dom";
9
9
  import { useDevPortal } from "../../components/context/DevPortalProvider.js";
10
10
  import { Button } from "../../ui/Button.js";
11
- import { Card } from "../../ui/Card.js";
12
- import { type ApiKeyPluginOptions, ApiKeyService } from "./index.js";
11
+ import { ApiKeyService } from "./index.js";
13
12
 
14
- export const SettingsApiKeys = ({
15
- options,
16
- service,
17
- }: {
18
- options: ApiKeyPluginOptions;
19
- service: ApiKeyService;
20
- }) => {
13
+ export const SettingsApiKeys = ({ service }: { service: ApiKeyService }) => {
21
14
  const context = useDevPortal();
22
15
  const queryClient = useQueryClient();
23
16
  const { data } = useSuspenseQuery({
24
17
  queryFn: () => service.getKeys(context),
25
18
  queryKey: ["api-keys"],
19
+ retry: false,
26
20
  });
27
21
 
28
22
  const deleteKeyMutation = useMutation({
@@ -49,58 +43,56 @@ export const SettingsApiKeys = ({
49
43
  )}
50
44
  </div>
51
45
 
52
- <Card>
53
- <ul className="grid grid-cols-[min-content_1fr_min-content] ">
54
- {data.map((key) => (
55
- <li
56
- className="border-b border-border p-5 grid grid-cols-subgrid col-span-full gap-2 items-center"
57
- key={key.id}
58
- >
59
- <div className="flex flex-col gap-1 text-sm">
60
- {key.description ?? key.id}
61
- <div className="text-muted-foreground text-xs">
62
- {key.createdOn && (
63
- <div>
64
- Created on {new Date(key.createdOn).toLocaleDateString()}
65
- </div>
66
- )}
67
- {key.expiresOn && (
68
- <div>
69
- Expires on {new Date(key.expiresOn).toLocaleDateString()}
70
- </div>
71
- )}
72
- </div>
73
- </div>
74
- <div className="items-center flex justify-center">
75
- <RevealApiKey apiKey={key.key} />
76
- </div>
77
- <div className="flex gap-2">
78
- {service.rollKey && (
79
- <Button size="icon">
80
- <RotateCwIcon size={16} />
81
- </Button>
46
+ <ul className="grid grid-cols-[min-content_1fr_min-content] ">
47
+ {data.map((key) => (
48
+ <li
49
+ className="border-b border-border p-5 grid grid-cols-subgrid col-span-full gap-2 items-center"
50
+ key={key.id}
51
+ >
52
+ <div className="flex flex-col gap-1 text-sm">
53
+ {key.description ?? key.id}
54
+ <div className="text-muted-foreground text-xs">
55
+ {key.createdOn && (
56
+ <div>
57
+ Created on {new Date(key.createdOn).toLocaleDateString()}
58
+ </div>
82
59
  )}
83
- {service.deleteKey && (
84
- <Button
85
- variant="ghost"
86
- size="icon"
87
- onClick={() => {
88
- if (!confirm("Do you want to delete this key?")) {
89
- return;
90
- }
91
-
92
- deleteKeyMutation.mutate(key.id);
93
- }}
94
- disabled={deleteKeyMutation.isPending}
95
- >
96
- <TrashIcon size={16} />
97
- </Button>
60
+ {key.expiresOn && (
61
+ <div>
62
+ Expires on {new Date(key.expiresOn).toLocaleDateString()}
63
+ </div>
98
64
  )}
99
65
  </div>
100
- </li>
101
- ))}
102
- </ul>
103
- </Card>
66
+ </div>
67
+ <div className="items-center flex justify-center">
68
+ <RevealApiKey apiKey={key.key} />
69
+ </div>
70
+ <div className="flex gap-2">
71
+ {service.rollKey && (
72
+ <Button size="icon">
73
+ <RotateCwIcon size={16} />
74
+ </Button>
75
+ )}
76
+ {service.deleteKey && (
77
+ <Button
78
+ variant="ghost"
79
+ size="icon"
80
+ onClick={() => {
81
+ if (!confirm("Do you want to delete this key?")) {
82
+ return;
83
+ }
84
+
85
+ deleteKeyMutation.mutate(key.id);
86
+ }}
87
+ disabled={deleteKeyMutation.isPending}
88
+ >
89
+ <TrashIcon size={16} />
90
+ </Button>
91
+ )}
92
+ </div>
93
+ </li>
94
+ ))}
95
+ </ul>
104
96
  </div>
105
97
  );
106
98
  };
@@ -1,8 +1,13 @@
1
+ import logger from "loglevel";
2
+ import { Outlet, useRouteError } from "react-router-dom";
3
+ import invariant from "tiny-invariant";
4
+ import { useAuth } from "../../authentication/hook.js";
1
5
  import { DevPortalContext } from "../../core/DevPortalContext.js";
2
6
  import {
3
7
  type ApiIdentityPlugin,
4
8
  type DevPortalPlugin,
5
9
  } from "../../core/plugins.js";
10
+ import { Button } from "../../ui/Button.js";
6
11
  import { CreateApiKey } from "./CreateApiKey.js";
7
12
  import { SettingsApiKeys } from "./SettingsApiKeys.js";
8
13
 
@@ -47,7 +52,8 @@ const createDefaultHandler = (endpoint: string): ApiKeyService => {
47
52
 
48
53
  await context.signRequest(request);
49
54
 
50
- await fetch(request);
55
+ const response = await fetch(request);
56
+ invariant(response.ok, "Failed to delete API key");
51
57
  },
52
58
  createKey: async (apiKey, context) => {
53
59
  const request = new Request(endpoint + `/v1/developer/api-keys`, {
@@ -59,7 +65,9 @@ const createDefaultHandler = (endpoint: string): ApiKeyService => {
59
65
  });
60
66
 
61
67
  await context.signRequest(request);
62
- await fetch(request);
68
+
69
+ const response = await fetch(request);
70
+ invariant(response.ok, "Failed to create API key");
63
71
  },
64
72
  getKeys: async (context) => {
65
73
  const request = new Request(endpoint + `/v1/developer/api-keys`);
@@ -67,12 +75,43 @@ const createDefaultHandler = (endpoint: string): ApiKeyService => {
67
75
  await context.signRequest(request);
68
76
 
69
77
  const keys = await fetch(request);
78
+ invariant(keys.ok, "Failed to fetch API keys");
70
79
 
71
80
  return await keys.json();
72
81
  },
73
82
  };
74
83
  };
75
84
 
85
+ const ProtectedRoute = () => {
86
+ const auth = useAuth();
87
+
88
+ // TODO: should we suspend here somehow?
89
+ if (auth.isPending) {
90
+ return null;
91
+ }
92
+
93
+ return auth.isAuthenticated ? (
94
+ <Outlet />
95
+ ) : (
96
+ <div className="flex flex-col justify-center gap-2 items-center h-1/2 my-12">
97
+ Please login first to view this page
98
+ <Button onClick={() => auth.login()}>Login</Button>
99
+ </div>
100
+ );
101
+ };
102
+
103
+ const SettingsErrorBoundary = () => {
104
+ const error = useRouteError();
105
+ logger.error(String(error));
106
+
107
+ return (
108
+ <div className="flex flex-col justify-center gap-2 items-center h-1/2 my-12">
109
+ <h1>Something went wrong</h1>
110
+ {error instanceof Error && <p>{error.message}</p>}
111
+ </div>
112
+ );
113
+ };
114
+
76
115
  export const apiKeyPlugin = (
77
116
  options: ApiKeyPluginOptions,
78
117
  ): DevPortalPlugin & ApiIdentityPlugin => {
@@ -102,12 +141,18 @@ export const apiKeyPlugin = (
102
141
  getRoutes: () => {
103
142
  return [
104
143
  {
105
- path: "/settings/api-keys",
106
- element: <SettingsApiKeys options={options} service={service} />,
107
- },
108
- {
109
- path: "/settings/api-keys/new",
110
- element: <CreateApiKey options={options} service={service} />,
144
+ element: <ProtectedRoute />,
145
+ errorElement: <SettingsErrorBoundary />,
146
+ children: [
147
+ {
148
+ path: "/settings/api-keys",
149
+ element: <SettingsApiKeys service={service} />,
150
+ },
151
+ {
152
+ path: "/settings/api-keys/new",
153
+ element: <CreateApiKey service={service} />,
154
+ },
155
+ ],
111
156
  },
112
157
  ];
113
158
  },
@@ -30,7 +30,7 @@ const MarkdownHeadings = {
30
30
 
31
31
  export const MdxPage = ({
32
32
  mdxComponent: MdxComponent,
33
- frontmatter,
33
+ frontmatter = {},
34
34
  tableOfContents,
35
35
  }: PropsWithChildren<
36
36
  Omit<MDXImport, "default"> & {
@@ -1,28 +0,0 @@
1
- var u = typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : typeof global < "u" ? global : typeof self < "u" ? self : {};
2
- function f(e) {
3
- return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
4
- }
5
- function l(e) {
6
- if (e.__esModule) return e;
7
- var r = e.default;
8
- if (typeof r == "function") {
9
- var t = function o() {
10
- return this instanceof o ? Reflect.construct(r, arguments, this.constructor) : r.apply(this, arguments);
11
- };
12
- t.prototype = r.prototype;
13
- } else t = {};
14
- return Object.defineProperty(t, "__esModule", { value: !0 }), Object.keys(e).forEach(function(o) {
15
- var n = Object.getOwnPropertyDescriptor(e, o);
16
- Object.defineProperty(t, o, n.get ? n : {
17
- enumerable: !0,
18
- get: function() {
19
- return e[o];
20
- }
21
- });
22
- }), t;
23
- }
24
- export {
25
- l as a,
26
- u as c,
27
- f as g
28
- };