declare type ArgFreeEventType =
  | 'selectionchange'
  | 'currentpagechange'
  | 'librarychange'
  | 'viewportchange'
  | 'close'

interface PluginAPI {
  readonly apiVersion: '2.0.0'
  readonly command: string
  readonly pluginId?: string
  readonly fileKey: string | undefined
  readonly viewport: ViewportAPI
  readonly currentUser: User | null
  readonly activeUsers: ActiveUser[]
  readonly currentTheme: ThemeType
  currentTool: ToolType
  closePlugin(message?: string): void
  notify(message: string, options?: NotificationOptions): NotificationHandler
  loading(message: string, options?: LoadingOptions): LoadingHandler
  commitUndo(): void
  triggerUndo(): void
  saveVersionHistoryAsync(title: string, description?: string): Promise<VersionHistoryResult>
  showUI(html: string, options?: ShowUIOptions): void
  readonly ui: UIAPI
  readonly host: HostObjectAPI
  readonly mouse: MouseAPI
  readonly clientStorage: ClientStorageAPI
  readonly serverStorage: ServerStorageAPI
  readonly vectorEditor: VectorEditorAPI
  readonly fieldset: FieldsetAPI
  readonly stickyToolbar: StickyToolbarAPI
  getNodeById(id: string): BaseNode | null
  getStyleById(id: string): BaseStyle | null
  readonly root: DocumentNode
  readonly variables: VariablesAPI
  readonly teamLibrary: TeamLibraryAPI
  currentPage: PageNode
  on(type: ArgFreeEventType, callback: () => void): void
  on(type: 'run', callback: (event: RunEvent) => void): void
  on(type: 'drop', callback: (event: DropEvent) => boolean): void
  on(type: 'documentchange', callback: (event: DocumentChangeEvent) => void): void
  on(type: 'edittypechange', callback: (event: EditTypeChangeEvent) => void): void
  on(type: 'themechange', callback: (event: ThemeChangeEvent) => void): void
  on(type: 'detachinstance', callback: (event: DetachInstanceEvent) => void): void
  on(type: 'detachstyle', callback: (event: DetachStyleChangeEvent) => void): void
  on(type: 'toptoolselect', callback: (event: ToptoolselectEvent) => void): void
  on(type: 'bottomtoolselect', callback: (event: BottomToolSelectEvent) => void): void
  on(type: 'contextmenuselect', callback: (event: ContextMenuSelectEvent) => void): void
  on(type: 'shortcuthit', callback: (event: ShortcutHitEvent) => void): void

  once(type: ArgFreeEventType, callback: () => void): void
  once(type: 'run', callback: (event: RunEvent) => void): void
  once(type: 'drop', callback: (event: DropEvent) => boolean): void
  once(type: 'documentchange', callback: (event: DocumentChangeEvent) => void): void
  once(type: 'edittypechange', callback: (event: EditTypeChangeEvent) => void): void
  once(type: 'themechange', callback: (event: ThemeChangeEvent) => void): void
  once(type: 'detachinstance', callback: (event: DetachInstanceEvent) => void): void
  once(type: 'detachstyle', callback: (event: DetachStyleChangeEvent) => void): void
  once(type: 'toptoolselect', callback: (event: ToptoolselectEvent) => void): void
  once(type: 'bottomtoolselect', callback: (event: BottomToolSelectEvent) => void): void
  once(type: 'contextmenuselect', callback: (event: ContextMenuSelectEvent) => void): void
  once(type: 'shortcuthit', callback: (event: ShortcutHitEvent) => void): void

  off(type: ArgFreeEventType, callback: () => void): void
  off(type: 'run', callback: (event: RunEvent) => void): void
  off(type: 'drop', callback: (event: DropEvent) => boolean): void
  off(type: 'documentchange', callback: (event: DocumentChangeEvent) => void): void
  off(type: 'edittypechange', callback: (event: EditTypeChangeEvent) => void): void
  off(type: 'themechange', callback: (event: ThemeChangeEvent) => void): void
  off(type: 'detachinstance', callback: (event: DetachInstanceEvent) => void): void
  off(type: 'detachstyle', callback: (event: DetachStyleChangeEvent) => void): void
  off(type: 'toptoolselect', callback: (event: ToptoolselectEvent) => void): void
  off(type: 'bottomtoolselect', callback: (event: BottomToolSelectEvent) => void): void
  off(type: 'contextmenuselect', callback: (event: ContextMenuSelectEvent) => void): void
  off(type: 'shortcuthit', callback: (event: ShortcutHitEvent) => void): void

  readonly mixed: string
  createRectangle(): RectangleNode
  createLine(): LineNode
  createEllipse(): EllipseNode
  createPolygon(): PolygonNode
  createStar(): StarNode
  createVector(): VectorNode
  createText(): TextNode
  createFrame(): FrameNode
  createComponent(): ComponentNode
  createPage(): PageNode
  createSlice(): SliceNode
  createBooleanOperation(): BooleanOperationNode

  createPaintStyle(): PaintStyle
  createTextStyle(): TextStyle
  createEffectStyle(): EffectStyle
  createGridStyle(): GridStyle
  getLocalPaintStyles(): PaintStyle[]
  getLocalTextStyles(): TextStyle[]
  getLocalEffectStyles(): EffectStyle[]
  getLocalGridStyles(): GridStyle[]
  // moveLocalPaintStyleAfter(targetNode: PaintStyle, reference: PaintStyle | null): void
  // moveLocalTextStyleAfter(targetNode: TextStyle, reference: TextStyle | null): void
  // moveLocalEffectStyleAfter(targetNode: EffectStyle, reference: EffectStyle | null): void
  // moveLocalGridStyleAfter(targetNode: GridStyle, reference: GridStyle | null): void
  // moveLocalPaintFolderAfter(targetFolder: string, reference: string | null): void
  // moveLocalTextFolderAfter(targetFolder: string, reference: string | null): void
  // moveLocalEffectFolderAfter(targetFolder: string, reference: string | null): void
  // moveLocalGridFolderAfter(targetFolder: string, reference: string | null): void

  importStyleByKeyAsync(key: string): Promise<BaseStyle>
  importComponentByKeyAsync(key: string): Promise<ComponentNode>
  importComponentSetByKeyAsync(key: string): Promise<ComponentSetNode>
  getLibraryListAsync(): Promise<LibraryItem[]>
  getLibraryByKeyAsync(key: string): Promise<LibraryAssets>
  subscribeLibraryAsync(key: string): Promise<void>
  unsubscribeLibraryAsync(key: string): Promise<void>
  publishLocalStyleAsync(libraryType?: LibraryType): Promise<void>
  publishLocalComponentAsync(libraryType?: LibraryType): Promise<void>
  getLibraryChange(): LibraryAssets
  updateLibraryComponentAsync(): Promise<void>
  updateLibraryStyleAsync(): Promise<void>

  listAvailableFontsAsync(): Promise<Font[]>
  loadFontAsync(fontName: FontName): Promise<void>
  readonly hasMissingFont: boolean
  createNodeFromSvg(svg: string): FrameNode
  createNodeFromSvgAsync(svg: Uint8Array): Promise<FrameNode>
  createImage(data: Uint8Array): Image
  getImageByHash(hash: string): Image | null

  // combineAsVariants(
  //   nodes: ReadonlyArray<ComponentNode>,
  //   parent: BaseNode & ChildrenMixin,
  //   index?: number,
  // ): ComponentSetNode
  group(nodes: ReadonlyArray<BaseNode>, parent: BaseNode & ChildrenMixin, index?: number): GroupNode
  flatten(
    nodes: ReadonlyArray<BaseNode>,
    parent?: BaseNode & ChildrenMixin,
    index?: number,
  ): VectorNode
  union(
    nodes: ReadonlyArray<BaseNode>,
    parent: BaseNode & ChildrenMixin,
    index?: number,
  ): BooleanOperationNode
  subtract(
    nodes: ReadonlyArray<BaseNode>,
    parent: BaseNode & ChildrenMixin,
    index?: number,
  ): BooleanOperationNode
  intersect(
    nodes: ReadonlyArray<BaseNode>,
    parent: BaseNode & ChildrenMixin,
    index?: number,
  ): BooleanOperationNode
  exclude(
    nodes: ReadonlyArray<BaseNode>,
    parent: BaseNode & ChildrenMixin,
    index?: number,
  ): BooleanOperationNode
  ungroup(node: SceneNode & ChildrenMixin): Array<SceneNode>
  base64Encode(data: Uint8Array): string
  base64Decode(data: string): Uint8Array
  getFileThumbnailNode(): FrameNode | ComponentNode | ComponentSetNode | SectionNode | null
  setFileThumbnailNodeAsync(
    node: FrameNode | ComponentNode | ComponentSetNode | SectionNode | null,
  ): Promise<void>
  setTopTools(tools: ToolItem[]): void
  setBottomTools(tools: ToolItem[]): void
  setContextMenus(menus: ContextMenuItem[]): void
  setShortcuts(shortcuts: ShortcutItem[]): void
  exportFileAsync(): Promise<Uint8Array>
  exportSceneNodeListStream(nodes: SceneNode[]): string
}
interface VersionHistoryResult {
  id: string
}
declare type ThemeType = 'LIGHT' | 'DARK'

declare type ToolType =
  | 'SELECT'
  | 'FRAME'
  | 'SLICE'
  | 'STAR'
  | 'LINE'
  | 'ARROW'
  | 'ELLIPSE'
  | 'RECTANGLE'
  | 'REGULAR_POLYGON'
  | 'PEN'
  | 'PENCIL'
  | 'TYPE'
  | 'CONNECTION'
  | 'SECTION'
  | 'FIELDSET'

interface MouseAPI {
  viewportX: number
  viewportY: number
  clientX: number
  clientY: number
  screenX: number
  screenY: number
}

interface ClientStorageAPI {
  getAsync(key: string): Promise<any | undefined>
  setAsync(key: string, value: any): Promise<void>
  deleteAsync(key: string): Promise<void>
  keysAsync(): Promise<string[]>
}

interface ServerStorageAPI {
  getAsync(key?: string): Promise<string>
  setAsync(key: string, value: string): Promise<string>
  deleteAsync(key: string): Promise<string>
}
interface VectorEditorAPI {
  enterVertorEditMode(node: VectorNode): void
  exitVertorEditMode(): void
  addVertex(vector: Vector): void
  deleteVertex(index: number): void
  selectVertex(index: number): void
  setSelectedVertexPosition(vector: Vector): void
  setSelectedVertexMirrorType(handleMirroring: HandleMirroring): void
  setSelectedVertexCornerRadius(cornerRadius: number): void
  getControlPoints(): Vector[]
  selectControlPoint(index: number): void
  setSelectedControlPointPosition(vector: Vector): void
  addSegment(startVectexIndex: number, endVectexIndex: number): void
  deleteSegment(index: number): void
}

interface FieldsetAPI {
  name: string
  description: string
  strokeColor: RGBA
  strokeWeight: number
  dashPattern: ReadonlyArray<number>
  setIcon(icon: string | Uint8Array): void
  enable(): void
  disable(): void
  remove(): void
  on(type: 'drawend' | 'move', callback: (event: FieldsetEvent) => void): void
  on(type: 'drawstart' | 'disappear', callback: () => void): void
  once(type: 'drawend' | 'move', callback: (event: FieldsetEvent) => void): void
  once(type: 'drawstart' | 'disappear', callback: () => void): void
  off(type: 'drawend' | 'move', callback: (event: FieldsetEvent) => void): void
  off(type: 'drawstart' | 'disappear', callback: () => void): void
}

interface FieldsetEvent {
  bounds: {
    x: number
    y: number
    width: number
    height: number
  }
  selection: SceneNode[]
}

interface StickyToolbarAPI {
  open(tools: ToolItem[]): void
  close(): void
  on(type: 'trigger', callback: (event: StickyToolTriggerEvent) => void): void
  once(type: 'trigger', callback: (event: StickyToolTriggerEvent) => void): void
  off(type: 'trigger', callback: (event: StickyToolTriggerEvent) => void): void
}

interface StickyToolTriggerEvent {
  type: 'MOUSE_ENTER' | 'MOUSE_LEAVE' | 'CLICK'
  command: string
  bounds: {
    x: number
    y: number
    width: number
    height: number
  }
}

interface NotificationOptions {
  timeout?: number
  error?: boolean
  icon?: 'SUCCESS' | 'ERROR' | 'WARN' | 'INFO'
  position?: 'TOP' | 'BOTTOM' | 'RIGHT_BOTTOM'
}
interface NotificationHandler {
  cancel: () => void
}

interface LoadingOptions {
  position?: 'TOP' | 'BOTTOM' | 'RIGHT_BOTTOM'
}

interface LoadingHandler {
  cancel: () => void
}

interface ShowUIOptions {
  visible?: boolean
  title?: string
  width?: number
  height?: number
  position?: {
    x: number
    y: number
  }
  themeColors?: boolean
  mode?: 'NORMAL' | 'SIMPLIFIED'
  enableMinimize?: boolean
}
interface UIPostMessageOptions {
  origin?: string
}
interface OnMessageProperties {
  origin: string
}
declare type MessageEventHandler = (pluginMessage: any, props: OnMessageProperties) => void
interface UIAPI {
  mode: 'NORMAL' | 'SIMPLIFIED'
  visible: boolean
  enableMinimize: boolean
  show(): void
  hide(): void
  resize(width: number, height: number): void
  reposition(x: number, y: number): void
  close(): void
  postMessage(pluginMessage: any, options?: UIPostMessageOptions): void
  onmessage: MessageEventHandler | undefined
  on(type: 'message', callback: MessageEventHandler): void
  once(type: 'message', callback: MessageEventHandler): void
  off(type: 'message', callback: MessageEventHandler): void
  readonly bounds: Rect
}

interface HostObjectAPI {
  readonly clientWidth: number
  readonly clientHeight: number
  postMessage(message: any): void
  onmessage: (message: any) => void | undefined
  on(type: 'message', callback: (message: any) => void): void
  once(type: 'message', callback: (message: any) => void): void
  off(type: 'message', callback: (message: any) => void): void
}

interface ViewportAPI {
  center: Vector
  zoom: number
  scrollAndZoomIntoView(nodes: ReadonlyArray<BaseNode>): void
  readonly position: Vector
  readonly bounds: Rect
}

interface RunEvent {
  command: string
}
interface DropEvent {
  node: BaseNode | SceneNode
  x: number
  y: number
  absoluteX: number
  absoluteY: number
  items: DropItem[]
  files: DropFile[]
  dropMetadata?: any
}
interface DropItem {
  type: string
  data: string
}
interface DropFile {
  name: string
  type: string
  getBytesAsync(): Promise<Uint8Array>
  getTextAsync(): Promise<string>
}

