/* BOM */

declare class Screen {
    +availHeight: number;
    +availWidth: number;
    +availLeft: number;
    +availTop: number;
    +top: number;
    +left: number;
    +colorDepth: number;
    +pixelDepth: number;
    +width: number;
    +height: number;
    +orientation?: {
      lock(): Promise<void>;
      unlock(): void;
      angle: number;
      onchange: () => mixed;
      type: 'portrait-primary' | 'portrait-secondary' | 'landscape-primary' | 'landscape-secondary';
      ...
    };
    // deprecated
    mozLockOrientation?: (orientation: string | Array<string>) => boolean;
    mozUnlockOrientation?: () => void;
    mozOrientation?: string;
    onmozorientationchange?: (...args: any[]) => mixed;
  }
  
  declare var screen: Screen;
  
  declare interface Crypto {
    // Not using $TypedArray as that would include Float32Array and Float64Array which are not accepted
    getRandomValues: <
      T: Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | BigInt64Array | BigUint64Array
    >(typedArray: T) => T;
    randomUUID: () => string;
  }
  declare var crypto: Crypto;
  
  declare var window: any;
  
  type GamepadButton = {
    pressed: boolean,
    value: number,
    ...
  }
  type GamepadHapticActuator = {
    type: 'vibration',
    pulse(value: number, duration: number): Promise<boolean>,
    ...
  }
  type GamepadPose = {
    angularAcceleration: null | Float32Array,
    angularVelocity: null | Float32Array,
    hasOrientation: boolean,
    hasPosition: boolean,
    linearAcceleration: null | Float32Array,
    linearVelocity: null | Float32Array,
    orientation: null | Float32Array,
    position: null | Float32Array,
    ...
  }
  type Gamepad = {
    axes: number[],
    buttons: GamepadButton[],
    connected: boolean,
    displayId?: number,
    hapticActuators?: GamepadHapticActuator[],
    hand?: '' | 'left' | 'right',
    id: string,
    index: number,
    mapping: string,
    pose?: null | GamepadPose,
    timestamp: number,
    ...
  }
  
  // deprecated
  type BatteryManager = {
    +charging: boolean,
    +chargingTime: number,
    +dischargingTime: number,
    +level: number,
    onchargingchange: ?((event: any) => mixed),
    onchargingtimechange: ?((event: any) => mixed),
    ondischargingtimechange: ?((event: any) => mixed),
    onlevelchange: ?((event: any) => mixed),
    ...
  }
  
  // https://wicg.github.io/web-share
  type ShareData = {
    title?: string,
    text?: string,
    url?: string,
    ...
  }
  
  type PermissionName =
    | "geolocation"
    | "notifications"
    | "push"
    | "midi"
    | "camera"
    | "microphone"
    | "speaker"
    | "usb"
    | "device-info"
    | "background-sync"
    | "bluetooth"
    | "persistent-storage"
    | "ambient-light-sensor"
    | "accelerometer"
    | "gyroscope"
    | "magnetometer"
    | "clipboard-read"
    | "clipboard-write";
  
  type PermissionState =
    | "granted"
    | "denied"
    | "prompt";
  
  type PermissionDescriptor = {|
    name: PermissionName;
  |}
  
  type DevicePermissionDescriptor = {|
    deviceId?: string;
    name: "camera" | "microphone" | "speaker";
  |}
  
  type MidiPermissionDescriptor = {|
    name: "midi";
    sysex?: boolean;
  |}
  
  type PushPermissionDescriptor = {|
    name: "push";
    userVisibleOnly?: boolean;
  |}
  
  type ClipboardPermissionDescriptor = {|
    name: "clipboard-read" | "clipboard-write";
    allowWithoutGesture: boolean;
  |}
  
  type USBPermissionDescriptor = {|
    name: "usb";
    filters: Array<USBDeviceFilter>;
    exclusionFilters: Array<USBDeviceFilter>;
  |}
  
  type FileSystemHandlePermissionDescriptor = {|
    mode: "read" | "readwrite";
  |}
  
  declare class PermissionStatus extends EventTarget {
    onchange: ?((event: any) => mixed);
    +state: PermissionState;
  }
  
  declare class Permissions {
    query(
      permissionDesc:
        | DevicePermissionDescriptor
        | MidiPermissionDescriptor
        | PushPermissionDescriptor
        | ClipboardPermissionDescriptor
        | USBPermissionDescriptor
        | PermissionDescriptor
    ): Promise<PermissionStatus>;
  }
  
  type MIDIPortType = 'input' | 'output';
  type MIDIPortDeviceState = 'connected' | 'disconnected';
  type MIDIPortConnectionState = 'open' | 'closed' | 'pending';
  
  type MIDIOptions = {|
    sysex: boolean;
    software: boolean;
  |}
  
  type MIDIMessageEvent$Init = Event$Init & {
    data: Uint8Array;
    ...
  }
  
  declare class MIDIMessageEvent extends Event {
    constructor(type: string, eventInitDict: MIDIMessageEvent$Init): void;
    +data: Uint8Array;
  }
  
  type MIDIConnectionEvent$Init = Event$Init & {
    port: MIDIPort;
    ...
  }
  
  declare class MIDIConnectionEvent extends Event {
    constructor(type: string, eventInitDict: MIDIConnectionEvent$Init): void;
    +port: MIDIPort;
  }
  
  declare class MIDIPort extends EventTarget {
    +id: string;
    +manufacturer?: string;
    +name?: string;
    +type: MIDIPortType;
    +version?: string;
    +state: MIDIPortDeviceState;
    +connection: MIDIPortConnectionState;
    onstatechange: ?((ev: MIDIConnectionEvent) => mixed);
    open(): Promise<MIDIPort>;
    close(): Promise<MIDIPort>;
  }
  
  declare class MIDIInput extends MIDIPort {
    onmidimessage: ?((ev: MIDIMessageEvent) => mixed);
  }
  
  declare class MIDIOutput extends MIDIPort {
    send(data: Iterable<number>, timestamp?: number): void;
    clear(): void;
  }
  
  declare class MIDIInputMap extends $ReadOnlyMap<string, MIDIInput> {}
  
  declare class MIDIOutputMap extends $ReadOnlyMap<string, MIDIOutput> {}
  
  declare class MIDIAccess extends EventTarget {
    +inputs: MIDIInputMap;
    +outputs: MIDIOutputMap;
    +sysexEnabled: boolean;
    onstatechange: ?((ev: MIDIConnectionEvent) => mixed);
  }
  
  declare class NavigatorID {
      appName: 'Netscape';
      appCodeName: 'Mozilla';
      product: 'Gecko';
      appVersion: string;
      platform: string;
      userAgent: string;
  }
  
  declare class NavigatorLanguage {
      +language: string;
      +languages: $ReadOnlyArray<string>;
  }
  
  declare class NavigatorContentUtils {
      registerContentHandler(mimeType: string, uri: string, title: string): void;
      registerProtocolHandler(protocol: string, uri: string, title: string): void;
  }
  
  declare class NavigatorCookies {
      +cookieEnabled: boolean;
  }
  
  declare class NavigatorPlugins {
      +plugins: PluginArray;
      +mimeTypes: MimeTypeArray;
      javaEnabled(): boolean;
  }
  
  declare class NavigatorOnLine {
      +onLine: boolean;
  }
  
  declare class NavigatorConcurrentHardware {
      +hardwareConcurrency: number;
  }
  
  declare class NavigatorStorage {
    storage?: StorageManager
  }
  
  declare class StorageManager {
    persist: () => Promise<boolean>;
    persisted: () => Promise<boolean>;
    estimate?: () => Promise<StorageEstimate>;
    getDirectory: () => Promise<FileSystemDirectoryHandle>;
  }
  
  type StorageManagerRegisteredEndpoint = 'caches' | 'indexedDB' | 'localStorage' | 'serviceWorkerRegistrations' | 'sessionStorage';
  
  type StorageManagerUsageDetails = {[StorageManagerRegisteredEndpoint]: number};
  
  declare class StorageEstimate {
    constructor(usage: number, quota: number, usageDetails?: StorageManagerUsageDetails): void;
    +usage: number;
    +quota: number;
  
    // Not a part of the standard
    +usageDetails?: StorageManagerUsageDetails;
  }
  
  declare class Navigator mixins
    NavigatorID,
    NavigatorLanguage,
    NavigatorOnLine,
    NavigatorContentUtils,
    NavigatorCookies,
    NavigatorPlugins,
    NavigatorConcurrentHardware,
    NavigatorStorage {
      productSub: '20030107' | '20100101';
      vendor: '' | 'Google Inc.' | 'Apple Computer, Inc';
      vendorSub: '';
  
      activeVRDisplays?: VRDisplay[];
      appCodeName: 'Mozilla';
      buildID: string;
      doNotTrack: string | null;
      geolocation: Geolocation;
      mediaDevices?: MediaDevices;
      usb?: USB;
      maxTouchPoints: number;
      permissions: Permissions;
      serviceWorker?: $FlowFixMe;
      getGamepads?: () => Array<Gamepad | null>;
      webkitGetGamepads?: Function;
      mozGetGamepads?: Function;
      mozGamepads?: any;
      gamepads?: any;
      webkitGamepads?: any;
      getVRDisplays?: () => Promise<VRDisplay[]>;
      registerContentHandler(mimeType: string, uri: string, title: string): void;
      registerProtocolHandler(protocol: string, uri: string, title: string): void;
      requestMIDIAccess?: (options?: MIDIOptions) => Promise<MIDIAccess>;
      requestMediaKeySystemAccess?: (keySystem: string, supportedConfigurations: any[]) => Promise<any>;
      sendBeacon?: (url: string, data?: BodyInit) => boolean;
      vibrate?: (pattern: number | number[]) => boolean;
      mozVibrate?: (pattern: number | number[]) => boolean;
      webkitVibrate?: (pattern: number | number[]) => boolean;
      canShare?: (shareData?: ShareData) => boolean;
      share?: (shareData: ShareData) => Promise<void>;
      clipboard: Clipboard;
      credentials?: CredMgmtCredentialsContainer;
      globalPrivacyControl?: boolean;
  
      // deprecated
      getBattery?: () => Promise<BatteryManager>;
      mozGetBattery?: () => Promise<BatteryManager>;
  
      // deprecated
      getUserMedia?: Function;
      webkitGetUserMedia?: Function;
      mozGetUserMedia?: Function;
      msGetUserMedia?: Function;
  
      // Gecko
      taintEnabled?: () => false;
      oscpu: string;
  }
  
  declare class Clipboard extends EventTarget {
      read(): Promise<DataTransfer>;
      readText(): Promise<string>;
      write(data: $ReadOnlyArray<ClipboardItem>): Promise<void>;
      writeText(data: string): Promise<void>;
  }
  
  declare var navigator: Navigator;
  
  declare class MimeType {
      type: string;
      description: string;
      suffixes: string;
      enabledPlugin: Plugin;
  }
  
  declare class MimeTypeArray {
      length: number;
      item(index: number): MimeType;
      namedItem(name: string): MimeType;
      [key: number | string]: MimeType;
  }
  
  declare class Plugin {
      description: string;
      filename: string;
      name: string;
      version?: string; // Gecko only
      length: number;
      item(index: number): MimeType;
      namedItem(name: string): MimeType;
      [key: number | string]: MimeType;
  }
  
  declare class PluginArray {
      length: number;
      item(index: number): Plugin;
      namedItem(name: string): Plugin;
      refresh(): void;
      [key: number | string]: Plugin;
  }
  
  // https://www.w3.org/TR/hr-time-2/#dom-domhighrestimestamp
  // https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp
  declare type DOMHighResTimeStamp = number;
  
  // https://www.w3.org/TR/navigation-timing-2/
  declare class PerformanceTiming {
      connectEnd: number;
      connectStart: number;
      domainLookupEnd: number;
      domainLookupStart: number;
      domComplete: number;
      domContentLoadedEventEnd: number;
      domContentLoadedEventStart: number;
      domInteractive: number;
      domLoading: number;
      fetchStart: number;
      loadEventEnd: number;
      loadEventStart: number;
      navigationStart: number;
      redirectEnd: number;
      redirectStart: number;
      requestStart: number;
      responseEnd: number;
      responseStart: number;
      secureConnectionStart: number;
      unloadEventEnd: number;
      unloadEventStart: number;
  }
  
  declare class PerformanceNavigation {
      TYPE_NAVIGATE: 0;
      TYPE_RELOAD: 1;
      TYPE_BACK_FORWARD: 2;
      TYPE_RESERVED: 255;
  
      type: 0 | 1 | 2 | 255;
      redirectCount: number;
  }
  
  type PerformanceEntryFilterOptions = {
    name: string,
    entryType: string,
    initiatorType: string,
    ...
  }
  
  // https://www.w3.org/TR/performance-timeline-2/
  declare class PerformanceEntry {
      name: string;
      entryType: string;
      startTime: DOMHighResTimeStamp;
      duration: DOMHighResTimeStamp;
      toJSON(): string;
  }
  
  // https://w3c.github.io/server-timing/#the-performanceservertiming-interface
  declare class PerformanceServerTiming {
    description: string;
    duration: DOMHighResTimeStamp;
    name: string;
    toJSON(): string;
  }
  
  // https://www.w3.org/TR/resource-timing-2/#sec-performanceresourcetiming
  // https://w3c.github.io/server-timing/#extension-to-the-performanceresourcetiming-interface
  declare class PerformanceResourceTiming extends PerformanceEntry {
      initiatorType: string;
      nextHopProtocol: string;
      workerStart: number;
      redirectStart: number;
      redirectEnd: number;
      fetchStart: number;
      domainLookupStart: number;
      domainLookupEnd: number;
      connectStart: number;
      connectEnd: number;
      secureConnectionStart: number;
      requestStart: number;
      responseStart: number;
      responseEnd: number;
      transferSize: string;
      encodedBodySize: number;
      decodedBodySize: number;
      serverTiming: Array<PerformanceServerTiming>;
  }
  
  // https://w3c.github.io/event-timing/#sec-performance-event-timing
  declare class PerformanceEventTiming extends PerformanceEntry {
    processingStart: number;
    processingEnd: number;
    cancelable: boolean;
    target: ?Node;
    interactionId: number;
  }
  
  // https://w3c.github.io/longtasks/#taskattributiontiming
  declare class TaskAttributionTiming extends PerformanceEntry {
    containerType: string;
    containerSrc: string;
    containerId: string;
    containerName: string;
  }
  
  // https://w3c.github.io/longtasks/#sec-PerformanceLongTaskTiming
  declare class PerformanceLongTaskTiming extends PerformanceEntry {
    attribution: $ReadOnlyArray<TaskAttributionTiming>;
  }
  
  // https://www.w3.org/TR/navigation-timing-2/
  declare class PerformanceNavigationTiming extends PerformanceResourceTiming {
      unloadEventStart: number;
      unloadEventEnd: number;
      domInteractive: number;
      domContentLoadedEventStart: number;
      domContentLoadedEventEnd: number;
      domComplete: number;
      loadEventStart: number;
      loadEventEnd: number;
      type: 'navigate' | 'reload' | 'back_forward' | 'prerender';
      redirectCount: number;
  }
  
  // https://www.w3.org/TR/user-timing/#extensions-performance-interface
  declare type PerformanceMarkOptions = {|
    detail?: mixed,
    startTime?: number,
  |};
  
  declare type PerformanceMeasureOptions = {|
    detail?: mixed,
    start?: number | string,
    end?: number | string,
    duration?: number,
  |};
  
  
  type EventCountsForEachCallbackType =
    | (() => void)
    | ((value: number) => void)
    | ((value: number, key: string) => void)
    | ((value: number, key: string, map: Map<string, number>) => void);
  
  // https://www.w3.org/TR/event-timing/#eventcounts
  declare interface EventCounts {
    size: number;
  
    entries(): Iterator<[string, number]>;
    forEach(callback: EventCountsForEachCallbackType): void;
    get(key: string): ?number;
    has(key: string): boolean;
    keys(): Iterator<string>;
    values(): Iterator<number>;
  }
  
  declare class Performance {
      eventCounts: EventCounts;
  
      // deprecated
      navigation: PerformanceNavigation;
      timing: PerformanceTiming;
  
      onresourcetimingbufferfull: (ev: any) => mixed;
      clearMarks(name?: string): void;
      clearMeasures(name?: string): void;
      clearResourceTimings(): void;
      getEntries(options?: PerformanceEntryFilterOptions): Array<PerformanceEntry>;
      getEntriesByName(name: string, type?: string): Array<PerformanceEntry>;
      getEntriesByType(type: string): Array<PerformanceEntry>;
      mark(name: string, options?: PerformanceMarkOptions): void;
      measure(name: string, startMarkOrOptions?: string | PerformanceMeasureOptions, endMark?: string): void;
      now(): DOMHighResTimeStamp;
      setResourceTimingBufferSize(maxSize: number): void;
      toJSON(): string;
  }
  
  declare var performance: Performance;
  
  type PerformanceEntryList = PerformanceEntry[];
  
  declare interface PerformanceObserverEntryList {
    getEntries(): PerformanceEntryList;
    getEntriesByType(type: string): PerformanceEntryList;
    getEntriesByName(name: string, type: ?string): PerformanceEntryList;
  }
  
  type PerformanceObserverInit = {
    entryTypes?: string[];
    type?: string;
    buffered?: boolean;
    ...
  }
  
  declare class PerformanceObserver {
    constructor(callback: (entries: PerformanceObserverEntryList, observer: PerformanceObserver) => mixed): void;
  
    observe(options: ?PerformanceObserverInit): void;
    disconnect(): void;
    takeRecords(): PerformanceEntryList;
  
    static supportedEntryTypes: string[];
  }
  
  declare class History {
      length: number;
      scrollRestoration: 'auto' | 'manual';
      state: any;
      back(): void;
      forward(): void;
      go(delta?: number): void;
      pushState(statedata: any, title: string, url?: string): void;
      replaceState(statedata: any, title: string, url?: string): void;
  }
  
  declare var history: History;
  
  declare class Location {
      ancestorOrigins: string[];
      hash: string;
      host: string;
      hostname: string;
      href: string;
      origin: string;
      pathname: string;
      port: string;
      protocol: string;
      search: string;
      assign(url: string): void;
      reload(flag?: boolean): void;
      replace(url: string): void;
      toString(): string;
  }
  
  declare var location: Location;
  
  ///////////////////////////////////////////////////////////////////////////////
  
  declare class DOMParser {
      parseFromString(source: string | TrustedHTML, mimeType: string): Document;
  }
  
  type FormDataEntryValue = string | File
  
  declare class FormData {
      constructor(form?: HTMLFormElement, submitter?: HTMLElement | null): void;
  
      has(name: string): boolean;
      get(name: string): ?FormDataEntryValue;
      getAll(name: string): Array<FormDataEntryValue>;
  
      set(name: string, value: string): void;
      set(name: string, value: Blob, filename?: string): void;
      set(name: string, value: File, filename?: string): void;
  
      append(name: string, value: string): void;
      append(name: string, value: Blob, filename?: string): void;
      append(name: string, value: File, filename?: string): void;
  
      delete(name: string): void;
  
      keys(): Iterator<string>;
      values(): Iterator<FormDataEntryValue>;
      entries(): Iterator<[string, FormDataEntryValue]>;
  }
  
  declare class MutationRecord {
      type: 'attributes' | 'characterData' | 'childList';
      target: Node;
      addedNodes: NodeList<Node>;
      removedNodes: NodeList<Node>;
      previousSibling: ?Node;
      nextSibling: ?Node;
      attributeName: ?string;
      attributeNamespace: ?string;
      oldValue: ?string;
  }
  
  type MutationObserverInitRequired =
      | { childList: true, ... }
      | { attributes: true, ... }
      | { characterData: true, ... }
  
  declare type MutationObserverInit = MutationObserverInitRequired & {
    subtree?: boolean,
    attributeOldValue?: boolean,
    characterDataOldValue?: boolean,
    attributeFilter?: Array<string>,
    ...
  }
  
  declare class MutationObserver {
      constructor(callback: (arr: Array<MutationRecord>, observer: MutationObserver) => mixed): void;
      observe(target: Node, options: MutationObserverInit): void;
      takeRecords(): Array<MutationRecord>;
      disconnect(): void;
  }
  
  declare class DOMRectReadOnly {
    static fromRect(rectangle?: {
      x: number,
      y: number,
      width: number,
      height: number,
      ...
    }): DOMRectReadOnly;
    constructor(x: number, y: number, width: number, height: number): void;
    +bottom: number;
    +height: number;
    +left: number;
    +right: number;
    +top: number;
    +width: number;
    +x: number;
    +y: number;
  }
  
  declare class DOMRect extends DOMRectReadOnly {
    static fromRect(rectangle?: {
      x: number,
      y: number,
      width: number,
      height: number,
      ...
    }): DOMRect;
    bottom: number;
    height: number;
    left: number;
    right: number;
    top: number;
    width: number;
    x: number;
    y: number;
  }
  
  declare class DOMRectList {
    @@iterator(): Iterator<DOMRect>;
    length: number;
    item(index: number): DOMRect;
    [index: number]: DOMRect;
  }
  
  declare type IntersectionObserverEntry = {
    boundingClientRect: DOMRectReadOnly,
    intersectionRatio: number,
    intersectionRect: DOMRectReadOnly,
    isIntersecting: boolean,
    rootBounds: DOMRectReadOnly,
    target: Element,
    time: DOMHighResTimeStamp,
    ...
  };
  
  declare type IntersectionObserverCallback = (
      entries: Array<IntersectionObserverEntry>,
      observer: IntersectionObserver,
  ) => mixed;
  
  declare type IntersectionObserverOptions = {
    root?: Node | null,
    rootMargin?: string,
    threshold?: number | Array<number>,
    ...
  };
  
  declare class IntersectionObserver {
      constructor(
        callback: IntersectionObserverCallback,
        options?: IntersectionObserverOptions
      ): void,
      root: Element | null;
      rootMargin: string;
      scrollMargin: string;
      thresholds: number[];
      observe(target: Element): void,
      unobserve(target: Element): void,
      takeRecords(): Array<IntersectionObserverEntry>,
      disconnect(): void,
  }
  
  declare interface ResizeObserverSize {
    +inlineSize: number;
    +blockSize: number;
  }
  
  declare interface ResizeObserverEntry {
    /**
     * The Element whose size has changed.
     */
    +target: Element;
    /**
     * Element's content rect when ResizeObserverCallback is invoked.
     *
     * Legacy, may be deprecated in the future.
     */
    +contentRect: DOMRectReadOnly;
    /**
     * An array containing the Element's border box size when
     * ResizeObserverCallback is invoked.
     */
    +borderBoxSize: $ReadOnlyArray<ResizeObserverSize>;
    /**
     * An array containing the Element's content rect size when
     * ResizeObserverCallback is invoked.
     */
    +contentBoxSize: $ReadOnlyArray<ResizeObserverSize>;
    /**
     * An array containing the Element's content rect size in integral device
     * pixels when ResizeObserverCallback is invoked.
     *
     * Not implemented in Firefox or Safari as of July 2021
     */
    +devicePixelContentBoxSize?: $ReadOnlyArray<ResizeObserverSize> | void;
  }
  
  /**
   * ResizeObserver can observe different kinds of CSS sizes:
   * - border-box : size of box border area as defined in CSS2.
   * - content-box : size of content area as defined in CSS2.
   * - device-pixel-content-box : size of content area as defined in CSS2, in device
   *     pixels, before applying any CSS transforms on the element or its ancestors.
   *     This size must contain integer values.
   */
  type ResizeObserverBoxOptions = "border-box" | "content-box" | "device-pixel-content-box";
  
  declare type ResizeObserverOptions = {
    box?: ResizeObserverBoxOptions;
    ...
  };
  
  /**
   * The ResizeObserver interface is used to observe changes to Element's size.
   */
  declare class ResizeObserver {
    constructor(callback: (entries: ResizeObserverEntry[], observer: ResizeObserver) => mixed): void;
    /**
     * Adds target to the list of observed elements.
     */
    observe(target: Element, options?: ResizeObserverOptions): void;
    /**
     * Removes target from the list of observed elements.
     */
    unobserve(target: Element): void;
    disconnect(): void;
  }
  
  declare class CloseEvent extends Event {
      code: number;
      reason: string;
      wasClean: boolean;
  }
  
  declare class WebSocket extends EventTarget {
      static CONNECTING: 0;
      static OPEN: 1;
      static CLOSING: 2;
      static CLOSED: 3;
      constructor(url: string, protocols?: string | Array<string>): void;
      protocol: string;
      readyState: number;
      bufferedAmount: number;
      extensions: string;
      onopen: (ev: any) => mixed;
      onmessage: (ev: MessageEvent) => mixed;
      onclose: (ev: CloseEvent) => mixed;
      onerror: (ev: any) => mixed;
      binaryType: 'blob' | 'arraybuffer';
      url: string;
      close(code?: number, reason?: string): void;
      send(data: string): void;
      send(data: Blob): void;
      send(data: ArrayBuffer): void;
      send(data: $ArrayBufferView): void;
      CONNECTING: 0;
      OPEN: 1;
      CLOSING: 2;
      CLOSED: 3;
  }
  
  type WorkerOptions = {
    type?: $FlowFixMe,
    credentials?: CredentialsType,
    name?: string,
    ...
  }
  
  declare class Worker extends EventTarget {
      constructor(stringUrl: string | TrustedScriptURL, workerOptions?: WorkerOptions): void;
      onerror: null | (ev: any) => mixed;
      onmessage: null | (ev: MessageEvent) => mixed;
      onmessageerror: null | (ev: MessageEvent) => mixed;
      postMessage(message: any, ports?: any): void;
      terminate(): void;
  }
  
  declare class SharedWorker extends EventTarget {
      constructor(stringUrl: string | TrustedScriptURL, name?: string): void;
      constructor(stringUrl: string | TrustedScriptURL, workerOptions?: WorkerOptions): void;
      port: MessagePort;
      onerror: (ev: any) => mixed;
  }
  
  declare function importScripts(...urls: Array<string | TrustedScriptURL>): void;
  
  declare class WorkerGlobalScope extends EventTarget {
      self: this;
      location: WorkerLocation;
      navigator: WorkerNavigator;
      close(): void;
      importScripts(...urls: Array<string | TrustedScriptURL>): void;
      onerror: (ev: any) => mixed;
      onlanguagechange: (ev: any) => mixed;
      onoffline: (ev: any) => mixed;
      ononline: (ev: any) => mixed;
      onrejectionhandled: (ev: PromiseRejectionEvent) => mixed;
      onunhandledrejection: (ev: PromiseRejectionEvent) => mixed;
  }
  
  declare class DedicatedWorkerGlobalScope extends WorkerGlobalScope {
      onmessage: (ev: MessageEvent) => mixed;
      onmessageerror: (ev: MessageEvent) => mixed;
      postMessage(message: any, transfer?: Iterable<any>): void;
  }
  
  declare class SharedWorkerGlobalScope extends WorkerGlobalScope {
      name: string;
      onconnect: (ev: MessageEvent) => mixed;
  }
  
  declare class WorkerLocation {
      origin: string;
      protocol: string;
      host: string;
      hostname: string;
      port: string;
      pathname: string;
      search: string;
      hash: string;
  }
  
  declare class WorkerNavigator mixins
    NavigatorID,
    NavigatorLanguage,
    NavigatorOnLine,
    NavigatorConcurrentHardware,
    NavigatorStorage {
      permissions: Permissions;
    }
  
  
  // deprecated
  declare class XDomainRequest {
      timeout: number;
      onerror: () => mixed;
      onload: () => mixed;
      onprogress: () => mixed;
      ontimeout: () => mixed;
      +responseText: string;
      +contentType: string;
      open(method: "GET" | "POST", url: string): void;
      abort(): void;
      send(data?: string): void;
  
      statics: { create(): XDomainRequest, ... }
  }
  
  declare class XMLHttpRequest extends EventTarget {
      static LOADING: number;
      static DONE: number;
      static UNSENT: number;
      static OPENED: number;
      static HEADERS_RECEIVED: number;
      responseBody: any;
      status: number;
      readyState: number;
      responseText: string;
      responseXML: any;
      responseURL: string;
      ontimeout: ProgressEventHandler;
      statusText: string;
      onreadystatechange: (ev: any) => mixed;
      timeout: number;
      onload: ProgressEventHandler;
      response: any;
      withCredentials: boolean;
      onprogress: ProgressEventHandler;
      onabort: ProgressEventHandler;
      responseType: string;
      onloadend: ProgressEventHandler;
      upload: XMLHttpRequestEventTarget;
      onerror: ProgressEventHandler;
      onloadstart: ProgressEventHandler;
      msCaching: string;
      open(method: string, url: string, async?: boolean, user?: string, password?: string): void;
      send(data?: any): void;
      abort(): void;
      getAllResponseHeaders(): string;
      setRequestHeader(header: string, value: string): void;
      getResponseHeader(header: string): string;
      msCachingEnabled(): boolean;
      overrideMimeType(mime: string): void;
      LOADING: number;
      DONE: number;
      UNSENT: number;
      OPENED: number;
      HEADERS_RECEIVED: number;
  
      statics: { create(): XMLHttpRequest, ... }
  }
  
  declare class XMLHttpRequestEventTarget extends EventTarget {
      onprogress: ProgressEventHandler;
      onerror: ProgressEventHandler;
      onload: ProgressEventHandler;
      ontimeout: ProgressEventHandler;
      onabort: ProgressEventHandler;
      onloadstart: ProgressEventHandler;
      onloadend: ProgressEventHandler;
  }
  
  declare class XMLSerializer {
      serializeToString(target: Node): string;
  }
  
  declare class Geolocation {
      getCurrentPosition(
          success: (position: Position) => mixed,
          error?: (error: PositionError) => mixed,
          options?: PositionOptions
      ): void;
      watchPosition(
          success: (position: Position) => mixed,
          error?: (error: PositionError) => mixed,
          options?: PositionOptions
      ): number;
      clearWatch(id: number): void;
  }
  
  declare class Position {
      coords: Coordinates;
      timestamp: number;
  }
  
  declare class Coordinates {
      latitude: number;
      longitude: number;
      altitude?: number;
      accuracy: number;
      altitudeAccuracy?: number;
      heading?: number;
      speed?: number;
  }
  
  declare class PositionError {
      code: number;
      message: string;
      PERMISSION_DENIED: 1;
      POSITION_UNAVAILABLE: 2;
      TIMEOUT: 3;
  }
  
  type PositionOptions = {
    enableHighAccuracy?: boolean,
    timeout?: number,
    maximumAge?: number,
    ...
  }
  
  type AudioContextState = 'suspended' | 'running' | 'closed';
  
  // deprecated
  type AudioProcessingEvent$Init = Event$Init & {
    playbackTime: number;
    inputBuffer: AudioBuffer;
    outputBuffer: AudioBuffer;
    ...
  }
  
  // deprecated
  declare class AudioProcessingEvent extends Event {
    constructor(type: string, eventInitDict: AudioProcessingEvent$Init): void;
  
    +playbackTime: number;
    +inputBuffer: AudioBuffer;
    +outputBuffer: AudioBuffer;
  }
  
  type OfflineAudioCompletionEvent$Init = Event$Init & {
    renderedBuffer: AudioBuffer;
    ...
  }
  
  declare class OfflineAudioCompletionEvent extends Event {
    constructor(type: string, eventInitDict: OfflineAudioCompletionEvent$Init): void;
  
    +renderedBuffer: AudioBuffer;
  }
  
  declare class BaseAudioContext extends EventTarget {
    currentTime: number;
    destination: AudioDestinationNode;
    listener: AudioListener;
    sampleRate: number;
    state: AudioContextState;
    onstatechange: (ev: any) => mixed;
    createBuffer(numOfChannels: number, length: number, sampleRate: number): AudioBuffer;
    createBufferSource(myMediaElement?: HTMLMediaElement): AudioBufferSourceNode;
    createMediaElementSource(myMediaElement: HTMLMediaElement): MediaElementAudioSourceNode;
    createMediaStreamSource(stream: MediaStream): MediaStreamAudioSourceNode;
    createMediaStreamDestination(): MediaStreamAudioDestinationNode;
  
    // deprecated
    createScriptProcessor(bufferSize: number, numberOfInputChannels: number, numberOfOutputChannels: number): ScriptProcessorNode;
  
    createAnalyser(): AnalyserNode;
    createBiquadFilter(): BiquadFilterNode;
    createChannelMerger(numberOfInputs?: number): ChannelMergerNode;
    createChannelSplitter(numberOfInputs?: number): ChannelSplitterNode;
    createConstantSource(): ConstantSourceNode;
    createConvolver(): ConvolverNode;
    createDelay(maxDelayTime?: number): DelayNode;
    createDynamicsCompressor(): DynamicsCompressorNode;
    createGain(): GainNode;
    createIIRFilter (feedforward: Float32Array, feedback: Float32Array): IIRFilterNode;
    createOscillator(): OscillatorNode;
    createPanner(): PannerNode;
    createStereoPanner(): StereoPannerNode;
    createPeriodicWave(real: Float32Array, img: Float32Array, options?: { disableNormalization: boolean, ... }): PeriodicWave;
    createStereoPanner(): StereoPannerNode;
    createWaveShaper(): WaveShaperNode;
    decodeAudioData(arrayBuffer: ArrayBuffer, decodeSuccessCallback: (decodedData: AudioBuffer) => mixed, decodeErrorCallback: (err: DOMError) => mixed): void;
    decodeAudioData(arrayBuffer: ArrayBuffer): Promise<AudioBuffer>;
  }
  
  declare class AudioTimestamp {
    contextTime: number;
    performanceTime: number;
  }
  
  declare class AudioContext extends BaseAudioContext {
    constructor(options?: {| latencyHint?: 'balanced' | 'interactive' | 'playback' | number, sampleRate?: number |}): AudioContext;
    baseLatency: number;
    outputLatency: number;
    getOutputTimestamp(): AudioTimestamp;
    resume(): Promise<void>;
    suspend(): Promise<void>;
    close(): Promise<void>;
    createMediaElementSource(myMediaElement: HTMLMediaElement): MediaElementAudioSourceNode;
    createMediaStreamSource(myMediaStream: MediaStream): MediaStreamAudioSourceNode;
    createMediaStreamTrackSource(myMediaStreamTrack: MediaStreamTrack): MediaStreamTrackAudioSourceNode;
    createMediaStreamDestination(): MediaStreamAudioDestinationNode;
  }
  
  declare class OfflineAudioContext extends BaseAudioContext {
    startRendering(): Promise<AudioBuffer>;
    suspend(suspendTime: number): Promise<void>;
    length: number;
    oncomplete: (ev: OfflineAudioCompletionEvent) => mixed;
  }
  
  declare class AudioNode extends EventTarget {
    context: AudioContext;
    numberOfInputs: number;
    numberOfOutputs: number;
    channelCount: number;
    channelCountMode: 'max' | 'clamped-max' | 'explicit';
    channelInterpretation: 'speakers' | 'discrete';
    connect(audioNode: AudioNode, output?: number, input?: number): AudioNode;
    connect(destination: AudioParam, output?: number): void;
    disconnect(destination?: AudioNode, output?: number, input?: number): void;
  }
  
  declare class AudioParam extends AudioNode {
    value: number;
    defaultValue: number;
    setValueAtTime(value: number, startTime: number): this;
    linearRampToValueAtTime(value: number, endTime: number): this;
    exponentialRampToValueAtTime(value: number, endTime: number): this;
    setTargetAtTime(target: number, startTime: number, timeConstant: number): this;
    setValueCurveAtTime(values: Float32Array, startTime: number, duration: number): this;
    cancelScheduledValues(startTime: number): this;
  }
  
  declare class AudioDestinationNode extends AudioNode {
    maxChannelCount: number;
  }
  
  declare class AudioListener extends AudioNode {
    positionX: AudioParam;
    positionY: AudioParam;
    positionZ: AudioParam;
    forwardX: AudioParam;
    forwardY: AudioParam;
    forwardZ: AudioParam;
    upX: AudioParam;
    upY: AudioParam;
    upZ: AudioParam;
    setPosition(x: number, y: number, c: number): void;
    setOrientation(x: number, y: number, z: number, xUp: number, yUp: number, zUp: number): void;
  }
  
  declare class AudioBuffer {
    sampleRate: number;
    length: number;
    duration: number;
    numberOfChannels: number;
    getChannelData(channel: number): Float32Array;
    copyFromChannel(destination: Float32Array, channelNumber: number, startInChannel?: number): void;
    copyToChannel(source: Float32Array, channelNumber: number, startInChannel?: number): void;
  }
  
  declare class AudioBufferSourceNode extends AudioNode {
    buffer: AudioBuffer;
    detune: AudioParam;
    loop: boolean;
    loopStart: number;
    loopEnd: number;
    playbackRate: AudioParam;
    onended: (ev: any) => mixed;
    start(when?: number, offset?: number, duration?: number): void;
    stop(when?: number): void;
  }
  
  declare class CanvasCaptureMediaStream extends MediaStream {
    canvas: HTMLCanvasElement;
    requestFrame(): void;
  }
  
  type DoubleRange = {
    max?: number;
    min?: number;
    ...
  }
  
  type LongRange = {
    max?: number;
    min?: number;
    ...
  }
  
  type ConstrainBooleanParameters = {
    exact?: boolean;
    ideal?: boolean;
    ...
  }
  
  type ConstrainDOMStringParameters = {
    exact?: string | string[];
    ideal?: string | string[];
    ...
  }
  
  type ConstrainDoubleRange = {
    ...DoubleRange;
    exact?: number;
    ideal?: number;
    ...
  }
  
  type ConstrainLongRange = {
    ...LongRange;
    exact?: number;
    ideal?: number;
    ...
  }
  
  type MediaTrackSupportedConstraints = {|
    width: boolean;
    height: boolean;
    aspectRatio: boolean;
    frameRate: boolean;
    facingMode: boolean;
    resizeMode: boolean;
    volume: boolean;
    sampleRate: boolean;
    sampleSize: boolean;
    echoCancellation: boolean;
    autoGainControl: boolean;
    noiseSuppression: boolean;
    latency: boolean;
    channelCount: boolean;
    deviceId: boolean;
    groupId: boolean;
  |}
  
  type MediaTrackConstraintSet = {
    width?: number | ConstrainLongRange;
    height?: number | ConstrainLongRange;
    aspectRatio?: number | ConstrainDoubleRange;
    frameRate?: number | ConstrainDoubleRange;
    facingMode?: string | string[] | ConstrainDOMStringParameters;
    resizeMode?: string | string[] | ConstrainDOMStringParameters;
    volume?: number | ConstrainDoubleRange;
    sampleRate?: number | ConstrainLongRange;
    sampleSize?: number | ConstrainLongRange;
    echoCancellation?: boolean | ConstrainBooleanParameters;
    autoGainControl?: boolean | ConstrainBooleanParameters;
    noiseSuppression?: boolean | ConstrainBooleanParameters;
    latency?: number | ConstrainDoubleRange;
    channelCount?: number | ConstrainLongRange;
    deviceId?: string | string[] | ConstrainDOMStringParameters;
    groupId?: string | string[] | ConstrainDOMStringParameters;
    ...
  }
  
  type MediaTrackConstraints = {
    ...MediaTrackConstraintSet;
    advanced?: Array<MediaTrackConstraintSet>;
    ...
  }
  
  type DisplayMediaStreamConstraints = {
    video?: boolean | MediaTrackConstraints;
    audio?: boolean | MediaTrackConstraints;
    ...
  }
  
  type MediaStreamConstraints = {
    audio?: boolean | MediaTrackConstraints;
    video?: boolean | MediaTrackConstraints;
    peerIdentity?: string;
    ...
  }
  
  type MediaTrackSettings = {
    aspectRatio?: number;
    deviceId?: string;
    displaySurface?: 'application' | 'browser' | 'monitor' | 'window';
    echoCancellation?: boolean;
    facingMode?: string;
    frameRate?: number;
    groupId?: string;
    height?: number;
    logicalSurface?: boolean;
    sampleRate?: number;
    sampleSize?: number;
    volume?: number;
    width?: number;
    ...
  }
  
  type MediaTrackCapabilities = {
    aspectRatio?: number | DoubleRange;
    deviceId?: string;
    echoCancellation?: boolean[];
    facingMode?: string;
    frameRate?: number | DoubleRange;
    groupId?: string;
    height?: number | LongRange;
    sampleRate?: number | LongRange;
    sampleSize?: number | LongRange;
    volume?: number | DoubleRange;
    width?: number | LongRange;
    ...
  }
  
  declare class MediaDevices extends EventTarget {
    ondevicechange: (ev: any) => mixed;
    enumerateDevices: () => Promise<Array<MediaDeviceInfo>>;
    getSupportedConstraints: () => MediaTrackSupportedConstraints;
    getDisplayMedia: (constraints?: DisplayMediaStreamConstraints) => Promise<MediaStream>;
    getUserMedia: (constraints: MediaStreamConstraints) => Promise<MediaStream>;
  }
  
  declare class MediaDeviceInfo {
    +deviceId: string;
    +groupId: string;
    +kind: 'videoinput' | 'audioinput' | 'audiooutput';
    +label: string;
  }
  
  type MediaRecorderOptions = {
    mimeType?: string,
    audioBitsPerSecond?: number,
    videoBitsPerSecond?: number,
    bitsPerSecond?: number,
    audioBitrateMode?: 'cbr' | 'vbr',
    ...
  }
  
  declare class MediaRecorder extends EventTarget {
    constructor(stream: MediaStream, options?: MediaRecorderOptions): void;
    +stream: MediaStream;
    +mimeType: string;
    +state: 'inactive' | 'recording' | 'paused';
  
    onstart: (ev: any) => mixed;
    onstop: (ev: any) => mixed;
    ondataavailable: (ev: any) => mixed;
    onpause: (ev: any) => mixed;
    onresume: (ev: any) => mixed;
    onerror: (ev: any) => mixed;
  
    +videoBitsPerSecond: number;
    +audioBitsPerSecond: number;
    +audioBitrateMode: 'cbr' | 'vbr';
  
    start(timeslice?: number): void;
    stop(): void;
    pause(): void;
    resume(): void;
    requestData(): void;
  
    static isTypeSupported(type: string): boolean;
  }
  
  declare class MediaStream extends EventTarget {
    active: boolean;
    ended: boolean;
    id: string;
    onactive: (ev: any) => mixed;
    oninactive: (ev: any) => mixed;
    onended: (ev: any) => mixed;
    onaddtrack: (ev: MediaStreamTrackEvent) => mixed;
    onremovetrack: (ev: MediaStreamTrackEvent) => mixed;
    addTrack(track: MediaStreamTrack): void;
    clone(): MediaStream;
    getAudioTracks(): MediaStreamTrack[];
    getTrackById(trackid?: string): ?MediaStreamTrack;
    getTracks(): MediaStreamTrack[];
    getVideoTracks(): MediaStreamTrack[];
    removeTrack(track: MediaStreamTrack): void;
  }
  
  declare class MediaStreamTrack extends EventTarget {
    enabled: boolean;
    id: string;
    kind: string;
    label: string;
    muted: boolean;
    readonly: boolean;
    readyState: 'live' | 'ended';
    remote: boolean;
    contentHint?: string;
    onstarted: (ev: any) => mixed;
    onmute: (ev: any) => mixed;
    onunmute: (ev: any) => mixed;
    onoverconstrained: (ev: any) => mixed;
    onended: (ev: any) => mixed;
    getConstraints(): MediaTrackConstraints;
    applyConstraints(constraints?: MediaTrackConstraints): Promise<void>;
    getSettings(): MediaTrackSettings;
    getCapabilities(): MediaTrackCapabilities;
    clone(): MediaStreamTrack;
    stop(): void;
  }
  
  declare class MediaStreamTrackEvent extends Event {
    track: MediaStreamTrack;
  }
  
  declare class MediaElementAudioSourceNode extends AudioNode {}
  declare class MediaStreamAudioSourceNode extends AudioNode {}
  declare class MediaStreamTrackAudioSourceNode extends AudioNode {}
  
  declare class MediaStreamAudioDestinationNode extends AudioNode {
    stream: MediaStream;
  }
  
  // deprecated
  declare class ScriptProcessorNode extends AudioNode {
    bufferSize: number;
    onaudioprocess: (ev: AudioProcessingEvent) => mixed;
  }
  
  declare class AnalyserNode extends AudioNode {
    fftSize: number;
    frequencyBinCount: number;
    minDecibels: number;
    maxDecibels: number;
    smoothingTimeConstant: number;
    getFloatFrequencyData(array: Float32Array): Float32Array;
    getByteFrequencyData(array: Uint8Array): Uint8Array;
    getFloatTimeDomainData(array: Float32Array): Float32Array;
    getByteTimeDomainData(array: Uint8Array): Uint8Array;
  }
  
  declare class BiquadFilterNode extends AudioNode {
    frequency: AudioParam;
    detune: AudioParam;
    Q: AudioParam;
    gain: AudioParam;
    type: 'lowpass'|'highpass'|'bandpass'|'lowshelf'|'highshelf'|'peaking'|'notch'|'allpass';
    getFrequencyResponse(frequencyHz: Float32Array, magResponse: Float32Array, phaseResponse: Float32Array): void;
  }
  
  declare class ChannelMergerNode extends AudioNode {}
  declare class ChannelSplitterNode extends AudioNode {}
  
  type ConstantSourceOptions = { offset?: number, ... }
  declare class ConstantSourceNode extends AudioNode {
    constructor(context: BaseAudioContext, options?: ConstantSourceOptions): void;
    offset: AudioParam;
    onended: (ev: any) => mixed;
    start(when?: number): void;
    stop(when?: number): void;
  }
  
  declare class ConvolverNode extends AudioNode {
    buffer: AudioBuffer;
    normalize: boolean;
  }
  
  declare class DelayNode extends AudioNode {
    delayTime: number;
  }
  
  declare class DynamicsCompressorNode extends AudioNode {
    threshold: AudioParam;
    knee: AudioParam;
    ratio: AudioParam;
    reduction: AudioParam;
    attack: AudioParam;
    release: AudioParam;
  }
  
  declare class GainNode extends AudioNode {
    gain: AudioParam;
  }
  
  declare class IIRFilterNode extends AudioNode {
    getFrequencyResponse(frequencyHz: Float32Array, magResponse: Float32Array, phaseResponse: Float32Array): void;
  }
  
  declare class OscillatorNode extends AudioNode {
    frequency: AudioParam;
    detune: AudioParam;
    type: 'sine' | 'square' | 'sawtooth' | 'triangle' | 'custom';
    start(when?: number): void;
    stop(when?: number): void;
    setPeriodicWave(periodicWave: PeriodicWave): void;
    onended: (ev: any) => mixed;
  }
  
  declare class StereoPannerNode extends AudioNode {
    pan: AudioParam;
  }
  
  declare class PannerNode extends AudioNode {
    panningModel: 'equalpower'|'HRTF';
    distanceModel: 'linear'|'inverse'|'exponential';
    refDistance: number;
    maxDistance: number;
    rolloffFactor: number;
    coneInnerAngle: number;
    coneOuterAngle: number;
    coneOuterGain: number;
    setPosition(x: number, y: number, z: number): void;
    setOrientation(x: number, y: number, z: number): void;
  }
  
  declare class PeriodicWave extends AudioNode {}
  declare class WaveShaperNode extends AudioNode {
    curve: Float32Array;
    oversample: 'none'|'2x'|'4x';
  }
  
  
  // this part of spec is not finished yet, apparently
  // https://stackoverflow.com/questions/35296664/can-fetch-get-object-as-headers
  type HeadersInit = Headers | Array<[string, string]> | { [key: string]: string, ... };
  
  
  // TODO Heades and URLSearchParams are almost the same thing.
  // Could it somehow be abstracted away?
  declare class Headers {
      @@iterator(): Iterator<[string, string]>;
      constructor(init?: HeadersInit): void;
      append(name: string, value: string): void;
      delete(name: string): void;
      entries(): Iterator<[string, string]>;
      forEach<This>(callback: (this : This, value: string, name: string, headers: Headers) => mixed, thisArg: This): void;
      get(name: string): null | string;
      has(name: string): boolean;
      keys(): Iterator<string>;
      set(name: string, value: string): void;
      values(): Iterator<string>;
  }
  
  declare class URLSearchParams {
      @@iterator(): Iterator<[string, string]>;
  
      size: number;
  
      constructor(init?: string | URLSearchParams | Array<[string, string]> | { [string]: string, ... } ): void;
      append(name: string, value: string): void;
      delete(name: string, value?: string): void;
      entries(): Iterator<[string, string]>;
      forEach<This>(callback: (this : This, value: string, name: string, params: URLSearchParams) => mixed, thisArg: This): void;
      get(name: string): null | string;
      getAll(name: string): Array<string>;
      has(name: string, value?: string): boolean;
      keys(): Iterator<string>;
      set(name: string, value: string): void;
      sort(): void;
      values(): Iterator<string>;
      toString(): string;
  }
  
  type CacheType =  'default' | 'no-store' | 'reload' | 'no-cache' | 'force-cache' | 'only-if-cached';
  type CredentialsType = 'omit' | 'same-origin' | 'include';
  type ModeType = 'cors' | 'no-cors' | 'same-origin' | 'navigate';
  type RedirectType = 'follow' | 'error' | 'manual';
  type ReferrerPolicyType =
      '' | 'no-referrer' | 'no-referrer-when-downgrade' | 'same-origin' |
      'origin' | 'strict-origin' | 'origin-when-cross-origin' |
      'strict-origin-when-cross-origin' | 'unsafe-url';
  
  type ResponseType =  'basic' | 'cors' | 'default' | 'error' | 'opaque' | 'opaqueredirect' ;
  
  type BodyInit = string | URLSearchParams | FormData | Blob | ArrayBuffer | $ArrayBufferView | $FlowFixMe;
  
  type RequestInfo = Request | URL | string;
  
  type RequestOptions = {
    body?: ?BodyInit,
    cache?: CacheType,
    credentials?: CredentialsType,
    headers?: HeadersInit,
    integrity?: string,
    keepalive?: boolean,
    method?: string,
    mode?: ModeType,
    redirect?: RedirectType,
    referrer?: string,
    referrerPolicy?: ReferrerPolicyType,
    signal?: ?AbortSignal,
    window?: any,
    ...
  }
  
  type ResponseOptions = {
    status?: number,
    statusText?: string,
    headers?: HeadersInit,
    ...
  }
  
  declare class Response {
      constructor(input?: ?BodyInit, init?: ResponseOptions): void;
      clone(): Response;
      static error(): Response;
      static redirect(url: string, status?: number): Response;
  
      redirected: boolean;
      type: ResponseType;
      url: string;
      ok: boolean;
      status: number;
      statusText: string;
      headers: Headers;
      trailer: Promise<Headers>;
  
      // Body methods and attributes
      bodyUsed: boolean;
      body: ?$FlowFixMe,
  
      arrayBuffer(): Promise<ArrayBuffer>;
      blob(): Promise<Blob>;
      formData(): Promise<FormData>;
      json(): Promise<any>;
      text(): Promise<string>;
  }
  
  declare class Request {
      constructor(input: RequestInfo, init?: RequestOptions): void;
      clone(): Request;
  
      url: string;
  
      cache: CacheType;
      credentials: CredentialsType;
      headers: Headers;
      integrity: string;
      method: string;
      mode: ModeType;
      redirect: RedirectType;
      referrer: string;
      referrerPolicy: ReferrerPolicyType;
      +signal: AbortSignal;
  
      // Body methods and attributes
      bodyUsed: boolean;
  
      arrayBuffer(): Promise<ArrayBuffer>;
      blob(): Promise<Blob>;
      formData(): Promise<FormData>;
      json(): Promise<any>;
      text(): Promise<string>;
  }
  
  declare class AbortController {
      constructor(): void;
      +signal: AbortSignal;
      abort(reason?: any): void;
  }
  
  declare class AbortSignal extends EventTarget {
      +aborted: boolean;
      +reason: any;
      abort(reason?: any): AbortSignal;
      onabort: (event: Event) => mixed;
      throwIfAborted(): void;
      timeout(time: number): AbortSignal;
  }
  
  declare function fetch(input: RequestInfo, init?: RequestOptions): Promise<Response>;
  
  
  type TextEncoder$availableEncodings = 'utf-8' | 'utf8' | 'unicode-1-1-utf-8' | 'utf-16be' | 'utf-16' | 'utf-16le';
  
  declare class TextEncoder {
    constructor(encoding?: TextEncoder$availableEncodings): void;
    encode(buffer: string, options?: { stream: boolean, ... }): Uint8Array;
    encoding: TextEncoder$availableEncodings;
  }
  
  type TextDecoder$availableEncodings =
    | '866'
    | 'ansi_x3.4-1968'
    | 'arabic'
    | 'ascii'
    | 'asmo-708'
    | 'big5-hkscs'
    | 'big5'
    | 'chinese'
    | 'cn-big5'
    | 'cp1250'
    | 'cp1251'
    | 'cp1252'
    | 'cp1253'
    | 'cp1254'
    | 'cp1255'
    | 'cp1256'
    | 'cp1257'
    | 'cp1258'
    | 'cp819'
    | 'cp866'
    | 'csbig5'
    | 'cseuckr'
    | 'cseucpkdfmtjapanese'
    | 'csgb2312'
    | 'csibm866'
    | 'csiso2022jp'
    | 'csiso2022kr'
    | 'csiso58gb231280'
    | 'csiso88596e'
    | 'csiso88596i'
    | 'csiso88598e'
    | 'csiso88598i'
    | 'csisolatin1'
    | 'csisolatin2'
    | 'csisolatin3'
    | 'csisolatin4'
    | 'csisolatin5'
    | 'csisolatin6'
    | 'csisolatin9'
    | 'csisolatinarabic'
    | 'csisolatincyrillic'
    | 'csisolatingreek'
    | 'csisolatinhebrew'
    | 'cskoi8r'
    | 'csksc56011987'
    | 'csmacintosh'
    | 'csshiftjis'
    | 'cyrillic'
    | 'dos-874'
    | 'ecma-114'
    | 'ecma-118'
    | 'elot_928'
    | 'euc-jp'
    | 'euc-kr'
    | 'gb_2312-80'
    | 'gb_2312'
    | 'gb18030'
    | 'gb2312'
    | 'gbk'
    | 'greek'
    | 'greek8'
    | 'hebrew'
    | 'hz-gb-2312'
    | 'ibm819'
    | 'ibm866'
    | 'iso_8859-1:1987'
    | 'iso_8859-1'
    | 'iso_8859-2:1987'
    | 'iso_8859-2'
    | 'iso_8859-3:1988'
    | 'iso_8859-3'
    | 'iso_8859-4:1988'
    | 'iso_8859-4'
    | 'iso_8859-5:1988'
    | 'iso_8859-5'
    | 'iso_8859-6:1987'
    | 'iso_8859-6'
    | 'iso_8859-7:1987'
    | 'iso_8859-7'
    | 'iso_8859-8:1988'
    | 'iso_8859-8'
    | 'iso_8859-9:1989'
    | 'iso_8859-9'
    | 'iso-2022-cn-ext'
    | 'iso-2022-cn'
    | 'iso-2022-jp'
    | 'iso-2022-kr'
    | 'iso-8859-1'
    | 'iso-8859-10'
    | 'iso-8859-11'
    | 'iso-8859-13'
    | 'iso-8859-14'
    | 'iso-8859-15'
    | 'iso-8859-16'
    | 'iso-8859-2'
    | 'iso-8859-3'
    | 'iso-8859-4'
    | 'iso-8859-5'
    | 'iso-8859-6-e'
    | 'iso-8859-6-i'
    | 'iso-8859-6'
    | 'iso-8859-7'
    | 'iso-8859-8-e'
    | 'iso-8859-8-i'
    | 'iso-8859-8'
    | 'iso-8859-9'
    | 'iso-ir-100'
    | 'iso-ir-101'
    | 'iso-ir-109'
    | 'iso-ir-110'
    | 'iso-ir-126'
    | 'iso-ir-127'
    | 'iso-ir-138'
    | 'iso-ir-144'
    | 'iso-ir-148'
    | 'iso-ir-149'
    | 'iso-ir-157'
    | 'iso-ir-58'
    | 'iso8859-1'
    | 'iso8859-10'
    | 'iso8859-11'
    | 'iso8859-13'
    | 'iso8859-14'
    | 'iso8859-15'
    | 'iso8859-2'
    | 'iso8859-3'
    | 'iso8859-4'
    | 'iso8859-6'
    | 'iso8859-7'
    | 'iso8859-8'
    | 'iso8859-9'
    | 'iso88591'
    | 'iso885910'
    | 'iso885911'
    | 'iso885913'
    | 'iso885914'
    | 'iso885915'
    | 'iso88592'
    | 'iso88593'
    | 'iso88594'
    | 'iso88595'
    | 'iso88596'
    | 'iso88597'
    | 'iso88598'
    | 'iso88599'
    | 'koi'
    | 'koi8_r'
    | 'koi8-r'
    | 'koi8-u'
    | 'koi8'
    | 'korean'
    | 'ks_c_5601-1987'
    | 'ks_c_5601-1989'
    | 'ksc_5601'
    | 'ksc5601'
    | 'l1'
    | 'l2'
    | 'l3'
    | 'l4'
    | 'l5'
    | 'l6'
    | 'l9'
    | 'latin1'
    | 'latin2'
    | 'latin3'
    | 'latin4'
    | 'latin5'
    | 'latin6'
    | 'latin9'
    | 'logical'
    | 'mac'
    | 'macintosh'
    | 'ms_kanji'
    | 'shift_jis'
    | 'shift-jis'
    | 'sjis'
    | 'sun_eu_greek'
    | 'tis-620'
    | 'unicode-1-1-utf-8'
    | 'us-ascii'
    | 'utf-16'
    | 'utf-16be'
    | 'utf-16le'
    | 'utf-8'
    | 'utf8'
    | 'visual'
    | 'windows-1250'
    | 'windows-1251'
    | 'windows-1252'
    | 'windows-1253'
    | 'windows-1254'
    | 'windows-1255'
    | 'windows-1256'
    | 'windows-1257'
    | 'windows-1258'
    | 'windows-31j'
    | 'windows-874'
    | 'windows-949'
    | 'x-cp1250'
    | 'x-cp1251'
    | 'x-cp1252'
    | 'x-cp1253'
    | 'x-cp1254'
    | 'x-cp1255'
    | 'x-cp1256'
    | 'x-cp1257'
    | 'x-cp1258'
    | 'x-euc-jp'
    | 'x-gbk'
    | 'x-mac-cyrillic'
    | 'x-mac-roman'
    | 'x-mac-ukrainian'
    | 'x-sjis'
    | 'x-user-defined'
    | 'x-x-big5';
  
  
  declare class TextDecoder {
    constructor(encoding?: TextDecoder$availableEncodings, options?: { fatal: boolean, ... }): void;
    encoding: TextDecoder$availableEncodings;
    fatal: boolean;
    ignoreBOM: boolean;
    decode(buffer?: ArrayBuffer | $ArrayBufferView, options?: { stream: boolean, ... }): string;
  }
  
  declare class TextDecoderStream {
    constructor(encoding?: TextDecoder$availableEncodings, options?: { fatal?: boolean, ignoreBOM?: boolean, ... }): void;
    encoding: TextDecoder$availableEncodings;
    fatal: boolean;
    ignoreBOM: boolean;
    readable: $FlowFixMe;
    writable: $FlowFixMe;
  }
  
  declare class MessagePort extends EventTarget {
    postMessage(message: any, transfer?: Iterable<any>): void;
    start(): void;
    close(): void;
  
    onmessage: null | (ev: MessageEvent) => mixed;
    onmessageerror: null | (ev: MessageEvent) => mixed;
  }
  
  declare class MessageChannel {
    port1: MessagePort;
    port2: MessagePort;
  }
  
  declare class VRDisplay extends EventTarget {
    capabilities: VRDisplayCapabilities;
    depthFar: number;
    depthNear: number;
    displayId: number;
    displayName: string;
    isPresenting: boolean;
    stageParameters: null | VRStageParameters;
  
    cancelAnimationFrame(number): void;
    exitPresent(): Promise<void>;
    getEyeParameters(VREye): VREyeParameters;
    getFrameData(VRFrameData): boolean;
    getLayers(): VRLayerInit[];
    requestAnimationFrame(cb: (number) => mixed): number;
    requestPresent(VRLayerInit[]): Promise<void>;
    submitFrame(): void;
  }
  
  type VRSource = HTMLCanvasElement;
  
  type VRLayerInit = {
    leftBounds?: number[],
    rightBounds?: number[],
    source?: null | VRSource,
    ...
  };
  
  type VRDisplayCapabilities = {
    canPresent: boolean,
    hasExternalDisplay: boolean,
    hasPosition: boolean,
    maxLayers: number,
    ...
  };
  
  type VREye = 'left' | 'right';
  
  type VRPose = {
    angularAcceleration?: Float32Array,
    angularVelocity?: Float32Array,
    linearAcceleration?: Float32Array,
    linearVelocity?: Float32Array,
    orientation?: Float32Array,
    position?: Float32Array,
    ...
  };
  
  declare class VRFrameData {
    leftProjectionMatrix: Float32Array;
    leftViewMatrix: Float32Array;
    pose: VRPose;
    rightProjectionMatrix: Float32Array;
    rightViewMatrix: Float32Array;
    timestamp: number;
  }
  
  type VREyeParameters = {
    offset: Float32Array,
    renderWidth: number,
    renderHeight: number,
    ...
  };
  
  type VRStageParameters = {
    sittingToStandingTransform: Float32Array,
    sizeX: number,
    sizeZ: number,
    ...
  };
  
  type VRDisplayEventReason = 'mounted' | 'navigation' | 'requested' | 'unmounted';
  
  type VRDisplayEventInit = {
    display: VRDisplay,
    reason: VRDisplayEventReason,
    ...
  };
  
  declare class VRDisplayEvent extends Event {
    constructor(type: string, eventInitDict: VRDisplayEventInit): void;
    display: VRDisplay;
    reason?: VRDisplayEventReason;
  }
  
  declare class MediaQueryListEvent {
    matches: boolean;
    media: string;
  }
  
  declare type MediaQueryListListener = MediaQueryListEvent => void;
  
  declare class MediaQueryList extends EventTarget {
    matches: boolean;
    media: string;
    addListener: MediaQueryListListener => void;
    removeListener: MediaQueryListListener => void;
    onchange: MediaQueryListListener;
  }
  
  declare var matchMedia: string => MediaQueryList;
  
  // https://w3c.github.io/webappsec-credential-management/#idl-index
  declare type CredMgmtCredentialRequestOptions = {
    mediation?: 'silent' | 'optional' | 'required',
    signal?: AbortSignal,
    ...
  }
  
  declare type CredMgmtCredentialCreationOptions = { signal: AbortSignal, ... }
  
  declare interface CredMgmtCredential {
    id: string;
    type: string;
  }
  
  declare interface CredMgmtPasswordCredential extends CredMgmtCredential {
    password: string;
  }
  
  declare interface CredMgmtCredentialsContainer {
    get(option?: CredMgmtCredentialRequestOptions): Promise<?CredMgmtCredential>;
    store(credential: CredMgmtCredential): Promise<CredMgmtCredential>;
    create(
      creationOption?: CredMgmtCredentialCreationOptions,
    ): Promise<?CredMgmtCredential>;
    preventSilentAccess(): Promise<void>;
  }
  
  type SpeechSynthesisErrorCode =
    | "canceled"
    | "interrupted"
    | "audio-busy"
    | "audio-hardware"
    | "network"
    | "synthesis-unavailable"
    | "synthesis-failed"
    | "language-unavailable"
    | "voice-unavailable"
    | "text-too-long"
    | "invalid-argument"
    | "not-allowed";
  
  declare class SpeechSynthesis extends EventTarget {
    +pending: boolean;
    +speaking: boolean;
    +paused: boolean;
  
    onvoiceschanged: ?((ev: Event) => mixed);
  
    speak(utterance: SpeechSynthesisUtterance): void;
    cancel(): void;
    pause(): void;
    resume(): void;
    getVoices(): Array<SpeechSynthesisVoice>;
  }
  
  declare var speechSynthesis: SpeechSynthesis;
  
  declare class SpeechSynthesisUtterance extends EventTarget {
    constructor(text?: string): void;
  
    text: string;
    lang: string;
    voice: SpeechSynthesisVoice | null;
    volume: number;
    rate: number;
    pitch: number;
  
    onstart: ?((ev: SpeechSynthesisEvent) => mixed);
    onend: ?((ev: SpeechSynthesisEvent) => mixed);
    onerror: ?((ev: SpeechSynthesisErrorEvent) => mixed);
    onpause: ?((ev: SpeechSynthesisEvent) => mixed);
    onresume: ?((ev: SpeechSynthesisEvent) => mixed);
    onmark: ?((ev: SpeechSynthesisEvent) => mixed);
    onboundary: ?((ev: SpeechSynthesisEvent) => mixed);
  }
  
  type SpeechSynthesisEvent$Init = Event$Init & {
    utterance: SpeechSynthesisUtterance;
    charIndex?: number;
    charLength?: number;
    elapsedTime?: number;
    name?: string;
    ...
  }
  
  declare class SpeechSynthesisEvent extends Event {
    constructor(type: string, eventInitDict?: SpeechSynthesisEvent$Init): void;
  
    +utterance: SpeechSynthesisUtterance;
    charIndex: number;
    charLength: number;
    elapsedTime: number;
    name: string;
  }
  
  type SpeechSynthesisErrorEvent$Init = SpeechSynthesisEvent$Init & {
    error: SpeechSynthesisErrorCode;
    ...
  }
  
  declare class SpeechSynthesisErrorEvent extends SpeechSynthesisEvent {
    constructor(type: string, eventInitDict?: SpeechSynthesisErrorEvent$Init): void;
    +error: SpeechSynthesisErrorCode;
  }
  
  declare class SpeechSynthesisVoice {
    +voiceURI: string;
    +name: string;
    +lang: string;
    +localService: boolean;
    +default: boolean;
  }
  
  type SpeechRecognitionErrorCode =
    | "no-speech"
    | "aborted"
    | "audio-capture"
    | "not-allowed"
    | "service-not-allowed"
    | "bad-grammar"
    | "language-not-supported";
  
  declare class SpeechGrammar {
    constructor(): void;
  
    src: string;
    weight?: number;
  }
  
  declare class SpeechGrammarList {
    +length: number;
  
    item(index: number): SpeechGrammar;
    addFromURI(src: string, weight?: number): void;
    addFromString(string: string, weight?: number): void;
  }
  
  declare class SpeechRecognitionAlternative {
    +transcript: string;
    +confidence: number;
  }
  
  declare class SpeechRecognitionResult {
    +isFinal: boolean;
    +length: number;
  
    item(index: number): SpeechRecognitionAlternative;
  }
  
  declare class SpeechRecognitionResultList {
    +length: number;
  
    item(index: number): SpeechRecognitionResult;
  }
  
  type SpeechRecognitionEvent$Init = Event$Init & {
    emma: any;
    interpretation: any;
    resultIndex: number;
    results: SpeechRecognitionResultList;
    ...
  }
  
  declare class SpeechRecognitionEvent extends Event {
    constructor(type: string, eventInitDict?: SpeechRecognitionEvent$Init): void;
  
    +emma: any;
    +interpretation: any;
    +resultIndex: number;
    +results: SpeechRecognitionResultList;
  }
  
  type SpeechRecognitionErrorEvent$Init = SpeechRecognitionEvent$Init & {
    error: SpeechRecognitionErrorCode;
    ...
  }
  
  declare class SpeechRecognitionErrorEvent extends SpeechRecognitionEvent {
    constructor(type: string, eventInitDict?: SpeechRecognitionErrorEvent$Init): void;
    +error: SpeechRecognitionErrorCode;
    +message: string;
  }
  
  declare class SpeechRecognition extends EventTarget {
    constructor(): void;
  
    +grammars: SpeechGrammar[];
    +lang: string;
    +continuous: boolean;
    +interimResults: boolean;
    +maxAlternatives: number;
    +serviceURI: string;
  
    onaudiostart: ?((ev: Event) => mixed);
    onaudioend: ?((ev: Event) => mixed);
    onend: ?((ev: Event) => mixed);
    onerror: ?((ev: Event) => mixed);
    onnomatch: ?((ev: Event) => mixed);
    onsoundstart: ?((ev: Event) => mixed);
    onsoundend: ?((ev: Event) => mixed);
    onspeechstart: ?((ev: Event) => mixed);
    onspeechend: ?((ev: Event) => mixed);
    onstart: ?((ev: Event) => mixed);
  
    abort(): void;
    start(): void;
    stop(): void;
  }
  
  /* Trusted Types
   * https://w3c.github.io/trusted-types/dist/spec/#trusted-types
   */
  declare class TrustedHTML {
    toString(): string;
    toJSON(): string;
  }
  
  declare class TrustedScript {
    toString(): string;
    toJSON(): string;
  }
  
  declare class TrustedScriptURL {
    toString(): string;
    toJSON(): string;
  }
  
  declare class TrustedTypePolicy {
    +name: string;
    createHTML(input: string, ...args: Array<mixed>): TrustedHTML;
    createScript(input: string, ...args: Array<mixed>): TrustedScript;
    createScriptURL(input: string, ...args: Array<mixed>): TrustedScriptURL;
  }
  
  declare type TrustedTypePolicyOptions = {|
    createHTML?: (string, ...args: Array<mixed>) => string;
    createScript?: (string, ...args: Array<mixed>) => string;
    createScriptURL?: (string, ...args: Array<mixed>) => string;
  |}
  
  // window.trustedTypes?: TrustedTypePolicyFactory
  declare class TrustedTypePolicyFactory {
    +emptyHTML: TrustedHTML;
    +emptyScript: TrustedScript;
    +defaultPolicy: ?TrustedTypePolicy;
    +isHTML: (value: mixed) => value is TrustedHTML;
    +isScript: (value: mixed) => value is TrustedScript;
    +isScriptURL: (value: mixed) => value is TrustedScriptURL;
    createPolicy(policyName: string, policyOptions?: TrustedTypePolicyOptions): TrustedTypePolicy;
    getAttributeType(tagName: string, attribute?: string, elementNS?: string, attrNS?: string): null | string;
    getPropertyType(tagName: string, property: string, elementNS?: string): null | string;
  }
  
  // https://wicg.github.io/webusb/
  // https://developer.mozilla.org/en-US/docs/Web/API/USBDevice
  declare class USBDevice {
    configuration: USBConfiguration;
    configurations: Array<USBConfiguration>;
    deviceClass: number;
    deviceProtocol: number;
    deviceSubclass: number;
    deviceVersionMajor: number;
    deviceVersionMinor: number;
    deviceVersionSubminor: number;
    manufacturerName: ?string;
    opened: boolean;
    productId: number;
    productName: ?string;
    serialNumber: ?string;
    usbVersionMajor: number;
    usbVersionMinor: number;
    usbVersionSubminor: number;
    vendorId: number;
    claimInterface(interfaceNumber: number): Promise<void>;
    clearHalt(direction: 'in' | 'out', endpointNumber: number): Promise<void>;
    close(): Promise<void>;
    controlTransferIn(setup: SetUpOptions, length: number): Promise<USBInTransferResult>;
    controlTransferOut(setup: SetUpOptions, data: ArrayBuffer): Promise<USBOutTransferResult>;
    forget(): Promise<void>;
    isochronousTransferIn(endpointNumber: number, packetLengths: Array<number>): Promise<USBIsochronousInTransferResult>;
    isochronousTransferOut(endpointNumber: number, data: ArrayBuffer, packetLengths: Array<number>): Promise<USBIsochronousOutTransferResult>;
    open(): Promise<void>;
    releaseInterface(interfaceNumber: number): Promise<void>;
    reset(): Promise<void>;
    selectAlternateInterface(interfaceNumber: number, alternateSetting: number): Promise<void>;
    selectConfiguration(configurationValue: number): Promise<void>;
    transferIn(endpointNumber: number, length: number): Promise<USBInTransferResult>;
    transferOut(endpointNumber: number, data: ArrayBuffer): Promise<USBOutTransferResult>;
  }
  
  declare class USB extends EventTarget {
    getDevices(): Promise<Array<USBDevice>>;
    requestDevice(options: USBDeviceRequestOptions): Promise<USBDevice>;
  }
  
  declare type USBDeviceFilter = {|
    vendorId?: number;
    productId?: number;
    classCode?: number;
    subclassCode?: number;
    protocolCode?: number;
    serialNumber?: string;
  |};
  
  declare type USBDeviceRequestOptions = {|
    filters: Array<USBDeviceFilter>;
    exclusionFilters?: Array<USBDeviceFilter>;
  |}
  
  declare class USBConfiguration {
    constructor(): void;
    configurationName: ?string;
    configurationValue: number;
    interfaces: $ReadOnlyArray<USBInterface>;
  
  }
  
  declare class USBInterface {
    constructor(): void;
    interfaceNumber: number;
    alternate: USBAlternateInterface;
    alternates: Array<USBAlternateInterface>;
    claimed: boolean;
  }
  
  declare class USBAlternateInterface {
    constructor(): void;
    alternateSetting: number;
    interfaceClass: number;
    interfaceSubclass: number;
    interfaceProtocol: number;
    interfaceName: ?string;
    endpoints : Array<USBEndpoint>;
  }
  
  declare class USBEndpoint {
    constructor(): void;
    endpointNumber: number;
    direction: 'in' | 'out';
    type:'bulk' | 'interrupt' | 'isochronous';
    packetSize: number;
  }
  
  declare class USBOutTransferResult {
    constructor(): void;
    bytesWritten: number;
    status: 'ok' | 'stall';
  }
  
  declare class USBInTransferResult {
    constructor(): void;
    data: DataView;
    status: 'ok' |'stall' | 'babble';
  }
  
  declare class USBIsochronousInTransferResult {
    constructor(): void;
    data: DataView;
    packets: Array<USBIsochronousInTransferPacket>;
  }
  
  declare class USBIsochronousInTransferPacket {
    constructor(): void;
    data: DataView;
    status: 'ok' |'stall' | 'babble';
  }
  
  declare class USBIsochronousOutTransferResult {
    constructor(): void;
    packets: Array<USBIsochronousOutTransferPacket>
  }
  
  declare class USBIsochronousOutTransferPacket {
    constructor(): void;
    bytesWritten: number;
    status: 'ok' | 'stall';
  }
  
  type SetUpOptions = {
    requestType: string;
    recipient: string;
    request: number;
    value: number;
    index: number;
    ...
  }
  
  declare type FileSystemHandleKind = "file" | "directory";
  
  // https://wicg.github.io/file-system-access/#api-filesystemhandle
  declare class FileSystemHandle {
    +kind: FileSystemHandleKind;
    +name: string;
  
    isSameEntry: (other: FileSystemHandle) => Promise<boolean>;
    queryPermission?: (
      descriptor: FileSystemHandlePermissionDescriptor
    ) => Promise<PermissionStatus>;
    requestPermission?: (
      descriptor: FileSystemHandlePermissionDescriptor
    ) => Promise<PermissionStatus>;
  }
  
  // https://fs.spec.whatwg.org/#api-filesystemfilehandle
  declare class FileSystemFileHandle extends FileSystemHandle {
    +kind: "file";
  
    constructor(name: string): void;
  
    getFile(): Promise<File>;
    createSyncAccessHandle(): Promise<FileSystemSyncAccessHandle>;
    createWritable(options?: {|
      keepExistingData?: boolean,
    |}): Promise<FileSystemWritableFileStream>;
  }
  
  // https://fs.spec.whatwg.org/#api-filesystemdirectoryhandle
  declare class FileSystemDirectoryHandle extends FileSystemHandle {
    +kind: "directory";
  
    constructor(name: string): void;
  
    getDirectoryHandle(
      name: string,
      options?: {| create?: boolean |}
    ): Promise<FileSystemDirectoryHandle>;
    getFileHandle(
      name: string,
      options?: {| create?: boolean |}
    ): Promise<FileSystemFileHandle>;
    removeEntry(name: string, options?: {| recursive?: boolean |}): Promise<void>;
    resolve(possibleDescendant: FileSystemHandle): Promise<Array<string> | null>;
  
    // Async iterator functions
    @@asyncIterator(): AsyncIterator<[string, FileSystemHandle]>;
    entries(): AsyncIterator<[string, FileSystemHandle]>;
    keys(): AsyncIterator<string>;
    values(): AsyncIterator<FileSystemHandle>;
  }
  
  // https://fs.spec.whatwg.org/#api-filesystemsyncaccesshandle
  declare class FileSystemSyncAccessHandle {
    close(): void;
    flush(): void;
    getSize(): number;
    read(buffer: ArrayBuffer, options?: {| at: number |}): number;
    truncate(newSize: number): void;
    write(buffer: ArrayBuffer, options?: {| at: number |}): number;
  }
  
  // https://streams.spec.whatwg.org/#default-writer-class
  declare class $FlowFixMeDefaultWriter {
    +closed: Promise<void>;
    +desiredSize: number;
    +ready: Promise<void>;
  
    constructor(): void;
  
    abort(reason?: string): Promise<void>;
    close(): Promise<void>;
    releaseLock(): void;
    write(chunk: any): Promise<void>;
  }
  
  // https://streams.spec.whatwg.org/#ws-class
  declare class WriteableStream {
    +locked: boolean;
  
    constructor(): void;
  
    abort(reason: string): Promise<string>;
    close(): Promise<void>;
    getWriter(): $FlowFixMeDefaultWriter;
  }
  
  // https://fs.spec.whatwg.org/#dictdef-writeparams
  declare type FileSystemWriteableFileStreamDataTypes =
    | ArrayBuffer
    | $TypedArray
    | DataView
    | Blob
    | string;
  
  // https://fs.spec.whatwg.org/#dictdef-writeparams
  declare type FileSystemWriteableFileStreamData =
    | FileSystemWriteableFileStreamDataTypes
    | {|
        type: "write",
        position?: number,
        data: FileSystemWriteableFileStreamDataTypes,
      |}
    | {|
        type: "seek",
        position: number,
        data: FileSystemWriteableFileStreamDataTypes,
      |}
    | {|
        type: "size",
        size: number,
      |};
  
  // https://fs.spec.whatwg.org/#api-filesystemwritablefilestream
  declare class FileSystemWritableFileStream extends WriteableStream {
    write(data: FileSystemWriteableFileStreamData): Promise<void>;
    truncate(size: number): Promise<void>;
    seek(position: number): Promise<void>;
  }