// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
// Trust me, you don't want to mess with it!

import {
  ArrayBufferDataStream,
  FfiConverter,
  FfiConverterArrayBuffer,
  FfiConverterInt8,
  FfiConverterUInt8,
  FfiConverterInt16,
  FfiConverterUInt16,
  FfiConverterInt32,
  FfiConverterUInt32,
  FfiConverterInt64,
  FfiConverterUInt64,
  FfiConverterFloat32,
  FfiConverterFloat64,
  FfiConverterBoolean,
  FfiConverterBytes,
  FfiConverterString,
  UniFFICallbackHandler,
  UniFFICallbackMethodHandler,
  UniFFIError,
  UniFFIInternalError,
  UniFFITypeError,
  constructUniffiObject,
  handleRustResult,
  uniffiObjectPtr,
} from "moz-src:///toolkit/components/uniffi-js/js/UniFFI.sys.mjs";

// Objects intended to be used in the unit tests
export var UnitTestObjs = {
    uniffiObjectPtr,
};



import {
  FfiConverterTypeDeviceType,
} from "./RustSync15.sys.mjs";

// Export the FFIConverter object to make external types work.
export { FfiConverterTypeDeviceType };


// Export the FFIConverter object to make external types work.
export class FfiConverterSequenceString extends FfiConverterArrayBuffer {
    static read(dataStream) {
        const len = dataStream.readInt32();
        const arr = [];
        for (let i = 0; i < len; i++) {
            arr.push(FfiConverterString.read(dataStream));
        }
        return arr;
    }

    static write(dataStream, value) {
        dataStream.writeInt32(value.length);
        value.forEach((innerValue) => {
            FfiConverterString.write(dataStream, innerValue);
        })
    }

    static computeSize(value) {
        // The size of the length
        let size = 4;
        for (const innerValue of value) {
            size += FfiConverterString.computeSize(innerValue);
        }
        return size;
    }

    static checkType(value) {
        if (!Array.isArray(value)) {
            throw new UniFFITypeError(`${value} is not an array`);
        }
        value.forEach((innerValue, idx) => {
            try {
                FfiConverterString.checkType(innerValue);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart(`[${idx}]`);
                }
                throw e;
            }
        })
    }
}
// Export the FFIConverter object to make external types work.
export class FfiConverterOptionalString extends FfiConverterArrayBuffer {
    static checkType(value) {
        if (value !== undefined && value !== null) {
            FfiConverterString.checkType(value)
        }
    }

    static read(dataStream) {
        const code = dataStream.readUint8(0);
        switch (code) {
            case 0:
                return null
            case 1:
                return FfiConverterString.read(dataStream)
            default:
                throw new UniFFIError(`Unexpected code: ${code}`);
        }
    }

    static write(dataStream, value) {
        if (value === null || value === undefined) {
            dataStream.writeUint8(0);
            return;
        }
        dataStream.writeUint8(1);
        FfiConverterString.write(dataStream, value)
    }

    static computeSize(value) {
        if (value === null || value === undefined) {
            return 1;
        }
        return 1 + FfiConverterString.computeSize(value)
    }
}




/**
 * RemoteTabRecord
 */
export class RemoteTabRecord {
    constructor(
        {
            title, 
            urlHistory, 
            icon, 
            lastUsed, 
            inactive= false, 
            pinned= false, 
            index= 0, 
            windowId= "", 
            tabGroupId= ""
        } = {
            title: undefined, 
            urlHistory: undefined, 
            icon: undefined, 
            lastUsed: undefined, 
            inactive: undefined, 
            pinned: undefined, 
            index: undefined, 
            windowId: undefined, 
            tabGroupId: undefined
        }
    ) {
        try {
            FfiConverterString.checkType(title)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("title");
            }
            throw e;
        }
        try {
            FfiConverterSequenceString.checkType(urlHistory)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("urlHistory");
            }
            throw e;
        }
        try {
            FfiConverterOptionalString.checkType(icon)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("icon");
            }
            throw e;
        }
        try {
            FfiConverterInt64.checkType(lastUsed)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("lastUsed");
            }
            throw e;
        }
        try {
            FfiConverterBoolean.checkType(inactive)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("inactive");
            }
            throw e;
        }
        try {
            FfiConverterBoolean.checkType(pinned)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("pinned");
            }
            throw e;
        }
        try {
            FfiConverterUInt32.checkType(index)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("index");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(windowId)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("windowId");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(tabGroupId)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("tabGroupId");
            }
            throw e;
        }
        /**
         * @type {string}
         */
        this.title = title;
        /**
         * @type {Array.<string>}
         */
        this.urlHistory = urlHistory;
        /**
         * @type {?string}
         */
        this.icon = icon;
        /**
         * @type {number}
         */
        this.lastUsed = lastUsed;
        /**
         * @type {boolean}
         */
        this.inactive = inactive;
        /**
         * @type {boolean}
         */
        this.pinned = pinned;
        /**
         * The index within the window_id.
         * @type {number}
         */
        this.index = index;
        /**
         * @type {string}
         */
        this.windowId = windowId;
        /**
         * @type {string}
         */
        this.tabGroupId = tabGroupId;
    }

    equals(other) {
        return (
            this.title == other.title
            && this.urlHistory == other.urlHistory
            && this.icon == other.icon
            && this.lastUsed == other.lastUsed
            && this.inactive == other.inactive
            && this.pinned == other.pinned
            && this.index == other.index
            && this.windowId == other.windowId
            && this.tabGroupId == other.tabGroupId
        )
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeRemoteTabRecord extends FfiConverterArrayBuffer {
    static read(dataStream) {
        return new RemoteTabRecord({
            title: FfiConverterString.read(dataStream),
            urlHistory: FfiConverterSequenceString.read(dataStream),
            icon: FfiConverterOptionalString.read(dataStream),
            lastUsed: FfiConverterInt64.read(dataStream),
            inactive: FfiConverterBoolean.read(dataStream),
            pinned: FfiConverterBoolean.read(dataStream),
            index: FfiConverterUInt32.read(dataStream),
            windowId: FfiConverterString.read(dataStream),
            tabGroupId: FfiConverterString.read(dataStream),
        });
    }
    static write(dataStream, value) {
        FfiConverterString.write(dataStream, value.title);
        FfiConverterSequenceString.write(dataStream, value.urlHistory);
        FfiConverterOptionalString.write(dataStream, value.icon);
        FfiConverterInt64.write(dataStream, value.lastUsed);
        FfiConverterBoolean.write(dataStream, value.inactive);
        FfiConverterBoolean.write(dataStream, value.pinned);
        FfiConverterUInt32.write(dataStream, value.index);
        FfiConverterString.write(dataStream, value.windowId);
        FfiConverterString.write(dataStream, value.tabGroupId);
    }

    static computeSize(value) {
        let totalSize = 0;
        totalSize += FfiConverterString.computeSize(value.title);
        totalSize += FfiConverterSequenceString.computeSize(value.urlHistory);
        totalSize += FfiConverterOptionalString.computeSize(value.icon);
        totalSize += FfiConverterInt64.computeSize(value.lastUsed);
        totalSize += FfiConverterBoolean.computeSize(value.inactive);
        totalSize += FfiConverterBoolean.computeSize(value.pinned);
        totalSize += FfiConverterUInt32.computeSize(value.index);
        totalSize += FfiConverterString.computeSize(value.windowId);
        totalSize += FfiConverterString.computeSize(value.tabGroupId);
        return totalSize
    }

    static checkType(value) {
        super.checkType(value);
        if (!(value instanceof RemoteTabRecord)) {
            throw new UniFFITypeError(`Expected 'RemoteTabRecord', found '${typeof value}'`);
        }
        try {
            FfiConverterString.checkType(value.title);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".title");
            }
            throw e;
        }
        try {
            FfiConverterSequenceString.checkType(value.urlHistory);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".urlHistory");
            }
            throw e;
        }
        try {
            FfiConverterOptionalString.checkType(value.icon);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".icon");
            }
            throw e;
        }
        try {
            FfiConverterInt64.checkType(value.lastUsed);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".lastUsed");
            }
            throw e;
        }
        try {
            FfiConverterBoolean.checkType(value.inactive);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".inactive");
            }
            throw e;
        }
        try {
            FfiConverterBoolean.checkType(value.pinned);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".pinned");
            }
            throw e;
        }
        try {
            FfiConverterUInt32.checkType(value.index);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".index");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(value.windowId);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".windowId");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(value.tabGroupId);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".tabGroupId");
            }
            throw e;
        }
    }
}
// Export the FFIConverter object to make external types work.
export class FfiConverterSequenceTypeRemoteTabRecord extends FfiConverterArrayBuffer {
    static read(dataStream) {
        const len = dataStream.readInt32();
        const arr = [];
        for (let i = 0; i < len; i++) {
            arr.push(FfiConverterTypeRemoteTabRecord.read(dataStream));
        }
        return arr;
    }

