"use strict";
/**
 *
 * common
 *
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringifyMessage = exports.parseMessage = exports.isMessage = exports.validateMessage = exports.MessageType = exports.CloseCode = exports.DEPRECATED_GRAPHQL_WS_PROTOCOL = exports.GRAPHQL_TRANSPORT_WS_PROTOCOL = void 0;
const utils_1 = require("./utils");
/**
 * The WebSocket sub-protocol used for the [GraphQL over WebSocket Protocol](https://github.com/graphql/graphql-over-http/blob/main/rfcs/GraphQLOverWebSocket.md).
 *
 * @category Common
 */
exports.GRAPHQL_TRANSPORT_WS_PROTOCOL = 'graphql-transport-ws';
/**
 * The deprecated subprotocol used by [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws).
 *
 * @private
 */
exports.DEPRECATED_GRAPHQL_WS_PROTOCOL = 'graphql-ws';
/**
 * `graphql-ws` expected and standard close codes of the [GraphQL over WebSocket Protocol](https://github.com/graphql/graphql-over-http/blob/main/rfcs/GraphQLOverWebSocket.md).
 *
 * @category Common
 */
var CloseCode;
(function (CloseCode) {
    CloseCode[CloseCode["InternalServerError"] = 4500] = "InternalServerError";
    CloseCode[CloseCode["InternalClientError"] = 4005] = "InternalClientError";
    CloseCode[CloseCode["BadRequest"] = 4400] = "BadRequest";
    CloseCode[CloseCode["BadResponse"] = 4004] = "BadResponse";
    /** Tried subscribing before connect ack */
    CloseCode[CloseCode["Unauthorized"] = 4401] = "Unauthorized";
    CloseCode[CloseCode["Forbidden"] = 4403] = "Forbidden";
    CloseCode[CloseCode["SubprotocolNotAcceptable"] = 4406] = "SubprotocolNotAcceptable";
    CloseCode[CloseCode["ConnectionInitialisationTimeout"] = 4408] = "ConnectionInitialisationTimeout";
    CloseCode[CloseCode["ConnectionAcknowledgementTimeout"] = 4504] = "ConnectionAcknowledgementTimeout";
    /** Subscriber distinction is very important */
    CloseCode[CloseCode["SubscriberAlreadyExists"] = 4409] = "SubscriberAlreadyExists";
    CloseCode[CloseCode["TooManyInitialisationRequests"] = 4429] = "TooManyInitialisationRequests";
})(CloseCode || (exports.CloseCode = CloseCode = {}));
/**
 * Types of messages allowed to be sent by the client/server over the WS protocol.
 *
 * @category Common
 */
var MessageType;
(function (MessageType) {
    MessageType["ConnectionInit"] = "connection_init";
    MessageType["ConnectionAck"] = "connection_ack";
    MessageType["Ping"] = "ping";
    MessageType["Pong"] = "pong";
    MessageType["Subscribe"] = "subscribe";
    MessageType["Next"] = "next";
    MessageType["Error"] = "error";
    MessageType["Complete"] = "complete";
})(MessageType || (exports.MessageType = MessageType = {}));
/**
 * Validates the message against the GraphQL over WebSocket Protocol.
 *
 * Invalid messages will throw descriptive errors.
 *
 * @category Common
 */
