{"version":3,"sources":["../../../packages/core/manifest/manifest-loader.ts"],"names":[],"mappings":"AAWA;;;GAGG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAoB;IACzD,OAAO,CAAC,MAAM,CAAC,UAAU,CAAgB;IACzC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAmB;IAC9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAwB;IAC/C,OAAO,CAAC,MAAM,CAAC,cAAc,CAAkD;IAE/E;;OAEG;IACH,IAAW,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjC;IAED;;OAEG;WACW,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC3C;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,IAAI;IAyFnB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IA2CnC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAkCrC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,MAAM;CAsBxB","file":"manifest-loader.d.ts","sourcesContent":["import { forkJoin, Observable, of } from 'rxjs';\r\nimport { catchError, map, mergeMap } from 'rxjs/operators';\r\nimport { ErrorExtended } from '../data/error-extended';\r\nimport { NativeQ } from '../data/native-q';\r\nimport { LogLevel } from '../diagnostics/log-level';\r\nimport { LogRecord } from '../diagnostics/log-record';\r\nimport { Logging } from '../diagnostics/logging';\r\nimport { HostCoreManager, HostCoreTokenMode } from '../host/host-core-manager';\r\nimport { SignedHttpRequestToken } from '../security/sign-on-manager';\r\nimport { EnvironmentModule } from './environment-modules';\r\n\r\n/**\r\n * The Manifest service class.\r\n *  (Localized string cannot be used in this class due to initialization phase when the strings are not ready yet.)\r\n */\r\nexport class ManifestLoader {\r\n    private static readonly logSourceName = 'ManifestLoader';\r\n    private static gatewayUrl = 'gatewayUrl';\r\n    private static manifestFile = 'manifest.json';\r\n    private static deferred = NativeQ.defer<any>();\r\n    private static internalLoaded: Promise<void> = ManifestLoader.deferred.promise;\r\n\r\n    /**\r\n     * Manifest loading promise.\r\n     */\r\n    public get loaded(): Promise<void> {\r\n        return ManifestLoader.internalLoaded;\r\n    }\r\n\r\n    /**\r\n     * Load the manifest.\r\n     */\r\n    public static loadManifest(): Promise<void> {\r\n        const self = MsftSme.self();\r\n        const mode: MsftSme.EnvironmentMode = self.Init ? self.Init.mode : MsftSme.EnvironmentMode.NotUse;\r\n        const hostCoreManager = new HostCoreManager();\r\n        switch (mode) {\r\n            case MsftSme.EnvironmentMode.NotUse:\r\n                // Turn OFF iframe feature.\r\n                ManifestLoader.deferred.reject('no iFrame');\r\n                break;\r\n            case MsftSme.EnvironmentMode.LoadEmbedded:\r\n                // JSON file posting by module iframe.\r\n                const manifest: any = {\r\n                    name: self.Init.moduleName,\r\n                    version: self.Init.moduleVersion,\r\n                    signature: EnvironmentModule.defaultSignature,\r\n                    shell: {\r\n                        name: EnvironmentModule.nameOfShell,\r\n                        origin: self.Init.shellOrigin\r\n                    }\r\n                };\r\n\r\n                // Turn ON module self-loading.\r\n                ManifestLoader.load(hostCoreManager, manifest);\r\n                break;\r\n            case MsftSme.EnvironmentMode.Load:\r\n                // Turn ON iframe feature by Shell and Module.\r\n                ManifestLoader.load(hostCoreManager);\r\n                break;\r\n        }\r\n\r\n        return ManifestLoader.internalLoaded;\r\n    }\r\n\r\n    /**\r\n     * Load the manifest into the MsftSme.Environment.\r\n     *\r\n     * @param hostCoreManager the hostCoreManager object to load the manifest.\r\n     * @param manifest the self loading manifest.\r\n     * @return Promise<any> the promise object.\r\n     */\r\n    private static load(hostCoreManager: HostCoreManager, manifest?: any): Promise<any> {\r\n        if (manifest) {\r\n            ManifestLoader.update(manifest, null);\r\n            return ManifestLoader.internalLoaded;\r\n        }\r\n\r\n        const gatewayUrlParam = MsftSme.getLocationSearchParameter(ManifestLoader.gatewayUrl);\r\n        let manifestUrl = ManifestLoader.manifestFile;\r\n        if (gatewayUrlParam && MsftSme.self().Init.isProduction && Object.keys(MsftSme.sideLoad()).length === 0) {\r\n            // use the gateway endpoint for manifest source.\r\n            manifestUrl = `${gatewayUrlParam.value}/${ManifestLoader.manifestFile}`;\r\n        }\r\n\r\n        hostCoreManager.httpGet(manifestUrl)\r\n            .pipe(\r\n                mergeMap(result => ManifestLoader.mergeGatewayManifest(hostCoreManager, result.response)),\r\n                mergeMap(\r\n                    shellManifest => {\r\n                        const response = shellManifest;\r\n                        if (response.modules) {\r\n                            return ManifestLoader.fetchSideloadManifests(hostCoreManager)\r\n                                .pipe(\r\n                                    map(sideLoads => {\r\n                                        const sideloadShellOrigins: string[] = [];\r\n\r\n                                        sideLoads = sideLoads.filter(s => {\r\n                                            if (MsftSme.isNullOrUndefined(s)) {\r\n                                                return false;\r\n                                            }\r\n\r\n                                            const isShell = s.name === EnvironmentModule.nameOfShell;\r\n                                            if (isShell) {\r\n                                                sideloadShellOrigins.push(s.origin);\r\n                                            }\r\n                                            return !isShell;\r\n                                        });\r\n\r\n                                        if (sideloadShellOrigins.length > 0) {\r\n                                            Logging.log(<LogRecord>{\r\n                                                source: ManifestLoader.logSourceName,\r\n                                                level: LogLevel.Warning,\r\n                                                consoleGroupHeader: `Unable to sideload: \"${sideloadShellOrigins}\".`,\r\n                                                message: `Cannot sideload ${EnvironmentModule.nameOfShell} from ${sideloadShellOrigins}.\r\n                                                    Did you mean to run ${EnvironmentModule.nameOfShell} locally?`\r\n                                            });\r\n                                        }\r\n                                        return { manifest: response, sideLoads: sideLoads };\r\n                                    }));\r\n                        }\r\n\r\n                        return of({ manifest: response, sideLoads: [] });\r\n                    })\r\n            )\r\n            .subscribe({\r\n                next: result => {\r\n                    const manifestResult = <MsftSme.MsftSmeEnvironment>result.manifest;\r\n                    const modules = manifestResult.modules;\r\n                    const selfInit = MsftSme.self().Init;\r\n                    selfInit.shellVersion = manifestResult.version;\r\n                    selfInit.gatewayApiVersion = manifestResult.gatewayApiVersion;\r\n                    selfInit.gatewayPlatform = manifestResult.gatewayPlatform;\r\n                    result.sideLoads.forEach(sideLoad => {\r\n                        if (sideLoad) {\r\n                            sideLoad.isSideLoaded = true;\r\n                            const foundIndex = modules.findIndex((item) => item.name === sideLoad.name);\r\n                            if (foundIndex >= 0) {\r\n                                modules.splice(foundIndex, 1, sideLoad);\r\n                            } else {\r\n                                modules.push(sideLoad);\r\n                            }\r\n                        }\r\n                    });\r\n\r\n                    ManifestLoader.update(result.manifest, hostCoreManager.token);\r\n                },\r\n                error: error => {\r\n                    // communicate main.ts for error message.\r\n                    const extendedError = <ErrorExtended<any>>error;\r\n                    if (hostCoreManager.tokenMode === HostCoreTokenMode.Aad) {\r\n                        extendedError.extendedSource = ErrorExtended.sources.aadSso;\r\n                    }\r\n\r\n                    ManifestLoader.deferred.reject(error);\r\n                }\r\n            });\r\n\r\n        return ManifestLoader.internalLoaded;\r\n    }\r\n\r\n    /**\r\n     * Merges the GatewayUrl manifest with the passed in shell manifest\r\n     * Merges modules only at this time with a preference for modules included in the shell\r\n     */\r\n    private static mergeGatewayManifest(hostCoreManager: HostCoreManager, shellManifest: any): Observable<any> {\r\n        // it's production mode and no side-loading omits calling manifest.json again.\r\n        if (MsftSme.self().Init.isProduction && Object.keys(MsftSme.sideLoad()).length === 0) {\r\n            return of(shellManifest);\r\n        }\r\n\r\n        const gatewayUrlParam = MsftSme.getLocationSearchParameter(ManifestLoader.gatewayUrl);\r\n        if (!gatewayUrlParam) {\r\n            return of(shellManifest);\r\n        }\r\n\r\n        return hostCoreManager.getNoCache(`${gatewayUrlParam.value}/${ManifestLoader.manifestFile}`, false, 'json')\r\n            .pipe(\r\n                map(result => {\r\n                    const gatewayManifest = result.response;\r\n                    if (Array.isArray(gatewayManifest.modules)) {\r\n                        if (!Array.isArray(shellManifest.modules)) {\r\n                            shellManifest.modules = gatewayManifest.modules;\r\n                        } else {\r\n                            gatewayManifest.modules.forEach(mod => {\r\n                                mod.origin = gatewayUrlParam.value;\r\n                                const foundIndex = shellManifest.modules.findIndex((item) => item.name === mod.name);\r\n                                if (foundIndex === -1) {\r\n                                    shellManifest.modules.push(mod);\r\n                                }\r\n                            });\r\n                        }\r\n                    }\r\n                    return shellManifest;\r\n                }),\r\n                catchError(() => {\r\n                    // no localization\r\n                    Logging.log(<LogRecord>{\r\n                        source: ManifestLoader.logSourceName,\r\n                        level: LogLevel.Warning,\r\n                        consoleGroupHeader: `Unable to load gateway manifest: \"${gatewayUrlParam.value}\".`,\r\n                        message: `Cannot load ${gatewayUrlParam.value}. Please make sure that a manifest.json is available at this location.`\r\n                    });\r\n                    return of(shellManifest);\r\n                })\r\n            );\r\n    }\r\n\r\n    /**\r\n     * retrieves all of the side loaded manifests.\r\n     *\r\n     * @return Observable<any[]> the manifests.\r\n     */\r\n    private static fetchSideloadManifests(hostCoreManager: HostCoreManager): Observable<any[]> {\r\n        const sideLoadList = MsftSme.sideLoad();\r\n        if (Object.keys(sideLoadList).length === 0) {\r\n            return of([]);\r\n        }\r\n\r\n        const sideLoadManifestAwaiters: Observable<any>[] = [];\r\n        MsftSme.forEachKey<MsftSme.SideLoad>(sideLoadList, (key, sideLoad) => {\r\n            sideLoadManifestAwaiters.push(\r\n                // don't send credentials when debugging a side-loading module.\r\n                hostCoreManager.getNoCache(`${sideLoad.origin}/${ManifestLoader.manifestFile}`, false, 'json', false)\r\n                    .pipe(\r\n                        map(result => {\r\n                            const manifest = result.response;\r\n                            manifest.origin = sideLoad.origin;\r\n                            return manifest;\r\n                        }),\r\n                        catchError(() => {\r\n                            // no localization\r\n                            Logging.log(<LogRecord>{\r\n                                source: ManifestLoader.logSourceName,\r\n                                level: LogLevel.Warning,\r\n                                consoleGroupHeader: `Unable to sideload: \"${sideLoad.origin}\".`,\r\n                                message: `Cannot sideload ${sideLoad.origin}. Please make sure that an extension is running at this origin.`\r\n                            });\r\n                            return of(null);\r\n                        })\r\n                    )\r\n            );\r\n        });\r\n\r\n        return forkJoin(sideLoadManifestAwaiters);\r\n    }\r\n\r\n    /**\r\n     * Update the environment by the manifest.\r\n     */\r\n    private static update(manifest: any, token: SignedHttpRequestToken): void {\r\n        try {\r\n            const self = MsftSme.self();\r\n            if (token) {\r\n                // store the last token if exists.\r\n                if (!manifest.configuration) {\r\n                    manifest.configuration = {};\r\n                }\r\n\r\n                // passed the signOn objec to GatewayConnection object to configure into the SignOnManager.\r\n                manifest.configuration.signOn = { signedHttpRequestToken: token };\r\n            }\r\n\r\n            self.Environment = EnvironmentModule.createEnvironment(manifest, self.Resources.localeId);\r\n            ManifestLoader.deferred.resolve();\r\n        } catch (e) {\r\n            // no localization\r\n            const message = 'Unable to load the manifest: {0}'.format(e);\r\n            ManifestLoader.deferred.reject(message);\r\n            throw new Error(message);\r\n        }\r\n    }\r\n}\r\n"]}