summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.travis.yml13
-rw-r--r--app/main.js399
-rw-r--r--flow-libs/electron.js.flow160
-rw-r--r--flow-libs/history.js.flow24
-rw-r--r--flow-libs/nseventmonitor.js.flow42
-rw-r--r--flow-typed/npm/electron-log_vx.x.x.js4
-rw-r--r--flow-typed/npm/sudo-prompt_vx.x.x.js4
7 files changed, 433 insertions, 213 deletions
diff --git a/.travis.yml b/.travis.yml
index 167dfca444..a79ed8d260 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,6 +12,19 @@ before_script:
cache:
yarn: true
+install:
+ - yarn install
+
+ # FIXME: Flow throws error for optional dependencies
+ # missing from node_modules on unsupported platforms
+ # see: https://github.com/facebook/flow/issues/4171
+ - NSEVENTMON_INDEX_JS=node_modules/nseventmonitor/index.js;
+ if [ ! -f $NSEVENTMON_INDEX_JS ]; then
+ echo "Installing a stub for NSEventMonitor..";
+ mkdir -p `dirname $NSEVENTMON_INDEX_JS`;
+ echo "module.exports = {};" > $NSEVENTMON_INDEX_JS;
+ fi
+
script:
- yarn run lint
- yarn run flow
diff --git a/app/main.js b/app/main.js
index 0360d43f05..62d98010ee 100644
--- a/app/main.js
+++ b/app/main.js
@@ -1,3 +1,4 @@
+// @flow
import path from 'path';
import fs from 'fs';
import sudo from 'sudo-prompt';
@@ -5,241 +6,253 @@ import log from 'electron-log';
import { app, BrowserWindow, ipcMain, Tray, Menu, nativeImage } from 'electron';
import TrayIconManager from './lib/tray-icon-manager';
+import type { TrayIconType } from './lib/tray-icon-manager';
+
const isDevelopment = (process.env.NODE_ENV === 'development');
const isMacOS = (process.platform === 'darwin');
-let window = null;
-let tray = null;
+const appDelegate = {
+ _window: (null: ?BrowserWindow),
+ _tray: (null: ?Tray),
-// Override appData path to avoid collisions with old client
-// New userData path, i.e on macOS: ~/Library/Application Support/mullvad.vpn
-app.setPath('userData', path.join(app.getPath('appData'), 'mullvad.vpn'));
+ setup: () => {
+ // Override appData path to avoid collisions with old client
+ // New userData path, i.e on macOS: ~/Library/Application Support/mullvad.vpn
+ app.setPath('userData', path.join(app.getPath('appData'), 'mullvad.vpn'));
-ipcMain.on('on-browser-window-ready', () => {
- sendBackendInfo();
-});
+ if (isDevelopment) {
+ log.transports.console.level = 'debug';
-const configureLogger = () => {
+ // Disable log file in development
+ log.transports.file.level = false;
+ } else {
+ log.transports.console.level = 'info';
+ log.transports.file.level = 'info';
+ }
- if (isDevelopment) {
- log.transports.console.level = 'debug';
+ if (isDevelopment) {
+ appDelegate._startBackend();
+ }
- // Disable log file in development
- log.transports.file.level = false;
- } else {
- log.transports.console.level = 'info';
- log.transports.file.level = 'info';
- }
-};
-configureLogger();
+ app.on('window-all-closed', () => appDelegate.onAllWindowsClosed());
+ app.on('ready', () => appDelegate.onReady());
+ },
-const installDevTools = async () => {
- const installer = require('electron-devtools-installer');
- const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
- const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
- for(const name of extensions) {
- try {
- await installer.default(installer[name], forceDownload);
- } catch (e) {
- log.info(`Error installing ${name} extension: ${e.message}`);
- }
- }
-};
+ onReady: async () => {
+ const window = appDelegate._window = appDelegate._createWindow();
-const createWindow = () => {
- const contentHeight = 568;
- let options = {
- width: 320,
- height: contentHeight,
- resizable: false,
- maximizable: false,
- fullscreenable: false,
- show: true,
- webPreferences: {
- // prevents renderer process code from not running when window is hidden
- backgroundThrottling: false,
- // Enable experimental features
- blinkFeatures: ['CSSBackdropFilter'].join(',')
- }
- };
+ ipcMain.on('on-browser-window-ready', () => appDelegate._sendBackendInfo(window));
- // setup window flags to mimic popover on macOS
- if(isMacOS) {
- options = Object.assign({}, options, {
- height: contentHeight + 12, // 12 is the size of transparent area around arrow
- frame: false,
- transparent: true,
- show: false
- });
- }
+ window.loadURL('file://' + path.join(__dirname, 'index.html'));
- window = new BrowserWindow(options);
- window.loadURL('file://' + path.join(__dirname, 'index.html'));
-};
+ // create tray icon on macOS
+ if(isMacOS) {
+ appDelegate._tray = appDelegate._createTray(window);
+ }
-const createAppMenu = () => {
- const template = [
- {
- label: 'Mullvad',
- submenu: [
- { role: 'about' },
- { type: 'separator' },
- { role: 'quit' }
- ]
- },
- {
- label: 'Edit',
- submenu: [
- { role: 'cut' },
- { role: 'copy' },
- { role: 'paste' },
- { type: 'separator' },
- { role: 'selectall' }
- ]
+ appDelegate._setAppMenu();
+ appDelegate._addContextMenu(window);
+
+ if(isDevelopment) {
+ await appDelegate._installDevTools();
+ window.openDevTools({ mode: 'detach' });
}
- ];
+ },
- Menu.setApplicationMenu(Menu.buildFromTemplate(template));
-};
+ onAllWindowsClosed: () => {
+ app.quit();
+ },
+
+ _startBackend: () => {
+ const pathToBackend = path.resolve(process.env.MULLVAD_BACKEND || '../talpid_core/target/debug/talpid_daemon');
+ log.info('Starting the mullvad backend at', pathToBackend);
-const createContextMenu = () => {
- let menuTemplate = [
- { role: 'cut' },
- { role: 'copy' },
- { role: 'paste' },
- { type: 'separator' },
- { role: 'selectall' }
- ];
+ const options = {
+ name: 'mullvad backend',
+ };
- // add inspect element on right click menu
- window.webContents.on('context-menu', (_e, props) => {
- let inspectTemplate = [{
- label: 'Inspect element',
- click() {
- window.openDevTools({ mode: 'detach' });
- window.inspectElement(props.x, props.y);
+ sudo.exec(pathToBackend, options, (err) => {
+ if (err && err.signal !== 'SIGINT') {
+ log.info('Backend exited with error', err);
+ } else {
+ log.info('Backend exited');
}
- }];
+ });
+ },
- if(props.isEditable) {
- let inputMenu = menuTemplate;
+ _sendBackendInfo: (window: BrowserWindow) => {
+ const file = './.mullvad_rpc_address';
+ log.info('reading the ipc connection info from', file);
- // mixin 'inspect element' into standard menu when in development mode
- if(isDevelopment) {
- inputMenu = menuTemplate.concat([{type: 'separator'}], inspectTemplate);
+ fs.readFile(file, 'utf8', function (err,data) {
+ if (err) {
+ return log.info('Could not find backend connection info', err);
}
- Menu.buildFromTemplate(inputMenu).popup(window);
- } else if(isDevelopment) {
- // display inspect element for all non-editable
- // elements when in development mode
- Menu.buildFromTemplate(inspectTemplate).popup(window);
+ log.info('Read IPC connection info', data);
+ window.webContents.send('backend-info', {
+ addr: data,
+ });
+ });
+ },
+
+ _installDevTools: async () => {
+ const installer = require('electron-devtools-installer');
+ const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
+ const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
+ for(const name of extensions) {
+ try {
+ await installer.default(installer[name], forceDownload);
+ } catch (e) {
+ log.info(`Error installing ${name} extension: ${e.message}`);
+ }
}
- });
-};
+ },
-const toggleWindow = () => {
- if (window.isVisible()) {
- window.hide();
- } else {
- showWindow();
- }
-};
+ _createWindow: (): BrowserWindow => {
+ const contentHeight = 568;
+ let options = {
+ width: 320,
+ height: contentHeight,
+ resizable: false,
+ maximizable: false,
+ fullscreenable: false,
+ webPreferences: {
+ // prevents renderer process code from not running when window is hidden
+ backgroundThrottling: false,
+ // Enable experimental features
+ blinkFeatures: 'CSSBackdropFilter'
+ }
+ };
-const showWindow = () => {
- // position window based on tray icon location
- if(tray) {
- const { x, y } = getWindowPosition();
- window.setPosition(x, y, false);
- }
+ // setup window flags to mimic popover on macOS
+ if(isMacOS) {
+ options = Object.assign({}, options, {
+ height: contentHeight + 12, // 12 is the size of transparent area around arrow
+ frame: false,
+ transparent: true,
+ show: false
+ });
+ }
- window.show();
- window.focus();
-};
+ return new BrowserWindow(options);
+ },
-const getWindowPosition = () => {
- const windowBounds = window.getBounds();
- const trayBounds = tray.getBounds();
+ _setAppMenu: () => {
+ const template = [
+ {
+ label: 'Mullvad',
+ submenu: [
+ { role: 'about' },
+ { type: 'separator' },
+ { role: 'quit' }
+ ]
+ },
+ {
+ label: 'Edit',
+ submenu: [
+ { role: 'cut' },
+ { role: 'copy' },
+ { role: 'paste' },
+ { type: 'separator' },
+ { role: 'selectall' }
+ ]
+ }
+ ];
+ Menu.setApplicationMenu(Menu.buildFromTemplate(template));
+ },
- // center window horizontally below the tray icon
- const x = Math.round(trayBounds.x + (trayBounds.width / 2) - (windowBounds.width / 2));
+ _addContextMenu: (window: BrowserWindow) => {
+ let menuTemplate = [
+ { role: 'cut' },
+ { role: 'copy' },
+ { role: 'paste' },
+ { type: 'separator' },
+ { role: 'selectall' }
+ ];
- // position window vertically below the tray icon
- const y = Math.round(trayBounds.y + trayBounds.height);
+ // add inspect element on right click menu
+ window.webContents.on('context-menu', (_e: Event, props: { x: number, y: number }) => {
+ let inspectTemplate = [{
+ label: 'Inspect element',
+ click() {
+ window.openDevTools({ mode: 'detach' });
+ window.inspectElement(props.x, props.y);
+ }
+ }];
- return { x, y };
-};
+ if(props.isEditable) {
+ let inputMenu = menuTemplate;
-const createTray = () => {
- tray = new Tray(nativeImage.createEmpty());
- tray.setHighlightMode('never');
- tray.on('click', toggleWindow);
+ // mixin 'inspect element' into standard menu when in development mode
+ if(isDevelopment) {
+ inputMenu = menuTemplate.concat([{type: 'separator'}], inspectTemplate);
+ }
- // setup NSEvent monitor to fix inconsistent window.blur
- // see https://github.com/electron/electron/issues/8689
- const { NSEventMonitor, NSEventMask } = require('nseventmonitor');
- const trayIconManager = new TrayIconManager(tray, 'unsecured');
- const macEventMonitor = new NSEventMonitor();
- const eventMask = NSEventMask.leftMouseDown | NSEventMask.rightMouseDown;
+ Menu.buildFromTemplate(inputMenu).popup(window);
+ } else if(isDevelopment) {
+ // display inspect element for all non-editable
+ // elements when in development mode
+ Menu.buildFromTemplate(inspectTemplate).popup(window);
+ }
+ });
+ },
- // add IPC handler to change tray icon from renderer
- ipcMain.on('changeTrayIcon', (_, type) => trayIconManager.iconType = type);
+ _toggleWindow: (window: BrowserWindow, tray: ?Tray) => {
+ if(window.isVisible()) {
+ window.hide();
+ } else {
+ appDelegate._showWindow(window, tray);
+ }
+ },
- // setup event handlers
- window.on('show', () => macEventMonitor.start(eventMask, () => window.hide()));
- window.on('hide', () => macEventMonitor.stop());
- window.on('close', () => window.closeDevTools());
- window.on('blur', () => !window.isDevToolsOpened() && window.hide());
-};
+ _showWindow: (window: BrowserWindow, tray: ?Tray) => {
+ // position window based on tray icon location
+ if(tray) {
+ const { x, y } = appDelegate._getWindowPosition(window, tray);
+ window.setPosition(x, y, false);
+ }
-app.on('window-all-closed', () => {
- app.quit();
-});
+ window.show();
+ window.focus();
+ },
-app.on('ready', async () => {
- createWindow();
+ _getWindowPosition: (window: BrowserWindow, tray: Tray): { x: number, y: number } => {
+ const windowBounds = window.getBounds();
+ const trayBounds = tray.getBounds();
- // create tray icon on macOS
- isMacOS && createTray();
+ // center window horizontally below the tray icon
+ const x = Math.round(trayBounds.x + (trayBounds.width / 2) - (windowBounds.width / 2));
- createAppMenu();
- createContextMenu();
+ // position window vertically below the tray icon
+ const y = Math.round(trayBounds.y + trayBounds.height);
- if(isDevelopment) {
- await installDevTools();
- window.openDevTools({ mode: 'detach' });
- }
-});
+ return { x, y };
+ },
-const sendBackendInfo = () => {
- const file = './.mullvad_rpc_address';
- log.info('reading the ipc connection info from', file);
+ _createTray: (window: BrowserWindow): Tray => {
+ const tray = new Tray(nativeImage.createEmpty());
+ tray.setHighlightMode('never');
+ tray.on('click', () => appDelegate._toggleWindow(window, tray));
- fs.readFile(file, 'utf8', function (err,data) {
- if (err) {
- return log.info('Could not find backend connection info', err);
- }
+ // setup NSEvent monitor to fix inconsistent window.blur
+ // see https://github.com/electron/electron/issues/8689
+ const { NSEventMonitor, NSEventMask } = require('nseventmonitor');
+ const trayIconManager = new TrayIconManager(tray, 'unsecured');
+ const macEventMonitor = new NSEventMonitor();
+ const eventMask = NSEventMask.leftMouseDown | NSEventMask.rightMouseDown;
- log.info('Read IPC connection info', data);
- window.webContents.send('backend-info', {
- addr: data,
- });
- });
-};
+ // add IPC handler to change tray icon from renderer
+ ipcMain.on('changeTrayIcon', (_: Event, type: TrayIconType) => trayIconManager.iconType = type);
-const startBackend = () => {
- const pathToBackend = path.resolve(process.env.MULLVAD_BACKEND || '../talpid_core/target/debug/talpid_daemon');
- log.info('Starting the mullvad backend at', pathToBackend);
+ // setup event handlers
+ window.on('show', () => macEventMonitor.start(eventMask, () => window.hide()));
+ window.on('hide', () => macEventMonitor.stop());
+ window.on('close', () => window.closeDevTools());
+ window.on('blur', () => !window.isDevToolsOpened() && window.hide());
- const options = {
- name: 'mullvad backend',
- };
- sudo.exec(pathToBackend, options, (err) => {
- if (err && err.signal !== 'SIGINT') {
- log.info('Backend exited with error', err);
- } else {
- log.info('Backend exited');
- }
- });
+ return tray;
+ }
};
-if (isDevelopment) startBackend();
+
+appDelegate.setup();
diff --git a/flow-libs/electron.js.flow b/flow-libs/electron.js.flow
index e1157020d5..98358003aa 100644
--- a/flow-libs/electron.js.flow
+++ b/flow-libs/electron.js.flow
@@ -1,7 +1,6 @@
-/**
- * Flow annotations for Electron
- * @flow
- */
+// @flow
+
+import EventEmitter from 'events';
declare module 'electron' {
@@ -19,6 +18,38 @@ declare module 'electron' {
y: number;
}
+ // http://electron.atom.io/docs/api/app
+
+ declare class App extends EventEmitter {
+ getPath(name: string): string;
+ setPath(name: string, path: string): void;
+ quit(): void;
+ }
+
+ // http://electron.atom.io/docs/api/shell
+ declare type OpenExternalOptions = {
+ activate: boolean;
+ }
+
+ declare class Shell {
+ openExternal(url: string, options?: OpenExternalOptions, callback: (error: Error) => void): boolean;
+ }
+
+ // http://electron.atom.io/docs/api/remote
+
+ declare class Remote {
+ app: App;
+ getCurrentWindow(): BrowserWindow;
+ getCurrentWebContents(): WebContents;
+ getGlobal(name: string): ?mixed;
+ }
+
+ // http://electron.atom.io/docs/api/clipboard
+
+ declare class Clipboard {
+ writeText(text: string, type?: string): void;
+ }
+
// http://electron.atom.io/docs/api/native-image
declare class NativeImage {
@@ -26,26 +57,123 @@ declare module 'electron' {
getSize(): Size;
}
- declare var nativeImage: {
- createEmpty(): NativeImage,
- createFromPath(path: string): NativeImage,
- createFromBuffer(buffer: Buffer, scaleFactor?: number): NativeImage,
- createFromDataURL(dataURL: string): NativeImage,
- }
-
// http://electron.atom.io/docs/api/tray
- declare type TrayEvent = 'click' | 'double-click'
- declare class Tray {
+ declare class Tray extends EventEmitter {
constructor(image: NativeImage | string): void;
getBounds(): Rectangle;
setHighlightMode(mode: 'selection' | 'always' | 'never'): void;
setImage(image: NativeImage | string): void;
setPressedImage(image: NativeImage | string): void;
+ }
+
+ // http://electron.atom.io/docs/api/web-frame
+
+ declare class WebFrame extends EventEmitter {
+ setZoomLevelLimits(minimumLevel: number, maximumLevel: number): void;
+ }
+
+ // http://electron.atom.io/docs/api/ipc-renderer
+
+ declare class IpcRenderer extends EventEmitter {
+ send(channel: string, ...args: Array<mixed>): void;
+ }
+
+ // http://electron.atom.io/docs/api/ipc-main
- on(event: TrayEvent, listener: Function): this;
- once(event: TrayEvent, listener: Function): this;
- removeEventListener(event: TrayEvent, listener: Function): this;
+ declare class IpcMain extends EventEmitter {}
+
+ declare class WebContents extends EventEmitter {}
+
+ // http://electron.atom.io/docs/api/browser-window
+
+ declare type OpenDevToolsOptions = {
+ mode: 'right' | 'bottom' | 'undocked' | 'detach';
+ }
+
+ declare type WebPreferences = {
+ backgroundThrottling?: boolean;
+ scrollBounce?: boolean;
+ blinkFeatures?: string;
+ disableBlinkFeatures?: string;
+ }
+
+ declare type BrowserWindowConstructorOptions = {
+ width?: number;
+ height?: number;
+ resizable?: boolean;
+ maximizable?: boolean;
+ fullscreenable?: boolean;
+ show?: boolean;
+ frame?: boolean;
+ transparent?: boolean;
+ webPreferences?: WebPreferences;
+ }
+
+ declare type LoadURLOptions = {
+ userAgent?: string;
+ }
+
+ declare class BrowserWindow extends EventEmitter {
+ constructor(options: ?BrowserWindowConstructorOptions): this;
+ isVisible(): boolean;
+ show(): void;
+ hide(): void;
+ focus(): void;
+ setPosition(x: number, y: number, animate?: boolean): void;
+ getBounds(): Rectangle;
+ inspectElement(x: number, y: number): void;
+ isDevToolsOpened(): boolean;isDevToolsOpened(): boolean;
+ openDevTools(options?: OpenDevToolsOptions): void;
+ closeDevTools(): void;
+ loadURL(url: string, options?: LoadURLOptions): void;
+ webContents: WebContents;
+ }
+
+ // http://electron.atom.io/docs/api/menu-item
+ declare class MenuItem {}
+
+ // http://electron.atom.io/docs/api/menu
+
+ declare type MenuItemConstructorOptions = {
+ type?: 'normal' | 'separator' | 'submenu' | 'checkbox' | 'radio';
+ label?: string;
+ role?: string;
+ click?: (menuItem: MenuItem, browserWindow: BrowserWindow, event: Event) => void;
+ }
+
+ declare type PopupOptions = {
+ x?: number;
+ y?: number;
+ }
+
+ declare class Menu {
+ static buildFromTemplate(template: Array<MenuItemConstructorOptions>): Menu;
+ static setApplicationMenu(menu: Menu): void;
+ popup(browserWindow?: BrowserWindow, options?: PopupOptions): void;
+ }
+
+ // http://electron.atom.io/docs/api/app
+
+ declare class App extends EventEmitter {
+ setPath(name: string, path: string): void;
+ getPath(name: string): string;
+ quit(): void;
}
+ // MainInterface
+
+ declare var nativeImage: {
+ createEmpty(): NativeImage,
+ createFromPath(path: string): NativeImage,
+ createFromBuffer(buffer: Buffer, scaleFactor?: number): NativeImage,
+ createFromDataURL(dataURL: string): NativeImage
+ };
+ declare var webFrame: WebFrame;
+ declare var app: App;
+ declare var ipcRenderer: IpcRenderer;
+ declare var ipcMain: IpcMain;
+ declare var remote: Remote;
+ declare var shell: Shell;
+ declare var clipboard: Clipboard;
} \ No newline at end of file
diff --git a/flow-libs/history.js.flow b/flow-libs/history.js.flow
new file mode 100644
index 0000000000..69c25e2011
--- /dev/null
+++ b/flow-libs/history.js.flow
@@ -0,0 +1,24 @@
+// @flow
+
+declare module 'history' {
+
+ declare class History {
+ length: number;
+ action: string;
+ location: string;
+ index: number;
+ entries: Array<string>;
+ createHref(location: string): string;
+ push(path: string): void;
+ replace(path: string): void;
+ go(index: number): void;
+ goBack(): void;
+ goForward(): void;
+ canGo(index: number): boolean;
+ block(prompt?: boolean): void;
+ listen(listener: (location: string, action: string) => void): void;
+ }
+
+ declare function createMemoryHistory(): History;
+
+} \ No newline at end of file
diff --git a/flow-libs/nseventmonitor.js.flow b/flow-libs/nseventmonitor.js.flow
new file mode 100644
index 0000000000..33b0c06966
--- /dev/null
+++ b/flow-libs/nseventmonitor.js.flow
@@ -0,0 +1,42 @@
+declare module 'nseventmonitor' {
+
+ declare export class NSEventMonitor {
+ start(eventMask: number, handler: () => void): void;
+ stop(): void;
+ }
+
+ declare export var NSEventMask: {
+ leftMouseDown: number;
+ leftMouseUp: number;
+ rightMouseDown: number;
+ rightMouseUp: number;
+ mouseMoved: number;
+ leftMouseDragged: number;
+ rightMouseDragged: number;
+ mouseEntered: number;
+ mouseExited: number;
+ keyDown: number;
+ keyUp: number;
+ flagsChanged: number;
+ appKitDefined: number;
+ applicationDefined: number;
+ periodic: number;
+ cursorUpdate: number;
+ scrollWheel: number;
+ tabletPoint: number;
+ tabletProximity: number;
+ otherMouseDown: number;
+ otherMouseUp: number;
+ otherMouseDragged: number;
+ gesture: number;
+ magnify: number;
+ swipe: number;
+ rotate: number;
+ beginGesture: number;
+ endGesture: number;
+ smartMagnify: number;
+ maskPressure: number;
+ directTouch: number;
+ any: number;
+ }
+} \ No newline at end of file
diff --git a/flow-typed/npm/electron-log_vx.x.x.js b/flow-typed/npm/electron-log_vx.x.x.js
index 021fae4cdf..ea47a182aa 100644
--- a/flow-typed/npm/electron-log_vx.x.x.js
+++ b/flow-typed/npm/electron-log_vx.x.x.js
@@ -1,5 +1,5 @@
-// flow-typed signature: 8f24be350d06d53ea4029a4a47f3c9ed
-// flow-typed version: <<STUB>>/electron-log_v^2.2.0/flow_v0.46.0
+// flow-typed signature: a2b1f23f2fe8286d15c43e28d1f28578
+// flow-typed version: <<STUB>>/electron-log_v2.2.6/flow_v0.48.0
/**
* This is an autogenerated libdef stub for:
diff --git a/flow-typed/npm/sudo-prompt_vx.x.x.js b/flow-typed/npm/sudo-prompt_vx.x.x.js
index 78a3eeda38..3c762d1dca 100644
--- a/flow-typed/npm/sudo-prompt_vx.x.x.js
+++ b/flow-typed/npm/sudo-prompt_vx.x.x.js
@@ -1,5 +1,5 @@
-// flow-typed signature: 9f8752969e81b3c77889d339ee49deb6
-// flow-typed version: <<STUB>>/sudo-prompt_v^7.0.0/flow_v0.46.0
+// flow-typed signature: ff03b3d5b4912b377eef1ed260d6968f
+// flow-typed version: <<STUB>>/sudo-prompt_v7.0.0/flow_v0.48.0
/**
* This is an autogenerated libdef stub for: