mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-20 21:37:17 +00:00
Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
85b1e3c2c2 | ||
![]() |
e5d1b4ce23 | ||
![]() |
aac092fd4d | ||
![]() |
ff852c029e | ||
![]() |
4759bc7686 | ||
![]() |
039a022353 |
8
.github/workflows/flowzone.yml
vendored
8
.github/workflows/flowzone.yml
vendored
@ -21,18 +21,18 @@ jobs:
|
||||
custom_test_matrix: >
|
||||
{
|
||||
"os": [
|
||||
["ubuntu-20.04"],
|
||||
["ubuntu-22.04"],
|
||||
["windows-2019"],
|
||||
["macos-12"],
|
||||
["macos-13"],
|
||||
["macos-latest-xlarge"]
|
||||
]
|
||||
}
|
||||
custom_publish_matrix: >
|
||||
{
|
||||
"os": [
|
||||
["ubuntu-20.04"],
|
||||
["ubuntu-22.04"],
|
||||
["windows-2019"],
|
||||
["macos-12"],
|
||||
["macos-13"],
|
||||
["macos-latest-xlarge"]
|
||||
]
|
||||
}
|
||||
|
@ -1,3 +1,25 @@
|
||||
- commits:
|
||||
- subject: Add informational notice about how to disable analytics collection
|
||||
hash: aac092fd4df8750024c082b25dcbd0ae6ee618fd
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
author: myarmolinsky
|
||||
nested: []
|
||||
version: 2.1.0
|
||||
title: ""
|
||||
date: 2025-02-27T16:16:57.036Z
|
||||
- commits:
|
||||
- subject: "major: build on ubuntu 22 and macos 13"
|
||||
hash: 039a022353d1980ef9ddd19166515c531e48aba4
|
||||
body: ""
|
||||
footer: {}
|
||||
author: Edwin Joassart
|
||||
nested: []
|
||||
version: 2.0.0
|
||||
title: ""
|
||||
date: 2025-02-20T14:27:01.338Z
|
||||
- commits:
|
||||
- subject: "patch: bump etcher-sdk to 9.1.2"
|
||||
hash: c726b51dca3383c76f4bf824fd5d594ac3069180
|
||||
@ -1254,13 +1276,10 @@
|
||||
nested: []
|
||||
- subject: "Patch: run linux build on ubuntu-20.04"
|
||||
hash: adcd8e0325bc891460b3e51aa5403f8675189f13
|
||||
body: >-
|
||||
as [`18.04` has been
|
||||
removed](https://github.blog/changelog/2022-08-09-github-actions-the-ubuntu-18-04-actions-runner-image-is-being-deprecated-and-will-be-removed-by-12-1-22/)
|
||||
body: |-
|
||||
as [`18.04` has been removed](https://github.blog/changelog/2022-08-09-github-actions-the-ubuntu-18-04-actions-runner-image-is-being-deprecated-and-will-be-removed-by-12-1-22/)
|
||||
|
||||
|
||||
We cannot use `latest` as the glibc version will cause issue with older
|
||||
ubuntu version.
|
||||
We cannot use `latest` as the glibc version will cause issue with older ubuntu version.
|
||||
footer: {}
|
||||
author: Edwin Joassart
|
||||
nested: []
|
||||
@ -12005,40 +12024,19 @@
|
||||
changelog-entry: Don't include user paths in Mixpanel usage reports
|
||||
link: https://github.com/resin-io-modules/etcher-image-stream/blob/master/CHANGELOG.md
|
||||
subject: Fix uncaught exception if no file was selected from a dialog
|
||||
body: >-
|
||||
body: |-
|
||||
The following error is thrown if the open file dialog is cancelled
|
||||
|
||||
without any selection:
|
||||
|
||||
Unhandled rejection TypeError: Cannot read property '0' of undefined
|
||||
|
||||
at Number.indexedGetter
|
||||
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/call_get.js:106:15)
|
||||
|
||||
at Number.tryCatcher
|
||||
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/util.js:16:23)
|
||||
|
||||
at Promise._settlePromiseFromHandler
|
||||
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:503:31)
|
||||
|
||||
at Promise._settlePromise
|
||||
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:560:18)
|
||||
|
||||
at Promise._settlePromise0
|
||||
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:605:10)
|
||||
|
||||
at Promise._settlePromises
|
||||
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:684:18)
|
||||
|
||||
at Async._drainQueue
|
||||
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:126:16)
|
||||
|
||||
at Async._drainQueues
|
||||
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:136:10)
|
||||
|
||||
at Immediate.Async.drainQueues [as _onImmediate]
|
||||
(/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:16:14)
|
||||
|
||||
at Number.indexedGetter (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/call_get.js:106:15)
|
||||
at Number.tryCatcher (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/util.js:16:23)
|
||||
at Promise._settlePromiseFromHandler (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:503:31)
|
||||
at Promise._settlePromise (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:560:18)
|
||||
at Promise._settlePromise0 (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:605:10)
|
||||
at Promise._settlePromises (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/promise.js:684:18)
|
||||
at Async._drainQueue (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:126:16)
|
||||
at Async._drainQueues (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:136:10)
|
||||
at Immediate.Async.drainQueues [as _onImmediate] (/home/parallels/Projects/etcher/node_modules/bluebird/js/release/async.js:16:14)
|
||||
at processImmediate [as _immediateCallback] (timers.js:383:17)
|
||||
- hash: 6bd086f1c5c6654a47125cf2d46788655cae2553
|
||||
author: Juan Cruz Viotti
|
||||
@ -12635,21 +12633,14 @@
|
||||
changelog-entry: Use info icon instead of "SHOW FULL FILE NAME" in first step.
|
||||
fixes: https://github.com/resin-io/etcher/issues/458
|
||||
subject: Make use of AppImage desktop integration script
|
||||
body: >-
|
||||
body: |-
|
||||
This is useful to prompt the user to install the `.desktop` file.
|
||||
|
||||
The `Description` key in `Etcher.desktop` was changed to `Comment` since
|
||||
|
||||
`desktop-file-validate` complained with:
|
||||
|
||||
Etcher.desktop: error: file contains key "Description" in group "Desktop
|
||||
|
||||
Entry", but keys extending the format should start with "X-"
|
||||
|
||||
After checking the desktop file format specification, the correct key
|
||||
|
||||
should be "Comment"
|
||||
|
||||
(https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s05.html).
|
||||
- hash: c3e360e61933ef0044c005b5e92c879ff9a47c49
|
||||
author: Juan Cruz Viotti
|
||||
@ -12862,17 +12853,12 @@
|
||||
changelog-entry: Fix flashing never starting after elevation in GNU/Linux.
|
||||
fixes: https://github.com/resin-io/etcher/issues/665
|
||||
subject: Make all angular modules export the name of the module
|
||||
body: >-
|
||||
body: |-
|
||||
This makes them very nicely require-able, for example:
|
||||
|
||||
angular.module('MyModule', [
|
||||
|
||||
require('my-dependency');
|
||||
|
||||
]);
|
||||
|
||||
From
|
||||
https://medium.com/@kentcdodds/how-to-distribute-your-angularjs-module-e04d4dd58ddc#.yqg2zo8im
|
||||
From https://medium.com/@kentcdodds/how-to-distribute-your-angularjs-module-e04d4dd58ddc#.yqg2zo8im
|
||||
- hash: b8f63af3f81bca3abd055303bc91ab35eb126655
|
||||
author: Juan Cruz Viotti
|
||||
footers:
|
||||
|
10
CHANGELOG.md
10
CHANGELOG.md
@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# v2.1.0
|
||||
## (2025-02-27)
|
||||
|
||||
* Add informational notice about how to disable analytics collection [myarmolinsky]
|
||||
|
||||
# v2.0.0
|
||||
## (2025-02-20)
|
||||
|
||||
* major: build on ubuntu 22 and macos 13 [Edwin Joassart]
|
||||
|
||||
# v1.19.25
|
||||
## (2024-10-10)
|
||||
|
||||
|
@ -308,6 +308,7 @@ const FlowSelector = styled(
|
||||
|
||||
interface SourceSelectorProps {
|
||||
flashing: boolean;
|
||||
hideAnalyticsAlert: () => void;
|
||||
}
|
||||
|
||||
interface SourceSelectorState {
|
||||
@ -359,6 +360,20 @@ export class SourceSelector extends React.Component<
|
||||
ipcRenderer.removeListener('select-image', this.onSelectImage);
|
||||
}
|
||||
|
||||
public componentDidUpdate(
|
||||
_prevProps: Readonly<SourceSelectorProps>,
|
||||
prevState: Readonly<SourceSelectorState>,
|
||||
) {
|
||||
if (
|
||||
(!prevState.showDriveSelector && this.state.showDriveSelector) ||
|
||||
(!prevState.showURLSelector && this.state.showURLSelector) ||
|
||||
(!prevState.showImageDetails && this.state.showImageDetails) ||
|
||||
(!prevState.imageSelectorOpen && this.state.imageSelectorOpen)
|
||||
) {
|
||||
this.props.hideAnalyticsAlert();
|
||||
}
|
||||
}
|
||||
|
||||
private async onSelectImage(_event: IpcRendererEvent, imagePath: string) {
|
||||
this.setState({ imageLoading: true });
|
||||
await this.selectSource(
|
||||
@ -382,6 +397,7 @@ export class SourceSelector extends React.Component<
|
||||
});
|
||||
|
||||
selectionState.deselectImage();
|
||||
this.props.hideAnalyticsAlert();
|
||||
}
|
||||
|
||||
private selectSource(
|
||||
|
@ -100,12 +100,14 @@ interface TargetSelectorProps {
|
||||
disabled: boolean;
|
||||
hasDrive: boolean;
|
||||
flashing: boolean;
|
||||
hideAnalyticsAlert: () => void;
|
||||
}
|
||||
|
||||
export const TargetSelector = ({
|
||||
disabled,
|
||||
hasDrive,
|
||||
flashing,
|
||||
hideAnalyticsAlert,
|
||||
}: TargetSelectorProps) => {
|
||||
// TODO: inject these from redux-connector
|
||||
const [{ driveListLabel, targets }, setStateSlice] = React.useState(
|
||||
@ -137,6 +139,7 @@ export const TargetSelector = ({
|
||||
tooltip={driveListLabel}
|
||||
openDriveSelector={() => {
|
||||
setShowTargetSelectorModal(true);
|
||||
hideAnalyticsAlert();
|
||||
}}
|
||||
reselectDrive={() => {
|
||||
analytics.logEvent('Reselect drive');
|
||||
|
@ -15,12 +15,13 @@
|
||||
*/
|
||||
|
||||
import CogSvg from '@fortawesome/fontawesome-free/svgs/solid/gear.svg';
|
||||
import CloseSvg from '@fortawesome/fontawesome-free/svgs/solid/x.svg';
|
||||
import QuestionCircleSvg from '@fortawesome/fontawesome-free/svgs/solid/circle-question.svg';
|
||||
|
||||
import * as path from 'path';
|
||||
import prettyBytes from 'pretty-bytes';
|
||||
import * as React from 'react';
|
||||
import { Flex } from 'rendition';
|
||||
import { Alert, Flex, Link } from 'rendition';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import FinishPage from '../../components/finish/finish';
|
||||
@ -35,6 +36,7 @@ import { observe } from '../../models/store';
|
||||
import { open as openExternal } from '../../os/open-external/services/open-external';
|
||||
import {
|
||||
IconButton as BaseIcon,
|
||||
IconButton,
|
||||
ThemedProvider,
|
||||
} from '../../styled-components';
|
||||
|
||||
@ -46,6 +48,7 @@ import { FlashStep } from './Flash';
|
||||
|
||||
import EtcherSvg from '../../../assets/etcher.svg';
|
||||
import { SafeWebview } from '../../components/safe-webview/safe-webview';
|
||||
import { theme } from '../../theme';
|
||||
|
||||
const Icon = styled(BaseIcon)`
|
||||
margin-right: 20px;
|
||||
@ -97,6 +100,8 @@ const StepBorder = styled.div<{
|
||||
margin-left: ${(props) => (props.right ? '-120px' : undefined)};
|
||||
`;
|
||||
|
||||
const ANALYTICS_ALERT_VISIBILITY_KEY = 'analytics_alert_visible';
|
||||
|
||||
interface MainPageStateFromStore {
|
||||
isFlashing: boolean;
|
||||
hasImage: boolean;
|
||||
@ -113,6 +118,7 @@ interface MainPageState {
|
||||
isWebviewShowing: boolean;
|
||||
hideSettings: boolean;
|
||||
featuredProjectURL?: string;
|
||||
analyticsAlertIsVisible: boolean;
|
||||
}
|
||||
|
||||
export class MainPage extends React.Component<
|
||||
@ -125,6 +131,8 @@ export class MainPage extends React.Component<
|
||||
current: 'main',
|
||||
isWebviewShowing: false,
|
||||
hideSettings: true,
|
||||
analyticsAlertIsVisible:
|
||||
localStorage.getItem(ANALYTICS_ALERT_VISIBILITY_KEY) !== 'false',
|
||||
...this.stateHelper(),
|
||||
};
|
||||
}
|
||||
@ -153,6 +161,13 @@ export class MainPage extends React.Component<
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
private hideAnalyticsAlert = () => {
|
||||
if (this.state.analyticsAlertIsVisible) {
|
||||
localStorage.setItem(ANALYTICS_ALERT_VISIBILITY_KEY, 'false');
|
||||
this.setState({ analyticsAlertIsVisible: false });
|
||||
}
|
||||
};
|
||||
|
||||
public async componentDidMount() {
|
||||
observe(() => {
|
||||
this.setState(this.stateHelper());
|
||||
@ -160,6 +175,17 @@ export class MainPage extends React.Component<
|
||||
this.setState({ featuredProjectURL: await this.getFeaturedProjectURL() });
|
||||
}
|
||||
|
||||
public componentDidUpdate(
|
||||
_prevProps: object,
|
||||
prevState: Readonly<MainPageState & MainPageStateFromStore>,
|
||||
) {
|
||||
if (this.state.analyticsAlertIsVisible) {
|
||||
if (prevState.hideSettings !== this.state.hideSettings) {
|
||||
this.setState({ analyticsAlertIsVisible: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private renderMain() {
|
||||
const state = flashState.getFlashState();
|
||||
const shouldDriveStepBeDisabled = !this.state.hasImage;
|
||||
@ -169,86 +195,127 @@ export class MainPage extends React.Component<
|
||||
!this.state.isFlashing || !this.state.isWebviewShowing;
|
||||
return (
|
||||
<Flex
|
||||
m={`110px ${this.state.isWebviewShowing ? 35 : 55}px`}
|
||||
justifyContent="space-between"
|
||||
m={`110px ${this.state.isWebviewShowing ? 35 : 55}px 18px ${this.state.isWebviewShowing ? 35 : 55}px`}
|
||||
flexDirection="column"
|
||||
>
|
||||
{notFlashingOrSplitView && (
|
||||
<>
|
||||
<SourceSelector flashing={this.state.isFlashing} />
|
||||
<Flex>
|
||||
<StepBorder disabled={shouldDriveStepBeDisabled} left />
|
||||
</Flex>
|
||||
<TargetSelector
|
||||
disabled={shouldDriveStepBeDisabled}
|
||||
hasDrive={this.state.hasDrive}
|
||||
flashing={this.state.isFlashing}
|
||||
/>
|
||||
<Flex>
|
||||
<StepBorder disabled={shouldFlashStepBeDisabled} right />
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
<Flex
|
||||
justifyContent="space-between"
|
||||
mb={this.state.analyticsAlertIsVisible ? '0px' : '92px'}
|
||||
>
|
||||
{notFlashingOrSplitView && (
|
||||
<>
|
||||
<SourceSelector
|
||||
flashing={this.state.isFlashing}
|
||||
hideAnalyticsAlert={this.hideAnalyticsAlert}
|
||||
/>
|
||||
<Flex>
|
||||
<StepBorder disabled={shouldDriveStepBeDisabled} left />
|
||||
</Flex>
|
||||
<TargetSelector
|
||||
disabled={shouldDriveStepBeDisabled}
|
||||
hasDrive={this.state.hasDrive}
|
||||
flashing={this.state.isFlashing}
|
||||
hideAnalyticsAlert={this.hideAnalyticsAlert}
|
||||
/>
|
||||
<Flex>
|
||||
<StepBorder disabled={shouldFlashStepBeDisabled} right />
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
|
||||
{this.state.isFlashing && this.state.isWebviewShowing && (
|
||||
<Flex
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '36.2vw',
|
||||
height: '100vh',
|
||||
zIndex: 1,
|
||||
boxShadow: '0 2px 15px 0 rgba(0, 0, 0, 0.2)',
|
||||
}}
|
||||
>
|
||||
<ReducedFlashingInfos
|
||||
imageLogo={this.state.imageLogo}
|
||||
imageName={this.state.imageName}
|
||||
imageSize={
|
||||
typeof this.state.imageSize === 'number'
|
||||
? prettyBytes(this.state.imageSize)
|
||||
: ''
|
||||
}
|
||||
driveTitle={this.state.driveTitle}
|
||||
driveLabel={this.state.driveLabel}
|
||||
{this.state.isFlashing && this.state.isWebviewShowing && (
|
||||
<Flex
|
||||
style={{
|
||||
position: 'absolute',
|
||||
color: '#fff',
|
||||
left: 35,
|
||||
top: 72,
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '36.2vw',
|
||||
height: '100vh',
|
||||
zIndex: 1,
|
||||
boxShadow: '0 2px 15px 0 rgba(0, 0, 0, 0.2)',
|
||||
}}
|
||||
>
|
||||
<ReducedFlashingInfos
|
||||
imageLogo={this.state.imageLogo}
|
||||
imageName={this.state.imageName}
|
||||
imageSize={
|
||||
typeof this.state.imageSize === 'number'
|
||||
? prettyBytes(this.state.imageSize)
|
||||
: ''
|
||||
}
|
||||
driveTitle={this.state.driveTitle}
|
||||
driveLabel={this.state.driveLabel}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
color: '#fff',
|
||||
left: 35,
|
||||
top: 72,
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
{this.state.isFlashing && this.state.featuredProjectURL && (
|
||||
<SafeWebview
|
||||
src={this.state.featuredProjectURL}
|
||||
onWebviewShow={(isWebviewShowing: boolean) => {
|
||||
this.setState({ isWebviewShowing });
|
||||
}}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
width: '63.8vw',
|
||||
height: '100vh',
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
{this.state.isFlashing && this.state.featuredProjectURL && (
|
||||
<SafeWebview
|
||||
src={this.state.featuredProjectURL}
|
||||
onWebviewShow={(isWebviewShowing: boolean) => {
|
||||
this.setState({ isWebviewShowing });
|
||||
}}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
width: '63.8vw',
|
||||
height: '100vh',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
)}
|
||||
|
||||
<FlashStep
|
||||
width={this.state.isWebviewShowing ? '220px' : '200px'}
|
||||
goToSuccess={() => this.setState({ current: 'success' })}
|
||||
shouldFlashStepBeDisabled={shouldFlashStepBeDisabled}
|
||||
isFlashing={this.state.isFlashing}
|
||||
step={state.type}
|
||||
percentage={state.percentage}
|
||||
position={state.position}
|
||||
failed={state.failed}
|
||||
speed={state.speed}
|
||||
eta={state.eta}
|
||||
style={{ zIndex: 1 }}
|
||||
/>
|
||||
<FlashStep
|
||||
width={this.state.isWebviewShowing ? '220px' : '200px'}
|
||||
goToSuccess={() => this.setState({ current: 'success' })}
|
||||
shouldFlashStepBeDisabled={shouldFlashStepBeDisabled}
|
||||
isFlashing={this.state.isFlashing}
|
||||
step={state.type}
|
||||
percentage={state.percentage}
|
||||
position={state.position}
|
||||
failed={state.failed}
|
||||
speed={state.speed}
|
||||
eta={state.eta}
|
||||
style={{ zIndex: 1 }}
|
||||
/>
|
||||
</Flex>
|
||||
{this.state.analyticsAlertIsVisible && (
|
||||
<Alert mt="18px" style={{ boxShadow: 'none', fontSize: '12px' }}>
|
||||
<Flex alignItems="center" justifyContent="space-between">
|
||||
<Flex flexDirection="column">
|
||||
<div>
|
||||
Etcher collects a limited amount of anonymous data to help us
|
||||
improve user experience. You can opt out in the{' '}
|
||||
<Link onClick={() => this.setState({ hideSettings: false })}>
|
||||
settings
|
||||
</Link>
|
||||
.
|
||||
</div>
|
||||
<div>
|
||||
For more information about how we use this data, see our{' '}
|
||||
<Link
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
openExternal('https://www.balena.io/privacy-policy');
|
||||
}}
|
||||
>
|
||||
privacy policy
|
||||
</Link>
|
||||
.
|
||||
</div>
|
||||
</Flex>
|
||||
{/* TODO: can we use onDismiss instead? */}
|
||||
<IconButton onClick={this.hideAnalyticsAlert}>
|
||||
<CloseSvg height="0.75rem" fill={theme.colors.text.main} />
|
||||
</IconButton>
|
||||
</Flex>
|
||||
</Alert>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
4
npm-shrinkwrap.json
generated
4
npm-shrinkwrap.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "balena-etcher",
|
||||
"version": "1.19.25",
|
||||
"version": "2.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "balena-etcher",
|
||||
"version": "1.19.25",
|
||||
"version": "2.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@electron/remote": "^2.1.2",
|
||||
|
@ -3,7 +3,7 @@
|
||||
"private": true,
|
||||
"displayName": "balenaEtcher",
|
||||
"productName": "balenaEtcher",
|
||||
"version": "1.19.25",
|
||||
"version": "2.1.0",
|
||||
"packageType": "local",
|
||||
"main": ".webpack/main",
|
||||
"description": "Flash OS images to SD cards and USB drives, safely and easily.",
|
||||
@ -144,7 +144,7 @@
|
||||
"node": ">=20 <21"
|
||||
},
|
||||
"versionist": {
|
||||
"publishedAt": "2024-10-10T10:03:29.992Z"
|
||||
"publishedAt": "2025-02-27T16:16:57.534Z"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bufferutil": "^4.0.8",
|
||||
|
Loading…
x
Reference in New Issue
Block a user