    static write(dataStream, value) {
        dataStream.writeInt32(value.length);
        value.forEach((innerValue) => {
            FfiConverterTypeRemoteTabRecord.write(dataStream, innerValue);
        })
    }

    static computeSize(value) {
        // The size of the length
        let size = 4;
        for (const innerValue of value) {
            size += FfiConverterTypeRemoteTabRecord.computeSize(innerValue);
        }
        return size;
    }

    static checkType(value) {
        if (!Array.isArray(value)) {
            throw new UniFFITypeError(`${value} is not an array`);
        }
        value.forEach((innerValue, idx) => {
            try {
                FfiConverterTypeRemoteTabRecord.checkType(innerValue);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart(`[${idx}]`);
                }
                throw e;
            }
        })
    }
}
/**
 * A tab-group, representing a session store `TabGroupStateData`.
 */
export class TabGroup {
    constructor(
        {
            id, 
            name, 
            color, 
            collapsed
        } = {
            id: undefined, 
            name: undefined, 
            color: undefined, 
            collapsed: undefined
        }
    ) {
        try {
            FfiConverterString.checkType(id)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("id");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(name)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("name");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(color)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("color");
            }
            throw e;
        }
        try {
            FfiConverterBoolean.checkType(collapsed)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("collapsed");
            }
            throw e;
        }
        /**
         * @type {string}
         */
        this.id = id;
        /**
         * @type {string}
         */
        this.name = name;
        /**
         * @type {string}
         */
        this.color = color;
        /**
         * @type {boolean}
         */
        this.collapsed = collapsed;
    }

    equals(other) {
        return (
            this.id == other.id
            && this.name == other.name
            && this.color == other.color
            && this.collapsed == other.collapsed
        )
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeTabGroup extends FfiConverterArrayBuffer {
    static read(dataStream) {
        return new TabGroup({
            id: FfiConverterString.read(dataStream),
            name: FfiConverterString.read(dataStream),
            color: FfiConverterString.read(dataStream),
            collapsed: FfiConverterBoolean.read(dataStream),
        });
    }
    static write(dataStream, value) {
        FfiConverterString.write(dataStream, value.id);
        FfiConverterString.write(dataStream, value.name);
        FfiConverterString.write(dataStream, value.color);
        FfiConverterBoolean.write(dataStream, value.collapsed);
    }

    static computeSize(value) {
        let totalSize = 0;
        totalSize += FfiConverterString.computeSize(value.id);
        totalSize += FfiConverterString.computeSize(value.name);
        totalSize += FfiConverterString.computeSize(value.color);
        totalSize += FfiConverterBoolean.computeSize(value.collapsed);
        return totalSize
    }

    static checkType(value) {
        super.checkType(value);
        if (!(value instanceof TabGroup)) {
            throw new UniFFITypeError(`Expected 'TabGroup', found '${typeof value}'`);
        }
        try {
            FfiConverterString.checkType(value.id);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".id");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(value.name);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".name");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(value.color);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".color");
            }
            throw e;
        }
        try {
            FfiConverterBoolean.checkType(value.collapsed);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".collapsed");
            }
            throw e;
        }
    }
}
// Export the FFIConverter object to make external types work.
export class FfiConverterMapStringTypeTabGroup extends FfiConverterArrayBuffer {
    static read(dataStream) {
        const len = dataStream.readInt32();
        const map = new Map();
        for (let i = 0; i < len; i++) {
            const key = FfiConverterString.read(dataStream);
            const value = FfiConverterTypeTabGroup.read(dataStream);
            map.set(key, value);
        }

        return map;
    }

     static write(dataStream, map) {
        dataStream.writeInt32(map.size);
        for (const [key, value] of map) {
            FfiConverterString.write(dataStream, key);
            FfiConverterTypeTabGroup.write(dataStream, value);
        }
    }

    static computeSize(map) {
        // The size of the length
        let size = 4;
        for (const [key, value] of map) {
            size += FfiConverterString.computeSize(key);
            size += FfiConverterTypeTabGroup.computeSize(value);
        }
        return size;
    }

    static checkType(map) {
        for (const [key, value] of map) {
            try {
                FfiConverterString.checkType(key);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("(key)");
                }
                throw e;
            }

            try {
                FfiConverterTypeTabGroup.checkType(value);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart(`[${key}]`);
                }
                throw e;
            }
        }
    }
}
export class FfiConverterTypeTimestamp extends FfiConverter {
    static lift(value) {
        return FfiConverterInt64.lift(value);
    }

    static lower(value) {
        return FfiConverterInt64.lower(value);
    }

    static write(dataStream, value) {
        FfiConverterInt64.write(dataStream, value);
    }

    static read(dataStream) {
        const builtinVal = FfiConverterInt64.read(dataStream);
        return builtinVal;
    }

    static computeSize(value) {
        return FfiConverterInt64.computeSize(value);
    }

    static checkType(value) {
        if (value === null || value === undefined) {
            throw new TypeError("value is null or undefined");
        }
    }
}

/**
 * WindowType
 */
export const WindowType = Object.freeze({
    /**
     * NORMAL
     */
    NORMAL: 0,
});

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeWindowType extends FfiConverterArrayBuffer {
    static #validValues = Object.values(WindowType)

    static read(dataStream) {
        // Use sequential indices (1-based) for the wire format to match the Rust scaffolding
        switch (dataStream.readInt32()) {
            case 1:
                return WindowType.NORMAL
            default:
                throw new UniFFITypeError("Unknown WindowType variant");
        }
    }

    static write(dataStream, value) {
        // Use sequential indices (1-based) for the wire format to match the Rust scaffolding
        if (value === WindowType.NORMAL) {
            dataStream.writeInt32(1);
            return;
        }
        throw new UniFFITypeError("Unknown WindowType variant");
    }

    static computeSize(value) {
        return 4;
    }

    static checkType(value) {
      // Check that the value is a valid enum variant
      if (!this.#validValues.includes(value)) {
          throw new UniFFITypeError(`${value} is not a valid value for WindowType`);
      }
    }
}
/**
 * Window
 */
