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