@civic/auth 0.8.0 → 0.8.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.
- package/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/dist/nextjs/config.d.ts +3 -0
- package/dist/nextjs/config.d.ts.map +1 -1
- package/dist/nextjs/config.js +3 -0
- package/dist/nextjs/config.js.map +1 -1
- package/dist/nextjs/middleware.d.ts.map +1 -1
- package/dist/nextjs/middleware.js +12 -4
- package/dist/nextjs/middleware.js.map +1 -1
- package/dist/shared/components/CivicAuthIframe.js +1 -1
- package/dist/shared/components/CivicAuthIframe.js.map +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/shared/version.js +1 -1
- package/dist/shared/version.js.map +1 -1
- package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts.map +1 -1
- package/dist/vanillajs/auth/handlers/IframeAuthHandler.js +19 -18
- package/dist/vanillajs/auth/handlers/IframeAuthHandler.js.map +1 -1
- package/dist/vanillajs/iframe/IframeManager.d.ts +1 -0
- package/dist/vanillajs/iframe/IframeManager.d.ts.map +1 -1
- package/dist/vanillajs/iframe/IframeManager.js +22 -6
- package/dist/vanillajs/iframe/IframeManager.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# 0.8.1 OAuth 2.0 Fix NextJS middleware for proxy support & bug fixes
|
|
2
|
+
|
|
3
|
+
- Fix NextJS middleware URL construction for apps behind reverse proxies
|
|
4
|
+
- Add `baseUrl` config option for reverse proxy scenarios
|
|
5
|
+
- Fix the iframe-resizer downsizing functionality when content is smaller than initial load
|
|
6
|
+
|
|
1
7
|
# 0.8.0 OAuth 2.0 Client Secret Support
|
|
2
8
|
|
|
3
9
|
- Add support for OAuth 2.0 client secrets in server-side integrations
|
package/README.md
CHANGED
|
@@ -445,7 +445,7 @@ export default withCivicAuth(nextConfig) // your next config here
|
|
|
445
445
|
|
|
446
446
|
Here are the available configuration options:
|
|
447
447
|
|
|
448
|
-
<table><thead><tr><th width="133">Field</th><th width="100">Required</th><th width="171">Default</th><th>Example</th><th>Description</th></tr></thead><tbody><tr><td>clientId</td><td>Yes</td><td>-</td><td><code>2cc5633d-2c92-48da-86aa-449634f274b9</code></td><td>The key obtained on signup to <a href="https://auth.civic.com">auth.civic.com</a></td></tr><tr><td>callbackUrl</td><td>No</td><td>/api/auth/callback</td><td>/api/myroute/callback</td><td>The path to route the browser to after a succesful login. Set this value if you are hosting your civic auth API route somewhere other than the default recommended <a href="next.js.md#create-an-api-route">above</a>.</td></tr><tr><td>loginUrl</td><td>No</td><td>/</td><td>/admin</td><td>The path your user will be sent to if they access a resource that needs them to be logged in. If you have a dedicated login page, you can set it here.</td></tr><tr><td>logoutUrl</td><td>No</td><td>/</td><td>/goodbye</td><td>The path your user will be sent to after a successful log-out.</td></tr><tr><td>include</td><td>No</td><td>['/*']</td><td><p>[</p><p> '/admin/*', '/api/admin/*'</p><p>]</p></td><td>An array of path <a href="https://man7.org/linux/man-pages/man7/glob.7.html">globs</a> that require a user to be logged-in to access. If not set, will include all paths matched by your Next.js <a href="next.js.md#middleware">middleware</a>.</td></tr><tr><td>exclude</td><td>No</td><td>-</td><td>['public/home']</td><td>An array of path <a href="https://man7.org/linux/man-pages/man7/glob.7.html">globs</a> that are excluded from the Civic Auth <a href="next.js.md#middleware">middleware</a>. In some cases, it might be easier and safer to specify exceptions rather than keep an inclusion list up to date.</td></tr></tbody></table>
|
|
448
|
+
<table><thead><tr><th width="133">Field</th><th width="100">Required</th><th width="171">Default</th><th>Example</th><th>Description</th></tr></thead><tbody><tr><td>clientId</td><td>Yes</td><td>-</td><td><code>2cc5633d-2c92-48da-86aa-449634f274b9</code></td><td>The key obtained on signup to <a href="https://auth.civic.com">auth.civic.com</a></td></tr><tr><td>callbackUrl</td><td>No</td><td>/api/auth/callback</td><td>/api/myroute/callback</td><td>The path to route the browser to after a succesful login. Set this value if you are hosting your civic auth API route somewhere other than the default recommended <a href="next.js.md#create-an-api-route">above</a>.</td></tr><tr><td>loginUrl</td><td>No</td><td>/</td><td>/admin</td><td>The path your user will be sent to if they access a resource that needs them to be logged in. If you have a dedicated login page, you can set it here.</td></tr><tr><td>logoutUrl</td><td>No</td><td>/</td><td>/goodbye</td><td>The path your user will be sent to after a successful log-out.</td></tr><tr><td>baseUrl</td><td>No</td><td>-</td><td>https://myapp.com</td><td>The public-facing base URL for apps deployed behind reverse proxies (e.g., Cloudfront + Vercel). When your app is behind a reverse proxy, the middleware may construct redirect URLs using internal origins instead of your public domain. Set this to ensure authentication redirects use the correct public URL.</td></tr><tr><td>include</td><td>No</td><td>['/*']</td><td><p>[</p><p> '/admin/*', '/api/admin/*'</p><p>]</p></td><td>An array of path <a href="https://man7.org/linux/man-pages/man7/glob.7.html">globs</a> that require a user to be logged-in to access. If not set, will include all paths matched by your Next.js <a href="next.js.md#middleware">middleware</a>.</td></tr><tr><td>exclude</td><td>No</td><td>-</td><td>['public/home']</td><td>An array of path <a href="https://man7.org/linux/man-pages/man7/glob.7.html">globs</a> that are excluded from the Civic Auth <a href="next.js.md#middleware">middleware</a>. In some cases, it might be easier and safer to specify exceptions rather than keep an inclusion list up to date.</td></tr></tbody></table>
|
|
449
449
|
|
|
450
450
|
# Server Integration
|
|
451
451
|
|
package/dist/nextjs/config.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export type AuthConfigWithDefaults = {
|
|
|
22
22
|
exclude: string[];
|
|
23
23
|
cookies: CookiesConfigObject;
|
|
24
24
|
basePath?: string;
|
|
25
|
+
baseUrl?: string;
|
|
25
26
|
};
|
|
26
27
|
/**
|
|
27
28
|
* All possible config values for Civic Auth
|
|
@@ -42,6 +43,7 @@ export type OptionalAuthConfig = Partial<AuthConfigWithDefaults | {
|
|
|
42
43
|
include?: string[];
|
|
43
44
|
exclude?: string[];
|
|
44
45
|
basePath?: string;
|
|
46
|
+
baseUrl?: string;
|
|
45
47
|
oauthServer?: string;
|
|
46
48
|
};
|
|
47
49
|
/**
|
|
@@ -130,6 +132,7 @@ export declare const createCivicAuthPlugin: (authConfig: AuthConfig) => (nextCon
|
|
|
130
132
|
_civic_auth_excludes: string;
|
|
131
133
|
_civic_auth_cookie_config: string;
|
|
132
134
|
_civic_auth_base_path: string | undefined;
|
|
135
|
+
_civic_auth_base_url: string | undefined;
|
|
133
136
|
};
|
|
134
137
|
allowedDevOrigins?: string[];
|
|
135
138
|
exportPathMap?: (defaultMap: import("next/dist/server/config-shared.js").ExportPathMap, ctx: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/nextjs/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAGvC,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAO/B,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,IAAI,EAAE,YAAY,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/nextjs/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAGvC,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAO/B,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,IAAI,EAAE,YAAY,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,CACpC,sBAAsB,GACtB;IACE,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACrC,IAAI,CAAC,EAAE,YAAY,CAAC;KACrB,CAAC;CACH,CACJ,GAAG;IAGF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,kBAAkB,GAAG;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAKF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,IAAI,CAAC,sBAAsB,EAAE,UAAU,CAkEtE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,iBAAiB,YACpB,OAAO,CAAC,UAAU,CAAC,KAC1B,sBA4CF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,qBAAqB,eAAgB,UAAU,mBACrC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA0Dy1T,CAAC;6BAAsG,CAAC;;;sBAAke,CAAC;yBAA4H,CAAC;;;qBAA+H,CAAC;;;;;;;;;;;;;;;;;;iBAA8pE,CAAC;;;;;;;6BAAg6C,CAAC;sBAAoC,CAAC;;aAAoC,CAAC;;6BAA0D,CAAC;oBAA8B,CAAC;0BAAkE,CAAC;;qBAA2C,CAAC;mBAAiC,CAAC;;wBAA+C,CAAC;eAAmD,CAAC;iBAA4C,CAAC;2BAAyC,CAAC;;;;;;;;;yBAA4zC,CAAC;6BAAwC,CAAC;;;eAAkD,CAAC;mBAAuB,CAAC;;;;CADlqgB,CAAC"}
|
package/dist/nextjs/config.js
CHANGED
|
@@ -22,6 +22,7 @@ export const defaultAuthConfig = {
|
|
|
22
22
|
include: ["/**"],
|
|
23
23
|
exclude: ["/api/auth/**"],
|
|
24
24
|
basePath: "",
|
|
25
|
+
baseUrl: undefined, // No default - will use request.nextUrl.origin when undefined
|
|
25
26
|
cookies: {
|
|
26
27
|
tokens: {
|
|
27
28
|
[OAuthTokenTypes.ID_TOKEN]: {
|
|
@@ -114,6 +115,7 @@ export const resolveAuthConfig = (config = {}) => {
|
|
|
114
115
|
? JSON.parse(process.env._civic_auth_cookie_config)
|
|
115
116
|
: undefined,
|
|
116
117
|
basePath: process.env._civic_auth_base_path || "",
|
|
118
|
+
baseUrl: process.env._civic_auth_base_url,
|
|
117
119
|
});
|
|
118
120
|
// Ensure "/api/auth/**" is always excluded
|
|
119
121
|
const finalExclude = new Set([
|
|
@@ -214,6 +216,7 @@ export const createCivicAuthPlugin = (authConfig) => {
|
|
|
214
216
|
_civic_auth_excludes: resolvedConfig.exclude.join(","),
|
|
215
217
|
_civic_auth_cookie_config: JSON.stringify(resolvedConfig.cookies),
|
|
216
218
|
_civic_auth_base_path: resolvedConfig.basePath,
|
|
219
|
+
_civic_auth_base_url: resolvedConfig.baseUrl,
|
|
217
220
|
},
|
|
218
221
|
};
|
|
219
222
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/nextjs/config.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable turbo/no-undeclared-env-vars */\nimport type { NextConfig } from \"next\";\nimport { loggers } from \"@/lib/logger.js\";\nimport { withoutUndefined } from \"@/utils.js\";\nimport {\n CodeVerifier,\n type CookieConfig,\n OAuthTokenTypes,\n type TokensCookieConfig,\n} from \"@/shared/lib/types.js\";\nimport { DEFAULT_AUTH_SERVER } from \"@/constants.js\";\nimport { merge } from \"ts-deepmerge\";\nimport { sanitizeBasePath } from \"./utils.js\";\n\nconst logger = loggers.nextjs.handlers.auth;\n\nexport type CookiesConfigObject = {\n tokens: TokensCookieConfig;\n user: CookieConfig;\n};\n\n/**\n * Configuration values for Civic Auth.\n * Only clientId is required, all others are optional.\n */\nexport type AuthConfigWithDefaults = {\n clientId: string;\n oauthServer: string;\n callbackUrl: string; // where Civic's internal OAuth callback is hosted\n loginSuccessUrl?: string; // where the user should be sent after the entire login completes, including the token exchange\n loginUrl: string;\n logoutUrl: string;\n logoutCallbackUrl: string;\n challengeUrl: string;\n refreshUrl: string;\n include: string[];\n exclude: string[];\n cookies: CookiesConfigObject;\n basePath?: string;\n};\n\n/**\n * All possible config values for Civic Auth\n */\nexport type OptionalAuthConfig = Partial<\n | AuthConfigWithDefaults\n | {\n cookies?: {\n tokens?: Partial<TokensCookieConfig>;\n user?: CookieConfig;\n };\n }\n> & {\n // Ensure TypeScript understands these properties are available\n // This doesn't change the public API, just helps TypeScript internally\n callbackUrl?: string; // where Civic's internal OAuth callback is hosted\n loginSuccessUrl?: string; // where the user should be sent after the entire login completes, including the token exchange\n loginUrl?: string;\n logoutUrl?: string;\n logoutCallbackUrl?: string;\n challengeUrl?: string;\n refreshUrl?: string;\n include?: string[];\n exclude?: string[];\n basePath?: string;\n oauthServer?: string;\n};\n\n/**\n * Configuration values for Civic Auth.\n * Only clientId is required, all others are optional.\n */\nexport type AuthConfig = OptionalAuthConfig & {\n clientId: string;\n exclude?: string[];\n};\n\nconst defaultServerSecure = !(process.env.NODE_ENV === \"development\");\nconst defaultCookiesMaxAge = 60 * 60; // 1 hour\n\n/**\n * Default configuration values that will be used if not overridden\n */\nexport const defaultAuthConfig: Omit<AuthConfigWithDefaults, \"clientId\"> = {\n oauthServer: DEFAULT_AUTH_SERVER,\n callbackUrl: \"/api/auth/callback\",\n loginSuccessUrl: undefined, // By default, the user is sent to the redirect_url\n challengeUrl: \"/api/auth/challenge\",\n refreshUrl: \"/api/auth/refresh\",\n logoutUrl: \"/api/auth/logout\",\n logoutCallbackUrl: \"/api/auth/logoutcallback\",\n loginUrl: \"/\",\n include: [\"/**\"],\n exclude: [\"/api/auth/**\"],\n basePath: \"\",\n cookies: {\n tokens: {\n [OAuthTokenTypes.ID_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.ACCESS_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.REFRESH_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT]: {\n secure: defaultServerSecure,\n httpOnly: false, // we need this to be available client-side\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [CodeVerifier.COOKIE_NAME]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [CodeVerifier.APP_URL]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n },\n user: {\n secure: defaultServerSecure,\n httpOnly: false, // we need this to be available client-side\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n },\n};\n\n/**\n * Resolves the authentication configuration by combining:\n * 1. Default values\n * 2. Environment variables (set internally by the plugin)\n * 3. Explicitly passed configuration\n *\n * Config will be merged deeply, with arrays not merged, so that the\n * default include list (for example) [\"/*\"] will not be added\n *\n * Note: Developers should not set _civic_auth_* environment variables directly.\n * Instead, pass configuration to the createCivicAuthPlugin in next.config.js:\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * callbackUrl: '/custom/callback',\n * })\n * ```\n */\nexport const resolveAuthConfig = (\n config: Partial<AuthConfig> = {},\n): AuthConfigWithDefaults => {\n // Read configuration that was set by the plugin via environment variables\n const configFromEnv = withoutUndefined({\n clientId: process.env._civic_auth_client_id,\n oauthServer: process.env._civic_oauth_server,\n callbackUrl: process.env._civic_auth_callback_url,\n loginSuccessUrl: process.env._civic_auth_login_success_url,\n challengeUrl: process.env._civic_auth_challenge_url,\n loginUrl: process.env._civic_auth_login_url,\n logoutUrl: process.env._civic_auth_logout_url,\n logoutCallbackUrl: process.env._civic_auth_logout_callback_url,\n refreshUrl: process.env._civic_auth_refresh_url,\n include: process.env._civic_auth_includes?.split(\",\"),\n exclude: process.env._civic_auth_excludes?.split(\",\"),\n cookies: process.env._civic_auth_cookie_config\n ? JSON.parse(process.env._civic_auth_cookie_config)\n : undefined,\n basePath: process.env._civic_auth_base_path || \"\",\n }) as AuthConfig;\n\n // Ensure \"/api/auth/**\" is always excluded\n const finalExclude = new Set([\n ...defaultAuthConfig.exclude,\n ...(configFromEnv.exclude || []),\n ...(config.exclude ?? []),\n ]);\n\n // Perform a deep merge of the configurations\n const mergedConfig = merge.withOptions(\n { mergeArrays: false },\n defaultAuthConfig,\n configFromEnv,\n config,\n );\n\n // Override the exclude list with the ensured list\n mergedConfig.exclude = Array.from(finalExclude);\n\n if (mergedConfig.clientId === undefined) {\n throw new Error(\"Civic Auth client ID is required\");\n }\n\n return mergedConfig as AuthConfigWithDefaults & { clientId: string };\n};\n\n/**\n * Creates a Next.js plugin that handles auth configuration.\n *\n * This is the main configuration point for the auth system.\n * Do not set _civic_auth_* environment variables directly - instead,\n * pass your configuration here.\n *\n * The only required field is clientId.\n *\n * Notes:\n * - If you provide explicit URLs, they will be used exactly as provided.\n * - Default URLs will automatically include the basePath from your Next.js config.\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * clientId: 'my-client-id',\n * });\n * ```\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * clientId: 'my-client-id',\n * callbackUrl: '/custom/callback',\n * loginUrl: '/custom/login',\n * logoutUrl: '/custom/logout',\n * logoutCallbackUrl: '/custom/logoutcallback',\n * include: ['/protected/*'],\n * exclude: ['/public/*']\n * })\n * ```\n *\n * The plugin sets internal environment variables that are used by\n * the auth system. These variables should not be set manually.\n */\nexport const createCivicAuthPlugin = (authConfig: AuthConfig) => {\n return (nextConfig?: NextConfig) => {\n logger.debug(\n \"createCivicAuthPlugin nextConfig\",\n JSON.stringify(nextConfig, null, 2),\n );\n\n // Extract basePath from Next.js config\n const basePath = sanitizeBasePath(nextConfig?.basePath || \"\");\n\n // Create a copy of default URLs with basePath added\n const defaultUrlsWithBasePath: Partial<AuthConfig> = {};\n\n // Only apply to URLs that aren't explicitly set in authConfig\n if (basePath) {\n if (!authConfig.callbackUrl)\n defaultUrlsWithBasePath.callbackUrl = `${basePath}/api/auth/callback`;\n if (!authConfig.challengeUrl)\n defaultUrlsWithBasePath.challengeUrl = `${basePath}/api/auth/challenge`;\n if (!authConfig.refreshUrl)\n defaultUrlsWithBasePath.refreshUrl = `${basePath}/api/auth/refresh`;\n if (!authConfig.logoutUrl)\n defaultUrlsWithBasePath.logoutUrl = `${basePath}/api/auth/logout`;\n if (!authConfig.logoutCallbackUrl)\n defaultUrlsWithBasePath.logoutCallbackUrl = `${basePath}/api/auth/logoutcallback`;\n if (!authConfig.loginUrl && authConfig.loginUrl !== \"\")\n defaultUrlsWithBasePath.loginUrl = basePath;\n }\n\n // Create final config with basePath and possibly modified URLs\n const resolvedConfig = resolveAuthConfig({\n ...defaultUrlsWithBasePath,\n ...authConfig,\n basePath,\n });\n\n return {\n ...nextConfig,\n env: {\n ...nextConfig?.env,\n // Internal environment variables - do not set these manually\n _civic_auth_client_id: resolvedConfig.clientId,\n _civic_oauth_server: resolvedConfig.oauthServer,\n _civic_auth_callback_url: resolvedConfig.callbackUrl,\n _civic_auth_login_success_url: resolvedConfig.loginSuccessUrl,\n _civic_auth_challenge_url: resolvedConfig.challengeUrl,\n _civic_auth_login_url: resolvedConfig.loginUrl,\n _civic_auth_logout_url: resolvedConfig.logoutUrl,\n _civic_auth_logout_callback_url: resolvedConfig.logoutCallbackUrl,\n _civic_auth_refresh_url: resolvedConfig.refreshUrl,\n _civic_auth_includes: resolvedConfig.include.join(\",\"),\n _civic_auth_excludes: resolvedConfig.exclude.join(\",\"),\n _civic_auth_cookie_config: JSON.stringify(resolvedConfig.cookies),\n _civic_auth_base_path: resolvedConfig.basePath,\n },\n };\n };\n};\n"]}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/nextjs/config.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable turbo/no-undeclared-env-vars */\nimport type { NextConfig } from \"next\";\nimport { loggers } from \"@/lib/logger.js\";\nimport { withoutUndefined } from \"@/utils.js\";\nimport {\n CodeVerifier,\n type CookieConfig,\n OAuthTokenTypes,\n type TokensCookieConfig,\n} from \"@/shared/lib/types.js\";\nimport { DEFAULT_AUTH_SERVER } from \"@/constants.js\";\nimport { merge } from \"ts-deepmerge\";\nimport { sanitizeBasePath } from \"./utils.js\";\n\nconst logger = loggers.nextjs.handlers.auth;\n\nexport type CookiesConfigObject = {\n tokens: TokensCookieConfig;\n user: CookieConfig;\n};\n\n/**\n * Configuration values for Civic Auth.\n * Only clientId is required, all others are optional.\n */\nexport type AuthConfigWithDefaults = {\n clientId: string;\n oauthServer: string;\n callbackUrl: string; // where Civic's internal OAuth callback is hosted\n loginSuccessUrl?: string; // where the user should be sent after the entire login completes, including the token exchange\n loginUrl: string;\n logoutUrl: string;\n logoutCallbackUrl: string;\n challengeUrl: string;\n refreshUrl: string;\n include: string[];\n exclude: string[];\n cookies: CookiesConfigObject;\n basePath?: string;\n baseUrl?: string; // Public domain for apps behind reverse proxies (e.g., \"https://myapp.com\")\n};\n\n/**\n * All possible config values for Civic Auth\n */\nexport type OptionalAuthConfig = Partial<\n | AuthConfigWithDefaults\n | {\n cookies?: {\n tokens?: Partial<TokensCookieConfig>;\n user?: CookieConfig;\n };\n }\n> & {\n // Ensure TypeScript understands these properties are available\n // This doesn't change the public API, just helps TypeScript internally\n callbackUrl?: string; // where Civic's internal OAuth callback is hosted\n loginSuccessUrl?: string; // where the user should be sent after the entire login completes, including the token exchange\n loginUrl?: string;\n logoutUrl?: string;\n logoutCallbackUrl?: string;\n challengeUrl?: string;\n refreshUrl?: string;\n include?: string[];\n exclude?: string[];\n basePath?: string;\n baseUrl?: string;\n oauthServer?: string;\n};\n\n/**\n * Configuration values for Civic Auth.\n * Only clientId is required, all others are optional.\n */\nexport type AuthConfig = OptionalAuthConfig & {\n clientId: string;\n exclude?: string[];\n};\n\nconst defaultServerSecure = !(process.env.NODE_ENV === \"development\");\nconst defaultCookiesMaxAge = 60 * 60; // 1 hour\n\n/**\n * Default configuration values that will be used if not overridden\n */\nexport const defaultAuthConfig: Omit<AuthConfigWithDefaults, \"clientId\"> = {\n oauthServer: DEFAULT_AUTH_SERVER,\n callbackUrl: \"/api/auth/callback\",\n loginSuccessUrl: undefined, // By default, the user is sent to the redirect_url\n challengeUrl: \"/api/auth/challenge\",\n refreshUrl: \"/api/auth/refresh\",\n logoutUrl: \"/api/auth/logout\",\n logoutCallbackUrl: \"/api/auth/logoutcallback\",\n loginUrl: \"/\",\n include: [\"/**\"],\n exclude: [\"/api/auth/**\"],\n basePath: \"\",\n baseUrl: undefined, // No default - will use request.nextUrl.origin when undefined\n cookies: {\n tokens: {\n [OAuthTokenTypes.ID_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.ACCESS_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.REFRESH_TOKEN]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT]: {\n secure: defaultServerSecure,\n httpOnly: false, // we need this to be available client-side\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [CodeVerifier.COOKIE_NAME]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n [CodeVerifier.APP_URL]: {\n secure: defaultServerSecure,\n httpOnly: true,\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n },\n user: {\n secure: defaultServerSecure,\n httpOnly: false, // we need this to be available client-side\n sameSite: \"strict\",\n path: \"/\",\n maxAge: defaultCookiesMaxAge,\n },\n },\n};\n\n/**\n * Resolves the authentication configuration by combining:\n * 1. Default values\n * 2. Environment variables (set internally by the plugin)\n * 3. Explicitly passed configuration\n *\n * Config will be merged deeply, with arrays not merged, so that the\n * default include list (for example) [\"/*\"] will not be added\n *\n * Note: Developers should not set _civic_auth_* environment variables directly.\n * Instead, pass configuration to the createCivicAuthPlugin in next.config.js:\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * callbackUrl: '/custom/callback',\n * })\n * ```\n */\nexport const resolveAuthConfig = (\n config: Partial<AuthConfig> = {},\n): AuthConfigWithDefaults => {\n // Read configuration that was set by the plugin via environment variables\n const configFromEnv = withoutUndefined({\n clientId: process.env._civic_auth_client_id,\n oauthServer: process.env._civic_oauth_server,\n callbackUrl: process.env._civic_auth_callback_url,\n loginSuccessUrl: process.env._civic_auth_login_success_url,\n challengeUrl: process.env._civic_auth_challenge_url,\n loginUrl: process.env._civic_auth_login_url,\n logoutUrl: process.env._civic_auth_logout_url,\n logoutCallbackUrl: process.env._civic_auth_logout_callback_url,\n refreshUrl: process.env._civic_auth_refresh_url,\n include: process.env._civic_auth_includes?.split(\",\"),\n exclude: process.env._civic_auth_excludes?.split(\",\"),\n cookies: process.env._civic_auth_cookie_config\n ? JSON.parse(process.env._civic_auth_cookie_config)\n : undefined,\n basePath: process.env._civic_auth_base_path || \"\",\n baseUrl: process.env._civic_auth_base_url,\n }) as AuthConfig;\n\n // Ensure \"/api/auth/**\" is always excluded\n const finalExclude = new Set([\n ...defaultAuthConfig.exclude,\n ...(configFromEnv.exclude || []),\n ...(config.exclude ?? []),\n ]);\n\n // Perform a deep merge of the configurations\n const mergedConfig = merge.withOptions(\n { mergeArrays: false },\n defaultAuthConfig,\n configFromEnv,\n config,\n );\n\n // Override the exclude list with the ensured list\n mergedConfig.exclude = Array.from(finalExclude);\n\n if (mergedConfig.clientId === undefined) {\n throw new Error(\"Civic Auth client ID is required\");\n }\n\n return mergedConfig as AuthConfigWithDefaults & { clientId: string };\n};\n\n/**\n * Creates a Next.js plugin that handles auth configuration.\n *\n * This is the main configuration point for the auth system.\n * Do not set _civic_auth_* environment variables directly - instead,\n * pass your configuration here.\n *\n * The only required field is clientId.\n *\n * Notes:\n * - If you provide explicit URLs, they will be used exactly as provided.\n * - Default URLs will automatically include the basePath from your Next.js config.\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * clientId: 'my-client-id',\n * });\n * ```\n *\n * @example\n * ```js\n * // next.config.js\n * export default createCivicAuthPlugin({\n * clientId: 'my-client-id',\n * callbackUrl: '/custom/callback',\n * loginUrl: '/custom/login',\n * logoutUrl: '/custom/logout',\n * logoutCallbackUrl: '/custom/logoutcallback',\n * include: ['/protected/*'],\n * exclude: ['/public/*']\n * })\n * ```\n *\n * The plugin sets internal environment variables that are used by\n * the auth system. These variables should not be set manually.\n */\nexport const createCivicAuthPlugin = (authConfig: AuthConfig) => {\n return (nextConfig?: NextConfig) => {\n logger.debug(\n \"createCivicAuthPlugin nextConfig\",\n JSON.stringify(nextConfig, null, 2),\n );\n\n // Extract basePath from Next.js config\n const basePath = sanitizeBasePath(nextConfig?.basePath || \"\");\n\n // Create a copy of default URLs with basePath added\n const defaultUrlsWithBasePath: Partial<AuthConfig> = {};\n\n // Only apply to URLs that aren't explicitly set in authConfig\n if (basePath) {\n if (!authConfig.callbackUrl)\n defaultUrlsWithBasePath.callbackUrl = `${basePath}/api/auth/callback`;\n if (!authConfig.challengeUrl)\n defaultUrlsWithBasePath.challengeUrl = `${basePath}/api/auth/challenge`;\n if (!authConfig.refreshUrl)\n defaultUrlsWithBasePath.refreshUrl = `${basePath}/api/auth/refresh`;\n if (!authConfig.logoutUrl)\n defaultUrlsWithBasePath.logoutUrl = `${basePath}/api/auth/logout`;\n if (!authConfig.logoutCallbackUrl)\n defaultUrlsWithBasePath.logoutCallbackUrl = `${basePath}/api/auth/logoutcallback`;\n if (!authConfig.loginUrl && authConfig.loginUrl !== \"\")\n defaultUrlsWithBasePath.loginUrl = basePath;\n }\n\n // Create final config with basePath and possibly modified URLs\n const resolvedConfig = resolveAuthConfig({\n ...defaultUrlsWithBasePath,\n ...authConfig,\n basePath,\n });\n\n return {\n ...nextConfig,\n env: {\n ...nextConfig?.env,\n // Internal environment variables - do not set these manually\n _civic_auth_client_id: resolvedConfig.clientId,\n _civic_oauth_server: resolvedConfig.oauthServer,\n _civic_auth_callback_url: resolvedConfig.callbackUrl,\n _civic_auth_login_success_url: resolvedConfig.loginSuccessUrl,\n _civic_auth_challenge_url: resolvedConfig.challengeUrl,\n _civic_auth_login_url: resolvedConfig.loginUrl,\n _civic_auth_logout_url: resolvedConfig.logoutUrl,\n _civic_auth_logout_callback_url: resolvedConfig.logoutCallbackUrl,\n _civic_auth_refresh_url: resolvedConfig.refreshUrl,\n _civic_auth_includes: resolvedConfig.include.join(\",\"),\n _civic_auth_excludes: resolvedConfig.exclude.join(\",\"),\n _civic_auth_cookie_config: JSON.stringify(resolvedConfig.cookies),\n _civic_auth_base_path: resolvedConfig.basePath,\n _civic_auth_base_url: resolvedConfig.baseUrl,\n },\n };\n };\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/nextjs/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,YAAY,CAAC;AA+B3D,KAAK,UAAU,GAAG,CAChB,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/nextjs/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,YAAY,CAAC;AA+B3D,KAAK,UAAU,GAAG,CAChB,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;AAoC1C;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,2BACd,sBAAsB,WACrC,WAAW,KACnB,OAAO,CAAC,WAAW,CAoBrB,CAAC;AA0HF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,gBACZ,kBAAkB,eACf,WAAW,KAAG,OAAO,CAAC,YAAY,CAOjD,CAAC;AAEJ;;;;;;;GAOG;AAEH,wBAAgB,QAAQ,CACtB,UAAU,EAAE,UAAU,GACrB,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAEjD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,UAAU,GAAE,kBAAuB,gBAExC,UAAU,KACrB,CAAC,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC,CAQrD"}
|
|
@@ -49,6 +49,14 @@ const matchesGlobs = (pathname, patterns) => patterns.some((pattern) => {
|
|
|
49
49
|
return false;
|
|
50
50
|
return matchGlob(pathname, pattern);
|
|
51
51
|
});
|
|
52
|
+
const getOriginUrl = (request, authConfig) => {
|
|
53
|
+
// Use configured baseUrl if provided (for reverse proxy scenarios)
|
|
54
|
+
if (authConfig.baseUrl) {
|
|
55
|
+
return authConfig.baseUrl;
|
|
56
|
+
}
|
|
57
|
+
// Fallback to nextUrl.origin (includes port automatically)
|
|
58
|
+
return request.nextUrl.origin;
|
|
59
|
+
};
|
|
52
60
|
/**
|
|
53
61
|
* use a ServerAuthenticationResolver to validate the existing session
|
|
54
62
|
* using NextJS cookie storage
|
|
@@ -118,12 +126,12 @@ const applyAuth = async (authConfig, request) => {
|
|
|
118
126
|
}
|
|
119
127
|
// Handle unauthenticated users on protected routes
|
|
120
128
|
if (!session.authenticated) {
|
|
121
|
-
const targetUrl = request
|
|
129
|
+
const targetUrl = getOriginUrl(request, authConfigWithDefaults) + request.nextUrl.pathname;
|
|
122
130
|
// Avoid redirect loops by checking if already in a redirect flow
|
|
123
131
|
if (!request.nextUrl.searchParams.has("targetUrl")) {
|
|
124
132
|
// Attempt session rehydration if refresh token exists
|
|
125
133
|
if (session.refreshToken) {
|
|
126
|
-
const refreshUrl = new URL(authConfigWithDefaults.refreshUrl, request
|
|
134
|
+
const refreshUrl = new URL(authConfigWithDefaults.refreshUrl, getOriginUrl(request, authConfigWithDefaults));
|
|
127
135
|
refreshUrl.searchParams.set("targetUrl", targetUrl);
|
|
128
136
|
const redirectUrl = `${refreshUrl.toString()}`;
|
|
129
137
|
logger.debug(`→ Refresh token found - redirecting to "${redirectUrl}"`);
|
|
@@ -131,7 +139,7 @@ const applyAuth = async (authConfig, request) => {
|
|
|
131
139
|
}
|
|
132
140
|
// Clear expired/invalid tokens if they exist without refresh token
|
|
133
141
|
if (session.accessToken || session.idToken) {
|
|
134
|
-
const clearBadTokensUrl = new URL(authConfigWithDefaults.logoutCallbackUrl, request
|
|
142
|
+
const clearBadTokensUrl = new URL(authConfigWithDefaults.logoutCallbackUrl, getOriginUrl(request, authConfigWithDefaults));
|
|
135
143
|
clearBadTokensUrl.searchParams.set("targetUrl", targetUrl);
|
|
136
144
|
logger.debug(`→ Invalid tokens found without refresh - clearing via "${clearBadTokensUrl}"`);
|
|
137
145
|
return NextResponse.redirect(clearBadTokensUrl);
|
|
@@ -143,7 +151,7 @@ const applyAuth = async (authConfig, request) => {
|
|
|
143
151
|
return undefined;
|
|
144
152
|
}
|
|
145
153
|
// Final fallback: redirect to login
|
|
146
|
-
const loginUrl = new URL(authConfigWithDefaults.loginUrl, request
|
|
154
|
+
const loginUrl = new URL(authConfigWithDefaults.loginUrl, getOriginUrl(request, authConfigWithDefaults));
|
|
147
155
|
const redirectUrl = `${loginUrl.toString()}`;
|
|
148
156
|
logger.debug(`→ No valid tokens found - redirecting to login "${redirectUrl}"`);
|
|
149
157
|
return NextResponse.redirect(redirectUrl);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/nextjs/middleware.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Authenticates the user on all requests by checking the token cookie\n *\n * Usage:\n * Option 1: use if no other middleware (e.g. no next-intl etc)\n * export default authMiddleware();\n *\n * Option 2: use if other middleware is needed - default auth config\n * export default withAuth((request) => {\n * logger.debug('in custom middleware', request.nextUrl.pathname);\n * return NextResponse.next();\n * })\n *\n * Option 3: use if other middleware is needed - specifying auth config\n * const withCivicAuth = auth({ loginUrl: '/login', include: ['/[.*]/user'] })\n * export default withCivicAuth((request) => {\n * logger.debug('in custom middleware', request.url);\n * return NextResponse.next();\n * })\n *\n */\nimport type { NextRequest } from \"next/server.js\";\nimport { NextResponse } from \"next/server.js\";\nimport picomatch from \"picomatch\";\nimport type {\n AuthConfigWithDefaults,\n OptionalAuthConfig,\n} from \"@/nextjs/config.js\";\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport { ServerAuthenticationResolver } from \"@/server/ServerAuthenticationResolver.js\";\nimport type { AuthStorage, SessionData } from \"@/types.js\";\n\nconst logger = loggers.nextjs.middleware;\n\n/**\n * CookieStorage implementation for NextJS middleware context that works with NextRequest\n */\nclass NextjsReadOnlyRequestCookieStorage implements AuthStorage {\n constructor(private request: NextRequest) {}\n\n async get(key: string): Promise<string | null> {\n return this.request.cookies.get(key)?.value || null;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async set(key: string, value: string): Promise<void> {\n // In middleware, we can only set cookies via response objects\n // This method can't be used directly in middleware\n logger.error(\"Cannot set cookies directly in middleware\");\n throw new Error(\"Cannot set cookies directly in middleware\");\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async delete(key: string): Promise<void> {\n // In middleware, we can only delete cookies via response objects\n // This method can't be used directly in middleware\n logger.error(\"Cannot delete cookies directly in middleware\");\n throw new Error(\"Cannot delete cookies directly in middleware\");\n }\n}\n\ntype Middleware = (\n request: NextRequest,\n) => Promise<NextResponse> | NextResponse;\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchGlob = (pathname: string, globPattern: string) => {\n const matches = picomatch(globPattern);\n return matches(pathname);\n};\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchesGlobs = (pathname: string, patterns: string[]) =>\n patterns.some((pattern) => {\n if (!pattern) return false;\n return matchGlob(pathname, pattern);\n });\n\n/**\n * use a ServerAuthenticationResolver to validate the existing session\n * using NextJS cookie storage\n * @param authConfigWithDefaults\n * @param request NextRequest object from middleware\n * @returns {Promise<SessionData>}\n */\nexport const validateAuthTokensIfPresent = async (\n authConfigWithDefaults: AuthConfigWithDefaults,\n request: NextRequest,\n): Promise<SessionData> => {\n try {\n // TODO: evaluate a more performant way to validate tokens\n // than having to call and verify the JWT tokens on every request\n const storage = new NextjsReadOnlyRequestCookieStorage(request);\n const authSessionService = await ServerAuthenticationResolver.build(\n {\n ...authConfigWithDefaults,\n redirectUrl: authConfigWithDefaults.callbackUrl,\n },\n storage,\n );\n // validate the existing session but don't auto-refresh as we can't set cookies in middleware\n const existingSession =\n await authSessionService.validateExistingSession(false);\n return existingSession;\n } catch (error) {\n logger.error(\"Error validating tokens\", error);\n return { authenticated: false };\n }\n};\n// internal - used by all exported functions\n/**\n * Core authentication middleware logic.\n *\n * Flow:\n * 1. Always validate tokens first to determine authentication state\n * 2. Skip protection for Civic Auth system URLs and excluded paths\n * 3. For unauthenticated users on protected routes:\n * - If refresh token exists: redirect to refresh endpoint\n * - If expired tokens exist: redirect to logout callback to clear them\n * - If on login URL: allow access (prevents redirect loops)\n * - Otherwise: redirect to login\n * 4. Allow authenticated users to continue\n */\nconst applyAuth = async (\n authConfig: OptionalAuthConfig,\n request: NextRequest,\n): Promise<NextResponse | undefined> => {\n const authConfigWithDefaults = resolveAuthConfig(authConfig);\n // Always validate tokens first to determine authentication state\n const session = await validateAuthTokensIfPresent(\n authConfigWithDefaults,\n request,\n );\n logger.debug(\"applyAuth session data:\", session);\n\n // Skip auth protection for Civic Auth system URLs (callback, challenge, logout)\n if (\n [\n authConfigWithDefaults.callbackUrl,\n authConfigWithDefaults.challengeUrl,\n authConfigWithDefaults.logoutCallbackUrl,\n authConfigWithDefaults.logoutUrl,\n ].includes(request.nextUrl.pathname) &&\n request.method === \"GET\"\n ) {\n logger.debug(\n \"→ Skipping auth check - this a URL defined in authConfig\",\n request.nextUrl.pathname,\n );\n return undefined;\n }\n\n // Skip auth protection for paths not in include patterns (except loginUrl)\n if (\n request.nextUrl.pathname !== authConfigWithDefaults.loginUrl &&\n !matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.include)\n ) {\n logger.debug(\n \"→ Skipping auth check - path not in include patterns\",\n request.nextUrl.pathname,\n );\n return undefined;\n }\n\n // Skip auth protection for paths in exclude patterns (except loginUrl)\n if (\n request.nextUrl.pathname !== authConfigWithDefaults.loginUrl &&\n matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.exclude)\n ) {\n logger.debug(\n \"→ Skipping auth check - path in exclude patterns\",\n request.nextUrl.pathname,\n );\n return undefined;\n }\n\n // Handle unauthenticated users on protected routes\n if (!session.authenticated) {\n const targetUrl = request.nextUrl.origin + request.nextUrl.pathname;\n\n // Avoid redirect loops by checking if already in a redirect flow\n if (!request.nextUrl.searchParams.has(\"targetUrl\")) {\n // Attempt session rehydration if refresh token exists\n if (session.refreshToken) {\n const refreshUrl = new URL(\n authConfigWithDefaults.refreshUrl,\n request.nextUrl.origin,\n );\n refreshUrl.searchParams.set(\"targetUrl\", targetUrl);\n const redirectUrl = `${refreshUrl.toString()}`;\n logger.debug(`→ Refresh token found - redirecting to \"${redirectUrl}\"`);\n return NextResponse.redirect(redirectUrl);\n }\n\n // Clear expired/invalid tokens if they exist without refresh token\n if (session.accessToken || session.idToken) {\n const clearBadTokensUrl = new URL(\n authConfigWithDefaults.logoutCallbackUrl,\n request.nextUrl.origin,\n );\n clearBadTokensUrl.searchParams.set(\"targetUrl\", targetUrl);\n logger.debug(\n `→ Invalid tokens found without refresh - clearing via \"${clearBadTokensUrl}\"`,\n );\n return NextResponse.redirect(clearBadTokensUrl);\n }\n }\n\n // Allow access to login page to prevent redirect loops\n if (request.nextUrl.pathname === authConfigWithDefaults.loginUrl) {\n logger.debug(`→ Allowing access to login page for unauthenticated user`);\n return undefined;\n }\n\n // Final fallback: redirect to login\n const loginUrl = new URL(\n authConfigWithDefaults.loginUrl,\n request.nextUrl.origin,\n );\n const redirectUrl = `${loginUrl.toString()}`;\n logger.debug(\n `→ No valid tokens found - redirecting to login \"${redirectUrl}\"`,\n );\n return NextResponse.redirect(redirectUrl);\n }\n logger.debug(\"→ Auth check passed\");\n return undefined;\n};\n\n/**\n *\n * Use this when auth is the only middleware you need.\n * Usage:\n *\n * export default authMiddleware({ loginUrl = '/login' }); // or just authMiddleware();\n *\n */\nexport const authMiddleware =\n (authConfig: OptionalAuthConfig = {}) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n // NextJS doesn't do middleware chaining yet, so this does not mean\n // \"call the next middleware\" - it means \"continue to the route handler\"\n return NextResponse.next();\n };\n\n/**\n * Usage:\n *\n * export default withAuth(async (request) => {\n * logger.debug('my middleware');\n * return NextResponse.next();\n * })\n */\n// use this when you have your own middleware to chain\nexport function withAuth(\n middleware: Middleware,\n): (request: NextRequest) => Promise<NextResponse> {\n return auth()(middleware);\n}\n\n/**\n * Use this when you want to configure the middleware here (an alternative is to do it in the next.config file)\n *\n * Usage:\n *\n * export default auth(authConfig: AuthConfig ) => {\n * logger.debug('my middleware');\n * return NextResponse.next();\n * })\n *\n */\nexport function auth(authConfig: OptionalAuthConfig = {}) {\n return (\n middleware: Middleware,\n ): ((request: NextRequest) => Promise<NextResponse>) => {\n return async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n return middleware(request);\n };\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/nextjs/middleware.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Authenticates the user on all requests by checking the token cookie\n *\n * Usage:\n * Option 1: use if no other middleware (e.g. no next-intl etc)\n * export default authMiddleware();\n *\n * Option 2: use if other middleware is needed - default auth config\n * export default withAuth((request) => {\n * logger.debug('in custom middleware', request.nextUrl.pathname);\n * return NextResponse.next();\n * })\n *\n * Option 3: use if other middleware is needed - specifying auth config\n * const withCivicAuth = auth({ loginUrl: '/login', include: ['/[.*]/user'] })\n * export default withCivicAuth((request) => {\n * logger.debug('in custom middleware', request.url);\n * return NextResponse.next();\n * })\n *\n */\nimport type { NextRequest } from \"next/server.js\";\nimport { NextResponse } from \"next/server.js\";\nimport picomatch from \"picomatch\";\nimport type {\n AuthConfigWithDefaults,\n OptionalAuthConfig,\n} from \"@/nextjs/config.js\";\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport { loggers } from \"@/lib/logger.js\";\nimport { ServerAuthenticationResolver } from \"@/server/ServerAuthenticationResolver.js\";\nimport type { AuthStorage, SessionData } from \"@/types.js\";\n\nconst logger = loggers.nextjs.middleware;\n\n/**\n * CookieStorage implementation for NextJS middleware context that works with NextRequest\n */\nclass NextjsReadOnlyRequestCookieStorage implements AuthStorage {\n constructor(private request: NextRequest) {}\n\n async get(key: string): Promise<string | null> {\n return this.request.cookies.get(key)?.value || null;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async set(key: string, value: string): Promise<void> {\n // In middleware, we can only set cookies via response objects\n // This method can't be used directly in middleware\n logger.error(\"Cannot set cookies directly in middleware\");\n throw new Error(\"Cannot set cookies directly in middleware\");\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async delete(key: string): Promise<void> {\n // In middleware, we can only delete cookies via response objects\n // This method can't be used directly in middleware\n logger.error(\"Cannot delete cookies directly in middleware\");\n throw new Error(\"Cannot delete cookies directly in middleware\");\n }\n}\n\ntype Middleware = (\n request: NextRequest,\n) => Promise<NextResponse> | NextResponse;\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchGlob = (pathname: string, globPattern: string) => {\n const matches = picomatch(globPattern);\n return matches(pathname);\n};\n\n// Matches globs:\n// Examples:\n// /user\n// /user/*\n// /user/**/info\nconst matchesGlobs = (pathname: string, patterns: string[]) =>\n patterns.some((pattern) => {\n if (!pattern) return false;\n return matchGlob(pathname, pattern);\n });\n\nconst getOriginUrl = (\n request: NextRequest,\n authConfig: AuthConfigWithDefaults,\n): string => {\n // Use configured baseUrl if provided (for reverse proxy scenarios)\n if (authConfig.baseUrl) {\n return authConfig.baseUrl;\n }\n\n // Fallback to nextUrl.origin (includes port automatically)\n return request.nextUrl.origin;\n};\n\n/**\n * use a ServerAuthenticationResolver to validate the existing session\n * using NextJS cookie storage\n * @param authConfigWithDefaults\n * @param request NextRequest object from middleware\n * @returns {Promise<SessionData>}\n */\nexport const validateAuthTokensIfPresent = async (\n authConfigWithDefaults: AuthConfigWithDefaults,\n request: NextRequest,\n): Promise<SessionData> => {\n try {\n // TODO: evaluate a more performant way to validate tokens\n // than having to call and verify the JWT tokens on every request\n const storage = new NextjsReadOnlyRequestCookieStorage(request);\n const authSessionService = await ServerAuthenticationResolver.build(\n {\n ...authConfigWithDefaults,\n redirectUrl: authConfigWithDefaults.callbackUrl,\n },\n storage,\n );\n // validate the existing session but don't auto-refresh as we can't set cookies in middleware\n const existingSession =\n await authSessionService.validateExistingSession(false);\n return existingSession;\n } catch (error) {\n logger.error(\"Error validating tokens\", error);\n return { authenticated: false };\n }\n};\n// internal - used by all exported functions\n/**\n * Core authentication middleware logic.\n *\n * Flow:\n * 1. Always validate tokens first to determine authentication state\n * 2. Skip protection for Civic Auth system URLs and excluded paths\n * 3. For unauthenticated users on protected routes:\n * - If refresh token exists: redirect to refresh endpoint\n * - If expired tokens exist: redirect to logout callback to clear them\n * - If on login URL: allow access (prevents redirect loops)\n * - Otherwise: redirect to login\n * 4. Allow authenticated users to continue\n */\nconst applyAuth = async (\n authConfig: OptionalAuthConfig,\n request: NextRequest,\n): Promise<NextResponse | undefined> => {\n const authConfigWithDefaults = resolveAuthConfig(authConfig);\n // Always validate tokens first to determine authentication state\n const session = await validateAuthTokensIfPresent(\n authConfigWithDefaults,\n request,\n );\n logger.debug(\"applyAuth session data:\", session);\n\n // Skip auth protection for Civic Auth system URLs (callback, challenge, logout)\n if (\n [\n authConfigWithDefaults.callbackUrl,\n authConfigWithDefaults.challengeUrl,\n authConfigWithDefaults.logoutCallbackUrl,\n authConfigWithDefaults.logoutUrl,\n ].includes(request.nextUrl.pathname) &&\n request.method === \"GET\"\n ) {\n logger.debug(\n \"→ Skipping auth check - this a URL defined in authConfig\",\n request.nextUrl.pathname,\n );\n return undefined;\n }\n\n // Skip auth protection for paths not in include patterns (except loginUrl)\n if (\n request.nextUrl.pathname !== authConfigWithDefaults.loginUrl &&\n !matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.include)\n ) {\n logger.debug(\n \"→ Skipping auth check - path not in include patterns\",\n request.nextUrl.pathname,\n );\n return undefined;\n }\n\n // Skip auth protection for paths in exclude patterns (except loginUrl)\n if (\n request.nextUrl.pathname !== authConfigWithDefaults.loginUrl &&\n matchesGlobs(request.nextUrl.pathname, authConfigWithDefaults.exclude)\n ) {\n logger.debug(\n \"→ Skipping auth check - path in exclude patterns\",\n request.nextUrl.pathname,\n );\n return undefined;\n }\n\n // Handle unauthenticated users on protected routes\n if (!session.authenticated) {\n const targetUrl =\n getOriginUrl(request, authConfigWithDefaults) + request.nextUrl.pathname;\n\n // Avoid redirect loops by checking if already in a redirect flow\n if (!request.nextUrl.searchParams.has(\"targetUrl\")) {\n // Attempt session rehydration if refresh token exists\n if (session.refreshToken) {\n const refreshUrl = new URL(\n authConfigWithDefaults.refreshUrl,\n getOriginUrl(request, authConfigWithDefaults),\n );\n refreshUrl.searchParams.set(\"targetUrl\", targetUrl);\n const redirectUrl = `${refreshUrl.toString()}`;\n logger.debug(`→ Refresh token found - redirecting to \"${redirectUrl}\"`);\n return NextResponse.redirect(redirectUrl);\n }\n\n // Clear expired/invalid tokens if they exist without refresh token\n if (session.accessToken || session.idToken) {\n const clearBadTokensUrl = new URL(\n authConfigWithDefaults.logoutCallbackUrl,\n getOriginUrl(request, authConfigWithDefaults),\n );\n clearBadTokensUrl.searchParams.set(\"targetUrl\", targetUrl);\n logger.debug(\n `→ Invalid tokens found without refresh - clearing via \"${clearBadTokensUrl}\"`,\n );\n return NextResponse.redirect(clearBadTokensUrl);\n }\n }\n\n // Allow access to login page to prevent redirect loops\n if (request.nextUrl.pathname === authConfigWithDefaults.loginUrl) {\n logger.debug(`→ Allowing access to login page for unauthenticated user`);\n return undefined;\n }\n\n // Final fallback: redirect to login\n const loginUrl = new URL(\n authConfigWithDefaults.loginUrl,\n getOriginUrl(request, authConfigWithDefaults),\n );\n const redirectUrl = `${loginUrl.toString()}`;\n logger.debug(\n `→ No valid tokens found - redirecting to login \"${redirectUrl}\"`,\n );\n return NextResponse.redirect(redirectUrl);\n }\n logger.debug(\"→ Auth check passed\");\n return undefined;\n};\n\n/**\n *\n * Use this when auth is the only middleware you need.\n * Usage:\n *\n * export default authMiddleware({ loginUrl = '/login' }); // or just authMiddleware();\n *\n */\nexport const authMiddleware =\n (authConfig: OptionalAuthConfig = {}) =>\n async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n // NextJS doesn't do middleware chaining yet, so this does not mean\n // \"call the next middleware\" - it means \"continue to the route handler\"\n return NextResponse.next();\n };\n\n/**\n * Usage:\n *\n * export default withAuth(async (request) => {\n * logger.debug('my middleware');\n * return NextResponse.next();\n * })\n */\n// use this when you have your own middleware to chain\nexport function withAuth(\n middleware: Middleware,\n): (request: NextRequest) => Promise<NextResponse> {\n return auth()(middleware);\n}\n\n/**\n * Use this when you want to configure the middleware here (an alternative is to do it in the next.config file)\n *\n * Usage:\n *\n * export default auth(authConfig: AuthConfig ) => {\n * logger.debug('my middleware');\n * return NextResponse.next();\n * })\n *\n */\nexport function auth(authConfig: OptionalAuthConfig = {}) {\n return (\n middleware: Middleware,\n ): ((request: NextRequest) => Promise<NextResponse>) => {\n return async (request: NextRequest): Promise<NextResponse> => {\n const response = await applyAuth(authConfig, request);\n if (response) return response;\n\n return middleware(request);\n };\n };\n}\n"]}
|
|
@@ -42,7 +42,7 @@ const CivicAuthIframe = forwardRef(({ onLoad, id }, ref) => {
|
|
|
42
42
|
}, onLoad: () => {
|
|
43
43
|
setIsLoaded(true);
|
|
44
44
|
onLoad?.();
|
|
45
|
-
}, allow: "camera; screen-wake-lock", allowFullScreen: true }) })] }));
|
|
45
|
+
}, allow: "camera; screen-wake-lock; publickey-credentials-get; publickey-credentials-create", allowFullScreen: true }) })] }));
|
|
46
46
|
});
|
|
47
47
|
CivicAuthIframe.displayName = "CivicAuthIframe";
|
|
48
48
|
export { CivicAuthIframe };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CivicAuthIframe.js","sourceRoot":"","sources":["../../../src/shared/components/CivicAuthIframe.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,UAAU,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO1C,MAAM,eAAe,GAAG,UAAU,CAChC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE;IACtB,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,SAAS,EAAE,CAAC;IACpD,MAAM,SAAS,GAAG,GAAG,CAAC;IACtB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,8GAA8G;IAC9G,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACxB,eACE,KAAK,EAAE;YACL,QAAQ,EAAE,UAAU;YACpB,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACnC,QAAQ,EAAE,QAAQ;YAClB,UAAU,EAAE,gBAAgB;YAC5B,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa;YAC3D,SAAS,EAAE,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;SACvD,aAEA,CAAC,QAAQ,CAAC,CAAC,CAAC,CACX,6BACc,uBAAuB,EACnC,KAAK,EAAE;oBACL,KAAK,EAAE,MAAM;oBACb,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,MAAM;oBACf,UAAU,EAAE,QAAQ;oBACpB,cAAc,EAAE,QAAQ;oBACxB,QAAQ,EAAE,UAAU;oBACpB,GAAG,EAAE,KAAK;oBACV,IAAI,EAAE,KAAK;oBACX,SAAS,EAAE,uBAAuB;oBAClC,YAAY,EAAE,MAAM;oBACpB,QAAQ,EAAE,QAAQ;iBACnB,YAEA,UAAU,KAAK,UAAU,IAAI,CAC5B,KAAC,UAAU,IAAC,eAAe,EAAE,eAAe,GAAI,CACjD,GACG,CACP,CAAC,CAAC,CAAC,IAAI,EACR,cACE,KAAK,EAAE;oBACL,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBACzB,UAAU,EAAE,oBAAoB;iBACjC,YAED,KAAC,aAAa,IACZ,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,EAAE,iBACO,gCAAgC,EAC7C,aAAa,EAAE,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,EACjE,OAAO,EAAE,IAAI,EACb,iBAAiB,EAAE,GAAG,EACtB,WAAW,EAAE,KAAK,EAClB,KAAK,EAAE;wBACL,KAAK,EAAE,MAAM;wBACb,MAAM,EAAE,MAAM;wBACd,QAAQ,EAAE,MAAM;wBAChB,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa;wBAC3D,aAAa,EAAE,MAAM;qBACtB,EACD,MAAM,EAAE,GAAG,EAAE;wBACX,WAAW,CAAC,IAAI,CAAC,CAAC;wBAClB,MAAM,EAAE,EAAE,CAAC;oBACb,CAAC,EACD,KAAK,EAAC,
|
|
1
|
+
{"version":3,"file":"CivicAuthIframe.js","sourceRoot":"","sources":["../../../src/shared/components/CivicAuthIframe.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,UAAU,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO1C,MAAM,eAAe,GAAG,UAAU,CAChC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE;IACtB,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,SAAS,EAAE,CAAC;IACpD,MAAM,SAAS,GAAG,GAAG,CAAC;IACtB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,8GAA8G;IAC9G,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACxB,eACE,KAAK,EAAE;YACL,QAAQ,EAAE,UAAU;YACpB,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACnC,QAAQ,EAAE,QAAQ;YAClB,UAAU,EAAE,gBAAgB;YAC5B,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa;YAC3D,SAAS,EAAE,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;SACvD,aAEA,CAAC,QAAQ,CAAC,CAAC,CAAC,CACX,6BACc,uBAAuB,EACnC,KAAK,EAAE;oBACL,KAAK,EAAE,MAAM;oBACb,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,MAAM;oBACf,UAAU,EAAE,QAAQ;oBACpB,cAAc,EAAE,QAAQ;oBACxB,QAAQ,EAAE,UAAU;oBACpB,GAAG,EAAE,KAAK;oBACV,IAAI,EAAE,KAAK;oBACX,SAAS,EAAE,uBAAuB;oBAClC,YAAY,EAAE,MAAM;oBACpB,QAAQ,EAAE,QAAQ;iBACnB,YAEA,UAAU,KAAK,UAAU,IAAI,CAC5B,KAAC,UAAU,IAAC,eAAe,EAAE,eAAe,GAAI,CACjD,GACG,CACP,CAAC,CAAC,CAAC,IAAI,EACR,cACE,KAAK,EAAE;oBACL,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBACzB,UAAU,EAAE,oBAAoB;iBACjC,YAED,KAAC,aAAa,IACZ,GAAG,EAAE,SAAS,EACd,EAAE,EAAE,EAAE,iBACO,gCAAgC,EAC7C,aAAa,EAAE,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,EACjE,OAAO,EAAE,IAAI,EACb,iBAAiB,EAAE,GAAG,EACtB,WAAW,EAAE,KAAK,EAClB,KAAK,EAAE;wBACL,KAAK,EAAE,MAAM;wBACb,MAAM,EAAE,MAAM;wBACd,QAAQ,EAAE,MAAM;wBAChB,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa;wBAC3D,aAAa,EAAE,MAAM;qBACtB,EACD,MAAM,EAAE,GAAG,EAAE;wBACX,WAAW,CAAC,IAAI,CAAC,CAAC;wBAClB,MAAM,EAAE,EAAE,CAAC;oBACb,CAAC,EACD,KAAK,EAAC,mFAAmF,EACzF,eAAe,SACf,GACE,IACF,CACP,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,eAAe,CAAC,WAAW,GAAG,iBAAiB,CAAC;AAIhD,OAAO,EAAE,eAAe,EAAE,CAAC","sourcesContent":["\"use client\";\nimport React, { forwardRef } from \"react\";\nimport { IframeResizer } from \"@civic/iframe-resizer\";\nimport SVGLoading from \"./SVGLoading.js\";\nimport { useIframe } from \"../hooks/useIframe.js\";\nimport { useIsClient } from \"usehooks-ts\";\n\ntype CivicAuthIframeProps = {\n onLoad?: () => void;\n id: string;\n};\n\nconst CivicAuthIframe = forwardRef<HTMLIFrameElement, CivicAuthIframeProps>(\n ({ onLoad, id }, ref) => {\n const [isLoaded, setIsLoaded] = React.useState(false);\n const { iframeMode, backgroundColor } = useIframe();\n const iframeRef = ref;\n const isClient = useIsClient();\n\n // don't render on the server as the appearance changes when the iframe is loaded from login-app post-messages\n return !isClient ? null : (\n <div\n style={{\n position: \"relative\",\n borderRadius: isLoaded ? \"26px\" : 0,\n overflow: \"hidden\",\n transition: \"all 250ms ease\",\n backgroundColor: isLoaded ? backgroundColor : \"transparent\",\n minHeight: iframeMode !== \"embedded\" ? \"26px\" : \"auto\",\n }}\n >\n {!isLoaded ? (\n <div\n data-testid=\"iframe-shimmer-loader\"\n style={{\n width: \"100%\",\n height: \"26px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n borderRadius: \"13px\",\n overflow: \"hidden\",\n }}\n >\n {iframeMode !== \"embedded\" && (\n <SVGLoading backgroundColor={backgroundColor} />\n )}\n </div>\n ) : null}\n <div\n style={{\n opacity: isLoaded ? 1 : 0,\n transition: \"opacity 250ms ease\",\n }}\n >\n <IframeResizer\n ref={iframeRef}\n id={id}\n data-testid={\"civic-auth-iframe-with-resizer\"}\n initialHeight={iframeMode !== \"embedded\" ? \"26px\" : \"max-content\"}\n animate={true}\n animationDuration={250}\n checkOrigin={false}\n style={{\n width: \"100%\",\n border: \"none\",\n minWidth: \"100%\",\n backgroundColor: isLoaded ? backgroundColor : \"transparent\",\n pointerEvents: \"auto\",\n }}\n onLoad={() => {\n setIsLoaded(true);\n onLoad?.();\n }}\n allow=\"camera; screen-wake-lock; publickey-credentials-get; publickey-credentials-create\"\n allowFullScreen\n />\n </div>\n </div>\n );\n },\n);\n\nCivicAuthIframe.displayName = \"CivicAuthIframe\";\n\nexport type { CivicAuthIframeProps };\n\nexport { CivicAuthIframe };\n"]}
|
package/dist/shared/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "@civic/auth:0.8.
|
|
1
|
+
export declare const VERSION = "@civic/auth:0.8.1";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/shared/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/shared/version.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,MAAM,CAAC,MAAM,OAAO,GAAG,mBAAmB,CAAC","sourcesContent":["// This is an auto-generated file. Do not edit.\n\nexport const VERSION = \"@civic/auth:0.8.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/shared/version.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,MAAM,CAAC,MAAM,OAAO,GAAG,mBAAmB,CAAC","sourcesContent":["// This is an auto-generated file. Do not edit.\n\nexport const VERSION = \"@civic/auth:0.8.1\";\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IframeAuthHandler.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/IframeAuthHandler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAGtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAG1D,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACxC,aAAa,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACpC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CAC/C;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,aAAa,CAAC,CAAoB;IAC1C,OAAO,CAAC,cAAc,CAAC,CAAiB;gBAE5B,aAAa,EAAE,uBAAuB;IAQrC,gBAAgB,CAC3B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC;IA2EtB,gBAAgB,IAAI,aAAa,GAAG,SAAS;IAI7C,gBAAgB,IAAI,iBAAiB,GAAG,SAAS;IAIjD,aAAa,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"IframeAuthHandler.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/IframeAuthHandler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAGtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAG1D,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACxC,aAAa,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACpC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CAC/C;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,aAAa,CAAC,CAAoB;IAC1C,OAAO,CAAC,cAAc,CAAC,CAAiB;gBAE5B,aAAa,EAAE,uBAAuB;IAQrC,gBAAgB,CAC3B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC;IA2EtB,gBAAgB,IAAI,aAAa,GAAG,SAAS;IAI7C,gBAAgB,IAAI,iBAAiB,GAAG,SAAS;IAIjD,aAAa,IAAI,IAAI;IAa5B,OAAO,CAAC,4BAA4B;IAgBpC,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,mBAAmB;IAmB3B,OAAO,CAAC,0BAA0B;IA4BlC,OAAO,CAAC,wBAAwB;IAyDhC,OAAO,CAAC,2BAA2B;IA4DnC,OAAO,CAAC,mBAAmB;IAsD3B,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,+BAA+B;IA6EvC,OAAO,CAAC,kBAAkB;IAgCnB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CA8BzC"}
|
|
@@ -78,11 +78,9 @@ export class IframeAuthHandler {
|
|
|
78
78
|
return this.iframeElement;
|
|
79
79
|
}
|
|
80
80
|
cleanupIframe() {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
this.iframeManager = undefined;
|
|
85
|
-
}
|
|
81
|
+
this.logger.debug("Cleaning up iframe manager");
|
|
82
|
+
this.iframeManager?.cleanup();
|
|
83
|
+
this.iframeManager = undefined;
|
|
86
84
|
if (this.iframeElement) {
|
|
87
85
|
this.iframeElement = undefined;
|
|
88
86
|
}
|
|
@@ -212,12 +210,10 @@ export class IframeAuthHandler {
|
|
|
212
210
|
currentOrigin,
|
|
213
211
|
expectedAuthServerOrigin,
|
|
214
212
|
});
|
|
215
|
-
|
|
216
|
-
this.iframeManager.forceHideLoader();
|
|
217
|
-
}
|
|
213
|
+
this.iframeManager?.forceHideLoader();
|
|
218
214
|
}
|
|
219
215
|
else {
|
|
220
|
-
this.logger.info("🙈
|
|
216
|
+
this.logger.info("🙈 Hiding iframe completely - not login app or on callback URL", {
|
|
221
217
|
currentUrl,
|
|
222
218
|
isOnAuthServer,
|
|
223
219
|
isCallbackUrl,
|
|
@@ -229,17 +225,18 @@ export class IframeAuthHandler {
|
|
|
229
225
|
: "auth server origin unknown"
|
|
230
226
|
: "on callback URL (or origin mismatch for login page)",
|
|
231
227
|
});
|
|
232
|
-
if (
|
|
233
|
-
this.iframeManager
|
|
228
|
+
if (isCallbackUrl) {
|
|
229
|
+
this.iframeManager?.hide();
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
this.iframeManager?.forceShowLoader();
|
|
234
233
|
}
|
|
235
234
|
}
|
|
236
235
|
}
|
|
237
236
|
}
|
|
238
237
|
catch (error) {
|
|
239
238
|
this.logger.debug("Cannot access iframe URL (likely cross-origin) - assuming login app, showing content.", { error: error instanceof Error ? error.message : String(error) });
|
|
240
|
-
|
|
241
|
-
this.iframeManager.forceHideLoader();
|
|
242
|
-
}
|
|
239
|
+
this.iframeManager?.forceHideLoader();
|
|
243
240
|
}
|
|
244
241
|
}
|
|
245
242
|
checkIframeRedirect() {
|
|
@@ -306,10 +303,10 @@ export class IframeAuthHandler {
|
|
|
306
303
|
redirectUrl: this.config.redirectUrl,
|
|
307
304
|
isCallbackUrl: currentUrl.startsWith(this.config.redirectUrl),
|
|
308
305
|
});
|
|
309
|
-
// Hide content if not on login app
|
|
310
|
-
this.checkAndHideNonLoginContent();
|
|
311
306
|
// Check if iframe has navigated to our callback URL
|
|
312
307
|
if (currentUrl.startsWith(this.config.redirectUrl)) {
|
|
308
|
+
// Hide immediately on callback URL detection
|
|
309
|
+
this.iframeManager?.hide();
|
|
313
310
|
this.logger.info("Iframe navigated to callback URL - setting up signal observer");
|
|
314
311
|
if (monitoringInterval) {
|
|
315
312
|
clearInterval(monitoringInterval);
|
|
@@ -322,6 +319,10 @@ export class IframeAuthHandler {
|
|
|
322
319
|
// Also check for URL parameters (code, error) in case of direct callback
|
|
323
320
|
this.processCallbackUrl(currentUrl);
|
|
324
321
|
}
|
|
322
|
+
else {
|
|
323
|
+
// Hide content if not on login app
|
|
324
|
+
this.checkAndHideNonLoginContent();
|
|
325
|
+
}
|
|
325
326
|
}
|
|
326
327
|
}
|
|
327
328
|
catch {
|
|
@@ -333,9 +334,9 @@ export class IframeAuthHandler {
|
|
|
333
334
|
}
|
|
334
335
|
}
|
|
335
336
|
};
|
|
336
|
-
// Check immediately and then every
|
|
337
|
+
// Check immediately and then every 100ms for faster detection
|
|
337
338
|
checkIframeNavigation();
|
|
338
|
-
monitoringInterval = window.setInterval(checkIframeNavigation,
|
|
339
|
+
monitoringInterval = window.setInterval(checkIframeNavigation, 100);
|
|
339
340
|
// Store cleanup function to clear monitoring
|
|
340
341
|
const originalCleanup = this.cleanup;
|
|
341
342
|
this.cleanup = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IframeAuthHandler.js","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/IframeAuthHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { AuthEvent } from \"../../types/index.js\";\nimport type { AuthResult } from \"../../types/index.js\";\nimport type { ProcessedCivicAuthConfig } from \"../types/AuthTypes.js\";\nimport { CivicAuthError, CivicAuthErrorCode } from \"../types/AuthTypes.js\";\nimport { SignalObserver } from \"../../iframe/SignalObserver.js\";\nimport { IframeManager } from \"../../iframe/IframeManager.js\";\nimport type { createLogger } from \"../../utils/logger.js\";\nimport { createLogger as createLoggerFn } from \"../../utils/logger.js\";\n\nexport interface IframeAuthHandlerConfig {\n config: ProcessedCivicAuthConfig;\n logger: ReturnType<typeof createLogger>;\n onAuthSuccess: (result: AuthResult) => void;\n onAuthError: (error: Error) => void;\n cleanup: () => void;\n messageHandler: (event: MessageEvent) => void;\n}\n\nexport class IframeAuthHandler {\n private config: ProcessedCivicAuthConfig;\n private logger = createLoggerFn(\"iframe-auth\");\n private onAuthSuccess: (result: AuthResult) => void;\n private onAuthError: (error: Error) => void;\n private cleanup: () => void;\n private messageHandler: (event: MessageEvent) => void;\n private iframeManager?: IframeManager;\n private iframeElement?: HTMLIFrameElement;\n private signalObserver?: SignalObserver;\n\n constructor(handlerConfig: IframeAuthHandlerConfig) {\n this.config = handlerConfig.config;\n this.onAuthSuccess = handlerConfig.onAuthSuccess;\n this.onAuthError = handlerConfig.onAuthError;\n this.cleanup = handlerConfig.cleanup;\n this.messageHandler = handlerConfig.messageHandler;\n }\n\n public async handleIframeAuth(\n fullAuthUrl: string,\n ): Promise<HTMLIFrameElement> {\n // Determine the actual display mode for IframeManager first\n const iframeDisplayMode = this.determineIframeDisplayMode();\n\n let container = this.getContainerElement();\n\n // For modal mode, if no container is provided, create one dynamically\n if (iframeDisplayMode === \"modal\" && !container) {\n container = this.createModalContainer();\n }\n\n if (!container) {\n const error = new CivicAuthError(\n \"Target container element not found.\",\n CivicAuthErrorCode.CONTAINER_NOT_FOUND,\n );\n this.logger.error(error.message);\n throw error;\n }\n\n this.logger.debug(\"Creating iframe with modal backdrop\", {\n url: fullAuthUrl,\n containerId: container?.id,\n iframeId: this.config.iframeId,\n origin: window.location.origin,\n iframeDisplayMode,\n containerCreated:\n iframeDisplayMode === \"modal\" && !this.config.targetContainerElement,\n });\n\n this.logger.debug(\n `🎯 CivicAuth: Creating IframeManager with display mode: ${iframeDisplayMode}`,\n );\n\n // Create IframeManager with appropriate display mode\n this.iframeManager = new IframeManager({\n container: container,\n displayMode: iframeDisplayMode,\n iframeId: this.config.iframeId,\n /**\n * Handles iframe closure events initiated by the user.\n * This includes backdrop clicks, close button clicks, or Escape key presses.\n * Emits an error event and cleans up the authentication process.\n */\n onClose: () => {\n this.logger.debug(\n \"Authentication close requested by user (backdrop click, close button, or Escape key)\",\n );\n this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: \"Authentication cancelled by user\",\n });\n\n const error = new CivicAuthError(\n \"Authentication cancelled by user\",\n CivicAuthErrorCode.USER_CANCELLED,\n );\n\n this.onAuthError(error);\n this.cleanup();\n },\n });\n\n // Create the iframe using IframeManager\n this.iframeElement = this.iframeManager.createIframe(fullAuthUrl);\n\n this.config.events?.emit(AuthEvent.SIGN_IN_STARTED, {\n detail: \"Iframe created with modal backdrop\",\n });\n\n this.setupIframeEventHandlers();\n this.setupIframeNavigationMonitoring();\n\n return this.iframeElement;\n }\n\n public getIframeManager(): IframeManager | undefined {\n return this.iframeManager;\n }\n\n public getIframeElement(): HTMLIFrameElement | undefined {\n return this.iframeElement;\n }\n\n public cleanupIframe(): void {\n if (this.iframeManager) {\n this.logger.debug(\"Cleaning up iframe manager\");\n this.iframeManager.cleanup();\n this.iframeManager = undefined;\n }\n\n if (this.iframeElement) {\n this.iframeElement = undefined;\n }\n\n // Clean up dynamically created modal containers\n this.cleanupDynamicModalContainer();\n }\n\n private cleanupDynamicModalContainer(): void {\n // Only clean up containers we created dynamically (not user-provided ones)\n if (!this.config.targetContainerElement) {\n const dynamicContainer = document.querySelector(\n `[data-civic-auth-modal=\"true\"]#${this.config.iframeId}-modal-container`,\n );\n\n if (dynamicContainer && dynamicContainer.parentNode) {\n this.logger.debug(\"Removing dynamic modal container\", {\n containerId: dynamicContainer.id,\n });\n dynamicContainer.parentNode.removeChild(dynamicContainer);\n }\n }\n }\n\n private createModalContainer(): HTMLElement {\n const container = document.createElement(\"div\");\n container.id = `${this.config.iframeId}-modal-container`;\n container.setAttribute(\"data-civic-auth-modal\", \"true\");\n\n // Append to body for modal overlay\n document.body.appendChild(container);\n\n this.logger.debug(\"Created dynamic modal container\", {\n containerId: container.id,\n });\n\n return container;\n }\n\n private getContainerElement(): HTMLElement | null {\n if (!this.config.targetContainerElement) {\n return null;\n }\n\n if (typeof this.config.targetContainerElement === \"string\") {\n const element = document.getElementById(\n this.config.targetContainerElement,\n );\n if (!element) {\n this.logger.warn(\n `Container element with ID \"${this.config.targetContainerElement}\" not found`,\n );\n }\n return element;\n }\n return this.config.targetContainerElement;\n }\n\n private determineIframeDisplayMode(): \"modal\" | \"embedded\" {\n // Priority 1: Explicit iframeDisplayMode setting from config\n // This is the most specific instruction for how the iframe itself should be styled.\n if (this.config.iframeDisplayMode) {\n this.logger.debug(\n `Using configured iframeDisplayMode: ${this.config.iframeDisplayMode}`,\n );\n return this.config.iframeDisplayMode;\n }\n\n // Priority 2: If iframeDisplayMode is NOT set, and the overall displayMode is \"iframe\",\n // default the iframe's own rendering style to \"modal\" (user-friendly default).\n // To get an embedded iframe, iframeDisplayMode: \"embedded\" should be set explicitly.\n if (this.config.displayMode === \"iframe\") {\n this.logger.debug(\n \"Overall displayMode is 'iframe' and iframeDisplayMode is not set, defaulting iframe style to 'modal'.\",\n );\n return \"modal\";\n }\n\n // Fallback for unexpected scenarios or if IframeAuthHandler is invoked with other displayModes.\n this.logger.warn(\n `determineIframeDisplayMode called with overall displayMode: '${this.config.displayMode}' ` +\n `and no explicit iframeDisplayMode. Defaulting iframe style to 'modal'.`,\n );\n return \"modal\";\n }\n\n private setupIframeEventHandlers(): void {\n if (!this.iframeElement) return;\n\n this.iframeElement.onload = () => {\n this.logger.info(\"Iframe loaded\", {\n iframeSrc: this.iframeElement?.src,\n currentOrigin: window.location.origin,\n expectedAuthServerOrigin: new URL(this.config.oauthServerBaseUrl)\n .origin,\n });\n\n if (!this.iframeElement?.contentWindow) {\n const errorMsg = \"Iframe content window not available after load.\";\n this.logger.error(errorMsg, {\n iframeSrc: this.iframeElement?.src,\n });\n\n const error = new Error(errorMsg);\n this.onAuthError(error);\n this.cleanup();\n return;\n }\n\n // Set up postMessage listener for cross-origin communication\n window.addEventListener(\"message\", this.messageHandler);\n this.logger.info(\n \"Added cross-origin message event listener for auth server communication\",\n {\n parentOrigin: window.location.origin,\n authServerOrigin: new URL(this.config.oauthServerBaseUrl).origin,\n },\n );\n\n // Hide iframe content if it's not the login app\n this.checkAndHideNonLoginContent();\n\n // Try to detect redirect to our domain\n this.checkIframeRedirect();\n };\n\n this.iframeElement.onerror = (event) => {\n this.logger.error(\"Iframe load error\", {\n event,\n iframeSrc: this.iframeElement?.src,\n currentOrigin: window.location.origin,\n });\n this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: \"Iframe load error\",\n error: event,\n });\n\n const error = new Error(\"Iframe failed to load.\");\n this.onAuthError(error);\n this.cleanup();\n };\n }\n\n private checkAndHideNonLoginContent(): void {\n try {\n const currentUrl = this.iframeElement?.contentWindow?.location.href;\n if (currentUrl) {\n const currentOrigin = new URL(currentUrl).origin;\n const expectedAuthServerOrigin = this.config.oauthServerBaseUrl\n ? new URL(this.config.oauthServerBaseUrl).origin\n : null;\n const isOnAuthServer = expectedAuthServerOrigin\n ? currentOrigin === expectedAuthServerOrigin\n : false;\n const isCallbackUrl = this.config.redirectUrl\n ? currentUrl.startsWith(this.config.redirectUrl)\n : false;\n\n if (isOnAuthServer && !isCallbackUrl) {\n this.logger.info(\n \"👀 Showing iframe content - confirmed login app on auth server origin\",\n {\n currentUrl,\n isOnAuthServer,\n isCallbackUrl,\n currentOrigin,\n expectedAuthServerOrigin,\n },\n );\n if (this.iframeManager) {\n this.iframeManager.forceHideLoader();\n }\n } else {\n this.logger.info(\n \"🙈 Masking iframe content with loader - not login app or on callback URL\",\n {\n currentUrl,\n isOnAuthServer,\n isCallbackUrl,\n currentOrigin,\n expectedAuthServerOrigin,\n reason: !isOnAuthServer\n ? expectedAuthServerOrigin\n ? \"not on auth server (origin mismatch)\"\n : \"auth server origin unknown\"\n : \"on callback URL (or origin mismatch for login page)\",\n },\n );\n if (this.iframeManager) {\n this.iframeManager.forceShowLoader();\n }\n }\n }\n } catch (error) {\n this.logger.debug(\n \"Cannot access iframe URL (likely cross-origin) - assuming login app, showing content.\",\n { error: error instanceof Error ? error.message : String(error) },\n );\n if (this.iframeManager) {\n this.iframeManager.forceHideLoader();\n }\n }\n }\n\n private checkIframeRedirect(): void {\n try {\n const currentIframeHref =\n this.iframeElement?.contentWindow?.location.href;\n\n if (currentIframeHref) {\n this.logger.debug(\"Iframe current href accessible\", {\n href: currentIframeHref,\n redirectUrl: this.config.redirectUrl,\n startsWithRedirect: currentIframeHref.startsWith(\n this.config.redirectUrl,\n ),\n });\n\n if (currentIframeHref.startsWith(this.config.redirectUrl)) {\n this.logger.info(\n \"Iframe has navigated to redirectUrl (same-origin). Setting up DOM observer.\",\n );\n\n // Hide content since we're on callback page now\n this.checkAndHideNonLoginContent();\n\n // Set up signal observer for same-origin callback page\n if (\n this.iframeElement?.contentDocument &&\n this.iframeElement.contentDocument.body\n ) {\n this.setupSignalObserver(this.iframeElement.contentDocument);\n } else {\n this.logger.warn(\n \"Iframe content document or body not available for signal observer\",\n );\n }\n }\n }\n } catch (error) {\n this.logger.debug(\n \"Error checking iframe href (expected for cross-origin)\",\n {\n error: error instanceof Error ? error.message : String(error),\n iframeSrc: this.iframeElement?.src,\n },\n );\n // This is expected when the iframe is on the auth server domain\n this.logger.info(\n \"Iframe is on auth server domain - using postMessage for communication\",\n {\n parentOrigin: window.location.origin,\n authServerOrigin: new URL(this.config.oauthServerBaseUrl).origin,\n },\n );\n }\n }\n\n private setupSignalObserver(iframeDoc: Document): void {\n const signalObserver = new SignalObserver(\n {\n textSignals: this.config.textSignals,\n events: this.config.events,\n logger: this.logger,\n },\n this.onAuthSuccess,\n (error?: Error) =>\n this.onAuthError(error || new Error(\"Signal observer error\")),\n () => this.cleanup(),\n );\n\n signalObserver.setup(iframeDoc);\n }\n\n private setupIframeNavigationMonitoring(): void {\n // Monitor iframe navigation to detect when it redirects to our callback URL\n let monitoringInterval: number | undefined = undefined;\n let lastKnownUrl = \"\";\n\n const checkIframeNavigation = () => {\n if (!this.iframeElement?.contentWindow) {\n if (monitoringInterval) {\n clearInterval(monitoringInterval);\n }\n return;\n }\n\n try {\n const currentUrl = this.iframeElement.contentWindow.location.href;\n\n if (currentUrl !== lastKnownUrl) {\n lastKnownUrl = currentUrl;\n this.logger.debug(\"Iframe navigation detected\", {\n newUrl: currentUrl,\n redirectUrl: this.config.redirectUrl,\n isCallbackUrl: currentUrl.startsWith(this.config.redirectUrl),\n });\n\n // Hide content if not on login app\n this.checkAndHideNonLoginContent();\n\n // Check if iframe has navigated to our callback URL\n if (currentUrl.startsWith(this.config.redirectUrl)) {\n this.logger.info(\n \"Iframe navigated to callback URL - setting up signal observer\",\n );\n\n if (monitoringInterval) {\n clearInterval(monitoringInterval);\n }\n\n // Set up signal observer for same-origin callback page\n if (\n this.iframeElement.contentDocument &&\n this.iframeElement.contentDocument.body\n ) {\n this.setupSignalObserver(this.iframeElement.contentDocument);\n }\n\n // Also check for URL parameters (code, error) in case of direct callback\n this.processCallbackUrl(currentUrl);\n }\n }\n } catch {\n // Expected when iframe is on different origin\n // Only log if we haven't seen this before\n if (lastKnownUrl !== \"cross-origin\") {\n lastKnownUrl = \"cross-origin\";\n this.logger.debug(\n \"Iframe on cross-origin domain (expected during auth flow)\",\n );\n }\n }\n };\n\n // Check immediately and then every 500ms\n checkIframeNavigation();\n monitoringInterval = window.setInterval(checkIframeNavigation, 500);\n\n // Store cleanup function to clear monitoring\n const originalCleanup = this.cleanup;\n this.cleanup = () => {\n if (monitoringInterval) {\n clearInterval(monitoringInterval);\n }\n originalCleanup();\n };\n }\n\n private processCallbackUrl(currentUrl: string): void {\n const urlParams = new URLSearchParams(new URL(currentUrl).search);\n const code = urlParams.get(\"code\");\n const error = urlParams.get(\"error\");\n\n if (code) {\n this.logger.info(\"Authorization code detected in iframe URL\", {\n code: code.substring(0, 10) + \"...\",\n hasState: !!urlParams.get(\"state\"),\n });\n }\n\n if (error) {\n this.logger.error(\"OAuth error detected in iframe URL\", {\n error,\n errorDescription: urlParams.get(\"error_description\"),\n });\n\n const authError = new CivicAuthError(\n `OAuth error: ${error}`,\n CivicAuthErrorCode.INVALID_MESSAGE,\n );\n\n this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: authError.message,\n error: urlParams.get(\"error_description\") || error,\n });\n\n this.onAuthError(authError);\n }\n }\n\n public navigateIframe(url: string): void {\n if (!this.iframeElement) {\n this.logger.error(\n \"Cannot navigate iframe, iframeElement is not available.\",\n );\n this.onAuthError(\n new CivicAuthError(\n \"Iframe element not found for navigation.\",\n CivicAuthErrorCode.IFRAME_NOT_FOUND,\n ),\n );\n return;\n }\n if (!this.iframeManager) {\n this.logger.error(\n \"Cannot navigate iframe, iframeManager is not available.\",\n );\n this.onAuthError(\n new CivicAuthError(\n \"Iframe manager not found for navigation.\",\n CivicAuthErrorCode.INTERNAL_ERROR,\n ),\n );\n return;\n }\n this.logger.info(\"Navigating iframe to new URL\", { url });\n this.iframeElement.src = url;\n // After changing src, existing onload/onmessage handlers in IframeManager\n // and navigation monitoring in this class should manage visibility and state.\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"IframeAuthHandler.js","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/IframeAuthHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { AuthEvent } from \"../../types/index.js\";\nimport type { AuthResult } from \"../../types/index.js\";\nimport type { ProcessedCivicAuthConfig } from \"../types/AuthTypes.js\";\nimport { CivicAuthError, CivicAuthErrorCode } from \"../types/AuthTypes.js\";\nimport { SignalObserver } from \"../../iframe/SignalObserver.js\";\nimport { IframeManager } from \"../../iframe/IframeManager.js\";\nimport type { createLogger } from \"../../utils/logger.js\";\nimport { createLogger as createLoggerFn } from \"../../utils/logger.js\";\n\nexport interface IframeAuthHandlerConfig {\n config: ProcessedCivicAuthConfig;\n logger: ReturnType<typeof createLogger>;\n onAuthSuccess: (result: AuthResult) => void;\n onAuthError: (error: Error) => void;\n cleanup: () => void;\n messageHandler: (event: MessageEvent) => void;\n}\n\nexport class IframeAuthHandler {\n private config: ProcessedCivicAuthConfig;\n private logger = createLoggerFn(\"iframe-auth\");\n private onAuthSuccess: (result: AuthResult) => void;\n private onAuthError: (error: Error) => void;\n private cleanup: () => void;\n private messageHandler: (event: MessageEvent) => void;\n private iframeManager?: IframeManager;\n private iframeElement?: HTMLIFrameElement;\n private signalObserver?: SignalObserver;\n\n constructor(handlerConfig: IframeAuthHandlerConfig) {\n this.config = handlerConfig.config;\n this.onAuthSuccess = handlerConfig.onAuthSuccess;\n this.onAuthError = handlerConfig.onAuthError;\n this.cleanup = handlerConfig.cleanup;\n this.messageHandler = handlerConfig.messageHandler;\n }\n\n public async handleIframeAuth(\n fullAuthUrl: string,\n ): Promise<HTMLIFrameElement> {\n // Determine the actual display mode for IframeManager first\n const iframeDisplayMode = this.determineIframeDisplayMode();\n\n let container = this.getContainerElement();\n\n // For modal mode, if no container is provided, create one dynamically\n if (iframeDisplayMode === \"modal\" && !container) {\n container = this.createModalContainer();\n }\n\n if (!container) {\n const error = new CivicAuthError(\n \"Target container element not found.\",\n CivicAuthErrorCode.CONTAINER_NOT_FOUND,\n );\n this.logger.error(error.message);\n throw error;\n }\n\n this.logger.debug(\"Creating iframe with modal backdrop\", {\n url: fullAuthUrl,\n containerId: container?.id,\n iframeId: this.config.iframeId,\n origin: window.location.origin,\n iframeDisplayMode,\n containerCreated:\n iframeDisplayMode === \"modal\" && !this.config.targetContainerElement,\n });\n\n this.logger.debug(\n `🎯 CivicAuth: Creating IframeManager with display mode: ${iframeDisplayMode}`,\n );\n\n // Create IframeManager with appropriate display mode\n this.iframeManager = new IframeManager({\n container: container,\n displayMode: iframeDisplayMode,\n iframeId: this.config.iframeId,\n /**\n * Handles iframe closure events initiated by the user.\n * This includes backdrop clicks, close button clicks, or Escape key presses.\n * Emits an error event and cleans up the authentication process.\n */\n onClose: () => {\n this.logger.debug(\n \"Authentication close requested by user (backdrop click, close button, or Escape key)\",\n );\n this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: \"Authentication cancelled by user\",\n });\n\n const error = new CivicAuthError(\n \"Authentication cancelled by user\",\n CivicAuthErrorCode.USER_CANCELLED,\n );\n\n this.onAuthError(error);\n this.cleanup();\n },\n });\n\n // Create the iframe using IframeManager\n this.iframeElement = this.iframeManager.createIframe(fullAuthUrl);\n\n this.config.events?.emit(AuthEvent.SIGN_IN_STARTED, {\n detail: \"Iframe created with modal backdrop\",\n });\n\n this.setupIframeEventHandlers();\n this.setupIframeNavigationMonitoring();\n\n return this.iframeElement;\n }\n\n public getIframeManager(): IframeManager | undefined {\n return this.iframeManager;\n }\n\n public getIframeElement(): HTMLIFrameElement | undefined {\n return this.iframeElement;\n }\n\n public cleanupIframe(): void {\n this.logger.debug(\"Cleaning up iframe manager\");\n this.iframeManager?.cleanup();\n this.iframeManager = undefined;\n\n if (this.iframeElement) {\n this.iframeElement = undefined;\n }\n\n // Clean up dynamically created modal containers\n this.cleanupDynamicModalContainer();\n }\n\n private cleanupDynamicModalContainer(): void {\n // Only clean up containers we created dynamically (not user-provided ones)\n if (!this.config.targetContainerElement) {\n const dynamicContainer = document.querySelector(\n `[data-civic-auth-modal=\"true\"]#${this.config.iframeId}-modal-container`,\n );\n\n if (dynamicContainer && dynamicContainer.parentNode) {\n this.logger.debug(\"Removing dynamic modal container\", {\n containerId: dynamicContainer.id,\n });\n dynamicContainer.parentNode.removeChild(dynamicContainer);\n }\n }\n }\n\n private createModalContainer(): HTMLElement {\n const container = document.createElement(\"div\");\n container.id = `${this.config.iframeId}-modal-container`;\n container.setAttribute(\"data-civic-auth-modal\", \"true\");\n\n // Append to body for modal overlay\n document.body.appendChild(container);\n\n this.logger.debug(\"Created dynamic modal container\", {\n containerId: container.id,\n });\n\n return container;\n }\n\n private getContainerElement(): HTMLElement | null {\n if (!this.config.targetContainerElement) {\n return null;\n }\n\n if (typeof this.config.targetContainerElement === \"string\") {\n const element = document.getElementById(\n this.config.targetContainerElement,\n );\n if (!element) {\n this.logger.warn(\n `Container element with ID \"${this.config.targetContainerElement}\" not found`,\n );\n }\n return element;\n }\n return this.config.targetContainerElement;\n }\n\n private determineIframeDisplayMode(): \"modal\" | \"embedded\" {\n // Priority 1: Explicit iframeDisplayMode setting from config\n // This is the most specific instruction for how the iframe itself should be styled.\n if (this.config.iframeDisplayMode) {\n this.logger.debug(\n `Using configured iframeDisplayMode: ${this.config.iframeDisplayMode}`,\n );\n return this.config.iframeDisplayMode;\n }\n\n // Priority 2: If iframeDisplayMode is NOT set, and the overall displayMode is \"iframe\",\n // default the iframe's own rendering style to \"modal\" (user-friendly default).\n // To get an embedded iframe, iframeDisplayMode: \"embedded\" should be set explicitly.\n if (this.config.displayMode === \"iframe\") {\n this.logger.debug(\n \"Overall displayMode is 'iframe' and iframeDisplayMode is not set, defaulting iframe style to 'modal'.\",\n );\n return \"modal\";\n }\n\n // Fallback for unexpected scenarios or if IframeAuthHandler is invoked with other displayModes.\n this.logger.warn(\n `determineIframeDisplayMode called with overall displayMode: '${this.config.displayMode}' ` +\n `and no explicit iframeDisplayMode. Defaulting iframe style to 'modal'.`,\n );\n return \"modal\";\n }\n\n private setupIframeEventHandlers(): void {\n if (!this.iframeElement) return;\n\n this.iframeElement.onload = () => {\n this.logger.info(\"Iframe loaded\", {\n iframeSrc: this.iframeElement?.src,\n currentOrigin: window.location.origin,\n expectedAuthServerOrigin: new URL(this.config.oauthServerBaseUrl)\n .origin,\n });\n\n if (!this.iframeElement?.contentWindow) {\n const errorMsg = \"Iframe content window not available after load.\";\n this.logger.error(errorMsg, {\n iframeSrc: this.iframeElement?.src,\n });\n\n const error = new Error(errorMsg);\n this.onAuthError(error);\n this.cleanup();\n return;\n }\n\n // Set up postMessage listener for cross-origin communication\n window.addEventListener(\"message\", this.messageHandler);\n this.logger.info(\n \"Added cross-origin message event listener for auth server communication\",\n {\n parentOrigin: window.location.origin,\n authServerOrigin: new URL(this.config.oauthServerBaseUrl).origin,\n },\n );\n\n // Hide iframe content if it's not the login app\n this.checkAndHideNonLoginContent();\n\n // Try to detect redirect to our domain\n this.checkIframeRedirect();\n };\n\n this.iframeElement.onerror = (event) => {\n this.logger.error(\"Iframe load error\", {\n event,\n iframeSrc: this.iframeElement?.src,\n currentOrigin: window.location.origin,\n });\n this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: \"Iframe load error\",\n error: event,\n });\n\n const error = new Error(\"Iframe failed to load.\");\n this.onAuthError(error);\n this.cleanup();\n };\n }\n\n private checkAndHideNonLoginContent(): void {\n try {\n const currentUrl = this.iframeElement?.contentWindow?.location.href;\n if (currentUrl) {\n const currentOrigin = new URL(currentUrl).origin;\n const expectedAuthServerOrigin = this.config.oauthServerBaseUrl\n ? new URL(this.config.oauthServerBaseUrl).origin\n : null;\n const isOnAuthServer = expectedAuthServerOrigin\n ? currentOrigin === expectedAuthServerOrigin\n : false;\n const isCallbackUrl = this.config.redirectUrl\n ? currentUrl.startsWith(this.config.redirectUrl)\n : false;\n\n if (isOnAuthServer && !isCallbackUrl) {\n this.logger.info(\n \"👀 Showing iframe content - confirmed login app on auth server origin\",\n {\n currentUrl,\n isOnAuthServer,\n isCallbackUrl,\n currentOrigin,\n expectedAuthServerOrigin,\n },\n );\n this.iframeManager?.forceHideLoader();\n } else {\n this.logger.info(\n \"🙈 Hiding iframe completely - not login app or on callback URL\",\n {\n currentUrl,\n isOnAuthServer,\n isCallbackUrl,\n currentOrigin,\n expectedAuthServerOrigin,\n reason: !isOnAuthServer\n ? expectedAuthServerOrigin\n ? \"not on auth server (origin mismatch)\"\n : \"auth server origin unknown\"\n : \"on callback URL (or origin mismatch for login page)\",\n },\n );\n\n if (isCallbackUrl) {\n this.iframeManager?.hide();\n } else {\n this.iframeManager?.forceShowLoader();\n }\n }\n }\n } catch (error) {\n this.logger.debug(\n \"Cannot access iframe URL (likely cross-origin) - assuming login app, showing content.\",\n { error: error instanceof Error ? error.message : String(error) },\n );\n this.iframeManager?.forceHideLoader();\n }\n }\n\n private checkIframeRedirect(): void {\n try {\n const currentIframeHref =\n this.iframeElement?.contentWindow?.location.href;\n\n if (currentIframeHref) {\n this.logger.debug(\"Iframe current href accessible\", {\n href: currentIframeHref,\n redirectUrl: this.config.redirectUrl,\n startsWithRedirect: currentIframeHref.startsWith(\n this.config.redirectUrl,\n ),\n });\n\n if (currentIframeHref.startsWith(this.config.redirectUrl)) {\n this.logger.info(\n \"Iframe has navigated to redirectUrl (same-origin). Setting up DOM observer.\",\n );\n\n // Hide content since we're on callback page now\n this.checkAndHideNonLoginContent();\n\n // Set up signal observer for same-origin callback page\n if (\n this.iframeElement?.contentDocument &&\n this.iframeElement.contentDocument.body\n ) {\n this.setupSignalObserver(this.iframeElement.contentDocument);\n } else {\n this.logger.warn(\n \"Iframe content document or body not available for signal observer\",\n );\n }\n }\n }\n } catch (error) {\n this.logger.debug(\n \"Error checking iframe href (expected for cross-origin)\",\n {\n error: error instanceof Error ? error.message : String(error),\n iframeSrc: this.iframeElement?.src,\n },\n );\n // This is expected when the iframe is on the auth server domain\n this.logger.info(\n \"Iframe is on auth server domain - using postMessage for communication\",\n {\n parentOrigin: window.location.origin,\n authServerOrigin: new URL(this.config.oauthServerBaseUrl).origin,\n },\n );\n }\n }\n\n private setupSignalObserver(iframeDoc: Document): void {\n const signalObserver = new SignalObserver(\n {\n textSignals: this.config.textSignals,\n events: this.config.events,\n logger: this.logger,\n },\n this.onAuthSuccess,\n (error?: Error) =>\n this.onAuthError(error || new Error(\"Signal observer error\")),\n () => this.cleanup(),\n );\n\n signalObserver.setup(iframeDoc);\n }\n\n private setupIframeNavigationMonitoring(): void {\n // Monitor iframe navigation to detect when it redirects to our callback URL\n let monitoringInterval: number | undefined = undefined;\n let lastKnownUrl = \"\";\n\n const checkIframeNavigation = () => {\n if (!this.iframeElement?.contentWindow) {\n if (monitoringInterval) {\n clearInterval(monitoringInterval);\n }\n return;\n }\n\n try {\n const currentUrl = this.iframeElement.contentWindow.location.href;\n\n if (currentUrl !== lastKnownUrl) {\n lastKnownUrl = currentUrl;\n this.logger.debug(\"Iframe navigation detected\", {\n newUrl: currentUrl,\n redirectUrl: this.config.redirectUrl,\n isCallbackUrl: currentUrl.startsWith(this.config.redirectUrl),\n });\n\n // Check if iframe has navigated to our callback URL\n if (currentUrl.startsWith(this.config.redirectUrl)) {\n // Hide immediately on callback URL detection\n this.iframeManager?.hide();\n this.logger.info(\n \"Iframe navigated to callback URL - setting up signal observer\",\n );\n\n if (monitoringInterval) {\n clearInterval(monitoringInterval);\n }\n\n // Set up signal observer for same-origin callback page\n if (\n this.iframeElement.contentDocument &&\n this.iframeElement.contentDocument.body\n ) {\n this.setupSignalObserver(this.iframeElement.contentDocument);\n }\n\n // Also check for URL parameters (code, error) in case of direct callback\n this.processCallbackUrl(currentUrl);\n } else {\n // Hide content if not on login app\n this.checkAndHideNonLoginContent();\n }\n }\n } catch {\n // Expected when iframe is on different origin\n // Only log if we haven't seen this before\n if (lastKnownUrl !== \"cross-origin\") {\n lastKnownUrl = \"cross-origin\";\n this.logger.debug(\n \"Iframe on cross-origin domain (expected during auth flow)\",\n );\n }\n }\n };\n\n // Check immediately and then every 100ms for faster detection\n checkIframeNavigation();\n monitoringInterval = window.setInterval(checkIframeNavigation, 100);\n\n // Store cleanup function to clear monitoring\n const originalCleanup = this.cleanup;\n this.cleanup = () => {\n if (monitoringInterval) {\n clearInterval(monitoringInterval);\n }\n originalCleanup();\n };\n }\n\n private processCallbackUrl(currentUrl: string): void {\n const urlParams = new URLSearchParams(new URL(currentUrl).search);\n const code = urlParams.get(\"code\");\n const error = urlParams.get(\"error\");\n\n if (code) {\n this.logger.info(\"Authorization code detected in iframe URL\", {\n code: code.substring(0, 10) + \"...\",\n hasState: !!urlParams.get(\"state\"),\n });\n }\n\n if (error) {\n this.logger.error(\"OAuth error detected in iframe URL\", {\n error,\n errorDescription: urlParams.get(\"error_description\"),\n });\n\n const authError = new CivicAuthError(\n `OAuth error: ${error}`,\n CivicAuthErrorCode.INVALID_MESSAGE,\n );\n\n this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: authError.message,\n error: urlParams.get(\"error_description\") || error,\n });\n\n this.onAuthError(authError);\n }\n }\n\n public navigateIframe(url: string): void {\n if (!this.iframeElement) {\n this.logger.error(\n \"Cannot navigate iframe, iframeElement is not available.\",\n );\n this.onAuthError(\n new CivicAuthError(\n \"Iframe element not found for navigation.\",\n CivicAuthErrorCode.IFRAME_NOT_FOUND,\n ),\n );\n return;\n }\n if (!this.iframeManager) {\n this.logger.error(\n \"Cannot navigate iframe, iframeManager is not available.\",\n );\n this.onAuthError(\n new CivicAuthError(\n \"Iframe manager not found for navigation.\",\n CivicAuthErrorCode.INTERNAL_ERROR,\n ),\n );\n return;\n }\n this.logger.info(\"Navigating iframe to new URL\", { url });\n this.iframeElement.src = url;\n // After changing src, existing onload/onmessage handlers in IframeManager\n // and navigation monitoring in this class should manage visibility and state.\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IframeManager.d.ts","sourceRoot":"","sources":["../../../src/vanillajs/iframe/IframeManager.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,WAAW,CAAC;IACvB,WAAW,EAAE,UAAU,GAAG,OAAO,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;GAGG;AACH,qBAAa,aAAa;IAExB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAU;IAC/C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAW;IAC9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAA2B;IACvE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAe;IAC1D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAU;IAC/C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAW;IACtD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAW;IACtD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAO;IAEjD,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,cAAc,CAAC,CAAiC;IACxD,OAAO,CAAC,YAAY,CAAC,CAA8B;IACnD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAC,CAAa;IAC7B,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,0BAA0B,CAAC,CAAgC;IACnE,OAAO,CAAC,MAAM,CAAkC;IAEhD,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,aAAa,CAA4B;gBAErC,MAAM,EAAE,YAAY;IAUhC,OAAO,CAAC,mBAAmB;IAgB3B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA4BxB,OAAO,CAAC,qBAAqB;IAWtB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB;IAqCnD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA+BzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;
|
|
1
|
+
{"version":3,"file":"IframeManager.d.ts","sourceRoot":"","sources":["../../../src/vanillajs/iframe/IframeManager.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,WAAW,CAAC;IACvB,WAAW,EAAE,UAAU,GAAG,OAAO,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;GAGG;AACH,qBAAa,aAAa;IAExB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAU;IAC/C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAW;IAC9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAA2B;IACvE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAe;IAC1D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAU;IAC/C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAW;IACtD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAW;IACtD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAO;IAEjD,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,cAAc,CAAC,CAAiC;IACxD,OAAO,CAAC,YAAY,CAAC,CAA8B;IACnD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAC,CAAa;IAC7B,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,0BAA0B,CAAC,CAAgC;IACnE,OAAO,CAAC,MAAM,CAAkC;IAEhD,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,aAAa,CAA4B;gBAErC,MAAM,EAAE,YAAY;IAUhC,OAAO,CAAC,mBAAmB;IAgB3B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA4BxB,OAAO,CAAC,qBAAqB;IAWtB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB;IAqCnD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA+BzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAehC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IA0BlC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA+ChC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA0DxB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA6B3B,OAAO,CAAC,iBAAiB;IAWzB,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,6BAA6B;IA2B9B,IAAI,IAAI,IAAI;IAYZ,IAAI,IAAI,IAAI;IAkBnB,OAAO,CAAC,iBAAiB;IAqClB,OAAO,IAAI,IAAI;IAsDtB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA2BjB,MAAM,IAAI,IAAI;IAMrB;;;OAGG;IACI,eAAe,IAAI,IAAI;IA8B9B;;;OAGG;IACI,eAAe,IAAI,IAAI;IAU9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAQ/B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAOhC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAMjC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAM3B,gCAAgC,IAAI,IAAI;CAgDhD"}
|
|
@@ -164,6 +164,8 @@ export class IframeManager {
|
|
|
164
164
|
this.iframe.setAttribute("scrolling", "no");
|
|
165
165
|
this.iframe.setAttribute("frameborder", "0");
|
|
166
166
|
this.iframe.setAttribute("seamless", "seamless");
|
|
167
|
+
this.iframe.setAttribute("allow", "camera; screen-wake-lock; publickey-credentials-get; publickey-credentials-create");
|
|
168
|
+
this.iframe.setAttribute("allowFullScreen", "true");
|
|
167
169
|
// Add additional CSS to prevent scrollbars
|
|
168
170
|
this.iframe.style.cssText +=
|
|
169
171
|
"; -ms-overflow-style: none; scrollbar-width: none;";
|
|
@@ -380,19 +382,33 @@ export class IframeManager {
|
|
|
380
382
|
}
|
|
381
383
|
hide() {
|
|
382
384
|
if (this.displayMode === "modal") {
|
|
383
|
-
//
|
|
385
|
+
// Hide immediately without transition
|
|
386
|
+
this.container.style.transition = "none";
|
|
384
387
|
this.container.style.opacity = "0";
|
|
385
|
-
this.container.style.
|
|
386
|
-
// Hide after transition completes
|
|
387
|
-
setTimeout(() => {
|
|
388
|
-
this.container.style.display = "none";
|
|
389
|
-
}, parseInt(IframeManager.TRANSITION_DURATION));
|
|
388
|
+
this.container.style.display = "none";
|
|
390
389
|
}
|
|
391
390
|
else {
|
|
392
391
|
// For embedded mode, just hide immediately
|
|
393
392
|
this.container.style.display = "none";
|
|
394
393
|
}
|
|
395
394
|
}
|
|
395
|
+
show() {
|
|
396
|
+
if (this.displayMode === "modal") {
|
|
397
|
+
// Show immediately, then fade in
|
|
398
|
+
this.container.style.display = "flex";
|
|
399
|
+
this.container.style.opacity = "0";
|
|
400
|
+
this.container.style.transition = `opacity ${IframeManager.TRANSITION_DURATION} ease`;
|
|
401
|
+
// Use setTimeout to ensure display change takes effect before opacity transition
|
|
402
|
+
setTimeout(() => {
|
|
403
|
+
this.container.style.opacity = "1";
|
|
404
|
+
}, 10);
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
// For embedded mode, just show immediately
|
|
408
|
+
this.container.style.display = "block";
|
|
409
|
+
this.container.style.opacity = "1";
|
|
410
|
+
}
|
|
411
|
+
}
|
|
396
412
|
cleanupIframeOnly() {
|
|
397
413
|
if (this.resizer) {
|
|
398
414
|
this.resizer.cleanup();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IframeManager.js","sourceRoot":"","sources":["../../../src/vanillajs/iframe/IframeManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { CivicIframeResizer } from \"./IframeResizer.js\";\nimport {\n createIframeShimmerLoader,\n createCloseButton,\n} from \"../ui/LoadingComponents.js\";\nimport { createLogger } from \"../utils/logger.js\";\n\nexport interface IframeConfig {\n container: HTMLElement;\n displayMode: \"embedded\" | \"modal\";\n width?: string;\n height?: string;\n iframeId?: string;\n onClose?: () => void;\n}\n\n/**\n * IframeManager - Manages iframe visual presentation and DOM lifecycle\n * Handles styling, positioning, UI components, and iframe element creation/cleanup\n */\nexport class IframeManager {\n // Constants for styling and configuration\n private static readonly MODAL_Z_INDEX = \"1050\";\n private static readonly MODAL_WIDTH = \"20rem\"; // 320px\n private static readonly MODAL_BACKDROP_COLOR = \"rgba(17, 24, 39, 0.5)\";\n private static readonly MODAL_BACKDROP_BLUR = \"blur(4px)\";\n private static readonly BORDER_RADIUS = \"24px\";\n private static readonly TRANSITION_DURATION = \"250ms\";\n private static readonly MODAL_MIN_HEIGHT = \"26px\";\n private static readonly EMBEDDED_MIN_HEIGHT = \"225px\";\n private static readonly IFRAME_READY_DELAY = 100; // ms\n\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLElement;\n private resizer: CivicIframeResizer | null = null;\n private displayMode: \"embedded\" | \"modal\";\n private keydownHandler?: (event: KeyboardEvent) => void;\n private clickHandler?: (event: MouseEvent) => void;\n private iframeId: string;\n private onClose?: () => void;\n private shimmerLoader: HTMLElement | null = null;\n private closeButton: HTMLButtonElement | null = null;\n private isIframeLoaded = false;\n private iframeReadyMessageListener?: (event: MessageEvent) => void;\n private logger: ReturnType<typeof createLogger>;\n // Store references to wrapper elements for styling control\n private contentWrapper: HTMLElement | null = null;\n private iframeWrapper: HTMLElement | null = null;\n\n constructor(config: IframeConfig) {\n this.container = config.container;\n this.displayMode = config.displayMode;\n this.iframeId = config.iframeId || \"civic-auth-iframe\";\n this.onClose = config.onClose;\n this.logger = createLogger(\"iframe\");\n this.initializeContainer(config);\n this.setupKeyboardHandlers();\n }\n\n private initializeContainer(config: IframeConfig): void {\n if (this.displayMode === \"modal\") {\n this.applyModalStyles();\n return;\n }\n\n // Embedded mode\n this.container.style.position = \"relative\";\n this.container.style.width = config.width || \"auto\";\n this.container.style.height = config.height || \"auto\";\n this.container.style.backgroundColor = \"white\";\n this.container.style.borderRadius = IframeManager.BORDER_RADIUS;\n this.container.style.overflow = \"hidden\";\n this.container.style.transition = \"all 0.5s ease-in-out\";\n }\n\n /**\n * Applies modal backdrop styles to create a full-screen overlay\n * Uses !important to override any existing styles\n */\n private applyModalStyles(): void {\n const modalStyles = {\n position: \"fixed\",\n left: \"0\",\n top: \"0\",\n width: \"100vw\",\n height: \"100vh\",\n \"z-index\": IframeManager.MODAL_Z_INDEX,\n display: \"flex\",\n \"align-items\": \"center\",\n \"justify-content\": \"center\",\n \"background-color\": IframeManager.MODAL_BACKDROP_COLOR,\n \"backdrop-filter\": IframeManager.MODAL_BACKDROP_BLUR,\n opacity: \"1\",\n transition: `opacity ${IframeManager.TRANSITION_DURATION} ease`,\n // Reset any conflicting styles that might prevent modal from working\n margin: \"0\",\n padding: \"0\",\n border: \"none\",\n \"border-radius\": \"0\",\n \"min-height\": \"100vh\",\n };\n\n Object.entries(modalStyles).forEach(([property, value]) => {\n this.container.style.setProperty(property, value, \"important\");\n });\n }\n\n private setupKeyboardHandlers(): void {\n if (this.displayMode === \"modal\") {\n this.keydownHandler = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n this.onClose?.();\n }\n };\n window.addEventListener(\"keydown\", this.keydownHandler);\n }\n }\n\n public createIframe(url: string): HTMLIFrameElement {\n // Clean up any existing iframe content, but preserve container styles for modal mode\n this.cleanupIframeOnly();\n\n // Create new iframe\n this.iframe = document.createElement(\"iframe\");\n this.iframe.id = this.iframeId;\n this.iframe.src = url;\n this.iframe.setAttribute(\"data-testid\", \"civic-auth-iframe-with-resizer\");\n\n // Apply iframe styles\n this.applyIframeStyles();\n\n // Add attributes that prevent scrollbars\n this.setIframeAttributes();\n\n // Add CSS to prevent scrollbars\n this.addScrollbarHidingStyles();\n\n // Set up message listener for iframe ready events (more reliable than onload)\n this.setupIframeMessageListener();\n\n // Set up iframe onload handler\n this.setupIframeOnloadHandler();\n\n if (this.displayMode === \"modal\") {\n this.setupModalIframe();\n } else {\n this.setupEmbeddedIframe();\n }\n\n // Initialize resizer - this will handle all the message-based resizing\n this.resizer = new CivicIframeResizer(this.iframe, this.container);\n\n return this.iframe;\n }\n\n /**\n * Applies base styles to the iframe element\n */\n private applyIframeStyles(): void {\n if (!this.iframe) return;\n\n const baseStyles = {\n border: \"none\",\n display: \"block\",\n pointerEvents: \"auto\",\n width: \"100%\",\n minWidth: \"100%\",\n overflow: \"hidden\",\n overflowX: \"hidden\",\n overflowY: \"hidden\",\n opacity: \"0\",\n transition: `opacity ${IframeManager.TRANSITION_DURATION} ease, height ${IframeManager.TRANSITION_DURATION} ease`,\n };\n\n Object.entries(baseStyles).forEach(([property, value]) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Required to handle dynamic CSS property assignment since CSSStyleDeclaration type doesn't fully capture all possible properties\n this.iframe!.style[property as any] = value;\n });\n\n // Set initial height based on display mode\n if (this.displayMode === \"modal\") {\n this.iframe!.style.height = IframeManager.MODAL_MIN_HEIGHT;\n this.iframe!.style.minHeight = IframeManager.MODAL_MIN_HEIGHT;\n } else {\n this.iframe!.style.height = \"auto\";\n this.iframe!.style.minHeight = IframeManager.EMBEDDED_MIN_HEIGHT; // Embedded mode minimum\n }\n }\n\n /**\n * Sets iframe attributes to prevent scrollbars\n */\n private setIframeAttributes(): void {\n if (!this.iframe) return;\n\n this.iframe.setAttribute(\"scrolling\", \"no\");\n this.iframe.setAttribute(\"frameborder\", \"0\");\n this.iframe.setAttribute(\"seamless\", \"seamless\");\n\n // Add additional CSS to prevent scrollbars\n this.iframe.style.cssText +=\n \"; -ms-overflow-style: none; scrollbar-width: none;\";\n }\n\n /**\n * Adds CSS styles to hide scrollbars across different browsers\n */\n private addScrollbarHidingStyles(): void {\n const iframeStyle = document.createElement(\"style\");\n iframeStyle.textContent = `\n iframe[id=\"${this.iframeId}\"] {\n -webkit-overflow-scrolling: touch !important;\n }\n iframe[id=\"${this.iframeId}\"]::webkit-scrollbar {\n display: none !important;\n width: 0 !important;\n height: 0 !important;\n }\n `;\n document.head.appendChild(iframeStyle);\n }\n\n /**\n * Sets up the message listener for iframe ready events\n */\n private setupIframeMessageListener(): void {\n this.iframeReadyMessageListener = (event: MessageEvent) => {\n try {\n // Only handle messages from our iframe\n if (\n !this.iframe?.contentWindow ||\n event.source !== this.iframe.contentWindow\n ) {\n return;\n }\n\n const message = event.data;\n\n // Handle ready message from iframe resizer\n if (message.type === \"civic-iframe-ready\") {\n this.logger.debug(\"Iframe content is ready - hiding shimmer loader\");\n this.markIframeAsLoaded();\n }\n } catch (error) {\n this.logger.debug(\"Error processing iframe ready message:\", error);\n }\n };\n\n window.addEventListener(\"message\", this.iframeReadyMessageListener);\n }\n\n /**\n * Sets up the iframe onload handler with CSS injection\n */\n private setupIframeOnloadHandler(): void {\n if (!this.iframe) return;\n\n this.iframe.onload = () => {\n // Use a small delay to allow ready message to arrive first\n setTimeout(() => {\n if (!this.isIframeLoaded) {\n this.logger.debug(\n \"Iframe onload fired - hiding shimmer loader (fallback)\",\n );\n this.markIframeAsLoaded();\n }\n }, IframeManager.IFRAME_READY_DELAY);\n\n try {\n const iframeDoc =\n this.iframe?.contentDocument || this.iframe?.contentWindow?.document;\n if (iframeDoc && iframeDoc.head) {\n const style = iframeDoc.createElement(\"style\");\n style.textContent = `\n html, body {\n overflow: hidden !important;\n overflow-x: hidden !important;\n overflow-y: hidden !important;\n -ms-overflow-style: none !important;\n scrollbar-width: none !important;\n margin: 0 !important;\n padding: 0 !important;\n }\n body::-webkit-scrollbar {\n display: none !important;\n }\n * {\n box-sizing: border-box !important;\n }\n `;\n iframeDoc.head.appendChild(style);\n }\n } catch (error) {\n this.logger.debug(\n \"Could not inject CSS into iframe (likely cross-origin):\",\n error,\n );\n }\n };\n }\n\n /**\n * Sets up the iframe for modal display mode\n */\n private setupModalIframe(): void {\n if (!this.iframe) return;\n\n // Ensure modal is visible (in case it was hidden by cleanup)\n this.container.style.setProperty(\"display\", \"flex\", \"important\");\n\n // Create content wrapper for modal\n this.contentWrapper = document.createElement(\"div\");\n this.contentWrapper.style.position = \"relative\";\n this.contentWrapper.style.overflow = \"hidden\";\n this.contentWrapper.style.width = IframeManager.MODAL_WIDTH; // 320px like React version\n\n // Apply initial visual styling\n this.applyModalVisualStyling();\n\n // Stop propagation on content wrapper to prevent backdrop clicks\n this.contentWrapper.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n });\n\n // Create inner iframe wrapper to match React structure\n this.iframeWrapper = document.createElement(\"div\");\n this.iframeWrapper.style.position = \"relative\";\n this.iframeWrapper.style.overflow = \"hidden\";\n this.iframeWrapper.style.overflowX = \"hidden\";\n this.iframeWrapper.style.overflowY = \"hidden\";\n this.iframeWrapper.style.transition = `all ${IframeManager.TRANSITION_DURATION} ease`;\n this.iframeWrapper.style.width = \"100%\";\n this.iframeWrapper.style.height = \"auto\";\n this.iframeWrapper.style.minHeight = IframeManager.MODAL_MIN_HEIGHT; // Start small for modal mode\n\n // Apply initial wrapper styling\n this.applyIframeWrapperStyling();\n\n // Add shimmer loader for modal mode\n this.showShimmerLoader(this.iframeWrapper, \"white\");\n\n // Add close button for modal mode (initially hidden)\n if (this.onClose) {\n this.closeButton = createCloseButton(this.onClose);\n this.contentWrapper.appendChild(this.closeButton);\n }\n\n // Add iframe to wrapper, then wrapper to content, then content to container\n this.iframeWrapper.appendChild(this.iframe);\n this.contentWrapper.appendChild(this.iframeWrapper);\n this.container.appendChild(this.contentWrapper);\n\n // Add click-to-close functionality after content is added\n this.clickHandler = (e: MouseEvent) => {\n if (e.target === this.container) {\n // Only close if clicking the backdrop, not the iframe content\n this.onClose?.();\n }\n };\n this.container.addEventListener(\"click\", this.clickHandler);\n }\n\n /**\n * Sets up the iframe for embedded display mode\n */\n private setupEmbeddedIframe(): void {\n if (!this.iframe) return;\n\n // Embedded mode - create wrapper with border radius and overflow hidden\n this.iframeWrapper = document.createElement(\"div\");\n this.iframeWrapper.style.position = \"relative\";\n this.iframeWrapper.style.overflow = \"hidden\";\n this.iframeWrapper.style.overflowX = \"hidden\";\n this.iframeWrapper.style.overflowY = \"hidden\";\n this.iframeWrapper.style.transition = \"all 0.5s ease-in-out\";\n this.iframeWrapper.style.width = \"100%\";\n this.iframeWrapper.style.height = \"auto\";\n this.iframeWrapper.style.minHeight = IframeManager.EMBEDDED_MIN_HEIGHT; // Embedded mode minimum\n\n // Apply initial wrapper styling\n this.applyIframeWrapperStyling();\n\n // Add shimmer loader for embedded mode with max width\n this.showShimmerLoader(\n this.iframeWrapper,\n \"white\",\n IframeManager.MODAL_WIDTH,\n );\n\n // Add iframe to wrapper, then wrapper to container\n this.iframeWrapper.appendChild(this.iframe);\n this.container.appendChild(this.iframeWrapper);\n }\n\n private showShimmerLoader(\n parentElement: HTMLElement,\n backgroundColor = \"white\",\n maxWidth?: string,\n ): void {\n if (!this.isIframeLoaded && !this.shimmerLoader) {\n this.shimmerLoader = createIframeShimmerLoader(backgroundColor, maxWidth);\n parentElement.appendChild(this.shimmerLoader);\n }\n }\n\n private hideShimmerLoader(): void {\n if (this.shimmerLoader && this.shimmerLoader.parentNode) {\n // Add fade-out transition before removing\n this.shimmerLoader.style.opacity = \"0\";\n this.shimmerLoader.style.transition = `opacity ${IframeManager.TRANSITION_DURATION} ease`;\n\n // Remove after transition completes\n setTimeout(() => {\n if (this.shimmerLoader && this.shimmerLoader.parentNode) {\n this.shimmerLoader.parentNode.removeChild(this.shimmerLoader);\n this.shimmerLoader = null;\n }\n }, parseInt(IframeManager.TRANSITION_DURATION));\n }\n }\n\n private markIframeAsLoaded(): void {\n if (!this.isIframeLoaded) {\n this.isIframeLoaded = true;\n this.hideShimmerLoader();\n this.updateWrapperForLoadedContent();\n }\n }\n\n private updateWrapperForLoadedContent(): void {\n // Fade in the iframe\n if (this.iframe) {\n this.iframe.style.opacity = \"1\";\n }\n\n // Show close button for modal mode when content is loaded\n if (this.displayMode === \"modal\" && this.closeButton) {\n this.closeButton.style.opacity = \"1\";\n }\n\n // Find the iframe wrapper and update its styles for loaded content\n const iframeWrapper = this.iframe?.parentElement;\n if (iframeWrapper) {\n // Remove minimum height constraints to allow natural sizing\n if (this.displayMode === \"modal\") {\n iframeWrapper.style.minHeight = \"auto\";\n } else {\n // For embedded mode, keep some minimum but allow natural growth\n iframeWrapper.style.minHeight = \"auto\";\n }\n\n // Add border radius transition for loaded state (matching React implementation)\n iframeWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;\n }\n }\n\n public hide(): void {\n if (this.displayMode === \"modal\") {\n // Add fade-out transition for modal backdrop\n this.container.style.opacity = \"0\";\n this.container.style.transition = `opacity ${IframeManager.TRANSITION_DURATION} ease`;\n\n // Hide after transition completes\n setTimeout(() => {\n this.container.style.display = \"none\";\n }, parseInt(IframeManager.TRANSITION_DURATION));\n } else {\n // For embedded mode, just hide immediately\n this.container.style.display = \"none\";\n }\n }\n\n private cleanupIframeOnly(): void {\n if (this.resizer) {\n this.resizer.cleanup();\n this.resizer = null;\n }\n\n // Clean up shimmer loader\n this.hideShimmerLoader();\n\n // Clean up close button\n if (this.closeButton && this.closeButton.parentNode) {\n this.closeButton.parentNode.removeChild(this.closeButton);\n this.closeButton = null;\n }\n\n // Clean up message listener\n if (this.iframeReadyMessageListener) {\n window.removeEventListener(\"message\", this.iframeReadyMessageListener);\n this.iframeReadyMessageListener = undefined;\n }\n\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Reset loading state\n this.isIframeLoaded = false;\n\n // Clear wrapper references\n this.contentWrapper = null;\n this.iframeWrapper = null;\n\n // Clear container content but DON'T reset styles for modal mode\n this.container.innerHTML = \"\";\n }\n\n public cleanup(): void {\n if (this.resizer) {\n this.resizer.cleanup();\n this.resizer = null;\n }\n\n // Clean up shimmer loader\n this.hideShimmerLoader();\n\n // Clean up close button\n if (this.closeButton && this.closeButton.parentNode) {\n this.closeButton.parentNode.removeChild(this.closeButton);\n this.closeButton = null;\n }\n\n // Clean up message listener\n if (this.iframeReadyMessageListener) {\n window.removeEventListener(\"message\", this.iframeReadyMessageListener);\n this.iframeReadyMessageListener = undefined;\n }\n\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Reset loading state\n this.isIframeLoaded = false;\n\n // Remove keyboard event listener\n if (this.keydownHandler) {\n window.removeEventListener(\"keydown\", this.keydownHandler);\n this.keydownHandler = undefined;\n }\n\n // Remove click event listener\n if (this.clickHandler) {\n this.container.removeEventListener(\"click\", this.clickHandler);\n this.clickHandler = undefined;\n }\n\n // Clear wrapper references\n this.contentWrapper = null;\n this.iframeWrapper = null;\n\n // Clear container content and reset styles\n this.container.innerHTML = \"\";\n\n if (this.displayMode === \"modal\") {\n // Reset all modal-specific styles to ensure clean state\n this.resetModalStyles();\n }\n }\n\n /**\n * Resets all modal-specific styles by removing CSS properties that were set with !important\n */\n private resetModalStyles(): void {\n const modalStyleProperties = [\n \"position\",\n \"left\",\n \"top\",\n \"width\",\n \"height\",\n \"z-index\",\n \"display\",\n \"align-items\",\n \"justify-content\",\n \"background-color\",\n \"backdrop-filter\",\n \"opacity\",\n \"transition\",\n \"margin\",\n \"padding\",\n \"border\",\n \"border-radius\",\n \"min-height\",\n ];\n\n modalStyleProperties.forEach((property) => {\n this.container.style.removeProperty(property);\n });\n }\n\n public resize(): void {\n if (this.resizer) {\n this.resizer.resize();\n }\n }\n\n /**\n * Force show the shimmer loader and hide iframe content\n * Used when we want to mask non-login content\n */\n public forceShowLoader(): void {\n // Reset loading state to show shimmer\n this.isIframeLoaded = false;\n\n // Hide iframe content\n if (this.iframe) {\n this.iframe.style.opacity = \"0\";\n }\n\n // Hide close button\n if (this.displayMode === \"modal\" && this.closeButton) {\n this.closeButton.style.opacity = \"0\";\n }\n\n // Hide visual decorations (borders, shadows) when masking content\n if (this.displayMode === \"modal\") {\n this.removeModalVisualStyling();\n }\n this.removeIframeWrapperStyling();\n\n // Show shimmer loader\n if (this.iframeWrapper && !this.shimmerLoader) {\n this.showShimmerLoader(\n this.iframeWrapper,\n \"white\",\n this.displayMode === \"embedded\" ? IframeManager.MODAL_WIDTH : undefined,\n );\n }\n }\n\n /**\n * Force hide the shimmer loader and show iframe content\n * Used when we want to show the login app\n */\n public forceHideLoader(): void {\n // Restore visual decorations when showing content\n if (this.displayMode === \"modal\") {\n this.applyModalVisualStyling();\n }\n this.applyIframeWrapperStyling();\n\n this.markIframeAsLoaded();\n }\n\n /**\n * Applies visual styling (borders, shadows) to modal content wrapper\n */\n private applyModalVisualStyling(): void {\n if (!this.contentWrapper) return;\n\n this.contentWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;\n this.contentWrapper.style.boxShadow =\n \"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)\";\n }\n\n /**\n * Removes visual styling (borders, shadows) from modal content wrapper\n */\n private removeModalVisualStyling(): void {\n if (!this.contentWrapper) return;\n\n this.contentWrapper.style.borderRadius = \"0\";\n this.contentWrapper.style.boxShadow = \"none\";\n }\n\n /**\n * Applies visual styling (borders) to iframe wrapper\n */\n private applyIframeWrapperStyling(): void {\n if (!this.iframeWrapper) return;\n\n this.iframeWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;\n }\n\n /**\n * Removes visual styling (borders) from iframe wrapper\n */\n private removeIframeWrapperStyling(): void {\n if (!this.iframeWrapper) return;\n\n this.iframeWrapper.style.borderRadius = \"0\";\n }\n\n public showSubtlePopupFallbackIndicator(): void {\n if (!this.iframeWrapper && !this.contentWrapper) {\n this.logger.warn(\n \"Cannot show popup fallback indicator, no iframe wrapper or content wrapper found.\",\n );\n return;\n }\n\n const targetElement = this.iframeWrapper || this.contentWrapper;\n\n if (targetElement) {\n this.logger.debug(\"Showing popup fallback overlay.\");\n\n // Create overlay element\n const overlay = document.createElement(\"div\");\n overlay.id = \"civic-popup-fallback-overlay\";\n overlay.style.cssText = `\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: transparent;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n border-radius: ${IframeManager.BORDER_RADIUS};\n backdrop-filter: blur(.4px);\n opacity: 1;\n `;\n\n // Add overlay to target element\n targetElement.style.position = \"relative\";\n targetElement.appendChild(overlay);\n\n // Remove overlay quickly\n setTimeout(() => {\n if (overlay.parentNode) {\n overlay.parentNode.removeChild(overlay);\n }\n this.logger.debug(\"Popup fallback overlay removed.\");\n }, 500); // Remove after 500ms\n\n this.logger.debug(\"Popup fallback overlay displayed.\");\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"IframeManager.js","sourceRoot":"","sources":["../../../src/vanillajs/iframe/IframeManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { CivicIframeResizer } from \"./IframeResizer.js\";\nimport {\n createIframeShimmerLoader,\n createCloseButton,\n} from \"../ui/LoadingComponents.js\";\nimport { createLogger } from \"../utils/logger.js\";\n\nexport interface IframeConfig {\n container: HTMLElement;\n displayMode: \"embedded\" | \"modal\";\n width?: string;\n height?: string;\n iframeId?: string;\n onClose?: () => void;\n}\n\n/**\n * IframeManager - Manages iframe visual presentation and DOM lifecycle\n * Handles styling, positioning, UI components, and iframe element creation/cleanup\n */\nexport class IframeManager {\n // Constants for styling and configuration\n private static readonly MODAL_Z_INDEX = \"1050\";\n private static readonly MODAL_WIDTH = \"20rem\"; // 320px\n private static readonly MODAL_BACKDROP_COLOR = \"rgba(17, 24, 39, 0.5)\";\n private static readonly MODAL_BACKDROP_BLUR = \"blur(4px)\";\n private static readonly BORDER_RADIUS = \"24px\";\n private static readonly TRANSITION_DURATION = \"250ms\";\n private static readonly MODAL_MIN_HEIGHT = \"26px\";\n private static readonly EMBEDDED_MIN_HEIGHT = \"225px\";\n private static readonly IFRAME_READY_DELAY = 100; // ms\n\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLElement;\n private resizer: CivicIframeResizer | null = null;\n private displayMode: \"embedded\" | \"modal\";\n private keydownHandler?: (event: KeyboardEvent) => void;\n private clickHandler?: (event: MouseEvent) => void;\n private iframeId: string;\n private onClose?: () => void;\n private shimmerLoader: HTMLElement | null = null;\n private closeButton: HTMLButtonElement | null = null;\n private isIframeLoaded = false;\n private iframeReadyMessageListener?: (event: MessageEvent) => void;\n private logger: ReturnType<typeof createLogger>;\n // Store references to wrapper elements for styling control\n private contentWrapper: HTMLElement | null = null;\n private iframeWrapper: HTMLElement | null = null;\n\n constructor(config: IframeConfig) {\n this.container = config.container;\n this.displayMode = config.displayMode;\n this.iframeId = config.iframeId || \"civic-auth-iframe\";\n this.onClose = config.onClose;\n this.logger = createLogger(\"iframe\");\n this.initializeContainer(config);\n this.setupKeyboardHandlers();\n }\n\n private initializeContainer(config: IframeConfig): void {\n if (this.displayMode === \"modal\") {\n this.applyModalStyles();\n return;\n }\n\n // Embedded mode\n this.container.style.position = \"relative\";\n this.container.style.width = config.width || \"auto\";\n this.container.style.height = config.height || \"auto\";\n this.container.style.backgroundColor = \"white\";\n this.container.style.borderRadius = IframeManager.BORDER_RADIUS;\n this.container.style.overflow = \"hidden\";\n this.container.style.transition = \"all 0.5s ease-in-out\";\n }\n\n /**\n * Applies modal backdrop styles to create a full-screen overlay\n * Uses !important to override any existing styles\n */\n private applyModalStyles(): void {\n const modalStyles = {\n position: \"fixed\",\n left: \"0\",\n top: \"0\",\n width: \"100vw\",\n height: \"100vh\",\n \"z-index\": IframeManager.MODAL_Z_INDEX,\n display: \"flex\",\n \"align-items\": \"center\",\n \"justify-content\": \"center\",\n \"background-color\": IframeManager.MODAL_BACKDROP_COLOR,\n \"backdrop-filter\": IframeManager.MODAL_BACKDROP_BLUR,\n opacity: \"1\",\n transition: `opacity ${IframeManager.TRANSITION_DURATION} ease`,\n // Reset any conflicting styles that might prevent modal from working\n margin: \"0\",\n padding: \"0\",\n border: \"none\",\n \"border-radius\": \"0\",\n \"min-height\": \"100vh\",\n };\n\n Object.entries(modalStyles).forEach(([property, value]) => {\n this.container.style.setProperty(property, value, \"important\");\n });\n }\n\n private setupKeyboardHandlers(): void {\n if (this.displayMode === \"modal\") {\n this.keydownHandler = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n this.onClose?.();\n }\n };\n window.addEventListener(\"keydown\", this.keydownHandler);\n }\n }\n\n public createIframe(url: string): HTMLIFrameElement {\n // Clean up any existing iframe content, but preserve container styles for modal mode\n this.cleanupIframeOnly();\n\n // Create new iframe\n this.iframe = document.createElement(\"iframe\");\n this.iframe.id = this.iframeId;\n this.iframe.src = url;\n this.iframe.setAttribute(\"data-testid\", \"civic-auth-iframe-with-resizer\");\n\n // Apply iframe styles\n this.applyIframeStyles();\n\n // Add attributes that prevent scrollbars\n this.setIframeAttributes();\n\n // Add CSS to prevent scrollbars\n this.addScrollbarHidingStyles();\n\n // Set up message listener for iframe ready events (more reliable than onload)\n this.setupIframeMessageListener();\n\n // Set up iframe onload handler\n this.setupIframeOnloadHandler();\n\n if (this.displayMode === \"modal\") {\n this.setupModalIframe();\n } else {\n this.setupEmbeddedIframe();\n }\n\n // Initialize resizer - this will handle all the message-based resizing\n this.resizer = new CivicIframeResizer(this.iframe, this.container);\n\n return this.iframe;\n }\n\n /**\n * Applies base styles to the iframe element\n */\n private applyIframeStyles(): void {\n if (!this.iframe) return;\n\n const baseStyles = {\n border: \"none\",\n display: \"block\",\n pointerEvents: \"auto\",\n width: \"100%\",\n minWidth: \"100%\",\n overflow: \"hidden\",\n overflowX: \"hidden\",\n overflowY: \"hidden\",\n opacity: \"0\",\n transition: `opacity ${IframeManager.TRANSITION_DURATION} ease, height ${IframeManager.TRANSITION_DURATION} ease`,\n };\n\n Object.entries(baseStyles).forEach(([property, value]) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Required to handle dynamic CSS property assignment since CSSStyleDeclaration type doesn't fully capture all possible properties\n this.iframe!.style[property as any] = value;\n });\n\n // Set initial height based on display mode\n if (this.displayMode === \"modal\") {\n this.iframe!.style.height = IframeManager.MODAL_MIN_HEIGHT;\n this.iframe!.style.minHeight = IframeManager.MODAL_MIN_HEIGHT;\n } else {\n this.iframe!.style.height = \"auto\";\n this.iframe!.style.minHeight = IframeManager.EMBEDDED_MIN_HEIGHT; // Embedded mode minimum\n }\n }\n\n /**\n * Sets iframe attributes to prevent scrollbars\n */\n private setIframeAttributes(): void {\n if (!this.iframe) return;\n\n this.iframe.setAttribute(\"scrolling\", \"no\");\n this.iframe.setAttribute(\"frameborder\", \"0\");\n this.iframe.setAttribute(\"seamless\", \"seamless\");\n this.iframe.setAttribute(\n \"allow\",\n \"camera; screen-wake-lock; publickey-credentials-get; publickey-credentials-create\",\n );\n this.iframe.setAttribute(\"allowFullScreen\", \"true\");\n\n // Add additional CSS to prevent scrollbars\n this.iframe.style.cssText +=\n \"; -ms-overflow-style: none; scrollbar-width: none;\";\n }\n\n /**\n * Adds CSS styles to hide scrollbars across different browsers\n */\n private addScrollbarHidingStyles(): void {\n const iframeStyle = document.createElement(\"style\");\n iframeStyle.textContent = `\n iframe[id=\"${this.iframeId}\"] {\n -webkit-overflow-scrolling: touch !important;\n }\n iframe[id=\"${this.iframeId}\"]::webkit-scrollbar {\n display: none !important;\n width: 0 !important;\n height: 0 !important;\n }\n `;\n document.head.appendChild(iframeStyle);\n }\n\n /**\n * Sets up the message listener for iframe ready events\n */\n private setupIframeMessageListener(): void {\n this.iframeReadyMessageListener = (event: MessageEvent) => {\n try {\n // Only handle messages from our iframe\n if (\n !this.iframe?.contentWindow ||\n event.source !== this.iframe.contentWindow\n ) {\n return;\n }\n\n const message = event.data;\n\n // Handle ready message from iframe resizer\n if (message.type === \"civic-iframe-ready\") {\n this.logger.debug(\"Iframe content is ready - hiding shimmer loader\");\n this.markIframeAsLoaded();\n }\n } catch (error) {\n this.logger.debug(\"Error processing iframe ready message:\", error);\n }\n };\n\n window.addEventListener(\"message\", this.iframeReadyMessageListener);\n }\n\n /**\n * Sets up the iframe onload handler with CSS injection\n */\n private setupIframeOnloadHandler(): void {\n if (!this.iframe) return;\n\n this.iframe.onload = () => {\n // Use a small delay to allow ready message to arrive first\n setTimeout(() => {\n if (!this.isIframeLoaded) {\n this.logger.debug(\n \"Iframe onload fired - hiding shimmer loader (fallback)\",\n );\n this.markIframeAsLoaded();\n }\n }, IframeManager.IFRAME_READY_DELAY);\n\n try {\n const iframeDoc =\n this.iframe?.contentDocument || this.iframe?.contentWindow?.document;\n if (iframeDoc && iframeDoc.head) {\n const style = iframeDoc.createElement(\"style\");\n style.textContent = `\n html, body {\n overflow: hidden !important;\n overflow-x: hidden !important;\n overflow-y: hidden !important;\n -ms-overflow-style: none !important;\n scrollbar-width: none !important;\n margin: 0 !important;\n padding: 0 !important;\n }\n body::-webkit-scrollbar {\n display: none !important;\n }\n * {\n box-sizing: border-box !important;\n }\n `;\n iframeDoc.head.appendChild(style);\n }\n } catch (error) {\n this.logger.debug(\n \"Could not inject CSS into iframe (likely cross-origin):\",\n error,\n );\n }\n };\n }\n\n /**\n * Sets up the iframe for modal display mode\n */\n private setupModalIframe(): void {\n if (!this.iframe) return;\n\n // Ensure modal is visible (in case it was hidden by cleanup)\n this.container.style.setProperty(\"display\", \"flex\", \"important\");\n\n // Create content wrapper for modal\n this.contentWrapper = document.createElement(\"div\");\n this.contentWrapper.style.position = \"relative\";\n this.contentWrapper.style.overflow = \"hidden\";\n this.contentWrapper.style.width = IframeManager.MODAL_WIDTH; // 320px like React version\n\n // Apply initial visual styling\n this.applyModalVisualStyling();\n\n // Stop propagation on content wrapper to prevent backdrop clicks\n this.contentWrapper.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n });\n\n // Create inner iframe wrapper to match React structure\n this.iframeWrapper = document.createElement(\"div\");\n this.iframeWrapper.style.position = \"relative\";\n this.iframeWrapper.style.overflow = \"hidden\";\n this.iframeWrapper.style.overflowX = \"hidden\";\n this.iframeWrapper.style.overflowY = \"hidden\";\n this.iframeWrapper.style.transition = `all ${IframeManager.TRANSITION_DURATION} ease`;\n this.iframeWrapper.style.width = \"100%\";\n this.iframeWrapper.style.height = \"auto\";\n this.iframeWrapper.style.minHeight = IframeManager.MODAL_MIN_HEIGHT; // Start small for modal mode\n\n // Apply initial wrapper styling\n this.applyIframeWrapperStyling();\n\n // Add shimmer loader for modal mode\n this.showShimmerLoader(this.iframeWrapper, \"white\");\n\n // Add close button for modal mode (initially hidden)\n if (this.onClose) {\n this.closeButton = createCloseButton(this.onClose);\n this.contentWrapper.appendChild(this.closeButton);\n }\n\n // Add iframe to wrapper, then wrapper to content, then content to container\n this.iframeWrapper.appendChild(this.iframe);\n this.contentWrapper.appendChild(this.iframeWrapper);\n this.container.appendChild(this.contentWrapper);\n\n // Add click-to-close functionality after content is added\n this.clickHandler = (e: MouseEvent) => {\n if (e.target === this.container) {\n // Only close if clicking the backdrop, not the iframe content\n this.onClose?.();\n }\n };\n this.container.addEventListener(\"click\", this.clickHandler);\n }\n\n /**\n * Sets up the iframe for embedded display mode\n */\n private setupEmbeddedIframe(): void {\n if (!this.iframe) return;\n\n // Embedded mode - create wrapper with border radius and overflow hidden\n this.iframeWrapper = document.createElement(\"div\");\n this.iframeWrapper.style.position = \"relative\";\n this.iframeWrapper.style.overflow = \"hidden\";\n this.iframeWrapper.style.overflowX = \"hidden\";\n this.iframeWrapper.style.overflowY = \"hidden\";\n this.iframeWrapper.style.transition = \"all 0.5s ease-in-out\";\n this.iframeWrapper.style.width = \"100%\";\n this.iframeWrapper.style.height = \"auto\";\n this.iframeWrapper.style.minHeight = IframeManager.EMBEDDED_MIN_HEIGHT; // Embedded mode minimum\n\n // Apply initial wrapper styling\n this.applyIframeWrapperStyling();\n\n // Add shimmer loader for embedded mode with max width\n this.showShimmerLoader(\n this.iframeWrapper,\n \"white\",\n IframeManager.MODAL_WIDTH,\n );\n\n // Add iframe to wrapper, then wrapper to container\n this.iframeWrapper.appendChild(this.iframe);\n this.container.appendChild(this.iframeWrapper);\n }\n\n private showShimmerLoader(\n parentElement: HTMLElement,\n backgroundColor = \"white\",\n maxWidth?: string,\n ): void {\n if (!this.isIframeLoaded && !this.shimmerLoader) {\n this.shimmerLoader = createIframeShimmerLoader(backgroundColor, maxWidth);\n parentElement.appendChild(this.shimmerLoader);\n }\n }\n\n private hideShimmerLoader(): void {\n if (this.shimmerLoader && this.shimmerLoader.parentNode) {\n // Add fade-out transition before removing\n this.shimmerLoader.style.opacity = \"0\";\n this.shimmerLoader.style.transition = `opacity ${IframeManager.TRANSITION_DURATION} ease`;\n\n // Remove after transition completes\n setTimeout(() => {\n if (this.shimmerLoader && this.shimmerLoader.parentNode) {\n this.shimmerLoader.parentNode.removeChild(this.shimmerLoader);\n this.shimmerLoader = null;\n }\n }, parseInt(IframeManager.TRANSITION_DURATION));\n }\n }\n\n private markIframeAsLoaded(): void {\n if (!this.isIframeLoaded) {\n this.isIframeLoaded = true;\n this.hideShimmerLoader();\n this.updateWrapperForLoadedContent();\n }\n }\n\n private updateWrapperForLoadedContent(): void {\n // Fade in the iframe\n if (this.iframe) {\n this.iframe.style.opacity = \"1\";\n }\n\n // Show close button for modal mode when content is loaded\n if (this.displayMode === \"modal\" && this.closeButton) {\n this.closeButton.style.opacity = \"1\";\n }\n\n // Find the iframe wrapper and update its styles for loaded content\n const iframeWrapper = this.iframe?.parentElement;\n if (iframeWrapper) {\n // Remove minimum height constraints to allow natural sizing\n if (this.displayMode === \"modal\") {\n iframeWrapper.style.minHeight = \"auto\";\n } else {\n // For embedded mode, keep some minimum but allow natural growth\n iframeWrapper.style.minHeight = \"auto\";\n }\n\n // Add border radius transition for loaded state (matching React implementation)\n iframeWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;\n }\n }\n\n public hide(): void {\n if (this.displayMode === \"modal\") {\n // Hide immediately without transition\n this.container.style.transition = \"none\";\n this.container.style.opacity = \"0\";\n this.container.style.display = \"none\";\n } else {\n // For embedded mode, just hide immediately\n this.container.style.display = \"none\";\n }\n }\n\n public show(): void {\n if (this.displayMode === \"modal\") {\n // Show immediately, then fade in\n this.container.style.display = \"flex\";\n this.container.style.opacity = \"0\";\n this.container.style.transition = `opacity ${IframeManager.TRANSITION_DURATION} ease`;\n\n // Use setTimeout to ensure display change takes effect before opacity transition\n setTimeout(() => {\n this.container.style.opacity = \"1\";\n }, 10);\n } else {\n // For embedded mode, just show immediately\n this.container.style.display = \"block\";\n this.container.style.opacity = \"1\";\n }\n }\n\n private cleanupIframeOnly(): void {\n if (this.resizer) {\n this.resizer.cleanup();\n this.resizer = null;\n }\n\n // Clean up shimmer loader\n this.hideShimmerLoader();\n\n // Clean up close button\n if (this.closeButton && this.closeButton.parentNode) {\n this.closeButton.parentNode.removeChild(this.closeButton);\n this.closeButton = null;\n }\n\n // Clean up message listener\n if (this.iframeReadyMessageListener) {\n window.removeEventListener(\"message\", this.iframeReadyMessageListener);\n this.iframeReadyMessageListener = undefined;\n }\n\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Reset loading state\n this.isIframeLoaded = false;\n\n // Clear wrapper references\n this.contentWrapper = null;\n this.iframeWrapper = null;\n\n // Clear container content but DON'T reset styles for modal mode\n this.container.innerHTML = \"\";\n }\n\n public cleanup(): void {\n if (this.resizer) {\n this.resizer.cleanup();\n this.resizer = null;\n }\n\n // Clean up shimmer loader\n this.hideShimmerLoader();\n\n // Clean up close button\n if (this.closeButton && this.closeButton.parentNode) {\n this.closeButton.parentNode.removeChild(this.closeButton);\n this.closeButton = null;\n }\n\n // Clean up message listener\n if (this.iframeReadyMessageListener) {\n window.removeEventListener(\"message\", this.iframeReadyMessageListener);\n this.iframeReadyMessageListener = undefined;\n }\n\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Reset loading state\n this.isIframeLoaded = false;\n\n // Remove keyboard event listener\n if (this.keydownHandler) {\n window.removeEventListener(\"keydown\", this.keydownHandler);\n this.keydownHandler = undefined;\n }\n\n // Remove click event listener\n if (this.clickHandler) {\n this.container.removeEventListener(\"click\", this.clickHandler);\n this.clickHandler = undefined;\n }\n\n // Clear wrapper references\n this.contentWrapper = null;\n this.iframeWrapper = null;\n\n // Clear container content and reset styles\n this.container.innerHTML = \"\";\n\n if (this.displayMode === \"modal\") {\n // Reset all modal-specific styles to ensure clean state\n this.resetModalStyles();\n }\n }\n\n /**\n * Resets all modal-specific styles by removing CSS properties that were set with !important\n */\n private resetModalStyles(): void {\n const modalStyleProperties = [\n \"position\",\n \"left\",\n \"top\",\n \"width\",\n \"height\",\n \"z-index\",\n \"display\",\n \"align-items\",\n \"justify-content\",\n \"background-color\",\n \"backdrop-filter\",\n \"opacity\",\n \"transition\",\n \"margin\",\n \"padding\",\n \"border\",\n \"border-radius\",\n \"min-height\",\n ];\n\n modalStyleProperties.forEach((property) => {\n this.container.style.removeProperty(property);\n });\n }\n\n public resize(): void {\n if (this.resizer) {\n this.resizer.resize();\n }\n }\n\n /**\n * Force show the shimmer loader and hide iframe content\n * Used when we want to mask non-login content\n */\n public forceShowLoader(): void {\n // Reset loading state to show shimmer\n this.isIframeLoaded = false;\n\n // Hide iframe content\n if (this.iframe) {\n this.iframe.style.opacity = \"0\";\n }\n\n // Hide close button\n if (this.displayMode === \"modal\" && this.closeButton) {\n this.closeButton.style.opacity = \"0\";\n }\n\n // Hide visual decorations (borders, shadows) when masking content\n if (this.displayMode === \"modal\") {\n this.removeModalVisualStyling();\n }\n this.removeIframeWrapperStyling();\n\n // Show shimmer loader\n if (this.iframeWrapper && !this.shimmerLoader) {\n this.showShimmerLoader(\n this.iframeWrapper,\n \"white\",\n this.displayMode === \"embedded\" ? IframeManager.MODAL_WIDTH : undefined,\n );\n }\n }\n\n /**\n * Force hide the shimmer loader and show iframe content\n * Used when we want to show the login app\n */\n public forceHideLoader(): void {\n // Restore visual decorations when showing content\n if (this.displayMode === \"modal\") {\n this.applyModalVisualStyling();\n }\n this.applyIframeWrapperStyling();\n\n this.markIframeAsLoaded();\n }\n\n /**\n * Applies visual styling (borders, shadows) to modal content wrapper\n */\n private applyModalVisualStyling(): void {\n if (!this.contentWrapper) return;\n\n this.contentWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;\n this.contentWrapper.style.boxShadow =\n \"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)\";\n }\n\n /**\n * Removes visual styling (borders, shadows) from modal content wrapper\n */\n private removeModalVisualStyling(): void {\n if (!this.contentWrapper) return;\n\n this.contentWrapper.style.borderRadius = \"0\";\n this.contentWrapper.style.boxShadow = \"none\";\n }\n\n /**\n * Applies visual styling (borders) to iframe wrapper\n */\n private applyIframeWrapperStyling(): void {\n if (!this.iframeWrapper) return;\n\n this.iframeWrapper.style.borderRadius = IframeManager.BORDER_RADIUS;\n }\n\n /**\n * Removes visual styling (borders) from iframe wrapper\n */\n private removeIframeWrapperStyling(): void {\n if (!this.iframeWrapper) return;\n\n this.iframeWrapper.style.borderRadius = \"0\";\n }\n\n public showSubtlePopupFallbackIndicator(): void {\n if (!this.iframeWrapper && !this.contentWrapper) {\n this.logger.warn(\n \"Cannot show popup fallback indicator, no iframe wrapper or content wrapper found.\",\n );\n return;\n }\n\n const targetElement = this.iframeWrapper || this.contentWrapper;\n\n if (targetElement) {\n this.logger.debug(\"Showing popup fallback overlay.\");\n\n // Create overlay element\n const overlay = document.createElement(\"div\");\n overlay.id = \"civic-popup-fallback-overlay\";\n overlay.style.cssText = `\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: transparent;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n border-radius: ${IframeManager.BORDER_RADIUS};\n backdrop-filter: blur(.4px);\n opacity: 1;\n `;\n\n // Add overlay to target element\n targetElement.style.position = \"relative\";\n targetElement.appendChild(overlay);\n\n // Remove overlay quickly\n setTimeout(() => {\n if (overlay.parentNode) {\n overlay.parentNode.removeChild(overlay);\n }\n this.logger.debug(\"Popup fallback overlay removed.\");\n }, 500); // Remove after 500ms\n\n this.logger.debug(\"Popup fallback overlay displayed.\");\n }\n }\n}\n"]}
|