function validateMessage(val) {
    if (!(0, utils_1.isObject)(val)) {
        throw new Error(`Message is expected to be an object, but got ${(0, utils_1.extendedTypeof)(val)}`);
    }
    if (!val.type) {
        throw new Error(`Message is missing the 'type' property`);
    }
    if (typeof val.type !== 'string') {
        throw new Error(`Message is expects the 'type' property to be a string, but got ${(0, utils_1.extendedTypeof)(val.type)}`);
    }
    switch (val.type) {
        case MessageType.ConnectionInit:
        case MessageType.ConnectionAck:
        case MessageType.Ping:
        case MessageType.Pong: {
            if (val.payload != null && !(0, utils_1.isObject)(val.payload)) {
                throw new Error(`"${val.type}" message expects the 'payload' property to be an object or nullish or missing, but got "${val.payload}"`);
            }
            break;
        }
        case MessageType.Subscribe: {
            if (typeof val.id !== 'string') {
                throw new Error(`"${val.type}" message expects the 'id' property to be a string, but got ${(0, utils_1.extendedTypeof)(val.id)}`);
            }
            if (!val.id) {
                throw new Error(`"${val.type}" message requires a non-empty 'id' property`);
            }
            if (!(0, utils_1.isObject)(val.payload)) {
                throw new Error(`"${val.type}" message expects the 'payload' property to be an object, but got ${(0, utils_1.extendedTypeof)(val.payload)}`);
            }
            if (typeof val.payload.query !== 'string') {
                throw new Error(`"${val.type}" message payload expects the 'query' property to be a string, but got ${(0, utils_1.extendedTypeof)(val.payload.query)}`);
            }
            if (val.payload.variables != null && !(0, utils_1.isObject)(val.payload.variables)) {
                throw new Error(`"${val.type}" message payload expects the 'variables' property to be a an object or nullish or missing, but got ${(0, utils_1.extendedTypeof)(val.payload.variables)}`);
            }
            if (val.payload.operationName != null &&
                (0, utils_1.extendedTypeof)(val.payload.operationName) !== 'string') {
                throw new Error(`"${val.type}" message payload expects the 'operationName' property to be a string or nullish or missing, but got ${(0, utils_1.extendedTypeof)(val.payload.operationName)}`);
            }
            if (val.payload.extensions != null && !(0, utils_1.isObject)(val.payload.extensions)) {
                throw new Error(`"${val.type}" message payload expects the 'extensions' property to be a an object or nullish or missing, but got ${(0, utils_1.extendedTypeof)(val.payload.extensions)}`);
            }
            break;
        }
        case MessageType.Next: {
            if (typeof val.id !== 'string') {
                throw new Error(`"${val.type}" message expects the 'id' property to be a string, but got ${(0, utils_1.extendedTypeof)(val.id)}`);
            }
            if (!val.id) {
                throw new Error(`"${val.type}" message requires a non-empty 'id' property`);
            }
            if (!(0, utils_1.isObject)(val.payload)) {
                throw new Error(`"${val.type}" message expects the 'payload' property to be an object, but got ${(0, utils_1.extendedTypeof)(val.payload)}`);
            }
            break;
        }
        case MessageType.Error: {
            if (typeof val.id !== 'string') {
                throw new Error(`"${val.type}" message expects the 'id' property to be a string, but got ${(0, utils_1.extendedTypeof)(val.id)}`);
            }
            if (!val.id) {
                throw new Error(`"${val.type}" message requires a non-empty 'id' property`);
            }
            if (!(0, utils_1.areGraphQLErrors)(val.payload)) {
                throw new Error(`"${val.type}" message expects the 'payload' property to be an array of GraphQL errors, but got ${JSON.stringify(val.payload)}`);
            }
            break;
        }
        case MessageType.Complete: {
            if (typeof val.id !== 'string') {
                throw new Error(`"${val.type}" message expects the 'id' property to be a string, but got ${(0, utils_1.extendedTypeof)(val.id)}`);
            }
            if (!val.id) {
                throw new Error(`"${val.type}" message requires a non-empty 'id' property`);
            }
            break;
        }
        default:
            throw new Error(`Invalid message 'type' property "${val.type}"`);
    }
    return val;
}
exports.validateMessage = validateMessage;
/**
 * Checks if the provided value is a valid GraphQL over WebSocket message.
 *
 * @deprecated Use `validateMessage` instead.
 *
 * @category Common
 */
function isMessage(val) {
    try {
        validateMessage(val);
        return true;
    }
    catch (_a) {
        return false;
    }
}
exports.isMessage = isMessage;
/**
 * Parses the raw websocket message data to a valid message.
 *
 * @category Common
 */
function parseMessage(data, reviver) {
    return validateMessage(typeof data === 'string' ? JSON.parse(data, reviver) : data);
}
exports.parseMessage = parseMessage;
/**
 * Stringifies a valid message ready to be sent through the socket.
 *
 * @category Common
 */
function stringifyMessage(msg, replacer) {
    validateMessage(msg);
    return JSON.stringify(msg, replacer);
}
exports.stringifyMessage = stringifyMessage;
