@civic/auth 0.6.1-beta.3 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/README.md +7 -0
  3. package/dist/nextjs/config.d.ts.map +1 -1
  4. package/dist/nextjs/config.js +1 -5
  5. package/dist/nextjs/config.js.map +1 -1
  6. package/dist/nextjs/hooks/useUserCookie.d.ts.map +1 -1
  7. package/dist/nextjs/hooks/useUserCookie.js.map +1 -1
  8. package/dist/nextjs/middleware.d.ts.map +1 -1
  9. package/dist/nextjs/middleware.js +51 -18
  10. package/dist/nextjs/middleware.js.map +1 -1
  11. package/dist/nextjs/providers/NextAuthProvider.d.ts.map +1 -1
  12. package/dist/nextjs/providers/NextAuthProvider.js +0 -1
  13. package/dist/nextjs/providers/NextAuthProvider.js.map +1 -1
  14. package/dist/nextjs/routeHandler.d.ts.map +1 -1
  15. package/dist/nextjs/routeHandler.js +8 -0
  16. package/dist/nextjs/routeHandler.js.map +1 -1
  17. package/dist/shared/hooks/useSignIn.d.ts +4 -9
  18. package/dist/shared/hooks/useSignIn.d.ts.map +1 -1
  19. package/dist/shared/hooks/useSignIn.js +42 -75
  20. package/dist/shared/hooks/useSignIn.js.map +1 -1
  21. package/dist/shared/providers/AuthContext.d.ts +2 -7
  22. package/dist/shared/providers/AuthContext.d.ts.map +1 -1
  23. package/dist/shared/providers/AuthContext.js.map +1 -1
  24. package/dist/shared/providers/UserProvider.d.ts +1 -5
  25. package/dist/shared/providers/UserProvider.d.ts.map +1 -1
  26. package/dist/shared/providers/UserProvider.js.map +1 -1
  27. package/dist/shared/version.d.ts +1 -1
  28. package/dist/shared/version.d.ts.map +1 -1
  29. package/dist/shared/version.js +1 -1
  30. package/dist/shared/version.js.map +1 -1
  31. package/dist/vanillajs/auth/AuthenticationEvents.d.ts.map +1 -1
  32. package/dist/vanillajs/auth/AuthenticationEvents.js +2 -2
  33. package/dist/vanillajs/auth/AuthenticationEvents.js.map +1 -1
  34. package/dist/vanillajs/auth/CivicAuth.d.ts +107 -68
  35. package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
  36. package/dist/vanillajs/auth/CivicAuth.js +412 -389
  37. package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
  38. package/dist/vanillajs/auth/{handlers/OAuthCallbackHandler.d.ts → OAuthCallbackHandler.d.ts} +2 -2
  39. package/dist/vanillajs/auth/OAuthCallbackHandler.d.ts.map +1 -0
  40. package/dist/vanillajs/auth/OAuthCallbackHandler.js +143 -0
  41. package/dist/vanillajs/auth/OAuthCallbackHandler.js.map +1 -0
  42. package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -1
  43. package/dist/vanillajs/auth/SessionManager.js +2 -2
  44. package/dist/vanillajs/auth/SessionManager.js.map +1 -1
  45. package/dist/vanillajs/auth/TokenRefresher.d.ts.map +1 -1
  46. package/dist/vanillajs/auth/TokenRefresher.js +2 -2
  47. package/dist/vanillajs/auth/TokenRefresher.js.map +1 -1
  48. package/dist/vanillajs/iframe/IframeManager.d.ts +0 -33
  49. package/dist/vanillajs/iframe/IframeManager.d.ts.map +1 -1
  50. package/dist/vanillajs/iframe/IframeManager.js +36 -163
  51. package/dist/vanillajs/iframe/IframeManager.js.map +1 -1
  52. package/dist/vanillajs/index.d.ts +2 -2
  53. package/dist/vanillajs/index.d.ts.map +1 -1
  54. package/dist/vanillajs/index.js +2 -2
  55. package/dist/vanillajs/index.js.map +1 -1
  56. package/dist/vanillajs/services/ApiService.d.ts.map +1 -1
  57. package/dist/vanillajs/services/ApiService.js +2 -2
  58. package/dist/vanillajs/services/ApiService.js.map +1 -1
  59. package/dist/vanillajs/types/index.d.ts +10 -15
  60. package/dist/vanillajs/types/index.d.ts.map +1 -1
  61. package/dist/vanillajs/types/index.js +10 -15
  62. package/dist/vanillajs/types/index.js.map +1 -1
  63. package/dist/vanillajs/utils/auth-utils.d.ts +1 -2
  64. package/dist/vanillajs/utils/auth-utils.d.ts.map +1 -1
  65. package/dist/vanillajs/utils/auth-utils.js +3 -6
  66. package/dist/vanillajs/utils/auth-utils.js.map +1 -1
  67. package/dist/vanillajs/utils/logger.d.ts +15 -16
  68. package/dist/vanillajs/utils/logger.d.ts.map +1 -1
  69. package/dist/vanillajs/utils/logger.js +19 -35
  70. package/dist/vanillajs/utils/logger.js.map +1 -1
  71. package/package.json +1 -6
  72. package/dist/vanillajs/auth/config/ConfigProcessor.d.ts +0 -6
  73. package/dist/vanillajs/auth/config/ConfigProcessor.d.ts.map +0 -1
  74. package/dist/vanillajs/auth/config/ConfigProcessor.js +0 -59
  75. package/dist/vanillajs/auth/config/ConfigProcessor.js.map +0 -1
  76. package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts +0 -40
  77. package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts.map +0 -1
  78. package/dist/vanillajs/auth/handlers/IframeAuthHandler.js +0 -388
  79. package/dist/vanillajs/auth/handlers/IframeAuthHandler.js.map +0 -1
  80. package/dist/vanillajs/auth/handlers/MessageHandler.d.ts +0 -170
  81. package/dist/vanillajs/auth/handlers/MessageHandler.d.ts.map +0 -1
  82. package/dist/vanillajs/auth/handlers/MessageHandler.js +0 -367
  83. package/dist/vanillajs/auth/handlers/MessageHandler.js.map +0 -1
  84. package/dist/vanillajs/auth/handlers/OAuthCallbackHandler.d.ts.map +0 -1
  85. package/dist/vanillajs/auth/handlers/OAuthCallbackHandler.js +0 -301
  86. package/dist/vanillajs/auth/handlers/OAuthCallbackHandler.js.map +0 -1
  87. package/dist/vanillajs/auth/handlers/PopupHandler.d.ts +0 -108
  88. package/dist/vanillajs/auth/handlers/PopupHandler.d.ts.map +0 -1
  89. package/dist/vanillajs/auth/handlers/PopupHandler.js +0 -333
  90. package/dist/vanillajs/auth/handlers/PopupHandler.js.map +0 -1
  91. package/dist/vanillajs/auth/types/AuthTypes.d.ts +0 -128
  92. package/dist/vanillajs/auth/types/AuthTypes.d.ts.map +0 -1
  93. package/dist/vanillajs/auth/types/AuthTypes.js +0 -40
  94. package/dist/vanillajs/auth/types/AuthTypes.js.map +0 -1
