@imtbl/auth 2.10.7-alpha.3 → 2.10.7-alpha.4

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.
@@ -2,7 +2,7 @@ import { PopupOverlayOptions } from '../types';
2
2
  import { PASSPORT_OVERLAY_CLOSE_ID, PASSPORT_OVERLAY_TRY_AGAIN_ID } from './constants';
3
3
  import { addLink, getBlockedOverlay, getGenericOverlay } from './elements';
4
4
 
5
- export default class ConfirmationOverlay {
5
+ export default class LoginPopupOverlay {
6
6
  private disableGenericPopupOverlay: boolean;
7
7
 
8
8
  private disableBlockedPopupOverlay: boolean;
package/src/types.ts CHANGED
@@ -126,3 +126,33 @@ export type DirectLoginOptions = {
126
126
  marketingConsentStatus?: MarketingConsentStatus;
127
127
  email?: string;
128
128
  };
129
+
130
+ /**
131
+ * Extended login options with caching and silent login support
132
+ */
133
+ export type LoginOptions = {
134
+ /** If true, attempts to use cached session without user interaction */
135
+ useCachedSession?: boolean;
136
+ /** If true, attempts silent authentication (force token refresh) */
137
+ useSilentLogin?: boolean;
138
+ /** If true, uses redirect flow instead of popup flow */
139
+ useRedirectFlow?: boolean;
140
+ /** Direct login options (social provider, email, etc.) */
141
+ directLoginOptions?: DirectLoginOptions;
142
+ };
143
+
144
+ /**
145
+ * Authentication events emitted by the Auth class
146
+ */
147
+ export enum AuthEvents {
148
+ LOGGED_OUT = 'loggedOut',
149
+ LOGGED_IN = 'loggedIn',
150
+ }
151
+
152
+ /**
153
+ * Event map for typed event emitter
154
+ */
155
+ export interface AuthEventMap extends Record<string, any> {
156
+ [AuthEvents.LOGGED_OUT]: [];
157
+ [AuthEvents.LOGGED_IN]: [User];
158
+ }
@@ -0,0 +1,26 @@
1
+ import { EventEmitter } from 'events';
2
+
3
+ export default class TypedEventEmitter<TEvents extends Record<string, any>> {
4
+ private emitter = new EventEmitter();
5
+
6
+ emit<TEventName extends keyof TEvents & string>(
7
+ eventName: TEventName,
8
+ ...eventArg: TEvents[TEventName]
9
+ ) {
10
+ this.emitter.emit(eventName, ...(eventArg as []));
11
+ }
12
+
13
+ on<TEventName extends keyof TEvents & string>(
14
+ eventName: TEventName,
15
+ handler: (...eventArg: TEvents[TEventName]) => void,
16
+ ) {
17
+ this.emitter.on(eventName, handler as any);
18
+ }
19
+
20
+ removeListener<TEventName extends keyof TEvents & string>(
21
+ eventName: TEventName,
22
+ handler: (...eventArg: TEvents[TEventName]) => void,
23
+ ) {
24
+ this.emitter.removeListener(eventName, handler as any);
25
+ }
26
+ }
@@ -1,28 +0,0 @@
1
- import * as GeneratedClients from '@imtbl/generated-clients';
2
- import { ConfirmationResult } from './types';
3
- import { IAuthConfiguration } from '../config';
4
- export declare const CONFIRMATION_IFRAME_ID = "passport-confirm";
5
- export declare const CONFIRMATION_IFRAME_STYLE = "display: none; position: absolute;width:0px;height:0px;border:0;";
6
- type MessageHandler = (arg0: MessageEvent) => void;
7
- type MessageType = 'erc191' | 'eip712';
8
- export default class ConfirmationScreen {
9
- private config;
10
- private confirmationWindow;
11
- private popupOptions;
12
- private overlay;
13
- private overlayClosed;
14
- private timer;
15
- constructor(config: IAuthConfiguration);
16
- private getHref;
17
- requestConfirmation(transactionId: string, etherAddress: string, chainType: GeneratedClients.mr.TransactionApprovalRequestChainTypeEnum, chainId?: string): Promise<ConfirmationResult>;
18
- requestMessageConfirmation(messageID: string, etherAddress: string, messageType?: MessageType): Promise<ConfirmationResult>;
19
- showServiceUnavailable(): Promise<void>;
20
- loading(popupOptions?: {
21
- width: number;
22
- height: number;
23
- }): void;
24
- closeWindow(): void;
25
- showConfirmationScreen(href: string, messageHandler: MessageHandler, resolve: Function): void;
26
- private recreateConfirmationWindow;
27
- }
28
- export {};
@@ -1,3 +0,0 @@
1
- export { default as ConfirmationScreen } from './confirmation';
2
- export { default as EmbeddedLoginPrompt } from './embeddedLoginPrompt';
3
- export * from './types';
@@ -1,8 +0,0 @@
1
- export type PopUpProps = {
2
- url: string;
3
- title: string;
4
- width: number;
5
- height: number;
6
- query?: string;
7
- };
8
- export declare const openPopupCenter: ({ url, title, width, height, }: PopUpProps) => Window;
@@ -1,275 +0,0 @@
1
- import * as GeneratedClients from '@imtbl/generated-clients';
2
- import { trackError } from '@imtbl/metrics';
3
-
4
- import {
5
- ConfirmationResult,
6
- PASSPORT_CONFIRMATION_EVENT_TYPE,
7
- ConfirmationReceiveMessage,
8
- ConfirmationSendMessage,
9
- } from './types';
10
- import { openPopupCenter } from './popup';
11
- import { IAuthConfiguration } from '../config';
12
- import ConfirmationOverlay from '../overlay/confirmationOverlay';
13
-
14
- const CONFIRMATION_WINDOW_TITLE = 'Confirm this transaction';
15
- const CONFIRMATION_WINDOW_HEIGHT = 720;
16
- const CONFIRMATION_WINDOW_WIDTH = 480;
17
- const CONFIRMATION_WINDOW_CLOSED_POLLING_DURATION = 1000;
18
-
19
- export const CONFIRMATION_IFRAME_ID = 'passport-confirm';
20
- export const CONFIRMATION_IFRAME_STYLE = 'display: none; position: absolute;width:0px;height:0px;border:0;';
21
-
22
- type MessageHandler = (arg0: MessageEvent) => void;
23
-
24
- type MessageType = 'erc191' | 'eip712';
25
-
26
- export default class ConfirmationScreen {
27
- private config: IAuthConfiguration;
28
-
29
- private confirmationWindow: Window | undefined;
30
-
31
- private popupOptions: { width: number; height: number } | undefined;
32
-
33
- private overlay: ConfirmationOverlay | undefined;
34
-
35
- private overlayClosed: boolean;
36
-
37
- private timer: NodeJS.Timeout | undefined;
38
-
39
- constructor(config: IAuthConfiguration) {
40
- this.config = config;
41
- this.overlayClosed = false;
42
- }
43
-
44
- private getHref(relativePath: string, queryStringParams?: { [key: string]: any }) {
45
- let href = `${this.config.passportDomain}/transaction-confirmation/${relativePath}`;
46
-
47
- if (queryStringParams) {
48
- const queryString = queryStringParams
49
- ? Object.keys(queryStringParams)
50
- .map((key) => `${key}=${queryStringParams[key]}`)
51
- .join('&')
52
- : '';
53
-
54
- href = `${href}?${queryString}`;
55
- }
56
-
57
- return href;
58
- }
59
-
60
- requestConfirmation(
61
- transactionId: string,
62
- etherAddress: string,
63
- chainType: GeneratedClients.mr.TransactionApprovalRequestChainTypeEnum,
64
- chainId?: string,
65
- ): Promise<ConfirmationResult> {
66
- return new Promise((resolve, reject) => {
67
- const messageHandler = ({ data, origin }: MessageEvent) => {
68
- if (
69
- origin !== this.config.passportDomain
70
- || data.eventType !== PASSPORT_CONFIRMATION_EVENT_TYPE
71
- ) {
72
- return;
73
- }
74
-
75
- switch (data.messageType as ConfirmationReceiveMessage) {
76
- case ConfirmationReceiveMessage.CONFIRMATION_WINDOW_READY: {
77
- this.confirmationWindow?.postMessage({
78
- eventType: PASSPORT_CONFIRMATION_EVENT_TYPE,
79
- messageType: ConfirmationSendMessage.CONFIRMATION_START,
80
- }, this.config.passportDomain);
81
- break;
82
- }
83
- case ConfirmationReceiveMessage.TRANSACTION_CONFIRMED: {
84
- this.closeWindow();
85
- resolve({ confirmed: true });
86
- break;
87
- }
88
- case ConfirmationReceiveMessage.TRANSACTION_REJECTED: {
89
- this.closeWindow();
90
- resolve({ confirmed: false });
91
- break;
92
- }
93
- case ConfirmationReceiveMessage.TRANSACTION_ERROR: {
94
- this.closeWindow();
95
- reject(new Error('Error during transaction confirmation'));
96
- break;
97
- }
98
- default:
99
- this.closeWindow();
100
- reject(new Error('Unsupported message type'));
101
- }
102
- };
103
-
104
- let href = '';
105
- if (chainType === GeneratedClients.mr.TransactionApprovalRequestChainTypeEnum.Starkex) {
106
- href = this.getHref('transaction', { transactionId, etherAddress, chainType });
107
- } else {
108
- href = this.getHref('zkevm/transaction', {
109
- transactionID: transactionId, etherAddress, chainType, chainID: chainId,
110
- });
111
- }
112
- window.addEventListener('message', messageHandler);
113
- this.showConfirmationScreen(href, messageHandler, resolve);
114
- });
115
- }
116
-
117
- requestMessageConfirmation(
118
- messageID: string,
119
- etherAddress: string,
120
- messageType?: MessageType,
121
- ): Promise<ConfirmationResult> {
122
- return new Promise((resolve, reject) => {
123
- const messageHandler = ({ data, origin }: MessageEvent) => {
124
- if (
125
- origin !== this.config.passportDomain
126
- || data.eventType !== PASSPORT_CONFIRMATION_EVENT_TYPE
127
- ) {
128
- return;
129
- }
130
- switch (data.messageType as ConfirmationReceiveMessage) {
131
- case ConfirmationReceiveMessage.CONFIRMATION_WINDOW_READY: {
132
- this.confirmationWindow?.postMessage({
133
- eventType: PASSPORT_CONFIRMATION_EVENT_TYPE,
134
- messageType: ConfirmationSendMessage.CONFIRMATION_START,
135
- }, this.config.passportDomain);
136
- break;
137
- }
138
- case ConfirmationReceiveMessage.MESSAGE_CONFIRMED: {
139
- this.closeWindow();
140
- resolve({ confirmed: true });
141
- break;
142
- }
143
- case ConfirmationReceiveMessage.MESSAGE_REJECTED: {
144
- this.closeWindow();
145
- resolve({ confirmed: false });
146
- break;
147
- }
148
- case ConfirmationReceiveMessage.MESSAGE_ERROR: {
149
- this.closeWindow();
150
- reject(new Error('Error during message confirmation'));
151
- break;
152
- }
153
- default:
154
- this.closeWindow();
155
- reject(new Error('Unsupported message type'));
156
- }
157
- };
158
-
159
- window.addEventListener('message', messageHandler);
160
- const href = this.getHref('zkevm/message', {
161
- messageID,
162
- etherAddress,
163
- ...(messageType ? { messageType } : {}),
164
- });
165
- this.showConfirmationScreen(href, messageHandler, resolve);
166
- });
167
- }
168
-
169
- showServiceUnavailable(): Promise<void> {
170
- return new Promise((_, reject) => {
171
- this.showConfirmationScreen(
172
- this.getHref('unavailable'),
173
- () => {},
174
- () => {
175
- this.closeWindow();
176
- reject(new Error('Service unavailable'));
177
- },
178
- );
179
- });
180
- }
181
-
182
- loading(popupOptions?: { width: number; height: number }) {
183
- if (this.config.crossSdkBridgeEnabled) {
184
- // There is no need to open a confirmation window if cross-sdk bridge is enabled
185
- return;
186
- }
187
-
188
- this.popupOptions = popupOptions;
189
-
190
- try {
191
- this.confirmationWindow = openPopupCenter({
192
- url: this.getHref('loading'),
193
- title: CONFIRMATION_WINDOW_TITLE,
194
- width: popupOptions?.width || CONFIRMATION_WINDOW_WIDTH,
195
- height: popupOptions?.height || CONFIRMATION_WINDOW_HEIGHT,
196
- });
197
- this.overlay = new ConfirmationOverlay(this.config.popupOverlayOptions || {});
198
- } catch (error) {
199
- // If an error is thrown here then the popup is blocked
200
- const errorMessage = error instanceof Error ? error.message : String(error);
201
- trackError('passport', 'confirmationPopupDenied', new Error(errorMessage));
202
- this.overlay = new ConfirmationOverlay(this.config.popupOverlayOptions || {}, true);
203
- }
204
-
205
- this.overlay.append(
206
- () => {
207
- try {
208
- this.confirmationWindow?.close();
209
- this.confirmationWindow = openPopupCenter({
210
- url: this.getHref('loading'),
211
- title: CONFIRMATION_WINDOW_TITLE,
212
- width: this.popupOptions?.width || CONFIRMATION_WINDOW_WIDTH,
213
- height: this.popupOptions?.height || CONFIRMATION_WINDOW_HEIGHT,
214
- });
215
- } catch { /* Empty */ }
216
- },
217
- () => {
218
- this.overlayClosed = true;
219
- this.closeWindow();
220
- },
221
- );
222
- }
223
-
224
- closeWindow() {
225
- this.confirmationWindow?.close();
226
- this.overlay?.remove();
227
- this.overlay = undefined;
228
- }
229
-
230
- showConfirmationScreen(href: string, messageHandler: MessageHandler, resolve: Function) {
231
- // If popup blocked, the confirmation window will not exist
232
- if (this.confirmationWindow) {
233
- this.confirmationWindow.location.href = href;
234
- }
235
-
236
- // This indicates the user closed the overlay so the transaction should be rejected
237
- if (!this.overlay) {
238
- this.overlayClosed = false;
239
- resolve({ confirmed: false });
240
- return;
241
- }
242
-
243
- // https://stackoverflow.com/questions/9388380/capture-the-close-event-of-popup-window-in-javascript/48240128#48240128
244
- const timerCallback = () => {
245
- if (this.confirmationWindow?.closed || this.overlayClosed) {
246
- clearInterval(this.timer);
247
- window.removeEventListener('message', messageHandler);
248
- resolve({ confirmed: false });
249
- this.overlayClosed = false;
250
- this.confirmationWindow = undefined;
251
- }
252
- };
253
- this.timer = setInterval(
254
- timerCallback,
255
- CONFIRMATION_WINDOW_CLOSED_POLLING_DURATION,
256
- );
257
- this.overlay.update(() => this.recreateConfirmationWindow(href, timerCallback));
258
- }
259
-
260
- private recreateConfirmationWindow(href: string, timerCallback: () => void) {
261
- try {
262
- // Clears and recreates the timer to ensure when the confirmation window
263
- // is closed and recreated the transaction is not rejected.
264
- clearInterval(this.timer);
265
- this.confirmationWindow?.close();
266
- this.confirmationWindow = openPopupCenter({
267
- url: href,
268
- title: CONFIRMATION_WINDOW_TITLE,
269
- width: this.popupOptions?.width || CONFIRMATION_WINDOW_WIDTH,
270
- height: this.popupOptions?.height || CONFIRMATION_WINDOW_HEIGHT,
271
- });
272
- this.timer = setInterval(timerCallback, CONFIRMATION_WINDOW_CLOSED_POLLING_DURATION);
273
- } catch { /* Empty */ }
274
- }
275
- }
@@ -1,3 +0,0 @@
1
- export { default as ConfirmationScreen } from './confirmation';
2
- export { default as EmbeddedLoginPrompt } from './embeddedLoginPrompt';
3
- export * from './types';
@@ -1,41 +0,0 @@
1
- export type PopUpProps = {
2
- url: string;
3
- title: string;
4
- width: number;
5
- height: number;
6
- query?: string;
7
- };
8
-
9
- export const openPopupCenter = ({
10
- url,
11
- title,
12
- width,
13
- height,
14
- }: PopUpProps): Window => {
15
- const left = Math.max(
16
- 0,
17
- Math.round(window.screenX + (window.outerWidth - width) / 2),
18
- );
19
- const top = Math.max(
20
- 0,
21
- Math.round(window.screenY + (window.outerHeight - height) / 2),
22
- );
23
-
24
- const newWindow = window.open(
25
- url,
26
- title,
27
- `
28
- scrollbars=yes,
29
- width=${width},
30
- height=${height},
31
- top=${top},
32
- left=${left}
33
- `,
34
- );
35
- if (!newWindow) {
36
- throw new Error('Failed to open confirmation screen');
37
- }
38
-
39
- newWindow.focus();
40
- return newWindow;
41
- };
File without changes
File without changes