interface DocumentChangeEvent {
  documentChanges: DocumentChange[]
}
interface EditTypeChangeEvent {
  id: string
  type: 'FOCUS' | 'BLUR'
}

interface ThemeChangeEvent {
  theme: ThemeType
}

interface DetachInstanceEvent {
  id: string
  componentId: string
}

interface DetachStyleChangeEvent {
  id: string
  styleId: string
}

interface ToptoolselectEvent {
  command: string
}
interface BottomToolSelectEvent {
  command: string
}

interface ContextMenuSelectEvent {
  command: string
}

interface ShortcutHitEvent {
  command: string
}

interface BaseDocumentChange {
  id: string
  origin: 'LOCAL' | 'REMOTE'
}
interface BaseNodeChange extends BaseDocumentChange {
  node: SceneNode | RemovedNode
}
interface RemovedNode {
  readonly removed: true
  readonly type: NodeType
  readonly id: string
}
interface CreateChange extends BaseNodeChange {
  type: 'CREATE'
}
interface DeleteChange extends BaseNodeChange {
  type: 'DELETE'
}
interface PropertyChange extends BaseNodeChange {
  type: 'PROPERTY_CHANGE'
  properties: NodeChangeProperty[]
}
interface BaseStyleChange extends BaseDocumentChange {
  style: PaintStyle | TextStyle | GridStyle | EffectStyle | null
}
interface StyleCreateChange extends BaseStyleChange {
  type: 'STYLE_CREATE'
}
interface StyleDeleteChange extends BaseStyleChange {
  type: 'STYLE_DELETE'
  style: null
}
interface StylePropertyChange extends BaseStyleChange {
  type: 'STYLE_PROPERTY_CHANGE'
  properties: StyleChangeProperty[]
}
declare type DocumentChange =
  | CreateChange
  | DeleteChange
  | PropertyChange
  | StyleCreateChange
  | StyleDeleteChange
  | StylePropertyChange
declare type NodeChangeProperty =
  | 'pointCount'
  | 'innerRadius'
  | 'name'
  | 'height'
  | 'width'
  | 'locked'
  | 'visible'
  | 'opacity'
  | 'blendMode'
  | 'layoutGrids'
  | 'characters'
  | 'vectorNetwork'
  | 'effects'
  | 'exportSettings'
  | 'arcData'
  | 'fontName'
  | 'fontSize'
  | 'lineHeight'
  | 'paragraphSpacing'
  | 'letterSpacing'
  | 'textAlignHorizontal'
  | 'textAlignVertical'
  | 'textCase'
  | 'textDecoration'
  | 'textAutoResize'
  | 'fills'
  | 'cornerRadius'
  | 'topLeftRadius'
  | 'topRightRadius'
  | 'bottomLeftRadius'
  | 'bottomRightRadius'
  | 'strokes'
  | 'strokeWeight'
  | 'strokeAlign'
  | 'strokeCap'
  | 'strokeJoin'
  | 'strokeMiterLimit'
  | 'dashPattern'
  | 'clipsContent'
  | 'type'
  | 'fillStyleId'
  | 'strokeStyleId'
  | 'textStyleId'
  | 'effectStyleId'
  | 'gridStyleId'
  | 'description'
  | 'paddingLeft'
  | 'paddingTop'
  | 'paddingRight'
  | 'paddingBottom'
  | 'itemSpacing'
  | 'primaryAxisAlignItems'
  | 'counterAxisAlignItems'
  | 'hyperlink'
declare type StyleChangeProperty =
  | 'name'
  | 'pluginData'
  | 'type'
  | 'description'
  | 'remote'
  | 'fontSize'
  | 'textDecoration'
  | 'letterSpacing'
  | 'lineHeight'
  | 'paragraphIndent'
  | 'paragraphSpacing'
  | 'textCase'
  | 'paint'
  | 'effects'
  | 'layoutGrids'

interface LibraryItem {
  readonly name: string
  readonly key: string
  readonly type: 'ENT' | 'TEAM'
  readonly teamName: string
  readonly teamID: number
  readonly subscribed: boolean
}

type LibraryType = 'TEAM' | 'ENT'

interface LibraryComponent {
  readonly name: string
  readonly key: string
  readonly thumbnailUrl: string
  readonly description: string
  readonly pageName: string
  readonly containerName: string
  readonly categories: string[]
  readonly type: 'COMPONENT'
}

interface LibraryComponentSet {
  readonly name: string
  readonly key: string
  readonly thumbnailUrl: string
  readonly description: string
  readonly pageName: string
  readonly containerName: string
  readonly categories: string[]
  readonly type: 'COMPONENT_SET'
  readonly variants: LibraryComponent[]
}

interface LibraryStyle {
  readonly name: string
  readonly key: string
  readonly thumbnailUrl: string
  readonly description: string
  readonly type: StyleType
}

interface LibraryAssets {
  readonly name: string
  readonly key: string // fileKey
  readonly subscribed: boolean
  readonly componentList: (LibraryComponent | LibraryComponentSet)[]
  readonly style: {
    paints: ReadonlyArray<LibraryStyle>
    effects: ReadonlyArray<LibraryStyle>
    texts: ReadonlyArray<LibraryStyle>
    grids: ReadonlyArray<LibraryStyle>
  }
}

type CommandItem = {
  label: string
  value: string
  disabled?: boolean
  description?: string
  icon?: string | Uint8Array // svg字符串 或 图片二进制数据。PS：iconUrl也存在时，优先使用icon数据
  iconUrl?: string
}

type CommandItemWithoutIcon = Omit<CommandItem, 'icon' | 'iconUrl'>

type SeparatorItem = {
  separator: true
}

type ToolItem =
  | SeparatorItem
  | (CommandItem & {
      children?: Array<ToolItem>
    })

type ContextMenuItem =
  | SeparatorItem
  | (CommandItemWithoutIcon & {
      children?: Array<ContextMenuItem>
    })

type SubShortcutItem = CommandItemWithoutIcon & {
  children?: Array<SubShortcutItem>
}

type ShortcutItem = CommandItem & {
  children?: Array<SubShortcutItem>
}

