@workos-inc/widgets 1.5.0 → 1.5.1

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 (94) hide show
  1. package/CHANGELOG.md +19 -8
  2. package/dist/cjs/admin-portal-domain-verification.client.cjs +2 -3
  3. package/dist/cjs/admin-portal-domain-verification.client.cjs.map +1 -1
  4. package/dist/cjs/admin-portal-sso-connection-client.cjs +3 -4
  5. package/dist/cjs/admin-portal-sso-connection-client.cjs.map +1 -1
  6. package/dist/cjs/api/api-provider.cjs +27 -19
  7. package/dist/cjs/api/api-provider.cjs.map +1 -1
  8. package/dist/cjs/api/api-provider.d.cts +4 -3
  9. package/dist/cjs/api/utils.cjs +10 -0
  10. package/dist/cjs/api/utils.cjs.map +1 -1
  11. package/dist/cjs/api/utils.d.cts +7 -2
  12. package/dist/cjs/api/widgets-api-client.cjs +11 -5
  13. package/dist/cjs/api/widgets-api-client.cjs.map +1 -1
  14. package/dist/cjs/api-keys-client.cjs +3 -8
  15. package/dist/cjs/api-keys-client.cjs.map +1 -1
  16. package/dist/cjs/lib/add-mfa-dialog.cjs +1 -1
  17. package/dist/cjs/lib/add-mfa-dialog.cjs.map +1 -1
  18. package/dist/cjs/lib/admin-portal-domain-verification.cjs +25 -18
  19. package/dist/cjs/lib/admin-portal-domain-verification.cjs.map +1 -1
  20. package/dist/cjs/lib/admin-portal-sso-connection.cjs +5 -27
  21. package/dist/cjs/lib/admin-portal-sso-connection.cjs.map +1 -1
  22. package/dist/cjs/lib/card-list.cjs.map +1 -0
  23. package/dist/cjs/lib/errors.cjs +1 -1
  24. package/dist/cjs/lib/errors.cjs.map +1 -1
  25. package/dist/cjs/lib/generic-error.cjs +27 -38
  26. package/dist/cjs/lib/generic-error.cjs.map +1 -1
  27. package/dist/cjs/lib/generic-error.d.cts +5 -1
  28. package/dist/cjs/lib/use-permissions.cjs +7 -14
  29. package/dist/cjs/lib/use-permissions.cjs.map +1 -1
  30. package/dist/cjs/lib/use-permissions.d.cts +1 -1
  31. package/dist/cjs/lib/user-security.cjs +1 -1
  32. package/dist/cjs/lib/user-security.cjs.map +1 -1
  33. package/dist/cjs/lib/user-sessions.cjs +1 -1
  34. package/dist/cjs/lib/user-sessions.cjs.map +1 -1
  35. package/dist/cjs/organization-switcher.client.cjs +2 -4
  36. package/dist/cjs/organization-switcher.client.cjs.map +1 -1
  37. package/dist/cjs/user-profile.client.cjs +2 -6
  38. package/dist/cjs/user-profile.client.cjs.map +1 -1
  39. package/dist/cjs/user-security.client.cjs +5 -4
  40. package/dist/cjs/user-security.client.cjs.map +1 -1
  41. package/dist/cjs/user-sessions.client.cjs +8 -12
  42. package/dist/cjs/user-sessions.client.cjs.map +1 -1
  43. package/dist/cjs/users-management.client.cjs +3 -9
  44. package/dist/cjs/users-management.client.cjs.map +1 -1
  45. package/dist/esm/admin-portal-domain-verification.client.js +3 -4
  46. package/dist/esm/admin-portal-domain-verification.client.js.map +1 -1
  47. package/dist/esm/admin-portal-sso-connection-client.js +4 -5
  48. package/dist/esm/admin-portal-sso-connection-client.js.map +1 -1
  49. package/dist/esm/api/api-provider.d.ts +4 -3
  50. package/dist/esm/api/api-provider.js +26 -19
  51. package/dist/esm/api/api-provider.js.map +1 -1
  52. package/dist/esm/api/utils.d.ts +7 -2
  53. package/dist/esm/api/utils.js +9 -0
  54. package/dist/esm/api/utils.js.map +1 -1
  55. package/dist/esm/api/widgets-api-client.js +11 -5
  56. package/dist/esm/api/widgets-api-client.js.map +1 -1
  57. package/dist/esm/api-keys-client.js +4 -9
  58. package/dist/esm/api-keys-client.js.map +1 -1
  59. package/dist/esm/lib/add-mfa-dialog.js +1 -1
  60. package/dist/esm/lib/add-mfa-dialog.js.map +1 -1
  61. package/dist/esm/lib/admin-portal-domain-verification.js +25 -18
  62. package/dist/esm/lib/admin-portal-domain-verification.js.map +1 -1
  63. package/dist/esm/lib/admin-portal-sso-connection.js +5 -27
  64. package/dist/esm/lib/admin-portal-sso-connection.js.map +1 -1
  65. package/dist/esm/lib/card-list.js.map +1 -0
  66. package/dist/esm/lib/errors.js +1 -1
  67. package/dist/esm/lib/errors.js.map +1 -1
  68. package/dist/esm/lib/generic-error.d.ts +5 -1
  69. package/dist/esm/lib/generic-error.js +27 -40
  70. package/dist/esm/lib/generic-error.js.map +1 -1
  71. package/dist/esm/lib/use-permissions.d.ts +1 -1
  72. package/dist/esm/lib/use-permissions.js +8 -15
  73. package/dist/esm/lib/use-permissions.js.map +1 -1
  74. package/dist/esm/lib/user-security.js +1 -1
  75. package/dist/esm/lib/user-security.js.map +1 -1
  76. package/dist/esm/lib/user-sessions.js +1 -1
  77. package/dist/esm/lib/user-sessions.js.map +1 -1
  78. package/dist/esm/organization-switcher.client.js +3 -5
  79. package/dist/esm/organization-switcher.client.js.map +1 -1
  80. package/dist/esm/user-profile.client.js +3 -7
  81. package/dist/esm/user-profile.client.js.map +1 -1
  82. package/dist/esm/user-security.client.js +6 -5
  83. package/dist/esm/user-security.client.js.map +1 -1
  84. package/dist/esm/user-sessions.client.js +10 -14
  85. package/dist/esm/user-sessions.client.js.map +1 -1
  86. package/dist/esm/users-management.client.js +4 -10
  87. package/dist/esm/users-management.client.js.map +1 -1
  88. package/package.json +4 -1
  89. package/dist/cjs/card-list.cjs.map +0 -1
  90. package/dist/esm/card-list.js.map +0 -1
  91. /package/dist/cjs/{card-list.cjs → lib/card-list.cjs} +0 -0
  92. /package/dist/cjs/{card-list.d.cts → lib/card-list.d.cts} +0 -0
  93. /package/dist/esm/{card-list.d.ts → lib/card-list.d.ts} +0 -0
  94. /package/dist/esm/{card-list.js → lib/card-list.js} +0 -0
@@ -1,5 +1,8 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
+ import { useQuery } from "@tanstack/react-query";
2
3
  import * as React from "react";
4
+ import { useIsHydrated } from "../lib/use-is-hydrated.js";
5
+ import { getClaims } from "./utils.js";
3
6
  const ApiContext = React.createContext(void 0);