export class Window {
    constructor(
        {
            id, 
            lastUsed, 
            index, 
            windowType
        } = {
            id: undefined, 
            lastUsed: undefined, 
            index: undefined, 
            windowType: undefined
        }
    ) {
        try {
            FfiConverterString.checkType(id)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("id");
            }
            throw e;
        }
        try {
            FfiConverterTypeTimestamp.checkType(lastUsed)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("lastUsed");
            }
            throw e;
        }
        try {
            FfiConverterUInt32.checkType(index)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("index");
            }
            throw e;
        }
        try {
            FfiConverterTypeWindowType.checkType(windowType)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("windowType");
            }
            throw e;
        }
        /**
         * @type {string}
         */
        this.id = id;
        /**
         * @type {Timestamp}
         */
        this.lastUsed = lastUsed;
        /**
         * @type {number}
         */
        this.index = index;
        /**
         * @type {WindowType[keyof WindowType]}
         */
        this.windowType = windowType;
    }

    equals(other) {
        return (
            this.id == other.id
            && this.lastUsed == other.lastUsed
            && this.index == other.index
            && this.windowType == other.windowType
        )
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeWindow extends FfiConverterArrayBuffer {
    static read(dataStream) {
        return new Window({
            id: FfiConverterString.read(dataStream),
            lastUsed: FfiConverterTypeTimestamp.read(dataStream),
            index: FfiConverterUInt32.read(dataStream),
            windowType: FfiConverterTypeWindowType.read(dataStream),
        });
    }
    static write(dataStream, value) {
        FfiConverterString.write(dataStream, value.id);
        FfiConverterTypeTimestamp.write(dataStream, value.lastUsed);
        FfiConverterUInt32.write(dataStream, value.index);
        FfiConverterTypeWindowType.write(dataStream, value.windowType);
    }

    static computeSize(value) {
        let totalSize = 0;
        totalSize += FfiConverterString.computeSize(value.id);
        totalSize += FfiConverterTypeTimestamp.computeSize(value.lastUsed);
        totalSize += FfiConverterUInt32.computeSize(value.index);
        totalSize += FfiConverterTypeWindowType.computeSize(value.windowType);
        return totalSize
    }

    static checkType(value) {
        super.checkType(value);
        if (!(value instanceof Window)) {
            throw new UniFFITypeError(`Expected 'Window', found '${typeof value}'`);
        }
        try {
            FfiConverterString.checkType(value.id);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".id");
            }
            throw e;
        }
        try {
            FfiConverterTypeTimestamp.checkType(value.lastUsed);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".lastUsed");
            }
            throw e;
        }
        try {
            FfiConverterUInt32.checkType(value.index);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".index");
            }
            throw e;
        }
        try {
            FfiConverterTypeWindowType.checkType(value.windowType);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".windowType");
            }
            throw e;
        }
    }
}
// Export the FFIConverter object to make external types work.
export class FfiConverterMapStringTypeWindow extends FfiConverterArrayBuffer {
    static read(dataStream) {
        const len = dataStream.readInt32();
        const map = new Map();
        for (let i = 0; i < len; i++) {
            const key = FfiConverterString.read(dataStream);
            const value = FfiConverterTypeWindow.read(dataStream);
            map.set(key, value);
        }

        return map;
    }

     static write(dataStream, map) {
        dataStream.writeInt32(map.size);
        for (const [key, value] of map) {
            FfiConverterString.write(dataStream, key);
            FfiConverterTypeWindow.write(dataStream, value);
        }
    }

    static computeSize(map) {
        // The size of the length
        let size = 4;
        for (const [key, value] of map) {
            size += FfiConverterString.computeSize(key);
            size += FfiConverterTypeWindow.computeSize(value);
        }
        return size;
    }

    static checkType(map) {
        for (const [key, value] of map) {
            try {
                FfiConverterString.checkType(key);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("(key)");
                }
                throw e;
            }

            try {
                FfiConverterTypeWindow.checkType(value);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart(`[${key}]`);
                }
                throw e;
            }
        }
    }
}
/**
 * ClientRemoteTabs
 */
export class ClientRemoteTabs {
    constructor(
        {
            clientId, 
            clientName, 
            deviceType, 
            lastModified, 
            remoteTabs, 
            tabGroups, 
            windows
        } = {
            clientId: undefined, 
            clientName: undefined, 
            deviceType: undefined, 
            lastModified: undefined, 
            remoteTabs: undefined, 
            tabGroups: undefined, 
            windows: undefined
        }
    ) {
        try {
            FfiConverterString.checkType(clientId)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("clientId");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(clientName)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("clientName");
            }
            throw e;
        }
        try {
            FfiConverterTypeDeviceType.checkType(deviceType)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("deviceType");
            }
            throw e;
        }
        try {
            FfiConverterInt64.checkType(lastModified)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("lastModified");
            }
            throw e;
        }
        try {
            FfiConverterSequenceTypeRemoteTabRecord.checkType(remoteTabs)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("remoteTabs");
            }
            throw e;
        }
        try {
            FfiConverterMapStringTypeTabGroup.checkType(tabGroups)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("tabGroups");
            }
            throw e;
        }
        try {
            FfiConverterMapStringTypeWindow.checkType(windows)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("windows");
            }
            throw e;
        }
        /**
         * misnamed: this is the fxa_device_id of the client (which may or may not be the same as the corresponding ID in the `clients` collection)
         * @type {string}
         */
        this.clientId = clientId;
        /**
         * @type {string}
         */
        this.clientName = clientName;
        /**
         * @type {DeviceType[keyof DeviceType]}
         */
        this.deviceType = deviceType;
        /**
         * Number of ms since the unix epoch (as reported by the server's clock)
         * @type {number}
         */
        this.lastModified = lastModified;
        /**
         * @type {Array.<RemoteTabRecord>}
         */
        this.remoteTabs = remoteTabs;
        /**
         * @type {object}
         */
        this.tabGroups = tabGroups;
        /**
         * @type {object}
         */
        this.windows = windows;
    }

    equals(other) {
        return (
            this.clientId == other.clientId
            && this.clientName == other.clientName
            && this.deviceType == other.deviceType
            && this.lastModified == other.lastModified
            && this.remoteTabs == other.remoteTabs
            && this.tabGroups == other.tabGroups
            && this.windows == other.windows
        )
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeClientRemoteTabs extends FfiConverterArrayBuffer {
    static read(dataStream) {
        return new ClientRemoteTabs({
            clientId: FfiConverterString.read(dataStream),
            clientName: FfiConverterString.read(dataStream),
            deviceType: FfiConverterTypeDeviceType.read(dataStream),
            lastModified: FfiConverterInt64.read(dataStream),
            remoteTabs: FfiConverterSequenceTypeRemoteTabRecord.read(dataStream),
            tabGroups: FfiConverterMapStringTypeTabGroup.read(dataStream),
            windows: FfiConverterMapStringTypeWindow.read(dataStream),
        });
    }
    static write(dataStream, value) {
        FfiConverterString.write(dataStream, value.clientId);
        FfiConverterString.write(dataStream, value.clientName);
        FfiConverterTypeDeviceType.write(dataStream, value.deviceType);
        FfiConverterInt64.write(dataStream, value.lastModified);
        FfiConverterSequenceTypeRemoteTabRecord.write(dataStream, value.remoteTabs);
        FfiConverterMapStringTypeTabGroup.write(dataStream, value.tabGroups);
        FfiConverterMapStringTypeWindow.write(dataStream, value.windows);
    }

    static computeSize(value) {
        let totalSize = 0;
        totalSize += FfiConverterString.computeSize(value.clientId);
        totalSize += FfiConverterString.computeSize(value.clientName);
        totalSize += FfiConverterTypeDeviceType.computeSize(value.deviceType);
        totalSize += FfiConverterInt64.computeSize(value.lastModified);
        totalSize += FfiConverterSequenceTypeRemoteTabRecord.computeSize(value.remoteTabs);
        totalSize += FfiConverterMapStringTypeTabGroup.computeSize(value.tabGroups);
        totalSize += FfiConverterMapStringTypeWindow.computeSize(value.windows);
        return totalSize
    }

    static checkType(value) {
        super.checkType(value);
        if (!(value instanceof ClientRemoteTabs)) {
            throw new UniFFITypeError(`Expected 'ClientRemoteTabs', found '${typeof value}'`);
        }
        try {
            FfiConverterString.checkType(value.clientId);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".clientId");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(value.clientName);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".clientName");
            }
            throw e;
        }
        try {
            FfiConverterTypeDeviceType.checkType(value.deviceType);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".deviceType");
            }
            throw e;
        }
        try {
            FfiConverterInt64.checkType(value.lastModified);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".lastModified");
            }
            throw e;
        }
        try {
            FfiConverterSequenceTypeRemoteTabRecord.checkType(value.remoteTabs);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".remoteTabs");
            }
            throw e;
        }
        try {
            FfiConverterMapStringTypeTabGroup.checkType(value.tabGroups);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".tabGroups");
            }
            throw e;
        }
        try {
            FfiConverterMapStringTypeWindow.checkType(value.windows);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".windows");
            }
            throw e;
        }
    }
}
/**
 * LocalTabsInfo
 */
