/**
 *
 * common
 *
 */
import { areGraphQLErrors, extendedTypeof, isObject } from './utils.mjs';
/**
 * 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
 */
export const GRAPHQL_TRANSPORT_WS_PROTOCOL = 'graphql-transport-ws';
/**
 * The deprecated subprotocol used by [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws).
 *
 * @private
 */
export const 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
 */
export 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 || (CloseCode = {}));
/**
 * Types of messages allowed to be sent by the client/server over the WS protocol.
 *
 * @category Common
 */
export 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 || (MessageType = {}));
/**
 * Validates the message against the GraphQL over WebSocket Protocol.
 *
 * Invalid messages will throw descriptive errors.
 *
 * @category Common
 */
export function validateMessage(val) {
    if (!isObject(val)) {
        throw new Error(`Message is expected to be an object, but got ${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 ${extendedTypeof(val.type)}`);
    }
    switch (val.type) {
        case MessageType.ConnectionInit:
        case MessageType.ConnectionAck:
        case MessageType.Ping:
        case MessageType.Pong: {
            if (val.payload != null && !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 ${extendedTypeof(val.id)}`);
            }
            if (!val.id) {
                throw new Error(`"${val.type}" message requires a non-empty 'id' property`);
            }
            if (!isObject(val.payload)) {
                throw new Error(`"${val.type}" message expects the 'payload' property to be an object, but got ${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 ${extendedTypeof(val.payload.query)}`);
            }
            if (val.payload.variables != null && !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 ${extendedTypeof(val.payload.variables)}`);
            }
            if (val.payload.operationName != null &&
                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 ${extendedTypeof(val.payload.operationName)}`);
            }
            if (val.payload.extensions != null && !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 ${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 ${extendedTypeof(val.id)}`);
            }
            if (!val.id) {
                throw new Error(`"${val.type}" message requires a non-empty 'id' property`);
            }
            if (!isObject(val.payload)) {
                throw new Error(`"${val.type}" message expects the 'payload' property to be an object, but got ${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 ${extendedTypeof(val.id)}`);
            }
            if (!val.id) {
                throw new Error(`"${val.type}" message requires a non-empty 'id' property`);
            }
            if (!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 ${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;
}
/**
 * Checks if the provided value is a valid GraphQL over WebSocket message.
 *
 * @deprecated Use `validateMessage` instead.
 *
 * @category Common
 */
export function isMessage(val) {
    try {
        validateMessage(val);
        return true;
    }
    catch (_a) {
        return false;
    }
}
/**
 * Parses the raw websocket message data to a valid message.
 *
 * @category Common
 */
export function parseMessage(data, reviver) {
    return validateMessage(typeof data === 'string' ? JSON.parse(data, reviver) : data);
}
/**
 * Stringifies a valid message ready to be sent through the socket.
 *
 * @category Common
 */
export function stringifyMessage(msg, replacer) {
    validateMessage(msg);
    return JSON.stringify(msg, replacer);
}
