@connect-xyz/auth-js 1.51.0 → 1.53.0
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/README.md +15 -0
- package/dist/index.d.ts +242 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -69,6 +69,9 @@ const auth = new Auth({
|
|
|
69
69
|
onEvent: ({ type, data }) => {
|
|
70
70
|
console.log('Event received:', type, data);
|
|
71
71
|
},
|
|
72
|
+
onLoaded: () => {
|
|
73
|
+
console.log('Auth widget loaded and ready');
|
|
74
|
+
},
|
|
72
75
|
});
|
|
73
76
|
|
|
74
77
|
// Render the widget to a container element
|
|
@@ -123,6 +126,7 @@ const auth = new Auth(config);
|
|
|
123
126
|
| `onClose` | `() => void` | No | - | Callback when the widget is closed |
|
|
124
127
|
| `onDeposit` | `({ data }) => void` | No | - | Callback for deposit received |
|
|
125
128
|
| `onEvent` | `({ type, data }) => void` | No | - | Callback for general events |
|
|
129
|
+
| `onLoaded` | `() => void` | No | - | Callback when the widget is loaded and ready |
|
|
126
130
|
|
|
127
131
|
### Constructor
|
|
128
132
|
|
|
@@ -142,6 +146,7 @@ Creates a new Auth instance with the provided configuration.
|
|
|
142
146
|
- `onClose` (function, optional): Close callback
|
|
143
147
|
- `onDeposit` (function, optional): Deposit callback
|
|
144
148
|
- `onEvent` (function, optional): General event callback
|
|
149
|
+
- `onLoaded` (function, optional): Callback when widget is loaded and ready
|
|
145
150
|
|
|
146
151
|
### Methods
|
|
147
152
|
|
|
@@ -237,6 +242,16 @@ onEvent: ({ type, data }) => {
|
|
|
237
242
|
};
|
|
238
243
|
```
|
|
239
244
|
|
|
245
|
+
### onLoaded
|
|
246
|
+
|
|
247
|
+
Called when the Auth widget has fully loaded and is ready for user interaction. This callback is useful for showing loading states or performing actions once the widget is initialized.
|
|
248
|
+
|
|
249
|
+
```javascript
|
|
250
|
+
onLoaded: () => {
|
|
251
|
+
// Widget is fully loaded and ready
|
|
252
|
+
};
|
|
253
|
+
```
|
|
254
|
+
|
|
240
255
|
## Browser Support
|
|
241
256
|
|
|
242
257
|
- Chrome/Edge 90+
|
package/dist/index.d.ts
CHANGED
|
@@ -94,8 +94,6 @@ export default Auth;
|
|
|
94
94
|
declare type AuthCallbacks = CommonCallbacks<AuthEvent> & {
|
|
95
95
|
/** Called when a deposit action occurs */
|
|
96
96
|
onDeposit?: (deposit: DepositCompletedPayload) => void;
|
|
97
|
-
/** Called when the Auth component has finished loading and is ready */
|
|
98
|
-
onLoaded?: () => void;
|
|
99
97
|
};
|
|
100
98
|
|
|
101
99
|
export declare interface AuthConfig extends BaseConfig<AuthEvent>, AuthCallbacks {
|
|
@@ -119,11 +117,13 @@ declare interface BaseConfig<TEvent = AppEvent> extends CommonCallbacks<TEvent>
|
|
|
119
117
|
* JWT token used for authentication
|
|
120
118
|
*/
|
|
121
119
|
jwt: string;
|
|
120
|
+
|
|
122
121
|
/**
|
|
123
122
|
* Target environment
|
|
124
123
|
* @default 'production'
|
|
125
124
|
*/
|
|
126
125
|
env?: Environment;
|
|
126
|
+
|
|
127
127
|
/**
|
|
128
128
|
* Theme mode
|
|
129
129
|
* @default 'auto'
|
|
@@ -136,54 +136,259 @@ declare interface BaseConfig<TEvent = AppEvent> extends CommonCallbacks<TEvent>
|
|
|
136
136
|
theme?: Theme;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
declare type BaseErrorMessageKeys =
|
|
139
|
+
declare type BaseErrorMessageKeys =
|
|
140
|
+
| 'ALREADY_RENDERED'
|
|
141
|
+
| 'NOT_RENDERED'
|
|
142
|
+
| 'INVALID_CONTAINER'
|
|
143
|
+
| 'SCRIPT_LOAD_FAILED'
|
|
144
|
+
| 'WEB_COMPONENT_NOT_DEFINED';
|
|
140
145
|
|
|
141
146
|
declare abstract class BaseJsSdk<Config extends BaseConfig<never> = BaseConfig> {
|
|
142
|
-
private config;
|
|
143
|
-
private state;
|
|
144
|
-
private scriptLoadingPromise
|
|
147
|
+
private config: Config;
|
|
148
|
+
private state: SdkState;
|
|
149
|
+
private scriptLoadingPromise?: Promise<void>;
|
|
150
|
+
|
|
145
151
|
protected abstract errorMessages: Record<BaseErrorMessageKeys, string>;
|
|
146
152
|
protected abstract scriptUrls: Record<string, string>;
|
|
147
153
|
protected abstract webComponentTag: string;
|
|
148
|
-
|
|
154
|
+
|
|
155
|
+
constructor(config: Config) {
|
|
156
|
+
if (!config.jwt || typeof config.jwt !== 'string') {
|
|
157
|
+
throw new Error(INVALID_JWT_ERROR_MESSAGE);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.config = {
|
|
161
|
+
...config,
|
|
162
|
+
env: config.env || DEFAULT_ENVIRONMENT,
|
|
163
|
+
theme: config.theme,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
this.state = {
|
|
167
|
+
initialized: false,
|
|
168
|
+
scriptLoaded: false,
|
|
169
|
+
container: null,
|
|
170
|
+
element: null,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
149
174
|
/**
|
|
150
175
|
* Render the widget to a container element
|
|
151
176
|
* @param container - The container element to render the widget into
|
|
152
177
|
* @returns Promise that resolves when the widget is rendered
|
|
153
178
|
*/
|
|
154
|
-
render(container: HTMLElement): Promise<void
|
|
179
|
+
async render(container: HTMLElement): Promise<void> {
|
|
180
|
+
// Validate container
|
|
181
|
+
if (!container || !(container instanceof HTMLElement)) {
|
|
182
|
+
throw new Error(this.errorMessages.INVALID_CONTAINER);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Check if already rendered
|
|
186
|
+
if (this.state.initialized) {
|
|
187
|
+
throw new Error(this.errorMessages.ALREADY_RENDERED);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
try {
|
|
191
|
+
// Ensure script is loaded
|
|
192
|
+
await this.ensureScriptLoaded();
|
|
193
|
+
|
|
194
|
+
// Create and append the web component
|
|
195
|
+
const element = this.createWebComponent();
|
|
196
|
+
|
|
197
|
+
// Clear the container and append the element
|
|
198
|
+
container.innerHTML = '';
|
|
199
|
+
container.appendChild(element);
|
|
200
|
+
|
|
201
|
+
// Update state
|
|
202
|
+
this.state.container = container;
|
|
203
|
+
this.state.element = element;
|
|
204
|
+
this.state.initialized = true;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
console.error('Failed to render widget:', error);
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
155
211
|
/**
|
|
156
212
|
* Update the configuration of the widget
|
|
157
213
|
* @param config - Partial configuration to update
|
|
158
214
|
* @returns void
|
|
159
215
|
*/
|
|
160
|
-
updateConfig(config: Partial<Config>): void
|
|
216
|
+
updateConfig(config: Partial<Config>): void {
|
|
217
|
+
if (!this.state.initialized || !this.state.element) {
|
|
218
|
+
throw new Error(this.errorMessages.NOT_RENDERED);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const element = this.state.element as SdkElement<Config>;
|
|
222
|
+
|
|
223
|
+
Object.entries(config).forEach(([key, value]) => {
|
|
224
|
+
if (value) {
|
|
225
|
+
this.config[key as keyof Config] = value;
|
|
226
|
+
element[key as keyof Config] = value;
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
161
231
|
/**
|
|
162
232
|
* Destroy the widget and clean up resources
|
|
163
233
|
*/
|
|
164
|
-
destroy(): void
|
|
234
|
+
destroy(): void {
|
|
235
|
+
if (!this.state.initialized) {
|
|
236
|
+
return; // Nothing to destroy
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Remove the element from the container
|
|
240
|
+
if (this.state.element && this.state.element.parentNode) {
|
|
241
|
+
this.state.element.parentNode.removeChild(this.state.element);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Clear the container
|
|
245
|
+
if (this.state.container) {
|
|
246
|
+
this.state.container.innerHTML = '';
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Reset state
|
|
250
|
+
this.state.container = null;
|
|
251
|
+
this.state.element = null;
|
|
252
|
+
this.state.initialized = false;
|
|
253
|
+
}
|
|
254
|
+
|
|
165
255
|
/**
|
|
166
256
|
* Check if the widget is currently rendered
|
|
167
257
|
* @returns True if the widget is rendered, false otherwise
|
|
168
258
|
*/
|
|
169
|
-
isRendered(): boolean
|
|
259
|
+
isRendered(): boolean {
|
|
260
|
+
return this.state.initialized;
|
|
261
|
+
}
|
|
262
|
+
|
|
170
263
|
/**
|
|
171
264
|
* Get the current configuration
|
|
172
265
|
* @returns The current configuration object
|
|
173
266
|
*/
|
|
174
|
-
getConfig(): Readonly<Config
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
private
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
267
|
+
getConfig(): Readonly<Config> {
|
|
268
|
+
return { ...this.config };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private getEnvironment(): Environment {
|
|
272
|
+
return this.config.env || DEFAULT_ENVIRONMENT;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
private getScriptId() {
|
|
276
|
+
return `${this.webComponentTag}-script-${this.getEnvironment()}`;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private isScriptLoaded() {
|
|
280
|
+
return !!document.getElementById(this.getScriptId());
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private getWebComponent() {
|
|
284
|
+
return customElements.get(this.webComponentTag);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
private getScriptUrl() {
|
|
288
|
+
// Support local development with Vite
|
|
289
|
+
if (typeof import.meta !== 'undefined' && import.meta.env?.['VITE_INTERNAL_BUILD'] === 'true') {
|
|
290
|
+
return import.meta.env['VITE_SCRIPT_URL'] || this.scriptUrls[this.getEnvironment()];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return this.scriptUrls[this.getEnvironment()];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
private async loadScript() {
|
|
297
|
+
if (this.isScriptLoaded()) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (this.scriptLoadingPromise) {
|
|
302
|
+
return this.scriptLoadingPromise;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
this.scriptLoadingPromise = new Promise<void>((resolve, reject) => {
|
|
306
|
+
const script = document.createElement('script');
|
|
307
|
+
script.id = this.getScriptId();
|
|
308
|
+
script.src = this.getScriptUrl();
|
|
309
|
+
script.type = 'module';
|
|
310
|
+
script.async = true;
|
|
311
|
+
|
|
312
|
+
script.onload = () => {
|
|
313
|
+
setTimeout(() => {
|
|
314
|
+
if (this.getWebComponent()) {
|
|
315
|
+
resolve();
|
|
316
|
+
} else {
|
|
317
|
+
reject(new Error(this.errorMessages.WEB_COMPONENT_NOT_DEFINED));
|
|
318
|
+
}
|
|
319
|
+
}, 0);
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
script.onerror = () => {
|
|
323
|
+
this.scriptLoadingPromise = undefined;
|
|
324
|
+
reject(new Error(`${this.errorMessages.SCRIPT_LOAD_FAILED} (${this.getEnvironment()})`));
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
document.head.appendChild(script);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
await this.scriptLoadingPromise;
|
|
332
|
+
} catch (error) {
|
|
333
|
+
this.scriptLoadingPromise = undefined;
|
|
334
|
+
throw error;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return this.scriptLoadingPromise;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private async waitForWebComponent(timeout = 5000) {
|
|
341
|
+
if (this.getWebComponent()) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return new Promise<void>((resolve, reject) => {
|
|
346
|
+
const timeoutId = setTimeout(() => {
|
|
347
|
+
reject(new Error(`Timeout waiting for ${this.webComponentTag} to be defined`));
|
|
348
|
+
}, timeout);
|
|
349
|
+
|
|
350
|
+
customElements
|
|
351
|
+
.whenDefined(this.webComponentTag)
|
|
352
|
+
.then(() => {
|
|
353
|
+
clearTimeout(timeoutId);
|
|
354
|
+
resolve();
|
|
355
|
+
})
|
|
356
|
+
.catch((error) => {
|
|
357
|
+
clearTimeout(timeoutId);
|
|
358
|
+
reject(error);
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
182
363
|
/**
|
|
183
364
|
* Load the web component script if not already loaded
|
|
184
365
|
*/
|
|
185
|
-
protected ensureScriptLoaded(): Promise<void
|
|
186
|
-
|
|
366
|
+
protected async ensureScriptLoaded(): Promise<void> {
|
|
367
|
+
if (this.state.scriptLoaded) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
try {
|
|
372
|
+
await this.loadScript();
|
|
373
|
+
await this.waitForWebComponent();
|
|
374
|
+
this.state.scriptLoaded = true;
|
|
375
|
+
} catch (error) {
|
|
376
|
+
console.error('Failed to load Connect script:', error);
|
|
377
|
+
throw error;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
private createWebComponent() {
|
|
382
|
+
const element = document.createElement(this.webComponentTag) as SdkElement<Config>;
|
|
383
|
+
|
|
384
|
+
Object.entries(this.config).forEach(([key, value]) => {
|
|
385
|
+
if (value) {
|
|
386
|
+
element[key as keyof Config] = value;
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
return element;
|
|
391
|
+
}
|
|
187
392
|
}
|
|
188
393
|
|
|
189
394
|
/**
|
|
@@ -197,6 +402,8 @@ declare type CommonCallbacks<TEvent = AppEvent> = {
|
|
|
197
402
|
onClose?: () => void;
|
|
198
403
|
/** Called when a general event occurs */
|
|
199
404
|
onEvent?: (event: TEvent) => void;
|
|
405
|
+
/** Called when the widget has loaded and is ready */
|
|
406
|
+
onLoaded?: () => void;
|
|
200
407
|
};
|
|
201
408
|
|
|
202
409
|
export declare type ConnectAuthElement = SdkElement<AuthConfig>;
|
|
@@ -284,6 +491,20 @@ declare type ErrorPayload = {
|
|
|
284
491
|
*/
|
|
285
492
|
declare type SdkElement<Config extends BaseConfig<never>> = HTMLElement & Config;
|
|
286
493
|
|
|
494
|
+
/**
|
|
495
|
+
* Internal state of the SDK
|
|
496
|
+
*/
|
|
497
|
+
declare interface SdkState {
|
|
498
|
+
/** Whether the SDK is initialized */
|
|
499
|
+
initialized: boolean;
|
|
500
|
+
/** Whether the web component script is loaded */
|
|
501
|
+
scriptLoaded: boolean;
|
|
502
|
+
/** The container element where the widget is rendered */
|
|
503
|
+
container: HTMLElement | null;
|
|
504
|
+
/** The web component element */
|
|
505
|
+
element: HTMLElement | null;
|
|
506
|
+
}
|
|
507
|
+
|
|
287
508
|
/**
|
|
288
509
|
* Theme configuration for the SDK
|
|
289
510
|
*
|