export class LocalTabsInfo {
    constructor(
        {
            tabs, 
            tabGroups, 
            windows
        } = {
            tabs: undefined, 
            tabGroups: undefined, 
            windows: undefined
        }
    ) {
        try {
            FfiConverterSequenceTypeRemoteTabRecord.checkType(tabs)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("tabs");
            }
            throw e;
        }
        try {
            FfiConverterMapStringTypeTabGroup.checkType(tabGroups)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("tabGroups");
            }
            throw e;
        }
        try {
            FfiConverterMapStringTypeWindow.checkType(windows)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("windows");
            }
            throw e;
        }
        /**
         * @type {Array.<RemoteTabRecord>}
         */
        this.tabs = tabs;
        /**
         * @type {object}
         */
        this.tabGroups = tabGroups;
        /**
         * @type {object}
         */
        this.windows = windows;
    }

    equals(other) {
        return (
            this.tabs == other.tabs
            && this.tabGroups == other.tabGroups
            && this.windows == other.windows
        )
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeLocalTabsInfo extends FfiConverterArrayBuffer {
    static read(dataStream) {
        return new LocalTabsInfo({
            tabs: FfiConverterSequenceTypeRemoteTabRecord.read(dataStream),
            tabGroups: FfiConverterMapStringTypeTabGroup.read(dataStream),
            windows: FfiConverterMapStringTypeWindow.read(dataStream),
        });
    }
    static write(dataStream, value) {
        FfiConverterSequenceTypeRemoteTabRecord.write(dataStream, value.tabs);
        FfiConverterMapStringTypeTabGroup.write(dataStream, value.tabGroups);
        FfiConverterMapStringTypeWindow.write(dataStream, value.windows);
    }

    static computeSize(value) {
        let totalSize = 0;
        totalSize += FfiConverterSequenceTypeRemoteTabRecord.computeSize(value.tabs);
        totalSize += FfiConverterMapStringTypeTabGroup.computeSize(value.tabGroups);
        totalSize += FfiConverterMapStringTypeWindow.computeSize(value.windows);
        return totalSize
    }

    static checkType(value) {
        super.checkType(value);
        if (!(value instanceof LocalTabsInfo)) {
            throw new UniFFITypeError(`Expected 'LocalTabsInfo', found '${typeof value}'`);
        }
        try {
            FfiConverterSequenceTypeRemoteTabRecord.checkType(value.tabs);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".tabs");
            }
            throw e;
        }
        try {
            FfiConverterMapStringTypeTabGroup.checkType(value.tabGroups);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".tabGroups");
            }
            throw e;
        }
        try {
            FfiConverterMapStringTypeWindow.checkType(value.windows);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".windows");
            }
            throw e;
        }
    }
}

/**
 * A command which should be sent to a remote device.
 */
export class RemoteCommand {}
/**
 * CloseTab
 */
