{"version":3,"sources":["../../../packages/core/rpc/rpc-channel.ts"],"names":[],"mappings":"AAOA,OAAO,EACH,OAAO,EACP,kBAAkB,EAClB,gBAAgB,EAEhB,OAAO,EAEP,OAAO,EACV,MAAM,YAAY,CAAC;AAIpB;;;GAGG;AACH,qBAAa,UAAW,SAAQ,OAAO;IAE5B,OAAO,EAAE,OAAO,CAAC;IAGjB,SAAS,EAAE,MAAM,CAAC;IAGzB,OAAO,CAAC,aAAa,CAAgC;IAErD,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,gBAAgB,CAAe;IACvC,OAAO,CAAC,cAAc,CAAS;IAE/B;;;;;;OAMG;gBACS,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAY3D;;OAEG;IACH,IAAW,kBAAkB,CAAC,QAAQ,EAAE,kBAAkB,EAEzD;IAED;;;;;OAKG;IACI,WAAW,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAS3D;;;;;;OAMG;IACI,aAAa,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC;IAiBxF;;;;;;;;OAQG;IACI,MAAM,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,UAAQ,GAAG,CAAC;IAejG;;OAEG;IACI,SAAS,CAAC,CAAC,SAAS,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC,EAAE;IAavD;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,oBAAoB;IAmB5B,OAAO,CAAC,eAAe;IAUvB;;OAEG;IACI,KAAK,IAAI,IAAI;IAKpB;;OAEG;IACI,IAAI,IAAI,IAAI;IAInB;;;;;;;;OAQG;IACI,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IA8C5G;;;;;;;OAOG;IACI,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgDxH;;;;;OAKG;IACI,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;IAUzC;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAIvD;;;;OAIG;IACH,SAAS,CAAC,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAUnF;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IA4MhB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;IAgBhB;;;;;OAKG;IACH,OAAO,CAAC,KAAK;CAehB","file":"rpc-channel.d.ts","sourcesContent":["import { NativeDeferred } from '../data/native-q';\r\nimport { Net } from '../data/net';\r\nimport { LogLevel } from '../diagnostics/log-level';\r\nimport { LogRecord } from '../diagnostics/log-record';\r\nimport { Logging } from '../diagnostics/logging';\r\nimport { Strings } from '../generated/strings';\r\nimport { EnvironmentModule } from '../manifest/environment-modules';\r\nimport {\r\n    RpcBase,\r\n    RpcInboundHandlers,\r\n    RpcMessagePacket,\r\n    RpcMessagePacketType,\r\n    RpcMode,\r\n    RpcOutboundCommands,\r\n    RpcType\r\n} from './rpc-base';\r\nimport { RpcOutbound } from './rpc-outbound';\r\nimport { RpcSeek, RpcSeekKey, RpcSeekMode } from './seek/rpc-seek-model';\r\n\r\n/**\r\n * RpcChannel class.\r\n * - Both Shell and Module creates one instance to present itself.\r\n */\r\nexport class RpcChannel extends RpcBase {\r\n    // Current Rpc mode.\r\n    public rpcMode: RpcMode;\r\n\r\n    // Signature of the gateway running instance.\r\n    public signature: string;\r\n\r\n    // RpcShell/RpcModule collection.\r\n    private rpcCollection = new Map<string, RpcBase[]>();\r\n\r\n    private sequence = 0;\r\n    private deferredQueue = new Map<number, NativeDeferred<any>>();\r\n    private global: Window = window;\r\n    private inboundHandlers: RpcInboundHandlers;\r\n    private listenerFunction: (ev) => void;\r\n    private webpackInvalid = false;\r\n\r\n    /**\r\n     * Initiates a new instance of the RpcChannel class.\r\n     *\r\n     * @param name the public name of itself.\r\n     * @param origin the origin url of itself.\r\n     * @param signature the signature of the gateway running instance.\r\n     */\r\n    constructor(name: string, origin: string, signature: string) {\r\n        super(null, name, origin, RpcType.Channel);\r\n        this.signature = signature;\r\n        if (MsftSme.isShell()) {\r\n            this.rpcMode = RpcMode.Shell;\r\n            this.depth = 0;\r\n        } else {\r\n            this.rpcMode = RpcMode.Module;\r\n            this.depth = null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets the rpc inbound handlers to use when creating for seek command.\r\n     */\r\n    public set rpcInboundHandlers(handlers: RpcInboundHandlers) {\r\n        this.inboundHandlers = handlers;\r\n    }\r\n\r\n    /**\r\n     * Register Inbound/Outbound.\r\n     *\r\n     * @param rpcObject the RpcInbound/RpcOutbound class instance.\r\n     * @param type the type of rpc object.\r\n     */\r\n    public registerRpc(rpcObject: RpcBase, type: RpcType): void {\r\n        if (rpcObject.type !== type) {\r\n            const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcTypeNoMatch.message;\r\n            throw new Error(message.format('registerRpc'));\r\n        }\r\n\r\n        this.addToCollection(rpcObject);\r\n    }\r\n\r\n    /**\r\n     * Unregister module with subName\r\n     *\r\n     * @param name the name of module.\r\n     * @param subName the subName.\r\n     * @return RpcBase the rpc object.\r\n     */\r\n    public unregisterRpc<T extends RpcBase>(name: string, subName: string, type: RpcType): T {\r\n        // unregister it by both origin and name.\r\n        const rpcObject = <T>this.getFromCollection(name, subName, true);\r\n        if (rpcObject.type !== type) {\r\n            const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcTypeNoMatch.message;\r\n            throw new Error(message.format('unregisterRpc'));\r\n        }\r\n\r\n        if (rpcObject) {\r\n            this.removeFromCollection(rpcObject);\r\n            return rpcObject;\r\n        } else {\r\n            const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcNotFoundModule.message;\r\n            throw new Error(message.format(name, subName));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Get Rpc object by module with subName for Inbound.\r\n     *\r\n     * @param name the name of module.\r\n     * @param subName the subName.\r\n     * @param type the type of rpc object.\r\n     * @param exact the matching type forced.\r\n     * @return RpcBase the rpc object.\r\n     */\r\n    public getRpc<T extends RpcBase>(name: string, subName: string, type: RpcType, nullOk = false): T {\r\n        const rpcObject = <T>this.getFromCollection(name, subName, true);\r\n        if (rpcObject && rpcObject.type !== type) {\r\n            if (nullOk) {\r\n                return null;\r\n            }\r\n\r\n            const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcTypeNoMatch.message;\r\n            throw new Error(message.format('getRpc'));\r\n        }\r\n\r\n        // return null if it cannot find.\r\n        return rpcObject;\r\n    }\r\n\r\n    /**\r\n     * Get all Rpc objects for the specified type.\r\n     */\r\n    public getAllRpc<T extends RpcBase>(type: RpcType): T[] {\r\n        const results: T[] = [];\r\n        this.rpcCollection.forEach((subCollection) => {\r\n            subCollection.forEach((rpc) => {\r\n                if (rpc.type === type) {\r\n                    results.push(<T>rpc);\r\n                }\r\n            });\r\n        });\r\n\r\n        return results;\r\n    }\r\n\r\n    /**\r\n     * Get RpcInbound/RpcOutbound object for module name and module sub name.\r\n     * If it doesn't configure subName yet, it returns it so the channel set it up.\r\n     *\r\n     * @param name the module name.\r\n     * @param subName the sub name of the iframe object.\r\n     * @return RpcBase the matched Rpc object.\r\n     */\r\n    private getFromCollection(name: string, subName: string, exact: boolean): RpcBase {\r\n        const subCollection: RpcBase[] = this.rpcCollection.get(name);\r\n        if (subCollection == null) {\r\n            return null;\r\n        }\r\n\r\n        return subCollection.find(value => (!exact && value.subName == null) || value.subName === subName);\r\n    }\r\n\r\n    private removeFromCollection(rpcObject: RpcBase): RpcBase {\r\n        const subCollection: RpcBase[] = this.rpcCollection.get(rpcObject.name);\r\n        if (subCollection == null) {\r\n            return null;\r\n        }\r\n\r\n        const results = MsftSme.remove(subCollection, rpcObject);\r\n        if (subCollection.length === 0) {\r\n            // remove the entry if it's empty.\r\n            this.rpcCollection.delete(rpcObject.name);\r\n        }\r\n\r\n        if (results && results.length === 1) {\r\n            return results[0];\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    private addToCollection(rpcObject: RpcBase): void {\r\n        let subCollection: RpcBase[] = this.rpcCollection.get(rpcObject.name);\r\n        if (subCollection == null) {\r\n            subCollection = [rpcObject];\r\n            this.rpcCollection.set(rpcObject.name, subCollection);\r\n        } else {\r\n            subCollection.push(rpcObject);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Start the message listener.\r\n     */\r\n    public start(): void {\r\n        this.listenerFunction = (ev) => this.listener(ev);\r\n        this.global.addEventListener('message', this.listenerFunction);\r\n    }\r\n\r\n    /**\r\n     * Stop the message listener.\r\n     */\r\n    public stop(): void {\r\n        this.global.removeEventListener('message', this.listenerFunction);\r\n    }\r\n\r\n    /**\r\n     * Post the message with retry delay.\r\n     *\r\n     * @param target the RpcToModule or RpcToShell object.\r\n     * @param message the message packet.\r\n     * @param count the retry count.\r\n     * @param delay the interval milliseconds.\r\n     * @return Promise<T> the promise object.\r\n     */\r\n    public retryPost<T>(target: RpcBase, message: RpcMessagePacket<T>, count: number, delay: number): Promise<T> {\r\n        if (target == null || target.window == null) {\r\n            const message2 = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcTargetWindowNotConfigured.message;\r\n            throw new Error(message2);\r\n        }\r\n\r\n        const deferred = new NativeDeferred<T>();\r\n        const lastSequence = this.sequence;\r\n        this.deferredQueue[this.sequence] = deferred;\r\n        message.srcName = this.name;\r\n        message.srcSubName = this.subName;\r\n        message.srcDepth = this.depth;\r\n        message.destName = target.name;\r\n        message.destSubName = target.subName;\r\n        message.signature = this.signature;\r\n        message.sequence = this.sequence;\r\n        message.type = RpcMessagePacketType.Request; // post\r\n        this.sequence++;\r\n        const header = `Retry ${RpcMessagePacketType[message.type]} \"${message.command}\" to ${message.destName}!${message.destSubName}`;\r\n        this.debugLogRpcMessage(message, header);\r\n        target.window.postMessage(message, target.origin);\r\n        const timer = setInterval(\r\n            () => {\r\n                if (deferred.isPending) {\r\n                    if (--count < 0) {\r\n                        const message2 = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcExpiredRetry.message;\r\n                        clearInterval(timer);\r\n                        deferred.reject(message2.format(message.command));\r\n                        if (this.deferredQueue[lastSequence]) {\r\n                            delete this.deferredQueue[lastSequence];\r\n                        }\r\n\r\n                        return;\r\n                    }\r\n\r\n                    target.window.postMessage(message, target.origin);\r\n                    return;\r\n                }\r\n\r\n                clearInterval(timer);\r\n            },\r\n            delay);\r\n\r\n        return deferred.promise;\r\n    }\r\n\r\n    /**\r\n     * Post the request message.\r\n     *\r\n     * @param target the RpcToModule or RpcToShell object.\r\n     * @param message the message packet.\r\n     * @param timeout the timeout. (10 seconds at default)\r\n     * @return Promise<TResult> the promise object.\r\n     */\r\n    public post<TMessage, TResult>(target: RpcBase, message: RpcMessagePacket<TMessage>, timeout?: number): Promise<TResult> {\r\n        let ignoreTimeout = false;\r\n        if (timeout === -1) {\r\n            ignoreTimeout = true;\r\n            timeout = null;\r\n        }\r\n\r\n        timeout = timeout || 10 * 1000; // 10 seconds\r\n        if (target == null || target.window == null) {\r\n            const message2 = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcTargetWindowNotConfigured.message;\r\n            throw new Error(message2);\r\n        }\r\n\r\n        const deferred = new NativeDeferred<TResult>();\r\n        const lastSequence = this.sequence;\r\n        this.deferredQueue[this.sequence] = deferred;\r\n        message.srcName = this.name;\r\n        message.srcSubName = this.subName;\r\n        message.srcDepth = this.depth;\r\n        message.destName = target.name;\r\n        message.destSubName = target.subName;\r\n        message.signature = this.signature;\r\n        message.sequence = this.sequence;\r\n        message.type = RpcMessagePacketType.Request; // post\r\n        this.sequence++;\r\n        const header = `${RpcMessagePacketType[message.type]}  \"${message.command}\" to ${message.destName}!${message.destSubName}`;\r\n        this.debugLogRpcMessage(message, header);\r\n        target.window.postMessage(message, target.origin);\r\n        setTimeout(\r\n            () => {\r\n                if (deferred.isPending) {\r\n                    if (ignoreTimeout) {\r\n                        deferred.resolve();\r\n                    } else {\r\n                        const message2 = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcExpired.message;\r\n                        deferred.reject(\r\n                            message2.format(this.name, this.subName, target.name, target.subName, message.command, message.type));\r\n                    }\r\n                }\r\n\r\n                if (this.deferredQueue[lastSequence]) {\r\n                    delete this.deferredQueue[lastSequence];\r\n                }\r\n            },\r\n            timeout);\r\n        return deferred.promise;\r\n    }\r\n\r\n    /**\r\n     * Validate the target window if exist by sending null packet.\r\n     *\r\n     * @param target the target Rpc object.\r\n     * @return boolean if false, it remove the target from the list.\r\n     */\r\n    public validate(target: RpcBase): boolean {\r\n        try {\r\n            target.window.postMessage({ validate: 'validate' }, target.origin);\r\n            return true;\r\n        } catch (error) {\r\n            this.removeFromCollection(target);\r\n            return false;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Log the debug message.\r\n     * @param message the message object.\r\n     * @param header the header string (used for the log group header).\r\n     */\r\n    protected debugLog(message: any, header?: string): void {\r\n        Logging.log({ source: 'rpc', message: message, level: LogLevel.Debug, consoleGroupHeader: header });\r\n    }\r\n\r\n    /**\r\n     * Process and log and rpc message.\r\n     * @param message the rpc message packet\r\n     * @param header the header string (used for the log group header).\r\n     */\r\n    protected debugLogRpcMessage(message: RpcMessagePacket<any>, header?: string): void {\r\n        const logMessage = { ...message };\r\n        if (message.command === RpcOutboundCommands[RpcOutboundCommands.Init]) {\r\n            // Why is this hidden?\r\n            logMessage.data = '(hidden...)';\r\n        }\r\n\r\n        this.debugLog(logMessage, header);\r\n    }\r\n\r\n    /**\r\n     * The listen handler.\r\n     *\r\n     * @param messageEvent the Rpc message event.\r\n     */\r\n    private listener(messageEvent: MessageEvent): void {\r\n\r\n        // ignore any shell hosting messages (don't handle them at all)\r\n        if (MsftSme.isShell()) {\r\n            const type = MsftSme.getValue<string>(messageEvent, 'data.type');\r\n            if (typeof type === 'string' && type.startsWith('msft-sme-shell-host')) {\r\n                return;\r\n            }\r\n        }\r\n\r\n        // We are operating as an iframe, any message we get, we should format to the parent to handle\r\n        if (MsftSme.isExtension() &&\r\n            window &&\r\n            window.parent &&\r\n            messageEvent.source === window.self &&\r\n            messageEvent.data &&\r\n            (messageEvent.data.type === 'webpackInvalid' ||\r\n            messageEvent.data.type === 'webpackOk')) {\r\n            // The rpc channel is an iframe, we need to send a message to the parent for the parent to reload after code change\r\n            // window.parent references the parent window, postMessage sends a message to the parent\r\n            // the '*' refers to sending the message to any origin, this can introduce potential security\r\n            // concerns so we only send messages of type 'webpackInvalid' and 'webpackOk'\r\n            window.parent.postMessage(messageEvent.data, '*');\r\n        }\r\n\r\n        if (\r\n            // Extension windows will only trust messages from there parent window\r\n            (MsftSme.isExtension() && messageEvent.source !== window.parent)\r\n            // Shell window only trusts extension origins on rpc\r\n            || (MsftSme.isShell() && !EnvironmentModule.isExtensionOrigin(messageEvent.origin))\r\n        ) {\r\n            // if we don't trust the origin, then just log a message\r\n            this.debugLog('RPC listener received message from untrusted sender: {0}'.format(messageEvent));\r\n            return;\r\n        }\r\n\r\n        if (messageEvent.data && messageEvent.data.type) {\r\n            // Watch for webpack reloads coming from the iframe\r\n            if (messageEvent.data.type === 'webpackInvalid') {\r\n                // Webpack is invalid, 1st message\r\n                this.webpackInvalid = true;\r\n            } else if (this.webpackInvalid && messageEvent.data.type === 'webpackOk') {\r\n                // Webpack is okay, 2nd message, we can reload\r\n                this.webpackInvalid = false;\r\n                location.reload();\r\n            }\r\n        }\r\n\r\n        // if the message if malformed, ignore it.\r\n        if (!messageEvent.data || !messageEvent.data.command) {\r\n            // ignore null event.\r\n            this.debugLog('RPC listener received malformed message from sender: {0}'.format(messageEvent));\r\n            return;\r\n        }\r\n\r\n        const message = messageEvent.data;\r\n        const header = `${RpcMessagePacketType[message.type]} \"${message.command}\" from ${message.srcName}!${message.srcSubName}`;\r\n        this.debugLogRpcMessage(message, header);\r\n        if (message.signature !== this.signature) {\r\n            const message2 = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcSignatureError.message;\r\n            throw new Error(message2);\r\n        }\r\n\r\n        // accept shell seek query\r\n        if (message.destName !== this.name) {\r\n            const message2 = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcUnexpectedDestination.message;\r\n            throw new Error(message2.format(message.destName));\r\n        }\r\n\r\n        let target: RpcBase = this.getFromCollection(message.srcName, message.srcSubName, false);\r\n        if (!target) {\r\n            // unknown request was received.\r\n            if (message.type === RpcMessagePacketType.Request\r\n                && message.command === RpcOutboundCommands[RpcOutboundCommands.Ping]) {\r\n                target = this.getFromCollection('*', '*', true);\r\n                if (target) {\r\n                    // keep remote window object to respond.\r\n                    // current channel is child, and target is parent.\r\n                    // target could be shell or a parent module.\r\n                    // remove the rpcInbound object once and re-register back again with new name.\r\n                    this.removeFromCollection(target);\r\n                    target.name = message.srcName;\r\n                    target.subName = message.srcSubName;\r\n                    target.window = <Window>messageEvent.source;\r\n                    target.origin = messageEvent.origin;\r\n                    target.depth = message.srcDepth;\r\n                    this.subName = message.destSubName;\r\n                    this.depth = message.srcDepth + 1;\r\n                    this.registerRpc(target, RpcType.Inbound);\r\n                }\r\n            }\r\n        }\r\n\r\n        // Seek to create or delete RpcInbound on the shell to access a child call.\r\n        if (message.command === RpcSeekKey.command\r\n            && this.name === EnvironmentModule.nameOfShell\r\n            && message.type === RpcMessagePacketType.Request) {\r\n            const seekData = <RpcSeek>message.data;\r\n            if (seekData.mode === RpcSeekMode.Create) {\r\n                if (target) {\r\n                    // update window object.\r\n                    target.subName = message.srcSubName;\r\n                    target.window = <Window>messageEvent.source;\r\n                    target.depth = message.srcDepth;\r\n                } else {\r\n                    target = new RpcOutbound(this, message.srcName, messageEvent.origin);\r\n                    target.subName = message.srcSubName;\r\n                    target.window = <Window>messageEvent.source;\r\n                    target.depth = message.srcDepth;\r\n                    (<RpcOutbound>target).registerAll(this.inboundHandlers);\r\n                    this.registerRpc(target, RpcType.Outbound);\r\n                }\r\n            } else if (seekData.mode === RpcSeekMode.Delete && target) {\r\n                this.removeFromCollection(target);\r\n            }\r\n        }\r\n\r\n        if (!target) {\r\n            // ignore older/unknown response packet. current channel no longer watching it for response, but treat new request as an error.\r\n            if (message.type === RpcMessagePacketType.Request) {\r\n                const message2 = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcUnexpectedEvent.message;\r\n                throw new Error(message2.format(message.srcName, message.srcSubName));\r\n            }\r\n\r\n            return;\r\n        }\r\n\r\n        let deferred: NativeDeferred<any>;\r\n        switch (message.type) {\r\n            case RpcMessagePacketType.Request: // post: processing response/error.\r\n                target.handle(message.command, message.version, message.srcName, message.srcSubName, message.data).then(\r\n                    (data: any) => {\r\n                        message.data = data;\r\n                        return this.response(target, message);\r\n                    },\r\n                    error => {\r\n                        let logMessage = '';\r\n                        let logStack = '';\r\n                        if (typeof error === 'string') {\r\n                            message.data = error;\r\n                            logMessage = error;\r\n                        } else {\r\n                            message.data = {};\r\n                            if (error && error.xhr) {\r\n                                const netError = Net.getErrorMessage(error);\r\n                                message.data.message = netError;\r\n                                logMessage = netError;\r\n                            } else if (error.message) {\r\n                                message.data.message = error.message;\r\n                                logMessage = error.message;\r\n                            }\r\n\r\n                            if (error.stack) {\r\n                                message.data.stack = error.stack;\r\n                                logStack = error.stack;\r\n                            }\r\n                        }\r\n\r\n                        Logging.log(<LogRecord>{\r\n                            source: 'RpcChannel',\r\n                            level: LogLevel.Error,\r\n                            message: logMessage,\r\n                            stack: logStack\r\n                        });\r\n\r\n                        // telemetry with predefined view/action name.\r\n                        Logging.trace({\r\n                            view: 'sme-generic-error',\r\n                            instance: 'rpc-channel',\r\n                            action: 'exceptionLog',\r\n                            data: { stack: '' }\r\n                        });\r\n\r\n                        return this.error(target, message);\r\n                    });\r\n                break;\r\n            case RpcMessagePacketType.Response: // response: received result with success.\r\n                deferred = this.deferredQueue[message.sequence];\r\n                if (!deferred) {\r\n                    if (message.command === RpcOutboundCommands[RpcOutboundCommands.Ping]) {\r\n                        // ping can be sent multiple times and deferred could be settled already.\r\n                        break;\r\n                    }\r\n\r\n                    const message2 = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcUnexpectedSequence.message;\r\n                    throw new Error(message2);\r\n                }\r\n\r\n                delete this.deferredQueue[message.sequence];\r\n                deferred.resolve(message.data);\r\n                break;\r\n            case RpcMessagePacketType.Error: // error: received result with error.\r\n                deferred = this.deferredQueue[message.sequence];\r\n                if (!deferred) {\r\n                    const message2 = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcUnexpectedErrorSequence.message;\r\n                    throw new Error(message2);\r\n                }\r\n\r\n                delete this.deferredQueue[message.sequence];\r\n                deferred.reject(message.data);\r\n                break;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sending response message.\r\n     *\r\n     * @param target the RpcToModule or RpcToShell object.\r\n     * @param message the Rpc message packet.\r\n     */\r\n    private response<T>(target: RpcBase, message: RpcMessagePacket<T>): void {\r\n        if (target == null || target.window == null) {\r\n            const message2 = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcTargetWindowNotConfigured.message;\r\n            throw new Error(message2);\r\n        }\r\n\r\n        message.srcName = this.name;\r\n        message.srcSubName = this.subName;\r\n        message.srcDepth = this.depth;\r\n        message.destName = target.name;\r\n        message.destSubName = target.subName;\r\n        message.signature = this.signature;\r\n        message.type = RpcMessagePacketType.Response; // response\r\n        target.window.postMessage(message, target.origin);\r\n    }\r\n\r\n    /**\r\n     * Sending error message.\r\n     *\r\n     * @param target the RpcToModule or RpcToShell object.\r\n     * @param message the Rpc message packet.\r\n     */\r\n    private error<T>(target: RpcBase, message: RpcMessagePacket<T>): void {\r\n        if (target == null || target.window == null) {\r\n            const message2 = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.RpcTargetWindowNotConfigured.message;\r\n            throw new Error(message2);\r\n        }\r\n\r\n        message.srcName = this.name;\r\n        message.srcSubName = this.subName;\r\n        message.srcDepth = this.depth;\r\n        message.destName = target.name;\r\n        message.destSubName = target.subName;\r\n        message.signature = this.signature;\r\n        message.type = RpcMessagePacketType.Error; // error\r\n        target.window.postMessage(message, target.origin);\r\n    }\r\n}\r\n"]}