"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.cancel = exports.close = void 0;
exports.exposeAll = exposeAll;
exports.createCaller = createCaller;
const postmsg_rpc_1 = require("postmsg-rpc");
const serializer_1 = require("./serializer");
function isRPCError(data) {
    return data && typeof data === 'object' && data.type === 'Error';
}
function getRPCOptions(messageBus) {
    return {
        addListener: messageBus.addEventListener.bind(messageBus),
        removeListener: messageBus.removeEventListener.bind(messageBus),
        postMessage(data) {
            return messageBus.postMessage(data);
        },
        getMessageData(event) {
            return event.data ?? event;
        },
    };
}
exports.close = Symbol('@@rpc.close');
exports.cancel = Symbol('@@rpc.cancel');
function exposeAll(obj, messageBus) {
    Object.entries(obj).forEach(([key, val]) => {
        const { close } = (0, postmsg_rpc_1.expose)(key, async (...args) => {
            try {
                return { type: 'Message', payload: await val(...args) };
            }
            catch (e) {
                return { type: 'Error', payload: (0, serializer_1.serializeError)(e) };
            }
        }, getRPCOptions(messageBus));
        val.close = close;
    });
    Object.defineProperty(obj, exports.close, {
        enumerable: false,
        value() {
            Object.values(obj).forEach((fn) => {
                fn.close();
            });
        },
    });
    return obj;
}
function createCaller(methodNames, messageBus, processors = {}) {
    const obj = {};
    const inflight = new Set();
    methodNames.forEach((name) => {
        const c = (0, postmsg_rpc_1.caller)(name, getRPCOptions(messageBus));
        obj[name] = async (...args) => {
            const processed = typeof processors[name] === 'function'
                ? processors[name]?.(...args)
                : args;
            const promise = c(...processed);
            inflight.add(promise);
            const result = (await promise);
            inflight.delete(promise);
            if (isRPCError(result))
                throw (0, serializer_1.deserializeError)(result.payload);
            return result.payload;
        };
    });
    Object.defineProperty(obj, exports.cancel, {
        enumerable: false,
        value() {
            for (const cancelable of inflight) {
                cancelable.cancel();
                inflight.delete(cancelable);
            }
        },
    });
    return obj;
}
//# sourceMappingURL=rpc.js.map