// This file has been generated by structbuf. Do not modify it!
import * as base from '~/common/network/structbuf/base.js';
import type * as types from '~/common/types.js';
import * as utils from '../utils.js';

/**
 * ## Handshake
 *
 * To perform authentication handshake, the following handshake structs have to
 * be exchanged in this order:
 *
 *     C -- client-hello -> S
 *     C <- server-hello -- S
 *     C ---- login ---- -> S
 *     C <-- login-ack ---- S
 *
 * Note that handshake structs have no wrapping frame container struct.
 */

/**
 * Initial message from the client, containing a server authentication
 * challenge in order to establish transport layer encryption.
 *
 * Direction: Client --> Server
 */
export interface ClientHelloLike {
    /**
     * 32 byte temporary public key (`TCK.public`).
     */
    readonly tck: Uint8Array;

    /**
     * 16 byte random cookie used for nonces (also acting as server
     * authentication challenge).
     */
    readonly cck: Uint8Array;
}

/**
 * Encodable of {@link ClientHelloLike}.
 */
interface ClientHelloEncodable_ {
    /**
     * 'tck' field value or encoder. See {@link ClientHelloLike#tck} for
     * the field's description.
     */
    readonly tck: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'cck' field value or encoder. See {@link ClientHelloLike#cck} for
     * the field's description.
     */
    readonly cck: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for ClientHelloEncodable.
 */
export type ClientHelloEncodable = types.WeakOpaque<
    ClientHelloEncodable_,
    {readonly ClientHelloEncodable: unique symbol}
>;

/** @inheritdoc */
export class ClientHello extends base.Struct implements ClientHelloLike {
    private readonly _array: Uint8Array;

    /**
     * Create a ClientHello from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
    }

    /**
     * Decode a client-hello struct from an array.
     *
     * @param array Array to decode from.
     * @returns ClientHello instance.
     */
    public static decode(array: Uint8Array): ClientHello {
        return new ClientHello(array);
    }

    /**
     * Encode a client-hello struct into an array.
     *
     * @param struct ClientHelloEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ClientHelloEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        // Encode `tck`
        utils.encodeBytes(struct.tck, array, 0);

        // Encode `cck`
        utils.encodeBytes(struct.cck, array, 32);

        return array.subarray(0, 48);
    }

    /**
     * Get the amount of bytes that would be written when encoding a client-hello struct into an
     * array.
     *
     * @param struct ClientHelloEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<ClientHelloEncodable, 'byteLength'>,
    ): types.u53 {
        return 48;
    }

    /**
     * 'tck' field accessor. See {@link ClientHelloLike#tck} for the
     * field's description.
     */
    public get tck(): Uint8Array {
        const offset = 0;
        return this._array.subarray(offset, offset + 32);
    }

    /**
     * 'cck' field accessor. See {@link ClientHelloLike#cck} for the
     * field's description.
     */
    public get cck(): Uint8Array {
        const offset = 32;
        return this._array.subarray(offset, offset + 16);
    }

    /**
     * Create a snapshot of ClientHelloLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ClientHelloLike snapshot.
     */
    public snapshot(): ClientHelloLike {
        return {
            tck: this.tck,
            cck: this.cck,
        };
    }

    /**
     * Create a clone of ClientHelloLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ClientHelloLike clone.
     */
    public clone(): ClientHello {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new ClientHello(array);
    }
}

/**
 * Initial message from the server, containing the server's authentication
 * challenge response. This concludes establishing transport layer
 * encryption based on `TCK` and `TSK`.
 *
 * Direction: Client <-- Server
 *
 * When creating this message:
 *
 * 1. Ensure that CCK and SCK are not equal.
 *
 * When receiving this message:
 *
 * 1. If CCK and SCK are equal, abort the connection and these steps.
 * 2. If the repeated random cookie of the client does not equal CCK,
 *    abort the connection and these steps.
 */
export interface ServerHelloLike {
    /**
     * 16 byte random cookie used for nonces (also acting as client
     * authentication challenge)
     */
    readonly sck: Uint8Array;

    /**
     * The server's challenge response (`server-challenge-response`),
     * encrypted by:
     *
     *     XSalsa20-Poly1305(
     *       key=X25519HSalsa20(SK.secret, TCK.public),
     *       nonce=SCK || u64-le(SSN+),
     *     )
     */
    readonly serverChallengeResponseBox: Uint8Array;
}

/**
 * Encodable of {@link ServerHelloLike}.
 */
interface ServerHelloEncodable_ {
    /**
     * 'sck' field value or encoder. See {@link ServerHelloLike#sck} for
     * the field's description.
     */
    readonly sck: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'server-challenge-response-box' field value or encoder. See {@link ServerHelloLike#serverChallengeResponseBox} for
     * the field's description.
     */
    readonly serverChallengeResponseBox: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for ServerHelloEncodable.
 */
export type ServerHelloEncodable = types.WeakOpaque<
    ServerHelloEncodable_,
    {readonly ServerHelloEncodable: unique symbol}
>;

/** @inheritdoc */
export class ServerHello extends base.Struct implements ServerHelloLike {
    private readonly _array: Uint8Array;

    /**
     * Create a ServerHello from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
    }

    /**
     * Decode a server-hello struct from an array.
     *
     * @param array Array to decode from.
     * @returns ServerHello instance.
     */
    public static decode(array: Uint8Array): ServerHello {
        return new ServerHello(array);
    }

    /**
     * Encode a server-hello struct into an array.
     *
     * @param struct ServerHelloEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ServerHelloEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        // Encode `sck`
        utils.encodeBytes(struct.sck, array, 0);

        // Encode `server-challenge-response-box`
        utils.encodeBytes(struct.serverChallengeResponseBox, array, 16);

        return array.subarray(0, 80);
    }

    /**
     * Get the amount of bytes that would be written when encoding a server-hello struct into an
     * array.
     *
     * @param struct ServerHelloEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<ServerHelloEncodable, 'byteLength'>,
    ): types.u53 {
        return 80;
    }

    /**
     * 'sck' field accessor. See {@link ServerHelloLike#sck} for the
     * field's description.
     */
    public get sck(): Uint8Array {
        const offset = 0;
        return this._array.subarray(offset, offset + 16);
    }

    /**
     * 'server-challenge-response-box' field accessor. See {@link ServerHelloLike#serverChallengeResponseBox} for the
     * field's description.
     */
    public get serverChallengeResponseBox(): Uint8Array {
        const offset = 16;
        return this._array.subarray(offset, offset + 64);
    }

    /**
     * Create a snapshot of ServerHelloLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ServerHelloLike snapshot.
     */
    public snapshot(): ServerHelloLike {
        return {
            sck: this.sck,
            serverChallengeResponseBox: this.serverChallengeResponseBox,
        };
    }

    /**
     * Create a clone of ServerHelloLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ServerHelloLike clone.
     */
    public clone(): ServerHello {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new ServerHello(array);
    }
}

/**
 * Authentication challenge response from the server.
 */
export interface ServerChallengeResponseLike {
    /**
     * 32 byte temporary public key (`TSK.public`)
     */
    readonly tsk: Uint8Array;

    /**
     * 16 byte repeated random cookie of the client (acting as the server's
     * challenge response)
     */
    readonly cck: Uint8Array;
}

/**
 * Encodable of {@link ServerChallengeResponseLike}.
 */
interface ServerChallengeResponseEncodable_ {
    /**
     * 'tsk' field value or encoder. See {@link ServerChallengeResponseLike#tsk} for
     * the field's description.
     */
    readonly tsk: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'cck' field value or encoder. See {@link ServerChallengeResponseLike#cck} for
     * the field's description.
     */
    readonly cck: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for ServerChallengeResponseEncodable.
 */
export type ServerChallengeResponseEncodable = types.WeakOpaque<
    ServerChallengeResponseEncodable_,
    {readonly ServerChallengeResponseEncodable: unique symbol}
>;

/** @inheritdoc */
export class ServerChallengeResponse extends base.Struct implements ServerChallengeResponseLike {
    private readonly _array: Uint8Array;

    /**
     * Create a ServerChallengeResponse from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
    }

    /**
     * Decode a server-challenge-response struct from an array.
     *
     * @param array Array to decode from.
     * @returns ServerChallengeResponse instance.
     */
    public static decode(array: Uint8Array): ServerChallengeResponse {
        return new ServerChallengeResponse(array);
    }

    /**
     * Encode a server-challenge-response struct into an array.
     *
     * @param struct ServerChallengeResponseEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ServerChallengeResponseEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        // Encode `tsk`
        utils.encodeBytes(struct.tsk, array, 0);

        // Encode `cck`
        utils.encodeBytes(struct.cck, array, 32);

        return array.subarray(0, 48);
    }

    /**
     * Get the amount of bytes that would be written when encoding a server-challenge-response struct into an
     * array.
     *
     * @param struct ServerChallengeResponseEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<ServerChallengeResponseEncodable, 'byteLength'>,
    ): types.u53 {
        return 48;
    }

    /**
     * 'tsk' field accessor. See {@link ServerChallengeResponseLike#tsk} for the
     * field's description.
     */
    public get tsk(): Uint8Array {
        const offset = 0;
        return this._array.subarray(offset, offset + 32);
    }

    /**
     * 'cck' field accessor. See {@link ServerChallengeResponseLike#cck} for the
     * field's description.
     */
    public get cck(): Uint8Array {
        const offset = 32;
        return this._array.subarray(offset, offset + 16);
    }

    /**
     * Create a snapshot of ServerChallengeResponseLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ServerChallengeResponseLike snapshot.
     */
    public snapshot(): ServerChallengeResponseLike {
        return {
            tsk: this.tsk,
            cck: this.cck,
        };
    }

    /**
     * Create a clone of ServerChallengeResponseLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ServerChallengeResponseLike clone.
     */
    public clone(): ServerChallengeResponse {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new ServerChallengeResponse(array);
    }
}

/**
 * Login request from the client.
 *
 * IMPORTANT: `CSN` is used and increased for `box` and then for
 * `extension-box`. It must follow this exact order.
 *
 * Direction: Client --> Server
 */
export interface LoginLike {
    /**
     * The [`login-data`](ref:handshake.login-data), encrypted by:
     *
     *     XSalsa20-Poly1305(
     *       key=X25519HSalsa20(TCK.secret, TSK.public),
     *       nonce=CCK || u64-le(CSN+),
     *     )
     */
    readonly box: Uint8Array;

    /**
     * An optional arbitrary amount of
     * [`extension`](ref:handshake.extension)s, encrypted by:
     *
     *     XSalsa20-Poly1305(
     *       key=X25519HSalsa20(TCK.secret, TSK.public),
     *       nonce=CCK || u64-le(CSN+),
     *     )
     *
     * These fields are only present if the
     * [`extension-indicator`](ref:handshake.extension-indicator) of the
     * [`login-data`](ref:handshake.login-data) field is present. If so,
     * extensions should be consumed until the extension indicator `length`
     * field is zero.
     */
    readonly extensionsBox: Uint8Array;
}

/**
 * Encodable of {@link LoginLike}.
 */
interface LoginEncodable_ {
    /**
     * 'box' field value or encoder. See {@link LoginLike#box} for
     * the field's description.
     */
    readonly box: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'extensions-box' field value or encoder. See {@link LoginLike#extensionsBox} for
     * the field's description.
     */
    readonly extensionsBox: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for LoginEncodable.
 */
export type LoginEncodable = types.WeakOpaque<
    LoginEncodable_,
    {readonly LoginEncodable: unique symbol}
>;

/** @inheritdoc */
export class Login extends base.Struct implements LoginLike {
    private readonly _array: Uint8Array;

    /**
     * Create a Login from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
    }

    /**
     * Decode a login struct from an array.
     *
     * @param array Array to decode from.
     * @returns Login instance.
     */
    public static decode(array: Uint8Array): Login {
        return new Login(array);
    }

    /**
     * Encode a login struct into an array.
     *
     * @param struct LoginEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<LoginEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        let offset = 144;

        // Encode `box`
        utils.encodeBytes(struct.box, array, 0);

        // Encode `extensions-box`
        offset += utils.encodeBytes(struct.extensionsBox, array, offset);

        return array.subarray(0, offset);
    }

    /**
     * Get the amount of bytes that would be written when encoding a login struct into an
     * array.
     *
     * @param struct LoginEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(struct: types.EncoderPick<LoginEncodable, 'byteLength'>): types.u53 {
        let offset = 144;
        offset += utils.getByteLength(struct.extensionsBox);
        return offset;
    }

    /**
     * 'box' field accessor. See {@link LoginLike#box} for the
     * field's description.
     */
    public get box(): Uint8Array {
        const offset = 0;
        return this._array.subarray(offset, offset + 144);
    }

    /**
     * 'extensions-box' field accessor. See {@link LoginLike#extensionsBox} for the
     * field's description.
     */
    public get extensionsBox(): Uint8Array {
        return this._array.subarray(144);
    }

    /**
     * Create a snapshot of LoginLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns LoginLike snapshot.
     */
    public snapshot(): LoginLike {
        return {
            box: this.box,
            extensionsBox: this.extensionsBox,
        };
    }

    /**
     * Create a clone of LoginLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns LoginLike clone.
     */
    public clone(): Login {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new Login(array);
    }
}

/**
 * Login data of the client.
 */
export interface LoginDataLike {
    /**
     * Threema ID of the client.
     */
    readonly identity: Uint8Array;

    /**
     * This is either the old client info field or an extension indicator.
     *
     * If the first 30 bytes of the field start with the string
     * `threema-clever-extension-field`, then parse this field as an
     * [`extension-indicator`](ref:handshake.extension-indicator) and parse
     * `extensions-box` appropriately.
     *
     * Otherwise, this represents an old client info and the content is
     * identical to the content of
     * [`client-info`](ref:handshake.client-info). Since the field has a
     * fixed size, the string is zero-padded.
     */
    readonly clientInfoOrExtensionIndicator: Uint8Array;

    /**
     * 16 byte repeated random cookie of the server (acting as the client's
     * challenge response)
     */
    readonly sck: Uint8Array;

    /**
     * 24 zero bytes (previously used as vouch nonce, now set to zero
     * indicating that the new vouch format is being used)
     */
    readonly reserved1: Uint8Array;

    /**
     * The vouch value, calculated as follows:
     *
     *     SS1 = X25519HSalsa20(CK.secret, SK.public)
     *     SS2 = X25519HSalsa20(CK.secret, TSK.public)
     *     VouchKey = BLAKE2b(key=SS1 || SS2, salt='v2', personal='3ma-csp')
     *     vouch = BLAKE2b(
     *       out-length=32,
     *       key=VouchKey,
     *       input=SCK || TCK.public,
     *     )
     */
    readonly vouch: Uint8Array;

    /**
     * 16 zero bytes (previously part of the vouch box, now set to zero for
     * compatibility)
     */
    readonly reserved2: Uint8Array;
}

/**
 * Encodable of {@link LoginDataLike}.
 */
interface LoginDataEncodable_ {
    /**
     * 'identity' field value or encoder. See {@link LoginDataLike#identity} for
     * the field's description.
     */
    readonly identity: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'client-info-or-extension-indicator' field value or encoder. See {@link LoginDataLike#clientInfoOrExtensionIndicator} for
     * the field's description.
     */
    readonly clientInfoOrExtensionIndicator: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'sck' field value or encoder. See {@link LoginDataLike#sck} for
     * the field's description.
     */
    readonly sck: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'reserved1' field value or encoder. See {@link LoginDataLike#reserved1} for
     * the field's description.
     */
    readonly reserved1: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'vouch' field value or encoder. See {@link LoginDataLike#vouch} for
     * the field's description.
     */
    readonly vouch: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'reserved2' field value or encoder. See {@link LoginDataLike#reserved2} for
     * the field's description.
     */
    readonly reserved2: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for LoginDataEncodable.
 */
export type LoginDataEncodable = types.WeakOpaque<
    LoginDataEncodable_,
    {readonly LoginDataEncodable: unique symbol}
>;

/** @inheritdoc */
export class LoginData extends base.Struct implements LoginDataLike {
    private readonly _array: Uint8Array;

    /**
     * Create a LoginData from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
    }

    /**
     * Decode a login-data struct from an array.
     *
     * @param array Array to decode from.
     * @returns LoginData instance.
     */
    public static decode(array: Uint8Array): LoginData {
        return new LoginData(array);
    }

    /**
     * Encode a login-data struct into an array.
     *
     * @param struct LoginDataEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<LoginDataEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        // Encode `identity`
        utils.encodeBytes(struct.identity, array, 0);

        // Encode `client-info-or-extension-indicator`
        utils.encodeBytes(struct.clientInfoOrExtensionIndicator, array, 8);

        // Encode `sck`
        utils.encodeBytes(struct.sck, array, 40);

        // Encode `reserved1`
        utils.encodeBytes(struct.reserved1, array, 56);

        // Encode `vouch`
        utils.encodeBytes(struct.vouch, array, 80);

        // Encode `reserved2`
        utils.encodeBytes(struct.reserved2, array, 112);

        return array.subarray(0, 128);
    }

    /**
     * Get the amount of bytes that would be written when encoding a login-data struct into an
     * array.
     *
     * @param struct LoginDataEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<LoginDataEncodable, 'byteLength'>,
    ): types.u53 {
        return 128;
    }

    /**
     * 'identity' field accessor. See {@link LoginDataLike#identity} for the
     * field's description.
     */
    public get identity(): Uint8Array {
        const offset = 0;
        return this._array.subarray(offset, offset + 8);
    }

    /**
     * 'client-info-or-extension-indicator' field accessor. See {@link LoginDataLike#clientInfoOrExtensionIndicator} for the
     * field's description.
     */
    public get clientInfoOrExtensionIndicator(): Uint8Array {
        const offset = 8;
        return this._array.subarray(offset, offset + 32);
    }

    /**
     * 'sck' field accessor. See {@link LoginDataLike#sck} for the
     * field's description.
     */
    public get sck(): Uint8Array {
        const offset = 40;
        return this._array.subarray(offset, offset + 16);
    }

    /**
     * 'reserved1' field accessor. See {@link LoginDataLike#reserved1} for the
     * field's description.
     */
    public get reserved1(): Uint8Array {
        const offset = 56;
        return this._array.subarray(offset, offset + 24);
    }

    /**
     * 'vouch' field accessor. See {@link LoginDataLike#vouch} for the
     * field's description.
     */
    public get vouch(): Uint8Array {
        const offset = 80;
        return this._array.subarray(offset, offset + 32);
    }

    /**
     * 'reserved2' field accessor. See {@link LoginDataLike#reserved2} for the
     * field's description.
     */
    public get reserved2(): Uint8Array {
        const offset = 112;
        return this._array.subarray(offset, offset + 16);
    }

    /**
     * Create a snapshot of LoginDataLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns LoginDataLike snapshot.
     */
    public snapshot(): LoginDataLike {
        return {
            identity: this.identity,
            clientInfoOrExtensionIndicator: this.clientInfoOrExtensionIndicator,
            sck: this.sck,
            reserved1: this.reserved1,
            vouch: this.vouch,
            reserved2: this.reserved2,
        };
    }

    /**
     * Create a clone of LoginDataLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns LoginDataLike clone.
     */
    public clone(): LoginData {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new LoginData(array);
    }
}

/**
 * Indicates that extensions are present
 */
export interface ExtensionIndicatorLike {
    /**
     * Magic string: `threema-clever-extension-field`
     */
    readonly magic: Uint8Array;

    /**
     * Amount of encrypted bytes present for extensions. Extension fields
     * need to be consumed until `length` is zero.
     */
    readonly length: types.u16;
}

/**
 * Encodable of {@link ExtensionIndicatorLike}.
 */
interface ExtensionIndicatorEncodable_ {
    /**
     * 'magic' field value or encoder. See {@link ExtensionIndicatorLike#magic} for
     * the field's description.
     */
    readonly magic: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'length' field value or encoder. See {@link ExtensionIndicatorLike#length} for
     * the field's description.
     */
    readonly length: types.u16;
}

/**
 * New-type for ExtensionIndicatorEncodable.
 */
export type ExtensionIndicatorEncodable = types.WeakOpaque<
    ExtensionIndicatorEncodable_,
    {readonly ExtensionIndicatorEncodable: unique symbol}
>;

/** @inheritdoc */
export class ExtensionIndicator extends base.Struct implements ExtensionIndicatorLike {
    private readonly _array: Uint8Array;
    private readonly _view: DataView;

    /**
     * Create a ExtensionIndicator from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
        this._view = new DataView(array.buffer, array.byteOffset, array.byteLength);
    }

    /**
     * Decode a extension-indicator struct from an array.
     *
     * @param array Array to decode from.
     * @returns ExtensionIndicator instance.
     */
    public static decode(array: Uint8Array): ExtensionIndicator {
        return new ExtensionIndicator(array);
    }

    /**
     * Encode a extension-indicator struct into an array.
     *
     * @param struct ExtensionIndicatorEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ExtensionIndicatorEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        const view = new DataView(array.buffer, array.byteOffset, array.byteLength);

        // Encode `magic`
        utils.encodeBytes(struct.magic, array, 0);

        // Encode `length`
        view.setUint16(30, struct.length, true);

        return array.subarray(0, 32);
    }

    /**
     * Get the amount of bytes that would be written when encoding a extension-indicator struct into an
     * array.
     *
     * @param struct ExtensionIndicatorEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<ExtensionIndicatorEncodable, 'byteLength'>,
    ): types.u53 {
        return 32;
    }

    /**
     * 'magic' field accessor. See {@link ExtensionIndicatorLike#magic} for the
     * field's description.
     */
    public get magic(): Uint8Array {
        const offset = 0;
        return this._array.subarray(offset, offset + 30);
    }

    /**
     * 'length' field accessor. See {@link ExtensionIndicatorLike#length} for the
     * field's description.
     */
    public get length(): types.u16 {
        return this._view.getUint16(30, true);
    }

    /**
     * Create a snapshot of ExtensionIndicatorLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ExtensionIndicatorLike snapshot.
     */
    public snapshot(): ExtensionIndicatorLike {
        return {
            magic: this.magic,
            length: this.length,
        };
    }

    /**
     * Create a clone of ExtensionIndicatorLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ExtensionIndicatorLike clone.
     */
    public clone(): ExtensionIndicator {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new ExtensionIndicator(array);
    }
}

/**
 * An extension field.
 */
export interface ExtensionLike {
    /**
     * Type of the extension. Must correspond to the encoded extension struct
     * of the `payload` field:
     *
     * - `0x00`: `client-info`
     * - `0x01`: `csp-device-id`
     * - `0x02`: `message-payload-version`
     * - `0x03`: `device-cookie`
     */
    readonly type: types.u8;

    /**
     * Length of the extension's `payload` field.
     */
    readonly length: types.u16;

    /**
     * Extension payload. Needs to be parsed according to the `type` field.
     */
    readonly payload: Uint8Array;
}

/**
 * Encodable of {@link ExtensionLike}.
 */
interface ExtensionEncodable_ {
    /**
     * 'type' field value or encoder. See {@link ExtensionLike#type} for
     * the field's description.
     */
    readonly type: types.u8;

    /**
     * 'payload' field value or encoder. See {@link ExtensionLike#payload} for
     * the field's description.
     */
    readonly payload: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for ExtensionEncodable.
 */
export type ExtensionEncodable = types.WeakOpaque<
    ExtensionEncodable_,
    {readonly ExtensionEncodable: unique symbol}
>;

/** @inheritdoc */
export class Extension extends base.Struct implements ExtensionLike {
    private readonly _array: Uint8Array;
    private readonly _view: DataView;

    /**
     * Create a Extension from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
        this._view = new DataView(array.buffer, array.byteOffset, array.byteLength);
    }

    /**
     * Decode a extension struct from an array.
     *
     * @param array Array to decode from.
     * @returns Extension instance.
     */
    public static decode(array: Uint8Array): Extension {
        return new Extension(array);
    }

    /**
     * Encode a extension struct into an array.
     *
     * @param struct ExtensionEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ExtensionEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        const view = new DataView(array.buffer, array.byteOffset, array.byteLength);
        let offset = 3;

        // Encode `type`
        array[0] = struct.type;

        // Encode `payload`
        const lengthValue = utils.encodeBytes(struct.payload, array, offset);
        offset += lengthValue;

        // Encode `length`
        view.setUint16(1, lengthValue, true);

        return array.subarray(0, offset);
    }

    /**
     * Get the amount of bytes that would be written when encoding a extension struct into an
     * array.
     *
     * @param struct ExtensionEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<ExtensionEncodable, 'byteLength'>,
    ): types.u53 {
        let offset = 3;
        offset += utils.getByteLength(struct.payload);
        return offset;
    }

    /**
     * 'type' field accessor. See {@link ExtensionLike#type} for the
     * field's description.
     */
    public get type(): types.u8 {
        return utils.unwrap(this._array[0]);
    }

    /**
     * 'length' field accessor. See {@link ExtensionLike#length} for the
     * field's description.
     */
    public get length(): types.u16 {
        return this._view.getUint16(1, true);
    }

    /**
     * 'payload' field accessor. See {@link ExtensionLike#payload} for the
     * field's description.
     */
    public get payload(): Uint8Array {
        const offset = 3;
        return this._array.subarray(offset, offset + this.length);
    }

    /**
     * Create a snapshot of ExtensionLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ExtensionLike snapshot.
     */
    public snapshot(): ExtensionLike {
        return {
            type: this.type,
            length: this.length,
            payload: this.payload,
        };
    }

    /**
     * Create a clone of ExtensionLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ExtensionLike clone.
     */
    public clone(): Extension {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new Extension(array);
    }
}

/**
 * Client info extension payload.
 */
export interface ClientInfoLike {
    /**
     * Client info string in the following format (without line breaks):
     *
     *     <app-version>;
     *     <platform>;
     *     <lang>/<country-code>;
     *     <rest>
     *
     * The `<rest>` looks like this for mobile clients (A/I/W):
     *
     *     <device-model>;
     *     <os-version>
     *
     * The `<rest>` looks like this for web/desktop clients (Q):
     *
     *     <renderer>;
     *     <renderer-version>;
     *     <os-name>;
     *     <os-architecture>
     *
     * The `<rest>` looks like this for Bots (B):
     *
     *     <os-name>;
     *     <os-architecture>
     *
     * The fields may contain the following values:
     *
     * - `app-version`: Arbitrary version string, depending on the platform
     * - `platform`:
     *   * `A`: Android
     *   * `I`: iOS
     *   * `Q`: Desktop/Web
     *   * `W`: Windows Phone
     *   * `B`: Bot
     * - `lang`: ISO 639-1:2002-ish language code
     * - `country-code`: ISO 3166-1-ish country code
     * - `device-model`: Arbitrary smartphone model
     * - `os-version`: Arbitrary OS version string
     * - `renderer`: Renderer name for Desktop/Web (e.g. `Firefox` or
     *   `Electron`)
     * - `renderer-version`: Renderer major version (e.g. `107`)
     * - `os-name`: Name of the operating system (e.g. `Linux` or `Windows`)
     * - `os-architecture`: Architecture of the operating system (e.g. `x64`)
     */
    readonly clientInfo: Uint8Array;
}

/**
 * Encodable of {@link ClientInfoLike}.
 */
interface ClientInfoEncodable_ {
    /**
     * 'client-info' field value or encoder. See {@link ClientInfoLike#clientInfo} for
     * the field's description.
     */
    readonly clientInfo: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for ClientInfoEncodable.
 */
export type ClientInfoEncodable = types.WeakOpaque<
    ClientInfoEncodable_,
    {readonly ClientInfoEncodable: unique symbol}
>;

/** @inheritdoc */
export class ClientInfo extends base.Struct implements ClientInfoLike {
    private readonly _array: Uint8Array;

    /**
     * Create a ClientInfo from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
    }

    /**
     * Decode a client-info struct from an array.
     *
     * @param array Array to decode from.
     * @returns ClientInfo instance.
     */
    public static decode(array: Uint8Array): ClientInfo {
        return new ClientInfo(array);
    }

    /**
     * Encode a client-info struct into an array.
     *
     * @param struct ClientInfoEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ClientInfoEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        let offset = 0;

        // Encode `client-info`
        offset += utils.encodeBytes(struct.clientInfo, array, offset);

        return array.subarray(0, offset);
    }

    /**
     * Get the amount of bytes that would be written when encoding a client-info struct into an
     * array.
     *
     * @param struct ClientInfoEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<ClientInfoEncodable, 'byteLength'>,
    ): types.u53 {
        let offset = 0;
        offset += utils.getByteLength(struct.clientInfo);
        return offset;
    }

    /**
     * 'client-info' field accessor. See {@link ClientInfoLike#clientInfo} for the
     * field's description.
     */
    public get clientInfo(): Uint8Array {
        return this._array.subarray(0);
    }

    /**
     * Create a snapshot of ClientInfoLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ClientInfoLike snapshot.
     */
    public snapshot(): ClientInfoLike {
        return {
            clientInfo: this.clientInfo,
        };
    }

    /**
     * Create a clone of ClientInfoLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ClientInfoLike clone.
     */
    public clone(): ClientInfo {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new ClientInfo(array);
    }
}

/**
 * CSP device ID extension payload.
 */
export interface CspDeviceIdLike {
    /**
     * CSP device ID, randomly generated **once** when the device got the
     * Mediator device ID.
     */
    readonly cspDeviceId: types.u64;
}

/**
 * Encodable of {@link CspDeviceIdLike}.
 */
interface CspDeviceIdEncodable_ {
    /**
     * 'csp-device-id' field value or encoder. See {@link CspDeviceIdLike#cspDeviceId} for
     * the field's description.
     */
    readonly cspDeviceId: types.u64;
}

/**
 * New-type for CspDeviceIdEncodable.
 */
export type CspDeviceIdEncodable = types.WeakOpaque<
    CspDeviceIdEncodable_,
    {readonly CspDeviceIdEncodable: unique symbol}
>;

/** @inheritdoc */
export class CspDeviceId extends base.Struct implements CspDeviceIdLike {
    private readonly _array: Uint8Array;
    private readonly _view: DataView;

    /**
     * Create a CspDeviceId from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
        this._view = new DataView(array.buffer, array.byteOffset, array.byteLength);
    }

    /**
     * Decode a csp-device-id struct from an array.
     *
     * @param array Array to decode from.
     * @returns CspDeviceId instance.
     */
    public static decode(array: Uint8Array): CspDeviceId {
        return new CspDeviceId(array);
    }

    /**
     * Encode a csp-device-id struct into an array.
     *
     * @param struct CspDeviceIdEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<CspDeviceIdEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        const view = new DataView(array.buffer, array.byteOffset, array.byteLength);

        // Encode `csp-device-id`
        view.setBigUint64(0, struct.cspDeviceId, true);

        return array.subarray(0, 8);
    }

    /**
     * Get the amount of bytes that would be written when encoding a csp-device-id struct into an
     * array.
     *
     * @param struct CspDeviceIdEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<CspDeviceIdEncodable, 'byteLength'>,
    ): types.u53 {
        return 8;
    }

    /**
     * 'csp-device-id' field accessor. See {@link CspDeviceIdLike#cspDeviceId} for the
     * field's description.
     */
    public get cspDeviceId(): types.u64 {
        return this._view.getBigUint64(0, true);
    }

    /**
     * Create a snapshot of CspDeviceIdLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns CspDeviceIdLike snapshot.
     */
    public snapshot(): CspDeviceIdLike {
        return {
            cspDeviceId: this.cspDeviceId,
        };
    }

    /**
     * Create a clone of CspDeviceIdLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns CspDeviceIdLike clone.
     */
    public clone(): CspDeviceId {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new CspDeviceId(array);
    }
}

/**
 * Message payload struct version to be used.
 *
 * In case this extension is not present, the server must assume that
 * version `0x00` has been selected.
 *
 * In case the server receives an unknown or unsupported protocol version,
 * it shall complete the handshake and then immediately send a `close-error`
 * payload.
 */
export interface MessagePayloadVersionLike {
    /**
     * Indicates the payload struct version the client will send and expects
     * to receive when exchanging message payload structs with the server:
     *
     * - `0x00`: `legacy-message`
     * - `0x01`: `message-with-metadata-box`
     */
    readonly version: types.u8;
}

/**
 * Encodable of {@link MessagePayloadVersionLike}.
 */
interface MessagePayloadVersionEncodable_ {
    /**
     * 'version' field value or encoder. See {@link MessagePayloadVersionLike#version} for
     * the field's description.
     */
    readonly version: types.u8;
}

/**
 * New-type for MessagePayloadVersionEncodable.
 */
export type MessagePayloadVersionEncodable = types.WeakOpaque<
    MessagePayloadVersionEncodable_,
    {readonly MessagePayloadVersionEncodable: unique symbol}
>;

/** @inheritdoc */
export class MessagePayloadVersion extends base.Struct implements MessagePayloadVersionLike {
    private readonly _array: Uint8Array;

    /**
     * Create a MessagePayloadVersion from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
    }

    /**
     * Decode a message-payload-version struct from an array.
     *
     * @param array Array to decode from.
     * @returns MessagePayloadVersion instance.
     */
    public static decode(array: Uint8Array): MessagePayloadVersion {
        return new MessagePayloadVersion(array);
    }

    /**
     * Encode a message-payload-version struct into an array.
     *
     * @param struct MessagePayloadVersionEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<MessagePayloadVersionEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        // Encode `version`
        array[0] = struct.version;

        return array.subarray(0, 1);
    }

    /**
     * Get the amount of bytes that would be written when encoding a message-payload-version struct into an
     * array.
     *
     * @param struct MessagePayloadVersionEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<MessagePayloadVersionEncodable, 'byteLength'>,
    ): types.u53 {
        return 1;
    }

    /**
     * 'version' field accessor. See {@link MessagePayloadVersionLike#version} for the
     * field's description.
     */
    public get version(): types.u8 {
        return utils.unwrap(this._array[0]);
    }

    /**
     * Create a snapshot of MessagePayloadVersionLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns MessagePayloadVersionLike snapshot.
     */
    public snapshot(): MessagePayloadVersionLike {
        return {
            version: this.version,
        };
    }

    /**
     * Create a clone of MessagePayloadVersionLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns MessagePayloadVersionLike clone.
     */
    public clone(): MessagePayloadVersion {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new MessagePayloadVersion(array);
    }
}

/**
 * A 16 byte random value chosen by the client and stored in a secure,
 * device-specific location (not included in any backups etc., not
 * viewable/exportable).
 *
 * Its purpose is to allow detection when a different (rogue) device has
 * connected to the chat server, e.g. because an attacker has obtained
 * the secret key of a user.
 *
 * The server will store the device cookie of the last connection, and if a
 * different cookie is sent by the client, it will set a flag on the identity
 * and send a
 * [`device-cookie-change-indication`](ref:payload.device-cookie-change-indication)
 * payload to the client every time it connects. The client should then show
 * a warning in form of a notification or a dialog to the user. Note that the
 * normal protocol flow should continue regardless of whether the user has
 * acknowledged the warning or not.
 *
 * If this extension is not sent by the client, then the server's behavior
 * depends on whether it has already stored a device cookie for this
 * identity or not. If not, then nothing will happen. If yes, then it will
 * act as if the client had sent an all-zero device cookie.
 */
export interface DeviceCookieLike {
    /**
     * Device cookie, randomly generated **once** per device.
     */
    readonly deviceCookie: Uint8Array;
}

/**
 * Encodable of {@link DeviceCookieLike}.
 */
interface DeviceCookieEncodable_ {
    /**
     * 'device-cookie' field value or encoder. See {@link DeviceCookieLike#deviceCookie} for
     * the field's description.
     */
    readonly deviceCookie: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for DeviceCookieEncodable.
 */
export type DeviceCookieEncodable = types.WeakOpaque<
    DeviceCookieEncodable_,
    {readonly DeviceCookieEncodable: unique symbol}
>;

/** @inheritdoc */
export class DeviceCookie extends base.Struct implements DeviceCookieLike {
    private readonly _array: Uint8Array;

    /**
     * Create a DeviceCookie from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
    }

    /**
     * Decode a device-cookie struct from an array.
     *
     * @param array Array to decode from.
     * @returns DeviceCookie instance.
     */
    public static decode(array: Uint8Array): DeviceCookie {
        return new DeviceCookie(array);
    }

    /**
     * Encode a device-cookie struct into an array.
     *
     * @param struct DeviceCookieEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<DeviceCookieEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        // Encode `device-cookie`
        utils.encodeBytes(struct.deviceCookie, array, 0);

        return array.subarray(0, 16);
    }

    /**
     * Get the amount of bytes that would be written when encoding a device-cookie struct into an
     * array.
     *
     * @param struct DeviceCookieEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<DeviceCookieEncodable, 'byteLength'>,
    ): types.u53 {
        return 16;
    }

    /**
     * 'device-cookie' field accessor. See {@link DeviceCookieLike#deviceCookie} for the
     * field's description.
     */
    public get deviceCookie(): Uint8Array {
        const offset = 0;
        return this._array.subarray(offset, offset + 16);
    }

    /**
     * Create a snapshot of DeviceCookieLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns DeviceCookieLike snapshot.
     */
    public snapshot(): DeviceCookieLike {
        return {
            deviceCookie: this.deviceCookie,
        };
    }

    /**
     * Create a clone of DeviceCookieLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns DeviceCookieLike clone.
     */
    public clone(): DeviceCookie {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new DeviceCookie(array);
    }
}

/**
 * Login acknowledgement from the server.
 *
 * Direction: Client <-- Server
 */
export interface LoginAckLike {
    /**
     * Reserved (16 zero bytes), encrypted by:
     *
     *     XSalsa20-Poly1305(
     *       key=X25519HSalsa20(TSK.secret, TCK.public),
     *       nonce=SCK || u64-le(SSN+),
     *     )
     */
    readonly reservedBox: Uint8Array;
}

/**
 * Encodable of {@link LoginAckLike}.
 */
interface LoginAckEncodable_ {
    /**
     * 'reserved-box' field value or encoder. See {@link LoginAckLike#reservedBox} for
     * the field's description.
     */
    readonly reservedBox: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for LoginAckEncodable.
 */
export type LoginAckEncodable = types.WeakOpaque<
    LoginAckEncodable_,
    {readonly LoginAckEncodable: unique symbol}
>;

/** @inheritdoc */
export class LoginAck extends base.Struct implements LoginAckLike {
    private readonly _array: Uint8Array;

    /**
     * Create a LoginAck from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
    }

    /**
     * Decode a login-ack struct from an array.
     *
     * @param array Array to decode from.
     * @returns LoginAck instance.
     */
    public static decode(array: Uint8Array): LoginAck {
        return new LoginAck(array);
    }

    /**
     * Encode a login-ack struct into an array.
     *
     * @param struct LoginAckEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<LoginAckEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        // Encode `reserved-box`
        utils.encodeBytes(struct.reservedBox, array, 0);

        return array.subarray(0, 32);
    }

    /**
     * Get the amount of bytes that would be written when encoding a login-ack struct into an
     * array.
     *
     * @param struct LoginAckEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<LoginAckEncodable, 'byteLength'>,
    ): types.u53 {
        return 32;
    }

    /**
     * 'reserved-box' field accessor. See {@link LoginAckLike#reservedBox} for the
     * field's description.
     */
    public get reservedBox(): Uint8Array {
        const offset = 0;
        return this._array.subarray(offset, offset + 32);
    }

    /**
     * Create a snapshot of LoginAckLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns LoginAckLike snapshot.
     */
    public snapshot(): LoginAckLike {
        return {
            reservedBox: this.reservedBox,
        };
    }

    /**
     * Create a clone of LoginAckLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns LoginAckLike clone.
     */
    public clone(): LoginAck {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new LoginAck(array);
    }
}