declare type Transform = [[number, number, number], [number, number, number]]
interface Vector {
  readonly x: number
  readonly y: number
}
interface Rect {
  readonly x: number
  readonly y: number
  readonly width: number
  readonly height: number
}
interface RGB {
  readonly r: number
  readonly g: number
  readonly b: number
}
interface RGBA {
  readonly r: number
  readonly g: number
  readonly b: number
  readonly a: number
}
interface FontName {
  readonly family: string
  readonly style: string
}
declare type TextCase = 'ORIGINAL' | 'UPPER' | 'LOWER' | 'TITLE'
declare type TextDecoration = 'NONE' | 'UNDERLINE' | 'STRIKETHROUGH'
interface ArcData {
  readonly startingAngle: number
  readonly endingAngle: number
  readonly innerRadius: number
}
interface DropShadowEffect {
  readonly type: 'DROP_SHADOW'
  readonly color: RGBA
  readonly offset: Vector
  readonly radius: number
  readonly spread?: number
  readonly visible: boolean
  readonly blendMode: BlendMode
  readonly showShadowBehindNode?: boolean
}
interface InnerShadowEffect {
  readonly type: 'INNER_SHADOW'
  readonly color: RGBA
  readonly offset: Vector
  readonly radius: number
  readonly spread?: number
  readonly visible: boolean
  readonly blendMode: BlendMode
}
interface BlurEffect {
  readonly type: 'LAYER_BLUR' | 'BACKGROUND_BLUR'
  readonly radius: number
  readonly visible: boolean
}
declare type Effect = DropShadowEffect | InnerShadowEffect | BlurEffect
declare type ConstraintType = 'MIN' | 'CENTER' | 'MAX' | 'STRETCH' | 'SCALE'
interface Constraints {
  readonly horizontal: ConstraintType
  readonly vertical: ConstraintType
}
interface ColorStop {
  readonly position: number
  readonly color: RGBA
}
interface ImageFilters {
  readonly exposure?: number
  readonly contrast?: number
  readonly saturation?: number
  readonly temperature?: number
  readonly tint?: number
  readonly highlights?: number
  readonly shadows?: number
}
interface SolidPaint {
  readonly type: 'SOLID'
  readonly color: RGB
  readonly visible?: boolean
  readonly opacity?: number
  readonly blendMode?: BlendMode
}
interface GradientPaint {
  readonly type: 'GRADIENT_LINEAR' | 'GRADIENT_RADIAL' | 'GRADIENT_ANGULAR' | 'GRADIENT_DIAMOND'
  readonly gradientTransform: Transform
  readonly gradientStops: ReadonlyArray<ColorStop>
  readonly visible?: boolean
  readonly opacity?: number
  readonly blendMode?: BlendMode
}
interface ImagePaint {
  readonly type: 'IMAGE'
  readonly scaleMode: 'FILL' | 'FIT' | 'CROP' | 'TILE'
  readonly imageHash: string | null
  readonly imageTransform?: Transform
  readonly scalingFactor?: number
  readonly rotation?: number
  readonly filters?: ImageFilters
  readonly visible?: boolean
  readonly opacity?: number
  readonly blendMode?: BlendMode
}

declare type Paint = SolidPaint | GradientPaint | ImagePaint
interface Guide {
  readonly axis: 'X' | 'Y'
  readonly offset: number
}
interface RowsColsLayoutGrid {
  readonly pattern: 'ROWS' | 'COLUMNS'
  readonly alignment: 'MIN' | 'MAX' | 'STRETCH' | 'CENTER'
  readonly gutterSize: number
  readonly count: number
  readonly sectionSize?: number
  readonly offset?: number
  readonly visible?: boolean
  readonly color?: RGBA
}
interface GridLayoutGrid {
  readonly pattern: 'GRID'
  readonly sectionSize: number
  readonly visible?: boolean
  readonly color?: RGBA
}
declare type LayoutGrid = RowsColsLayoutGrid | GridLayoutGrid
interface ExportSettingsConstraints {
  readonly type: 'SCALE' | 'WIDTH' | 'HEIGHT'
  readonly value: number
}
interface ExportSettingsImage {
  readonly format: 'JPG' | 'PNG'
  readonly contentsOnly?: boolean
  readonly useAbsoluteBounds?: boolean
  readonly suffix?: string
  readonly constraint?: ExportSettingsConstraints
}
interface ExportSettingsSVG {
  readonly format: 'SVG'
  readonly contentsOnly?: boolean
  readonly useAbsoluteBounds?: boolean
  readonly suffix?: string
  readonly svgOutlineText?: boolean
  readonly svgIdAttribute?: boolean
}
interface ExportSettingsPDF {
  readonly format: 'PDF'
  readonly contentsOnly?: boolean
  readonly useAbsoluteBounds?: boolean
  readonly suffix?: string
}
declare type ExportSettings = ExportSettingsImage | ExportSettingsSVG | ExportSettingsPDF
declare type WindingRule = 'NONZERO' | 'EVENODD'
interface VectorVertex {
  readonly x: number
  readonly y: number
  readonly strokeCap?: StrokeCap
  readonly strokeJoin?: StrokeJoin
  readonly cornerRadius?: number
  readonly handleMirroring?: HandleMirroring
}
interface VectorSegment {
  readonly start: number
  readonly end: number
  readonly tangentStart?: Vector
  readonly tangentEnd?: Vector
}
interface VectorRegion {
  readonly windingRule: WindingRule
  readonly loops: ReadonlyArray<ReadonlyArray<number>>
  readonly fills?: ReadonlyArray<Paint>
  readonly fillStyleId?: string
}
interface VectorNetwork {
  readonly vertices: ReadonlyArray<VectorVertex>
  readonly segments: ReadonlyArray<VectorSegment>
  readonly regions?: ReadonlyArray<VectorRegion>
}
interface VectorPath {
  readonly windingRule: WindingRule | 'NONE'
  readonly data: string
}
declare type VectorPaths = ReadonlyArray<VectorPath>
interface LetterSpacing {
  readonly value: number
  readonly unit: 'PIXELS' | 'PERCENT'
}
declare type LineHeight =
  | {
      readonly value: number
      readonly unit: 'PIXELS' | 'PERCENT'
    }
  | {
      readonly unit: 'AUTO'
    }
declare type HyperlinkTarget = {
  type: 'URL' | 'NODE'
  value: string
}
declare type TextListOptions = {
  type: 'ORDERED' | 'UNORDERED' | 'NONE'
}
declare type BlendMode =
  | 'PASS_THROUGH'
  | 'NORMAL'
  | 'DARKEN'
  | 'MULTIPLY'
  | 'LINEAR_BURN'
  | 'COLOR_BURN'
  | 'LIGHTEN'
  | 'SCREEN'
  | 'LINEAR_DODGE'
  | 'COLOR_DODGE'
  | 'OVERLAY'
  | 'SOFT_LIGHT'
  | 'HARD_LIGHT'
  | 'DIFFERENCE'
  | 'EXCLUSION'
  | 'HUE'
  | 'SATURATION'
  | 'COLOR'
  | 'LUMINOSITY'
interface Font {
  fontName: FontName
}
interface StyledTextSegment {
  characters: string
  start: number
  end: number
  fontSize: number
  fontName: FontName
  fontWeight: number
  textDecoration: TextDecoration
  textCase: TextCase
  lineHeight: LineHeight
  letterSpacing: LetterSpacing
  fills: Paint[]
  textStyleId: string
  fillStyleId: string
  listOptions: TextListOptions
  indentation: number
  hyperlink: HyperlinkTarget | null
}
declare type Reaction = {
  action: Action | null
  trigger: Trigger | null
}
declare type Action =
  | {
      readonly type: 'BACK' | 'CLOSE'
    }
  | {
      readonly type: 'URL'
      url: string
    }
  | {
      readonly type: 'UPDATE_MEDIA_RUNTIME'
      readonly mediaAction: 'PLAY' | 'PAUSE' | 'TOGGLE_PLAY_PAUSE'
    }
  | {
      readonly type: 'NODE'
      readonly destinationId: string | null
      readonly navigation: Navigation
      readonly transition: Transition | null
      readonly preserveScrollPosition: boolean
      readonly overlayRelativePosition?: Vector
      readonly resetVideoPosition?: boolean
    }
interface SimpleTransition {
  readonly type: 'DISSOLVE' | 'SMART_ANIMATE' | 'SCROLL_ANIMATE'
  readonly easing: Easing
  readonly duration: number
}
interface DirectionalTransition {
  readonly type: 'MOVE_IN' | 'MOVE_OUT' | 'PUSH' | 'SLIDE_IN' | 'SLIDE_OUT'
  readonly direction: 'LEFT' | 'RIGHT' | 'TOP' | 'BOTTOM'
  readonly matchLayers: boolean
  readonly easing: Easing
  readonly duration: number
}
declare type Transition = SimpleTransition | DirectionalTransition
declare type Trigger =
  | {
      readonly type: 'ON_CLICK' | 'ON_HOVER' | 'ON_PRESS' | 'ON_DRAG'
    }
  | {
      readonly type: 'AFTER_TIMEOUT'
      readonly timeout: number
    }
  | {
      readonly type: 'MOUSE_ENTER' | 'MOUSE_LEAVE' | 'MOUSE_UP' | 'MOUSE_DOWN'
      readonly delay: number
    }
  | {
      readonly type: 'ON_KEY_DOWN'
      readonly device: 'KEYBOARD' | 'XBOX_ONE' | 'PS4' | 'SWITCH_PRO' | 'UNKNOWN_CONTROLLER'
      readonly keyCodes: ReadonlyArray<number>
    }