RemoteCommand.CloseTab = class extends RemoteCommand{
   constructor({url = undefined } = {}) {
                super();
            try {
                FfiConverterString.checkType(url);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("url");
                }
                throw e;
            }
            this.url = url;
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeRemoteCommand extends FfiConverterArrayBuffer {
    static read(dataStream) {
        // Use sequential indices (1-based) for the wire format to match the Rust scaffolding
        switch (dataStream.readInt32()) {
            case 1:
                return new RemoteCommand.CloseTab({
                    url: FfiConverterString.read(dataStream)
                });
            default:
                throw new UniFFITypeError("Unknown RemoteCommand variant");
        }
    }

    static write(dataStream, value) {
        // Use sequential indices (1-based) for the wire format to match the Rust scaffolding
        if (value instanceof RemoteCommand.CloseTab) {
            dataStream.writeInt32(1);
            FfiConverterString.write(dataStream, value.url);
            return;
        }
        throw new UniFFITypeError("Unknown RemoteCommand variant");
    }

    static computeSize(value) {
        // Size of the Int indicating the variant
        let totalSize = 4;
        if (value instanceof RemoteCommand.CloseTab) {
            totalSize += FfiConverterString.computeSize(value.url);
            return totalSize;
        }
        throw new UniFFITypeError("Unknown RemoteCommand variant");
    }

    static checkType(value) {
      if (!(value instanceof RemoteCommand)) {
        throw new UniFFITypeError(`${value} is not a subclass instance of RemoteCommand`);
      }
    }
}
// Export the FFIConverter object to make external types work.
export class FfiConverterOptionalTypeTimestamp extends FfiConverterArrayBuffer {
    static checkType(value) {
        if (value !== undefined && value !== null) {
            FfiConverterTypeTimestamp.checkType(value)
        }
    }

    static read(dataStream) {
        const code = dataStream.readUint8(0);
        switch (code) {
            case 0:
                return null
            case 1:
                return FfiConverterTypeTimestamp.read(dataStream)
            default:
                throw new UniFFIError(`Unexpected code: ${code}`);
        }
    }

    static write(dataStream, value) {
        if (value === null || value === undefined) {
            dataStream.writeUint8(0);
            return;
        }
        dataStream.writeUint8(1);
        FfiConverterTypeTimestamp.write(dataStream, value)
    }

    static computeSize(value) {
        if (value === null || value === undefined) {
            return 1;
        }
        return 1 + FfiConverterTypeTimestamp.computeSize(value)
    }
}
/**
 * Represents a "pending" command.
 */
export class PendingCommand {
    constructor(
        {
            deviceId, 
            command, 
            timeRequested, 
            timeSent
        } = {
            deviceId: undefined, 
            command: undefined, 
            timeRequested: undefined, 
            timeSent: undefined
        }
    ) {
        try {
            FfiConverterString.checkType(deviceId)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("deviceId");
            }
            throw e;
        }
        try {
            FfiConverterTypeRemoteCommand.checkType(command)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("command");
            }
            throw e;
        }
        try {
            FfiConverterTypeTimestamp.checkType(timeRequested)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("timeRequested");
            }
            throw e;
        }
        try {
            FfiConverterOptionalTypeTimestamp.checkType(timeSent)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("timeSent");
            }
            throw e;
        }
        /**
         * @type {string}
         */
        this.deviceId = deviceId;
        /**
         * @type {RemoteCommand[keyof RemoteCommand]}
         */
        this.command = command;
        /**
         * @type {Timestamp}
         */
        this.timeRequested = timeRequested;
        /**
         * @type {?Timestamp}
         */
        this.timeSent = timeSent;
    }

    equals(other) {
        return (
            this.deviceId == other.deviceId
            && this.command == other.command
            && this.timeRequested == other.timeRequested
            && this.timeSent == other.timeSent
        )
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypePendingCommand extends FfiConverterArrayBuffer {
    static read(dataStream) {
        return new PendingCommand({
            deviceId: FfiConverterString.read(dataStream),
            command: FfiConverterTypeRemoteCommand.read(dataStream),
            timeRequested: FfiConverterTypeTimestamp.read(dataStream),
            timeSent: FfiConverterOptionalTypeTimestamp.read(dataStream),
        });
    }
    static write(dataStream, value) {
        FfiConverterString.write(dataStream, value.deviceId);
        FfiConverterTypeRemoteCommand.write(dataStream, value.command);
        FfiConverterTypeTimestamp.write(dataStream, value.timeRequested);
        FfiConverterOptionalTypeTimestamp.write(dataStream, value.timeSent);
    }

    static computeSize(value) {
        let totalSize = 0;
        totalSize += FfiConverterString.computeSize(value.deviceId);
        totalSize += FfiConverterTypeRemoteCommand.computeSize(value.command);
        totalSize += FfiConverterTypeTimestamp.computeSize(value.timeRequested);
        totalSize += FfiConverterOptionalTypeTimestamp.computeSize(value.timeSent);
        return totalSize
    }

    static checkType(value) {
        super.checkType(value);
        if (!(value instanceof PendingCommand)) {
            throw new UniFFITypeError(`Expected 'PendingCommand', found '${typeof value}'`);
        }
        try {
            FfiConverterString.checkType(value.deviceId);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".deviceId");
            }
            throw e;
        }
        try {
            FfiConverterTypeRemoteCommand.checkType(value.command);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".command");
            }
            throw e;
        }
        try {
            FfiConverterTypeTimestamp.checkType(value.timeRequested);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".timeRequested");
            }
            throw e;
        }
        try {
            FfiConverterOptionalTypeTimestamp.checkType(value.timeSent);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".timeSent");
            }
            throw e;
        }
    }
}

/**
 * TabsApiError
 */
export class TabsApiError extends Error {}


/**
 * SyncError
 */
export class SyncError extends TabsApiError {

    constructor(
        reason,
        ...params
    ) {
        const message = `reason: ${ reason }`;
        super(message, ...params);
        this.reason = reason;
    }
    toString() {
        return `SyncError: ${super.toString()}`
    }
}

/**
 * SqlError
 */
export class SqlError extends TabsApiError {

    constructor(
        reason,
        ...params
    ) {
        const message = `reason: ${ reason }`;
        super(message, ...params);
        this.reason = reason;
    }
    toString() {
        return `SqlError: ${super.toString()}`
    }
}

/**
 * UnexpectedTabsError
 */
export class UnexpectedTabsError extends TabsApiError {

    constructor(
        reason,
        ...params
    ) {
        const message = `reason: ${ reason }`;
        super(message, ...params);
        this.reason = reason;
    }
    toString() {
        return `UnexpectedTabsError: ${super.toString()}`
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeTabsApiError extends FfiConverterArrayBuffer {
    static read(dataStream) {
        switch (dataStream.readInt32()) {
            case 1:
                return new SyncError(
                    FfiConverterString.read(dataStream)
                    );
            case 2:
                return new SqlError(
                    FfiConverterString.read(dataStream)
                    );
            case 3:
                return new UnexpectedTabsError(
                    FfiConverterString.read(dataStream)
                    );
            default:
                throw new UniFFITypeError("Unknown TabsApiError variant");
        }
    }
    static computeSize(value) {
        // Size of the Int indicating the variant
        let totalSize = 4;
        if (value instanceof SyncError) {
            totalSize += FfiConverterString.computeSize(value.reason);
            return totalSize;
        }
        if (value instanceof SqlError) {
            totalSize += FfiConverterString.computeSize(value.reason);
            return totalSize;
        }
        if (value instanceof UnexpectedTabsError) {
            totalSize += FfiConverterString.computeSize(value.reason);
            return totalSize;
        }
        throw new UniFFITypeError("Unknown TabsApiError variant");
    }
    static write(dataStream, value) {
        if (value instanceof SyncError) {
            dataStream.writeInt32(1);
            FfiConverterString.write(dataStream, value.reason);
            return;
        }
        if (value instanceof SqlError) {
            dataStream.writeInt32(2);
            FfiConverterString.write(dataStream, value.reason);
            return;
        }
        if (value instanceof UnexpectedTabsError) {
            dataStream.writeInt32(3);
            FfiConverterString.write(dataStream, value.reason);
            return;
        }
        throw new UniFFITypeError("Unknown TabsApiError variant");
    }

    static errorClass = TabsApiError;
}
export class FfiConverterTypeTabsGuid extends FfiConverter {
    static lift(value) {
        return FfiConverterString.lift(value);
    }

    static lower(value) {
        return FfiConverterString.lower(value);
    }

    static write(dataStream, value) {
        FfiConverterString.write(dataStream, value);
    }

    static read(dataStream) {
        const builtinVal = FfiConverterString.read(dataStream);
        return builtinVal;
    }

    static computeSize(value) {
        return FfiConverterString.computeSize(value);
    }

    static checkType(value) {
        if (value === null || value === undefined) {
            throw new TypeError("value is null or undefined");
        }
    }
}
// Export the FFIConverter object to make external types work.
export class FfiConverterSequenceTypePendingCommand extends FfiConverterArrayBuffer {
    static read(dataStream) {
        const len = dataStream.readInt32();
        const arr = [];
        for (let i = 0; i < len; i++) {
            arr.push(FfiConverterTypePendingCommand.read(dataStream));
        }
        return arr;
    }

    static write(dataStream, value) {
        dataStream.writeInt32(value.length);
        value.forEach((innerValue) => {
            FfiConverterTypePendingCommand.write(dataStream, innerValue);
        })
    }

    static computeSize(value) {
        // The size of the length
        let size = 4;
        for (const innerValue of value) {
            size += FfiConverterTypePendingCommand.computeSize(innerValue);
        }
        return size;
    }

    static checkType(value) {
        if (!Array.isArray(value)) {
            throw new UniFFITypeError(`${value} is not an array`);
        }
        value.forEach((innerValue, idx) => {
            try {
                FfiConverterTypePendingCommand.checkType(innerValue);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart(`[${idx}]`);
                }
                throw e;
            }
        })
    }
}

/**
 * RemoteCommandStoreInterface
 */
export class RemoteCommandStoreInterface {
    /**
     * Add a new command, after which it will be pending. Returns false if the command is already active.
     * @param {string} deviceId
     * @param {RemoteCommand[keyof RemoteCommand]} command
     * @returns {Promise<boolean>}}
     */
    async addRemoteCommand(
        deviceId, 
        command) {
      throw Error("addRemoteCommand not implemented");
    }
    /**
     * Add a new command with an explicit timestamp. Primarily used by tests.
     * @param {string} deviceId
     * @param {RemoteCommand[keyof RemoteCommand]} command
     * @param {Timestamp} when
     * @returns {Promise<boolean>}}
     */
    async addRemoteCommandAt(
        deviceId, 
        command, 
        when) {
      throw Error("addRemoteCommandAt not implemented");
    }
    /**
     * Return all unsent commands. This is for the code sending the commands, result is sorted by time_requested.
     * @returns {Promise<Array.<PendingCommand>>}}
     */
    async getUnsentCommands() {
      throw Error("getUnsentCommands not implemented");
    }
    /**
     * Removes the remote command. Typically used to implement "undo" but may also be used by the queue
     * processor when it gives up trying to send a command.
     * @param {string} deviceId
     * @param {RemoteCommand[keyof RemoteCommand]} command
     * @returns {Promise<boolean>}}
     */
    async removeRemoteCommand(
        deviceId, 
        command) {
      throw Error("removeRemoteCommand not implemented");
    }
    /**
     * Flag a command as sent.
     * @param {PendingCommand} command
     * @returns {Promise<boolean>}}
     */
    async setPendingCommandSent(
        command) {
      throw Error("setPendingCommandSent not implemented");
    }

}

/**
 * RemoteCommandStore
 */
export class RemoteCommandStore extends RemoteCommandStoreInterface {
    // Use `init` to instantiate this class.
    // DO NOT USE THIS CONSTRUCTOR DIRECTLY
    constructor(opts) {
        super();
        if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) {
            throw new UniFFIError("Attempting to construct an int using the JavaScript constructor directly" +
            "Please use a UDL defined constructor, or the init function for the primary constructor")
        }
        if (!(opts[constructUniffiObject] instanceof UniFFIPointer)) {
            throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer")
        }
        this[uniffiObjectPtr] = opts[constructUniffiObject];
    }