@@ -1,333 +0,0 @@
1
- import { AuthEvent } from "../../types/index.js";
2
- import { CivicAuthError, CivicAuthErrorCode } from "../types/AuthTypes.js";
3
- import { PopupError } from "../../../services/types.js";
4
- import { createLogger as createLoggerFn } from "../../utils/logger.js";
5
- export class PopupHandler {
6
- config;
7
- logger = createLoggerFn("popup"); // Create own logger
8
- popup;
9
- popupCheckInterval;
10
- onAuthSuccess;
11
- onAuthError;
12
- cleanup;
13
- constructor(handlerConfig) {
14
- this.config = handlerConfig.config;
15
- // Don't use handlerConfig.logger - use our own logger instead
16
- this.onAuthSuccess = handlerConfig.onAuthSuccess;
17
- this.onAuthError = handlerConfig.onAuthError;
18
- this.cleanup = handlerConfig.cleanup;
19
- }
20
- /**
21
- * Initiates authentication flow using a popup window.
22
- *
23
- * Opens a new browser window/tab for authentication, handles browser compatibility
24
- * (especially Safari), and sets up monitoring for the authentication process.
25
- *
26
- * @param fullAuthUrl - The complete authentication URL to open in the popup
27
- * @throws {PopupError} When popup window cannot be opened (blocked by browser)
28
- * @returns Promise that resolves when popup setup is complete
29
- */
30
- async handleNewTabAuth(fullAuthUrl) {
31
- this.logger.info("🚀 Starting new tab authentication", {
32
- url: fullAuthUrl,
33
- userAgent: navigator.userAgent,
34
- isSafari: /Safari/.test(navigator.userAgent) &&
35
- !/Chrome/.test(navigator.userAgent),
36
- });
37
- try {
38
- // For Safari, use specific window features that work better
39
- const isSafari = /Safari/.test(navigator.userAgent) &&
40
- !/Chrome/.test(navigator.userAgent);
41
- const windowFeatures = isSafari
42
- ? "width=500,height=600,scrollbars=yes,resizable=yes"
43
- : "";
44
- const popupWindow = isSafari
45
- ? window.open(fullAuthUrl, "_blank", windowFeatures)
46
- : window.open(fullAuthUrl, "_blank");
47
- this.logger.info("📱 Popup window attempt result", {
48
- popupWindow: popupWindow,
49
- popupWindowType: typeof popupWindow,
50
- isNull: popupWindow === null,
51
- isUndefined: popupWindow === undefined,
52
- windowFeatures: isSafari ? windowFeatures : "none specified",
53
- isSafari,
54
- });
55
- if (!popupWindow) {
56
- throw new PopupError("Failed to open popup window - likely blocked by browser");
57
- }
58
- // Additional Safari-specific check: Safari might return a window object but still block it
59
- if (isSafari) {
60
- // Give Safari a moment to potentially close the popup if it was blocked
61
- setTimeout(() => {
62
- if (popupWindow.closed) {
63
- this.logger.warn("🚫 Safari popup was immediately closed (likely blocked)");
64
- const error = new PopupError("Safari blocked popup window");
65
- if (this.config.events) {
66
- this.config.events.emit(AuthEvent.SIGN_IN_ERROR, {
67
- detail: error.message,
68
- error,
69
- });
70
- }
71
- this.onAuthError(error);
72
- return;
73
- }
74
- }, 100);
75
- }
76
- this.logger.info("✅ Popup window opened successfully", {
77
- popupWindow: !!popupWindow,
78
- popupClosed: popupWindow.closed,
79
- popupLocation: this.getPopupLocationSafely(popupWindow),
80
- });
81
- // Set up popup monitoring
82
- this.monitorPopup(popupWindow);
83
- }
84
- catch (error) {
85
- this.logger.error("❌ Popup window creation failed", {
86
- error: error,
87
- errorType: error instanceof PopupError ? "PopupError" : "Other",
88
- });
89
- if (error instanceof PopupError) {
90
- // Re-throw PopupError to be caught by the main authentication flow
91
- throw error;
92
- }
93
- else {
94
- // Wrap other errors as PopupError
95
- throw new PopupError(`window.open has thrown: ${error instanceof Error ? error.message : String(error)}`);
96
- }
97
- }
98
- }
99
- /**
100
- * Safely retrieves the current location of a popup window.
101
- *
102
- * Attempts to access the popup's location.href property, handling cross-origin
103
- * access restrictions gracefully by returning a descriptive message instead of throwing.
104
- *
105
- * @param popup - The popup window to get location from
106
- * @returns The popup's URL or a descriptive message if access is restricted
107
- */
108
- getPopupLocationSafely(popup) {
109
- try {
110
- return popup.location.href;
111
- }
112
- catch {
113
- return "cross-origin (cannot access)";
114
- }
115
- }
116
- /**
117
- * Monitors a popup window for authentication results and handles communication.
118
- *
119
- * This method sets up a postMessage listener to receive authentication results from the popup
120
- * and periodically checks if the popup has been closed. It handles success/error messages
121
- * and automatically cleans up resources when the popup closes or times out.
122
- *
123
- * @param popup - The popup window to monitor for authentication completion
124
- *
125
- * @remarks
126
- * - Monitors popup for up to 5 minutes (300 checks at 1-second intervals)
127
- * - Listens for 'auth_success' and 'auth_error' message types from the popup
128
- * - Automatically removes event listeners and resolves/rejects promises when done
129
- * - Logs detailed debugging information throughout the monitoring process
130
- *
131
- * @private
132
- */
133
- monitorPopup(popup) {
134
- this.logger.info("👀 Starting popup monitoring");
135
- let checkCount = 0;
136
- const maxChecks = 300; // 5 minutes at 1 second intervals
137
- let popupMessageHandler = null;
138
- // Set up postMessage listener for popup communication
139
- popupMessageHandler = (event) => {
140
- this.logger.debug("📨 Received message from popup", {
141
- origin: event.origin,
142
- data: event.data,
143
- source: event.source === popup,
144
- messageType: event.data?.type,
145
- isFromTargetPopup: event.source === popup,
146
- });
147
- // Verify the message is from our popup
148
- if (event.source !== popup) {
149
- this.logger.debug("🚫 Ignoring message from different source", {
150
- expectedSource: popup,
151
- actualSource: event.source,
152
- });
153
- return;
154
- }
155
- const message = event.data;
156
- if (message && typeof message === "object" && message.type) {
157
- this.logger.info("✅ Valid popup message received", {
158
- type: message.type,
159
- detail: message.detail,
160
- hasData: !!message.data,
161
- });
162
- switch (message.type) {
163
- case "auth_success":
164
- this.handlePopupSuccess(message, popupMessageHandler);
165
- break;
166
- case "auth_error":
167
- this.handlePopupError(message, popupMessageHandler);
168
- break;
169
- default:
170
- this.logger.debug("🤷 Unknown message type from popup", {
171
- type: message.type,
172
- fullMessage: message,
173
- });
174
- }
175
- }
176
- else {
177
- this.logger.debug("📨 Non-auth message received from popup", {
178
- messageType: typeof message,
179
- message,
180
- });
181
- }
182
- };
183
- // Add the message listener
184
- window.addEventListener("message", popupMessageHandler);
185
- this.logger.info("📡 Added popup message listener", {
186
- popupWindowExists: !!popup,
187
- popupClosed: popup.closed,
188
- });
189
- const checkClosed = () => {
190
- checkCount++;
191
- this.logger.debug(`🔍 Popup check #${checkCount}`, {
192
- closed: popup.closed,
193
- location: this.getPopupLocationSafely(popup),
194
- maxChecks,
195
- });
196
- if (popup.closed) {
197
- this.handlePopupClosed(popupMessageHandler);
198
- return;
199
- }
200
- if (checkCount >= maxChecks) {
201
- this.handlePopupTimeout(popupMessageHandler);
202
- return;
203
- }
204
- // Check popup location for redirect (this is now mainly for debugging)
205
- this.checkPopupLocation(popup);
206
- // Continue monitoring
207
- setTimeout(checkClosed, 1000);
208
- };
209
- // Start monitoring
210
- setTimeout(checkClosed, 1000);
211
- }
212
- /**
213
- * Handles successful authentication completion from the popup.
214
- *
215
- * Processes the authentication success message received from the popup window,
216
- * emits success events, triggers the success callback, and performs cleanup.
217
- *
218
- * @param message - The authentication message containing success data
219
- * @param popupMessageHandler - The message event handler to clean up, or null if none exists
220
- */
221
- handlePopupSuccess(message, popupMessageHandler) {
222
- this.logger.info("🎉 Popup authentication successful");
223
- this.config.events?.emit(AuthEvent.SIGN_IN_COMPLETE, {
224
- detail: "Popup authentication successful",
225
- data: message.data,
226
- });
227
- this.onAuthSuccess(message.data || {});
228
- this.cleanup();
229
- // Clean up message listener
230
- if (popupMessageHandler) {
231
- window.removeEventListener("message", popupMessageHandler);
232
- }
233
- }
234
- /**
235
- * Handles authentication errors received from the popup.
236
- *
237
- * Processes error messages from the popup window, emits error events,
238
- * creates appropriate CivicAuthError instances, and performs cleanup.
239
- *
240
- * @param message - The authentication message containing error details
241
- * @param popupMessageHandler - The message event handler to clean up, or null if none exists
242
- */
243
- handlePopupError(message, popupMessageHandler) {
244
- this.logger.error("❌ Popup authentication failed", {
245
- detail: message.detail,
246
- });
247
- this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {
248
- detail: message.detail || "Popup authentication failed",
249
- error: message.error,
250
- });
251
- const error = new CivicAuthError(message.detail || "Popup authentication failed", CivicAuthErrorCode.INVALID_MESSAGE);
252
- this.onAuthError(error);
253
- this.cleanup();
254
- // Clean up message listener
255
- if (popupMessageHandler) {
256
- window.removeEventListener("message", popupMessageHandler);
257
- }
258
- }
259
- /**
260
- * Handles the scenario when the authentication popup is closed by the user.
261
- * This method is called when the popup window is detected as closed during monitoring.
262
- * It emits an error event, creates an appropriate error, and performs cleanup.
263
- *
264
- * @param popupMessageHandler - The message event handler to clean up, or null if none exists
265
- */
266
- handlePopupClosed(popupMessageHandler) {
267
- this.logger.warn("🔒 Popup was closed by user");
268
- this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {
269
- detail: "Authentication cancelled by user (popup closed)",
270
- });
271
- const error = new CivicAuthError("Authentication cancelled by user", CivicAuthErrorCode.USER_CANCELLED);
272
- this.onAuthError(error);
273
- this.cleanup();
274
- // Clean up message listener
275
- if (popupMessageHandler) {
276
- window.removeEventListener("message", popupMessageHandler);
277
- }
278
- }
279
- /**
280
- * Handles authentication timeout scenarios.
281
- *
282
- * Called when the popup monitoring reaches its maximum time limit without
283
- * receiving authentication results. Emits timeout events, creates timeout errors,
284
- * and performs cleanup operations.
285
- *
286
- * @param popupMessageHandler - The message event handler to clean up, or null if none exists
287
- */
288
- handlePopupTimeout(popupMessageHandler) {
289
- this.logger.warn("⏰ Popup monitoring timeout reached");
290
- this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {
291
- detail: "Authentication timeout - popup monitoring stopped",
292
- });
293
- const error = new CivicAuthError("Authentication timeout", CivicAuthErrorCode.AUTH_PROCESS_TIMEOUT);
294
- this.onAuthError(error);
295
- this.cleanup();
296
- // Clean up message listener
297
- if (popupMessageHandler) {
298
- window.removeEventListener("message", popupMessageHandler);
299
- }
300
- }
301
- /**
302
- * Monitors the popup's location for redirect changes.
303
- *
304
- * Attempts to check if the popup has redirected to the callback URL, which
305
- * indicates the authentication flow has progressed. Handles cross-origin
306
- * access restrictions gracefully by catching and logging access errors.
307
- *
308
- * @param popup - The popup window to monitor for location changes
309
- */
310
- checkPopupLocation(popup) {
311
- try {
312
- const popupLocation = popup.location.href;
313
- this.logger.debug("📍 Popup location accessible", {
314
- location: popupLocation,
315
- startsWithRedirect: popupLocation.startsWith(this.config.redirectUrl),
316
- });
317
- if (popupLocation.startsWith(this.config.redirectUrl)) {
318
- this.logger.info("🎯 Popup redirected to callback URL", {
319
- location: popupLocation,
320
- });
321
- // The callback page should send us a postMessage, so we just wait for that
322
- }
323
- }
324
- catch (error) {
325
- // Expected when popup is on different origin
326
- const errorMessage = error instanceof Error ? error.message : String(error);
327
- this.logger.debug("🔒 Cannot access popup location (cross-origin)", {
328
- error: errorMessage,
329
- });
330
- }
331
- }
332
- }
333
- //# sourceMappingURL=PopupHandler.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PopupHandler.js","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/PopupHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { AuthEvent } from \"../../types/index.js\";\nimport type { AuthResult } from \"../../types/index.js\";\nimport type {\n ProcessedCivicAuthConfig,\n AuthMessage,\n} from \"../types/AuthTypes.js\";\nimport { CivicAuthError, CivicAuthErrorCode } from \"../types/AuthTypes.js\";\nimport { PopupError } from \"../../../services/types.js\";\nimport type { createLogger } from \"../../utils/logger.js\";\nimport { createLogger as createLoggerFn } from \"../../utils/logger.js\";\n\nexport interface PopupHandlerConfig {\n config: ProcessedCivicAuthConfig;\n logger: ReturnType<typeof createLogger>; // Keep for interface compatibility but won't use\n onAuthSuccess: (result: AuthResult) => void;\n onAuthError: (error: Error) => void;\n cleanup: () => void;\n}\n\nexport class PopupHandler {\n private config: ProcessedCivicAuthConfig;\n private logger = createLoggerFn(\"popup\"); // Create own logger\n private popup?: Window | null;\n private popupCheckInterval?: number;\n private onAuthSuccess: (result: AuthResult) => void;\n private onAuthError: (error: Error) => void;\n private cleanup: () => void;\n\n constructor(handlerConfig: PopupHandlerConfig) {\n this.config = handlerConfig.config;\n // Don't use handlerConfig.logger - use our own logger instead\n this.onAuthSuccess = handlerConfig.onAuthSuccess;\n this.onAuthError = handlerConfig.onAuthError;\n this.cleanup = handlerConfig.cleanup;\n }\n\n /**\n * Initiates authentication flow using a popup window.\n *\n * Opens a new browser window/tab for authentication, handles browser compatibility\n * (especially Safari), and sets up monitoring for the authentication process.\n *\n * @param fullAuthUrl - The complete authentication URL to open in the popup\n * @throws {PopupError} When popup window cannot be opened (blocked by browser)\n * @returns Promise that resolves when popup setup is complete\n */\n public async handleNewTabAuth(fullAuthUrl: string): Promise<void> {\n this.logger.info(\"🚀 Starting new tab authentication\", {\n url: fullAuthUrl,\n userAgent: navigator.userAgent,\n isSafari:\n /Safari/.test(navigator.userAgent) &&\n !/Chrome/.test(navigator.userAgent),\n });\n\n try {\n // For Safari, use specific window features that work better\n const isSafari =\n /Safari/.test(navigator.userAgent) &&\n !/Chrome/.test(navigator.userAgent);\n const windowFeatures = isSafari\n ? \"width=500,height=600,scrollbars=yes,resizable=yes\"\n : \"\";\n\n const popupWindow = isSafari\n ? window.open(fullAuthUrl, \"_blank\", windowFeatures)\n : window.open(fullAuthUrl, \"_blank\");\n\n this.logger.info(\"📱 Popup window attempt result\", {\n popupWindow: popupWindow,\n popupWindowType: typeof popupWindow,\n isNull: popupWindow === null,\n isUndefined: popupWindow === undefined,\n windowFeatures: isSafari ? windowFeatures : \"none specified\",\n isSafari,\n });\n\n if (!popupWindow) {\n throw new PopupError(\n \"Failed to open popup window - likely blocked by browser\",\n );\n }\n\n // Additional Safari-specific check: Safari might return a window object but still block it\n if (isSafari) {\n // Give Safari a moment to potentially close the popup if it was blocked\n setTimeout(() => {\n if (popupWindow.closed) {\n this.logger.warn(\n \"🚫 Safari popup was immediately closed (likely blocked)\",\n );\n const error = new PopupError(\"Safari blocked popup window\");\n if (this.config.events) {\n this.config.events.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: error.message,\n error,\n });\n }\n this.onAuthError(error);\n return;\n }\n }, 100);\n }\n\n this.logger.info(\"✅ Popup window opened successfully\", {\n popupWindow: !!popupWindow,\n popupClosed: popupWindow.closed,\n popupLocation: this.getPopupLocationSafely(popupWindow),\n });\n\n // Set up popup monitoring\n this.monitorPopup(popupWindow);\n } catch (error) {\n this.logger.error(\"❌ Popup window creation failed\", {\n error: error,\n errorType: error instanceof PopupError ? \"PopupError\" : \"Other\",\n });\n\n if (error instanceof PopupError) {\n // Re-throw PopupError to be caught by the main authentication flow\n throw error;\n } else {\n // Wrap other errors as PopupError\n throw new PopupError(\n `window.open has thrown: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n }\n\n /**\n * Safely retrieves the current location of a popup window.\n *\n * Attempts to access the popup's location.href property, handling cross-origin\n * access restrictions gracefully by returning a descriptive message instead of throwing.\n *\n * @param popup - The popup window to get location from\n * @returns The popup's URL or a descriptive message if access is restricted\n */\n private getPopupLocationSafely(popup: Window): string {\n try {\n return popup.location.href;\n } catch {\n return \"cross-origin (cannot access)\";\n }\n }\n\n /**\n * Monitors a popup window for authentication results and handles communication.\n *\n * This method sets up a postMessage listener to receive authentication results from the popup\n * and periodically checks if the popup has been closed. It handles success/error messages\n * and automatically cleans up resources when the popup closes or times out.\n *\n * @param popup - The popup window to monitor for authentication completion\n *\n * @remarks\n * - Monitors popup for up to 5 minutes (300 checks at 1-second intervals)\n * - Listens for 'auth_success' and 'auth_error' message types from the popup\n * - Automatically removes event listeners and resolves/rejects promises when done\n * - Logs detailed debugging information throughout the monitoring process\n *\n * @private\n */\n private monitorPopup(popup: Window): void {\n this.logger.info(\"👀 Starting popup monitoring\");\n\n let checkCount = 0;\n const maxChecks = 300; // 5 minutes at 1 second intervals\n let popupMessageHandler: ((event: MessageEvent) => void) | null = null;\n\n // Set up postMessage listener for popup communication\n popupMessageHandler = (event: MessageEvent) => {\n this.logger.debug(\"📨 Received message from popup\", {\n origin: event.origin,\n data: event.data,\n source: event.source === popup,\n messageType: event.data?.type,\n isFromTargetPopup: event.source === popup,\n });\n\n // Verify the message is from our popup\n if (event.source !== popup) {\n this.logger.debug(\"🚫 Ignoring message from different source\", {\n expectedSource: popup,\n actualSource: event.source,\n });\n return;\n }\n\n const message = event.data;\n if (message && typeof message === \"object\" && message.type) {\n this.logger.info(\"✅ Valid popup message received\", {\n type: message.type,\n detail: message.detail,\n hasData: !!message.data,\n });\n\n switch (message.type) {\n case \"auth_success\":\n this.handlePopupSuccess(message, popupMessageHandler);\n break;\n case \"auth_error\":\n this.handlePopupError(message, popupMessageHandler);\n break;\n default:\n this.logger.debug(\"🤷 Unknown message type from popup\", {\n type: message.type,\n fullMessage: message,\n });\n }\n } else {\n this.logger.debug(\"📨 Non-auth message received from popup\", {\n messageType: typeof message,\n message,\n });\n }\n };\n\n // Add the message listener\n window.addEventListener(\"message\", popupMessageHandler);\n this.logger.info(\"📡 Added popup message listener\", {\n popupWindowExists: !!popup,\n popupClosed: popup.closed,\n });\n\n const checkClosed = () => {\n checkCount++;\n this.logger.debug(`🔍 Popup check #${checkCount}`, {\n closed: popup.closed,\n location: this.getPopupLocationSafely(popup),\n maxChecks,\n });\n\n if (popup.closed) {\n this.handlePopupClosed(popupMessageHandler);\n return;\n }\n\n if (checkCount >= maxChecks) {\n this.handlePopupTimeout(popupMessageHandler);\n return;\n }\n\n // Check popup location for redirect (this is now mainly for debugging)\n this.checkPopupLocation(popup);\n\n // Continue monitoring\n setTimeout(checkClosed, 1000);\n };\n\n // Start monitoring\n setTimeout(checkClosed, 1000);\n }\n\n /**\n * Handles successful authentication completion from the popup.\n *\n * Processes the authentication success message received from the popup window,\n * emits success events, triggers the success callback, and performs cleanup.\n *\n * @param message - The authentication message containing success data\n * @param popupMessageHandler - The message event handler to clean up, or null if none exists\n */\n private handlePopupSuccess(\n message: AuthMessage,\n popupMessageHandler: ((event: MessageEvent) => void) | null,\n ): void {\n this.logger.info(\"🎉 Popup authentication successful\");\n this.config.events?.emit(AuthEvent.SIGN_IN_COMPLETE, {\n detail: \"Popup authentication successful\",\n data: message.data,\n });\n this.onAuthSuccess(message.data || {});\n this.cleanup();\n\n // Clean up message listener\n if (popupMessageHandler) {\n window.removeEventListener(\"message\", popupMessageHandler);\n }\n }\n\n /**\n * Handles authentication errors received from the popup.\n *\n * Processes error messages from the popup window, emits error events,\n * creates appropriate CivicAuthError instances, and performs cleanup.\n *\n * @param message - The authentication message containing error details\n * @param popupMessageHandler - The message event handler to clean up, or null if none exists\n */\n private handlePopupError(\n message: AuthMessage,\n popupMessageHandler: ((event: MessageEvent) => void) | null,\n ): void {\n this.logger.error(\"❌ Popup authentication failed\", {\n detail: message.detail,\n });\n this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: message.detail || \"Popup authentication failed\",\n error: message.error,\n });\n\n const error = new CivicAuthError(\n message.detail || \"Popup authentication failed\",\n CivicAuthErrorCode.INVALID_MESSAGE,\n );\n\n this.onAuthError(error);\n this.cleanup();\n\n // Clean up message listener\n if (popupMessageHandler) {\n window.removeEventListener(\"message\", popupMessageHandler);\n }\n }\n\n /**\n * Handles the scenario when the authentication popup is closed by the user.\n * This method is called when the popup window is detected as closed during monitoring.\n * It emits an error event, creates an appropriate error, and performs cleanup.\n *\n * @param popupMessageHandler - The message event handler to clean up, or null if none exists\n */\n private handlePopupClosed(\n popupMessageHandler: ((event: MessageEvent) => void) | null,\n ): void {\n this.logger.warn(\"🔒 Popup was closed by user\");\n this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: \"Authentication cancelled by user (popup closed)\",\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 // Clean up message listener\n if (popupMessageHandler) {\n window.removeEventListener(\"message\", popupMessageHandler);\n }\n }\n\n /**\n * Handles authentication timeout scenarios.\n *\n * Called when the popup monitoring reaches its maximum time limit without\n * receiving authentication results. Emits timeout events, creates timeout errors,\n * and performs cleanup operations.\n *\n * @param popupMessageHandler - The message event handler to clean up, or null if none exists\n */\n private handlePopupTimeout(\n popupMessageHandler: ((event: MessageEvent) => void) | null,\n ): void {\n this.logger.warn(\"⏰ Popup monitoring timeout reached\");\n this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: \"Authentication timeout - popup monitoring stopped\",\n });\n\n const error = new CivicAuthError(\n \"Authentication timeout\",\n CivicAuthErrorCode.AUTH_PROCESS_TIMEOUT,\n );\n\n this.onAuthError(error);\n this.cleanup();\n\n // Clean up message listener\n if (popupMessageHandler) {\n window.removeEventListener(\"message\", popupMessageHandler);\n }\n }\n\n /**\n * Monitors the popup's location for redirect changes.\n *\n * Attempts to check if the popup has redirected to the callback URL, which\n * indicates the authentication flow has progressed. Handles cross-origin\n * access restrictions gracefully by catching and logging access errors.\n *\n * @param popup - The popup window to monitor for location changes\n */\n private checkPopupLocation(popup: Window): void {\n try {\n const popupLocation = popup.location.href;\n this.logger.debug(\"📍 Popup location accessible\", {\n location: popupLocation,\n startsWithRedirect: popupLocation.startsWith(this.config.redirectUrl),\n });\n\n if (popupLocation.startsWith(this.config.redirectUrl)) {\n this.logger.info(\"🎯 Popup redirected to callback URL\", {\n location: popupLocation,\n });\n // The callback page should send us a postMessage, so we just wait for that\n }\n } catch (error) {\n // Expected when popup is on different origin\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n this.logger.debug(\"🔒 Cannot access popup location (cross-origin)\", {\n error: errorMessage,\n });\n }\n }\n}\n"]}
@@ -1,128 +0,0 @@
1
- import type { AuthenticationEvents } from "../AuthenticationEvents.js";
2
- import type { DisplayMode, AuthStorage } from "../../../types.js";
3
- /**
4
- * Error codes for CivicAuth errors
5
- */
6
- export declare enum CivicAuthErrorCode {
7
- CONFIG_REQUIRED = "CONFIG_REQUIRED",
8
- INIT_FAILED = "INIT_FAILED",
9
- ENDPOINTS_NOT_INITIALIZED = "ENDPOINTS_NOT_INITIALIZED",
10
- CONTAINER_NOT_FOUND = "CONTAINER_NOT_FOUND",
11
- AUTH_PROCESS_TIMEOUT = "AUTH_PROCESS_TIMEOUT",
12
- IFRAME_LOAD_ERROR = "IFRAME_LOAD_ERROR",
13
- INVALID_MESSAGE = "INVALID_MESSAGE",
14
- LOGOUT_FAILED = "LOGOUT_FAILED",
15
- POPUP_BLOCKED = "popup_blocked",
16
- USER_CANCELLED = "user_cancelled",
17
- CONFIGURATION_ERROR = "configuration_error",
18
- TOKEN_REFRESH_FAILED = "token_refresh_failed",
19
- SESSION_NOT_FOUND = "session_not_found",
20
- STORAGE_ERROR = "storage_error",
21
- IFRAME_NOT_FOUND = "iframe_not_found",
22
- INTERNAL_ERROR = "internal_error"
23
- }
24
- /**
25
- * Constants for the auth client
26
- */
27
- export declare const CIVIC_AUTH_CONSTANTS: {
28
- readonly DEFAULT_IFRAME_ID: "civic-auth-iframe";
29
- readonly DEFAULT_AUTH_PROCESS_TIMEOUT: 60000;
30
- readonly SUCCESS_SIGNAL_ID: "civic-auth-success-signal";
31
- readonly ERROR_SIGNAL_ID: "civic-auth-error-signal";
32
- };
33
- /**
34
- * Message types for postMessage communication
35
- */
36
- export type AuthMessageType = "auth_success" | "auth_error";
37
- export interface AuthMessage {
38
- type: AuthMessageType;
39
- detail?: string;
40
- data?: unknown;
41
- error?: unknown;
42
- }
43
- /**
44
- * Login app message types for postMessage communication
45
- */
46
- export interface LoginAppMessage {
47
- source: "civicloginApp";
48
- type: string;
49
- clientId: string;
50
- data?: unknown;
51
- }
52
- /**
53
- * Combined message type for all iframe communications
54
- */
55
- export type IframeMessage = AuthMessage | LoginAppMessage | Record<string, unknown>;
56
- export declare class CivicAuthError extends Error {
57
- readonly code: CivicAuthErrorCode;
58
- constructor(message: string, code: CivicAuthErrorCode);
59
- }
60
- /**
61
- * Configuration options for the CivicAuth client
62
- */
63
- export interface CivicAuthClientConfig {
64
- /** OAuth client ID */
65
- clientId: string;
66
- /** URL to redirect to after authentication */
67
- redirectUrl?: string;
68
- /** Base URL of the OAuth server */
69
- oauthServerBaseUrl?: string;
70
- /** Array of OAuth scopes to request */
71
- scopes?: string[];
72
- /** HTML element or element ID where the auth iframe will be mounted (required for embedded iframe mode) */
73
- targetContainerElement?: HTMLElement | string;
74
- /** Text signals for success and error states */
75
- textSignals?: {
76
- /** Text to display on successful authentication */
77
- success: string;
78
- /** Optional text to display on authentication error */
79
- error?: string;
80
- };
81
- /** Display mode for the authentication UI */
82
- displayMode?: DisplayMode;
83
- /** Display mode for iframe rendering - modal (full-screen overlay) or embedded (within container) */
84
- iframeDisplayMode?: "modal" | "embedded";
85
- /**
86
- * Timeout duration in milliseconds for the entire authentication process.
87
- * If the authentication process takes longer than this duration, it will be cancelled
88
- * and an error will be thrown.
89
- */
90
- authProcessTimeout?: number;
91
- /** Event handlers for authentication events */
92
- events?: AuthenticationEvents;
93
- /** Custom ID for the auth iframe */
94
- iframeId?: string;
95
- /** Custom storage adapter for auth state - uses shared AuthStorage interface */
96
- storageAdapter?: AuthStorage;
97
- /** OAuth nonce parameter for security */
98
- nonce?: string;
99
- /** Initial state for OAuth flow */
100
- initialState?: string;
101
- /** Logging configuration */
102
- logging?: LoggingConfig;
103
- }
104
- export interface LoggingConfig {
105
- enabled: boolean;
106
- namespace?: string;
107
- level?: "debug" | "info" | "warn" | "error";
108
- }
109
- /**
110
- * Internal configuration with all optional properties resolved to required ones.
111
- */
112
- export type ProcessedCivicAuthConfig = CivicAuthClientConfig & {
113
- redirectUrl: string;
114
- oauthServerBaseUrl: string;
115
- scopes: string[];
116
- textSignals: {
117
- success: string;
118
- error?: string;
119
- };
120
- storageAdapter: AuthStorage;
121
- logging: LoggingConfig;
122
- displayMode: DisplayMode;
123
- authProcessTimeout: number;
124
- iframeId: string;
125
- prompt: string;
126
- nonce?: string;
127
- };
128
- //# sourceMappingURL=AuthTypes.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AuthTypes.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/types/AuthTypes.ts"],"names":[],"mappings":"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"}
@@ -1,40 +0,0 @@
1
- /**
2
- * Error codes for CivicAuth errors
3
- */
4
- export var CivicAuthErrorCode;
5
- (function (CivicAuthErrorCode) {
6
- CivicAuthErrorCode["CONFIG_REQUIRED"] = "CONFIG_REQUIRED";
7
- CivicAuthErrorCode["INIT_FAILED"] = "INIT_FAILED";
8
- CivicAuthErrorCode["ENDPOINTS_NOT_INITIALIZED"] = "ENDPOINTS_NOT_INITIALIZED";
9
- CivicAuthErrorCode["CONTAINER_NOT_FOUND"] = "CONTAINER_NOT_FOUND";
10
- CivicAuthErrorCode["AUTH_PROCESS_TIMEOUT"] = "AUTH_PROCESS_TIMEOUT";
11
- CivicAuthErrorCode["IFRAME_LOAD_ERROR"] = "IFRAME_LOAD_ERROR";
12
- CivicAuthErrorCode["INVALID_MESSAGE"] = "INVALID_MESSAGE";
13
- CivicAuthErrorCode["LOGOUT_FAILED"] = "LOGOUT_FAILED";
14
- CivicAuthErrorCode["POPUP_BLOCKED"] = "popup_blocked";
15
- CivicAuthErrorCode["USER_CANCELLED"] = "user_cancelled";
16
- CivicAuthErrorCode["CONFIGURATION_ERROR"] = "configuration_error";
17
- CivicAuthErrorCode["TOKEN_REFRESH_FAILED"] = "token_refresh_failed";
18
- CivicAuthErrorCode["SESSION_NOT_FOUND"] = "session_not_found";
19
- CivicAuthErrorCode["STORAGE_ERROR"] = "storage_error";
20
- CivicAuthErrorCode["IFRAME_NOT_FOUND"] = "iframe_not_found";
21
- CivicAuthErrorCode["INTERNAL_ERROR"] = "internal_error";
22
- })(CivicAuthErrorCode || (CivicAuthErrorCode = {}));
23
- /**
24
- * Constants for the auth client
25
- */
26
- export const CIVIC_AUTH_CONSTANTS = {
27
- DEFAULT_IFRAME_ID: "civic-auth-iframe",
28
- DEFAULT_AUTH_PROCESS_TIMEOUT: 60000, // 60 seconds
29
- SUCCESS_SIGNAL_ID: "civic-auth-success-signal",
30
- ERROR_SIGNAL_ID: "civic-auth-error-signal",
31
- };
32
- export class CivicAuthError extends Error {
33
- code;
34
- constructor(message, code) {
35
- super(message);
36
- this.code = code;
37
- this.name = "CivicAuthError";
38
- }
39
- }
40
- //# sourceMappingURL=AuthTypes.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AuthTypes.js","sourceRoot":"","sources":["../../../../src/vanillajs/auth/types/AuthTypes.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,CAAN,IAAY,kBAiBX;AAjBD,WAAY,kBAAkB;IAC5B,yDAAmC,CAAA;IACnC,iDAA2B,CAAA;IAC3B,6EAAuD,CAAA;IACvD,iEAA2C,CAAA;IAC3C,mEAA6C,CAAA;IAC7C,6DAAuC,CAAA;IACvC,yDAAmC,CAAA;IACnC,qDAA+B,CAAA;IAC/B,qDAA+B,CAAA;IAC/B,uDAAiC,CAAA;IACjC,iEAA2C,CAAA;IAC3C,mEAA6C,CAAA;IAC7C,6DAAuC,CAAA;IACvC,qDAA+B,CAAA;IAC/B,2DAAqC,CAAA;IACrC,uDAAiC,CAAA;AACnC,CAAC,EAjBW,kBAAkB,KAAlB,kBAAkB,QAiB7B;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,iBAAiB,EAAE,mBAAmB;IACtC,4BAA4B,EAAE,KAAK,EAAE,aAAa;IAClD,iBAAiB,EAAE,2BAA2B;IAC9C,eAAe,EAAE,yBAAyB;CAClC,CAAC;AAgCX,MAAM,OAAO,cAAe,SAAQ,KAAK;IAGrB;IAFlB,YACE,OAAe,EACC,IAAwB;QAExC,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,SAAI,GAAJ,IAAI,CAAoB;QAGxC,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF","sourcesContent":["import type { AuthenticationEvents } from \"../AuthenticationEvents.js\";\nimport type { DisplayMode, AuthStorage } from \"../../../types.js\";\n\n/**\n * Error codes for CivicAuth errors\n */\nexport enum CivicAuthErrorCode {\n CONFIG_REQUIRED = \"CONFIG_REQUIRED\",\n INIT_FAILED = \"INIT_FAILED\",\n ENDPOINTS_NOT_INITIALIZED = \"ENDPOINTS_NOT_INITIALIZED\",\n CONTAINER_NOT_FOUND = \"CONTAINER_NOT_FOUND\",\n AUTH_PROCESS_TIMEOUT = \"AUTH_PROCESS_TIMEOUT\",\n IFRAME_LOAD_ERROR = \"IFRAME_LOAD_ERROR\",\n INVALID_MESSAGE = \"INVALID_MESSAGE\",\n LOGOUT_FAILED = \"LOGOUT_FAILED\",\n POPUP_BLOCKED = \"popup_blocked\",\n USER_CANCELLED = \"user_cancelled\",\n CONFIGURATION_ERROR = \"configuration_error\",\n TOKEN_REFRESH_FAILED = \"token_refresh_failed\",\n SESSION_NOT_FOUND = \"session_not_found\",\n STORAGE_ERROR = \"storage_error\",\n IFRAME_NOT_FOUND = \"iframe_not_found\",\n INTERNAL_ERROR = \"internal_error\",\n}\n\n/**\n * Constants for the auth client\n */\nexport const CIVIC_AUTH_CONSTANTS = {\n DEFAULT_IFRAME_ID: \"civic-auth-iframe\",\n DEFAULT_AUTH_PROCESS_TIMEOUT: 60000, // 60 seconds\n SUCCESS_SIGNAL_ID: \"civic-auth-success-signal\",\n ERROR_SIGNAL_ID: \"civic-auth-error-signal\",\n} as const;\n\n/**\n * Message types for postMessage communication\n */\nexport type AuthMessageType = \"auth_success\" | \"auth_error\";\n\nexport interface AuthMessage {\n type: AuthMessageType;\n detail?: string;\n data?: unknown;\n error?: unknown;\n}\n\n/**\n * Login app message types for postMessage communication\n */\nexport interface LoginAppMessage {\n source: \"civicloginApp\";\n type: string;\n clientId: string;\n data?: unknown;\n}\n\n/**\n * Combined message type for all iframe communications\n */\nexport type IframeMessage =\n | AuthMessage\n | LoginAppMessage\n | Record<string, unknown>;\n\nexport class CivicAuthError extends Error {\n constructor(\n message: string,\n public readonly code: CivicAuthErrorCode,\n ) {\n super(message);\n this.name = \"CivicAuthError\";\n }\n}\n\n/**\n * Configuration options for the CivicAuth client\n */\nexport interface CivicAuthClientConfig {\n /** OAuth client ID */\n clientId: string;\n /** URL to redirect to after authentication */\n redirectUrl?: string;\n /** Base URL of the OAuth server */\n oauthServerBaseUrl?: string;\n /** Array of OAuth scopes to request */\n scopes?: string[];\n /** HTML element or element ID where the auth iframe will be mounted (required for embedded iframe mode) */\n targetContainerElement?: HTMLElement | string;\n /** Text signals for success and error states */\n textSignals?: {\n /** Text to display on successful authentication */\n success: string;\n /** Optional text to display on authentication error */\n error?: string;\n };\n /** Display mode for the authentication UI */\n displayMode?: DisplayMode;\n /** Display mode for iframe rendering - modal (full-screen overlay) or embedded (within container) */\n iframeDisplayMode?: \"modal\" | \"embedded\";\n /**\n * Timeout duration in milliseconds for the entire authentication process.\n * If the authentication process takes longer than this duration, it will be cancelled\n * and an error will be thrown.\n */\n authProcessTimeout?: number;\n /** Event handlers for authentication events */\n events?: AuthenticationEvents;\n /** Custom ID for the auth iframe */\n iframeId?: string;\n /** Custom storage adapter for auth state - uses shared AuthStorage interface */\n storageAdapter?: AuthStorage;\n /** OAuth nonce parameter for security */\n nonce?: string;\n /** Initial state for OAuth flow */\n initialState?: string;\n /** Logging configuration */\n logging?: LoggingConfig;\n}\n\nexport interface LoggingConfig {\n enabled: boolean;\n namespace?: string;\n level?: \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\n/**\n * Internal configuration with all optional properties resolved to required ones.\n */\nexport type ProcessedCivicAuthConfig = CivicAuthClientConfig & {\n redirectUrl: string;\n oauthServerBaseUrl: string;\n scopes: string[];\n textSignals: {\n success: string;\n error?: string;\n };\n storageAdapter: AuthStorage;\n logging: LoggingConfig;\n displayMode: DisplayMode;\n authProcessTimeout: number;\n iframeId: string;\n prompt: string;\n nonce?: string;\n // targetContainerElement remains optional as it's not needed for all display modes\n};\n"]}