declare type Navigation = 'NAVIGATE' | 'SWAP' | 'OVERLAY' | 'SCROLL_TO' | 'CHANGE_TO'
interface Easing {
  readonly type:
    | 'EASE_IN'
    | 'EASE_OUT'
    | 'EASE_IN_AND_OUT'
    | 'LINEAR'
    | 'EASE_IN_BACK'
    | 'EASE_OUT_BACK'
    | 'EASE_IN_AND_OUT_BACK'
    | 'CUSTOM_CUBIC_BEZIER'
  readonly easingFunctionCubicBezier?: EasingFunctionBezier
}
interface EasingFunctionBezier {
  x1: number
  y1: number
  x2: number
  y2: number
}
declare type OverflowDirection = 'NONE' | 'HORIZONTAL' | 'VERTICAL' | 'BOTH'
declare type OverlayPositionType =
  | 'CENTER'
  | 'TOP_LEFT'
  | 'TOP_CENTER'
  | 'TOP_RIGHT'
  | 'BOTTOM_LEFT'
  | 'BOTTOM_CENTER'
  | 'BOTTOM_RIGHT'
  | 'MANUAL'
declare type OverlayBackground =
  | {
      readonly type: 'NONE'
    }
  | {
      readonly type: 'SOLID_COLOR'
      readonly color: RGBA
    }
declare type OverlayBackgroundInteraction = 'NONE' | 'CLOSE_ON_CLICK_OUTSIDE'
declare type PublishStatus = 'UNPUBLISHED' | 'CURRENT' | 'CHANGED'

interface BaseNodeMixin extends PluginDataMixin {
  readonly id: string
  readonly parent: (BaseNode & ChildrenMixin) | null
  readonly index: number
  name: string
  readonly removed: boolean
  toString(): string
  remove(): void
  setRelaunchData(data: { [command: string]: string }): void
  getRelaunchData(): {
    [command: string]: string
  }
}
interface PluginDataMixin {
  getPluginData(key: string): string
  setPluginData(key: string, value: string): void
  getPluginDataKeys(): string[]
  getSharedPluginData(namespace: string, key: string): string
  setSharedPluginData(namespace: string, key: string, value: string): void
  getSharedPluginDataKeys(namespace: string): string[]
}
interface SceneNodeMixin extends ExplicitVariableModesMixin {
  visible: boolean
  locked: boolean
  // readonly stuckNodes: SceneNode[]
  componentPropertyReferences:
    | {
        [nodeProperty in 'visible' | 'characters' | 'mainComponent']: string
      }
    | null

  readonly boundVariables?: {
    readonly [field in VariableBindableNodeField]?: VariableAlias
  } & {
    readonly [field in VariableBindableTextField]?: VariableAlias[]
  } & {
    readonly fills?: VariableAlias[]
    readonly strokes?: VariableAlias[]
    readonly effects?: VariableAlias[]
    readonly layoutGrids?: VariableAlias[]
    readonly componentProperties?: {
      readonly [propertyName: string]: VariableAlias
    }
    readonly textRangeFills?: VariableAlias[]
  }

  setBoundVariable(
    field: VariableBindableNodeField | VariableBindableTextField,
    variable: Variable | null,
  ): void

  resolvedVariableModes: {
    [collectionId: string]: string
  }
}

interface ChildrenMixin {
  readonly children: ReadonlyArray<SceneNode>
  readonly childrenCount: number
  appendChild(child: SceneNode, preserveAbsolutePostion?: boolean): void
  insertChild(index: number, child: SceneNode, preserveAbsolutePostion?: boolean): void
  findChildrenAsync(callback?: (node: SceneNode) => boolean): Promise<SceneNode[]>
  findChildAsync(callback: (node: SceneNode) => boolean): Promise<SceneNode | null>
  findAllAsync(callback?: (node: SceneNode) => boolean): Promise<SceneNode[]>
  findOneAsync(callback: (node: SceneNode) => boolean): Promise<SceneNode | null>
  findAllWithCriteria<T extends NodeType[]>(criteria: {
    types: T
  }): Array<
    {
      type: T[number]
    } & SceneNode
  >
}
interface ConstraintMixin {
  constraints: Constraints
}
interface AutoLayoutChildrenMixin {
  layoutAlign: 'MIN' | 'CENTER' | 'MAX' | 'STRETCH' | 'INHERIT'
  layoutGrow: number
  // layoutPositioning: 'AUTO' | 'ABSOLUTE'
}
interface DimensionAndPositionMixin {
  x: number
  y: number
  readonly width: number
  readonly height: number
  // minWidth: number | null
  // maxWidth: number | null
  // minHeight: number | null
  // maxHeight: number | null
  relativeTransform: Transform
  readonly absoluteTransform: Transform
  readonly absoluteBoundingBox: Rect | null
  getNestedBoundaryBox(): NestedBoundaryBox
}

interface SimplifiedRect {
  readonly x: number
  readonly y: number
  readonly w: number
  readonly h: number
}
interface NestedBoundaryBox {
  readonly guid: string
  readonly name: string
  readonly type: NodeType
  readonly bbox: SimplifiedRect
  readonly layers?: NestedBoundaryBox[]
}

interface LayoutMixin extends DimensionAndPositionMixin, AutoLayoutChildrenMixin {
  readonly absoluteRenderBounds: Rect | null
  constrainProportions: boolean
  rotation: number
  resize(width: number, height: number): void
  resizeWithoutConstraints(width: number, height: number): void
  rescale(scale: number): void
}
interface BlendMixin extends MinimalBlendMixin {
  isMask: boolean
  effects: ReadonlyArray<Effect>
  effectStyleId: string
}
interface ContainerMixin {
  expanded: boolean
}
declare type StrokeCap = 'NONE' | 'ROUND' | 'SQUARE' | 'ARROW_LINES' | 'ARROW_EQUILATERAL'
declare type StrokeJoin = 'MITER' | 'BEVEL' | 'ROUND'
declare type HandleMirroring = 'NONE' | 'ANGLE' | 'ANGLE_AND_LENGTH' | 'RIGHT_ANGLE'
interface MinimalStrokesMixin {
  strokes: ReadonlyArray<Paint>
  strokeStyleId: string
  strokeWeight: number | PluginAPI['mixed']
  strokeJoin: StrokeJoin | PluginAPI['mixed']
  strokeAlign: 'CENTER' | 'INSIDE' | 'OUTSIDE'
  dashPattern: ReadonlyArray<number>
  // strokeGeometry: VectorPaths
}
interface IndividualStrokesMixin {
  strokeTopWeight: number
  strokeBottomWeight: number
  strokeLeftWeight: number
  strokeRightWeight: number
}
interface MinimalFillsMixin {
  fills: ReadonlyArray<Paint> | PluginAPI['mixed']
  fillStyleId: string | PluginAPI['mixed']
}
interface GeometryMixin extends MinimalStrokesMixin, MinimalFillsMixin {
  strokeCap: StrokeCap | PluginAPI['mixed']
  strokeMiterLimit: number
  // outlineStroke(): VectorNode | null
  // fillGeometry: VectorPaths
}
interface CornerMixin {
  cornerRadius: number | PluginAPI['mixed']
  cornerSmoothing: number
}
interface RectangleCornerMixin {
  topLeftRadius: number
  topRightRadius: number
  bottomLeftRadius: number
  bottomRightRadius: number
}
interface ExportMixin {
  exportSettings: ReadonlyArray<ExportSettings>
  exportAsync(settings?: ExportSettings): Promise<Uint8Array>
}
interface FramePrototypingMixin {
  overflowDirection: OverflowDirection
  numberOfFixedChildren: number
  readonly overlayPositionType: OverlayPositionType
  readonly overlayBackground: OverlayBackground
  readonly overlayBackgroundInteraction: OverlayBackgroundInteraction
}
interface VectorLikeMixin {
  vectorNetwork: VectorNetwork
  vectorPaths: VectorPaths
  handleMirroring: HandleMirroring | PluginAPI['mixed']
}
interface ReactionMixin {
  reactions: ReadonlyArray<Reaction>
}
interface DocumentationLink {
  readonly uri: string
}
interface PublishableMixin {
  description: string
  // documentationLinks: ReadonlyArray<DocumentationLink>
  readonly remote: boolean
  readonly key: string
  getPublishStatusAsync(): Promise<PublishStatus>
  getLibraryInfoAsync(): Promise<{ key: string; name: string }>
}