    /**
     * Add a new command, after which it will be pending. Returns false if the command is already active.
     * @param {string} deviceId
     * @param {RemoteCommand[keyof RemoteCommand]} command
     * @returns {Promise<boolean>}}
     */
    async addRemoteCommand(
        deviceId, 
        command) {
       
        FfiConverterString.checkType(deviceId);
        FfiConverterTypeRemoteCommand.checkType(command);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            120, // uniffi_tabs_fn_method_remotecommandstore_add_remote_command
            FfiConverterTypeRemoteCommandStore.lowerReceiver(this),
            FfiConverterString.lower(deviceId),
            FfiConverterTypeRemoteCommand.lower(command),
        )
        return handleRustResult(
            result,
            FfiConverterBoolean.lift.bind(FfiConverterBoolean),
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * Add a new command with an explicit timestamp. Primarily used by tests.
     * @param {string} deviceId
     * @param {RemoteCommand[keyof RemoteCommand]} command
     * @param {Timestamp} when
     * @returns {Promise<boolean>}}
     */
    async addRemoteCommandAt(
        deviceId, 
        command, 
        when) {
       
        FfiConverterString.checkType(deviceId);
        FfiConverterTypeRemoteCommand.checkType(command);
        FfiConverterTypeTimestamp.checkType(when);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            121, // uniffi_tabs_fn_method_remotecommandstore_add_remote_command_at
            FfiConverterTypeRemoteCommandStore.lowerReceiver(this),
            FfiConverterString.lower(deviceId),
            FfiConverterTypeRemoteCommand.lower(command),
            FfiConverterTypeTimestamp.lower(when),
        )
        return handleRustResult(
            result,
            FfiConverterBoolean.lift.bind(FfiConverterBoolean),
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * Return all unsent commands. This is for the code sending the commands, result is sorted by time_requested.
     * @returns {Promise<Array.<PendingCommand>>}}
     */
    async getUnsentCommands() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            122, // uniffi_tabs_fn_method_remotecommandstore_get_unsent_commands
            FfiConverterTypeRemoteCommandStore.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            FfiConverterSequenceTypePendingCommand.lift.bind(FfiConverterSequenceTypePendingCommand),
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * Removes the remote command. Typically used to implement "undo" but may also be used by the queue
     * processor when it gives up trying to send a command.
     * @param {string} deviceId
     * @param {RemoteCommand[keyof RemoteCommand]} command
     * @returns {Promise<boolean>}}
     */
    async removeRemoteCommand(
        deviceId, 
        command) {
       
        FfiConverterString.checkType(deviceId);
        FfiConverterTypeRemoteCommand.checkType(command);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            123, // uniffi_tabs_fn_method_remotecommandstore_remove_remote_command
            FfiConverterTypeRemoteCommandStore.lowerReceiver(this),
            FfiConverterString.lower(deviceId),
            FfiConverterTypeRemoteCommand.lower(command),
        )
        return handleRustResult(
            result,
            FfiConverterBoolean.lift.bind(FfiConverterBoolean),
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * Flag a command as sent.
     * @param {PendingCommand} command
     * @returns {Promise<boolean>}}
     */
    async setPendingCommandSent(
        command) {
       
        FfiConverterTypePendingCommand.checkType(command);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            124, // uniffi_tabs_fn_method_remotecommandstore_set_pending_command_sent
            FfiConverterTypeRemoteCommandStore.lowerReceiver(this),
            FfiConverterTypePendingCommand.lower(command),
        )
        return handleRustResult(
            result,
            FfiConverterBoolean.lift.bind(FfiConverterBoolean),
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeRemoteCommandStore extends FfiConverter {
    static lift(value) {
        const opts = {};
        opts[constructUniffiObject] = value;
        return new RemoteCommandStore(opts);
    }

    static lower(value) {
        const ptr = value[uniffiObjectPtr];
        if (!(ptr instanceof UniFFIPointer)) {
            throw new UniFFITypeError("Object is not a 'RemoteCommandStore' instance");
        }
        return ptr;
    }

    static lowerReceiver(value) {
        // This works exactly the same as lower for non-trait interfaces
        return this.lower(value);
    }

    static read(dataStream) {
        return this.lift(dataStream.readPointer(17));
    }

    static write(dataStream, value) {
        dataStream.writePointer(17, this.lower(value));
    }

    static computeSize(value) {
        return 8;
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterSequenceTypeTabsGuid extends FfiConverterArrayBuffer {
    static read(dataStream) {
        const len = dataStream.readInt32();
        const arr = [];
        for (let i = 0; i < len; i++) {
            arr.push(FfiConverterTypeTabsGuid.read(dataStream));
        }
        return arr;
    }

    static write(dataStream, value) {
        dataStream.writeInt32(value.length);
        value.forEach((innerValue) => {
            FfiConverterTypeTabsGuid.write(dataStream, innerValue);
        })
    }

    static computeSize(value) {
        // The size of the length
        let size = 4;
        for (const innerValue of value) {
            size += FfiConverterTypeTabsGuid.computeSize(innerValue);
        }
        return size;
    }

    static checkType(value) {
        if (!Array.isArray(value)) {
            throw new UniFFITypeError(`${value} is not an array`);
        }
        value.forEach((innerValue, idx) => {
            try {
                FfiConverterTypeTabsGuid.checkType(innerValue);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart(`[${idx}]`);
                }
                throw e;
            }
        })
    }
}

/**
 * Note the canonical docs for this are in https://searchfox.org/mozilla-central/source/services/interfaces/mozIBridgedSyncEngine.idl
 * It's only actually used in desktop, but it's fine to expose this everywhere.
 * NOTE: all timestamps here are milliseconds.
 */
export class TabsBridgedEngineInterface {
    /**
     * apply
     * @returns {Promise<Array.<string>>}}
     */
    async apply() {
      throw Error("apply not implemented");
    }
    /**
     * ensureCurrentSyncId
     * @param {string} newSyncId
     * @returns {Promise<string>}}
     */
    async ensureCurrentSyncId(
        newSyncId) {
      throw Error("ensureCurrentSyncId not implemented");
    }
    /**
     * lastSync
     * @returns {Promise<number>}}
     */
    async lastSync() {
      throw Error("lastSync not implemented");
    }
    /**
     * prepareForSync
     * @param {string} clientData
     */
    async prepareForSync(
        clientData) {
      throw Error("prepareForSync not implemented");
    }
    /**
     * reset
     */
    async reset() {
      throw Error("reset not implemented");
    }
    /**
     * resetSyncId
     * @returns {Promise<string>}}
     */
    async resetSyncId() {
      throw Error("resetSyncId not implemented");
    }
    /**
     * setLastSync
     * @param {number} lastSync
     */
    async setLastSync(
        lastSync) {
      throw Error("setLastSync not implemented");
    }
    /**
     * setUploaded
     * @param {number} newTimestamp
     * @param {Array.<TabsGuid>} uploadedIds
     */
    async setUploaded(
        newTimestamp, 
        uploadedIds) {
      throw Error("setUploaded not implemented");
    }
    /**
     * storeIncoming
     * @param {Array.<string>} incomingEnvelopesAsJson
     */
    async storeIncoming(
        incomingEnvelopesAsJson) {
      throw Error("storeIncoming not implemented");
    }
    /**
     * syncFinished
     */
    async syncFinished() {
      throw Error("syncFinished not implemented");
    }
    /**
     * syncId
     * @returns {Promise<?string>}}
     */
    async syncId() {
      throw Error("syncId not implemented");
    }
    /**
     * syncStarted
     */
    async syncStarted() {
      throw Error("syncStarted not implemented");
    }
    /**
     * wipe
     */
    async wipe() {
      throw Error("wipe not implemented");
    }

}

/**
 * Note the canonical docs for this are in https://searchfox.org/mozilla-central/source/services/interfaces/mozIBridgedSyncEngine.idl
 * It's only actually used in desktop, but it's fine to expose this everywhere.
 * NOTE: all timestamps here are milliseconds.
 */
export class TabsBridgedEngine extends TabsBridgedEngineInterface {
    // Use `init` to instantiate this class.
    // DO NOT USE THIS CONSTRUCTOR DIRECTLY
    constructor(opts) {
        super();
        if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) {
            throw new UniFFIError("Attempting to construct an int using the JavaScript constructor directly" +
            "Please use a UDL defined constructor, or the init function for the primary constructor")
        }
        if (!(opts[constructUniffiObject] instanceof UniFFIPointer)) {
            throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer")
        }
        this[uniffiObjectPtr] = opts[constructUniffiObject];
    }

    /**
     * apply
     * @returns {Promise<Array.<string>>}}
     */
    async apply() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            125, // uniffi_tabs_fn_method_tabsbridgedengine_apply
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            FfiConverterSequenceString.lift.bind(FfiConverterSequenceString),
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * ensureCurrentSyncId
     * @param {string} newSyncId
     * @returns {Promise<string>}}
     */
    async ensureCurrentSyncId(
        newSyncId) {
       
        FfiConverterString.checkType(newSyncId);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            126, // uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
            FfiConverterString.lower(newSyncId),
        )
        return handleRustResult(
            result,
            FfiConverterString.lift.bind(FfiConverterString),
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * lastSync
     * @returns {Promise<number>}}
     */
    async lastSync() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            127, // uniffi_tabs_fn_method_tabsbridgedengine_last_sync
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            FfiConverterInt64.lift.bind(FfiConverterInt64),
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * prepareForSync
     * @param {string} clientData
     */
    async prepareForSync(
        clientData) {
       
        FfiConverterString.checkType(clientData);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            128, // uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
            FfiConverterString.lower(clientData),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * reset
     */
    async reset() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            129, // uniffi_tabs_fn_method_tabsbridgedengine_reset
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * resetSyncId
     * @returns {Promise<string>}}
     */
    async resetSyncId() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            130, // uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            FfiConverterString.lift.bind(FfiConverterString),
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * setLastSync
     * @param {number} lastSync
     */
    async setLastSync(
        lastSync) {
       
        FfiConverterInt64.checkType(lastSync);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            131, // uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
            FfiConverterInt64.lower(lastSync),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * setUploaded
     * @param {number} newTimestamp
     * @param {Array.<TabsGuid>} uploadedIds
     */
    async setUploaded(
        newTimestamp, 
        uploadedIds) {
       
        FfiConverterInt64.checkType(newTimestamp);
        FfiConverterSequenceTypeTabsGuid.checkType(uploadedIds);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            132, // uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
            FfiConverterInt64.lower(newTimestamp),
            FfiConverterSequenceTypeTabsGuid.lower(uploadedIds),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * storeIncoming
     * @param {Array.<string>} incomingEnvelopesAsJson
     */
    async storeIncoming(
        incomingEnvelopesAsJson) {
       
        FfiConverterSequenceString.checkType(incomingEnvelopesAsJson);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            133, // uniffi_tabs_fn_method_tabsbridgedengine_store_incoming
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
            FfiConverterSequenceString.lower(incomingEnvelopesAsJson),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * syncFinished
     */
    async syncFinished() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            134, // uniffi_tabs_fn_method_tabsbridgedengine_sync_finished
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * syncId
     * @returns {Promise<?string>}}
     */
    async syncId() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            135, // uniffi_tabs_fn_method_tabsbridgedengine_sync_id
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            FfiConverterOptionalString.lift.bind(FfiConverterOptionalString),
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * syncStarted
     */
    async syncStarted() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            136, // uniffi_tabs_fn_method_tabsbridgedengine_sync_started
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

    /**
     * wipe
     */
    async wipe() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            137, // uniffi_tabs_fn_method_tabsbridgedengine_wipe
            FfiConverterTypeTabsBridgedEngine.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            FfiConverterTypeTabsApiError.lift.bind(FfiConverterTypeTabsApiError),
        )
    }

}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeTabsBridgedEngine extends FfiConverter {
    static lift(value) {
        const opts = {};
        opts[constructUniffiObject] = value;
        return new TabsBridgedEngine(opts);
    }

    static lower(value) {
        const ptr = value[uniffiObjectPtr];
        if (!(ptr instanceof UniFFIPointer)) {
            throw new UniFFITypeError("Object is not a 'TabsBridgedEngine' instance");
        }
        return ptr;
    }

    static lowerReceiver(value) {
        // This works exactly the same as lower for non-trait interfaces
        return this.lower(value);
    }

    static read(dataStream) {
        return this.lift(dataStream.readPointer(18));
    }

    static write(dataStream, value) {
        dataStream.writePointer(18, this.lower(value));
    }

    static computeSize(value) {
        return 8;
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterSequenceTypeClientRemoteTabs extends FfiConverterArrayBuffer {
    static read(dataStream) {
        const len = dataStream.readInt32();
        const arr = [];
        for (let i = 0; i < len; i++) {
            arr.push(FfiConverterTypeClientRemoteTabs.read(dataStream));
        }
        return arr;
    }

    static write(dataStream, value) {
        dataStream.writeInt32(value.length);
        value.forEach((innerValue) => {
            FfiConverterTypeClientRemoteTabs.write(dataStream, innerValue);
        })
    }

    static computeSize(value) {
        // The size of the length
        let size = 4;
        for (const innerValue of value) {
            size += FfiConverterTypeClientRemoteTabs.computeSize(innerValue);
        }
        return size;
    }

    static checkType(value) {
        if (!Array.isArray(value)) {
            throw new UniFFITypeError(`${value} is not an array`);
        }
        value.forEach((innerValue, idx) => {
            try {
                FfiConverterTypeClientRemoteTabs.checkType(innerValue);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart(`[${idx}]`);
                }
                throw e;
            }
        })
    }
}

/**
 * TabsStoreInterface
 */
export class TabsStoreInterface {
    /**
     * bridgedEngine
     * @returns {Promise<TabsBridgedEngine>}}
     */
    async bridgedEngine() {
      throw Error("bridgedEngine not implemented");
    }
    /**
     * closeConnection
     */
    async closeConnection() {
      throw Error("closeConnection not implemented");
    }
    /**
     * getAll
     * @returns {Promise<Array.<ClientRemoteTabs>>}}
     */
    async getAll() {
      throw Error("getAll not implemented");
    }
    /**
     * newRemoteCommandStore
     * @returns {Promise<RemoteCommandStore>}}
     */
    async newRemoteCommandStore() {
      throw Error("newRemoteCommandStore not implemented");
    }
    /**
     * registerWithSyncManager
     */
    async registerWithSyncManager() {
      throw Error("registerWithSyncManager not implemented");
    }
    /**
     * An API for clients which know nothing about windows or tab groups.
     * @param {Array.<RemoteTabRecord>} remoteTabs
     */
    async setLocalTabs(
        remoteTabs) {
      throw Error("setLocalTabs not implemented");
    }
    /**
     * More context-aware API for setting information about a tab like window and groups.
     * @param {LocalTabsInfo} info
     */
    async setLocalTabsInfo(
        info) {
      throw Error("setLocalTabsInfo not implemented");
    }

}

/**
 * TabsStore
 */
export class TabsStore extends TabsStoreInterface {
    // Use `init` to instantiate this class.
    // DO NOT USE THIS CONSTRUCTOR DIRECTLY
    constructor(opts) {
        super();
        if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) {
            throw new UniFFIError("Attempting to construct an int using the JavaScript constructor directly" +
            "Please use a UDL defined constructor, or the init function for the primary constructor")
        }
        if (!(opts[constructUniffiObject] instanceof UniFFIPointer)) {
            throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer")
        }
        this[uniffiObjectPtr] = opts[constructUniffiObject];
    }
    /**
     * init
     * @param {string} path
     * @returns {Promise<TabsStore>}}
     */
    static async init(
        path) {
       
        FfiConverterString.checkType(path);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            138, // uniffi_tabs_fn_constructor_tabsstore_new
            FfiConverterString.lower(path),
        )
        return handleRustResult(
            result,
            FfiConverterTypeTabsStore.lift.bind(FfiConverterTypeTabsStore),
            null,
        )
    }

    /**
     * bridgedEngine
     * @returns {Promise<TabsBridgedEngine>}}
     */
    async bridgedEngine() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            139, // uniffi_tabs_fn_method_tabsstore_bridged_engine
            FfiConverterTypeTabsStore.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            FfiConverterTypeTabsBridgedEngine.lift.bind(FfiConverterTypeTabsBridgedEngine),
            null,
        )
    }

    /**
     * closeConnection
     */
    async closeConnection() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            140, // uniffi_tabs_fn_method_tabsstore_close_connection
            FfiConverterTypeTabsStore.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            null,
        )
    }

    /**
     * getAll
     * @returns {Promise<Array.<ClientRemoteTabs>>}}
     */
    async getAll() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            141, // uniffi_tabs_fn_method_tabsstore_get_all
            FfiConverterTypeTabsStore.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            FfiConverterSequenceTypeClientRemoteTabs.lift.bind(FfiConverterSequenceTypeClientRemoteTabs),
            null,
        )
    }

    /**
     * newRemoteCommandStore
     * @returns {Promise<RemoteCommandStore>}}
     */
    async newRemoteCommandStore() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            142, // uniffi_tabs_fn_method_tabsstore_new_remote_command_store
            FfiConverterTypeTabsStore.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            FfiConverterTypeRemoteCommandStore.lift.bind(FfiConverterTypeRemoteCommandStore),
            null,
        )
    }

    /**
     * registerWithSyncManager
     */
    async registerWithSyncManager() {
       
        const result = await UniFFIScaffolding.callAsyncWrapper(
            143, // uniffi_tabs_fn_method_tabsstore_register_with_sync_manager
            FfiConverterTypeTabsStore.lowerReceiver(this),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            null,
        )
    }

    /**
     * An API for clients which know nothing about windows or tab groups.
     * @param {Array.<RemoteTabRecord>} remoteTabs
     */
    async setLocalTabs(
        remoteTabs) {
       
        FfiConverterSequenceTypeRemoteTabRecord.checkType(remoteTabs);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            144, // uniffi_tabs_fn_method_tabsstore_set_local_tabs
            FfiConverterTypeTabsStore.lowerReceiver(this),
            FfiConverterSequenceTypeRemoteTabRecord.lower(remoteTabs),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            null,
        )
    }

    /**
     * More context-aware API for setting information about a tab like window and groups.
     * @param {LocalTabsInfo} info
     */
    async setLocalTabsInfo(
        info) {
       
        FfiConverterTypeLocalTabsInfo.checkType(info);
        const result = await UniFFIScaffolding.callAsyncWrapper(
            145, // uniffi_tabs_fn_method_tabsstore_set_local_tabs_info
            FfiConverterTypeTabsStore.lowerReceiver(this),
            FfiConverterTypeLocalTabsInfo.lower(info),
        )
        return handleRustResult(
            result,
            (result) => undefined,
            null,
        )
    }

}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeTabsStore extends FfiConverter {
    static lift(value) {
        const opts = {};
        opts[constructUniffiObject] = value;
        return new TabsStore(opts);
    }

    static lower(value) {
        const ptr = value[uniffiObjectPtr];
        if (!(ptr instanceof UniFFIPointer)) {
            throw new UniFFITypeError("Object is not a 'TabsStore' instance");
        }
        return ptr;
    }

    static lowerReceiver(value) {
        // This works exactly the same as lower for non-trait interfaces
        return this.lower(value);
    }

    static read(dataStream) {
        return this.lift(dataStream.readPointer(19));
    }

    static write(dataStream, value) {
        dataStream.writePointer(19, this.lower(value));
    }

    static computeSize(value) {
        return 8;
    }
}





