@hexclave/react 1.0.30 → 1.0.32

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 (109) hide show
  1. package/dist/clickmap/clickmap-core.js +1 -1
  2. package/dist/clickmap/index.js +2 -2
  3. package/dist/components/api-key-dialogs.js +2 -2
  4. package/dist/components/credential-sign-in.js +1 -1
  5. package/dist/components/credential-sign-up.js +1 -1
  6. package/dist/components/magic-link-sign-in.js +1 -1
  7. package/dist/components/team-switcher.js +1 -1
  8. package/dist/components-page/account-settings/active-sessions/active-sessions-page.js +1 -1
  9. package/dist/components-page/account-settings/email-and-auth/emails-section.js +1 -1
  10. package/dist/components-page/account-settings/email-and-auth/mfa-section.js +1 -1
  11. package/dist/components-page/account-settings/email-and-auth/password-section.js +1 -1
  12. package/dist/components-page/account-settings/teams/team-api-keys-section.js +1 -1
  13. package/dist/components-page/account-settings/teams/team-creation-page.js +1 -1
  14. package/dist/components-page/account-settings/teams/team-member-invitation-section.js +1 -1
  15. package/dist/components-page/auth-page.js +1 -1
  16. package/dist/components-page/cli-auth-confirm.js +1 -1
  17. package/dist/components-page/cli-auth-confirm.test.js +1 -1
  18. package/dist/components-page/forgot-password.js +1 -1
  19. package/dist/components-page/oauth-callback.d.ts.map +1 -1
  20. package/dist/components-page/oauth-callback.js +3 -1
  21. package/dist/components-page/oauth-callback.js.map +1 -1
  22. package/dist/components-page/oauth-callback.test.js +3 -1
  23. package/dist/components-page/oauth-callback.test.js.map +1 -1
  24. package/dist/components-page/onboarding.js +1 -1
  25. package/dist/components-page/password-reset.js +1 -1
  26. package/dist/components-page/team-creation.js +1 -1
  27. package/dist/dev-tool/dev-tool-core.js +1 -1
  28. package/dist/dev-tool/index.js +1 -1
  29. package/dist/esm/clickmap/clickmap-core.js +1 -1
  30. package/dist/esm/clickmap/index.js +2 -2
  31. package/dist/esm/components/api-key-dialogs.js +2 -2
  32. package/dist/esm/components/credential-sign-in.js +1 -1
  33. package/dist/esm/components/credential-sign-up.js +1 -1
  34. package/dist/esm/components/magic-link-sign-in.js +1 -1
  35. package/dist/esm/components/team-switcher.js +1 -1
  36. package/dist/esm/components-page/account-settings/active-sessions/active-sessions-page.js +1 -1
  37. package/dist/esm/components-page/account-settings/email-and-auth/emails-section.js +1 -1
  38. package/dist/esm/components-page/account-settings/email-and-auth/mfa-section.js +1 -1
  39. package/dist/esm/components-page/account-settings/email-and-auth/password-section.js +1 -1
  40. package/dist/esm/components-page/account-settings/teams/team-api-keys-section.js +1 -1
  41. package/dist/esm/components-page/account-settings/teams/team-creation-page.js +1 -1
  42. package/dist/esm/components-page/account-settings/teams/team-member-invitation-section.js +1 -1
  43. package/dist/esm/components-page/auth-page.js +1 -1
  44. package/dist/esm/components-page/cli-auth-confirm.js +1 -1
  45. package/dist/esm/components-page/cli-auth-confirm.test.js +1 -1
  46. package/dist/esm/components-page/forgot-password.js +1 -1
  47. package/dist/esm/components-page/oauth-callback.d.ts.map +1 -1
  48. package/dist/esm/components-page/oauth-callback.js +3 -1
  49. package/dist/esm/components-page/oauth-callback.js.map +1 -1
  50. package/dist/esm/components-page/oauth-callback.test.js +3 -1
  51. package/dist/esm/components-page/oauth-callback.test.js.map +1 -1
  52. package/dist/esm/components-page/onboarding.js +1 -1
  53. package/dist/esm/components-page/password-reset.js +1 -1
  54. package/dist/esm/components-page/team-creation.js +1 -1
  55. package/dist/esm/dev-tool/dev-tool-core.js +1 -1
  56. package/dist/esm/dev-tool/index.js +1 -1
  57. package/dist/esm/generated/quetzal-translations.d.ts +2 -2
  58. package/dist/esm/lib/auth.js +1 -1
  59. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +2 -1
  60. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  61. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
  62. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  63. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +6 -10
  64. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  65. package/dist/esm/lib/hexclave-app/apps/implementations/common.js +2 -2
  66. package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.js +1 -1
  67. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
  68. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.d.ts.map +1 -1
  69. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js +11 -4
  70. package/dist/esm/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
  71. package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.js +1 -1
  72. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -0
  73. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
  74. package/dist/esm/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  75. package/dist/esm/lib/hexclave-app/teams/index.d.ts +4 -0
  76. package/dist/esm/lib/hexclave-app/teams/index.d.ts.map +1 -1
  77. package/dist/esm/lib/hexclave-app/teams/index.js.map +1 -1
  78. package/dist/esm/providers/theme-provider.js +1 -1
  79. package/dist/esm/pushed-config-error-overlay/index.js +1 -1
  80. package/dist/generated/quetzal-translations.d.ts +2 -2
  81. package/dist/lib/auth.js +1 -1
  82. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -0
  83. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  84. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
  85. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  86. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +6 -10
  87. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  88. package/dist/lib/hexclave-app/apps/implementations/common.js +2 -2
  89. package/dist/lib/hexclave-app/apps/implementations/event-tracker.js +1 -1
  90. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
  91. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts.map +1 -1
  92. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js +11 -4
  93. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.js.map +1 -1
  94. package/dist/lib/hexclave-app/apps/implementations/session-replay.js +1 -1
  95. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts +1 -0
  96. package/dist/lib/hexclave-app/apps/interfaces/client-app.d.ts.map +1 -1
  97. package/dist/lib/hexclave-app/apps/interfaces/client-app.js.map +1 -1
  98. package/dist/lib/hexclave-app/teams/index.d.ts +4 -0
  99. package/dist/lib/hexclave-app/teams/index.d.ts.map +1 -1
  100. package/dist/lib/hexclave-app/teams/index.js.map +1 -1
  101. package/dist/providers/theme-provider.js +1 -1
  102. package/dist/pushed-config-error-overlay/index.js +1 -1
  103. package/package.json +3 -3
  104. package/src/components-page/oauth-callback.test.tsx +4 -0
  105. package/src/components-page/oauth-callback.tsx +6 -0
  106. package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +3 -5
  107. package/src/lib/hexclave-app/apps/implementations/server-app-impl.ts +11 -7
  108. package/src/lib/hexclave-app/apps/interfaces/client-app.ts +1 -0
  109. package/src/lib/hexclave-app/teams/index.ts +4 -0
