zudoku 0.66.4 → 0.66.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.
- package/dist/app/main.d.ts +6 -6
- package/dist/config/validators/InputNavigationSchema.d.ts +2 -0
- package/dist/config/validators/InputNavigationSchema.js +1 -0
- package/dist/config/validators/InputNavigationSchema.js.map +1 -1
- package/dist/config/validators/NavigationSchema.js +6 -1
- package/dist/config/validators/NavigationSchema.js.map +1 -1
- package/dist/flat-config.d.ts +1 -0
- package/dist/lib/authentication/components/CallbackHandler.js +1 -1
- package/dist/lib/authentication/components/CallbackHandler.js.map +1 -1
- package/dist/lib/authentication/providers/auth0.js +11 -7
- package/dist/lib/authentication/providers/auth0.js.map +1 -1
- package/dist/lib/authentication/providers/clerk.js +0 -22
- package/dist/lib/authentication/providers/clerk.js.map +1 -1
- package/dist/lib/authentication/providers/supabase.js +6 -15
- package/dist/lib/authentication/providers/supabase.js.map +1 -1
- package/dist/lib/core/RouteGuard.js +12 -7
- package/dist/lib/core/RouteGuard.js.map +1 -1
- package/dist/lib/oas/graphql/circular.d.ts +1 -0
- package/dist/lib/oas/graphql/circular.js +20 -5
- package/dist/lib/oas/graphql/circular.js.map +1 -1
- package/dist/lib/plugins/api-keys/index.d.ts +9 -5
- package/dist/lib/plugins/api-keys/index.js +18 -8
- package/dist/lib/plugins/api-keys/index.js.map +1 -1
- package/dist/lib/plugins/api-keys/settings/ApiKeyList.js +3 -0
- package/dist/lib/plugins/api-keys/settings/ApiKeyList.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationList.js +5 -1
- package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
- package/dist/lib/plugins/openapi/schema/utils.js +11 -3
- package/dist/lib/plugins/openapi/schema/utils.js.map +1 -1
- package/dist/lib/util/invariant.d.ts +1 -1
- package/dist/lib/util/invariant.js +2 -2
- package/dist/lib/util/invariant.js.map +1 -1
- package/dist/vite/api/SchemaManager.d.ts +1 -0
- package/dist/vite/api/SchemaManager.js +9 -3
- package/dist/vite/api/SchemaManager.js.map +1 -1
- package/dist/vite/mdx/remark-link-rewrite.js +1 -1
- package/dist/vite/plugin-api-keys.js +1 -0
- package/dist/vite/plugin-api-keys.js.map +1 -1
- package/dist/vite/prerender/utils.js +9 -3
- package/dist/vite/prerender/utils.js.map +1 -1
- package/lib/{ActionButton-BSM2oNHF.js → ActionButton-B0CXL1Lq.js} +3 -3
- package/lib/{ActionButton-BSM2oNHF.js.map → ActionButton-B0CXL1Lq.js.map} +1 -1
- package/lib/{Button-IOAeVaIH.js → Button-GUVe7pmt.js} +2 -2
- package/lib/{Button-IOAeVaIH.js.map → Button-GUVe7pmt.js.map} +1 -1
- package/lib/{Card-KFniaZn5.js → Card-DCdq37aA.js} +2 -2
- package/lib/{Card-KFniaZn5.js.map → Card-DCdq37aA.js.map} +1 -1
- package/lib/{ClaudeLogo-DgjivS8A.js → ClaudeLogo-BpqHBMS8.js} +4 -4
- package/lib/{ClaudeLogo-DgjivS8A.js.map → ClaudeLogo-BpqHBMS8.js.map} +1 -1
- package/lib/{Command-BpT1iBE6.js → Command-N6VujV30.js} +3 -3
- package/lib/{Command-BpT1iBE6.js.map → Command-N6VujV30.js.map} +1 -1
- package/lib/{Dialog-BQciPiHN.js → Dialog-hlvmmQ_c.js} +2 -2
- package/lib/{Dialog-BQciPiHN.js.map → Dialog-hlvmmQ_c.js.map} +1 -1
- package/lib/{Drawer-BRMcpfuF.js → Drawer-Ch7927PF.js} +2 -2
- package/lib/{Drawer-BRMcpfuF.js.map → Drawer-Ch7927PF.js.map} +1 -1
- package/lib/{DropdownMenu-C8SX_-S_.js → DropdownMenu-DN0jNrjj.js} +2 -2
- package/lib/{DropdownMenu-C8SX_-S_.js.map → DropdownMenu-DN0jNrjj.js.map} +1 -1
- package/lib/{Frame-DxlznfVd.js → Frame-DKlOmSkU.js} +2 -2
- package/lib/{Frame-DxlznfVd.js.map → Frame-DKlOmSkU.js.map} +1 -1
- package/lib/{IndexingDialog-DZWj_3cU.js → IndexingDialog-D0YdGfbn.js} +3 -3
- package/lib/{IndexingDialog-DZWj_3cU.js.map → IndexingDialog-D0YdGfbn.js.map} +1 -1
- package/lib/{Input-D-kqEQ5M.js → Input-B6YcAPv-.js} +39 -18
- package/lib/Input-B6YcAPv-.js.map +1 -0
- package/lib/{MdxPage-BL-HbZrv.js → MdxPage-CeFSxGb_.js} +11 -11
- package/lib/{MdxPage-BL-HbZrv.js.map → MdxPage-CeFSxGb_.js.map} +1 -1
- package/lib/{Mermaid-BjSczjLW.js → Mermaid-COVtAqcZ.js} +4 -4
- package/lib/{Mermaid-BjSczjLW.js.map → Mermaid-COVtAqcZ.js.map} +1 -1
- package/lib/{OAuthErrorPage-DQtg28Go.js → OAuthErrorPage-XTPBOMN8.js} +9 -9
- package/lib/OAuthErrorPage-XTPBOMN8.js.map +1 -0
- package/lib/{OasProvider--qcZwrKS.js → OasProvider-BS4rdzZC.js} +4 -4
- package/lib/{OasProvider--qcZwrKS.js.map → OasProvider-BS4rdzZC.js.map} +1 -1
- package/lib/{OperationList-CSJYzxQY.js → OperationList-Dg0Nm1tg.js} +136 -133
- package/lib/{OperationList-CSJYzxQY.js.map → OperationList-Dg0Nm1tg.js.map} +1 -1
- package/lib/RouteGuard-kCicqF3x.js +77 -0
- package/lib/RouteGuard-kCicqF3x.js.map +1 -0
- package/lib/{SchemaList-DtyuDrQA.js → SchemaList-DZKBH2WC.js} +9 -9
- package/lib/{SchemaList-DtyuDrQA.js.map → SchemaList-DZKBH2WC.js.map} +1 -1
- package/lib/{SchemaView-G-SVXxAG.js → SchemaView-DBaqV2yU.js} +95 -92
- package/lib/SchemaView-DBaqV2yU.js.map +1 -0
- package/lib/{Secret-BxGpIhDP.js → Secret-BDBqq4p3.js} +2 -2
- package/lib/{Secret-BxGpIhDP.js.map → Secret-BDBqq4p3.js.map} +1 -1
- package/lib/{Separator-CTPSeW1S.js → Separator-BXt1LYnm.js} +2 -2
- package/lib/{Separator-CTPSeW1S.js.map → Separator-BXt1LYnm.js.map} +1 -1
- package/lib/{SignUp-CDl7bQj3.js → SignUp-DNmOFbLD.js} +5 -5
- package/lib/{SignUp-CDl7bQj3.js.map → SignUp-DNmOFbLD.js.map} +1 -1
- package/lib/{SyntaxHighlight-Dgd0AaaX.js → SyntaxHighlight-C75W8uCn.js} +374 -365
- package/lib/SyntaxHighlight-C75W8uCn.js.map +1 -0
- package/lib/{Toc-D_Rj4jVx.js → Toc-ICilS65g.js} +3 -3
- package/lib/{Toc-D_Rj4jVx.js.map → Toc-ICilS65g.js.map} +1 -1
- package/lib/{ZudokuContext-DNHMZfcP.js → ZudokuContext-Ea7gxmGq.js} +542 -469
- package/lib/ZudokuContext-Ea7gxmGq.js.map +1 -0
- package/lib/{___vite-browser-external_commonjs-proxy-Cga3HsWk.js → ___vite-browser-external_commonjs-proxy-BttVsNON.js} +2 -2
- package/lib/___vite-browser-external_commonjs-proxy-BttVsNON.js.map +1 -0
- package/lib/chunk-EPOLDU6W-C6C8jAwd.js +8558 -0
- package/lib/chunk-EPOLDU6W-C6C8jAwd.js.map +1 -0
- package/lib/{circular-BxODTa7z.js → circular-DleWPaPP.js} +767 -747
- package/lib/{circular-BxODTa7z.js.map → circular-DleWPaPP.js.map} +1 -1
- package/lib/{cn-dYga0KKN.js → cn-5-Gd1Dss.js} +531 -498
- package/lib/cn-5-Gd1Dss.js.map +1 -0
- package/lib/{createServer-BpreIXp6.js → createServer-nqMW9kro.js} +6 -6
- package/lib/{createServer-BpreIXp6.js.map → createServer-nqMW9kro.js.map} +1 -1
- package/lib/{createVariantComponent-CQVt-H3r.js → createVariantComponent-Dc0vtOvr.js} +2 -2
- package/lib/{createVariantComponent-CQVt-H3r.js.map → createVariantComponent-Dc0vtOvr.js.map} +1 -1
- package/lib/{errors-DliW1dED.js → errors-D2FbERKl.js} +3 -3
- package/lib/{errors-DliW1dED.js.map → errors-D2FbERKl.js.map} +1 -1
- package/lib/{firebase-D4tbaCYB.js → firebase-Cn9CmB6h.js} +21 -21
- package/lib/{firebase-D4tbaCYB.js.map → firebase-Cn9CmB6h.js.map} +1 -1
- package/lib/{hook-CHw_R_xu.js → hook-B2nmfmYN.js} +3 -3
- package/lib/{hook-CHw_R_xu.js.map → hook-B2nmfmYN.js.map} +1 -1
- package/lib/{index-DXXZDuSJ.js → index-CC4L3gtM.js} +4 -4
- package/lib/{index-DXXZDuSJ.js.map → index-CC4L3gtM.js.map} +1 -1
- package/lib/{index-9MxNUgg4.js → index-CSDW7CHl.js} +21 -21
- package/lib/{index-9MxNUgg4.js.map → index-CSDW7CHl.js.map} +1 -1
- package/lib/{index-CboxZOVW.js → index-D5NeW2z6.js} +12 -12
- package/lib/{index-CboxZOVW.js.map → index-D5NeW2z6.js.map} +1 -1
- package/lib/{index-1TbL0HXQ.js → index-DSKBOdpT.js} +2 -2
- package/lib/{index-1TbL0HXQ.js.map → index-DSKBOdpT.js.map} +1 -1
- package/lib/{index.esm-ti5zvZS_.js → index.esm-B35e7P83.js} +2 -2
- package/lib/index.esm-B35e7P83.js.map +1 -0
- package/lib/{index.esm-DtzT_KoE.js → index.esm-B_0dvNjB.js} +2 -2
- package/lib/{index.esm-DtzT_KoE.js.map → index.esm-B_0dvNjB.js.map} +1 -1
- package/lib/{invariant-CGOLuIIz.js → invariant-BJAl77rw.js} +4 -4
- package/lib/invariant-BJAl77rw.js.map +1 -0
- package/lib/{mutation-DMHWqmFp.js → mutation-BOYnEDf6.js} +70 -44
- package/lib/mutation-BOYnEDf6.js.map +1 -0
- package/lib/ui/Accordion.js +1 -1
- package/lib/ui/ActionButton.js +2 -2
- package/lib/ui/Alert.js +1 -1
- package/lib/ui/AlertDialog.js +1 -1
- package/lib/ui/Badge.js +1 -1
- package/lib/ui/Breadcrumb.js +1 -1
- package/lib/ui/Button.js +1 -1
- package/lib/ui/ButtonGroup.js +1 -1
- package/lib/ui/Callout.js +1 -1
- package/lib/ui/Card.js +1 -1
- package/lib/ui/Carousel.js +1 -1
- package/lib/ui/Checkbox.js +1 -1
- package/lib/ui/CodeBlock.js +1 -1
- package/lib/ui/Command.js +2 -2
- package/lib/ui/Dialog.js +1 -1
- package/lib/ui/Drawer.js +2 -2
- package/lib/ui/DropdownMenu.js +1 -1
- package/lib/ui/EmbeddedCodeBlock.js +1 -1
- package/lib/ui/Form.js +1 -1
- package/lib/ui/Frame.js +1 -1
- package/lib/ui/HoverCard.js +1 -1
- package/lib/ui/Input.js +1 -1
- package/lib/ui/Item.js +1 -1
- package/lib/ui/Label.js +1 -1
- package/lib/ui/NativeSelect.js +1 -1
- package/lib/ui/Pagination.js +1 -1
- package/lib/ui/Popover.js +1 -1
- package/lib/ui/Progress.js +1 -1
- package/lib/ui/RadioGroup.js +1 -1
- package/lib/ui/ScrollArea.js +1 -1
- package/lib/ui/Secret.js +1 -1
- package/lib/ui/Separator.js +1 -1
- package/lib/ui/Skeleton.js +1 -1
- package/lib/ui/Slider.js +1 -1
- package/lib/ui/Switch.js +1 -1
- package/lib/ui/SyntaxHighlight.js +3 -3
- package/lib/ui/Tabs.js +1 -1
- package/lib/ui/Textarea.js +1 -1
- package/lib/ui/Toggle.js +1 -1
- package/lib/ui/ToggleGroup.js +1 -1
- package/lib/ui/Value.js +1 -1
- package/lib/ui/util.js +1 -1
- package/lib/zudoku.__internal.js +604 -602
- package/lib/zudoku.__internal.js.map +1 -1
- package/lib/zudoku.auth-auth0.js +16 -16
- package/lib/zudoku.auth-auth0.js.map +1 -1
- package/lib/zudoku.auth-azureb2c.js +4 -4
- package/lib/zudoku.auth-clerk.js +52 -75
- package/lib/zudoku.auth-clerk.js.map +1 -1
- package/lib/zudoku.auth-firebase.js +5 -5
- package/lib/zudoku.auth-openid.js +5 -5
- package/lib/zudoku.auth-supabase.js +31 -40
- package/lib/zudoku.auth-supabase.js.map +1 -1
- package/lib/zudoku.components.js +6 -6
- package/lib/zudoku.hooks.js +3 -3
- package/lib/zudoku.mermaid.js +3 -3
- package/lib/zudoku.plugin-api-catalog.js +5 -5
- package/lib/zudoku.plugin-api-keys.js +258 -240
- package/lib/zudoku.plugin-api-keys.js.map +1 -1
- package/lib/zudoku.plugin-custom-pages.js +1 -1
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +3 -3
- package/lib/zudoku.plugin-redirect.js +1 -1
- package/lib/zudoku.plugin-search-pagefind.js +7 -7
- package/lib/zudoku.router.js +1130 -1404
- package/lib/zudoku.router.js.map +1 -1
- package/package.json +12 -12
- package/src/lib/authentication/components/CallbackHandler.tsx +1 -1
- package/src/lib/authentication/providers/auth0.tsx +15 -9
- package/src/lib/authentication/providers/clerk.tsx +0 -26
- package/src/lib/authentication/providers/supabase.tsx +6 -15
- package/src/lib/core/RouteGuard.tsx +30 -24
- package/src/lib/oas/graphql/circular.ts +36 -3
- package/src/lib/plugins/api-keys/index.tsx +46 -16
- package/src/lib/plugins/api-keys/settings/ApiKeyList.tsx +3 -0
- package/src/lib/plugins/openapi/OperationList.tsx +6 -1
- package/src/lib/plugins/openapi/schema/utils.ts +15 -4
- package/src/lib/util/invariant.ts +2 -1
- package/lib/Input-D-kqEQ5M.js.map +0 -1
- package/lib/OAuthErrorPage-DQtg28Go.js.map +0 -1
- package/lib/RouteGuard-D0f743SM.js +0 -77
- package/lib/RouteGuard-D0f743SM.js.map +0 -1
- package/lib/SchemaView-G-SVXxAG.js.map +0 -1
- package/lib/SyntaxHighlight-Dgd0AaaX.js.map +0 -1
- package/lib/ZudokuContext-DNHMZfcP.js.map +0 -1
- package/lib/___vite-browser-external_commonjs-proxy-Cga3HsWk.js.map +0 -1
- package/lib/chunk-PVWAREVJ-ClM0m2aJ.js +0 -7965
- package/lib/chunk-PVWAREVJ-ClM0m2aJ.js.map +0 -1
- package/lib/cn-dYga0KKN.js.map +0 -1
- package/lib/index.esm-ti5zvZS_.js.map +0 -1
- package/lib/invariant-CGOLuIIz.js.map +0 -1
- package/lib/mutation-DMHWqmFp.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zudoku",
|
|
3
|
-
"version": "0.66.
|
|
3
|
+
"version": "0.66.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"homepage": "https://zudoku.dev",
|
|
6
6
|
"repository": {
|
|
@@ -180,17 +180,17 @@
|
|
|
180
180
|
"@radix-ui/react-visually-hidden": "1.2.4",
|
|
181
181
|
"@scalar/openapi-parser": "0.23.2",
|
|
182
182
|
"@sentry/node": "10.27.0",
|
|
183
|
-
"@shikijs/engine-javascript": "3.
|
|
184
|
-
"@shikijs/langs": "3.
|
|
185
|
-
"@shikijs/rehype": "3.
|
|
186
|
-
"@shikijs/themes": "3.
|
|
187
|
-
"@shikijs/transformers": "3.
|
|
183
|
+
"@shikijs/engine-javascript": "3.20.0",
|
|
184
|
+
"@shikijs/langs": "3.20.0",
|
|
185
|
+
"@shikijs/rehype": "3.20.0",
|
|
186
|
+
"@shikijs/themes": "3.20.0",
|
|
187
|
+
"@shikijs/transformers": "3.20.0",
|
|
188
188
|
"@sindresorhus/slugify": "3.0.0",
|
|
189
189
|
"@stefanprobst/rehype-extract-toc": "3.0.0",
|
|
190
190
|
"@tailwindcss/typography": "0.5.19",
|
|
191
191
|
"@tailwindcss/vite": "4.1.16",
|
|
192
192
|
"@tanem/react-nprogress": "5.0.56",
|
|
193
|
-
"@tanstack/react-query": "5.
|
|
193
|
+
"@tanstack/react-query": "5.90.12",
|
|
194
194
|
"@types/react": "19.2.7",
|
|
195
195
|
"@types/react-dom": "19.2.3",
|
|
196
196
|
"@vitejs/plugin-react": "5.1.0",
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
"react-hook-form": "7.66.0",
|
|
234
234
|
"react-is": "19.2.3",
|
|
235
235
|
"react-markdown": "10.1.0",
|
|
236
|
-
"react-router": "7.
|
|
236
|
+
"react-router": "7.12.0",
|
|
237
237
|
"rehype-mdx-import-media": "1.2.0",
|
|
238
238
|
"rehype-raw": "7.0.0",
|
|
239
239
|
"rehype-slug": "6.0.0",
|
|
@@ -245,11 +245,11 @@
|
|
|
245
245
|
"remark-mdx-frontmatter": "5.2.0",
|
|
246
246
|
"rollup": "4.52.5",
|
|
247
247
|
"semver": "7.7.2",
|
|
248
|
-
"shiki": "3.
|
|
248
|
+
"shiki": "3.20.0",
|
|
249
249
|
"sitemap": "9.0.0",
|
|
250
250
|
"strip-ansi": "7.1.2",
|
|
251
|
-
"tailwind-merge": "3.
|
|
252
|
-
"tailwindcss": "4.1.
|
|
251
|
+
"tailwind-merge": "3.4.0",
|
|
252
|
+
"tailwindcss": "4.1.18",
|
|
253
253
|
"tw-animate-css": "1.4.0",
|
|
254
254
|
"unified": "^11.0.5",
|
|
255
255
|
"unist-util-visit": "5.0.0",
|
|
@@ -280,7 +280,7 @@
|
|
|
280
280
|
"@types/semver": "7.7.0",
|
|
281
281
|
"@types/unist": "^3.0.3",
|
|
282
282
|
"@types/yargs": "17.0.35",
|
|
283
|
-
"@vitest/coverage-v8": "
|
|
283
|
+
"@vitest/coverage-v8": "4.0.16",
|
|
284
284
|
"esbuild": "0.27.0",
|
|
285
285
|
"happy-dom": "20.0.10",
|
|
286
286
|
"mdast-util-mdx": "3.0.0",
|
|
@@ -13,7 +13,7 @@ export function CallbackHandler({
|
|
|
13
13
|
const { options } = useZudoku();
|
|
14
14
|
const executeCallback = useSuspenseQuery({
|
|
15
15
|
retry: false,
|
|
16
|
-
queryKey: ["oauth-callback"],
|
|
16
|
+
queryKey: ["oauth-callback", window.location.search],
|
|
17
17
|
queryFn: async () => {
|
|
18
18
|
const url = new URL(window.location.href);
|
|
19
19
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Auth0AuthenticationConfig } from "../../../config/config.js";
|
|
2
|
+
import { joinUrl } from "../../util/joinUrl.js";
|
|
2
3
|
import type {
|
|
3
4
|
AuthActionContext,
|
|
4
5
|
AuthenticationPlugin,
|
|
@@ -43,7 +44,10 @@ class Auth0AuthenticationProvider
|
|
|
43
44
|
|
|
44
45
|
signOut = async (_: AuthActionContext): Promise<void> => {
|
|
45
46
|
const as = await this.getAuthServer();
|
|
46
|
-
|
|
47
|
+
|
|
48
|
+
// biome-ignore lint/suspicious/noExplicitAny: We don't have a good way for typing provider-data yet.
|
|
49
|
+
const providerData = useAuthState.getState().providerData as any;
|
|
50
|
+
const idToken = providerData?.idToken;
|
|
47
51
|
|
|
48
52
|
useAuthState.setState({
|
|
49
53
|
isAuthenticated: false,
|
|
@@ -53,15 +57,18 @@ class Auth0AuthenticationProvider
|
|
|
53
57
|
});
|
|
54
58
|
|
|
55
59
|
const redirectUrl = new URL(window.location.origin);
|
|
56
|
-
redirectUrl.pathname =
|
|
60
|
+
redirectUrl.pathname = joinUrl(
|
|
61
|
+
import.meta.env.BASE_URL,
|
|
62
|
+
this.redirectToAfterSignOut,
|
|
63
|
+
);
|
|
57
64
|
|
|
58
65
|
// SEE: https://auth0.com/docs/authenticate/login/logout/log-users-out-of-auth0
|
|
59
66
|
// For Auth0 tenants created on or after 14 November 2023, RP-Initiated
|
|
60
67
|
// Logout End Session Endpoint Discovery is enabled by default.
|
|
61
68
|
// Otherwise we fallback to the old non-compliant logout
|
|
62
69
|
|
|
63
|
-
// The
|
|
64
|
-
// so we use
|
|
70
|
+
// The end_session_endpoint is set, the IdP supports some form of logout,
|
|
71
|
+
// so we use auth0 logout. Otherwise, just redirect the user to home
|
|
65
72
|
if (as.end_session_endpoint) {
|
|
66
73
|
const logoutUrl = new URL(as.end_session_endpoint);
|
|
67
74
|
if (idToken) {
|
|
@@ -72,12 +79,11 @@ class Auth0AuthenticationProvider
|
|
|
72
79
|
redirectUrl.toString(),
|
|
73
80
|
);
|
|
74
81
|
|
|
75
|
-
|
|
82
|
+
window.location.href = logoutUrl.toString();
|
|
76
83
|
} else {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// window.location.href = logoutUrl.toString();
|
|
84
|
+
// const logoutUrl = new URL(`${this.issuer.replace(/\/$/, "")}/v2/logout`);
|
|
85
|
+
// logoutUrl.searchParams.set("returnTo", redirectUrl.toString());
|
|
86
|
+
// don't support the deprecated logout today
|
|
81
87
|
}
|
|
82
88
|
};
|
|
83
89
|
}
|
|
@@ -29,32 +29,6 @@ const clerkAuth: AuthenticationProviderInitializer<
|
|
|
29
29
|
|
|
30
30
|
await clerkApi.load();
|
|
31
31
|
|
|
32
|
-
if (clerkApi.user) {
|
|
33
|
-
const verifiedEmail = clerkApi.user.emailAddresses.find(
|
|
34
|
-
(email) => email.verification.status === "verified",
|
|
35
|
-
);
|
|
36
|
-
useAuthState.getState().setLoggedIn({
|
|
37
|
-
profile: {
|
|
38
|
-
sub: clerkApi.user.id,
|
|
39
|
-
name: clerkApi.user.fullName ?? undefined,
|
|
40
|
-
email:
|
|
41
|
-
verifiedEmail?.emailAddress ??
|
|
42
|
-
clerkApi.user.emailAddresses[0]?.emailAddress,
|
|
43
|
-
emailVerified: verifiedEmail !== undefined,
|
|
44
|
-
pictureUrl: clerkApi.user.imageUrl,
|
|
45
|
-
},
|
|
46
|
-
providerData: {
|
|
47
|
-
user: {
|
|
48
|
-
publicMetadata: clerkApi.user.publicMetadata,
|
|
49
|
-
id: clerkApi.user.id,
|
|
50
|
-
emailAddresses: clerkApi.user.emailAddresses,
|
|
51
|
-
imageUrl: clerkApi.user.imageUrl,
|
|
52
|
-
fullName: clerkApi.user.fullName,
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
32
|
return clerkApi;
|
|
59
33
|
})();
|
|
60
34
|
|
|
@@ -129,21 +129,12 @@ class SupabaseAuthenticationProvider
|
|
|
129
129
|
};
|
|
130
130
|
|
|
131
131
|
signOut = async () => {
|
|
132
|
-
await
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
void this.client.auth.signOut();
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
useAuthState.setState({
|
|
142
|
-
isAuthenticated: false,
|
|
143
|
-
isPending: false,
|
|
144
|
-
profile: undefined,
|
|
145
|
-
providerData: undefined,
|
|
146
|
-
});
|
|
132
|
+
const { error } = await this.client.auth.signOut({ scope: "local" });
|
|
133
|
+
if (error) {
|
|
134
|
+
// biome-ignore lint/suspicious: Logging is better than not doing anything
|
|
135
|
+
console.error("Error signing out", error);
|
|
136
|
+
}
|
|
137
|
+
useAuthState.getState().setLoggedOut();
|
|
147
138
|
};
|
|
148
139
|
|
|
149
140
|
onPageLoad = async () => {
|
|
@@ -27,16 +27,31 @@ export const RouteGuard = () => {
|
|
|
27
27
|
const shouldBypass = use(BypassProtectedRoutesContext);
|
|
28
28
|
const { protectedRoutes } = zudoku.options;
|
|
29
29
|
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
: undefined;
|
|
30
|
+
const protectedRouteEntry = protectedRoutes
|
|
31
|
+
? Object.entries(protectedRoutes).find(([path]) =>
|
|
32
|
+
matchPath({ path, end: true }, location.pathname),
|
|
33
|
+
)
|
|
34
|
+
: undefined;
|
|
36
35
|
|
|
37
|
-
const isProtectedRoute =
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
const isProtectedRoute = protectedRouteEntry !== undefined;
|
|
37
|
+
|
|
38
|
+
// SSR/prerendering mode: render content with search meta tag, skip all auth
|
|
39
|
+
if (shouldBypass) {
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
{isProtectedRoute && (
|
|
43
|
+
<Helmet>
|
|
44
|
+
<meta
|
|
45
|
+
name="pagefind"
|
|
46
|
+
data-pagefind-filter={`section:${SEARCH_PROTECTED_SECTION}`}
|
|
47
|
+
content="true"
|
|
48
|
+
/>
|
|
49
|
+
</Helmet>
|
|
50
|
+
)}
|
|
51
|
+
<Outlet />
|
|
52
|
+
</>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
40
55
|
|
|
41
56
|
if (isProtectedRoute && !auth.isAuthEnabled) {
|
|
42
57
|
throw new ZudokuError("Authentication is not enabled", {
|
|
@@ -46,6 +61,10 @@ export const RouteGuard = () => {
|
|
|
46
61
|
});
|
|
47
62
|
}
|
|
48
63
|
|
|
64
|
+
const authCheckFn = protectedRouteEntry?.[1];
|
|
65
|
+
const needsToSignIn =
|
|
66
|
+
isProtectedRoute && !authCheckFn?.({ auth, context: zudoku });
|
|
67
|
+
|
|
49
68
|
if (needsToSignIn && auth.isPending && typeof window !== "undefined") {
|
|
50
69
|
return null;
|
|
51
70
|
}
|
|
@@ -91,7 +110,7 @@ export const RouteGuard = () => {
|
|
|
91
110
|
)
|
|
92
111
|
}
|
|
93
112
|
>
|
|
94
|
-
Login
|
|
113
|
+
Login
|
|
95
114
|
</Button>
|
|
96
115
|
</DialogFooter>
|
|
97
116
|
</DialogContent>
|
|
@@ -99,18 +118,5 @@ export const RouteGuard = () => {
|
|
|
99
118
|
);
|
|
100
119
|
}
|
|
101
120
|
|
|
102
|
-
return
|
|
103
|
-
<>
|
|
104
|
-
{shouldBypass && isProtectedRoute && (
|
|
105
|
-
<Helmet>
|
|
106
|
-
<meta
|
|
107
|
-
name="pagefind"
|
|
108
|
-
data-pagefind-filter={`section:${SEARCH_PROTECTED_SECTION}`}
|
|
109
|
-
content="true"
|
|
110
|
-
/>
|
|
111
|
-
</Helmet>
|
|
112
|
-
)}
|
|
113
|
-
<Outlet />
|
|
114
|
-
</>
|
|
115
|
-
);
|
|
121
|
+
return <Outlet />;
|
|
116
122
|
};
|
|
@@ -3,6 +3,7 @@ import { GraphQLJSON } from "graphql-type-json";
|
|
|
3
3
|
import type { RecordAny } from "../../util/traverse.js";
|
|
4
4
|
|
|
5
5
|
export const CIRCULAR_REF = "$[Circular Reference]";
|
|
6
|
+
export const SCHEMA_REF_PREFIX = "$ref:";
|
|
6
7
|
|
|
7
8
|
const OPENAPI_PROPS = new Set([
|
|
8
9
|
"properties",
|
|
@@ -19,13 +20,28 @@ const handleCircularRefs = (
|
|
|
19
20
|
visited = new WeakSet(),
|
|
20
21
|
refs = new WeakMap(),
|
|
21
22
|
path: string[] = [],
|
|
23
|
+
seenRefPaths = new Set<string>(),
|
|
22
24
|
// biome-ignore lint/suspicious/noExplicitAny: Allow any type
|
|
23
25
|
): any => {
|
|
24
26
|
if (obj === null || typeof obj !== "object") return obj;
|
|
25
27
|
|
|
28
|
+
const refPath = obj.__$ref;
|
|
29
|
+
|
|
30
|
+
// Check if this object has a __$ref marker (set during schema code generation)
|
|
31
|
+
// If we've already fully processed this ref path, return a reference marker
|
|
32
|
+
// instead of the full data to avoid JSON.stringify serializing duplicates
|
|
33
|
+
if (typeof refPath === "string" && seenRefPaths.has(refPath)) {
|
|
34
|
+
return SCHEMA_REF_PREFIX + refPath;
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
if (visited.has(obj)) {
|
|
27
38
|
const cached = refs.get(obj);
|
|
28
|
-
if (cached)
|
|
39
|
+
if (cached) {
|
|
40
|
+
return typeof refPath === "string"
|
|
41
|
+
? // If already processed, return ref marker to avoid duplicate serialization
|
|
42
|
+
SCHEMA_REF_PREFIX + refPath
|
|
43
|
+
: cached;
|
|
44
|
+
}
|
|
29
45
|
const circularProp = path.find((p) => !OPENAPI_PROPS.has(p)) || path[0];
|
|
30
46
|
|
|
31
47
|
return [CIRCULAR_REF, circularProp].filter(Boolean).join(":");
|
|
@@ -35,7 +51,13 @@ const handleCircularRefs = (
|
|
|
35
51
|
|
|
36
52
|
if (Array.isArray(obj)) {
|
|
37
53
|
const result = obj.map((item, index) =>
|
|
38
|
-
handleCircularRefs(
|
|
54
|
+
handleCircularRefs(
|
|
55
|
+
item,
|
|
56
|
+
visited,
|
|
57
|
+
refs,
|
|
58
|
+
[...path, index.toString()],
|
|
59
|
+
seenRefPaths,
|
|
60
|
+
),
|
|
39
61
|
);
|
|
40
62
|
refs.set(obj, result);
|
|
41
63
|
return result;
|
|
@@ -43,9 +65,20 @@ const handleCircularRefs = (
|
|
|
43
65
|
|
|
44
66
|
const result: RecordAny = {};
|
|
45
67
|
for (const [key, value] of Object.entries(obj)) {
|
|
46
|
-
result[key] = handleCircularRefs(
|
|
68
|
+
result[key] = handleCircularRefs(
|
|
69
|
+
value,
|
|
70
|
+
visited,
|
|
71
|
+
refs,
|
|
72
|
+
[...path, key],
|
|
73
|
+
seenRefPaths,
|
|
74
|
+
);
|
|
47
75
|
}
|
|
48
76
|
refs.set(obj, result);
|
|
77
|
+
|
|
78
|
+
if (typeof refPath === "string") {
|
|
79
|
+
seenRefPaths.add(refPath);
|
|
80
|
+
}
|
|
81
|
+
|
|
49
82
|
return result;
|
|
50
83
|
};
|
|
51
84
|
|
|
@@ -37,9 +37,11 @@ export type ApiKeyService = {
|
|
|
37
37
|
}) => Promise<void>;
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
-
export type ApiKeyPluginOptions =
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
export type ApiKeyPluginOptions = ApiKeyService | DefaultApiKeyServiceOptions;
|
|
41
|
+
|
|
42
|
+
type DefaultApiKeyServiceOptions = {
|
|
43
|
+
deploymentName?: string;
|
|
44
|
+
} & Partial<ApiKeyService>;
|
|
43
45
|
|
|
44
46
|
export interface ApiKey {
|
|
45
47
|
id: string;
|
|
@@ -79,12 +81,19 @@ const throwIfProblemJson = async (response: Response) => {
|
|
|
79
81
|
}
|
|
80
82
|
};
|
|
81
83
|
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
const developerHintOptions = {
|
|
85
|
+
developerHint:
|
|
86
|
+
"This project is not linked to a Zuplo deployment. Run `zuplo link` to get started with API Keys.",
|
|
87
|
+
title: "Not linked to a Zuplo deployment",
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const createZuploService = ({
|
|
91
|
+
deploymentName,
|
|
92
|
+
...options
|
|
93
|
+
}: DefaultApiKeyServiceOptions): ApiKeyService => {
|
|
86
94
|
return {
|
|
87
95
|
deleteKey: async (consumerId, keyId, context) => {
|
|
96
|
+
invariant(deploymentName, "Cannot delete API key.", developerHintOptions);
|
|
88
97
|
const request = new Request(
|
|
89
98
|
DEFAULT_API_KEY_ENDPOINT +
|
|
90
99
|
`/${deploymentName}/consumers/${consumerId}/keys/${keyId}`,
|
|
@@ -97,11 +106,15 @@ const createDefaultHandler = (
|
|
|
97
106
|
invariant(response.ok, "Failed to delete API key");
|
|
98
107
|
},
|
|
99
108
|
updateConsumer: async (consumer, context) => {
|
|
109
|
+
invariant(
|
|
110
|
+
deploymentName,
|
|
111
|
+
"Cannot update API key description.",
|
|
112
|
+
developerHintOptions,
|
|
113
|
+
);
|
|
100
114
|
const response = await fetch(
|
|
101
115
|
await context.signRequest(
|
|
102
116
|
new Request(
|
|
103
|
-
DEFAULT_API_KEY_ENDPOINT
|
|
104
|
-
`/${deploymentName}/consumers/${consumer.id}`,
|
|
117
|
+
`${DEFAULT_API_KEY_ENDPOINT}/${deploymentName}/consumers/${consumer.id}`,
|
|
105
118
|
{
|
|
106
119
|
method: "PATCH",
|
|
107
120
|
headers: {
|
|
@@ -118,11 +131,11 @@ const createDefaultHandler = (
|
|
|
118
131
|
invariant(response.ok, "Failed to update API key description");
|
|
119
132
|
},
|
|
120
133
|
rollKey: async (consumerId, context) => {
|
|
134
|
+
invariant(deploymentName, "Cannot roll API key.", developerHintOptions);
|
|
121
135
|
const response = await fetch(
|
|
122
136
|
await context.signRequest(
|
|
123
137
|
new Request(
|
|
124
|
-
DEFAULT_API_KEY_ENDPOINT
|
|
125
|
-
`/${deploymentName}/consumers/${consumerId}/roll-key`,
|
|
138
|
+
`${DEFAULT_API_KEY_ENDPOINT}/${deploymentName}/consumers/${consumerId}/roll-key`,
|
|
126
139
|
{
|
|
127
140
|
method: "POST",
|
|
128
141
|
headers: {
|
|
@@ -137,6 +150,7 @@ const createDefaultHandler = (
|
|
|
137
150
|
invariant(response.ok, "Failed to roll API key");
|
|
138
151
|
},
|
|
139
152
|
getConsumers: async (context) => {
|
|
153
|
+
invariant(deploymentName, "Cannot get API keys.", developerHintOptions);
|
|
140
154
|
const request = new Request(
|
|
141
155
|
`${DEFAULT_API_KEY_ENDPOINT}/${deploymentName}/consumers`,
|
|
142
156
|
);
|
|
@@ -179,14 +193,30 @@ const createDefaultHandler = (
|
|
|
179
193
|
export const createApiKeyService = <T extends ApiKeyService>(service: T): T =>
|
|
180
194
|
service;
|
|
181
195
|
|
|
196
|
+
type InternalApiKeyPluginOptions = {
|
|
197
|
+
// The name of the Zuplo deployment
|
|
198
|
+
deploymentName?: string;
|
|
199
|
+
// Indicates that the plugin is running in Zuplo "mode"
|
|
200
|
+
isZuplo?: boolean;
|
|
201
|
+
};
|
|
202
|
+
|
|
182
203
|
export const apiKeyPlugin = ({
|
|
183
204
|
deploymentName,
|
|
205
|
+
isZuplo,
|
|
184
206
|
...options
|
|
185
|
-
}: Omit<ApiKeysOptions, "enabled"> &
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
207
|
+
}: Omit<ApiKeysOptions, "enabled"> &
|
|
208
|
+
InternalApiKeyPluginOptions): ZudokuPlugin &
|
|
209
|
+
ApiIdentityPlugin &
|
|
210
|
+
ProfileMenuPlugin => {
|
|
211
|
+
if (isZuplo && !deploymentName) {
|
|
212
|
+
// biome-ignore lint/suspicious/noConsole: Important warning
|
|
213
|
+
console.warn(
|
|
214
|
+
"This project is not linked to a Zuplo deployment. Run `zuplo link` to get started.",
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const service = isZuplo
|
|
219
|
+
? createZuploService({ deploymentName, ...options })
|
|
190
220
|
: options;
|
|
191
221
|
|
|
192
222
|
if (!service.getConsumers) {
|
|
@@ -15,6 +15,9 @@ export const ApiKeyList = ({ service }: { service: ApiKeyService }) => {
|
|
|
15
15
|
try {
|
|
16
16
|
return await service.getConsumers(context);
|
|
17
17
|
} catch (error) {
|
|
18
|
+
if (error instanceof ZudokuError) {
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
18
21
|
throw new ZudokuError("Cannot get API keys", {
|
|
19
22
|
cause: error,
|
|
20
23
|
title: "Error getting API keys",
|
|
@@ -151,6 +151,11 @@ const OperationsForTagQuery = graphql(/* GraphQL */ `
|
|
|
151
151
|
|
|
152
152
|
const LAZY_OPERATION_LIST_THRESHOLD = 30;
|
|
153
153
|
|
|
154
|
+
const getFileExtension = (filename: string): string => {
|
|
155
|
+
const lastDotIndex = filename.lastIndexOf(".");
|
|
156
|
+
return lastDotIndex !== -1 ? filename.slice(lastDotIndex) : "";
|
|
157
|
+
};
|
|
158
|
+
|
|
154
159
|
export const OperationList = ({
|
|
155
160
|
tag,
|
|
156
161
|
untagged,
|
|
@@ -251,7 +256,7 @@ export const OperationList = ({
|
|
|
251
256
|
typeof input === "string"
|
|
252
257
|
? type === "url"
|
|
253
258
|
? input
|
|
254
|
-
: joinUrl(path, version, input
|
|
259
|
+
: joinUrl(path, version, `schema${getFileExtension(input)}`)
|
|
255
260
|
: undefined;
|
|
256
261
|
|
|
257
262
|
return (
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CIRCULAR_REF,
|
|
3
|
+
SCHEMA_REF_PREFIX,
|
|
4
|
+
} from "../../../oas/graphql/circular.js";
|
|
2
5
|
import type {
|
|
3
6
|
ArraySchemaObject,
|
|
4
7
|
SchemaObject,
|
|
@@ -25,7 +28,8 @@ export const isComplexType = (value?: SchemaObject) =>
|
|
|
25
28
|
(!value.items.type || value.items.type === "object")));
|
|
26
29
|
|
|
27
30
|
export const isCircularRef = (schema: unknown): schema is string =>
|
|
28
|
-
typeof schema === "string" &&
|
|
31
|
+
typeof schema === "string" &&
|
|
32
|
+
(schema.startsWith(CIRCULAR_REF) || schema.startsWith(SCHEMA_REF_PREFIX));
|
|
29
33
|
|
|
30
34
|
export const isArrayCircularRef = (
|
|
31
35
|
schema: SchemaObject,
|
|
@@ -34,5 +38,12 @@ export const isArrayCircularRef = (
|
|
|
34
38
|
|
|
35
39
|
export const extractCircularRefInfo = (
|
|
36
40
|
ref?: string | SchemaObject,
|
|
37
|
-
): string | undefined =>
|
|
38
|
-
typeof ref
|
|
41
|
+
): string | undefined => {
|
|
42
|
+
if (typeof ref !== "string") return undefined;
|
|
43
|
+
|
|
44
|
+
if (ref.startsWith(SCHEMA_REF_PREFIX)) {
|
|
45
|
+
return ref.slice(SCHEMA_REF_PREFIX.length).split("/").pop();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return ref.split(":")[1];
|
|
49
|
+
};
|
|
@@ -7,6 +7,7 @@ export default function invariant(
|
|
|
7
7
|
* the message takes a fair amount of effort to compute
|
|
8
8
|
*/
|
|
9
9
|
message?: string | (() => string),
|
|
10
|
+
options?: ZudokuErrorOptions,
|
|
10
11
|
): asserts condition {
|
|
11
12
|
if (condition) {
|
|
12
13
|
return;
|
|
@@ -16,7 +17,7 @@ export default function invariant(
|
|
|
16
17
|
const provided: string | undefined =
|
|
17
18
|
typeof message === "function" ? message() : message;
|
|
18
19
|
|
|
19
|
-
throw new ZudokuError(provided ?? "Invariant failed");
|
|
20
|
+
throw new ZudokuError(provided ?? "Invariant failed", options);
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export type ZudokuErrorOptions = {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Input-D-kqEQ5M.js","sources":["../../../node_modules/.pnpm/@tanstack+query-core@5.85.5/node_modules/@tanstack/query-core/build/modern/mutationObserver.js","../../../node_modules/.pnpm/@tanstack+react-query@5.85.5_react@19.2.3/node_modules/@tanstack/react-query/build/modern/useMutation.js","../src/lib/ui/Input.tsx"],"sourcesContent":["// src/mutationObserver.ts\nimport { getDefaultState } from \"./mutation.js\";\nimport { notifyManager } from \"./notifyManager.js\";\nimport { Subscribable } from \"./subscribable.js\";\nimport { hashKey, shallowEqualObjects } from \"./utils.js\";\nvar MutationObserver = class extends Subscribable {\n #client;\n #currentResult = void 0;\n #currentMutation;\n #mutateOptions;\n constructor(client, options) {\n super();\n this.#client = client;\n this.setOptions(options);\n this.bindMethods();\n this.#updateResult();\n }\n bindMethods() {\n this.mutate = this.mutate.bind(this);\n this.reset = this.reset.bind(this);\n }\n setOptions(options) {\n const prevOptions = this.options;\n this.options = this.#client.defaultMutationOptions(options);\n if (!shallowEqualObjects(this.options, prevOptions)) {\n this.#client.getMutationCache().notify({\n type: \"observerOptionsUpdated\",\n mutation: this.#currentMutation,\n observer: this\n });\n }\n if (prevOptions?.mutationKey && this.options.mutationKey && hashKey(prevOptions.mutationKey) !== hashKey(this.options.mutationKey)) {\n this.reset();\n } else if (this.#currentMutation?.state.status === \"pending\") {\n this.#currentMutation.setOptions(this.options);\n }\n }\n onUnsubscribe() {\n if (!this.hasListeners()) {\n this.#currentMutation?.removeObserver(this);\n }\n }\n onMutationUpdate(action) {\n this.#updateResult();\n this.#notify(action);\n }\n getCurrentResult() {\n return this.#currentResult;\n }\n reset() {\n this.#currentMutation?.removeObserver(this);\n this.#currentMutation = void 0;\n this.#updateResult();\n this.#notify();\n }\n mutate(variables, options) {\n this.#mutateOptions = options;\n this.#currentMutation?.removeObserver(this);\n this.#currentMutation = this.#client.getMutationCache().build(this.#client, this.options);\n this.#currentMutation.addObserver(this);\n return this.#currentMutation.execute(variables);\n }\n #updateResult() {\n const state = this.#currentMutation?.state ?? getDefaultState();\n this.#currentResult = {\n ...state,\n isPending: state.status === \"pending\",\n isSuccess: state.status === \"success\",\n isError: state.status === \"error\",\n isIdle: state.status === \"idle\",\n mutate: this.mutate,\n reset: this.reset\n };\n }\n #notify(action) {\n notifyManager.batch(() => {\n if (this.#mutateOptions && this.hasListeners()) {\n const variables = this.#currentResult.variables;\n const context = this.#currentResult.context;\n if (action?.type === \"success\") {\n this.#mutateOptions.onSuccess?.(action.data, variables, context);\n this.#mutateOptions.onSettled?.(action.data, null, variables, context);\n } else if (action?.type === \"error\") {\n this.#mutateOptions.onError?.(action.error, variables, context);\n this.#mutateOptions.onSettled?.(\n void 0,\n action.error,\n variables,\n context\n );\n }\n }\n this.listeners.forEach((listener) => {\n listener(this.#currentResult);\n });\n });\n }\n};\nexport {\n MutationObserver\n};\n//# sourceMappingURL=mutationObserver.js.map","\"use client\";\n\n// src/useMutation.ts\nimport * as React from \"react\";\nimport {\n MutationObserver,\n noop,\n notifyManager,\n shouldThrowError\n} from \"@tanstack/query-core\";\nimport { useQueryClient } from \"./QueryClientProvider.js\";\nfunction useMutation(options, queryClient) {\n const client = useQueryClient(queryClient);\n const [observer] = React.useState(\n () => new MutationObserver(\n client,\n options\n )\n );\n React.useEffect(() => {\n observer.setOptions(options);\n }, [observer, options]);\n const result = React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) => observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer]\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult()\n );\n const mutate = React.useCallback(\n (variables, mutateOptions) => {\n observer.mutate(variables, mutateOptions).catch(noop);\n },\n [observer]\n );\n if (result.error && shouldThrowError(observer.options.throwOnError, [result.error])) {\n throw result.error;\n }\n return { ...result, mutate, mutateAsync: result.mutate };\n}\nexport {\n useMutation\n};\n//# sourceMappingURL=useMutation.js.map","import * as React from \"react\";\nimport { cn } from \"../util/cn.js\";\n\ntype InputProps = React.InputHTMLAttributes<HTMLInputElement>;\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n },\n);\nInput.displayName = \"Input\";\n\nexport { Input };\n"],"names":["MutationObserver","Subscribable","#client","#currentResult","#currentMutation","#mutateOptions","client","options","#updateResult","prevOptions","shallowEqualObjects","hashKey","action","#notify","variables","state","getDefaultState","notifyManager","context","listener","useMutation","queryClient","useQueryClient","observer","React","result","onStoreChange","mutate","mutateOptions","noop","shouldThrowError","Input","className","type","props","ref","jsx","cn"],"mappings":";;;;;AAKA,IAAIA,IAAmB,cAAcC,EAAa;AAAA,EAChDC;AAAA,EACAC,KAAiB;AAAA,EACjBC;AAAA,EACAC;AAAA,EACA,YAAYC,GAAQC,GAAS;AAC3B,UAAK,GACL,KAAKL,KAAUI,GACf,KAAK,WAAWC,CAAO,GACvB,KAAK,YAAW,GAChB,KAAKC,GAAa;AAAA,EACpB;AAAA,EACA,cAAc;AACZ,SAAK,SAAS,KAAK,OAAO,KAAK,IAAI,GACnC,KAAK,QAAQ,KAAK,MAAM,KAAK,IAAI;AAAA,EACnC;AAAA,EACA,WAAWD,GAAS;AAClB,UAAME,IAAc,KAAK;AACzB,SAAK,UAAU,KAAKP,GAAQ,uBAAuBK,CAAO,GACrDG,EAAoB,KAAK,SAASD,CAAW,KAChD,KAAKP,GAAQ,iBAAgB,EAAG,OAAO;AAAA,MACrC,MAAM;AAAA,MACN,UAAU,KAAKE;AAAA,MACf,UAAU;AAAA,IAClB,CAAO,GAECK,GAAa,eAAe,KAAK,QAAQ,eAAeE,EAAQF,EAAY,WAAW,MAAME,EAAQ,KAAK,QAAQ,WAAW,IAC/H,KAAK,MAAK,IACD,KAAKP,IAAkB,MAAM,WAAW,aACjD,KAAKA,GAAiB,WAAW,KAAK,OAAO;AAAA,EAEjD;AAAA,EACA,gBAAgB;AACd,IAAK,KAAK,kBACR,KAAKA,IAAkB,eAAe,IAAI;AAAA,EAE9C;AAAA,EACA,iBAAiBQ,GAAQ;AACvB,SAAKJ,GAAa,GAClB,KAAKK,GAAQD,CAAM;AAAA,EACrB;AAAA,EACA,mBAAmB;AACjB,WAAO,KAAKT;AAAA,EACd;AAAA,EACA,QAAQ;AACN,SAAKC,IAAkB,eAAe,IAAI,GAC1C,KAAKA,KAAmB,QACxB,KAAKI,GAAa,GAClB,KAAKK,GAAO;AAAA,EACd;AAAA,EACA,OAAOC,GAAWP,GAAS;AACzB,gBAAKF,KAAiBE,GACtB,KAAKH,IAAkB,eAAe,IAAI,GAC1C,KAAKA,KAAmB,KAAKF,GAAQ,iBAAgB,EAAG,MAAM,KAAKA,IAAS,KAAK,OAAO,GACxF,KAAKE,GAAiB,YAAY,IAAI,GAC/B,KAAKA,GAAiB,QAAQU,CAAS;AAAA,EAChD;AAAA,EACAN,KAAgB;AACd,UAAMO,IAAQ,KAAKX,IAAkB,SAASY,EAAe;AAC7D,SAAKb,KAAiB;AAAA,MACpB,GAAGY;AAAA,MACH,WAAWA,EAAM,WAAW;AAAA,MAC5B,WAAWA,EAAM,WAAW;AAAA,MAC5B,SAASA,EAAM,WAAW;AAAA,MAC1B,QAAQA,EAAM,WAAW;AAAA,MACzB,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,IAClB;AAAA,EACE;AAAA,EACAF,GAAQD,GAAQ;AACd,IAAAK,EAAc,MAAM,MAAM;AACxB,UAAI,KAAKZ,MAAkB,KAAK,aAAY,GAAI;AAC9C,cAAMS,IAAY,KAAKX,GAAe,WAChCe,IAAU,KAAKf,GAAe;AACpC,QAAIS,GAAQ,SAAS,aACnB,KAAKP,GAAe,YAAYO,EAAO,MAAME,GAAWI,CAAO,GAC/D,KAAKb,GAAe,YAAYO,EAAO,MAAM,MAAME,GAAWI,CAAO,KAC5DN,GAAQ,SAAS,YAC1B,KAAKP,GAAe,UAAUO,EAAO,OAAOE,GAAWI,CAAO,GAC9D,KAAKb,GAAe;AAAA,UAClB;AAAA,UACAO,EAAO;AAAA,UACPE;AAAA,UACAI;AAAA,QACZ;AAAA,MAEM;AACA,WAAK,UAAU,QAAQ,CAACC,MAAa;AACnC,QAAAA,EAAS,KAAKhB,EAAc;AAAA,MAC9B,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;ACtFA,SAASiB,EAAYb,GAASc,GAAa;AACzC,QAAMf,IAASgB,EAAeD,CAAW,GACnC,CAACE,CAAQ,IAAIC,EAAM;AAAA,IACvB,MAAM,IAAIxB;AAAA,MACRM;AAAA,MACAC;AAAA,IACN;AAAA,EACA;AACE,EAAAiB,EAAM,UAAU,MAAM;AACpB,IAAAD,EAAS,WAAWhB,CAAO;AAAA,EAC7B,GAAG,CAACgB,GAAUhB,CAAO,CAAC;AACtB,QAAMkB,IAASD,EAAM;AAAA,IACnBA,EAAM;AAAA,MACJ,CAACE,MAAkBH,EAAS,UAAUN,EAAc,WAAWS,CAAa,CAAC;AAAA,MAC7E,CAACH,CAAQ;AAAA,IACf;AAAA,IACI,MAAMA,EAAS,iBAAgB;AAAA,IAC/B,MAAMA,EAAS,iBAAgB;AAAA,EACnC,GACQI,IAASH,EAAM;AAAA,IACnB,CAACV,GAAWc,MAAkB;AAC5B,MAAAL,EAAS,OAAOT,GAAWc,CAAa,EAAE,MAAMC,CAAI;AAAA,IACtD;AAAA,IACA,CAACN,CAAQ;AAAA,EACb;AACE,MAAIE,EAAO,SAASK,EAAiBP,EAAS,QAAQ,cAAc,CAACE,EAAO,KAAK,CAAC;AAChF,UAAMA,EAAO;AAEf,SAAO,EAAE,GAAGA,GAAQ,QAAAE,GAAQ,aAAaF,EAAO,OAAM;AACxD;ACnCA,MAAMM,IAAQP,EAAM;AAAA,EAClB,CAAC,EAAE,WAAAQ,GAAW,MAAAC,GAAM,GAAGC,EAAA,GAASC,MAE5BC,gBAAAA,EAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAAH;AAAA,MACA,WAAWI;AAAA,QACT;AAAA,QACAL;AAAA,MAAA;AAAA,MAEF,KAAAG;AAAA,MACC,GAAGD;AAAA,IAAA;AAAA,EAAA;AAIZ;AACAH,EAAM,cAAc;","x_google_ignoreList":[0,1]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"OAuthErrorPage-DQtg28Go.js","sources":["../src/lib/util/url.ts","../src/lib/authentication/components/CallbackHandler.tsx","../src/lib/authentication/components/OAuthErrorPage.tsx"],"sourcesContent":["/**\n * Normalizes a redirect URL by removing the origin and optionally the root path\n */\nexport function normalizeRedirectUrl(\n redirectTo: string,\n origin: string,\n basePath: string = \"/\",\n): string {\n if (!redirectTo.startsWith(origin)) {\n return redirectTo;\n }\n\n if (basePath !== \"/\" && redirectTo.startsWith(origin + basePath)) {\n return redirectTo.slice(origin.length + basePath.length);\n }\n\n return redirectTo.slice(origin.length);\n}\n","import { useSuspenseQuery } from \"@tanstack/react-query\";\nimport { Navigate } from \"react-router\";\nimport { useZudoku } from \"zudoku/components\";\nimport { joinUrl } from \"../../util/joinUrl.js\";\nimport { normalizeRedirectUrl } from \"../../util/url.js\";\nimport { OAuthAuthorizationError, type OAuthErrorType } from \"../errors.js\";\n\nexport function CallbackHandler({\n handleCallback,\n}: {\n handleCallback: () => Promise<string>;\n}) {\n const { options } = useZudoku();\n const executeCallback = useSuspenseQuery({\n retry: false,\n queryKey: [\"oauth-callback\"],\n queryFn: async () => {\n const url = new URL(window.location.href);\n\n const errorParam = url.searchParams.get(\"error\");\n const errorDescription =\n url.searchParams.get(\"error_description\") ?? undefined;\n const errorUri = url.searchParams.get(\"error_uri\") ?? undefined;\n if (errorParam) {\n throw new OAuthAuthorizationError(\n `OAuth error '${errorParam}': ${errorDescription}`,\n {\n error: errorParam as OAuthErrorType,\n error_description: errorDescription,\n error_uri: errorUri,\n },\n );\n }\n return joinUrl(\n normalizeRedirectUrl(\n await handleCallback(),\n window.location.origin,\n options.basePath,\n ),\n );\n },\n });\n\n return <Navigate to={executeCallback.data} replace />;\n}\n","import { HomeIcon } from \"lucide-react\";\nimport { Link } from \"react-router\";\nimport { Heading } from \"../../components/Heading.js\";\nimport { Typography } from \"../../components/Typography.js\";\nimport { Button } from \"../../ui/Button.js\";\nimport { OAuthAuthorizationError } from \"../errors.js\";\nimport { useAuth } from \"../hook.js\";\n\nconst errorDetailsMap: Record<string, { message: string }> = {\n invalid_request: {\n message:\n \"The authentication request was invalid. Please try signing in again.\",\n },\n unauthorized_client: {\n message:\n \"This application is not authorized to access your account. Please contact support.\",\n },\n access_denied: {\n message:\n \"You denied access to this application. To continue, please sign in and grant access.\",\n },\n unsupported_response_type: {\n message:\n \"The authentication method is not supported. Please contact support.\",\n },\n invalid_scope: {\n message: \"The requested permissions are invalid. Please contact support.\",\n },\n server_error: {\n message:\n \"The authentication server encountered an error. Please try again in a few moments.\",\n },\n temporarily_unavailable: {\n message:\n \"The authentication service is temporarily unavailable. Please try again in a few moments.\",\n },\n // Token errors\n invalid_client: {\n message: \"Invalid application credentials. Please contact support.\",\n },\n invalid_grant: {\n message:\n \"The authentication code has expired or is invalid. Please sign in again.\",\n },\n unsupported_grant_type: {\n message:\n \"The authentication method is not supported. Please contact support.\",\n },\n // Custom errors\n invalid_state: {\n message:\n \"Security validation failed. This may be due to a potential security attack. Please try signing in again.\",\n },\n missing_code_verifier: {\n message:\n \"Authentication security information is missing. Please clear your browser cache and try again.\",\n },\n network_error: {\n message:\n \"A network error occurred during authentication. Please check your connection and try again.\",\n },\n token_expired: {\n message: \"Your authentication session has expired. Please sign in again.\",\n },\n configuration_error: {\n message:\n \"There is an issue with the authentication configuration. Please contact support.\",\n },\n unknown_error: {\n message:\n \"An unexpected error occurred during authentication. Please try again or contact support.\",\n },\n};\n\nexport function OAuthErrorPage({ error }: { error: unknown }) {\n const { login } = useAuth();\n\n if (!(error instanceof OAuthAuthorizationError)) {\n throw error;\n }\n\n const oauthError = error.error;\n const type = oauthError.error;\n\n const details = errorDetailsMap[type] ?? errorDetailsMap.unknown_error;\n\n return (\n <div className=\"min-h-[400px] flex items-center justify-center p-4\">\n <div className=\"max-w-md w-full text-center space-y-6\">\n <div className=\"space-y-4 items-center\">\n <Heading level={2} className=\"text-2xl inline-block font-bold\">\n {titles[type] || \"Authentication Error\"}\n </Heading>\n\n <Typography className=\"text-gray-600 dark:text-gray-300 leading-relaxed\">\n {details?.message}\n </Typography>\n\n {/* Technical details for developers (only in development) */}\n </div>\n\n {/* Action Buttons */}\n <div className=\"space-y-3 pt-4\">\n <div className=\"space-y-2\">\n {(type === \"access_denied\" ||\n type === \"invalid_grant\" ||\n type === \"token_expired\") && (\n <Button\n onClick={() => login()}\n className=\"w-full capitalize\"\n variant={\"default\"}\n >\n Sign in again\n </Button>\n )}\n </div>\n\n <div className=\"flex gap-2\">\n <Button asChild className=\"flex-1\" variant=\"outline\">\n <Link to=\"/\">\n <HomeIcon className=\"w-4 h-4 mr-2\" />\n Go Home\n </Link>\n </Button>\n </div>\n </div>\n\n {/* Additional Help */}\n {helpMessages[type] && (\n <Typography className=\"text-sm text-gray-500 dark:text-gray-400\">\n {helpMessages[type]}\n </Typography>\n )}\n </div>\n </div>\n );\n}\n\nconst titles: Record<string, string> = {\n access_denied: \"Access Denied\",\n invalid_request: \"Invalid Request\",\n unauthorized_client: \"Unauthorized Application\",\n unsupported_response_type: \"Unsupported Method\",\n invalid_scope: \"Invalid Permissions\",\n server_error: \"Server Error\",\n temporarily_unavailable: \"Service Unavailable\",\n invalid_client: \"Invalid Credentials\",\n invalid_grant: \"Authentication Expired\",\n unsupported_grant_type: \"Unsupported Authentication\",\n invalid_state: \"Security Check Failed\",\n missing_code_verifier: \"Security Information Missing\",\n network_error: \"Network Error\",\n token_expired: \"Session Expired\",\n configuration_error: \"Configuration Error\",\n unknown_error: \"Authentication Failed\",\n};\n\nconst helpMessages: Record<string, string> = {\n access_denied:\n \"If you changed your mind, you can try signing in again to grant access.\",\n invalid_state:\n \"This error can occur if you have multiple tabs open or if your session was compromised.\",\n missing_code_verifier:\n \"Try clearing your browser's cache and cookies for this site.\",\n network_error:\n \"Check your internet connection and ensure you can access other websites.\",\n server_error:\n \"The issue is on our end. Our team has been notified and is working to fix it.\",\n temporarily_unavailable:\n \"This is usually temporary. Try again in a few minutes.\",\n};\n"],"names":["normalizeRedirectUrl","redirectTo","origin","basePath","CallbackHandler","handleCallback","options","useZudoku","executeCallback","useSuspenseQuery","url","errorParam","errorDescription","errorUri","OAuthAuthorizationError","joinUrl","Navigate","errorDetailsMap","OAuthErrorPage","error","login","useAuth","type","details","jsxs","jsx","Heading","titles","Typography","Button","Link","HomeIcon","helpMessages"],"mappings":"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"}
|