@civic/auth 0.6.0-beta.3 → 0.6.1-beta.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/dist/shared/components/CivicAuthIframeContainer.js +1 -1
- package/dist/shared/components/CivicAuthIframeContainer.js.map +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.d.ts +7 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.d.ts.map +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.js +15 -2
- package/dist/shared/lib/BrowserAuthenticationRefresher.js.map +1 -1
- package/dist/shared/lib/util.d.ts +1 -1
- package/dist/shared/lib/util.d.ts.map +1 -1
- package/dist/shared/lib/util.js +6 -1
- package/dist/shared/lib/util.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/AuthenticationEvents.d.ts +11 -0
- package/dist/vanillajs/auth/AuthenticationEvents.d.ts.map +1 -0
- package/dist/vanillajs/auth/AuthenticationEvents.js +36 -0
- package/dist/vanillajs/auth/AuthenticationEvents.js.map +1 -0
- package/dist/vanillajs/auth/CivicAuth.d.ts +205 -0
- package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -0
- package/dist/vanillajs/auth/CivicAuth.js +689 -0
- package/dist/vanillajs/auth/CivicAuth.js.map +1 -0
- package/dist/vanillajs/auth/OAuthCallbackHandler.d.ts +90 -0
- package/dist/vanillajs/auth/OAuthCallbackHandler.d.ts.map +1 -0
- package/dist/vanillajs/auth/OAuthCallbackHandler.js +143 -0
- package/dist/vanillajs/auth/OAuthCallbackHandler.js.map +1 -0
- package/dist/vanillajs/auth/SessionManager.d.ts +48 -0
- package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -0
- package/dist/vanillajs/auth/SessionManager.js +121 -0
- package/dist/vanillajs/auth/SessionManager.js.map +1 -0
- package/dist/vanillajs/auth/TokenRefresher.d.ts +54 -0
- package/dist/vanillajs/auth/TokenRefresher.d.ts.map +1 -0
- package/dist/vanillajs/auth/TokenRefresher.js +166 -0
- package/dist/vanillajs/auth/TokenRefresher.js.map +1 -0
- package/dist/vanillajs/iframe/IframeManager.d.ts +82 -0
- package/dist/vanillajs/iframe/IframeManager.d.ts.map +1 -0
- package/dist/vanillajs/iframe/IframeManager.js +487 -0
- package/dist/vanillajs/iframe/IframeManager.js.map +1 -0
- package/dist/vanillajs/iframe/IframeResizer.d.ts +15 -0
- package/dist/vanillajs/iframe/IframeResizer.d.ts.map +1 -0
- package/dist/vanillajs/iframe/IframeResizer.js +127 -0
- package/dist/vanillajs/iframe/IframeResizer.js.map +1 -0
- package/dist/vanillajs/iframe/SignalObserver.d.ts +33 -0
- package/dist/vanillajs/iframe/SignalObserver.d.ts.map +1 -0
- package/dist/vanillajs/iframe/SignalObserver.js +162 -0
- package/dist/vanillajs/iframe/SignalObserver.js.map +1 -0
- package/dist/vanillajs/index.d.ts +17 -0
- package/dist/vanillajs/index.d.ts.map +1 -0
- package/dist/vanillajs/index.js +18 -0
- package/dist/vanillajs/index.js.map +1 -0
- package/dist/vanillajs/services/ApiService.d.ts +22 -0
- package/dist/vanillajs/services/ApiService.d.ts.map +1 -0
- package/dist/vanillajs/services/ApiService.js +82 -0
- package/dist/vanillajs/services/ApiService.js.map +1 -0
- package/dist/vanillajs/types/index.d.ts +28 -0
- package/dist/vanillajs/types/index.d.ts.map +1 -0
- package/dist/vanillajs/types/index.js +14 -0
- package/dist/vanillajs/types/index.js.map +1 -0
- package/dist/vanillajs/ui/LoadingComponents.d.ts +51 -0
- package/dist/vanillajs/ui/LoadingComponents.d.ts.map +1 -0
- package/dist/vanillajs/ui/LoadingComponents.js +363 -0
- package/dist/vanillajs/ui/LoadingComponents.js.map +1 -0
- package/dist/vanillajs/utils/auth-utils.d.ts +13 -0
- package/dist/vanillajs/utils/auth-utils.d.ts.map +1 -0
- package/dist/vanillajs/utils/auth-utils.js +15 -0
- package/dist/vanillajs/utils/auth-utils.js.map +1 -0
- package/dist/vanillajs/utils/logger.d.ts +29 -0
- package/dist/vanillajs/utils/logger.d.ts.map +1 -0
- package/dist/vanillajs/utils/logger.js +62 -0
- package/dist/vanillajs/utils/logger.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Message types for communication between parent and child
|
|
2
|
+
import { createLogger } from "../utils/logger.js";
|
|
3
|
+
var MessageType;
|
|
4
|
+
(function (MessageType) {
|
|
5
|
+
MessageType["RESIZE"] = "civic-iframe-resize";
|
|
6
|
+
MessageType["READY"] = "civic-iframe-ready";
|
|
7
|
+
})(MessageType || (MessageType = {}));
|
|
8
|
+
export class CivicIframeResizer {
|
|
9
|
+
iframe;
|
|
10
|
+
container;
|
|
11
|
+
logger;
|
|
12
|
+
messageListener = null;
|
|
13
|
+
requestSizeTimeouts = [];
|
|
14
|
+
constructor(iframe, container) {
|
|
15
|
+
this.iframe = iframe;
|
|
16
|
+
this.container = container;
|
|
17
|
+
this.logger = createLogger("iframe");
|
|
18
|
+
this.initializeResizer();
|
|
19
|
+
}
|
|
20
|
+
initializeResizer() {
|
|
21
|
+
this.logger.debug("Initializing Civic iframe resizer");
|
|
22
|
+
// Set up message listener for iframe resize messages
|
|
23
|
+
this.messageListener = (event) => {
|
|
24
|
+
this.handleMessage(event);
|
|
25
|
+
};
|
|
26
|
+
window.addEventListener("message", this.messageListener);
|
|
27
|
+
// Request size from child iframe after it loads
|
|
28
|
+
this.iframe.addEventListener("load", () => {
|
|
29
|
+
this.logger.debug("Iframe loaded, requesting size from child");
|
|
30
|
+
this.requestSizeFromChild();
|
|
31
|
+
// Schedule multiple size requests to ensure we get the correct height
|
|
32
|
+
const intervals = [100, 500, 1000, 2000, 3000];
|
|
33
|
+
intervals.forEach((interval) => {
|
|
34
|
+
const timeoutId = window.setTimeout(() => {
|
|
35
|
+
this.requestSizeFromChild();
|
|
36
|
+
}, interval);
|
|
37
|
+
this.requestSizeTimeouts.push(timeoutId);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
handleMessage(event) {
|
|
42
|
+
try {
|
|
43
|
+
const message = event.data;
|
|
44
|
+
// Only handle messages from our iframe
|
|
45
|
+
if (!this.iframe.contentWindow ||
|
|
46
|
+
event.source !== this.iframe.contentWindow) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.logger.debug("Received message from iframe:", message);
|
|
50
|
+
// Handle ready message
|
|
51
|
+
if (message.type === MessageType.READY) {
|
|
52
|
+
this.logger.debug("Iframe child is ready");
|
|
53
|
+
this.requestSizeFromChild();
|
|
54
|
+
}
|
|
55
|
+
// Handle resize message
|
|
56
|
+
if (message.type === MessageType.RESIZE &&
|
|
57
|
+
typeof message.height === "number") {
|
|
58
|
+
this.logger.debug("Resizing iframe to height:", message.height);
|
|
59
|
+
this.resizeIframe(message.height, message.suggestedAnimationDuration);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
this.logger.debug("Error processing iframe message:", error);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
requestSizeFromChild() {
|
|
67
|
+
if (this.iframe.contentWindow) {
|
|
68
|
+
try {
|
|
69
|
+
this.logger.debug("Requesting size from iframe child");
|
|
70
|
+
this.iframe.contentWindow.postMessage({ type: "request-size" }, "*");
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
this.logger.debug("Error requesting size from iframe:", error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
resizeIframe(height, animationDuration) {
|
|
78
|
+
// Ensure minimum height
|
|
79
|
+
const minHeight = 200;
|
|
80
|
+
const finalHeight = Math.max(height, minHeight);
|
|
81
|
+
// Apply height to iframe and ensure no overflow
|
|
82
|
+
this.iframe.style.height = `${finalHeight}px`;
|
|
83
|
+
this.iframe.style.maxHeight = `${finalHeight}px`;
|
|
84
|
+
this.iframe.style.overflow = "hidden";
|
|
85
|
+
this.iframe.style.overflowX = "hidden";
|
|
86
|
+
this.iframe.style.overflowY = "hidden";
|
|
87
|
+
// Apply transition if animation duration is suggested
|
|
88
|
+
if (animationDuration) {
|
|
89
|
+
this.iframe.style.transition = `height ${animationDuration}ms ease`;
|
|
90
|
+
}
|
|
91
|
+
// Try to inject additional CSS to prevent scrollbars after resize
|
|
92
|
+
try {
|
|
93
|
+
const iframeDoc = this.iframe.contentDocument || this.iframe.contentWindow?.document;
|
|
94
|
+
if (iframeDoc && iframeDoc.body) {
|
|
95
|
+
iframeDoc.body.style.overflow = "hidden";
|
|
96
|
+
iframeDoc.body.style.overflowX = "hidden";
|
|
97
|
+
iframeDoc.body.style.overflowY = "hidden";
|
|
98
|
+
if (iframeDoc.documentElement) {
|
|
99
|
+
iframeDoc.documentElement.style.overflow = "hidden";
|
|
100
|
+
iframeDoc.documentElement.style.overflowX = "hidden";
|
|
101
|
+
iframeDoc.documentElement.style.overflowY = "hidden";
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
this.logger.debug("Could not apply overflow styles to iframe content (likely cross-origin):", error);
|
|
107
|
+
}
|
|
108
|
+
this.logger.debug(`Iframe resized to ${finalHeight}px`);
|
|
109
|
+
}
|
|
110
|
+
cleanup() {
|
|
111
|
+
this.logger.debug("Cleaning up iframe resizer");
|
|
112
|
+
if (this.messageListener) {
|
|
113
|
+
window.removeEventListener("message", this.messageListener);
|
|
114
|
+
this.messageListener = null;
|
|
115
|
+
}
|
|
116
|
+
// Clear any pending timeouts
|
|
117
|
+
this.requestSizeTimeouts.forEach((timeoutId) => {
|
|
118
|
+
window.clearTimeout(timeoutId);
|
|
119
|
+
});
|
|
120
|
+
this.requestSizeTimeouts = [];
|
|
121
|
+
}
|
|
122
|
+
resize() {
|
|
123
|
+
// Request size from child iframe
|
|
124
|
+
this.requestSizeFromChild();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=IframeResizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IframeResizer.js","sourceRoot":"","sources":["../../../src/vanillajs/iframe/IframeResizer.ts"],"names":[],"mappings":"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","sourcesContent":["// Message types for communication between parent and child\nimport { createLogger } from \"../utils/logger.js\";\n\nenum MessageType {\n RESIZE = \"civic-iframe-resize\",\n READY = \"civic-iframe-ready\",\n}\n\ninterface IframeMessage {\n type: MessageType;\n height?: number;\n messageCount?: number;\n suggestedAnimationDuration?: number;\n}\n\nexport class CivicIframeResizer {\n private iframe: HTMLIFrameElement;\n private container: HTMLElement;\n private logger: ReturnType<typeof createLogger>;\n private messageListener: ((event: MessageEvent) => void) | null = null;\n private requestSizeTimeouts: number[] = [];\n\n constructor(iframe: HTMLIFrameElement, container: HTMLElement) {\n this.iframe = iframe;\n this.container = container;\n this.logger = createLogger(\"iframe\");\n\n this.initializeResizer();\n }\n\n private initializeResizer(): void {\n this.logger.debug(\"Initializing Civic iframe resizer\");\n\n // Set up message listener for iframe resize messages\n this.messageListener = (event: MessageEvent) => {\n this.handleMessage(event);\n };\n\n window.addEventListener(\"message\", this.messageListener);\n\n // Request size from child iframe after it loads\n this.iframe.addEventListener(\"load\", () => {\n this.logger.debug(\"Iframe loaded, requesting size from child\");\n this.requestSizeFromChild();\n\n // Schedule multiple size requests to ensure we get the correct height\n const intervals = [100, 500, 1000, 2000, 3000];\n intervals.forEach((interval) => {\n const timeoutId = window.setTimeout(() => {\n this.requestSizeFromChild();\n }, interval);\n this.requestSizeTimeouts.push(timeoutId);\n });\n });\n }\n\n private handleMessage(event: MessageEvent): void {\n try {\n const message = event.data as IframeMessage;\n\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 this.logger.debug(\"Received message from iframe:\", message);\n\n // Handle ready message\n if (message.type === MessageType.READY) {\n this.logger.debug(\"Iframe child is ready\");\n this.requestSizeFromChild();\n }\n\n // Handle resize message\n if (\n message.type === MessageType.RESIZE &&\n typeof message.height === \"number\"\n ) {\n this.logger.debug(\"Resizing iframe to height:\", message.height);\n this.resizeIframe(message.height, message.suggestedAnimationDuration);\n }\n } catch (error) {\n this.logger.debug(\"Error processing iframe message:\", error);\n }\n }\n\n private requestSizeFromChild(): void {\n if (this.iframe.contentWindow) {\n try {\n this.logger.debug(\"Requesting size from iframe child\");\n this.iframe.contentWindow.postMessage({ type: \"request-size\" }, \"*\");\n } catch (error) {\n this.logger.debug(\"Error requesting size from iframe:\", error);\n }\n }\n }\n\n private resizeIframe(height: number, animationDuration?: number): void {\n // Ensure minimum height\n const minHeight = 200;\n const finalHeight = Math.max(height, minHeight);\n\n // Apply height to iframe and ensure no overflow\n this.iframe.style.height = `${finalHeight}px`;\n this.iframe.style.maxHeight = `${finalHeight}px`;\n this.iframe.style.overflow = \"hidden\";\n this.iframe.style.overflowX = \"hidden\";\n this.iframe.style.overflowY = \"hidden\";\n\n // Apply transition if animation duration is suggested\n if (animationDuration) {\n this.iframe.style.transition = `height ${animationDuration}ms ease`;\n }\n\n // Try to inject additional CSS to prevent scrollbars after resize\n try {\n const iframeDoc =\n this.iframe.contentDocument || this.iframe.contentWindow?.document;\n if (iframeDoc && iframeDoc.body) {\n iframeDoc.body.style.overflow = \"hidden\";\n iframeDoc.body.style.overflowX = \"hidden\";\n iframeDoc.body.style.overflowY = \"hidden\";\n if (iframeDoc.documentElement) {\n iframeDoc.documentElement.style.overflow = \"hidden\";\n iframeDoc.documentElement.style.overflowX = \"hidden\";\n iframeDoc.documentElement.style.overflowY = \"hidden\";\n }\n }\n } catch (error) {\n this.logger.debug(\n \"Could not apply overflow styles to iframe content (likely cross-origin):\",\n error,\n );\n }\n\n this.logger.debug(`Iframe resized to ${finalHeight}px`);\n }\n\n public cleanup(): void {\n this.logger.debug(\"Cleaning up iframe resizer\");\n\n if (this.messageListener) {\n window.removeEventListener(\"message\", this.messageListener);\n this.messageListener = null;\n }\n\n // Clear any pending timeouts\n this.requestSizeTimeouts.forEach((timeoutId) => {\n window.clearTimeout(timeoutId);\n });\n this.requestSizeTimeouts = [];\n }\n\n public resize(): void {\n // Request size from child iframe\n this.requestSizeFromChild();\n }\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AuthenticationEvents } from "../auth/AuthenticationEvents.js";
|
|
2
|
+
import type { createLogger } from "../utils/logger.js";
|
|
3
|
+
import type { AuthResult } from "../types/index.js";
|
|
4
|
+
interface SignalObserverConfig {
|
|
5
|
+
textSignals: {
|
|
6
|
+
success: string;
|
|
7
|
+
error?: string;
|
|
8
|
+
};
|
|
9
|
+
events?: AuthenticationEvents;
|
|
10
|
+
logger: ReturnType<typeof createLogger>;
|
|
11
|
+
}
|
|
12
|
+
export declare class SignalObserver {
|
|
13
|
+
private config;
|
|
14
|
+
private observer?;
|
|
15
|
+
private authPromiseResolve?;
|
|
16
|
+
private authPromiseReject?;
|
|
17
|
+
private cleanupCallback?;
|
|
18
|
+
constructor(config: SignalObserverConfig, authPromiseResolve?: (value: AuthResult) => void, authPromiseReject?: (reason?: Error) => void, cleanupCallback?: () => void);
|
|
19
|
+
setup(iframeDoc: Document): void;
|
|
20
|
+
disconnect(): void;
|
|
21
|
+
private isRelevantMutation;
|
|
22
|
+
private handleSignalNodes;
|
|
23
|
+
private handleSuccessNode;
|
|
24
|
+
private handleErrorNode;
|
|
25
|
+
private handleBodyTextSignals;
|
|
26
|
+
private handleBodySuccessSignal;
|
|
27
|
+
private handleBodyErrorSignal;
|
|
28
|
+
private parseUserInfo;
|
|
29
|
+
private handleInitialSignals;
|
|
30
|
+
private cleanup;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=SignalObserver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignalObserver.d.ts","sourceRoot":"","sources":["../../../src/vanillajs/iframe/SignalObserver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAQ,MAAM,mBAAmB,CAAC;AAE1D,UAAU,oBAAoB;IAC5B,WAAW,EAAE;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;CACzC;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAC,CAAmB;IACpC,OAAO,CAAC,kBAAkB,CAAC,CAA8B;IACzD,OAAO,CAAC,iBAAiB,CAAC,CAA2B;IACrD,OAAO,CAAC,eAAe,CAAC,CAAa;gBAGnC,MAAM,EAAE,oBAAoB,EAC5B,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,EAChD,iBAAiB,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,KAAK,IAAI,EAC5C,eAAe,CAAC,EAAE,MAAM,IAAI;IAQvB,KAAK,CAAC,SAAS,EAAE,QAAQ,GAAG,IAAI;IA4BhC,UAAU,IAAI,IAAI;IAQzB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,qBAAqB;IAc7B,OAAO,CAAC,uBAAuB;IAoB/B,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,aAAa;IAsBrB,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,OAAO;CAIhB"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { AuthEvent } from "../types/index.js";
|
|
2
|
+
export class SignalObserver {
|
|
3
|
+
config;
|
|
4
|
+
observer;
|
|
5
|
+
authPromiseResolve;
|
|
6
|
+
authPromiseReject;
|
|
7
|
+
cleanupCallback;
|
|
8
|
+
constructor(config, authPromiseResolve, authPromiseReject, cleanupCallback) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.authPromiseResolve = authPromiseResolve;
|
|
11
|
+
this.authPromiseReject = authPromiseReject;
|
|
12
|
+
this.cleanupCallback = cleanupCallback;
|
|
13
|
+
}
|
|
14
|
+
setup(iframeDoc) {
|
|
15
|
+
this.config.logger.info("Setting up signal observer for iframe document");
|
|
16
|
+
this.observer = new MutationObserver((mutationsList) => {
|
|
17
|
+
for (const mutation of mutationsList) {
|
|
18
|
+
if (!this.isRelevantMutation(mutation)) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (this.handleSignalNodes(iframeDoc)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
this.handleBodyTextSignals(iframeDoc);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
this.config.logger.debug("Starting observation of iframe body");
|
|
28
|
+
this.observer.observe(iframeDoc.body, {
|
|
29
|
+
childList: true,
|
|
30
|
+
subtree: true,
|
|
31
|
+
characterData: true,
|
|
32
|
+
});
|
|
33
|
+
// Check for initial signals
|
|
34
|
+
this.handleInitialSignals(iframeDoc);
|
|
35
|
+
}
|
|
36
|
+
disconnect() {
|
|
37
|
+
if (this.observer) {
|
|
38
|
+
this.config.logger.debug("Disconnecting mutation observer");
|
|
39
|
+
this.observer.disconnect();
|
|
40
|
+
this.observer = undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
isRelevantMutation(mutation) {
|
|
44
|
+
return mutation.type === "childList" || mutation.type === "characterData";
|
|
45
|
+
}
|
|
46
|
+
handleSignalNodes(iframeDoc) {
|
|
47
|
+
const successNode = iframeDoc.getElementById("civic-auth-success-signal");
|
|
48
|
+
const errorNode = iframeDoc.getElementById("civic-auth-error-signal");
|
|
49
|
+
if (this.handleSuccessNode(successNode)) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
if (this.handleErrorNode(errorNode)) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
handleSuccessNode(successNode) {
|
|
58
|
+
if (successNode?.textContent !== this.config.textSignals.success) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
this.config.logger.info("Success signal detected in iframe by ID");
|
|
62
|
+
const userInfo = this.parseUserInfo(successNode);
|
|
63
|
+
this.config.events?.emit(AuthEvent.SIGN_IN_COMPLETE, {
|
|
64
|
+
detail: "Success signal detected in iframe",
|
|
65
|
+
user: userInfo,
|
|
66
|
+
});
|
|
67
|
+
this.authPromiseResolve?.({
|
|
68
|
+
user: userInfo,
|
|
69
|
+
signalText: successNode.textContent,
|
|
70
|
+
});
|
|
71
|
+
this.cleanup();
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
handleErrorNode(errorNode) {
|
|
75
|
+
if (!errorNode) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
this.config.logger.warn("Error signal detected in iframe by ID");
|
|
79
|
+
const errorMessage = errorNode.textContent || "Error signal detected in iframe";
|
|
80
|
+
this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {
|
|
81
|
+
detail: errorMessage,
|
|
82
|
+
});
|
|
83
|
+
this.authPromiseReject?.(new Error(errorMessage));
|
|
84
|
+
this.cleanup();
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
handleBodyTextSignals(iframeDoc) {
|
|
88
|
+
const bodyText = iframeDoc.body?.textContent || "";
|
|
89
|
+
this.config.logger.debug("Checking iframe body text for signals (fallback)", { bodyText });
|
|
90
|
+
if (this.handleBodySuccessSignal(bodyText)) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
this.handleBodyErrorSignal(bodyText);
|
|
94
|
+
}
|
|
95
|
+
handleBodySuccessSignal(bodyText) {
|
|
96
|
+
if (!bodyText.includes(this.config.textSignals.success)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
this.config.logger.info("Success signal detected in iframe by text content (fallback)");
|
|
100
|
+
this.config.events?.emit(AuthEvent.SIGN_IN_COMPLETE, {
|
|
101
|
+
detail: "Success signal detected in iframe (text fallback)",
|
|
102
|
+
});
|
|
103
|
+
this.authPromiseResolve?.({
|
|
104
|
+
signalText: this.config.textSignals.success,
|
|
105
|
+
});
|
|
106
|
+
this.cleanup();
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
handleBodyErrorSignal(bodyText) {
|
|
110
|
+
if (!this.config.textSignals.error ||
|
|
111
|
+
!bodyText.includes(this.config.textSignals.error)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
this.config.logger.warn("Error signal detected in iframe by text content (fallback)");
|
|
115
|
+
this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {
|
|
116
|
+
detail: this.config.textSignals.error,
|
|
117
|
+
});
|
|
118
|
+
this.authPromiseReject?.(new Error(this.config.textSignals.error));
|
|
119
|
+
this.cleanup();
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
parseUserInfo(node) {
|
|
123
|
+
const userInfoAttr = node.getAttribute("data-user-info");
|
|
124
|
+
if (!userInfoAttr) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const parsed = JSON.parse(userInfoAttr);
|
|
129
|
+
// Ensure we have at least an id field
|
|
130
|
+
if (!parsed.id || typeof parsed.id !== "string") {
|
|
131
|
+
this.config.logger.error("User info missing required 'id' field");
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
return parsed;
|
|
135
|
+
}
|
|
136
|
+
catch (parseError) {
|
|
137
|
+
this.config.logger.error("Failed to parse user info:", {
|
|
138
|
+
error: parseError,
|
|
139
|
+
});
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
handleInitialSignals(iframeDoc) {
|
|
144
|
+
const successNode = iframeDoc.getElementById("civic-auth-success-signal");
|
|
145
|
+
const errorNode = iframeDoc.getElementById("civic-auth-error-signal");
|
|
146
|
+
if (this.handleSuccessNode(successNode) ||
|
|
147
|
+
this.handleErrorNode(errorNode)) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const initialBodyText = iframeDoc.body?.textContent || "";
|
|
151
|
+
this.config.logger.debug("Performing initial signal check by text (fallback)", { initialBodyText });
|
|
152
|
+
if (this.handleBodySuccessSignal(initialBodyText) ||
|
|
153
|
+
this.handleBodyErrorSignal(initialBodyText)) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
cleanup() {
|
|
158
|
+
this.disconnect();
|
|
159
|
+
this.cleanupCallback?.();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=SignalObserver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignalObserver.js","sourceRoot":"","sources":["../../../src/vanillajs/iframe/SignalObserver.ts"],"names":[],"mappings":"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","sourcesContent":["import { AuthEvent } from \"../types/index.js\";\nimport type { AuthenticationEvents } from \"../auth/AuthenticationEvents.js\";\nimport type { createLogger } from \"../utils/logger.js\";\nimport type { AuthResult, User } from \"../types/index.js\";\n\ninterface SignalObserverConfig {\n textSignals: {\n success: string;\n error?: string;\n };\n events?: AuthenticationEvents;\n logger: ReturnType<typeof createLogger>;\n}\n\nexport class SignalObserver {\n private config: SignalObserverConfig;\n private observer?: MutationObserver;\n private authPromiseResolve?: (value: AuthResult) => void;\n private authPromiseReject?: (reason?: Error) => void;\n private cleanupCallback?: () => void;\n\n constructor(\n config: SignalObserverConfig,\n authPromiseResolve?: (value: AuthResult) => void,\n authPromiseReject?: (reason?: Error) => void,\n cleanupCallback?: () => void,\n ) {\n this.config = config;\n this.authPromiseResolve = authPromiseResolve;\n this.authPromiseReject = authPromiseReject;\n this.cleanupCallback = cleanupCallback;\n }\n\n public setup(iframeDoc: Document): void {\n this.config.logger.info(\"Setting up signal observer for iframe document\");\n\n this.observer = new MutationObserver((mutationsList) => {\n for (const mutation of mutationsList) {\n if (!this.isRelevantMutation(mutation)) {\n continue;\n }\n\n if (this.handleSignalNodes(iframeDoc)) {\n return;\n }\n\n this.handleBodyTextSignals(iframeDoc);\n }\n });\n\n this.config.logger.debug(\"Starting observation of iframe body\");\n this.observer.observe(iframeDoc.body, {\n childList: true,\n subtree: true,\n characterData: true,\n });\n\n // Check for initial signals\n this.handleInitialSignals(iframeDoc);\n }\n\n public disconnect(): void {\n if (this.observer) {\n this.config.logger.debug(\"Disconnecting mutation observer\");\n this.observer.disconnect();\n this.observer = undefined;\n }\n }\n\n private isRelevantMutation(mutation: MutationRecord): boolean {\n return mutation.type === \"childList\" || mutation.type === \"characterData\";\n }\n\n private handleSignalNodes(iframeDoc: Document): boolean {\n const successNode = iframeDoc.getElementById(\"civic-auth-success-signal\");\n const errorNode = iframeDoc.getElementById(\"civic-auth-error-signal\");\n\n if (this.handleSuccessNode(successNode)) {\n return true;\n }\n\n if (this.handleErrorNode(errorNode)) {\n return true;\n }\n\n return false;\n }\n\n private handleSuccessNode(successNode: HTMLElement | null): boolean {\n if (successNode?.textContent !== this.config.textSignals.success) {\n return false;\n }\n\n this.config.logger.info(\"Success signal detected in iframe by ID\");\n const userInfo = this.parseUserInfo(successNode);\n\n this.config.events?.emit(AuthEvent.SIGN_IN_COMPLETE, {\n detail: \"Success signal detected in iframe\",\n user: userInfo,\n });\n\n this.authPromiseResolve?.({\n user: userInfo,\n signalText: successNode.textContent,\n });\n\n this.cleanup();\n return true;\n }\n\n private handleErrorNode(errorNode: HTMLElement | null): boolean {\n if (!errorNode) {\n return false;\n }\n\n this.config.logger.warn(\"Error signal detected in iframe by ID\");\n const errorMessage =\n errorNode.textContent || \"Error signal detected in iframe\";\n\n this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: errorMessage,\n });\n\n this.authPromiseReject?.(new Error(errorMessage));\n this.cleanup();\n return true;\n }\n\n private handleBodyTextSignals(iframeDoc: Document): void {\n const bodyText = iframeDoc.body?.textContent || \"\";\n this.config.logger.debug(\n \"Checking iframe body text for signals (fallback)\",\n { bodyText },\n );\n\n if (this.handleBodySuccessSignal(bodyText)) {\n return;\n }\n\n this.handleBodyErrorSignal(bodyText);\n }\n\n private handleBodySuccessSignal(bodyText: string): boolean {\n if (!bodyText.includes(this.config.textSignals.success)) {\n return false;\n }\n\n this.config.logger.info(\n \"Success signal detected in iframe by text content (fallback)\",\n );\n this.config.events?.emit(AuthEvent.SIGN_IN_COMPLETE, {\n detail: \"Success signal detected in iframe (text fallback)\",\n });\n\n this.authPromiseResolve?.({\n signalText: this.config.textSignals.success,\n });\n\n this.cleanup();\n return true;\n }\n\n private handleBodyErrorSignal(bodyText: string): boolean {\n if (\n !this.config.textSignals.error ||\n !bodyText.includes(this.config.textSignals.error)\n ) {\n return false;\n }\n\n this.config.logger.warn(\n \"Error signal detected in iframe by text content (fallback)\",\n );\n this.config.events?.emit(AuthEvent.SIGN_IN_ERROR, {\n detail: this.config.textSignals.error,\n });\n\n this.authPromiseReject?.(new Error(this.config.textSignals.error));\n this.cleanup();\n return true;\n }\n\n private parseUserInfo(node: HTMLElement): User | undefined {\n const userInfoAttr = node.getAttribute(\"data-user-info\");\n if (!userInfoAttr) {\n return undefined;\n }\n\n try {\n const parsed = JSON.parse(userInfoAttr) as { [key: string]: unknown };\n // Ensure we have at least an id field\n if (!parsed.id || typeof parsed.id !== \"string\") {\n this.config.logger.error(\"User info missing required 'id' field\");\n return undefined;\n }\n return parsed as User;\n } catch (parseError) {\n this.config.logger.error(\"Failed to parse user info:\", {\n error: parseError,\n });\n return undefined;\n }\n }\n\n private handleInitialSignals(iframeDoc: Document): void {\n const successNode = iframeDoc.getElementById(\"civic-auth-success-signal\");\n const errorNode = iframeDoc.getElementById(\"civic-auth-error-signal\");\n\n if (\n this.handleSuccessNode(successNode) ||\n this.handleErrorNode(errorNode)\n ) {\n return;\n }\n\n const initialBodyText = iframeDoc.body?.textContent || \"\";\n this.config.logger.debug(\n \"Performing initial signal check by text (fallback)\",\n { initialBodyText },\n );\n\n if (\n this.handleBodySuccessSignal(initialBodyText) ||\n this.handleBodyErrorSignal(initialBodyText)\n ) {\n return;\n }\n }\n\n private cleanup(): void {\n this.disconnect();\n this.cleanupCallback?.();\n }\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from "./auth/AuthenticationEvents.js";
|
|
2
|
+
export * from "./auth/SessionManager.js";
|
|
3
|
+
export * from "./auth/TokenRefresher.js";
|
|
4
|
+
export * from "./types/index.js";
|
|
5
|
+
export * from "./services/ApiService.js";
|
|
6
|
+
export * from "./auth/CivicAuth.js";
|
|
7
|
+
export { AuthenticationEvents } from "./auth/AuthenticationEvents.js";
|
|
8
|
+
export { AuthEvent } from "./types/index.js";
|
|
9
|
+
export { handleOAuthRedirectPage, storeTokens, type HandleOAuthRedirectConfig, } from "./auth/OAuthCallbackHandler.js";
|
|
10
|
+
export { storeTokens as sharedStoreTokens, retrieveTokens, clearTokens, } from "../shared/lib/util.js";
|
|
11
|
+
export { getUser, getTokens, clearAuthCookies } from "../shared/lib/session.js";
|
|
12
|
+
export { LocalStorageAdapter } from "../browser/storage.js";
|
|
13
|
+
export { createShimmerLoader, createIframeShimmerLoader, createSkeletonLoader, createButtonContentLoader, createCloseIcon, createCloseButton, cleanupLoadingStyles, type ShimmerLoaderOptions, } from "./ui/LoadingComponents.js";
|
|
14
|
+
export { BrowserCookieStorage } from "../shared/lib/BrowserCookieStorage.js";
|
|
15
|
+
export type { AuthStorage } from "../types.js";
|
|
16
|
+
export type { User, Session } from "./types/index.js";
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vanillajs/index.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AAEpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EACL,uBAAuB,EACvB,WAAW,EACX,KAAK,yBAAyB,GAC/B,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,WAAW,IAAI,iBAAiB,EAChC,cAAc,EACd,WAAW,GACZ,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAGhF,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAG5D,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,oBAAoB,EACpB,yBAAyB,EACzB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,oBAAoB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAG7E,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export * from "./auth/AuthenticationEvents.js";
|
|
2
|
+
export * from "./auth/SessionManager.js";
|
|
3
|
+
export * from "./auth/TokenRefresher.js";
|
|
4
|
+
export * from "./types/index.js";
|
|
5
|
+
export * from "./services/ApiService.js";
|
|
6
|
+
export * from "./auth/CivicAuth.js";
|
|
7
|
+
export { AuthenticationEvents } from "./auth/AuthenticationEvents.js";
|
|
8
|
+
export { AuthEvent } from "./types/index.js";
|
|
9
|
+
export { handleOAuthRedirectPage, storeTokens, } from "./auth/OAuthCallbackHandler.js";
|
|
10
|
+
// Re-export shared utilities for convenience
|
|
11
|
+
export { storeTokens as sharedStoreTokens, retrieveTokens, clearTokens, } from "../shared/lib/util.js";
|
|
12
|
+
export { getUser, getTokens, clearAuthCookies } from "../shared/lib/session.js";
|
|
13
|
+
// Re-export shared storage adapters - these are the only storage implementations needed
|
|
14
|
+
export { LocalStorageAdapter } from "../browser/storage.js";
|
|
15
|
+
// Export UI components for loading states
|
|
16
|
+
export { createShimmerLoader, createIframeShimmerLoader, createSkeletonLoader, createButtonContentLoader, createCloseIcon, createCloseButton, cleanupLoadingStyles, } from "./ui/LoadingComponents.js";
|
|
17
|
+
export { BrowserCookieStorage } from "../shared/lib/BrowserCookieStorage.js";
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vanillajs/index.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AAEpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EACL,uBAAuB,EACvB,WAAW,GAEZ,MAAM,gCAAgC,CAAC;AAExC,6CAA6C;AAC7C,OAAO,EACL,WAAW,IAAI,iBAAiB,EAChC,cAAc,EACd,WAAW,GACZ,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEhF,wFAAwF;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,0CAA0C;AAC1C,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,oBAAoB,EACpB,yBAAyB,EACzB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,GAErB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC","sourcesContent":["export * from \"./auth/AuthenticationEvents.js\";\nexport * from \"./auth/SessionManager.js\";\nexport * from \"./auth/TokenRefresher.js\";\nexport * from \"./types/index.js\";\nexport * from \"./services/ApiService.js\";\nexport * from \"./auth/CivicAuth.js\";\n\nexport { AuthenticationEvents } from \"./auth/AuthenticationEvents.js\";\nexport { AuthEvent } from \"./types/index.js\";\nexport {\n handleOAuthRedirectPage,\n storeTokens,\n type HandleOAuthRedirectConfig,\n} from \"./auth/OAuthCallbackHandler.js\";\n\n// Re-export shared utilities for convenience\nexport {\n storeTokens as sharedStoreTokens,\n retrieveTokens,\n clearTokens,\n} from \"../shared/lib/util.js\";\nexport { getUser, getTokens, clearAuthCookies } from \"../shared/lib/session.js\";\n\n// Re-export shared storage adapters - these are the only storage implementations needed\nexport { LocalStorageAdapter } from \"../browser/storage.js\";\n\n// Export UI components for loading states\nexport {\n createShimmerLoader,\n createIframeShimmerLoader,\n createSkeletonLoader,\n createButtonContentLoader,\n createCloseIcon,\n createCloseButton,\n cleanupLoadingStyles,\n type ShimmerLoaderOptions,\n} from \"./ui/LoadingComponents.js\";\nexport { BrowserCookieStorage } from \"../shared/lib/BrowserCookieStorage.js\";\n\n// Re-export shared types\nexport type { AuthStorage } from \"../types.js\";\nexport type { User, Session } from \"./types/index.js\";\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface RequestOptions<TBody extends BodyInit | null = BodyInit | null> extends Omit<RequestInit, "body"> {
|
|
2
|
+
baseUrl?: string;
|
|
3
|
+
params?: Record<string, string>;
|
|
4
|
+
body?: TBody;
|
|
5
|
+
token?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* ApiService is a wrapper around the fetch API for making HTTP requests.
|
|
9
|
+
* It can be configured with a base URL and default headers.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ApiService {
|
|
12
|
+
private logger;
|
|
13
|
+
private defaultConfig;
|
|
14
|
+
constructor(defaultConfig?: Omit<RequestOptions, "body" | "params">);
|
|
15
|
+
request<TResponse, TBody extends BodyInit | null = BodyInit | null>(url: string, options?: RequestOptions<TBody>): Promise<TResponse>;
|
|
16
|
+
get<TResponse>(url: string, options?: Omit<RequestOptions<never>, "method" | "body">): Promise<TResponse>;
|
|
17
|
+
post<TResponse, TBody extends BodyInit | null = BodyInit | null>(url: string, options?: Omit<RequestOptions<TBody>, "method">): Promise<TResponse>;
|
|
18
|
+
put<TResponse, TBody extends BodyInit | null = BodyInit | null>(url: string, options?: Omit<RequestOptions<TBody>, "method">): Promise<TResponse>;
|
|
19
|
+
delete<TResponse>(url: string, options?: Omit<RequestOptions<never>, "method" | "body">): Promise<TResponse>;
|
|
20
|
+
patch<TResponse, TBody extends BodyInit | null = BodyInit | null>(url: string, options?: Omit<RequestOptions<TBody>, "method">): Promise<TResponse>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=ApiService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiService.d.ts","sourceRoot":"","sources":["../../../src/vanillajs/services/ApiService.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc,CAAC,KAAK,SAAS,QAAQ,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,CAC7E,SAAQ,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,aAAa,CAA0C;gBAEnD,aAAa,GAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,QAAQ,CAAM;IAUjE,OAAO,CAAC,SAAS,EAAE,KAAK,SAAS,QAAQ,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,EACtE,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,cAAc,CAAC,KAAK,CAAM,GAClC,OAAO,CAAC,SAAS,CAAC;IAwDrB,GAAG,CAAC,SAAS,EACX,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAM,GAC3D,OAAO,CAAC,SAAS,CAAC;IAIrB,IAAI,CAAC,SAAS,EAAE,KAAK,SAAS,QAAQ,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,EAC7D,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAM,GAClD,OAAO,CAAC,SAAS,CAAC;IAIrB,GAAG,CAAC,SAAS,EAAE,KAAK,SAAS,QAAQ,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,EAC5D,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAM,GAClD,OAAO,CAAC,SAAS,CAAC;IAIrB,MAAM,CAAC,SAAS,EACd,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAM,GAC3D,OAAO,CAAC,SAAS,CAAC;IAIrB,KAAK,CAAC,SAAS,EAAE,KAAK,SAAS,QAAQ,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,EAC9D,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAM,GAClD,OAAO,CAAC,SAAS,CAAC;CAGtB"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { getCurrentLogger } from "../utils/logger.js";
|
|
2
|
+
/**
|
|
3
|
+
* ApiService is a wrapper around the fetch API for making HTTP requests.
|
|
4
|
+
* It can be configured with a base URL and default headers.
|
|
5
|
+
*/
|
|
6
|
+
export class ApiService {
|
|
7
|
+
logger = getCurrentLogger();
|
|
8
|
+
defaultConfig;
|
|
9
|
+
constructor(defaultConfig = {}) {
|
|
10
|
+
this.defaultConfig = {
|
|
11
|
+
headers: {
|
|
12
|
+
"Content-Type": "application/json",
|
|
13
|
+
...defaultConfig.headers,
|
|
14
|
+
},
|
|
15
|
+
...defaultConfig,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
async request(url, options = {}) {
|
|
19
|
+
const { baseUrl, params, token, ...fetchOptions } = options;
|
|
20
|
+
// Construct full URL
|
|
21
|
+
let fullUrl = baseUrl ? `${baseUrl}${url}` : url;
|
|
22
|
+
if (params) {
|
|
23
|
+
const searchParams = new URLSearchParams();
|
|
24
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
25
|
+
searchParams.append(key, value);
|
|
26
|
+
});
|
|
27
|
+
fullUrl += `?${searchParams.toString()}`;
|
|
28
|
+
}
|
|
29
|
+
// Add authorization header if token is provided
|
|
30
|
+
if (token) {
|
|
31
|
+
fetchOptions.headers = {
|
|
32
|
+
...fetchOptions.headers,
|
|
33
|
+
Authorization: `Bearer ${token}`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Stringify body if it's an object
|
|
37
|
+
if (fetchOptions.body &&
|
|
38
|
+
typeof fetchOptions.body === "object" &&
|
|
39
|
+
!(fetchOptions.body instanceof FormData)) {
|
|
40
|
+
fetchOptions.body = JSON.stringify(fetchOptions.body);
|
|
41
|
+
fetchOptions.headers = {
|
|
42
|
+
...fetchOptions.headers,
|
|
43
|
+
"Content-Type": "application/json",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
this.logger.debug("Making API request", {
|
|
48
|
+
url: fullUrl,
|
|
49
|
+
options: fetchOptions,
|
|
50
|
+
});
|
|
51
|
+
const response = await fetch(fullUrl, fetchOptions);
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
const error = new Error(`HTTP error! status: ${response.status}`);
|
|
54
|
+
this.logger.error("API request failed", { error, response });
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
const data = await response.json();
|
|
58
|
+
this.logger.debug("API request successful", { data });
|
|
59
|
+
return data;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
this.logger.error("API request failed", { error, url: fullUrl });
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
get(url, options = {}) {
|
|
67
|
+
return this.request(url, { ...options, method: "GET" });
|
|
68
|
+
}
|
|
69
|
+
post(url, options = {}) {
|
|
70
|
+
return this.request(url, { ...options, method: "POST" });
|
|
71
|
+
}
|
|
72
|
+
put(url, options = {}) {
|
|
73
|
+
return this.request(url, { ...options, method: "PUT" });
|
|
74
|
+
}
|
|
75
|
+
delete(url, options = {}) {
|
|
76
|
+
return this.request(url, { ...options, method: "DELETE" });
|
|
77
|
+
}
|
|
78
|
+
patch(url, options = {}) {
|
|
79
|
+
return this.request(url, { ...options, method: "PATCH" });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=ApiService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiService.js","sourceRoot":"","sources":["../../../src/vanillajs/services/ApiService.ts"],"names":[],"mappings":"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","sourcesContent":["import { getCurrentLogger } from \"../utils/logger.js\";\n\nexport interface RequestOptions<TBody extends BodyInit | null = BodyInit | null>\n extends Omit<RequestInit, \"body\"> {\n baseUrl?: string;\n params?: Record<string, string>;\n body?: TBody; // Generic type for request body\n token?: string; // Optional bearer token\n}\n\n/**\n * ApiService is a wrapper around the fetch API for making HTTP requests.\n * It can be configured with a base URL and default headers.\n */\nexport class ApiService {\n private logger = getCurrentLogger();\n private defaultConfig: Omit<RequestOptions, \"body\" | \"params\">;\n\n constructor(defaultConfig: Omit<RequestOptions, \"body\" | \"params\"> = {}) {\n this.defaultConfig = {\n headers: {\n \"Content-Type\": \"application/json\",\n ...defaultConfig.headers,\n },\n ...defaultConfig,\n };\n }\n\n async request<TResponse, TBody extends BodyInit | null = BodyInit | null>(\n url: string,\n options: RequestOptions<TBody> = {},\n ): Promise<TResponse> {\n const { baseUrl, params, token, ...fetchOptions } = options;\n\n // Construct full URL\n let fullUrl = baseUrl ? `${baseUrl}${url}` : url;\n if (params) {\n const searchParams = new URLSearchParams();\n Object.entries(params).forEach(([key, value]) => {\n searchParams.append(key, value);\n });\n fullUrl += `?${searchParams.toString()}`;\n }\n\n // Add authorization header if token is provided\n if (token) {\n fetchOptions.headers = {\n ...fetchOptions.headers,\n Authorization: `Bearer ${token}`,\n };\n }\n\n // Stringify body if it's an object\n if (\n fetchOptions.body &&\n typeof fetchOptions.body === \"object\" &&\n !(fetchOptions.body instanceof FormData)\n ) {\n fetchOptions.body = JSON.stringify(fetchOptions.body) as TBody;\n fetchOptions.headers = {\n ...fetchOptions.headers,\n \"Content-Type\": \"application/json\",\n };\n }\n\n try {\n this.logger.debug(\"Making API request\", {\n url: fullUrl,\n options: fetchOptions,\n });\n const response = await fetch(fullUrl, fetchOptions as RequestInit);\n\n if (!response.ok) {\n const error = new Error(`HTTP error! status: ${response.status}`);\n this.logger.error(\"API request failed\", { error, response });\n throw error;\n }\n\n const data = await response.json();\n this.logger.debug(\"API request successful\", { data });\n return data as TResponse;\n } catch (error) {\n this.logger.error(\"API request failed\", { error, url: fullUrl });\n throw error;\n }\n }\n\n get<TResponse>(\n url: string,\n options: Omit<RequestOptions<never>, \"method\" | \"body\"> = {},\n ): Promise<TResponse> {\n return this.request<TResponse>(url, { ...options, method: \"GET\" });\n }\n\n post<TResponse, TBody extends BodyInit | null = BodyInit | null>(\n url: string,\n options: Omit<RequestOptions<TBody>, \"method\"> = {},\n ): Promise<TResponse> {\n return this.request<TResponse, TBody>(url, { ...options, method: \"POST\" });\n }\n\n put<TResponse, TBody extends BodyInit | null = BodyInit | null>(\n url: string,\n options: Omit<RequestOptions<TBody>, \"method\"> = {},\n ): Promise<TResponse> {\n return this.request<TResponse, TBody>(url, { ...options, method: \"PUT\" });\n }\n\n delete<TResponse>(\n url: string,\n options: Omit<RequestOptions<never>, \"method\" | \"body\"> = {},\n ): Promise<TResponse> {\n return this.request<TResponse>(url, { ...options, method: \"DELETE\" });\n }\n\n patch<TResponse, TBody extends BodyInit | null = BodyInit | null>(\n url: string,\n options: Omit<RequestOptions<TBody>, \"method\"> = {},\n ): Promise<TResponse> {\n return this.request<TResponse, TBody>(url, { ...options, method: \"PATCH\" });\n }\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { User } from "../../types.js";
|
|
2
|
+
export type { User };
|
|
3
|
+
export interface Session {
|
|
4
|
+
accessToken?: string;
|
|
5
|
+
idToken: string;
|
|
6
|
+
refreshToken?: string;
|
|
7
|
+
user?: User;
|
|
8
|
+
expiresAt?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare enum AuthEvent {
|
|
11
|
+
SIGN_IN_STARTED = "signInStarted",
|
|
12
|
+
SIGN_IN_COMPLETE = "signInComplete",
|
|
13
|
+
SIGN_IN_ERROR = "signInError",
|
|
14
|
+
SIGN_OUT_STARTED = "signOutStarted",
|
|
15
|
+
SIGN_OUT_COMPLETE = "signOutComplete",
|
|
16
|
+
SIGN_OUT_ERROR = "signOutError",
|
|
17
|
+
TOKEN_REFRESH_STARTED = "tokenRefreshStarted",
|
|
18
|
+
TOKEN_REFRESH_COMPLETE = "tokenRefreshComplete",
|
|
19
|
+
TOKEN_REFRESH_ERROR = "tokenRefreshError",
|
|
20
|
+
USER_SESSION_CHANGED = "userSessionChanged"
|
|
21
|
+
}
|
|
22
|
+
export interface AuthResult {
|
|
23
|
+
/** User information returned from authentication */
|
|
24
|
+
user?: User;
|
|
25
|
+
/** Signal text indicating the result */
|
|
26
|
+
signalText?: string;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/vanillajs/types/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAE3C,YAAY,EAAE,IAAI,EAAE,CAAC;AAErB,MAAM,WAAW,OAAO;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CAEpB;AAED,oBAAY,SAAS;IACnB,eAAe,kBAAkB;IACjC,gBAAgB,mBAAmB;IACnC,aAAa,gBAAgB;IAC7B,gBAAgB,mBAAmB;IACnC,iBAAiB,oBAAoB;IACrC,cAAc,iBAAiB;IAC/B,qBAAqB,wBAAwB;IAC7C,sBAAsB,yBAAyB;IAC/C,mBAAmB,sBAAsB;IACzC,oBAAoB,uBAAuB;CAC5C;AAED,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export var AuthEvent;
|
|
2
|
+
(function (AuthEvent) {
|
|
3
|
+
AuthEvent["SIGN_IN_STARTED"] = "signInStarted";
|
|
4
|
+
AuthEvent["SIGN_IN_COMPLETE"] = "signInComplete";
|
|
5
|
+
AuthEvent["SIGN_IN_ERROR"] = "signInError";
|
|
6
|
+
AuthEvent["SIGN_OUT_STARTED"] = "signOutStarted";
|
|
7
|
+
AuthEvent["SIGN_OUT_COMPLETE"] = "signOutComplete";
|
|
8
|
+
AuthEvent["SIGN_OUT_ERROR"] = "signOutError";
|
|
9
|
+
AuthEvent["TOKEN_REFRESH_STARTED"] = "tokenRefreshStarted";
|
|
10
|
+
AuthEvent["TOKEN_REFRESH_COMPLETE"] = "tokenRefreshComplete";
|
|
11
|
+
AuthEvent["TOKEN_REFRESH_ERROR"] = "tokenRefreshError";
|
|
12
|
+
AuthEvent["USER_SESSION_CHANGED"] = "userSessionChanged";
|
|
13
|
+
})(AuthEvent || (AuthEvent = {}));
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/vanillajs/types/index.ts"],"names":[],"mappings":"AAcA,MAAM,CAAN,IAAY,SAWX;AAXD,WAAY,SAAS;IACnB,8CAAiC,CAAA;IACjC,gDAAmC,CAAA;IACnC,0CAA6B,CAAA;IAC7B,gDAAmC,CAAA;IACnC,kDAAqC,CAAA;IACrC,4CAA+B,CAAA;IAC/B,0DAA6C,CAAA;IAC7C,4DAA+C,CAAA;IAC/C,sDAAyC,CAAA;IACzC,wDAA2C,CAAA;AAC7C,CAAC,EAXW,SAAS,KAAT,SAAS,QAWpB","sourcesContent":["// Export other type files as they are created\nimport type { User } from \"../../types.js\";\n\nexport type { User };\n\nexport interface Session {\n accessToken?: string;\n idToken: string;\n refreshToken?: string;\n user?: User;\n expiresAt?: number; // Timestamp in milliseconds\n // any other session-related data\n}\n\nexport enum AuthEvent {\n SIGN_IN_STARTED = \"signInStarted\",\n SIGN_IN_COMPLETE = \"signInComplete\",\n SIGN_IN_ERROR = \"signInError\",\n SIGN_OUT_STARTED = \"signOutStarted\",\n SIGN_OUT_COMPLETE = \"signOutComplete\",\n SIGN_OUT_ERROR = \"signOutError\",\n TOKEN_REFRESH_STARTED = \"tokenRefreshStarted\",\n TOKEN_REFRESH_COMPLETE = \"tokenRefreshComplete\",\n TOKEN_REFRESH_ERROR = \"tokenRefreshError\",\n USER_SESSION_CHANGED = \"userSessionChanged\",\n}\n\nexport interface AuthResult {\n /** User information returned from authentication */\n user?: User;\n /** Signal text indicating the result */\n signalText?: string;\n}\n"]}
|