UNPKG

rws-js-client

Version:
304 lines (224 loc) 9.67 kB
import IRWSConfig from './interfaces/IRWSConfig'; import startClient from './run'; import RWSNotify from './types/RWSNotify'; import ConfigService, { ConfigServiceInstance } from './services/ConfigService'; import UtilsService, { UtilsServiceInstance } from './services/UtilsService'; import DOMService, { DOMServiceInstance, DOMOutputType } from './services/DOMService'; import ApiService, { ApiServiceInstance } from './services/ApiService'; import NotifyService, { NotifyServiceInstance } from './services/NotifyService'; import RoutingService, { RoutingServiceInstance } from './services/RoutingService'; import WSService, { WSServiceInstance } from './services/WSService'; import ServiceWorkerService, { ServiceWorkerServiceInstance } from './services/ServiceWorkerService'; import { IBackendRoute } from './services/ApiService'; import IRWSUser from './interfaces/IRWSUser'; import RWSWindow, { RWSWindowComponentEntry, RWSWindowComponentRegister, loadRWSRichWindow } from './interfaces/RWSWindow'; import { DI, Container } from "@microsoft/fast-foundation"; import { IFrontRoutes, _ROUTING_EVENT_NAME } from './services/RoutingService'; import RWSViewComponent, { IWithCompose } from './components/_component'; import { provideRWSDesignSystem } from './components/_design_system'; import RWSContainer from './components/_container'; interface IHotModule extends NodeModule { hot?: { accept(dependencies: string[], callback?: (updatedDependencies: string[]) => void): void; accept(dependency: string, callback?: () => void): void; accept(errHandler?: (err: Error) => void): void; dispose(callback: (data: any) => void): void; } } type RWSEventListener = (event: CustomEvent) => void; class RWSClient { private _container: Container; private user: IRWSUser = null; private config: IRWSConfig = { backendUrl: '', routes: {}, splitFileDir: '/', splitPrefix: 'rws' }; protected initCallback: () => Promise<void> = async () => { }; private isSetup = false; protected devStorage: { [key: string]: any } = {}; private cfgSetupListener: RWSEventListener = (event: CustomEvent<{ callId: string }>) => { console.log('Received custom event from web component:', event.detail); // this.broadcastConfigForViewComponents(); }; constructor( @ConfigService public appConfig: ConfigServiceInstance, @RoutingService public routingService: RoutingServiceInstance, @DOMService public domService: DOMServiceInstance, @UtilsService public utilsService: UtilsServiceInstance, @ApiService public apiService: ApiServiceInstance, @WSService public wsService: WSServiceInstance, @ServiceWorkerService public swService: ServiceWorkerServiceInstance, @NotifyService public notifyService: NotifyServiceInstance ) { this._container = RWSContainer(); this.user = this.getUser(); this.pushDataToServiceWorker('SET_WS_URL', { url: this.appConfig.get('wsUrl') }, 'ws_url'); if (this.user) { this.pushUserToServiceWorker({ ...this.user, instructor: false }); } } async setup(config: IRWSConfig = {}): Promise<IRWSConfig> { if (this.isSetup) { return this.config; } this.config = { ...this.config, ...config }; this.appConfig.mergeConfig(this.config); // this.on<IRWSConfig>('rws_cfg_call', this.cfgSetupListener); const hotModule: IHotModule = (module as IHotModule); if (hotModule.hot) { hotModule.hot.accept('./print.js', function () { console.log('Accepting the updated module!'); }); } if (this.appConfig.get('parted')) { await this.loadPartedComponents(); } this.isSetup = true; return this.config; } async start(config: IRWSConfig = {}): Promise<RWSClient> { this.config = { ...this.config, ...config }; if (!this.isSetup) { this.config = await this.setup(this.config); } if (Object.keys(config).length) { this.appConfig.mergeConfig(this.config); } console.log(this.isSetup, this.config, this.appConfig); if (this.config.user && !this.config.dontPushToSW) { this.pushUserToServiceWorker(this.user); } await startClient(this.appConfig, this.wsService, this.notifyService, this.routingService); await this.initCallback(); return this; } addRoutes(routes: IFrontRoutes) { this.config.routes = routes; } setNotifier(notifier: RWSNotify): RWSClient { this.notifyService.setNotifier(notifier); return this; } setDefaultLayout(DefaultLayout: any): RWSClient { this.config.defaultLayout = DefaultLayout; return this; } setBackendRoutes(routes: IBackendRoute[]): RWSClient { this.config.backendRoutes = routes; return this; } async onInit(callback: () => Promise<void>): Promise<RWSClient> { this.initCallback = callback; return this; } pushDataToServiceWorker(type: string, data: any, asset_type: string = 'data_push'): void { let tries = 0; const doIt: () => void = () => { try { this.swService.sendDataToServiceWorker(type, data, asset_type); } catch (e) { if (tries < 3) { setTimeout(() => { doIt(); }, 300) tries++; } } } doIt(); } pushUserToServiceWorker(userData: any) { this.setUser(userData); this.pushDataToServiceWorker('SET_USER', userData, 'logged_user'); } getUser(): IRWSUser { const localSaved = localStorage.getItem('the_rws_user'); if (!!localSaved) { this.setUser(JSON.parse(localSaved) as IRWSUser); } return this.user; } setUser(user: IRWSUser): RWSClient { if (!user || !user?.jwt_token) { console.warn('[RWS Client Warning]', 'Passed user is not valid', user); return this; } this.user = user; this.apiService.setToken(this.user.jwt_token); this.wsService.setUser(this.user); localStorage.setItem('the_rws_user', JSON.stringify(this.user)); return this; } getConfig(): ConfigServiceInstance { return this.appConfig; } on<T>(eventName: string, listener: RWSEventListener): void { document.addEventListener(eventName, (event: Event) => { listener(event as CustomEvent<T>); }); } setDevStorage(key: string, stuff: any): RWSClient { this.devStorage[key] = stuff; return this; } getDevStorage(key: string): any { return this.devStorage[key]; } registerToDI(): void { } async loadPartedComponents(): Promise<void> { this.assignClientToBrowser(); const componentParts: string[] = await this.apiService.get<string[]>(this.appConfig.get('splitFileDir') + '/rws_chunks_info.json'); const _all: Promise<string>[] = []; componentParts.forEach((componentName: string) => { const scriptUrl: string = this.appConfig.get('splitFileDir') + `/${this.appConfig.get('splitPrefix')}.${componentName}.js`; // Replace with the path to your script file const headers: any = {}; headers['Content-Type'] = 'application/javascript'; _all.push(this.apiService.pureGet(scriptUrl, { headers })); }); (await Promise.all(_all)).forEach((scriptCnt: string, key: number) => { const script: HTMLScriptElement = document.createElement('script'); script.textContent = scriptCnt; script.async = true script.type = 'text/javascript'; document.body.appendChild(script); console.log(`Appended ${componentParts[key]} component`); }); RWSClient.defineAllComponents(); } async onDOMLoad(): Promise<void> { return new Promise<void>((resolve) => { document.addEventListener('DOMContentLoaded', () => { resolve(); }); }); } assignClientToBrowser(): void { this.getBrowserObject().RWS.client = this; } enableRouting(): void { this.appConfig.mergeConfig({ routing_enabled: true }); } disableRouting(): void { this.appConfig.mergeConfig({ routing_enabled: false }); } private getBrowserObject(): RWSWindow { loadRWSRichWindow(); return window; } private broadcastConfigForViewComponents(): void { document.dispatchEvent(new CustomEvent<{ config: IRWSConfig }>('rws_cfg_broadcast', { detail: { config: this.appConfig.getData() } })); } static getDI(): typeof DI { return DI; } static defineAllComponents() { const richWindowComponents: RWSWindowComponentRegister = (window as Window & RWSWindow).RWS.components; // provideRWSDesignSystem().register(richWindowComponents[devStr].component); console.log(richWindowComponents); Object.keys(richWindowComponents).map(key => richWindowComponents[key].component).forEach((el: IWithCompose<RWSViewComponent>) => { el.define(el, el.definition); }); } } export default DI.createInterface<RWSClient>(x => x.singleton(RWSClient)); export { IHotModule, RWSClient as RWSClientInstance }