4
7
  const ApiProvider = ({
5
8
  authToken,
@@ -7,7 +10,20 @@ const ApiProvider = ({
7
10
  children,
8
11
  widgetType
9
12
  }) => {
10
- const authTokenPromiseOrString = typeof authToken === "string" ? authToken : authToken();
13
+ const authTokenQuery = useQuery({
14
+ initialData: typeof authToken === "string" ? {
15
+ authToken,
16
+ permissions: getClaims(authToken).permissions
17
+ } : void 0,
18
+ queryFn: async () => {
19
+ const resolvedToken = typeof authToken === "string" ? authToken : await authToken();
20
+ return {
21
+ authToken: resolvedToken,
22
+ permissions: getClaims(resolvedToken).permissions
23
+ };
24
+ },
25
+ queryKey: ["authToken"]
26
+ });
11
27
  const [elevatedAccess, setElevatedAccess] = React.useState();
12
28
  const elevatedAccessTimeout = React.useRef(void 0);
13
29
  React.useEffect(() => {
@@ -31,15 +47,15 @@ const ApiProvider = ({
31
47
  }, [elevatedAccess]);
32
48
  const value = React.useMemo(
33
49
  () => ({
34
- authToken: authTokenPromiseOrString,
35
- authTokenQueryKey: getAuthTokenQueryKey(authTokenPromiseOrString),
50
+ authToken: authTokenQuery.data?.authToken,
51
+ permissions: authTokenQuery.data?.permissions,
36
52
  baseUrl,
37
53
  elevatedAccess,
38
54
  setElevatedAccess,
39
55
  widgetType
40
56
  }),
41
57
  [
42
- authTokenPromiseOrString,
58
+ authTokenQuery.data,
43
59
  baseUrl,
44
60
  elevatedAccess,
45
61
  setElevatedAccess,
@@ -59,24 +75,15 @@ const useElevatedAccessToken = () => {
59
75
  const { elevatedAccess, setElevatedAccess } = useApi();
60
76
  return { elevatedAccess, setElevatedAccess };
61
77
  };
62
- const PromiseKey = /* @__PURE__ */ new WeakMap();
63
- function getAuthTokenQueryKey(authTokenPromiseOrString) {
64
- if (typeof authTokenPromiseOrString === "string") {
65
- return authTokenPromiseOrString;
66
- }
67
- const authTokenPromise = authTokenPromiseOrString;
68
- const promiseKey = PromiseKey.get(authTokenPromise);
69
- if (!promiseKey) {
70
- const newPromiseKey = `${Math.random()}`;
71
- PromiseKey.set(authTokenPromise, newPromiseKey);
72
- return newPromiseKey;
73
- } else {
74
- return promiseKey;
75
- }
76
- }
78
+ const useApiReady = () => {
79
+ const { authToken } = useApi();
80
+ const isHydrated = useIsHydrated();
81
+ return isHydrated && authToken !== void 0;
82
+ };
77
83
  export {
78
84
  ApiProvider,
79
85
  useApi,
86
+ useApiReady,
80
87
  useElevatedAccessToken
81
88
  };
82
89
  //# sourceMappingURL=api-provider.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/api/api-provider.tsx"],"sourcesContent":["import * as React from \"react\";\n\nexport type WidgetType =\n | \"admin-portal-domain-verification\"\n | \"user-management\"\n | \"organization-switcher\"\n | \"user-sessions\"\n | \"user-security\"\n | \"user-profile\"\n | \"admin-portal-sso-connection\"\n | \"api-keys\";\n\nexport type AuthToken = string | (() => Promise<string>);\n\ninterface ElevatedAccess {\n token: string;\n expiresAt: string;\n}\n\ninterface ApiConfig {\n authToken: Promise<string> | string;\n authTokenQueryKey: string;\n baseUrl: string;\n widgetType: WidgetType;\n elevatedAccess?: ElevatedAccess;\n setElevatedAccess: (elevatedAccess?: ElevatedAccess) => void;\n}\n\nconst ApiContext = React.createContext<ApiConfig | undefined>(undefined);\n\ninterface ApiProviderProps {\n authToken: AuthToken;\n baseUrl: string;\n children: React.ReactNode;\n widgetType: WidgetType;\n}\n\nexport const ApiProvider = ({\n authToken,\n baseUrl,\n children,\n widgetType,\n}: ApiProviderProps) => {\n const authTokenPromiseOrString =\n typeof authToken === \"string\" ? authToken : authToken();\n const [elevatedAccess, setElevatedAccess] = React.useState<ElevatedAccess>();\n const elevatedAccessTimeout = React.useRef<number | undefined>(undefined);\n\n // This effect manages the expiration of elevated access tokens\n // When an elevated access token is present, it checks every 30 seconds if the token has expired\n // If the token has expired (current time > expiration time), it clears the elevated access\n React.useEffect(() => {\n if (elevatedAccessTimeout.current) {\n window.clearInterval(elevatedAccessTimeout.current);\n }\n\n if (elevatedAccess) {\n elevatedAccessTimeout.current = window.setInterval(() => {\n const now = new Date();\n const expiresAtDate = new Date(elevatedAccess.expiresAt);\n\n // Reset the elevated access if it has expired\n if (now > expiresAtDate) {\n setElevatedAccess(undefined);\n }\n }, 30_000); // every 30 seconds\n }\n\n return () => {\n if (elevatedAccessTimeout.current) {\n window.clearInterval(elevatedAccessTimeout.current);\n }\n };\n }, [elevatedAccess]);\n\n const value = React.useMemo(\n () => ({\n authToken: authTokenPromiseOrString,\n authTokenQueryKey: getAuthTokenQueryKey(authTokenPromiseOrString),\n baseUrl,\n elevatedAccess,\n setElevatedAccess,\n widgetType,\n }),\n [\n authTokenPromiseOrString,\n baseUrl,\n elevatedAccess,\n setElevatedAccess,\n widgetType,\n ],\n );\n\n return <ApiContext.Provider value={value}>{children}</ApiContext.Provider>;\n};\n\nexport const useApi = () => {\n const context = React.useContext(ApiContext);\n\n if (context === undefined) {\n throw new Error(\"useApi must be used within an ApiProvider\");\n }\n\n return context;\n};\n\nexport const useElevatedAccessToken = () => {\n const { elevatedAccess, setElevatedAccess } = useApi();\n\n return { elevatedAccess, setElevatedAccess };\n};\n\n// Map promises to a UUID that they can be identified by\nconst PromiseKey = new WeakMap<Promise<string>, string>();\n/*\n *\n * @param getAccessToken - Async function that returns a promise that resolves to a string\n * @returns a resolved string or null from the access token promise\n */\nfunction getAuthTokenQueryKey(\n authTokenPromiseOrString: Promise<string> | string,\n): string {\n // Need to go by equality of the promise to avoid scenarios where\n // 1. The promise is the same, but the function changes\n // 2. The function is the same, but the promise is different ⚠️\n //\n // This does have the unfortunate side effect where if the function result\n // isn't memoized somehow, then it will invalidate the query on every render.\n // This doesn't occur with the current use case of getAccessToken from\n // useAuth, but could in a custom implementation.\n //\n // Other things I explored:\n // 1. Removing promise api, and force user to resolve the promise\n // themselves. The user can already do this with the string API, so\n // it's not necessary, and they could run into issues 1, or 2 if\n // implemented wrong.\n // 2. Memoizing the function - this results in issue 2, where the function\n // is static, but the promise changes. I believe this actually is the\n // case with useAuth since it only sets the client once on initialization,\n // and binds the function to the client after that promise resolves.\n\n if (typeof authTokenPromiseOrString === \"string\") {\n return authTokenPromiseOrString;\n }\n\n const authTokenPromise = authTokenPromiseOrString;\n\n // Cannot memoize on the function because it could remain the same while\n // returning a different promise (and useAuth behaves this way).\n\n const promiseKey = PromiseKey.get(authTokenPromise);\n\n // Side effect, but we we're using a weak map, so it should be pretty safe\n if (!promiseKey) {\n const newPromiseKey = `${Math.random()}`;\n PromiseKey.set(authTokenPromise, newPromiseKey);\n return newPromiseKey;\n } else {\n return promiseKey;\n }\n}\n"],"mappings":"AA6FS;AA7FT,YAAY,WAAW;AA4BvB,MAAM,aAAa,MAAM,cAAqC,MAAS;AAShE,MAAM,cAAc,CAAC;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAwB;AACtB,QAAM,2BACJ,OAAO,cAAc,WAAW,YAAY,UAAU;AACxD,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAyB;AAC3E,QAAM,wBAAwB,MAAM,OAA2B,MAAS;AAKxE,QAAM,UAAU,MAAM;AACpB,QAAI,sBAAsB,SAAS;AACjC,aAAO,cAAc,sBAAsB,OAAO;AAAA,IACpD;AAEA,QAAI,gBAAgB;AAClB,4BAAsB,UAAU,OAAO,YAAY,MAAM;AACvD,cAAM,MAAM,oBAAI,KAAK;AACrB,cAAM,gBAAgB,IAAI,KAAK,eAAe,SAAS;AAGvD,YAAI,MAAM,eAAe;AACvB,4BAAkB,MAAS;AAAA,QAC7B;AAAA,MACF,GAAG,GAAM;AAAA,IACX;AAEA,WAAO,MAAM;AACX,UAAI,sBAAsB,SAAS;AACjC,eAAO,cAAc,sBAAsB,OAAO;AAAA,MACpD;AAAA,IACF;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAEnB,QAAM,QAAQ,MAAM;AAAA,IAClB,OAAO;AAAA,MACL,WAAW;AAAA,MACX,mBAAmB,qBAAqB,wBAAwB;AAAA,MAChE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,oBAAC,WAAW,UAAX,EAAoB,OAAe,UAAS;AACtD;AAEO,MAAM,SAAS,MAAM;AAC1B,QAAM,UAAU,MAAM,WAAW,UAAU;AAE3C,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAEA,SAAO;AACT;AAEO,MAAM,yBAAyB,MAAM;AAC1C,QAAM,EAAE,gBAAgB,kBAAkB,IAAI,OAAO;AAErD,SAAO,EAAE,gBAAgB,kBAAkB;AAC7C;AAGA,MAAM,aAAa,oBAAI,QAAiC;AAMxD,SAAS,qBACP,0BACQ;AAoBR,MAAI,OAAO,6BAA6B,UAAU;AAChD,WAAO;AAAA,EACT;AAEA,QAAM,mBAAmB;AAKzB,QAAM,aAAa,WAAW,IAAI,gBAAgB;AAGlD,MAAI,CAAC,YAAY;AACf,UAAM,gBAAgB,GAAG,KAAK,OAAO,CAAC;AACtC,eAAW,IAAI,kBAAkB,aAAa;AAC9C,WAAO;AAAA,EACT,OAAO;AACL,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/api/api-provider.tsx"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport { useIsHydrated } from \"../lib/use-is-hydrated.js\";\nimport { getClaims } from \"./utils.js\";\n\nexport type WidgetType =\n | \"admin-portal-domain-verification\"\n | \"user-management\"\n | \"organization-switcher\"\n | \"user-sessions\"\n | \"user-security\"\n | \"user-profile\"\n | \"admin-portal-sso-connection\"\n | \"api-keys\";\n\nexport type AuthToken = string | (() => Promise<string>);\n\ninterface ElevatedAccess {\n token: string;\n expiresAt: string;\n}\n\ninterface ApiConfig {\n authToken: string | undefined;\n permissions: string[] | undefined;\n baseUrl: string;\n widgetType: WidgetType;\n elevatedAccess?: ElevatedAccess;\n setElevatedAccess: (elevatedAccess?: ElevatedAccess) => void;\n}\n\nconst ApiContext = React.createContext<ApiConfig | undefined>(undefined);\n\ninterface ApiProviderProps {\n authToken: AuthToken;\n baseUrl: string;\n children: React.ReactNode;\n widgetType: WidgetType;\n}\n\nexport const ApiProvider = ({\n authToken,\n baseUrl,\n children,\n widgetType,\n}: ApiProviderProps) => {\n const authTokenQuery = useQuery({\n initialData:\n typeof authToken === \"string\"\n ? {\n authToken,\n permissions: getClaims(authToken).permissions,\n }\n : undefined,\n queryFn: async () => {\n const resolvedToken =\n typeof authToken === \"string\" ? authToken : await authToken();\n\n return {\n authToken: resolvedToken,\n permissions: getClaims(resolvedToken).permissions,\n };\n },\n queryKey: [\"authToken\"],\n });\n\n const [elevatedAccess, setElevatedAccess] = React.useState<ElevatedAccess>();\n const elevatedAccessTimeout = React.useRef<number | undefined>(undefined);\n\n // This effect manages the expiration of elevated access tokens\n // When an elevated access token is present, it checks every 30 seconds if the token has expired\n // If the token has expired (current time > expiration time), it clears the elevated access\n React.useEffect(() => {\n if (elevatedAccessTimeout.current) {\n window.clearInterval(elevatedAccessTimeout.current);\n }\n\n if (elevatedAccess) {\n elevatedAccessTimeout.current = window.setInterval(() => {\n const now = new Date();\n const expiresAtDate = new Date(elevatedAccess.expiresAt);\n\n // Reset the elevated access if it has expired\n if (now > expiresAtDate) {\n setElevatedAccess(undefined);\n }\n }, 30_000); // every 30 seconds\n }\n\n return () => {\n if (elevatedAccessTimeout.current) {\n window.clearInterval(elevatedAccessTimeout.current);\n }\n };\n }, [elevatedAccess]);\n\n const value = React.useMemo(\n () => ({\n authToken: authTokenQuery.data?.authToken,\n permissions: authTokenQuery.data?.permissions,\n baseUrl,\n elevatedAccess,\n setElevatedAccess,\n widgetType,\n }),\n [\n authTokenQuery.data,\n baseUrl,\n elevatedAccess,\n setElevatedAccess,\n widgetType,\n ],\n );\n\n return <ApiContext.Provider value={value}>{children}</ApiContext.Provider>;\n};\n\nexport const useApi = () => {\n const context = React.useContext(ApiContext);\n\n if (context === undefined) {\n throw new Error(\"useApi must be used within an ApiProvider\");\n }\n\n return context;\n};\n\nexport const useElevatedAccessToken = () => {\n const { elevatedAccess, setElevatedAccess } = useApi();\n\n return { elevatedAccess, setElevatedAccess };\n};\n\nexport const useApiReady = () => {\n const { authToken } = useApi();\n const isHydrated = useIsHydrated();\n\n return isHydrated && authToken !== undefined;\n};\n"],"mappings":"AAkHS;AAlHT,SAAS,gBAAgB;AACzB,YAAY,WAAW;AACvB,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AA4B1B,MAAM,aAAa,MAAM,cAAqC,MAAS;AAShE,MAAM,cAAc,CAAC;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAwB;AACtB,QAAM,iBAAiB,SAAS;AAAA,IAC9B,aACE,OAAO,cAAc,WACjB;AAAA,MACE;AAAA,MACA,aAAa,UAAU,SAAS,EAAE;AAAA,IACpC,IACA;AAAA,IACN,SAAS,YAAY;AACnB,YAAM,gBACJ,OAAO,cAAc,WAAW,YAAY,MAAM,UAAU;AAE9D,aAAO;AAAA,QACL,WAAW;AAAA,QACX,aAAa,UAAU,aAAa,EAAE;AAAA,MACxC;AAAA,IACF;AAAA,IACA,UAAU,CAAC,WAAW;AAAA,EACxB,CAAC;AAED,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAyB;AAC3E,QAAM,wBAAwB,MAAM,OAA2B,MAAS;AAKxE,QAAM,UAAU,MAAM;AACpB,QAAI,sBAAsB,SAAS;AACjC,aAAO,cAAc,sBAAsB,OAAO;AAAA,IACpD;AAEA,QAAI,gBAAgB;AAClB,4BAAsB,UAAU,OAAO,YAAY,MAAM;AACvD,cAAM,MAAM,oBAAI,KAAK;AACrB,cAAM,gBAAgB,IAAI,KAAK,eAAe,SAAS;AAGvD,YAAI,MAAM,eAAe;AACvB,4BAAkB,MAAS;AAAA,QAC7B;AAAA,MACF,GAAG,GAAM;AAAA,IACX;AAEA,WAAO,MAAM;AACX,UAAI,sBAAsB,SAAS;AACjC,eAAO,cAAc,sBAAsB,OAAO;AAAA,MACpD;AAAA,IACF;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAEnB,QAAM,QAAQ,MAAM;AAAA,IAClB,OAAO;AAAA,MACL,WAAW,eAAe,MAAM;AAAA,MAChC,aAAa,eAAe,MAAM;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE,eAAe;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,oBAAC,WAAW,UAAX,EAAoB,OAAe,UAAS;AACtD;AAEO,MAAM,SAAS,MAAM;AAC1B,QAAM,UAAU,MAAM,WAAW,UAAU;AAE3C,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAEA,SAAO;AACT;AAEO,MAAM,yBAAyB,MAAM;AAC1C,QAAM,EAAE,gBAAgB,kBAAkB,IAAI,OAAO;AAErD,SAAO,EAAE,gBAAgB,kBAAkB;AAC7C;AAEO,MAAM,cAAc,MAAM;AAC/B,QAAM,EAAE,UAAU,IAAI,OAAO;AAC7B,QAAM,aAAa,cAAc;AAEjC,SAAO,cAAc,cAAc;AACrC;","names":[]}
@@ -1,4 +1,4 @@
1
- declare function getAuthHeaders(authToken: string): HeadersInit;
1
+ declare function getAuthHeaders(authToken?: string): HeadersInit;
2
2
  declare function isObjectLike(value: unknown): value is Record<string, unknown>;
3
3
  declare function isErrorLike(value: unknown): value is Record<string, unknown> & {
4
4
  message: string;
@@ -7,5 +7,10 @@ declare function parseErrorResponse(response: Response): Promise<{
7
7
  message: string;
8
8
  status: number;
9
9
  }>;
10
+ type Claims = {
11
+ sid: string;
12
+ permissions?: string[];
13
+ };
14
+ declare function getClaims(accessToken: string): Claims;
10
15
 
11
- export { getAuthHeaders, isErrorLike, isObjectLike, parseErrorResponse };
16
+ export { getAuthHeaders, getClaims, isErrorLike, isObjectLike, parseErrorResponse };
@@ -1,5 +1,10 @@
1
1
  import { WIDGETS_API_VERSION } from "./constants.js";
2
2
  function getAuthHeaders(authToken) {
3
+ if (!authToken) {
4
+ return {
5
+ "WorkOS-Widgets-Version": WIDGETS_API_VERSION
6
+ };
7
+ }
3
8
  return {
4
9
  Authorization: `Bearer ${authToken}`,
5
10
  "WorkOS-Widgets-Version": WIDGETS_API_VERSION
@@ -32,8 +37,12 @@ async function parseErrorResponse(response) {
32
37
  };
33
38
  }
34
39
  }
40
+ function getClaims(accessToken) {
41
+ return JSON.parse(atob(accessToken.split(".")[1]));
42
+ }
35
43
  export {
36
44
  getAuthHeaders,
45
+ getClaims,
37
46
  isErrorLike,
38
47
  isObjectLike,
39
48
  parseErrorResponse
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/api/utils.ts"],"sourcesContent":["import { WIDGETS_API_VERSION } from \"./constants.js\";\n\nexport function getAuthHeaders(authToken: string): HeadersInit {\n return {\n Authorization: `Bearer ${authToken}`,\n \"WorkOS-Widgets-Version\": WIDGETS_API_VERSION,\n };\n}\n\nexport function isObjectLike(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nexport function isErrorLike(\n value: unknown,\n): value is Record<string, unknown> & { message: string } {\n return isObjectLike(value) && typeof value.message === \"string\";\n}\n\nexport async function parseErrorResponse(\n response: Response,\n): Promise<{ message: string; status: number }> {\n try {\n const json = await response.json();\n if (!isObjectLike(json) || typeof json.message !== \"string\") {\n return {\n status: response.status,\n message: response.statusText,\n };\n }\n return {\n ...json,\n status: response.status,\n message: json.message || response.statusText,\n };\n } catch {\n return {\n status: response.status,\n message: response.statusText,\n };\n }\n}\n"],"mappings":"AAAA,SAAS,2BAA2B;AAE7B,SAAS,eAAe,WAAgC;AAC7D,SAAO;AAAA,IACL,eAAe,UAAU,SAAS;AAAA,IAClC,0BAA0B;AAAA,EAC5B;AACF;AAEO,SAAS,aAAa,OAAkD;AAC7E,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEO,SAAS,YACd,OACwD;AACxD,SAAO,aAAa,KAAK,KAAK,OAAO,MAAM,YAAY;AACzD;AAEA,eAAsB,mBACpB,UAC8C;AAC9C,MAAI;AACF,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,CAAC,aAAa,IAAI,KAAK,OAAO,KAAK,YAAY,UAAU;AAC3D,aAAO;AAAA,QACL,QAAQ,SAAS;AAAA,QACjB,SAAS,SAAS;AAAA,MACpB;AAAA,IACF;AACA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ,SAAS;AAAA,MACjB,SAAS,KAAK,WAAW,SAAS;AAAA,IACpC;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,MACL,QAAQ,SAAS;AAAA,MACjB,SAAS,SAAS;AAAA,IACpB;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/api/utils.ts"],"sourcesContent":["import { WIDGETS_API_VERSION } from \"./constants.js\";\n\nexport function getAuthHeaders(authToken?: string): HeadersInit {\n if (!authToken) {\n return {\n \"WorkOS-Widgets-Version\": WIDGETS_API_VERSION,\n };\n }\n\n return {\n Authorization: `Bearer ${authToken}`,\n \"WorkOS-Widgets-Version\": WIDGETS_API_VERSION,\n };\n}\n\nexport function isObjectLike(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nexport function isErrorLike(\n value: unknown,\n): value is Record<string, unknown> & { message: string } {\n return isObjectLike(value) && typeof value.message === \"string\";\n}\n\nexport async function parseErrorResponse(\n response: Response,\n): Promise<{ message: string; status: number }> {\n try {\n const json = await response.json();\n if (!isObjectLike(json) || typeof json.message !== \"string\") {\n return {\n status: response.status,\n message: response.statusText,\n };\n }\n return {\n ...json,\n status: response.status,\n message: json.message || response.statusText,\n };\n } catch {\n return {\n status: response.status,\n message: response.statusText,\n };\n }\n}\n\ntype Claims = {\n sid: string;\n permissions?: string[];\n};\n\nexport function getClaims(accessToken: string): Claims {\n return JSON.parse(atob(accessToken.split(\".\")[1]));\n}\n"],"mappings":"AAAA,SAAS,2BAA2B;AAE7B,SAAS,eAAe,WAAiC;AAC9D,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,0BAA0B;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AAAA,IACL,eAAe,UAAU,SAAS;AAAA,IAClC,0BAA0B;AAAA,EAC5B;AACF;AAEO,SAAS,aAAa,OAAkD;AAC7E,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEO,SAAS,YACd,OACwD;AACxD,SAAO,aAAa,KAAK,KAAK,OAAO,MAAM,YAAY;AACzD;AAEA,eAAsB,mBACpB,UAC8C;AAC9C,MAAI;AACF,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,CAAC,aAAa,IAAI,KAAK,OAAO,KAAK,YAAY,UAAU;AAC3D,aAAO;AAAA,QACL,QAAQ,SAAS;AAAA,QACjB,SAAS,SAAS;AAAA,MACpB;AAAA,IACF;AACA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ,SAAS;AAAA,MACjB,SAAS,KAAK,WAAW,SAAS;AAAA,IACpC;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,MACL,QAAQ,SAAS;AAAA,MACjB,SAAS,SAAS;AAAA,IACpB;AAAA,EACF;AACF;AAOO,SAAS,UAAU,aAA6B;AACrD,SAAO,KAAK,MAAM,KAAK,YAAY,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;AACnD;","names":[]}
@@ -1,6 +1,7 @@
1
1
  import { useApi } from "./api-provider.js";
2
2
  import { ApiError, FetchError } from "./errors.js";
3
3
  import { getAuthHeaders, parseErrorResponse } from "./utils.js";
4
+ import { IncorrectPermissionsError } from "../lib/errors.js";
4
5
  const useWidgetsApiClient = () => {
5
6
  const { authToken, baseUrl, elevatedAccess, widgetType } = useApi();
6
7
  return async ({ url: pathname, method, params, data }) => {
@@ -14,7 +15,7 @@ const useWidgetsApiClient = () => {
14
15
  }
15
16
  const queryType = method.toLowerCase() === "get" ? "query" : "mutation";
16
17
  const headers = {
17
- ...getAuthHeaders(await Promise.resolve(authToken)),
18
+ ...getAuthHeaders(authToken),
18
19
  ...elevatedAccess && queryType === "mutation" ? { "x-elevated-access-token": elevatedAccess.token } : {},
19
20
  "WorkOS-Widgets-Type": widgetType,
20
21
  "Content-Type": "application/json"
@@ -33,21 +34,26 @@ const useWidgetsApiClient = () => {
33
34
  });
34
35
  if (!response.ok) {
35
36
  const { message, status } = await parseErrorResponse(response);
36
- throw new ApiError({
37
+ const ctx = {
37
38
  message,
38
39
  status,
39
40
  queryType: method.toLowerCase() === "get" ? "query" : "mutation"
40
- });
41
+ };
42
+ if (status === 403) {
43
+ throw new IncorrectPermissionsError({ context: ctx });
44
+ }
45
+ throw new ApiError(ctx);
41
46
  }
42
47
  return response.json();
43
48
  };
44
49
  };
45
50
  const useWidgetsApiQueryOptions = (queryOptions) => {
46
- const { authTokenQueryKey, baseUrl } = useApi();
51
+ const { permissions, baseUrl } = useApi();
47
52
  const queryKey = [
48
53
  // initial query key needs to go first to allow invalidation of the query name to work
49
54
  ...queryOptions.queryKey,
50
- { authTokenQueryKey, baseUrl }
55
+ permissions,
56
+ baseUrl
51
57
  ];
52
58
  return {
53
59
  ...queryOptions,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/api/widgets-api-client.ts"],"sourcesContent":["import { QueryKey } from \"@tanstack/react-query\";\nimport { useApi } from \"./api-provider.js\";\nimport { ApiError, FetchError } from \"./errors.js\";\nimport { getAuthHeaders, parseErrorResponse } from \"./utils.js\";\n\ntype WidgetsApiClient<T> = (data: {\n url: string;\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n params?: Record<string, any>;\n headers?: Record<string, any>;\n data?: BodyType<unknown>;\n signal?: AbortSignal;\n}) => Promise<T>;\n\nexport const useWidgetsApiClient = <T>(): WidgetsApiClient<T> => {\n const { authToken, baseUrl, elevatedAccess, widgetType } = useApi();\n\n return async ({ url: pathname, method, params, data }) => {\n const url = new URL(baseUrl);\n url.pathname = pathname;\n\n if (params) {\n const cleanParams = Object.fromEntries(\n Object.entries(params).filter(([_, value]) => value !== undefined),\n );\n url.search = new URLSearchParams(cleanParams).toString();\n }\n\n const queryType = method.toLowerCase() === \"get\" ? \"query\" : \"mutation\";\n const headers = {\n ...getAuthHeaders(await Promise.resolve(authToken)),\n ...(elevatedAccess && queryType === \"mutation\"\n ? { \"x-elevated-access-token\": elevatedAccess.token }\n : {}),\n \"WorkOS-Widgets-Type\": widgetType,\n \"Content-Type\": \"application/json\",\n };\n\n const response = await fetch(url, {\n method,\n cache: \"no-store\",\n headers,\n ...(data ? { body: JSON.stringify(data) } : {}),\n }).catch((error) => {\n throw new FetchError({\n message: `Failed to ${method} ${url.toString()}`,\n queryType,\n context: { error },\n });\n });\n\n if (!response.ok) {\n const { message, status } = await parseErrorResponse(response);\n\n throw new ApiError({\n message,\n status,\n queryType: method.toLowerCase() === \"get\" ? \"query\" : \"mutation\",\n });\n }\n\n return response.json();\n };\n};\n\nexport type ErrorType<ErrorData> = ErrorData;\n\nexport type BodyType<BodyData> = BodyData & { headers?: any };\n\nexport const useWidgetsApiQueryOptions = <\n QueryOptions extends { queryKey: QK },\n QK extends QueryKey,\n>(\n queryOptions: QueryOptions,\n) => {\n const { authTokenQueryKey, baseUrl } = useApi();\n const queryKey = [\n // initial query key needs to go first to allow invalidation of the query name to work\n ...queryOptions.queryKey,\n { authTokenQueryKey, baseUrl },\n ] as unknown as QK;\n\n return {\n ...queryOptions,\n queryKey: queryKey as QK,\n };\n};\n"],"mappings":"AACA,SAAS,cAAc;AACvB,SAAS,UAAU,kBAAkB;AACrC,SAAS,gBAAgB,0BAA0B;AAW5C,MAAM,sBAAsB,MAA8B;AAC/D,QAAM,EAAE,WAAW,SAAS,gBAAgB,WAAW,IAAI,OAAO;AAElE,SAAO,OAAO,EAAE,KAAK,UAAU,QAAQ,QAAQ,KAAK,MAAM;AACxD,UAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAI,WAAW;AAEf,QAAI,QAAQ;AACV,YAAM,cAAc,OAAO;AAAA,QACzB,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,KAAK,MAAM,UAAU,MAAS;AAAA,MACnE;AACA,UAAI,SAAS,IAAI,gBAAgB,WAAW,EAAE,SAAS;AAAA,IACzD;AAEA,UAAM,YAAY,OAAO,YAAY,MAAM,QAAQ,UAAU;AAC7D,UAAM,UAAU;AAAA,MACd,GAAG,eAAe,MAAM,QAAQ,QAAQ,SAAS,CAAC;AAAA,MAClD,GAAI,kBAAkB,cAAc,aAChC,EAAE,2BAA2B,eAAe,MAAM,IAClD,CAAC;AAAA,MACL,uBAAuB;AAAA,MACvB,gBAAgB;AAAA,IAClB;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,GAAI,OAAO,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,CAAC;AAAA,IAC/C,CAAC,EAAE,MAAM,CAAC,UAAU;AAClB,YAAM,IAAI,WAAW;AAAA,QACnB,SAAS,aAAa,MAAM,IAAI,IAAI,SAAS,CAAC;AAAA,QAC9C;AAAA,QACA,SAAS,EAAE,MAAM;AAAA,MACnB,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,EAAE,SAAS,OAAO,IAAI,MAAM,mBAAmB,QAAQ;AAE7D,YAAM,IAAI,SAAS;AAAA,QACjB;AAAA,QACA;AAAA,QACA,WAAW,OAAO,YAAY,MAAM,QAAQ,UAAU;AAAA,MACxD,CAAC;AAAA,IACH;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AACF;AAMO,MAAM,4BAA4B,CAIvC,iBACG;AACH,QAAM,EAAE,mBAAmB,QAAQ,IAAI,OAAO;AAC9C,QAAM,WAAW;AAAA;AAAA,IAEf,GAAG,aAAa;AAAA,IAChB,EAAE,mBAAmB,QAAQ;AAAA,EAC/B;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/api/widgets-api-client.ts"],"sourcesContent":["import { QueryKey } from \"@tanstack/react-query\";\nimport { useApi } from \"./api-provider.js\";\nimport { ApiError, FetchError } from \"./errors.js\";\nimport { getAuthHeaders, parseErrorResponse } from \"./utils.js\";\nimport { IncorrectPermissionsError } from \"../lib/errors.js\";\n\ntype WidgetsApiClient<T> = (data: {\n url: string;\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n params?: Record<string, any>;\n headers?: Record<string, any>;\n data?: BodyType<unknown>;\n signal?: AbortSignal;\n}) => Promise<T>;\n\nexport const useWidgetsApiClient = <T>(): WidgetsApiClient<T> => {\n const { authToken, baseUrl, elevatedAccess, widgetType } = useApi();\n\n return async ({ url: pathname, method, params, data }) => {\n const url = new URL(baseUrl);\n url.pathname = pathname;\n\n if (params) {\n const cleanParams = Object.fromEntries(\n Object.entries(params).filter(([_, value]) => value !== undefined),\n );\n url.search = new URLSearchParams(cleanParams).toString();\n }\n\n const queryType = method.toLowerCase() === \"get\" ? \"query\" : \"mutation\";\n const headers = {\n ...getAuthHeaders(authToken),\n ...(elevatedAccess && queryType === \"mutation\"\n ? { \"x-elevated-access-token\": elevatedAccess.token }\n : {}),\n \"WorkOS-Widgets-Type\": widgetType,\n \"Content-Type\": \"application/json\",\n };\n\n const response = await fetch(url, {\n method,\n cache: \"no-store\",\n headers,\n ...(data ? { body: JSON.stringify(data) } : {}),\n }).catch((error) => {\n throw new FetchError({\n message: `Failed to ${method} ${url.toString()}`,\n queryType,\n context: { error },\n });\n });\n\n if (!response.ok) {\n const { message, status } = await parseErrorResponse(response);\n const ctx = {\n message,\n status,\n queryType: method.toLowerCase() === \"get\" ? \"query\" : \"mutation\",\n } as const;\n\n if (status === 403) {\n throw new IncorrectPermissionsError({ context: ctx });\n }\n\n throw new ApiError(ctx);\n }\n\n return response.json();\n };\n};\n\nexport type ErrorType<ErrorData> = ErrorData;\n\nexport type BodyType<BodyData> = BodyData & { headers?: any };\n\nexport const useWidgetsApiQueryOptions = <\n QueryOptions extends { queryKey: QK },\n QK extends QueryKey,\n>(\n queryOptions: QueryOptions,\n) => {\n const { permissions, baseUrl } = useApi();\n const queryKey = [\n // initial query key needs to go first to allow invalidation of the query name to work\n ...queryOptions.queryKey,\n permissions,\n baseUrl,\n ] as unknown as QK;\n\n return {\n ...queryOptions,\n queryKey: queryKey as QK,\n };\n};\n"],"mappings":"AACA,SAAS,cAAc;AACvB,SAAS,UAAU,kBAAkB;AACrC,SAAS,gBAAgB,0BAA0B;AACnD,SAAS,iCAAiC;AAWnC,MAAM,sBAAsB,MAA8B;AAC/D,QAAM,EAAE,WAAW,SAAS,gBAAgB,WAAW,IAAI,OAAO;AAElE,SAAO,OAAO,EAAE,KAAK,UAAU,QAAQ,QAAQ,KAAK,MAAM;AACxD,UAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAI,WAAW;AAEf,QAAI,QAAQ;AACV,YAAM,cAAc,OAAO;AAAA,QACzB,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,KAAK,MAAM,UAAU,MAAS;AAAA,MACnE;AACA,UAAI,SAAS,IAAI,gBAAgB,WAAW,EAAE,SAAS;AAAA,IACzD;AAEA,UAAM,YAAY,OAAO,YAAY,MAAM,QAAQ,UAAU;AAC7D,UAAM,UAAU;AAAA,MACd,GAAG,eAAe,SAAS;AAAA,MAC3B,GAAI,kBAAkB,cAAc,aAChC,EAAE,2BAA2B,eAAe,MAAM,IAClD,CAAC;AAAA,MACL,uBAAuB;AAAA,MACvB,gBAAgB;AAAA,IAClB;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,GAAI,OAAO,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,CAAC;AAAA,IAC/C,CAAC,EAAE,MAAM,CAAC,UAAU;AAClB,YAAM,IAAI,WAAW;AAAA,QACnB,SAAS,aAAa,MAAM,IAAI,IAAI,SAAS,CAAC;AAAA,QAC9C;AAAA,QACA,SAAS,EAAE,MAAM;AAAA,MACnB,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,EAAE,SAAS,OAAO,IAAI,MAAM,mBAAmB,QAAQ;AAC7D,YAAM,MAAM;AAAA,QACV;AAAA,QACA;AAAA,QACA,WAAW,OAAO,YAAY,MAAM,QAAQ,UAAU;AAAA,MACxD;AAEA,UAAI,WAAW,KAAK;AAClB,cAAM,IAAI,0BAA0B,EAAE,SAAS,IAAI,CAAC;AAAA,MACtD;AAEA,YAAM,IAAI,SAAS,GAAG;AAAA,IACxB;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AACF;AAMO,MAAM,4BAA4B,CAIvC,iBACG;AACH,QAAM,EAAE,aAAa,QAAQ,IAAI,OAAO;AACxC,QAAM,WAAW;AAAA;AAAA,IAEf,GAAG,aAAa;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
@@ -1,9 +1,8 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { ApiProvider, useApi } from "./api/api-provider.js";
3
+ import { ApiProvider, useApiReady } from "./api/api-provider.js";
4
4
  import { ApiKeysTable } from "./lib/api-keys/api-keys-table.js";
5
5
  import { useWorkOsApiUrl } from "./lib/widgets-context.js";
6
- import { useIsHydrated } from "./lib/use-is-hydrated.js";
7
6
  import {
8
7
  ApiKeysEmptyState,
9
8
  ApiKeysLoading,
@@ -36,16 +35,12 @@ const ApiKeys = ({ authToken }) => {
36
35
  ) });
37
36
  };
38
37
  const ApiKeysContent = () => {
39
- const isHydrated = useIsHydrated();
38
+ const isApiReady = useApiReady();
40
39
  const apiKeys = useApiKeys();
41
- const context = useApi();
42
40
  const { state } = useApiKeysContext();
43
41
  useListOrganizationApiKeyPermissions({ limit: 100 });
44
- const permissionsQuery = usePermissions(
45
- "widgets:api-keys:manage",
46
- context.authToken
47
- );
48
- if (!isHydrated || apiKeys.isLoading || permissionsQuery.isLoading) {
42
+ const permissionsQuery = usePermissions("widgets:api-keys:manage");
43
+ if (!isApiReady || apiKeys.isLoading || permissionsQuery.isLoading) {
49
44
  return /* @__PURE__ */ jsx(ApiKeysLoading, {});
50
45
  }
51
46
  if (permissionsQuery.isError || apiKeys.isError) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/api-keys-client.tsx"],"sourcesContent":["\"use client\";\nimport { ApiProvider, AuthToken, useApi } from \"./api/api-provider.js\";\nimport { ApiKeysTable } from \"./lib/api-keys/api-keys-table.js\";\nimport { useWorkOsApiUrl } from \"./lib/widgets-context.js\";\nimport { useIsHydrated } from \"./lib/use-is-hydrated.js\";\nimport {\n ApiKeysEmptyState,\n ApiKeysLoading,\n ApiKeysRoot,\n} from \"./lib/api-keys/api-keys.js\";\nimport { useListOrganizationApiKeyPermissions } from \"./api/endpoint.js\";\nimport * as React from \"react\";\nimport { GenericError } from \"./lib/generic-error.js\";\nimport { ErrorBoundary } from \"./lib/error-boundary.js\";\nimport { usePermissions } from \"./lib/use-permissions.js\";\nimport {\n ApiKeysContextProvider,\n useApiKeysContext,\n} from \"./lib/api-keys/api-keys-context.js\";\nimport { useApiKeys } from \"./lib/api/api-key.js\";\nimport { ApiKeysSearchProvider } from \"./lib/api-keys/api-keys-search-provider.js\";\nimport { CreateApiKeyDialog } from \"./lib/api-keys/create-api-key.js\";\n\nexport interface ApiKeysProps {\n authToken: AuthToken;\n}\n\nexport const ApiKeys: React.FC<ApiKeysProps> = ({ authToken }) => {\n const baseUrl = useWorkOsApiUrl();\n\n return (\n <ErrorBoundary FallbackComponent={GenericError}>\n <ApiProvider\n widgetType=\"api-keys\"\n authToken={authToken}\n baseUrl={baseUrl}\n >\n <ApiKeysContextProvider>\n <CreateApiKeyDialog />\n <ApiKeysRoot>\n <ApiKeysContent />\n </ApiKeysRoot>\n </ApiKeysContextProvider>\n </ApiProvider>\n </ErrorBoundary>\n );\n};\n\nconst ApiKeysContent = () => {\n const isHydrated = useIsHydrated();\n const apiKeys = useApiKeys();\n const context = useApi();\n const { state } = useApiKeysContext();\n useListOrganizationApiKeyPermissions({ limit: 100 });\n const permissionsQuery = usePermissions(\n \"widgets:api-keys:manage\",\n context.authToken,\n );\n\n if (!isHydrated || apiKeys.isLoading || permissionsQuery.isLoading) {\n return <ApiKeysLoading />;\n }\n\n if (permissionsQuery.isError || apiKeys.isError) {\n return <GenericError error={permissionsQuery.error || apiKeys.error} />;\n }\n\n if (apiKeys.isSuccess) {\n if (apiKeys.data.data.length === 0 && !state.searchQuery) {\n return <ApiKeysEmptyState />;\n }\n\n return (\n <ApiKeysSearchProvider>\n <ApiKeysTable apiKeys={apiKeys.data} />\n </ApiKeysSearchProvider>\n );\n }\n\n return <GenericError error={apiKeys.error} />;\n};\n"],"mappings":";AAqCQ,SACE,KADF;AApCR,SAAS,aAAwB,cAAc;AAC/C,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,4CAA4C;AAErD,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B,SAAS,6BAA6B;AACtC,SAAS,0BAA0B;AAM5B,MAAM,UAAkC,CAAC,EAAE,UAAU,MAAM;AAChE,QAAM,UAAU,gBAAgB;AAEhC,SACE,oBAAC,iBAAc,mBAAmB,cAChC;AAAA,IAAC;AAAA;AAAA,MACC,YAAW;AAAA,MACX;AAAA,MACA;AAAA,MAEA,+BAAC,0BACC;AAAA,4BAAC,sBAAmB;AAAA,QACpB,oBAAC,eACC,8BAAC,kBAAe,GAClB;AAAA,SACF;AAAA;AAAA,EACF,GACF;AAEJ;AAEA,MAAM,iBAAiB,MAAM;AAC3B,QAAM,aAAa,cAAc;AACjC,QAAM,UAAU,WAAW;AAC3B,QAAM,UAAU,OAAO;AACvB,QAAM,EAAE,MAAM,IAAI,kBAAkB;AACpC,uCAAqC,EAAE,OAAO,IAAI,CAAC;AACnD,QAAM,mBAAmB;AAAA,IACvB;AAAA,IACA,QAAQ;AAAA,EACV;AAEA,MAAI,CAAC,cAAc,QAAQ,aAAa,iBAAiB,WAAW;AAClE,WAAO,oBAAC,kBAAe;AAAA,EACzB;AAEA,MAAI,iBAAiB,WAAW,QAAQ,SAAS;AAC/C,WAAO,oBAAC,gBAAa,OAAO,iBAAiB,SAAS,QAAQ,OAAO;AAAA,EACvE;AAEA,MAAI,QAAQ,WAAW;AACrB,QAAI,QAAQ,KAAK,KAAK,WAAW,KAAK,CAAC,MAAM,aAAa;AACxD,aAAO,oBAAC,qBAAkB;AAAA,IAC5B;AAEA,WACE,oBAAC,yBACC,8BAAC,gBAAa,SAAS,QAAQ,MAAM,GACvC;AAAA,EAEJ;AAEA,SAAO,oBAAC,gBAAa,OAAO,QAAQ,OAAO;AAC7C;","names":[]}
1
+ {"version":3,"sources":["../../src/api-keys-client.tsx"],"sourcesContent":["\"use client\";\nimport { ApiProvider, AuthToken, useApiReady } from \"./api/api-provider.js\";\nimport { ApiKeysTable } from \"./lib/api-keys/api-keys-table.js\";\nimport { useWorkOsApiUrl } from \"./lib/widgets-context.js\";\nimport {\n ApiKeysEmptyState,\n ApiKeysLoading,\n ApiKeysRoot,\n} from \"./lib/api-keys/api-keys.js\";\nimport { useListOrganizationApiKeyPermissions } from \"./api/endpoint.js\";\nimport * as React from \"react\";\nimport { GenericError } from \"./lib/generic-error.js\";\nimport { ErrorBoundary } from \"./lib/error-boundary.js\";\nimport { usePermissions } from \"./lib/use-permissions.js\";\nimport {\n ApiKeysContextProvider,\n useApiKeysContext,\n} from \"./lib/api-keys/api-keys-context.js\";\nimport { useApiKeys } from \"./lib/api/api-key.js\";\nimport { ApiKeysSearchProvider } from \"./lib/api-keys/api-keys-search-provider.js\";\nimport { CreateApiKeyDialog } from \"./lib/api-keys/create-api-key.js\";\n\nexport interface ApiKeysProps {\n authToken: AuthToken;\n}\n\nexport const ApiKeys: React.FC<ApiKeysProps> = ({ authToken }) => {\n const baseUrl = useWorkOsApiUrl();\n\n return (\n <ErrorBoundary FallbackComponent={GenericError}>\n <ApiProvider\n widgetType=\"api-keys\"\n authToken={authToken}\n baseUrl={baseUrl}\n >\n <ApiKeysContextProvider>\n <CreateApiKeyDialog />\n <ApiKeysRoot>\n <ApiKeysContent />\n </ApiKeysRoot>\n </ApiKeysContextProvider>\n </ApiProvider>\n </ErrorBoundary>\n );\n};\n\nconst ApiKeysContent = () => {\n const isApiReady = useApiReady();\n const apiKeys = useApiKeys();\n const { state } = useApiKeysContext();\n useListOrganizationApiKeyPermissions({ limit: 100 });\n const permissionsQuery = usePermissions(\"widgets:api-keys:manage\");\n\n if (!isApiReady || apiKeys.isLoading || permissionsQuery.isLoading) {\n return <ApiKeysLoading />;\n }\n\n if (permissionsQuery.isError || apiKeys.isError) {\n return <GenericError error={permissionsQuery.error || apiKeys.error} />;\n }\n\n if (apiKeys.isSuccess) {\n if (apiKeys.data.data.length === 0 && !state.searchQuery) {\n return <ApiKeysEmptyState />;\n }\n\n return (\n <ApiKeysSearchProvider>\n <ApiKeysTable apiKeys={apiKeys.data} />\n </ApiKeysSearchProvider>\n );\n }\n\n return <GenericError error={apiKeys.error} />;\n};\n"],"mappings":";AAoCQ,SACE,KADF;AAnCR,SAAS,aAAwB,mBAAmB;AACpD,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,4CAA4C;AAErD,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B,SAAS,6BAA6B;AACtC,SAAS,0BAA0B;AAM5B,MAAM,UAAkC,CAAC,EAAE,UAAU,MAAM;AAChE,QAAM,UAAU,gBAAgB;AAEhC,SACE,oBAAC,iBAAc,mBAAmB,cAChC;AAAA,IAAC;AAAA;AAAA,MACC,YAAW;AAAA,MACX;AAAA,MACA;AAAA,MAEA,+BAAC,0BACC;AAAA,4BAAC,sBAAmB;AAAA,QACpB,oBAAC,eACC,8BAAC,kBAAe,GAClB;AAAA,SACF;AAAA;AAAA,EACF,GACF;AAEJ;AAEA,MAAM,iBAAiB,MAAM;AAC3B,QAAM,aAAa,YAAY;AAC/B,QAAM,UAAU,WAAW;AAC3B,QAAM,EAAE,MAAM,IAAI,kBAAkB;AACpC,uCAAqC,EAAE,OAAO,IAAI,CAAC;AACnD,QAAM,mBAAmB,eAAe,yBAAyB;AAEjE,MAAI,CAAC,cAAc,QAAQ,aAAa,iBAAiB,WAAW;AAClE,WAAO,oBAAC,kBAAe;AAAA,EACzB;AAEA,MAAI,iBAAiB,WAAW,QAAQ,SAAS;AAC/C,WAAO,oBAAC,gBAAa,OAAO,iBAAiB,SAAS,QAAQ,OAAO;AAAA,EACvE;AAEA,MAAI,QAAQ,WAAW;AACrB,QAAI,QAAQ,KAAK,KAAK,WAAW,KAAK,CAAC,MAAM,aAAa;AACxD,aAAO,oBAAC,qBAAkB;AAAA,IAC5B;AAEA,WACE,oBAAC,yBACC,8BAAC,gBAAa,SAAS,QAAQ,MAAM,GACvC;AAAA,EAEJ;AAEA,SAAO,oBAAC,gBAAa,OAAO,QAAQ,OAAO;AAC7C;","names":[]}
@@ -273,7 +273,7 @@ function SecretDialog({ children, setupKey }) {
273
273
  return /* @__PURE__ */ jsxs(Dialog.Root, { children: [
274
274
  /* @__PURE__ */ jsx(Dialog.Trigger, { children }),
275
275
  /* @__PURE__ */ jsxs(
276
- Dialog.Content,
276
+ DialogContent,
277
277
  {
278
278
  maxWidth: "90vw",
279
279
  size: { initial: "3", sm: "4" },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/add-mfa-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Box,\n Code,\n Dialog,\n Flex,\n Grid,\n Link,\n Separator,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport { type ReactNode } from \"react\";\nimport * as Otp from \"./otp-input.js\";\nimport { DialogContent, PrimaryButton, SecondaryButton } from \"./elements.js\";\nimport {\n CreateTotpFactorResponse,\n CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf,\n useCreateTotpFactor,\n useVerifyTotpFactor,\n} from \"../api/endpoint.js\";\nimport { useElevatedAccessToken } from \"../api/api-provider.js\";\nimport * as Form from \"@radix-ui/react-form\";\nimport { Marker } from \"./marker.js\";\nimport { CopyButton } from \"./copy-button.js\";\nimport { useSecuritySettings } from \"./use-security-settings.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { useDialogClose } from \"./use-dialog-close.js\";\n\ninterface AddMfaDialogProps extends Dialog.RootProps {\n children?: ReactNode;\n onSuccess?: () => void;\n}\n\nexport function AddMfaDialog({\n children,\n onSuccess,\n ...props\n}: AddMfaDialogProps) {\n const [open, setOpen] = React.useState(false);\n const [manuallyTriggered, setManuallyTriggered] = React.useState(false);\n const { elevatedAccess } = useElevatedAccessToken();\n const createAuthFactor = useCreateTotpFactor();\n\n const handleVerified = async () => {\n await createAuthFactor.mutateAsync(undefined);\n };\n\n const onTriggerClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n if (elevatedAccess && !createAuthFactor.data) {\n event.preventDefault();\n setManuallyTriggered(true);\n createAuthFactor.mutate(undefined, {\n onSuccess: () => {\n setOpen(true);\n },\n });\n } else {\n setManuallyTriggered(false);\n }\n };\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <Dialog.Root\n {...props}\n open={props.open || open}\n onOpenChange={props.onOpenChange || setOpen}\n >\n <Dialog.Trigger\n onClick={onTriggerClick}\n // @ts-ignore I've to find a way to pass the loading state to the trigger\n loading={manuallyTriggered && createAuthFactor.isPending}\n >\n {children}\n </Dialog.Trigger>\n\n <DialogContent maxWidth=\"480px\">\n <ElevatedAccess onVerified={handleVerified}>\n <Content onClose={handleClose} totpFactor={createAuthFactor.data} />\n </ElevatedAccess>\n </DialogContent>\n </Dialog.Root>\n );\n}\n\ninterface ContentProps {\n totpFactor?: CreateTotpFactorResponse;\n onClose?: () => void;\n}\n\nfunction Content({ onClose, totpFactor }: ContentProps) {\n const securitySettings = useSecuritySettings();\n\n const [customError, setCustomError] = React.useState<string | null>(null);\n const totp = hasQrCode(totpFactor)\n ? totpFactor.authenticationFactor.totp\n : undefined;\n\n const verifyTotp = useVerifyTotpFactor({\n mutation: {\n onSuccess: ({ success }) => {\n if (!success) {\n setCustomError(\"Invalid passcode\");\n }\n },\n },\n });\n\n const serverError = verifyTotp.error || customError;\n const isSuccess = verifyTotp.isSuccess && !serverError;\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setCustomError(null);\n\n const formData = new FormData(event.currentTarget);\n const otpCode = formData.get(\"otp-code\")?.toString();\n\n verifyTotp.mutate({\n data: {\n authenticationChallengeId: totpFactor?.authenticationChallenge.id ?? \"\",\n code: otpCode ?? \"\",\n },\n });\n };\n\n useDialogClose(isSuccess, () => {\n securitySettings.update(\"Mfa\", true);\n });\n\n return (\n <>\n <Dialog.Title mb=\"5\">Set up an authenticator app</Dialog.Title>\n\n <Form.Root onSubmit={handleSubmit}>\n <Grid columns=\"auto 1fr\" rows=\"repeat(4, auto)\" gapX=\"3\" gapY=\"1\">\n <Grid\n rows=\"subgrid\"\n gridRow=\"span 4\"\n style={{ placeItems: \"center\" }}\n >\n <Marker>1</Marker>\n <Separator\n orientation=\"vertical\"\n size=\"4\"\n style={{ width: \"2px\" }}\n />\n <Marker>2</Marker>\n <div />\n </Grid>\n\n <Grid rows=\"subgrid\" gridRow=\"span 4\">\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Scan the QR code\n </Text>\n <Flex direction=\"column\" gap=\"1\">\n <Text as=\"p\" size=\"2\">\n Use an authenticator app like{\" \"}\n <Link\n href=\"https://1password.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n 1Password\n </Link>\n ,{\" \"}\n <Link\n href=\"https://apps.apple.com/us/app/google-authenticator/id388497605\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Google Authenticator\n </Link>\n ,{\" \"}\n <Link\n href=\"https://authy.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Authy\n </Link>\n , or{\" \"}\n <Link\n href=\"https://www.microsoft.com/en-gb/security/mobile-authenticator-app\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Microsoft Authenticator\n </Link>{\" \"}\n to scan the QR code below.\n </Text>\n <Flex align=\"center\" gap=\"5\" my=\"5\">\n <Grid\n position=\"relative\"\n width=\"160px\"\n height=\"160px\"\n p=\"2\"\n style={{\n border: \"1px solid var(--gray-7)\",\n borderRadius: \"var(--radius-4)\",\n background: \"var(--gray-2)\",\n overflow: \"hidden\",\n }}\n >\n {totp?.qr_code && (\n <Box asChild width=\"100%\" height=\"auto\">\n <img\n alt=\"Scan this QR code to enroll\"\n aria-describedby=\"secret-note\"\n height=\"160\"\n src={totp.qr_code}\n style={{ userSelect: \"none\", background: \"white\" }}\n width=\"160\"\n />\n </Box>\n )}\n </Grid>\n\n <Flex direction=\"column\" gap=\"1\" align=\"start\">\n <Text color=\"gray\" id=\"secret-note\" size=\"2\">\n Can‘t scan the code?{\" \"}\n </Text>\n\n <SecretDialog setupKey={totp?.secret ?? \"\"}>\n <SecondaryButton\n size=\"1\"\n disabled={verifyTotp.isPending || isSuccess}\n >\n View setup key\n </SecondaryButton>\n </SecretDialog>\n </Flex>\n </Flex>\n </Flex>\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Get verification passcode\n </Text>\n <Flex direction=\"column\" gap=\"4\">\n <Text as=\"p\" size=\"2\">\n Enter the 6-digit passcode from your authenticator app.\n </Text>\n\n <Flex direction=\"column\" gap=\"2\">\n <Otp.Root\n autoSubmit\n gap=\"3\"\n justify=\"start\"\n name=\"otp-code\"\n rows=\"48px\"\n columns=\"repeat(6, 48px)\"\n readOnly={verifyTotp.isPending || isSuccess}\n >\n <Otp.Input required autoFocus autoComplete=\"off\" />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n </Otp.Root>\n\n {serverError && (\n <Text size=\"2\" color=\"red\">\n {getMutationErrorMessage(serverError)}\n </Text>\n )}\n </Flex>\n </Flex>\n </Grid>\n </Grid>\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <SecondaryButton disabled={verifyTotp.isPending || isSuccess}>\n Cancel\n </SecondaryButton>\n </Dialog.Close>\n\n <SaveButton\n asChild\n loading={verifyTotp.isPending}\n done={isSuccess}\n onDone={onClose}\n >\n <PrimaryButton type=\"submit\">Confirm</PrimaryButton>\n </SaveButton>\n </Flex>\n </Form.Root>\n\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">\n {getMutationErrorMessage(serverError)}\n </section>\n </VisuallyHidden>\n </>\n );\n}\n\ninterface SecretDialogProps extends React.PropsWithChildren {\n setupKey: string;\n}\n\nfunction SecretDialog({ children, setupKey }: SecretDialogProps) {\n return (\n <Dialog.Root>\n <Dialog.Trigger>{children}</Dialog.Trigger>\n <Dialog.Content\n maxWidth=\"90vw\"\n size={{ initial: \"3\", sm: \"4\" }}\n minWidth=\"300px\"\n width=\"fit-content\"\n >\n <Dialog.Title size=\"2\" weight=\"regular\">\n Your setup key\n </Dialog.Title>\n <Dialog.Description>\n <Text size=\"6\">\n <Code variant=\"ghost\" style={{ letterSpacing: \"0.15rem\" }}>\n {setupKey}\n </Code>\n </Text>\n </Dialog.Description>\n\n <Flex align=\"center\" gap=\"3\" justify=\"end\" mt=\"5\">\n <Dialog.Close>\n <CopyButton asChild value={setupKey}>\n <PrimaryButton>Copy and close</PrimaryButton>\n </CopyButton>\n </Dialog.Close>\n </Flex>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\nfunction getMutationErrorMessage(error: unknown) {\n let message = \"Something went wrong, please try again\";\n\n if (typeof error === \"string\") {\n message = error;\n }\n\n if (error instanceof Error) {\n message = error.message;\n }\n\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n message = error.message;\n }\n\n if (message === \"Invalid passcode\") {\n message = \"Invalid passcode, please try again\";\n }\n\n return message;\n}\n\nfunction hasQrCode(\n response?: CreateTotpFactorResponse,\n): response is CreateTotpFactorResponse & {\n authenticationFactor: {\n totp: NonNullable<CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf>;\n };\n} {\n const totp = response?.authenticationFactor.totp;\n return totp != null && \"qr_code\" in totp;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/add-mfa-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Box,\n Code,\n Dialog,\n Flex,\n Grid,\n Link,\n Separator,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport { type ReactNode } from \"react\";\nimport * as Otp from \"./otp-input.js\";\nimport { DialogContent, PrimaryButton, SecondaryButton } from \"./elements.js\";\nimport {\n CreateTotpFactorResponse,\n CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf,\n useCreateTotpFactor,\n useVerifyTotpFactor,\n} from \"../api/endpoint.js\";\nimport { useElevatedAccessToken } from \"../api/api-provider.js\";\nimport * as Form from \"@radix-ui/react-form\";\nimport { Marker } from \"./marker.js\";\nimport { CopyButton } from \"./copy-button.js\";\nimport { useSecuritySettings } from \"./use-security-settings.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { useDialogClose } from \"./use-dialog-close.js\";\n\ninterface AddMfaDialogProps extends Dialog.RootProps {\n children?: ReactNode;\n onSuccess?: () => void;\n}\n\nexport function AddMfaDialog({\n children,\n onSuccess,\n ...props\n}: AddMfaDialogProps) {\n const [open, setOpen] = React.useState(false);\n const [manuallyTriggered, setManuallyTriggered] = React.useState(false);\n const { elevatedAccess } = useElevatedAccessToken();\n const createAuthFactor = useCreateTotpFactor();\n\n const handleVerified = async () => {\n await createAuthFactor.mutateAsync(undefined);\n };\n\n const onTriggerClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n if (elevatedAccess && !createAuthFactor.data) {\n event.preventDefault();\n setManuallyTriggered(true);\n createAuthFactor.mutate(undefined, {\n onSuccess: () => {\n setOpen(true);\n },\n });\n } else {\n setManuallyTriggered(false);\n }\n };\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <Dialog.Root\n {...props}\n open={props.open || open}\n onOpenChange={props.onOpenChange || setOpen}\n >\n <Dialog.Trigger\n onClick={onTriggerClick}\n // @ts-ignore I've to find a way to pass the loading state to the trigger\n loading={manuallyTriggered && createAuthFactor.isPending}\n >\n {children}\n </Dialog.Trigger>\n\n <DialogContent maxWidth=\"480px\">\n <ElevatedAccess onVerified={handleVerified}>\n <Content onClose={handleClose} totpFactor={createAuthFactor.data} />\n </ElevatedAccess>\n </DialogContent>\n </Dialog.Root>\n );\n}\n\ninterface ContentProps {\n totpFactor?: CreateTotpFactorResponse;\n onClose?: () => void;\n}\n\nfunction Content({ onClose, totpFactor }: ContentProps) {\n const securitySettings = useSecuritySettings();\n\n const [customError, setCustomError] = React.useState<string | null>(null);\n const totp = hasQrCode(totpFactor)\n ? totpFactor.authenticationFactor.totp\n : undefined;\n\n const verifyTotp = useVerifyTotpFactor({\n mutation: {\n onSuccess: ({ success }) => {\n if (!success) {\n setCustomError(\"Invalid passcode\");\n }\n },\n },\n });\n\n const serverError = verifyTotp.error || customError;\n const isSuccess = verifyTotp.isSuccess && !serverError;\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setCustomError(null);\n\n const formData = new FormData(event.currentTarget);\n const otpCode = formData.get(\"otp-code\")?.toString();\n\n verifyTotp.mutate({\n data: {\n authenticationChallengeId: totpFactor?.authenticationChallenge.id ?? \"\",\n code: otpCode ?? \"\",\n },\n });\n };\n\n useDialogClose(isSuccess, () => {\n securitySettings.update(\"Mfa\", true);\n });\n\n return (\n <>\n <Dialog.Title mb=\"5\">Set up an authenticator app</Dialog.Title>\n\n <Form.Root onSubmit={handleSubmit}>\n <Grid columns=\"auto 1fr\" rows=\"repeat(4, auto)\" gapX=\"3\" gapY=\"1\">\n <Grid\n rows=\"subgrid\"\n gridRow=\"span 4\"\n style={{ placeItems: \"center\" }}\n >\n <Marker>1</Marker>\n <Separator\n orientation=\"vertical\"\n size=\"4\"\n style={{ width: \"2px\" }}\n />\n <Marker>2</Marker>\n <div />\n </Grid>\n\n <Grid rows=\"subgrid\" gridRow=\"span 4\">\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Scan the QR code\n </Text>\n <Flex direction=\"column\" gap=\"1\">\n <Text as=\"p\" size=\"2\">\n Use an authenticator app like{\" \"}\n <Link\n href=\"https://1password.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n 1Password\n </Link>\n ,{\" \"}\n <Link\n href=\"https://apps.apple.com/us/app/google-authenticator/id388497605\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Google Authenticator\n </Link>\n ,{\" \"}\n <Link\n href=\"https://authy.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Authy\n </Link>\n , or{\" \"}\n <Link\n href=\"https://www.microsoft.com/en-gb/security/mobile-authenticator-app\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Microsoft Authenticator\n </Link>{\" \"}\n to scan the QR code below.\n </Text>\n <Flex align=\"center\" gap=\"5\" my=\"5\">\n <Grid\n position=\"relative\"\n width=\"160px\"\n height=\"160px\"\n p=\"2\"\n style={{\n border: \"1px solid var(--gray-7)\",\n borderRadius: \"var(--radius-4)\",\n background: \"var(--gray-2)\",\n overflow: \"hidden\",\n }}\n >\n {totp?.qr_code && (\n <Box asChild width=\"100%\" height=\"auto\">\n <img\n alt=\"Scan this QR code to enroll\"\n aria-describedby=\"secret-note\"\n height=\"160\"\n src={totp.qr_code}\n style={{ userSelect: \"none\", background: \"white\" }}\n width=\"160\"\n />\n </Box>\n )}\n </Grid>\n\n <Flex direction=\"column\" gap=\"1\" align=\"start\">\n <Text color=\"gray\" id=\"secret-note\" size=\"2\">\n Can‘t scan the code?{\" \"}\n </Text>\n\n <SecretDialog setupKey={totp?.secret ?? \"\"}>\n <SecondaryButton\n size=\"1\"\n disabled={verifyTotp.isPending || isSuccess}\n >\n View setup key\n </SecondaryButton>\n </SecretDialog>\n </Flex>\n </Flex>\n </Flex>\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Get verification passcode\n </Text>\n <Flex direction=\"column\" gap=\"4\">\n <Text as=\"p\" size=\"2\">\n Enter the 6-digit passcode from your authenticator app.\n </Text>\n\n <Flex direction=\"column\" gap=\"2\">\n <Otp.Root\n autoSubmit\n gap=\"3\"\n justify=\"start\"\n name=\"otp-code\"\n rows=\"48px\"\n columns=\"repeat(6, 48px)\"\n readOnly={verifyTotp.isPending || isSuccess}\n >\n <Otp.Input required autoFocus autoComplete=\"off\" />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n </Otp.Root>\n\n {serverError && (\n <Text size=\"2\" color=\"red\">\n {getMutationErrorMessage(serverError)}\n </Text>\n )}\n </Flex>\n </Flex>\n </Grid>\n </Grid>\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <SecondaryButton disabled={verifyTotp.isPending || isSuccess}>\n Cancel\n </SecondaryButton>\n </Dialog.Close>\n\n <SaveButton\n asChild\n loading={verifyTotp.isPending}\n done={isSuccess}\n onDone={onClose}\n >\n <PrimaryButton type=\"submit\">Confirm</PrimaryButton>\n </SaveButton>\n </Flex>\n </Form.Root>\n\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">\n {getMutationErrorMessage(serverError)}\n </section>\n </VisuallyHidden>\n </>\n );\n}\n\ninterface SecretDialogProps extends React.PropsWithChildren {\n setupKey: string;\n}\n\nfunction SecretDialog({ children, setupKey }: SecretDialogProps) {\n return (\n <Dialog.Root>\n <Dialog.Trigger>{children}</Dialog.Trigger>\n <DialogContent\n maxWidth=\"90vw\"\n size={{ initial: \"3\", sm: \"4\" }}\n minWidth=\"300px\"\n width=\"fit-content\"\n >\n <Dialog.Title size=\"2\" weight=\"regular\">\n Your setup key\n </Dialog.Title>\n <Dialog.Description>\n <Text size=\"6\">\n <Code variant=\"ghost\" style={{ letterSpacing: \"0.15rem\" }}>\n {setupKey}\n </Code>\n </Text>\n </Dialog.Description>\n\n <Flex align=\"center\" gap=\"3\" justify=\"end\" mt=\"5\">\n <Dialog.Close>\n <CopyButton asChild value={setupKey}>\n <PrimaryButton>Copy and close</PrimaryButton>\n </CopyButton>\n </Dialog.Close>\n </Flex>\n </DialogContent>\n </Dialog.Root>\n );\n}\n\nfunction getMutationErrorMessage(error: unknown) {\n let message = \"Something went wrong, please try again\";\n\n if (typeof error === \"string\") {\n message = error;\n }\n\n if (error instanceof Error) {\n message = error.message;\n }\n\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n message = error.message;\n }\n\n if (message === \"Invalid passcode\") {\n message = \"Invalid passcode, please try again\";\n }\n\n return message;\n}\n\nfunction hasQrCode(\n response?: CreateTotpFactorResponse,\n): response is CreateTotpFactorResponse & {\n authenticationFactor: {\n totp: NonNullable<CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf>;\n };\n} {\n const totp = response?.authenticationFactor.totp;\n return totp != null && \"qr_code\" in totp;\n}\n"],"mappings":"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","names":[]}
@@ -5,7 +5,7 @@ import { Skeleton } from "./elements.js";
5
5
  import { IconPanel } from "./icon-panel.js";
6
6
  import { GenericError } from "./generic-error.js";
7
7
  import { ExternalLinkIcon } from "@radix-ui/react-icons";
8
- import * as CardList from "../card-list.js";
8
+ import * as CardList from "./card-list.js";
9
9
  import { DomainItem } from "./domain-item.js";
10
10
  import clsx from "clsx";
11
11
  const AdminPortalDomainVerification = ({
@@ -16,23 +16,30 @@ const AdminPortalDomainVerification = ({
16
16
  isPending = false
17
17
  }) => {
18
18
  if (organizationDomains.length === 0) {
19
- return /* @__PURE__ */ jsx(Card, { size: "2", children: /* @__PURE__ */ jsxs(Flex, { direction: "row", justify: "between", align: "center", children: [
20
- /* @__PURE__ */ jsx(Text, { size: "2", color: "gray", children: "You haven't added any verified domains yet." }),
21
- /* @__PURE__ */ jsxs(
22
- Button,
23
- {
24
- variant: "outline",
25
- color: "gray",
26
- loading: isPending,
27
- disabled: isPending,
28
- onClick: onAddDomain,
29
- children: [
30
- "Add domain ",
31
- /* @__PURE__ */ jsx(ExternalLinkIcon, {})
32
- ]
33
- }
34
- )
35
- ] }) });
19
+ return /* @__PURE__ */ jsx(
20
+ Card,
21
+ {
22
+ size: "2",
23
+ "data-woswidgets-widget-id": "admin-portal-domain-verification",
24
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "row", justify: "between", align: "center", children: [
25
+ /* @__PURE__ */ jsx(Text, { size: "2", color: "gray", children: "You haven't added any verified domains yet." }),
26
+ /* @__PURE__ */ jsxs(
27
+ Button,
28
+ {
29
+ variant: "outline",
30
+ color: "gray",
31
+ loading: isPending,
32
+ disabled: isPending,
33
+ onClick: onAddDomain,
34
+ children: [
35
+ "Add domain ",
36
+ /* @__PURE__ */ jsx(ExternalLinkIcon, {})
37
+ ]
38
+ }
39
+ )
40
+ ] })
41
+ }
42
+ );
36
43
  }
37
44
  return /* @__PURE__ */ jsxs(
38
45
  Flex,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/admin-portal-domain-verification.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Button, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport { ExternalLinkIcon } from \"@radix-ui/react-icons\";\nimport * as CardList from \"../card-list.js\";\nimport { OrganizationDomain } from \"../api/endpoint.js\";\nimport { DomainItem } from \"./domain-item.js\";\n\nimport clsx from \"clsx\";\n\ninterface AdminPortalDomainVerificationProps {\n organizationDomains: OrganizationDomain[];\n onAddDomain: () => void;\n onDeleteDomain: (domainId: string) => void;\n onReverifyDomain: (domainId: string) => void;\n isPending?: boolean;\n}\n\nexport const AdminPortalDomainVerification = ({\n organizationDomains,\n onAddDomain,\n onDeleteDomain,\n onReverifyDomain,\n isPending = false,\n}: AdminPortalDomainVerificationProps) => {\n if (organizationDomains.length === 0) {\n return (\n <Card size=\"2\">\n <Flex direction=\"row\" justify=\"between\" align=\"center\">\n <Text size=\"2\" color=\"gray\">\n You haven't added any verified domains yet.\n </Text>\n <Button\n variant=\"outline\"\n color=\"gray\"\n loading={isPending}\n disabled={isPending}\n onClick={onAddDomain}\n >\n Add domain <ExternalLinkIcon />\n </Button>\n </Flex>\n </Card>\n );\n }\n\n return (\n <Flex\n direction=\"column\"\n gap=\"4\"\n className={clsx(\"woswidgets-widget\")}\n data-woswidgets-widget-id=\"admin-portal-domain-verification\"\n >\n <CardList.Root>\n {organizationDomains.map((domain) => (\n <CardList.Item key={domain.id}>\n <DomainItem\n domain={domain}\n onDeleteDomain={onDeleteDomain}\n onReverifyDomain={onReverifyDomain}\n />\n </CardList.Item>\n ))}\n </CardList.Root>\n\n <Box>\n <Button\n loading={isPending}\n disabled={isPending}\n color=\"gray\"\n variant=\"outline\"\n onClick={onAddDomain}\n >\n Add domain <ExternalLinkIcon />\n </Button>\n </Box>\n </Flex>\n );\n};\n\nexport const AdminPortalDomainVerificationLoading: React.FC = () => {\n return (\n <Card size=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>Domain name</Skeleton>\n </Text>\n\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Skeleton>Added recently</Skeleton>\n </Text>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\nexport function AdminPortalDomainVerificationError({\n error,\n}: {\n error: unknown;\n}) {\n return (\n <Card size=\"2\">\n <GenericError error={error} />\n </Card>\n );\n}\n"],"mappings":";AAiCU,cAGA,YAHA;AA9BV,SAAS,KAAK,QAAQ,MAAM,MAAM,YAAY;AAC9C,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC,YAAY,cAAc;AAE1B,SAAS,kBAAkB;AAE3B,OAAO,UAAU;AAUV,MAAM,gCAAgC,CAAC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,MAA0C;AACxC,MAAI,oBAAoB,WAAW,GAAG;AACpC,WACE,oBAAC,QAAK,MAAK,KACT,+BAAC,QAAK,WAAU,OAAM,SAAQ,WAAU,OAAM,UAC5C;AAAA,0BAAC,QAAK,MAAK,KAAI,OAAM,QAAO,yDAE5B;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,OAAM;AAAA,UACN,SAAS;AAAA,UACT,UAAU;AAAA,UACV,SAAS;AAAA,UACV;AAAA;AAAA,YACY,oBAAC,oBAAiB;AAAA;AAAA;AAAA,MAC/B;AAAA,OACF,GACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,KAAI;AAAA,MACJ,WAAW,KAAK,mBAAmB;AAAA,MACnC,6BAA0B;AAAA,MAE1B;AAAA,4BAAC,SAAS,MAAT,EACE,8BAAoB,IAAI,CAAC,WACxB,oBAAC,SAAS,MAAT,EACC;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF,KALkB,OAAO,EAM3B,CACD,GACH;AAAA,QAEA,oBAAC,OACC;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,UAAU;AAAA,YACV,OAAM;AAAA,YACN,SAAQ;AAAA,YACR,SAAS;AAAA,YACV;AAAA;AAAA,cACY,oBAAC,oBAAiB;AAAA;AAAA;AAAA,QAC/B,GACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEO,MAAM,uCAAiD,MAAM;AAClE,SACE,oBAAC,QAAK,MAAK,KACT,+BAAC,QAAK,KAAI,KAAI,OAAM,UAClB;AAAA,wBAAC,YACC,8BAAC,aAAU,GACb;AAAA,IAEA,qBAAC,QAAK,WAAU,UACd;AAAA,0BAAC,QAAK,MAAK,KAAI,cAAY,MAAC,QAAO,QAAO,IAAG,KAAI,IAAG,QAClD,8BAAC,YAAS,yBAAW,GACvB;AAAA,MAEA,oBAAC,QAAK,MAAK,KAAI,OAAM,QAAO,IAAG,KAC7B,8BAAC,YAAS,4BAAc,GAC1B;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAEO,SAAS,mCAAmC;AAAA,EACjD;AACF,GAEG;AACD,SACE,oBAAC,QAAK,MAAK,KACT,8BAAC,gBAAa,OAAc,GAC9B;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/admin-portal-domain-verification.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Button, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport { ExternalLinkIcon } from \"@radix-ui/react-icons\";\nimport * as CardList from \"./card-list.js\";\nimport { OrganizationDomain } from \"../api/endpoint.js\";\nimport { DomainItem } from \"./domain-item.js\";\n\nimport clsx from \"clsx\";\n\ninterface AdminPortalDomainVerificationProps {\n organizationDomains: OrganizationDomain[];\n onAddDomain: () => void;\n onDeleteDomain: (domainId: string) => void;\n onReverifyDomain: (domainId: string) => void;\n isPending?: boolean;\n}\n\nexport const AdminPortalDomainVerification = ({\n organizationDomains,\n onAddDomain,\n onDeleteDomain,\n onReverifyDomain,\n isPending = false,\n}: AdminPortalDomainVerificationProps) => {\n if (organizationDomains.length === 0) {\n return (\n <Card\n size=\"2\"\n data-woswidgets-widget-id=\"admin-portal-domain-verification\"\n >\n <Flex direction=\"row\" justify=\"between\" align=\"center\">\n <Text size=\"2\" color=\"gray\">\n You haven't added any verified domains yet.\n </Text>\n <Button\n variant=\"outline\"\n color=\"gray\"\n loading={isPending}\n disabled={isPending}\n onClick={onAddDomain}\n >\n Add domain <ExternalLinkIcon />\n </Button>\n </Flex>\n </Card>\n );\n }\n\n return (\n <Flex\n direction=\"column\"\n gap=\"4\"\n className={clsx(\"woswidgets-widget\")}\n data-woswidgets-widget-id=\"admin-portal-domain-verification\"\n >\n <CardList.Root>\n {organizationDomains.map((domain) => (\n <CardList.Item key={domain.id}>\n <DomainItem\n domain={domain}\n onDeleteDomain={onDeleteDomain}\n onReverifyDomain={onReverifyDomain}\n />\n </CardList.Item>\n ))}\n </CardList.Root>\n\n <Box>\n <Button\n loading={isPending}\n disabled={isPending}\n color=\"gray\"\n variant=\"outline\"\n onClick={onAddDomain}\n >\n Add domain <ExternalLinkIcon />\n </Button>\n </Box>\n </Flex>\n );\n};\n\nexport const AdminPortalDomainVerificationLoading: React.FC = () => {\n return (\n <Card size=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>Domain name</Skeleton>\n </Text>\n\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Skeleton>Added recently</Skeleton>\n </Text>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\nexport function AdminPortalDomainVerificationError({\n error,\n}: {\n error: unknown;\n}) {\n return (\n <Card size=\"2\">\n <GenericError error={error} />\n </Card>\n );\n}\n"],"mappings":";AAoCU,cAGA,YAHA;AAjCV,SAAS,KAAK,QAAQ,MAAM,MAAM,YAAY;AAC9C,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC,YAAY,cAAc;AAE1B,SAAS,kBAAkB;AAE3B,OAAO,UAAU;AAUV,MAAM,gCAAgC,CAAC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,MAA0C;AACxC,MAAI,oBAAoB,WAAW,GAAG;AACpC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,6BAA0B;AAAA,QAE1B,+BAAC,QAAK,WAAU,OAAM,SAAQ,WAAU,OAAM,UAC5C;AAAA,8BAAC,QAAK,MAAK,KAAI,OAAM,QAAO,yDAE5B;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,SAAS;AAAA,cACT,UAAU;AAAA,cACV,SAAS;AAAA,cACV;AAAA;AAAA,gBACY,oBAAC,oBAAiB;AAAA;AAAA;AAAA,UAC/B;AAAA,WACF;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,KAAI;AAAA,MACJ,WAAW,KAAK,mBAAmB;AAAA,MACnC,6BAA0B;AAAA,MAE1B;AAAA,4BAAC,SAAS,MAAT,EACE,8BAAoB,IAAI,CAAC,WACxB,oBAAC,SAAS,MAAT,EACC;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF,KALkB,OAAO,EAM3B,CACD,GACH;AAAA,QAEA,oBAAC,OACC;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,UAAU;AAAA,YACV,OAAM;AAAA,YACN,SAAQ;AAAA,YACR,SAAS;AAAA,YACV;AAAA;AAAA,cACY,oBAAC,oBAAiB;AAAA;AAAA;AAAA,QAC/B,GACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEO,MAAM,uCAAiD,MAAM;AAClE,SACE,oBAAC,QAAK,MAAK,KACT,+BAAC,QAAK,KAAI,KAAI,OAAM,UAClB;AAAA,wBAAC,YACC,8BAAC,aAAU,GACb;AAAA,IAEA,qBAAC,QAAK,WAAU,UACd;AAAA,0BAAC,QAAK,MAAK,KAAI,cAAY,MAAC,QAAO,QAAO,IAAG,KAAI,IAAG,QAClD,8BAAC,YAAS,yBAAW,GACvB;AAAA,MAEA,oBAAC,QAAK,MAAK,KAAI,OAAM,QAAO,IAAG,KAC7B,8BAAC,YAAS,4BAAc,GAC1B;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAEO,SAAS,mCAAmC;AAAA,EACjD;AACF,GAEG;AACD,SACE,oBAAC,QAAK,MAAK,KACT,8BAAC,gBAAa,OAAc,GAC9B;AAEJ;","names":[]}
@@ -9,7 +9,7 @@ import {
9
9
  InfoCircledIcon,
10
10
  Cross2Icon
11
11
  } from "@radix-ui/react-icons";
12
- import * as CardList from "../card-list.js";
12
+ import * as CardList from "./card-list.js";
13
13
  import { ProviderIcon } from "./provider-icon.js";
14
14
  import {
15
15
  getIdentityProviderName
@@ -17,7 +17,7 @@ import {
17
17
  import { Status } from "./status.js";
18
18
  import { unreachable } from "./utils.js";
19
19
  import clsx from "clsx";
20
- import { ApiError, FetchError, NoAuthTokenError } from "./errors.js";
20
+ import { getErrorMessage } from "./generic-error.js";
21
21
  const AdminPortalSsoConnectionContext = React.createContext(null);
22
22
  AdminPortalSsoConnectionContext.displayName = "AdminPortalSsoConnectionContext";
23
23
  function useAdminPortalSsoConnectionContext() {
@@ -219,30 +219,7 @@ function AdminPortalSsoConnectionError({ error }) {
219
219
  React.useEffect(() => {
220
220
  console.error(error);
221
221
  }, [error]);
222
- const { heading, message } = (() => {
223
- if (error instanceof FetchError) {
224
- return {
225
- heading: "Error fetching data",
226
- message: "An error occurred. You may need to configure CORS in the WorkOS Dashboard. Contact your organization admin for support."
227
- };
228
- }
229
- if (error instanceof NoAuthTokenError) {
230
- return {
231
- heading: "Error fetching data",
232
- message: "Authorization error. You likely forgot to provide an authorization token to the Users Management Widget."
233
- };
234
- }
235
- if (error instanceof ApiError && error.status === 404) {
236
- return {
237
- heading: "Error fetching data",
238
- message: "Authorization error. Contact your organization admin for support."
239
- };
240
- }
241
- return {
242
- heading: "Unknown error",
243
- message: "An unexpected error occurred. Please try refreshing the page, or contact your organization admin for support."
244
- };
245
- })();
222
+ const { heading, message } = getErrorMessage(error);
246
223
  return /* @__PURE__ */ jsx(Card, { size: "2", children: /* @__PURE__ */ jsx(Flex, { direction: "row", justify: "between", align: "center", gap: "2", children: /* @__PURE__ */ jsxs(Flex, { gap: "4", align: "center", children: [
247
224
  /* @__PURE__ */ jsx(
248
225
  Flex,
@@ -254,7 +231,8 @@ function AdminPortalSsoConnectionError({ error }) {
254
231
  style: {
255
232
  borderRadius: "9999px",
256
233
  backgroundColor: "var(--red-a4)",
257
- color: "var(--red-a11)"
234
+ color: "var(--red-a11)",
235
+ flexShrink: 0
258
236
  },
259
237
  children: /* @__PURE__ */ jsx(Cross2Icon, { width: "18px", height: "18px" })
260
238
  }