@@ -1,13 +1,14 @@
1
1
  'use client';
2
2
 
3
- import { runAsynchronously } from "@hexclave/shared/dist/utils/promises";
4
3
  import { captureError } from "@hexclave/shared/dist/utils/errors";
4
+ import { runAsynchronously } from "@hexclave/shared/dist/utils/promises";
5
5
  import { Spinner, cn } from "@hexclave/ui";
6
6
  import { useEffect, useRef, useState } from "react";
7
7
  import { useStackApp } from "../index.js";
8
8
  import { useTranslation } from "../lib/translations.js";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
  import { KnownError } from "@hexclave/shared";
11
+ import { hexclaveAppInternalsSymbol } from "../lib/hexclave-app/common.js";
11
12
  import { MaybeFullPage } from "../components/elements/maybe-full-page.js";
12
13
  import { StyledLink } from "../components/link.js";
13
14
  import { ErrorPage } from "./error-page.js";
@@ -23,6 +24,7 @@ function OAuthCallback({ fullPage }) {
23
24
  if (called.current) return;
24
25
  called.current = true;
25
26
  try {
27
+ await app[hexclaveAppInternalsSymbol].awaitPendingAuthResolutions();
26
28
  if (!await app.callOAuthCallback()) await app.redirectToSignIn({ noRedirectBack: true });
27
29
  } catch (e) {
28
30
  if (KnownError.isKnownError(e)) {
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-callback.js","names":[],"sources":["../../../src/components-page/oauth-callback.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { KnownError } from \"@hexclave/shared\";\nimport { captureError } from \"@hexclave/shared/dist/utils/errors\";\nimport { runAsynchronously } from \"@hexclave/shared/dist/utils/promises\";\nimport { Spinner, cn } from \"@hexclave/ui\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useStackApp } from \"..\";\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { StyledLink } from \"../components/link\";\nimport { useTranslation } from \"../lib/translations\";\nimport { ErrorPage } from \"./error-page\";\n\nexport function OAuthCallback({ fullPage }: { fullPage?: boolean }) {\n const { t } = useTranslation();\n const app = useStackApp();\n const called = useRef(false);\n const [showRedirectLink, setShowRedirectLink] = useState(false);\n const [errorSearchParams, setErrorSearchParams] = useState<Record<string, string> | null>(null);\n\n useEffect(() => runAsynchronously(async () => {\n if (called.current) return;\n called.current = true;\n try {\n const hasRedirected = await app.callOAuthCallback();\n if (!hasRedirected) {\n await app.redirectToSignIn({ noRedirectBack: true });\n }\n } catch (e) {\n if (KnownError.isKnownError(e)) {\n setErrorSearchParams({\n errorCode: e.errorCode,\n message: e.message,\n details: JSON.stringify(e.details ?? {}),\n });\n return;\n }\n captureError(\"<OAuthCallback />\", e);\n setErrorSearchParams({});\n }\n }), [app]);\n\n useEffect(() => {\n setTimeout(() => setShowRedirectLink(true), 3000);\n }, []);\n\n if (errorSearchParams != null) {\n return <ErrorPage searchParams={errorSearchParams} fullPage={fullPage} />;\n }\n\n return (\n <MaybeFullPage\n fullPage={fullPage ?? false}\n containerClassName=\"flex items-center justify-center\"\n >\n <div\n className={cn(\n \"text-center justify-center items-center stack-scope flex flex-col gap-4 max-w-[380px]\",\n fullPage ? \"p-4\" : \"p-0\"\n )}\n >\n <div className=\"flex flex-col justify-center items-center gap-4\">\n <Spinner size={20} />\n </div>\n {showRedirectLink ? <p>{t('If you are not redirected automatically, ')}<StyledLink\n className=\"whitespace-nowrap\"\n href=\"#\"\n onClick={(e) => {\n e.preventDefault();\n runAsynchronously(app.redirectToHome());\n }}\n >{t(\"click here\")}</StyledLink></p> : null}\n </div>\n </MaybeFullPage>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,SAAgB,cAAc,EAAE,YAAoC;CAClE,MAAM,EAAE,MAAM,gBAAgB;CAC9B,MAAM,MAAM,aAAa;CACzB,MAAM,SAAS,OAAO,MAAM;CAC5B,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,MAAM;CAC/D,MAAM,CAAC,mBAAmB,wBAAwB,SAAwC,KAAK;AAE/F,iBAAgB,kBAAkB,YAAY;AAC5C,MAAI,OAAO,QAAS;AACpB,SAAO,UAAU;AACjB,MAAI;AAEF,OAAI,CADkB,MAAM,IAAI,mBAAmB,CAEjD,OAAM,IAAI,iBAAiB,EAAE,gBAAgB,MAAM,CAAC;WAE/C,GAAG;AACV,OAAI,WAAW,aAAa,EAAE,EAAE;AAC9B,yBAAqB;KACnB,WAAW,EAAE;KACb,SAAS,EAAE;KACX,SAAS,KAAK,UAAU,EAAE,WAAW,EAAE,CAAC;KACzC,CAAC;AACF;;AAEF,gBAAa,qBAAqB,EAAE;AACpC,wBAAqB,EAAE,CAAC;;GAE1B,EAAE,CAAC,IAAI,CAAC;AAEV,iBAAgB;AACd,mBAAiB,oBAAoB,KAAK,EAAE,IAAK;IAChD,EAAE,CAAC;AAEN,KAAI,qBAAqB,KACvB,QAAO,oBAAC;EAAU,cAAc;EAA6B;GAAY;AAG3E,QACE,oBAAC;EACC,UAAU,YAAY;EACtB,oBAAmB;YAEnB,qBAAC;GACC,WAAW,GACT,yFACA,WAAW,QAAQ,MACpB;cAED,oBAAC;IAAI,WAAU;cACb,oBAAC,WAAQ,MAAM,KAAM;KACjB,EACL,mBAAmB,qBAAC,kBAAG,EAAE,4CAA4C,EAAC,oBAAC;IACtE,WAAU;IACV,MAAK;IACL,UAAU,MAAM;AACd,OAAE,gBAAgB;AAClB,uBAAkB,IAAI,gBAAgB,CAAC;;cAEzC,EAAE,aAAa;KAAc,IAAI,GAAG;IAClC;GACQ"}
1
+ {"version":3,"file":"oauth-callback.js","names":[],"sources":["../../../src/components-page/oauth-callback.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { KnownError } from \"@hexclave/shared\";\nimport { captureError } from \"@hexclave/shared/dist/utils/errors\";\nimport { runAsynchronously } from \"@hexclave/shared/dist/utils/promises\";\nimport { Spinner, cn } from \"@hexclave/ui\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useStackApp } from \"..\";\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { StyledLink } from \"../components/link\";\nimport { hexclaveAppInternalsSymbol } from \"../lib/hexclave-app/common\";\nimport { useTranslation } from \"../lib/translations\";\nimport { ErrorPage } from \"./error-page\";\n\nexport function OAuthCallback({ fullPage }: { fullPage?: boolean }) {\n const { t } = useTranslation();\n const app = useStackApp();\n const called = useRef(false);\n const [showRedirectLink, setShowRedirectLink] = useState(false);\n const [errorSearchParams, setErrorSearchParams] = useState<Record<string, string> | null>(null);\n\n useEffect(() => runAsynchronously(async () => {\n if (called.current) return;\n called.current = true;\n try {\n // The startup handler in StackClientApp's constructor may have already consumed the\n // one-time OAuth params (code + state cookie) via a microtask that fires before this\n // macrotask-scheduled useEffect. Await its completion so we don't race: if it succeeds\n // it will redirect and this page tears down; if it fails we fall through below.\n await app[hexclaveAppInternalsSymbol].awaitPendingAuthResolutions();\n const hasRedirected = await app.callOAuthCallback();\n if (!hasRedirected) {\n await app.redirectToSignIn({ noRedirectBack: true });\n }\n } catch (e) {\n if (KnownError.isKnownError(e)) {\n setErrorSearchParams({\n errorCode: e.errorCode,\n message: e.message,\n details: JSON.stringify(e.details ?? {}),\n });\n return;\n }\n captureError(\"<OAuthCallback />\", e);\n setErrorSearchParams({});\n }\n }), [app]);\n\n useEffect(() => {\n setTimeout(() => setShowRedirectLink(true), 3000);\n }, []);\n\n if (errorSearchParams != null) {\n return <ErrorPage searchParams={errorSearchParams} fullPage={fullPage} />;\n }\n\n return (\n <MaybeFullPage\n fullPage={fullPage ?? false}\n containerClassName=\"flex items-center justify-center\"\n >\n <div\n className={cn(\n \"text-center justify-center items-center stack-scope flex flex-col gap-4 max-w-[380px]\",\n fullPage ? \"p-4\" : \"p-0\"\n )}\n >\n <div className=\"flex flex-col justify-center items-center gap-4\">\n <Spinner size={20} />\n </div>\n {showRedirectLink ? <p>{t('If you are not redirected automatically, ')}<StyledLink\n className=\"whitespace-nowrap\"\n href=\"#\"\n onClick={(e) => {\n e.preventDefault();\n runAsynchronously(app.redirectToHome());\n }}\n >{t(\"click here\")}</StyledLink></p> : null}\n </div>\n </MaybeFullPage>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAmBA,SAAgB,cAAc,EAAE,YAAoC;CAClE,MAAM,EAAE,MAAM,gBAAgB;CAC9B,MAAM,MAAM,aAAa;CACzB,MAAM,SAAS,OAAO,MAAM;CAC5B,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,MAAM;CAC/D,MAAM,CAAC,mBAAmB,wBAAwB,SAAwC,KAAK;AAE/F,iBAAgB,kBAAkB,YAAY;AAC5C,MAAI,OAAO,QAAS;AACpB,SAAO,UAAU;AACjB,MAAI;AAKF,SAAM,IAAI,4BAA4B,6BAA6B;AAEnE,OAAI,CADkB,MAAM,IAAI,mBAAmB,CAEjD,OAAM,IAAI,iBAAiB,EAAE,gBAAgB,MAAM,CAAC;WAE/C,GAAG;AACV,OAAI,WAAW,aAAa,EAAE,EAAE;AAC9B,yBAAqB;KACnB,WAAW,EAAE;KACb,SAAS,EAAE;KACX,SAAS,KAAK,UAAU,EAAE,WAAW,EAAE,CAAC;KACzC,CAAC;AACF;;AAEF,gBAAa,qBAAqB,EAAE;AACpC,wBAAqB,EAAE,CAAC;;GAE1B,EAAE,CAAC,IAAI,CAAC;AAEV,iBAAgB;AACd,mBAAiB,oBAAoB,KAAK,EAAE,IAAK;IAChD,EAAE,CAAC;AAEN,KAAI,qBAAqB,KACvB,QAAO,oBAAC;EAAU,cAAc;EAA6B;GAAY;AAG3E,QACE,oBAAC;EACC,UAAU,YAAY;EACtB,oBAAmB;YAEnB,qBAAC;GACC,WAAW,GACT,yFACA,WAAW,QAAQ,MACpB;cAED,oBAAC;IAAI,WAAU;cACb,oBAAC,WAAQ,MAAM,KAAM;KACjB,EACL,mBAAmB,qBAAC,kBAAG,EAAE,4CAA4C,EAAC,oBAAC;IACtE,WAAU;IACV,MAAK;IACL,UAAU,MAAM;AACd,OAAE,gBAAgB;AAClB,uBAAkB,IAAI,gBAAgB,CAAC;;cAEzC,EAAE,aAAa;KAAc,IAAI,GAAG;IAClC;GACQ"}
@@ -1,6 +1,7 @@
1
1
  import React, { act } from "react";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { KnownErrors } from "@hexclave/shared";
4
+ import { hexclaveAppInternalsSymbol } from "../lib/hexclave-app/common.js";
4
5
  import { createRoot } from "react-dom/client";
5
6
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6
7
  import { OAuthCallback } from "./oauth-callback.js";
@@ -31,7 +32,8 @@ function createAppTestDouble(options) {
31
32
  return {
32
33
  callOAuthCallback: options.callOAuthCallback,
33
34
  redirectToSignIn: vi.fn(async () => {}),
34
- redirectToHome: vi.fn(async () => {})
35
+ redirectToHome: vi.fn(async () => {}),
36
+ [hexclaveAppInternalsSymbol]: { awaitPendingAuthResolutions: vi.fn(async () => {}) }
35
37
  };
36
38
  }
37
39
  let root = null;
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-callback.test.js","names":[],"sources":["../../../src/components-page/oauth-callback.test.tsx"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n// @vitest-environment jsdom\n\nimport { KnownErrors } from \"@hexclave/shared\";\nimport React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport type { StackClientApp } from \"../lib/hexclave-app/apps/interfaces/client-app\";\nimport { TranslationProviderClient } from \"../providers/translation-provider-client\";\nimport { OAuthCallback } from \"./oauth-callback\";\n\nconst appMockState = vi.hoisted(() => ({ app: null as unknown }));\n\nvi.mock(\"..\", () => ({\n useStackApp: () => {\n if (appMockState.app == null) {\n throw new Error(\"Expected test app to be set before rendering.\");\n }\n return appMockState.app;\n },\n}));\n\nvi.mock(\"@hexclave/ui\", async () => {\n const React = await import(\"react\");\n return {\n Button: (props: { children: React.ReactNode, onClick?: () => void }) => (\n <button type=\"button\" onClick={props.onClick}>{props.children}</button>\n ),\n Spinner: () => <div data-testid=\"spinner\" />,\n Typography: (props: { children: React.ReactNode }) => <div>{props.children}</div>,\n cn: (...classes: (string | false | null | undefined)[]) => classes.filter(Boolean).join(\" \"),\n };\n});\n\nconst previousActEnvironment = Reflect.get(globalThis, \"IS_REACT_ACT_ENVIRONMENT\");\n\nfunction createAppTestDouble(options: {\n callOAuthCallback: () => Promise<boolean>,\n}) {\n const app = {\n callOAuthCallback: options.callOAuthCallback,\n redirectToSignIn: vi.fn(async () => {}),\n redirectToHome: vi.fn(async () => {}),\n };\n\n // This test double intentionally implements only the StackClientApp surface\n // that OAuthCallback and the rendered error card touch.\n return app as unknown as StackClientApp<true>;\n}\n\nlet root: Root | null = null;\nlet container: HTMLDivElement | null = null;\n\nasync function renderWithApp(app: StackClientApp<true>) {\n appMockState.app = app;\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n await act(async () => {\n root?.render(\n <TranslationProviderClient quetzalKeys={new Map()} quetzalLocale={new Map()}>\n <OAuthCallback />\n </TranslationProviderClient>\n );\n });\n}\n\nasync function flushEffects() {\n await act(async () => {\n await new Promise((resolve) => setTimeout(resolve, 0));\n });\n}\n\ndescribe(\"OAuthCallback\", () => {\n beforeEach(() => {\n Reflect.set(globalThis, \"IS_REACT_ACT_ENVIRONMENT\", true);\n });\n\n afterEach(() => {\n act(() => {\n root?.unmount();\n });\n container?.remove();\n root = null;\n container = null;\n appMockState.app = null;\n vi.restoreAllMocks();\n Reflect.set(globalThis, \"IS_REACT_ACT_ENVIRONMENT\", previousActEnvironment);\n });\n\n it(\"renders backend-encoded OAuth callback errors on the callback page\", async () => {\n const errorMessage = \"Your sign up was rejected by an administrator's sign-up rule.\";\n const callOAuthCallback = vi.fn(async () => {\n throw new KnownErrors.SignUpRejected(errorMessage);\n });\n const app = createAppTestDouble({ callOAuthCallback });\n\n await renderWithApp(app);\n await flushEffects();\n\n expect(callOAuthCallback).toHaveBeenCalledOnce();\n expect(container?.textContent).toContain(\"SIGN_UP_REJECTED\");\n expect(container?.textContent).toContain(errorMessage);\n expect(app.redirectToSignIn).not.toHaveBeenCalled();\n });\n});\n"],"mappings":";;;;;;;;;;AAcA,MAAM,eAAe,GAAG,eAAe,EAAE,KAAK,MAAiB,EAAE;AAEjE,GAAG,KAAK,aAAa,EACnB,mBAAmB;AACjB,KAAI,aAAa,OAAO,KACtB,OAAM,IAAI,MAAM,gDAAgD;AAElE,QAAO,aAAa;GAEvB,EAAE;AAEH,GAAG,KAAK,gBAAgB,YAAY;AACpB,OAAM,OAAO;AAC3B,QAAO;EACL,SAAS,UACP,oBAAC;GAAO,MAAK;GAAS,SAAS,MAAM;aAAU,MAAM;IAAkB;EAEzE,eAAe,oBAAC,SAAI,eAAY,YAAY;EAC5C,aAAa,UAAyC,oBAAC,mBAAK,MAAM,WAAe;EACjF,KAAK,GAAG,YAAmD,QAAQ,OAAO,QAAQ,CAAC,KAAK,IAAI;EAC7F;EACD;AAEF,MAAM,yBAAyB,QAAQ,IAAI,YAAY,2BAA2B;AAElF,SAAS,oBAAoB,SAE1B;AASD,QARY;EACV,mBAAmB,QAAQ;EAC3B,kBAAkB,GAAG,GAAG,YAAY,GAAG;EACvC,gBAAgB,GAAG,GAAG,YAAY,GAAG;EACtC;;AAOH,IAAI,OAAoB;AACxB,IAAI,YAAmC;AAEvC,eAAe,cAAc,KAA2B;AACtD,cAAa,MAAM;AACnB,aAAY,SAAS,cAAc,MAAM;AACzC,UAAS,KAAK,OAAO,UAAU;AAC/B,QAAO,WAAW,UAAU;AAC5B,OAAM,IAAI,YAAY;AACpB,QAAM,OACJ,oBAAC;GAA0B,6BAAa,IAAI,KAAK;GAAE,+BAAe,IAAI,KAAK;aACzE,oBAAC,kBAAgB;IACS,CAC7B;GACD;;AAGJ,eAAe,eAAe;AAC5B,OAAM,IAAI,YAAY;AACpB,QAAM,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;GACtD;;AAGJ,SAAS,uBAAuB;AAC9B,kBAAiB;AACf,UAAQ,IAAI,YAAY,4BAA4B,KAAK;GACzD;AAEF,iBAAgB;AACd,YAAU;AACR,SAAM,SAAS;IACf;AACF,aAAW,QAAQ;AACnB,SAAO;AACP,cAAY;AACZ,eAAa,MAAM;AACnB,KAAG,iBAAiB;AACpB,UAAQ,IAAI,YAAY,4BAA4B,uBAAuB;GAC3E;AAEF,IAAG,sEAAsE,YAAY;EACnF,MAAM,eAAe;EACrB,MAAM,oBAAoB,GAAG,GAAG,YAAY;AAC1C,SAAM,IAAI,YAAY,eAAe,aAAa;IAClD;EACF,MAAM,MAAM,oBAAoB,EAAE,mBAAmB,CAAC;AAEtD,QAAM,cAAc,IAAI;AACxB,QAAM,cAAc;AAEpB,SAAO,kBAAkB,CAAC,sBAAsB;AAChD,SAAO,WAAW,YAAY,CAAC,UAAU,mBAAmB;AAC5D,SAAO,WAAW,YAAY,CAAC,UAAU,aAAa;AACtD,SAAO,IAAI,iBAAiB,CAAC,IAAI,kBAAkB;GACnD;EACF"}
1
+ {"version":3,"file":"oauth-callback.test.js","names":[],"sources":["../../../src/components-page/oauth-callback.test.tsx"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n// @vitest-environment jsdom\n\nimport { KnownErrors } from \"@hexclave/shared\";\nimport React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport type { StackClientApp } from \"../lib/hexclave-app/apps/interfaces/client-app\";\nimport { hexclaveAppInternalsSymbol } from \"../lib/hexclave-app/common\";\nimport { TranslationProviderClient } from \"../providers/translation-provider-client\";\nimport { OAuthCallback } from \"./oauth-callback\";\n\nconst appMockState = vi.hoisted(() => ({ app: null as unknown }));\n\nvi.mock(\"..\", () => ({\n useStackApp: () => {\n if (appMockState.app == null) {\n throw new Error(\"Expected test app to be set before rendering.\");\n }\n return appMockState.app;\n },\n}));\n\nvi.mock(\"@hexclave/ui\", async () => {\n const React = await import(\"react\");\n return {\n Button: (props: { children: React.ReactNode, onClick?: () => void }) => (\n <button type=\"button\" onClick={props.onClick}>{props.children}</button>\n ),\n Spinner: () => <div data-testid=\"spinner\" />,\n Typography: (props: { children: React.ReactNode }) => <div>{props.children}</div>,\n cn: (...classes: (string | false | null | undefined)[]) => classes.filter(Boolean).join(\" \"),\n };\n});\n\nconst previousActEnvironment = Reflect.get(globalThis, \"IS_REACT_ACT_ENVIRONMENT\");\n\nfunction createAppTestDouble(options: {\n callOAuthCallback: () => Promise<boolean>,\n}) {\n const app = {\n callOAuthCallback: options.callOAuthCallback,\n redirectToSignIn: vi.fn(async () => {}),\n redirectToHome: vi.fn(async () => {}),\n [hexclaveAppInternalsSymbol]: {\n awaitPendingAuthResolutions: vi.fn(async () => {}),\n },\n };\n\n // This test double intentionally implements only the StackClientApp surface\n // that OAuthCallback and the rendered error card touch.\n return app as unknown as StackClientApp<true>;\n}\n\nlet root: Root | null = null;\nlet container: HTMLDivElement | null = null;\n\nasync function renderWithApp(app: StackClientApp<true>) {\n appMockState.app = app;\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n await act(async () => {\n root?.render(\n <TranslationProviderClient quetzalKeys={new Map()} quetzalLocale={new Map()}>\n <OAuthCallback />\n </TranslationProviderClient>\n );\n });\n}\n\nasync function flushEffects() {\n await act(async () => {\n await new Promise((resolve) => setTimeout(resolve, 0));\n });\n}\n\ndescribe(\"OAuthCallback\", () => {\n beforeEach(() => {\n Reflect.set(globalThis, \"IS_REACT_ACT_ENVIRONMENT\", true);\n });\n\n afterEach(() => {\n act(() => {\n root?.unmount();\n });\n container?.remove();\n root = null;\n container = null;\n appMockState.app = null;\n vi.restoreAllMocks();\n Reflect.set(globalThis, \"IS_REACT_ACT_ENVIRONMENT\", previousActEnvironment);\n });\n\n it(\"renders backend-encoded OAuth callback errors on the callback page\", async () => {\n const errorMessage = \"Your sign up was rejected by an administrator's sign-up rule.\";\n const callOAuthCallback = vi.fn(async () => {\n throw new KnownErrors.SignUpRejected(errorMessage);\n });\n const app = createAppTestDouble({ callOAuthCallback });\n\n await renderWithApp(app);\n await flushEffects();\n\n expect(callOAuthCallback).toHaveBeenCalledOnce();\n expect(container?.textContent).toContain(\"SIGN_UP_REJECTED\");\n expect(container?.textContent).toContain(errorMessage);\n expect(app.redirectToSignIn).not.toHaveBeenCalled();\n });\n});\n"],"mappings":";;;;;;;;;;;AAeA,MAAM,eAAe,GAAG,eAAe,EAAE,KAAK,MAAiB,EAAE;AAEjE,GAAG,KAAK,aAAa,EACnB,mBAAmB;AACjB,KAAI,aAAa,OAAO,KACtB,OAAM,IAAI,MAAM,gDAAgD;AAElE,QAAO,aAAa;GAEvB,EAAE;AAEH,GAAG,KAAK,gBAAgB,YAAY;AACpB,OAAM,OAAO;AAC3B,QAAO;EACL,SAAS,UACP,oBAAC;GAAO,MAAK;GAAS,SAAS,MAAM;aAAU,MAAM;IAAkB;EAEzE,eAAe,oBAAC,SAAI,eAAY,YAAY;EAC5C,aAAa,UAAyC,oBAAC,mBAAK,MAAM,WAAe;EACjF,KAAK,GAAG,YAAmD,QAAQ,OAAO,QAAQ,CAAC,KAAK,IAAI;EAC7F;EACD;AAEF,MAAM,yBAAyB,QAAQ,IAAI,YAAY,2BAA2B;AAElF,SAAS,oBAAoB,SAE1B;AAYD,QAXY;EACV,mBAAmB,QAAQ;EAC3B,kBAAkB,GAAG,GAAG,YAAY,GAAG;EACvC,gBAAgB,GAAG,GAAG,YAAY,GAAG;GACpC,6BAA6B,EAC5B,6BAA6B,GAAG,GAAG,YAAY,GAAG,EACnD;EACF;;AAOH,IAAI,OAAoB;AACxB,IAAI,YAAmC;AAEvC,eAAe,cAAc,KAA2B;AACtD,cAAa,MAAM;AACnB,aAAY,SAAS,cAAc,MAAM;AACzC,UAAS,KAAK,OAAO,UAAU;AAC/B,QAAO,WAAW,UAAU;AAC5B,OAAM,IAAI,YAAY;AACpB,QAAM,OACJ,oBAAC;GAA0B,6BAAa,IAAI,KAAK;GAAE,+BAAe,IAAI,KAAK;aACzE,oBAAC,kBAAgB;IACS,CAC7B;GACD;;AAGJ,eAAe,eAAe;AAC5B,OAAM,IAAI,YAAY;AACpB,QAAM,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;GACtD;;AAGJ,SAAS,uBAAuB;AAC9B,kBAAiB;AACf,UAAQ,IAAI,YAAY,4BAA4B,KAAK;GACzD;AAEF,iBAAgB;AACd,YAAU;AACR,SAAM,SAAS;IACf;AACF,aAAW,QAAQ;AACnB,SAAO;AACP,cAAY;AACZ,eAAa,MAAM;AACnB,KAAG,iBAAiB;AACpB,UAAQ,IAAI,YAAY,4BAA4B,uBAAuB;GAC3E;AAEF,IAAG,sEAAsE,YAAY;EACnF,MAAM,eAAe;EACrB,MAAM,oBAAoB,GAAG,GAAG,YAAY;AAC1C,SAAM,IAAI,YAAY,eAAe,aAAa;IAClD;EACF,MAAM,MAAM,oBAAoB,EAAE,mBAAmB,CAAC;AAEtD,QAAM,cAAc,IAAI;AACxB,QAAM,cAAc;AAEpB,SAAO,kBAAkB,CAAC,sBAAsB;AAChD,SAAO,WAAW,YAAY,CAAC,UAAU,mBAAmB;AAC5D,SAAO,WAAW,YAAY,CAAC,UAAU,aAAa;AACtD,SAAO,IAAI,iBAAiB,CAAC,IAAI,kBAAkB;GACnD;EACF"}
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- import { runAsynchronously, runAsynchronouslyWithAlert } from "@hexclave/shared/dist/utils/promises";
4
3
  import { yupResolver } from "@hookform/resolvers/yup";
5
4
  import { strictEmailSchema, yupObject } from "@hexclave/shared/dist/schema-fields";
5
+ import { runAsynchronously, runAsynchronouslyWithAlert } from "@hexclave/shared/dist/utils/promises";
6
6
  import { Button, Input, Typography } from "@hexclave/ui";
7
7
  import { useState } from "react";
8
8
  import { useForm } from "react-hook-form";
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- import { runAsynchronouslyWithAlert } from "@hexclave/shared/dist/utils/promises";
4
3
  import { yupResolver } from "@hookform/resolvers/yup";
5
4
  import { passwordSchema, yupObject, yupString } from "@hexclave/shared/dist/schema-fields";
5
+ import { runAsynchronouslyWithAlert } from "@hexclave/shared/dist/utils/promises";
6
6
  import { Button, Label, PasswordInput, Typography, cn } from "@hexclave/ui";
7
7
  import { useState } from "react";
8
8
  import { useForm } from "react-hook-form";
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- import { runAsynchronously } from "@hexclave/shared/dist/utils/promises";
4
3
  import { yupResolver } from "@hookform/resolvers/yup";
5
4
  import { yupObject, yupString } from "@hexclave/shared/dist/schema-fields";
5
+ import { runAsynchronously } from "@hexclave/shared/dist/utils/promises";
6
6
  import { Button, Input, Label, Typography } from "@hexclave/ui";
7
7
  import { useState } from "react";
8
8
  import { useForm } from "react-hook-form";
@@ -1,5 +1,5 @@
1
- import { DEV_TOOL_ROOT_ID } from "@hexclave/shared/dist/utils/dev-tool";
2
1
  import { runAsynchronously } from "@hexclave/shared/dist/utils/promises";
2
+ import { DEV_TOOL_ROOT_ID } from "@hexclave/shared/dist/utils/dev-tool";
3
3
  import { getGlobalUiInstance, h, hasAppendChild, setGlobalUiInstance, setHtml } from "../in-page-ui/dom.js";
4
4
  import { hexclaveAppInternalsSymbol } from "../lib/hexclave-app/common.js";
5
5
  import { isLocalhost } from "@hexclave/shared/dist/utils/urls";
@@ -1,6 +1,6 @@
1
+ import { captureError } from "@hexclave/shared/dist/utils/errors";
1
2
  import { runAsynchronously } from "@hexclave/shared/dist/utils/promises";
2
3
  import { canMountIntoDom } from "../in-page-ui/dom.js";
3
- import { captureError } from "@hexclave/shared/dist/utils/errors";
4
4
  import { isLocalhost } from "@hexclave/shared/dist/utils/urls";
5
5
  import { envVars } from "../generated/env.js";
6
6