interface PublishableNodeMixin {
  readonly pageName: string
  readonly containerName: string
}

interface DefaultShapeMixin
  extends BaseNodeMixin,
    SceneNodeMixin,
    ReactionMixin,
    BlendMixin,
    GeometryMixin,
    LayoutMixin,
    ExportMixin {}
interface BaseFrameMixin
  extends BaseNodeMixin,
    SceneNodeMixin,
    ChildrenMixin,
    ContainerMixin,
    GeometryMixin,
    CornerMixin,
    RectangleCornerMixin,
    BlendMixin,
    ConstraintMixin,
    LayoutMixin,
    ExportMixin,
    IndividualStrokesMixin {
  layoutMode: 'NONE' | 'HORIZONTAL' | 'VERTICAL'
  layoutWrap: 'NO_WRAP' | 'WRAP'
  primaryAxisSizingMode: 'FIXED' | 'AUTO'
  counterAxisSizingMode: 'FIXED' | 'AUTO'
  primaryAxisAlignItems: 'MIN' | 'MAX' | 'CENTER' | 'SPACE_BETWEEN'
  counterAxisAlignItems: 'MIN' | 'MAX' | 'CENTER' | 'BASELINE'
  paddingLeft: number
  paddingRight: number
  paddingTop: number
  paddingBottom: number
  itemSpacing: number
  itemReverseZIndex: boolean
  strokesIncludedInLayout: boolean
  // horizontalPadding: number
  // verticalPadding: number
  layoutGrids: ReadonlyArray<LayoutGrid>
  gridStyleId: string
  clipsContent: boolean
  // guides: ReadonlyArray<Guide>
}
interface DefaultFrameMixin extends BaseFrameMixin, FramePrototypingMixin, ReactionMixin {}
interface OpaqueNodeMixin
  extends BaseNodeMixin,
    SceneNodeMixin,
    ExportMixin,
    DimensionAndPositionMixin {}
interface MinimalBlendMixin {
  opacity: number
  blendMode: BlendMode
}
interface VariantMixin {
  readonly variantProperties: {
    [property: string]: string
  } | null
}
interface ComponentPropertiesMixin {
  readonly componentPropertyDefinitions: ComponentPropertyDefinitions
  addComponentProperty(
    propertyName: string,
    type: ComponentPropertyType,
    defaultValue: string | boolean,
    options?: ComponentPropertyOptions,
  ): string
  editComponentProperty(
    propertyName: string,
    newValue: {
      name?: string
      defaultValue?: string | boolean
      preferredValues?: InstanceSwapPreferredValue[]
    },
  ): string
  deleteComponentProperty(propertyName: string): void
}
interface TextSublayerNode extends MinimalFillsMixin {
  readonly hasMissingFont: boolean
  // paragraphIndent: number
  paragraphSpacing: number
  fontSize: number | PluginAPI['mixed']
  fontName: FontName | PluginAPI['mixed']
  // readonly fontWeight: number | PluginAPI['mixed']
  textCase: TextCase | PluginAPI['mixed']
  textDecoration: TextDecoration | PluginAPI['mixed']
  letterSpacing: LetterSpacing | PluginAPI['mixed']
  lineHeight: LineHeight | PluginAPI['mixed']
  hyperlink: HyperlinkTarget | null | PluginAPI['mixed']
  listOptions: TextListOptions | PluginAPI['mixed']
  characters: string
  insertCharacters(start: number, characters: string, useStyle?: 'BEFORE' | 'AFTER'): void
  deleteCharacters(start: number, end: number): void
  getRangeFontSize(start: number, end: number): number | PluginAPI['mixed']
  setRangeFontSize(start: number, end: number, value: number): void
  getRangeFontName(start: number, end: number): FontName | PluginAPI['mixed']
  setRangeFontName(start: number, end: number, value: FontName): void
  // getRangeFontWeight(start: number, end: number): number | PluginAPI['mixed']
  getRangeAllFontNames(start: number, end: number): FontName[]
  getRangeTextCase(start: number, end: number): TextCase | PluginAPI['mixed']
  setRangeTextCase(start: number, end: number, value: TextCase): void
  getRangeTextDecoration(start: number, end: number): TextDecoration | PluginAPI['mixed']
  setRangeTextDecoration(start: number, end: number, value: TextDecoration): void
  getRangeLetterSpacing(start: number, end: number): LetterSpacing | PluginAPI['mixed']
  setRangeLetterSpacing(start: number, end: number, value: LetterSpacing): void
  getRangeLineHeight(start: number, end: number): LineHeight | PluginAPI['mixed']
  setRangeLineHeight(start: number, end: number, value: LineHeight): void
  getRangeHyperlink(start: number, end: number): HyperlinkTarget | null | PluginAPI['mixed']
  // setRangeHyperlink(start: number, end: number, value: HyperlinkTarget | null): void
  getRangeFills(start: number, end: number): Paint[] | PluginAPI['mixed']
  setRangeFills(start: number, end: number, value: Paint[]): void
  getRangeTextStyleId(start: number, end: number): string | PluginAPI['mixed']
  setRangeTextStyleId(start: number, end: number, value: string): void
  getRangeFillStyleId(start: number, end: number): string | PluginAPI['mixed']
  setRangeFillStyleId(start: number, end: number, value: string): void
  getRangeListOptions(start: number, end: number): TextListOptions | PluginAPI['mixed']
  setRangeListOptions(start: number, end: number, value: TextListOptions): void
  // getRangeIndentation(start: number, end: number): number | PluginAPI['mixed']
  // setRangeIndentation(start: number, end: number, value: number): void
  // getStyledTextSegments<
  //   StyledTextSegmentFields extends (keyof Omit<
  //     StyledTextSegment,
  //     'characters' | 'start' | 'end'
  //   >)[],
  // >(
  //   fields: StyledTextSegmentFields,
  //   start?: number,
  //   end?: number,
  // ): Array<
  //   Pick<StyledTextSegment, StyledTextSegmentFields[number] | 'characters' | 'start' | 'end'>
  // >
}
interface DocumentNode extends BaseNodeMixin {
  readonly type: 'DOCUMENT'
  readonly children: ReadonlyArray<PageNode>
  appendChild(child: PageNode): void
  insertChild(index: number, child: PageNode): void
  findChildrenAsync(callback?: (node: PageNode) => boolean): Promise<Array<PageNode>>
  findChildAsync(callback: (node: PageNode) => boolean): Promise<PageNode | null>
  findAllAsync(callback?: (node: PageNode | SceneNode) => boolean): Promise<Array<PageNode | SceneNode>>
  findOneAsync(callback: (node: PageNode | SceneNode) => boolean): Promise<PageNode | SceneNode | null>
  findAllWithCriteria<T extends NodeType[]>(criteria: {
    types: T
  }): Promise<Array<
    {
      type: T[number]
    } & (PageNode | SceneNode)
  >>
}
interface PageNode extends BaseNodeMixin, ChildrenMixin, ExportMixin, ExplicitVariableModesMixin {
  readonly type: 'PAGE'
  clone(): PageNode
  guides: ReadonlyArray<Guide>
  selection: ReadonlyArray<SceneNode>
  // selectedTextRange: {
  //   node: TextNode
  //   start: number
  //   end: number
  // } | null
  // flowStartingPoints: ReadonlyArray<{
  //   nodeId: string
  //   name: string
  // }>
  backgrounds: ReadonlyArray<Paint>
  prototypeBackgrounds: ReadonlyArray<Paint>
  readonly prototypeStartNode: FrameNode | GroupNode | ComponentNode | InstanceNode | null
}
interface FrameNode extends DefaultFrameMixin {
  readonly type: 'FRAME'
  clone(): FrameNode
}
interface GroupNode
  extends BaseNodeMixin,
    SceneNodeMixin,
    ReactionMixin,
    ChildrenMixin,
    ContainerMixin,
    BlendMixin,
    LayoutMixin,
    ExportMixin {
  readonly type: 'GROUP'
  clone(): GroupNode
}
interface SliceNode extends BaseNodeMixin, SceneNodeMixin, LayoutMixin, ExportMixin {
  readonly type: 'SLICE'
  clone(): SliceNode
}
interface RectangleNode
  extends DefaultShapeMixin,
    ConstraintMixin,
    CornerMixin,
    RectangleCornerMixin,
    IndividualStrokesMixin {
  readonly type: 'RECTANGLE'
  clone(): RectangleNode
}
interface LineNode extends DefaultShapeMixin, ConstraintMixin {
  readonly type: 'LINE'
  clone(): LineNode
}
interface EllipseNode extends DefaultShapeMixin, ConstraintMixin, CornerMixin {
  readonly type: 'ELLIPSE'
  clone(): EllipseNode
  arcData: ArcData
}
interface PolygonNode extends DefaultShapeMixin, ConstraintMixin, CornerMixin {
  readonly type: 'POLYGON'
  clone(): PolygonNode
  pointCount: number
}
interface StarNode extends DefaultShapeMixin, ConstraintMixin, CornerMixin {
  readonly type: 'STAR'
  clone(): StarNode
  pointCount: number
  innerRadius: number
}
interface VectorNode extends DefaultShapeMixin, ConstraintMixin, CornerMixin, VectorLikeMixin {
  readonly type: 'VECTOR'
  clone(): VectorNode
}
interface TextNode extends DefaultShapeMixin, ConstraintMixin, TextSublayerNode {
  readonly type: 'TEXT'
  clone(): TextNode
  textAlignHorizontal: 'LEFT' | 'CENTER' | 'RIGHT' | 'JUSTIFIED'
  textAlignVertical: 'TOP' | 'CENTER' | 'BOTTOM'
  textAutoResize: 'NONE' | 'WIDTH_AND_HEIGHT' | 'HEIGHT' | 'TRUNCATE'
  autoRename: boolean
  textStyleId: string | PluginAPI['mixed']
}
declare type ComponentPropertyType = 'BOOLEAN' | 'TEXT' | 'INSTANCE_SWAP' | 'VARIANT'
declare type InstanceSwapPreferredValue = {
  type: 'COMPONENT' | 'COMPONENT_SET'
  key: string
}
declare type ComponentPropertyOptions = {
  preferredValues?: InstanceSwapPreferredValue[]
}
declare type ComponentPropertyDefinitions = {
  [propertyName: string]: {
    type: ComponentPropertyType
    defaultValue: string | boolean
    preferredValues?: InstanceSwapPreferredValue[]
    variantOptions?: string[]
  }
}
interface ComponentSetNode
  extends BaseFrameMixin,
    PublishableMixin,
    PublishableNodeMixin,
    ComponentPropertiesMixin {
  readonly type: 'COMPONENT_SET'
  clone(): ComponentSetNode
  readonly defaultVariant: ComponentNode
  readonly variantGroupProperties: {
    [property: string]: {
      values: string[]
    }
  }
}
interface ComponentNode
  extends DefaultFrameMixin,
    PublishableMixin,
    PublishableNodeMixin,
    VariantMixin,
    ComponentPropertiesMixin {
  readonly type: 'COMPONENT'
  clone(): ComponentNode
  createInstance(): InstanceNode
  readonly instances: InstanceNode[]
}
declare type ComponentProperties = {
  [propertyName: string]: {
    type: ComponentPropertyType
    value: string | boolean
    preferredValues?: InstanceSwapPreferredValue[]
  }
}
interface InstanceNode extends DefaultFrameMixin, VariantMixin {
  readonly type: 'INSTANCE'
  clone(): InstanceNode
  mainComponent: ComponentNode | null
  swapComponent(componentNode: ComponentNode): void
  setProperties(properties: { [propertyName: string]: string | boolean }): void
  readonly componentProperties: ComponentProperties
  detachInstance(): FrameNode
  scaleFactor: number
  readonly exposedInstances: InstanceNode[]
  isExposedInstance: boolean
  readonly overrides: {
    id: string
    overriddenFields: NodeChangeProperty[]
  }[]
  resetOverrides(): void
}
interface BooleanOperationNode extends DefaultShapeMixin, ChildrenMixin, CornerMixin {
  readonly type: 'BOOLEAN_OPERATION'
  clone(): BooleanOperationNode
  booleanOperation: 'UNION' | 'INTERSECT' | 'SUBTRACT' | 'EXCLUDE'
}

interface SectionNode extends ChildrenMixin, MinimalFillsMixin, OpaqueNodeMixin {
  readonly type: 'SECTION'
  clone(): SectionNode
  resizeWithoutConstraints(width: number, height: number): void
}

declare type BaseNode = DocumentNode | PageNode | SceneNode
declare type SceneNode =
  | SliceNode
  | FrameNode
  | GroupNode
  | ComponentSetNode
  | ComponentNode
  | InstanceNode
  | BooleanOperationNode
  | VectorNode
  | StarNode
  | LineNode
  | EllipseNode
  | PolygonNode
  | RectangleNode
  | TextNode
  | SectionNode
declare type NodeType = BaseNode['type']
declare type StyleType = 'PAINT' | 'TEXT' | 'EFFECT' | 'GRID'
interface BaseStyle extends PublishableMixin, PluginDataMixin {
  readonly id: string
  readonly type: StyleType
  name: string
  remove(): void
}
interface PaintStyle extends BaseStyle {
  type: 'PAINT'
  paints: ReadonlyArray<Paint>
}
interface TextStyle extends BaseStyle {
  type: 'TEXT'
  fontSize: number
  textDecoration: TextDecoration
  fontName: FontName
  letterSpacing: LetterSpacing
  lineHeight: LineHeight
  paragraphIndent: number
  paragraphSpacing: number
  textCase: TextCase
}
interface EffectStyle extends BaseStyle {
  type: 'EFFECT'
  effects: ReadonlyArray<Effect>
}
interface GridStyle extends BaseStyle {
  type: 'GRID'
  layoutGrids: ReadonlyArray<LayoutGrid>
}
interface Image {
  readonly hash: string
  getBytesAsync(): Promise<Uint8Array>
}
interface BaseUser {
  readonly id: string | null
  readonly name: string
  readonly photoUrl: string | null
}
interface User extends BaseUser {
  readonly color: string
  readonly sessionId: number
}
interface ActiveUser extends User {
  readonly position: Vector | null
  readonly viewport: Rect
  readonly selection: string[]
}

interface ExplicitVariableModesMixin {
  explicitVariableModes: {
    [collectionId: string]: string
  }
  clearExplicitVariableModeForCollection(collection: VariableCollection): void
  setExplicitVariableModeForCollection(collection: VariableCollection, modeId: string): void
}

interface TeamLibraryAPI {
  getAvailableLibraryVariableCollectionsAsync(): Promise<LibraryVariableCollection[]>
  getVariablesInLibraryCollectionAsync(libraryCollectionKey: string): Promise<LibraryVariable[]>
}

interface VariablesAPI {
  getVariableByIdAsync(id: string): Promise<Variable | null>
  // getVariableById(id: string): Variable | null
  getVariableCollectionByIdAsync(id: string): Promise<VariableCollection | null>
  // getVariableCollectionById(id: string): VariableCollection | null
  getLocalVariablesAsync(type?: VariableResolvedDataType): Promise<Variable[]>
  // getLocalVariables(type?: VariableResolvedDataType): Variable[]
  getLocalVariableCollectionsAsync(): Promise<VariableCollection[]>
  // getLocalVariableCollections(): VariableCollection[]
  // createVariable(
  //   name: string,
  //   collectionId: string,
  //   resolvedType: VariableResolvedDataType,
  // ): Variable
  createVariable(
    name: string,
    collection: VariableCollection,
    resolvedType: VariableResolvedDataType,
  ): Variable
  createVariableCollection(name: string): VariableCollection
  createVariableAlias(variable: Variable): VariableAlias
  createVariableAliasByIdAsync(variableId: string): Promise<VariableAlias>
  setBoundVariableForPaint(
    paint: SolidPaint,
    field: VariableBindablePaintField,
    variable: Variable | null,
  ): SolidPaint
  setBoundVariableForEffect(
    effect: Effect,
    field: VariableBindableEffectField,
    variable: Variable | null,
  ): Effect
  setBoundVariableForLayoutGrid(
    layoutGrid: LayoutGrid,
    field: VariableBindableLayoutGridField,
    variable: Variable | null,
  ): LayoutGrid
  importVariableByKeyAsync(key: string): Promise<Variable>
}


interface LibraryVariableCollection {
  name: string
  key: string
  libraryName: string
}
interface LibraryVariable {
  name: string
  key: string
  resolvedType: VariableResolvedDataType
}

type VariableBindableNodeField =
  | 'height'
  | 'width'
  | 'characters'
  | 'itemSpacing'
  | 'paddingLeft'
  | 'paddingRight'
  | 'paddingTop'
  | 'paddingBottom'
  | 'visible'
  | 'topLeftRadius'
  | 'topRightRadius'
  | 'bottomLeftRadius'
  | 'bottomRightRadius'
  | 'minWidth'
  | 'maxWidth'
  | 'minHeight'
  | 'maxHeight'
  | 'counterAxisSpacing'
  | 'strokeWeight'
  | 'strokeTopWeight'
  | 'strokeRightWeight'
  | 'strokeBottomWeight'
  | 'strokeLeftWeight'
  | 'opacity'
  | 'gridRowGap'
  | 'gridColumnGap'
type VariableBindableTextField =
  | 'fontFamily'
  | 'fontSize'
  | 'fontStyle'
  | 'fontWeight'
  | 'letterSpacing'
  | 'lineHeight'
  | 'paragraphSpacing'
  | 'paragraphIndent'
type VariableBindablePaintField = 'color'
type VariableBindablePaintStyleField = 'paints'
type VariableBindableColorStopField = 'color'
type VariableBindableEffectField = 'color' | 'radius' | 'spread' | 'offsetX' | 'offsetY'
type VariableBindableEffectStyleField = 'effects'
type VariableBindableLayoutGridField = 'sectionSize' | 'count' | 'offset' | 'gutterSize'
type VariableBindableGridStyleField = 'layoutGrids'
type VariableBindableComponentPropertyField = 'value'
type VariableBindableComponentPropertyDefinitionField = 'defaultValue'

type VariableResolvedDataType = 'BOOLEAN' | 'COLOR' | 'FLOAT' | 'STRING'
interface VariableAlias {
  type: 'VARIABLE_ALIAS'
  id: string
}
type VariableValue = boolean | string | number | RGB | RGBA | VariableAlias
type VariableScope =
  | 'ALL_SCOPES'
  | 'TEXT_CONTENT'
  | 'CORNER_RADIUS'
  | 'WIDTH_HEIGHT'
  | 'GAP'
  | 'ALL_FILLS'
  | 'FRAME_FILL'
  | 'SHAPE_FILL'
  | 'TEXT_FILL'
  | 'STROKE_COLOR'
  | 'STROKE_FLOAT'
  | 'EFFECT_FLOAT'
  | 'EFFECT_COLOR'
  | 'OPACITY'
  | 'FONT_FAMILY'
  | 'FONT_STYLE'
  | 'FONT_WEIGHT'
  | 'FONT_SIZE'
  | 'LINE_HEIGHT'
  | 'LETTER_SPACING'
  | 'PARAGRAPH_SPACING'
  | 'PARAGRAPH_INDENT'
type CodeSyntaxPlatform = 'WEB' | 'ANDROID' | 'iOS'

interface Variable extends PluginDataMixin {
  readonly id: string
  name: string
  description: string
  hiddenFromPublishing: boolean
  getPublishStatusAsync(): Promise<PublishStatus>
  readonly remote: boolean
  readonly variableCollectionId: string
  readonly key: string
  readonly resolvedType: VariableResolvedDataType
  resolveForConsumer(consumer: SceneNode): {
    value: VariableValue
    resolvedType: VariableResolvedDataType
  }
  setValueForMode(modeId: string, newValue: VariableValue): void
  readonly valuesByMode: {
    [modeId: string]: VariableValue
  }
  remove(): void
  scopes: Array<VariableScope>
  readonly codeSyntax: {
    [platform in CodeSyntaxPlatform]?: string
  }
  setVariableCodeSyntax(platform: CodeSyntaxPlatform, value: string): void
  removeVariableCodeSyntax(platform: CodeSyntaxPlatform): void
}

interface VariableCollection extends PluginDataMixin {
  readonly id: string
  name: string
  hiddenFromPublishing: boolean
  getPublishStatusAsync(): Promise<PublishStatus>
  readonly remote: boolean
  readonly modes: Array<{
    modeId: string
    name: string
  }>
  readonly variableIds: string[]
  readonly defaultModeId: string
  readonly key: string
  remove(): void
  removeMode(modeId: string): void
  addMode(name: string): string
  renameMode(modeId: string, newName: string): void
}