Upload via GUI (7543 Dateien)

This commit is contained in:
2026-10-22 06:56:19 +00:00
parent e4585e50ee
commit d6518698b1
50 changed files with 1914 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
Copyright (c) 2020 Electron Maintainers.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+78
View File
@@ -0,0 +1,78 @@
# @electron/fuses
> Flip [Electron Fuses](https://github.com/electron/electron/blob/main/docs/tutorial/fuses.md) and customize your packaged build of Electron
[![CircleCI](https://circleci.com/gh/electron/fuses.svg?style=shield)](https://circleci.com/gh/electron/fuses)
[![npm version](http://img.shields.io/npm/v/@electron/fuses.svg)](https://npmjs.org/package/@electron/fuses)
## Usage
### Via JavaScript
```typescript
import { flipFuses, FuseVersion, FuseV1Options } from '@electron/fuses';
// During your build / package process
await flipFuses(
require('electron'), // Returns the path to the electron binary
{
version: FuseVersion.V1,
[FuseV1Options.RunAsNode]: false, // Disables ELECTRON_RUN_AS_NODE
[FuseV1Options.EnableCookieEncryption]: true, // Enables cookie encryption
[FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false, // Disables the NODE_OPTIONS environment variable
[FuseV1Options.EnableNodeCliInspectArguments]: false, // Disables the --inspect and --inspect-brk family of CLI options
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true, // Enables validation of the app.asar archive on macOS
[FuseV1Options.OnlyLoadAppFromAsar]: true, // Enforces that Electron will only load your app from "app.asar" instead of its normal search paths
[FuseV1Options.LoadBrowserProcessSpecificV8Snapshot]: true, // Loads V8 Snapshot from `browser_v8_context_snapshot.bin` for the browser process
[FuseV1Options.GrantFileProtocolExtraPrivileges]: true, // Grants the file protocol extra privileges
},
);
```
### From the command line
```sh
$ npx @electron/fuses read --app /Applications/Foo.app
$ npx @electron/fuses write --app /Applications/Foo.app <...key=on/off>
```
### Apple Silicon
For `arm64` macOS builds of your app if you are not immediately codesigning your app after flipping
the fuses you will need to pass `resetAdHocDarwinSignature: true` to the `flipFuses` method. Otherwise
the app will refuse to launch with code signature validation errors. This is a new security measure on
Apple Silicon devices.
```typescript
import { flipFuses, FuseVersion, FuseV1Options } from '@electron/fuses';
await flipFuses(
require('electron'),
{
version: FuseVersion.V1,
resetAdHocDarwinSignature: targetPlatform === 'darwin' && targetArch === 'arm64',
[FuseV1Options.RunAsNode]: false,
},
);
```
### New Fuses
If you want to ensure you provide a config for every fuse, even newly added fuses during Electron upgrades
you can set the `strictlyRequireAllFuses` option to `true`. This will hard fail the build if you are on
a version of `@electron/fuses` that doesn't have configuration options for every fuse in the Electron binary
you are targetting or if you don't provide a configuration for a specific fuse present in the Electron binary
you are targetting.
```typescript
import { flipFuses, FuseVersion, FuseV1Options } from '@electron/fuses';
await flipFuses(
require('electron'),
{
version: FuseVersion.V1,
strictlyRequireAllFuses: true,
[FuseV1Options.RunAsNode]: false,
},
);
```
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/env node
export {};
+146
View File
@@ -0,0 +1,146 @@
#!/usr/bin/env node
"use strict";
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
const chalk = require("chalk");
const minimist = require("minimist");
const path = require("path");
const _1 = require(".");
const config_1 = require("./config");
const constants_1 = require("./constants");
const mode = process.argv[2];
const readHelpText = `electron-fuses read --app [path-to-app]`;
const writeHelpText = `electron-fuses write --app [path-to-app] <...key=on/off>`;
if (mode !== 'read' && mode !== 'write') {
console.error('Invalid mode, check the usage below:');
console.info(readHelpText);
console.info(writeHelpText);
process.exit(0);
}
function stringForState(state) {
switch (state) {
case constants_1.FuseState.ENABLE:
return chalk.green('Enabled');
case constants_1.FuseState.DISABLE:
return chalk.red('Disabled');
case constants_1.FuseState.INHERIT:
return chalk.yellow('Inherited');
case constants_1.FuseState.REMOVED:
return chalk.strikethrough(chalk.red('Removed'));
}
}
if (mode === 'read') {
const argv = minimist(process.argv.slice(3), {
string: ['app'],
boolean: ['help'],
});
if (argv.help) {
console.log(readHelpText);
process.exit(0);
}
if (!argv.app) {
console.error('--app argument is required');
process.exit(1);
}
console.log('Analyzing app:', chalk.cyan(path.basename(argv.app)));
(0, _1.getCurrentFuseWire)(argv.app)
.then((config) => {
const { version, resetAdHocDarwinSignature, strictlyRequireAllFuses } = config, rest = __rest(config, ["version", "resetAdHocDarwinSignature", "strictlyRequireAllFuses"]);
console.log(`Fuse Version: ${chalk.cyan(`v${version}`)}`);
switch (config.version) {
case config_1.FuseVersion.V1:
for (const key of Object.keys(rest)) {
console.log(` ${chalk.yellow(config_1.FuseV1Options[key])} is ${stringForState(rest[key])}`);
}
break;
}
})
.catch((err) => {
console.error(err);
process.exit(1);
});
}
else {
const argv = minimist(process.argv.slice(3), {
string: ['app'],
boolean: ['help'],
});
if (argv.help) {
console.log(writeHelpText);
process.exit(0);
}
if (!argv.app) {
console.error('--app argument is required');
process.exit(1);
}
console.log('Analyzing app:', chalk.cyan(path.basename(argv.app)));
(0, _1.getCurrentFuseWire)(argv.app)
.then((config) => {
const { version, resetAdHocDarwinSignature } = config, rest = __rest(config, ["version", "resetAdHocDarwinSignature"]);
console.log(`Fuse Version: ${chalk.cyan(`v${version}`)}`);
const keyPairs = argv._ || [];
for (const keyPair of keyPairs) {
const [key, state] = keyPair.split('=');
if (!key || !state) {
console.error('Invalid fuse:', keyPair);
console.error('Must be in the format FuseName=on/off');
process.exit(1);
}
if (state !== 'on' && state !== 'off') {
console.error('Invalid fuse state:', chalk.yellow(keyPair));
console.error(`Fuses can only be set to the "${chalk.green('on')}" or "${chalk.red('off')}" state`);
process.exit(1);
}
switch (config.version) {
case config_1.FuseVersion.V1:
const validFuseNames = Object.keys(config_1.FuseV1Options).filter((k) => !/^[0-9]+$/.test(k));
if (!validFuseNames.includes(key)) {
console.error('Invalid fuse name', chalk.yellow(key));
console.error('Expected name to be one of', chalk.yellow(JSON.stringify(validFuseNames)));
process.exit(1);
}
const currentState = config[config_1.FuseV1Options[key]];
const newState = state === 'on' ? constants_1.FuseState.ENABLE : constants_1.FuseState.DISABLE;
if (currentState === newState) {
console.log(` ${chalk.yellow(key)} is already ${stringForState(currentState)} and will not be changed`);
}
else {
console.log(` ${chalk.yellow(key)} is ${stringForState(currentState)} and will become ${stringForState(newState)}`);
}
config[config_1.FuseV1Options[key]] = newState;
break;
}
}
console.log('Writing to app:', chalk.cyan(path.basename(argv.app)));
function adaptConfig(config) {
const { version, resetAdHocDarwinSignature } = config, rest = __rest(config, ["version", "resetAdHocDarwinSignature"]);
const fuseConfig = {
version,
resetAdHocDarwinSignature,
};
for (const key of Object.keys(rest)) {
fuseConfig[key] = rest[key] === constants_1.FuseState.ENABLE;
}
return fuseConfig;
}
return (0, _1.flipFuses)(argv.app, adaptConfig(config));
})
.then(() => {
console.log(chalk.green('Fuses written to disk'));
})
.catch((err) => {
console.error(err);
process.exit(1);
});
}
//# sourceMappingURL=bin.js.map
+1
View File
File diff suppressed because one or more lines are too long
+34
View File
@@ -0,0 +1,34 @@
export declare enum FuseVersion {
V1 = "1"
}
/**
* Maps config keys to their index in the fuse wire
*/
export declare enum FuseV1Options {
RunAsNode = 0,
EnableCookieEncryption = 1,
EnableNodeOptionsEnvironmentVariable = 2,
EnableNodeCliInspectArguments = 3,
EnableEmbeddedAsarIntegrityValidation = 4,
OnlyLoadAppFromAsar = 5,
LoadBrowserProcessSpecificV8Snapshot = 6,
GrantFileProtocolExtraPrivileges = 7
}
export declare type FuseV1Config<T = boolean> = {
version: FuseVersion.V1;
resetAdHocDarwinSignature?: boolean;
/**
* Ensures that all fuses in the fuse wire being set have been defined to a set value
* by the provided config. Set this to true to ensure you don't accidentally miss a
* fuse being added in future Electron upgrades.
*
* This option may default to "true" in a future version of @electron/fuses but currently
* defaults to "false"
*/
strictlyRequireAllFuses?: boolean;
} & ((Partial<Record<FuseV1Options, T>> & {
strictlyRequireAllFuses?: false | undefined;
}) | (Record<FuseV1Options, T> & {
strictlyRequireAllFuses: true;
}));
export declare type FuseConfig<T = boolean> = FuseV1Config<T>;
+22
View File
@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FuseV1Options = exports.FuseVersion = void 0;
var FuseVersion;
(function (FuseVersion) {
FuseVersion["V1"] = "1";
})(FuseVersion = exports.FuseVersion || (exports.FuseVersion = {}));
/**
* Maps config keys to their index in the fuse wire
*/
var FuseV1Options;
(function (FuseV1Options) {
FuseV1Options[FuseV1Options["RunAsNode"] = 0] = "RunAsNode";
FuseV1Options[FuseV1Options["EnableCookieEncryption"] = 1] = "EnableCookieEncryption";
FuseV1Options[FuseV1Options["EnableNodeOptionsEnvironmentVariable"] = 2] = "EnableNodeOptionsEnvironmentVariable";
FuseV1Options[FuseV1Options["EnableNodeCliInspectArguments"] = 3] = "EnableNodeCliInspectArguments";
FuseV1Options[FuseV1Options["EnableEmbeddedAsarIntegrityValidation"] = 4] = "EnableEmbeddedAsarIntegrityValidation";
FuseV1Options[FuseV1Options["OnlyLoadAppFromAsar"] = 5] = "OnlyLoadAppFromAsar";
FuseV1Options[FuseV1Options["LoadBrowserProcessSpecificV8Snapshot"] = 6] = "LoadBrowserProcessSpecificV8Snapshot";
FuseV1Options[FuseV1Options["GrantFileProtocolExtraPrivileges"] = 7] = "GrantFileProtocolExtraPrivileges";
})(FuseV1Options = exports.FuseV1Options || (exports.FuseV1Options = {}));
//# sourceMappingURL=config.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;AAAA,IAAY,WAEX;AAFD,WAAY,WAAW;IACrB,uBAAQ,CAAA;AACV,CAAC,EAFW,WAAW,GAAX,mBAAW,KAAX,mBAAW,QAEtB;AAED;;GAEG;AACH,IAAY,aASX;AATD,WAAY,aAAa;IACvB,2DAAa,CAAA;IACb,qFAA0B,CAAA;IAC1B,iHAAwC,CAAA;IACxC,mGAAiC,CAAA;IACjC,mHAAyC,CAAA;IACzC,+EAAuB,CAAA;IACvB,iHAAwC,CAAA;IACxC,yGAAoC,CAAA;AACtC,CAAC,EATW,aAAa,GAAb,qBAAa,KAAb,qBAAa,QASxB"}
+7
View File
@@ -0,0 +1,7 @@
export declare const SENTINEL = "dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX";
export declare enum FuseState {
DISABLE = 48,
ENABLE = 49,
REMOVED = 114,
INHERIT = 144
}
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FuseState = exports.SENTINEL = void 0;
exports.SENTINEL = 'dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX';
var FuseState;
(function (FuseState) {
FuseState[FuseState["DISABLE"] = 48] = "DISABLE";
FuseState[FuseState["ENABLE"] = 49] = "ENABLE";
FuseState[FuseState["REMOVED"] = 114] = "REMOVED";
FuseState[FuseState["INHERIT"] = 144] = "INHERIT";
})(FuseState = exports.FuseState || (exports.FuseState = {}));
//# sourceMappingURL=constants.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,QAAQ,GAAG,kCAAkC,CAAC;AAE3D,IAAY,SAKX;AALD,WAAY,SAAS;IACnB,gDAAc,CAAA;IACd,8CAAa,CAAA;IACb,iDAAc,CAAA;IACd,iDAAc,CAAA;AAChB,CAAC,EALW,SAAS,GAAT,iBAAS,KAAT,iBAAS,QAKpB"}
+5
View File
@@ -0,0 +1,5 @@
import { FuseConfig } from './config';
import { FuseState } from './constants';
export * from './config';
export declare const getCurrentFuseWire: (pathToElectron: string) => Promise<FuseConfig<FuseState>>;
export declare const flipFuses: (pathToElectron: string, fuseConfig: FuseConfig) => Promise<number>;
+155
View File
@@ -0,0 +1,155 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.flipFuses = exports.getCurrentFuseWire = void 0;
const cp = require("child_process");
const fs = require("fs-extra");
const path = require("path");
const config_1 = require("./config");
const constants_1 = require("./constants");
__exportStar(require("./config"), exports);
const state = (b) => b === undefined ? constants_1.FuseState.INHERIT : b ? constants_1.FuseState.ENABLE : constants_1.FuseState.DISABLE;
const buildFuseV1Wire = (config, wireLength) => {
const { version } = config, nonVersionConfig = __rest(config, ["version"]);
const badFuseOption = Object.keys(nonVersionConfig).find((fuseOption) => parseInt(fuseOption, 10) >= wireLength);
if (badFuseOption !== undefined) {
throw new Error(`Trying to configure ${config_1.FuseV1Options[badFuseOption]} but the fuse wire in this version of Electron is not long enough`);
}
return [
state(config[config_1.FuseV1Options.RunAsNode]),
state(config[config_1.FuseV1Options.EnableCookieEncryption]),
state(config[config_1.FuseV1Options.EnableNodeOptionsEnvironmentVariable]),
state(config[config_1.FuseV1Options.EnableNodeCliInspectArguments]),
state(config[config_1.FuseV1Options.EnableEmbeddedAsarIntegrityValidation]),
state(config[config_1.FuseV1Options.OnlyLoadAppFromAsar]),
state(config[config_1.FuseV1Options.LoadBrowserProcessSpecificV8Snapshot]),
state(config[config_1.FuseV1Options.GrantFileProtocolExtraPrivileges]),
];
};
const pathToFuseFile = (pathToElectron) => {
if (pathToElectron.endsWith('.app')) {
return path.resolve(pathToElectron, 'Contents', 'Frameworks', 'Electron Framework.framework', 'Electron Framework');
}
if (pathToElectron.includes('.app')) {
return path.resolve(pathToElectron, '..', '..', 'Frameworks', 'Electron Framework.framework', 'Electron Framework');
}
return pathToElectron;
};
const setFuseWire = async (pathToElectron, fuseVersion, strictlyRequireAllFuses, fuseWireBuilder, fuseNamer) => {
const fuseFilePath = pathToFuseFile(pathToElectron);
const electron = await fs.readFile(fuseFilePath);
const firstSentinel = electron.indexOf(constants_1.SENTINEL);
const lastSentinel = electron.lastIndexOf(constants_1.SENTINEL);
// If the last sentinel is different to the first sentinel we are probably in a universal build
// We should flip the fuses in both sentinels to affect both slices of the universal binary
const sentinels = firstSentinel === lastSentinel ? [firstSentinel] : [firstSentinel, lastSentinel];
for (const indexOfSentinel of sentinels) {
if (indexOfSentinel === -1) {
throw new Error('Could not find sentinel in the provided Electron binary, fuses are only supported in Electron 12 and higher');
}
const fuseWirePosition = indexOfSentinel + constants_1.SENTINEL.length;
const fuseWireVersion = electron[fuseWirePosition];
if (parseInt(fuseVersion, 10) !== fuseWireVersion) {
throw new Error(`Provided fuse wire version "${parseInt(fuseVersion, 10)}" does not match watch was found in the binary "${fuseWireVersion}". You should update your usage of @electron/fuses.`);
}
const fuseWireLength = electron[fuseWirePosition + 1];
const wire = fuseWireBuilder(fuseWireLength).slice(0, fuseWireLength);
if (wire.length < fuseWireLength && strictlyRequireAllFuses) {
throw new Error(`strictlyRequireAllFuses: The fuse wire in the Electron binary has ${fuseWireLength} fuses but you only provided a config for ${wire.length} fuses, you may need to update @electron/fuses or provide additional fuse settings`);
}
for (let i = 0; i < wire.length; i++) {
const idx = fuseWirePosition + 2 + i;
const currentState = electron[idx];
const newState = wire[i];
if (currentState === constants_1.FuseState.REMOVED && newState !== constants_1.FuseState.INHERIT) {
console.warn(`Overriding fuse "${fuseNamer(i)}" that has been marked as removed, setting this fuse is a noop`);
}
if (newState === constants_1.FuseState.INHERIT) {
if (strictlyRequireAllFuses) {
throw new Error(`strictlyRequireAllFuses: Missing explicit configuration for fuse ${fuseNamer(i)}`);
}
continue;
}
electron[idx] = newState;
}
}
await fs.writeFile(fuseFilePath, electron);
return sentinels.length;
};
const getCurrentFuseWire = async (pathToElectron) => {
const fuseFilePath = pathToFuseFile(pathToElectron);
const electron = await fs.readFile(fuseFilePath);
const fuseWirePosition = electron.indexOf(constants_1.SENTINEL) + constants_1.SENTINEL.length;
if (fuseWirePosition - constants_1.SENTINEL.length === -1) {
throw new Error('Could not find sentinel in the provided Electron binary, fuses are only supported in Electron 12 and higher');
}
const fuseWireVersion = electron[fuseWirePosition];
const fuseWireLength = electron[fuseWirePosition + 1];
const fuseConfig = {
version: `${fuseWireVersion}`,
};
for (let i = 0; i < fuseWireLength; i++) {
const idx = fuseWirePosition + 2 + i;
const currentState = electron[idx];
switch (fuseConfig.version) {
case config_1.FuseVersion.V1:
fuseConfig[i] = currentState;
break;
}
}
return fuseConfig;
};
exports.getCurrentFuseWire = getCurrentFuseWire;
const flipFuses = async (pathToElectron, fuseConfig) => {
let numSentinels;
switch (fuseConfig.version) {
case config_1.FuseVersion.V1:
numSentinels = await setFuseWire(pathToElectron, fuseConfig.version, fuseConfig.strictlyRequireAllFuses || false, buildFuseV1Wire.bind(null, fuseConfig), (i) => config_1.FuseV1Options[i]);
break;
default:
throw new Error(`Unsupported fuse version number: ${fuseConfig.version}`);
}
// Reset the ad-hoc signature on macOS, should only be done for arm64 apps
if (fuseConfig.resetAdHocDarwinSignature && pathToElectron.includes('.app')) {
const pathToApp = `${pathToElectron.split('.app')[0]}.app`;
const result = cp.spawnSync('codesign', [
'--sign',
'-',
'--force',
'--preserve-metadata=entitlements,requirements,flags,runtime',
'--deep',
pathToApp,
]);
if (result.status !== 0) {
console.error(result.stderr.toString());
throw new Error(`Ad-hoc codesign failed with status: ${result.status}`);
}
}
return numSentinels;
};
exports.flipFuses = flipFuses;
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+58
View File
@@ -0,0 +1,58 @@
{
"name": "@electron/fuses",
"version": "1.8.0",
"main": "dist/index.js",
"license": "MIT",
"bin": {
"electron-fuses": "dist/bin.js"
},
"scripts": {
"build": "tsc",
"test": "jest",
"prepublishOnly": "tsc",
"prepare": "husky install"
},
"devDependencies": {
"@electron/get": "^2.0.1",
"@electron/universal": "^1.3.0",
"@types/fs-extra": "^9.0.1",
"@types/jest": "^29.0.3",
"@types/minimist": "^1.2.1",
"@types/node": "^14.11.2",
"extract-zip": "^2.0.1",
"husky": "^8.0.0",
"jest": "^29.0.3",
"lint-staged": "^10.4.0",
"prettier": "^2.1.2",
"ts-jest": "^29.0.1",
"typescript": "^4.3.3"
},
"lint-staged": {
"*.ts": [
"prettier --write"
]
},
"dependencies": {
"chalk": "^4.1.1",
"fs-extra": "^9.0.1",
"minimist": "^1.2.5"
},
"files": [
"dist",
"README.md"
],
"description": "Flip Electron Fuses and customize your packaged build of Electron",
"repository": {
"type": "git",
"url": "git+https://github.com/electron/fuses.git"
},
"keywords": [
"electron",
"fuses"
],
"author": "Electron Community",
"bugs": {
"url": "https://github.com/electron/fuses/issues"
},
"homepage": "https://github.com/electron/fuses#readme"
}