Skip to content

Commit

Permalink
Add note about handling invalid URLs (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
theogravity authored Oct 21, 2024
1 parent d070956 commit 33229aa
Show file tree
Hide file tree
Showing 36 changed files with 7,876 additions and 3 deletions.
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ test
config
__mocks__
.github
test-app
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 3.2.1 (2024-10-21)

- Add an FAQ section to `README.md` on how to handle invalid URLs

# 3.2.0 (2024-08-04)

- Fix issues around starting multiple downloads at the same time.
Expand Down
45 changes: 44 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ manager.resumeDownload(id);
- [`isDownloadInterrupted()`](#isdownloadinterrupted)
- [`isDownloadCompleted()`](#isdownloadcompleted)
- [Mock class](#mock-class)
- [FAQ](#faq)
- [Acknowledgments](#acknowledgments)

# Installation
Expand Down Expand Up @@ -352,7 +353,9 @@ class DownloadData {
*/
resolvedFilename: string
/**
* If true, the download was cancelled from the save as dialog
* If true, the download was cancelled from the save as dialog. This flag
* will also be true if the download was cancelled by the application when
* using the save as dialog.
*/
cancelledFromSaveAsDialog?: boolean
/**
Expand Down Expand Up @@ -455,6 +458,46 @@ If you need to mock out `ElectronDownloadManager` in your tests, you can use the

`import { ElectronDownloadManagerMock } from 'electron-dl-manager'`

# FAQ

## How do I capture if the download is invalid? `onError()` is not being called.

Electron doesn't provide an explicit way to capture errors for downloads in general.
What it does for invalid URLs, it will trigger the `onDownloadCancelled()` callback.

```typescript
const id = await manager.download({
window: mainWindow,
url: 'https://alkjsdflksjdflk.com/file.zip',
callbacks: {
onDownloadCancelled: async (...) => {
// Invalid download; this callback will be called
},
}
});
```

A better way to handle this is to check if the URL exists prior to the download yourself.
I couldn't find a library that I felt was reliable to include into this package,
so it's best you find a library that works for you:

- https://www.npmjs.com/search?q=url%20exists&ranking=maintenance

GPT also suggests the following code (untested):

```typescript
async function urlExists(url: string): Promise<boolean> {
try {
const response = await fetch(url, { method: 'HEAD' });
return response.ok;
} catch (error) {
return false;
}
}

const exists = await urlExists('https://example.com/file.jpg');
```

# Acknowledgments

This code uses small portions from [`electron-dl`](https://github.com/sindresorhus/electron-dl) and is noted in the
Expand Down
4 changes: 3 additions & 1 deletion src/DownloadData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ export class DownloadData {
*/
resolvedFilename: string;
/**
* If true, the download was cancelled from the save as dialog
* If true, the download was cancelled from the save as dialog. This flag
* will also be true if the download was cancelled by the application when
* using the save as dialog.
*/
cancelledFromSaveAsDialog?: boolean;
/**
Expand Down
2 changes: 1 addition & 1 deletion src/DownloadInitiator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export class DownloadInitiator {
}
} else if (this.downloadData.isDownloadCancelled()) {
clearInterval(interval);
this.log("Download was cancelled by user");
this.log("Download was cancelled");
this.downloadData.cancelledFromSaveAsDialog = true;
await this.callbackDispatcher.onDownloadCancelled(this.downloadData);
} else {
Expand Down
9 changes: 9 additions & 0 deletions test-app/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
4 changes: 4 additions & 0 deletions test-app/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
out
.gitignore
7 changes: 7 additions & 0 deletions test-app/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
extends: [
'eslint:recommended',
'@electron-toolkit/eslint-config-ts/recommended',
'@electron-toolkit/eslint-config-prettier'
]
}
5 changes: 5 additions & 0 deletions test-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
dist
out
.DS_Store
*.log*
6 changes: 6 additions & 0 deletions test-app/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
out
dist
pnpm-lock.yaml
LICENSE.md
tsconfig.json
tsconfig.*.json
4 changes: 4 additions & 0 deletions test-app/.prettierrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
singleQuote: true
semi: false
printWidth: 100
trailingComma: none
3 changes: 3 additions & 0 deletions test-app/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["dbaeumer.vscode-eslint"]
}
39 changes: 39 additions & 0 deletions test-app/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
},
"runtimeArgs": ["--sourcemap"],
"env": {
"REMOTE_DEBUGGING_PORT": "9222"
}
},
{
"name": "Debug Renderer Process",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}/src/renderer",
"timeout": 60000,
"presentation": {
"hidden": true
}
}
],
"compounds": [
{
"name": "Debug All",
"configurations": ["Debug Main Process", "Debug Renderer Process"],
"presentation": {
"order": 1
}
}
]
}
11 changes: 11 additions & 0 deletions test-app/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
34 changes: 34 additions & 0 deletions test-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# test-app

A minimal Electron application with TypeScript

## Recommended IDE Setup

- [VSCode](https://code.visualstudio.com/) + [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) + [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)

## Project Setup

### Install

```bash
$ npm install
```

### Development

```bash
$ npm run dev
```

### Build

```bash
# For windows
$ npm run build:win

# For macOS
$ npm run build:mac

# For Linux
$ npm run build:linux
```
12 changes: 12 additions & 0 deletions test-app/build/entitlements.mac.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>
Binary file added test-app/build/icon.icns
Binary file not shown.
Binary file added test-app/build/icon.ico
Binary file not shown.
Binary file added test-app/build/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions test-app/electron-builder.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
appId: com.electron.app
productName: test-app
directories:
buildResources: build
files:
- '!**/.vscode/*'
- '!src/*'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.js,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
- '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
asarUnpack:
- resources/**
win:
executableName: test-app
nsis:
artifactName: ${name}-${version}-setup.${ext}
shortcutName: ${productName}
uninstallDisplayName: ${productName}
createDesktopShortcut: always
mac:
entitlementsInherit: build/entitlements.mac.plist
extendInfo:
- NSCameraUsageDescription: Application requests access to the device's camera.
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
notarize: false
dmg:
artifactName: ${name}-${version}.${ext}
linux:
target:
- AppImage
- snap
- deb
maintainer: electronjs.org
category: Utility
appImage:
artifactName: ${name}-${version}.${ext}
npmRebuild: false
publish:
provider: generic
url: https://example.com/auto-updates
11 changes: 11 additions & 0 deletions test-app/electron.vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'

export default defineConfig({
main: {
plugins: [externalizeDepsPlugin()]
},
preload: {
plugins: [externalizeDepsPlugin()]
},
renderer: {}
})
Loading

0 comments on commit 33229aa

Please sign in to comment.