@sequencemedia/minimserver 0.1.26 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ . "$(dirname "$0")/_/husky.sh"
3
+
4
+ npm run pre-commit
@@ -1,23 +1,29 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- require('dotenv/config')
3
+ import 'dotenv/config'
4
4
 
5
- const debug = require('debug')
5
+ import debug from 'debug'
6
6
 
7
- const psList = require('ps-list')
7
+ import {
8
+ readFile
9
+ } from 'fs/promises'
8
10
 
9
- const {
10
- execute
11
- } = require('./lib')
11
+ import psList from 'ps-list'
12
12
 
13
- const commander = require('commander')
13
+ import commander from 'commander'
14
14
 
15
- const PACKAGE = require('./package')
15
+ import minimServer from '#minimserver'
16
+
17
+ const log = debug('@sequencemedia/minimserver')
18
+
19
+ log('`minimserver` is awake')
16
20
 
17
21
  const NAME = 'ms.App'
18
22
  process.title = NAME
19
23
 
20
24
  async function app () {
25
+ const PACKAGE = JSON.parse(await readFile('./package.json', 'utf8'))
26
+
21
27
  const {
22
28
  name
23
29
  } = PACKAGE
@@ -38,21 +44,19 @@ async function app () {
38
44
  pid
39
45
  } = a.find(({ pid }) => pid !== PID)
40
46
 
41
- const log = debug('minimserver:process:log')
47
+ const log = debug('@sequencemedia/minimserver:process')
42
48
 
43
49
  log(`Killing application "${name}" in process ${pid}.`)
44
50
 
45
51
  process.kill(pid)
46
52
  }
47
53
  } catch ({ message }) {
48
- const error = debug('minimserver:process:error')
54
+ const error = debug('@sequencemedia/minimserver:process:error')
49
55
 
50
56
  error(message)
51
57
  return
52
58
  }
53
59
 
54
- const log = debug('minimserver:log')
55
-
56
60
  const {
57
61
  pid,
58
62
  argv,
@@ -86,7 +90,7 @@ async function app () {
86
90
  code
87
91
  } = e
88
92
 
89
- const error = debug('minimserver:commander:error')
93
+ const error = debug('@sequencemedia/minimserver:commander:error')
90
94
 
91
95
  if (code !== 'commander.missingMandatoryOptionValue') error(e)
92
96
 
@@ -111,12 +115,12 @@ async function app () {
111
115
  })
112
116
 
113
117
  try {
114
- await execute(origin, destination, server, ignore, bounce)
118
+ await minimServer(origin, destination, server, ignore, bounce)
115
119
  } catch ({ message }) {
116
- const error = debug('minimserver:execute:error')
120
+ const error = debug('@sequencemedia/minimserver:error')
117
121
 
118
122
  error(message)
119
123
  }
120
124
  }
121
125
 
122
- module.exports = app()
126
+ export default app()
@@ -0,0 +1,21 @@
1
+ const presets = [
2
+ [
3
+ '@babel/env',
4
+ {
5
+ targets: {
6
+ node: 'current'
7
+ },
8
+ useBuiltIns: 'usage',
9
+ corejs: 3
10
+ }
11
+ ]
12
+ ]
13
+
14
+ const plugins = []
15
+
16
+ module.exports = {
17
+ compact: true,
18
+ comments: false,
19
+ presets,
20
+ plugins
21
+ }
@@ -0,0 +1,86 @@
1
+ import debug from 'debug'
2
+
3
+ import {
4
+ exec
5
+ } from 'child_process'
6
+
7
+ const log = debug('@sequencemedia/minimserver:build:gulp:pre-commit')
8
+
9
+ log('`@sequencemedia/minimserver` is awake')
10
+
11
+ const PACKAGE_VERSION_CHANGES = /\-+\s+"version":\s+"(\d+\.\d+\.\d+)",+\s+\++\s+"version":\s+"(\d+\.\d+\.\d+)",+\s+/ /* eslint-disable-line no-useless-escape */
12
+
13
+ const HAS_STAGED_CHANGES = /Changes to be committed/s
14
+
15
+ const NOT_STAGED_CHANGES = /Changes not staged for commit/s
16
+
17
+ const OPTIONS = {
18
+ maxBuffer: 1024 * 500
19
+ }
20
+
21
+ export const hasPackageVersionChanges = () => (
22
+ new Promise((resolve, reject) => {
23
+ exec('git diff HEAD origin/master package.json', OPTIONS, (e, v) => (!e) ? resolve(PACKAGE_VERSION_CHANGES.test(v)) : reject(e))
24
+ })
25
+ )
26
+
27
+ export const notPackageVersionChanges = () => (
28
+ new Promise((resolve, reject) => {
29
+ exec('git diff HEAD origin/master package.json', OPTIONS, (e, v) => (!e) ? resolve(PACKAGE_VERSION_CHANGES.test(v) !== true) : reject(e))
30
+ })
31
+ )
32
+
33
+ export const hasStagedChanges = () => (
34
+ new Promise((resolve, reject) => {
35
+ exec('git status', OPTIONS, (e, v) => (!e) ? resolve(HAS_STAGED_CHANGES.test(v)) : reject(e))
36
+ })
37
+ )
38
+
39
+ export const notStagedChanges = () => (
40
+ new Promise((resolve, reject) => {
41
+ exec('git status', OPTIONS, (e, v) => (!e) ? resolve(NOT_STAGED_CHANGES.test(v)) : reject(e))
42
+ })
43
+ )
44
+
45
+ export const notPushedChanges = () => (
46
+ new Promise((resolve, reject) => {
47
+ exec('git log origin/master..HEAD', OPTIONS, (e, v) => (!e) ? resolve(!!v) : reject(e))
48
+ })
49
+ )
50
+
51
+ export const patchPackageVersion = () => (
52
+ new Promise((resolve, reject) => {
53
+ exec('npm version patch -m %s -n --no-git-tag-version --no-verify', OPTIONS, (e) => (!e) ? resolve() : reject(e))
54
+ })
55
+ )
56
+
57
+ export const addPackageVersionChanges = () => (
58
+ new Promise((resolve, reject) => {
59
+ exec('git add package.json package-lock.json', OPTIONS, (e) => (!e) ? resolve() : reject(e))
60
+ })
61
+ )
62
+
63
+ export default async function preCommit () {
64
+ log('pre-commit')
65
+
66
+ try {
67
+ /**
68
+ * Not changes added, exit
69
+ */
70
+ if (await notStagedChanges()) return
71
+ /**
72
+ * Has changes added, continue
73
+ */
74
+ if (await hasStagedChanges()) {
75
+ /**
76
+ * Not package version changes, continue
77
+ */
78
+ if (await notPackageVersionChanges()) {
79
+ await patchPackageVersion()
80
+ await addPackageVersionChanges()
81
+ }
82
+ }
83
+ } catch ({ code = 'NONE', message = 'No error message defined' }) {
84
+ log({ code, message })
85
+ }
86
+ }
package/gulpfile.mjs ADDED
@@ -0,0 +1,9 @@
1
+ import gulp from 'gulp'
2
+
3
+ import preCommit from '#build/gulp/pre-commit'
4
+
5
+ gulp
6
+ .task('pre-commit', preCommit)
7
+
8
+ gulp
9
+ .task('default', gulp.series('pre-commit'))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sequencemedia/minimserver",
3
- "version": "0.1.26",
3
+ "version": "1.2.1",
4
4
  "description": "Watch for changes to M3Us and rescan MinimServer",
5
5
  "keywords": [
6
6
  "minimserver",
@@ -14,11 +14,11 @@
14
14
  "m3u",
15
15
  "m3u8"
16
16
  ],
17
- "main": "./app.js",
17
+ "main": "./app.mjs",
18
18
  "author": "Jonathan Perry for Sequence Media Limited <sequencemedia@sequencemedia.net>",
19
19
  "license": "MIT",
20
20
  "engines": {
21
- "node": ">=12.19.0"
21
+ "node": ">=16.13.0"
22
22
  },
23
23
  "repository": {
24
24
  "type": "git",
@@ -29,49 +29,42 @@
29
29
  "url": "https://github.com/sequencemedia/minimserver/issues"
30
30
  },
31
31
  "scripts": {
32
- "build": "npm run babel",
33
- "build:watch": "npm run babel:watch",
34
- "clean": "rimraf lib",
35
- "babel": "babel src -d lib",
36
- "babel:watch": "npm run babel -- -w",
37
- "lint": "eslint .",
32
+ "lint": "eslint . --ext .mjs --ext .cjs",
38
33
  "lint:fix": "npm run lint -- --fix",
39
- "start": "cross-env DEBUG=minimserver*,itunes* NODE_ENV=production node app",
40
- "start:dev": "cross-env DEBUG=minimserver*,itunes* NODE_ENV=development node app",
41
- "prepublishOnly": "npm run build",
42
- "prebuild": "npm run clean"
34
+ "start": "cross-env DEBUG=@sequencemedia/minimserver* NODE_ENV=production node .",
35
+ "dev": "cross-env DEBUG=@sequencemedia/minimserver* NODE_ENV=development node .",
36
+ "gulp": "gulp --color",
37
+ "pre-commit": "npm run lint && npm run gulp -- pre-commit",
38
+ "prepare": "husky install"
43
39
  },
44
40
  "dependencies": {
45
- "@babel/runtime": "^7.15.4",
46
41
  "anymatch": "^3.1.2",
47
42
  "chokidar": "^3.5.2",
48
- "commander": "^8.2.0",
43
+ "commander": "^8.3.0",
49
44
  "cross-env": "^7.0.3",
50
- "debug": "^4.3.2",
45
+ "debug": "^4.3.3",
51
46
  "del": "^6.0.0",
52
47
  "dotenv": "^10.0.0",
53
48
  "fs-extra": "^10.0.0",
54
- "ps-list": "^7.2.0",
55
- "supports-color": "^9.0.2"
49
+ "ps-list": "^8.0.0",
50
+ "supports-color": "^9.2.1"
56
51
  },
57
52
  "devDependencies": {
58
- "@babel/cli": "^7.15.7",
59
- "@babel/core": "^7.15.5",
60
- "@babel/eslint-parser": "^7.15.7",
61
- "@babel/plugin-proposal-export-default-from": "^7.14.5",
62
- "@babel/plugin-proposal-export-namespace-from": "^7.14.5",
63
- "@babel/plugin-transform-runtime": "^7.15.0",
64
- "@babel/preset-env": "^7.15.6",
65
- "@babel/register": "^7.15.3",
66
- "babel-plugin-module-resolver": "^4.1.0",
67
- "babel-plugin-syntax-async-functions": "^6.13.0",
68
- "core-js": "^3.18.0",
69
- "eslint": "^7.32.0",
53
+ "@babel/cli": "^7.16.0",
54
+ "@babel/core": "^7.16.5",
55
+ "@babel/eslint-parser": "^7.16.5",
56
+ "@babel/preset-env": "^7.16.5",
57
+ "core-js": "^3.20.1",
58
+ "eslint": "7.32.0",
70
59
  "eslint-config-standard": "^16.0.3",
71
- "eslint-import-resolver-babel-module": "^5.3.1",
72
- "eslint-plugin-import": "^2.24.2",
60
+ "eslint-plugin-import": "^2.25.3",
73
61
  "eslint-plugin-node": "^11.1.0",
74
- "eslint-plugin-promise": "^5.1.0",
75
- "rimraf": "^3.0.2"
62
+ "eslint-plugin-promise": "5.2.0",
63
+ "gulp": "^4.0.2",
64
+ "husky": "^7.0.4"
65
+ },
66
+ "imports": {
67
+ "#minimserver": "./src/index.mjs",
68
+ "#build/gulp/*": "./build/gulp/*.mjs"
76
69
  }
77
70
  }
@@ -1,13 +1,12 @@
1
+ import debug from 'debug'
2
+
1
3
  import os from 'os'
2
4
  import path from 'path'
3
5
  import {
4
6
  exec
5
7
  } from 'child_process'
6
8
 
7
- import {
8
- ensureDir,
9
- ensureFile
10
- } from 'fs-extra'
9
+ import fsExtra from 'fs-extra'
11
10
 
12
11
  import {
13
12
  stat,
@@ -18,10 +17,15 @@ import chokidar from 'chokidar'
18
17
  import anymatch from 'anymatch'
19
18
  import del from 'del'
20
19
 
21
- import debug from 'debug'
20
+ const {
21
+ ensureDir,
22
+ ensureFile
23
+ } = fsExtra
22
24
 
23
- const error = debug('minimserver:error')
24
- const log = debug('minimserver:log')
25
+ const error = debug('@sequencemedia/minimserver:error')
26
+ const log = debug('@sequencemedia/minimserver')
27
+
28
+ log('`minimserver` is awake')
25
29
 
26
30
  async function originDirExists (path) {
27
31
  try {
@@ -43,19 +47,36 @@ async function originDirExists (path) {
43
47
  }
44
48
  }
45
49
 
46
- const removeAllM3UFromDestinationDir = async (path) => del(path, { force: true })
50
+ export async function removeAllM3UFromDestinationDir (path) {
51
+ /**
52
+ * log('removeAllM3UFromDestinationDir')
53
+ */
54
+ return (
55
+ await del(path, { force: true })
56
+ )
57
+ }
47
58
 
48
- const ensureDestinationDir = (path) => (
49
- new Promise((resolve, reject) => {
50
- ensureDir(path, (e) => (!e) ? resolve() : reject(e))
51
- })
52
- )
59
+ export function ensureDestinationDir (path) {
60
+ /*
61
+ * log('ensureDestinationDir')
62
+ */
63
+ return (
64
+ new Promise((resolve, reject) => {
65
+ ensureDir(path, (e) => (!e) ? resolve() : reject(e))
66
+ })
67
+ )
68
+ }
53
69
 
54
- const ensureDestinationM3U = (filePath) => (
55
- new Promise((resolve, reject) => {
56
- ensureFile(filePath, (e) => (!e) ? resolve() : reject(e))
57
- })
58
- )
70
+ export function ensureDestinationM3U (filePath) {
71
+ /*
72
+ * log('ensureDestinationM3U')
73
+ */
74
+ return (
75
+ new Promise((resolve, reject) => {
76
+ ensureFile(filePath, (e) => (!e) ? resolve() : reject(e))
77
+ })
78
+ )
79
+ }
59
80
 
60
81
  export function rescan (server) {
61
82
  /*
@@ -175,7 +196,9 @@ export function removeFactory (origin, destination) {
175
196
  log('remove', to)
176
197
 
177
198
  try {
178
- return del(to, { force: true })
199
+ return (
200
+ await del(to, { force: true })
201
+ )
179
202
  } catch ({ message }) {
180
203
  error(message)
181
204
  }
@@ -328,7 +351,7 @@ export function ignorePatternFactory (ignore) {
328
351
  }
329
352
  }
330
353
 
331
- export async function execute (
354
+ export default async function minimServer (
332
355
  origin = '.',
333
356
  destination = '.',
334
357
  server = 'http://0.0.0.0:9790',
@@ -336,7 +359,7 @@ export async function execute (
336
359
  bounce = 60000
337
360
  ) {
338
361
  /*
339
- * log('execute')
362
+ * log('minimServer')
340
363
  */
341
364
  let watcher
342
365
 
@@ -387,7 +410,7 @@ export async function execute (
387
410
  error(message)
388
411
  }
389
412
  })
390
- .on('error', ({ message }) => {
413
+ .on('error', function handleError ({ message }) {
391
414
  error(`Error in watcher: "${message}"`)
392
415
  })
393
416
 
@@ -1,58 +0,0 @@
1
- version: 2.1
2
-
3
- jobs:
4
- publish:
5
- docker:
6
- - image: circleci/node:lts
7
- steps:
8
- - checkout
9
- - run:
10
- name: Publish to NPM
11
- command: |
12
- echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
13
-
14
- PATTERN="([0-9]+)\.([0-9]+)\.([0-9]+)"
15
- NAME=$(node -p "require('./package').name")
16
- VERSION=$(node -p "require('./package').version")
17
- PUBLISHED_VERSION=$(npm view $NAME version)
18
-
19
- echo Version is $VERSION
20
- echo Published version is $PUBLISHED_VERSION
21
-
22
- [[ $VERSION =~ $PATTERN ]]
23
-
24
- VERSION_MAJOR="${BASH_REMATCH[1]}"
25
- VERSION_MINOR="${BASH_REMATCH[2]}"
26
- VERSION_PATCH="${BASH_REMATCH[3]}"
27
-
28
- [[ $PUBLISHED_VERSION =~ $PATTERN ]]
29
-
30
- PUBLISHED_VERSION_MAJOR="${BASH_REMATCH[1]}"
31
- PUBLISHED_VERSION_MINOR="${BASH_REMATCH[2]}"
32
- PUBLISHED_VERSION_PATCH="${BASH_REMATCH[3]}"
33
-
34
- if [ $VERSION_MAJOR -gt $PUBLISHED_VERSION_MAJOR ] || [ $VERSION_MINOR -gt $PUBLISHED_VERSION_MINOR ] || [ $VERSION_PATCH -gt $PUBLISHED_VERSION_PATCH ]
35
- then
36
- set +e
37
-
38
- npm ci
39
- npm publish
40
-
41
- if [[ $? != 0 ]];
42
- then
43
- echo Version $VERSION was not published
44
- else
45
- echo Published version $VERSION
46
- fi
47
- fi
48
-
49
- workflows:
50
- version: 2
51
- commit-workflow:
52
- jobs:
53
- - publish:
54
- filters:
55
- branches:
56
- only: master
57
- tags:
58
- only: /^v.*/
@@ -1,9 +0,0 @@
1
- version: 2
2
-
3
- updates:
4
- - package-ecosystem: "npm"
5
- directory: "/"
6
- schedule:
7
- interval: "daily"
8
- reviewers:
9
- - sequencemedialimited
package/babel.config.js DELETED
@@ -1,35 +0,0 @@
1
- const presets = [
2
- [
3
- '@babel/env',
4
- {
5
- useBuiltIns: 'usage',
6
- targets: {
7
- node: '12.9.0'
8
- },
9
- corejs: 3
10
- }
11
- ]
12
- ]
13
-
14
- const plugins = [
15
- '@babel/transform-runtime',
16
- '@babel/proposal-export-default-from',
17
- '@babel/proposal-export-namespace-from',
18
- 'syntax-async-functions',
19
- [
20
- 'module-resolver', {
21
- root: ['./src'],
22
- cwd: 'babelrc',
23
- alias: {
24
- '~': './src'
25
- }
26
- }
27
- ]
28
- ]
29
-
30
- module.exports = {
31
- compact: true,
32
- comments: false,
33
- presets,
34
- plugins
35
- }
package/lib/index.js DELETED
@@ -1 +0,0 @@
1
- "use strict";var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.rescan=rescan;exports.restart=restart;exports.relaunch=relaunch;exports.exit=exit;exports.createFactory=createFactory;exports.changeFactory=changeFactory;exports.removeFactory=removeFactory;exports.queueRescanFactory=queueRescanFactory;exports.queueRestartFactory=queueRestartFactory;exports.queueRelaunchFactory=queueRelaunchFactory;exports.ignorePatternFactory=ignorePatternFactory;exports.execute=execute;var _os=_interopRequireDefault(require("os"));var _path=_interopRequireDefault(require("path"));var _child_process=require("child_process");var _fsExtra=require("fs-extra");var _promises=require("fs/promises");var _chokidar=_interopRequireDefault(require("chokidar"));var _anymatch=_interopRequireDefault(require("anymatch"));var _del=_interopRequireDefault(require("del"));var _debug=_interopRequireDefault(require("debug"));const error=(0,_debug.default)('minimserver:error');const log=(0,_debug.default)('minimserver:log');async function originDirExists(path){try{await(0,_promises.stat)(path);return true;}catch(e){const{code}=e;if(code!=='ENOENT'){const{message}=e;error(message);}return false;}}const removeAllM3UFromDestinationDir=async path=>(0,_del.default)(path,{force:true});const ensureDestinationDir=path=>new Promise((resolve,reject)=>{(0,_fsExtra.ensureDir)(path,e=>!e?resolve():reject(e));});const ensureDestinationM3U=filePath=>new Promise((resolve,reject)=>{(0,_fsExtra.ensureFile)(filePath,e=>!e?resolve():reject(e));});function rescan(server){return new Promise((resolve,reject)=>{(0,_child_process.exec)(`curl -X POST -H "Content-Type: text/plain" ${server} -d rescan`,(e,r)=>!e?resolve(r):reject(e));});}function restart(server){return new Promise((resolve,reject)=>{(0,_child_process.exec)(`curl -X POST -H "Content-Type: text/plain" ${server} -d restart`,(e,r)=>!e?resolve(r):reject(e));});}function relaunch(server){return new Promise((resolve,reject)=>{(0,_child_process.exec)(`curl -X POST -H "Content-Type: text/plain" ${server} -d relaunch`,(e,r)=>!e?resolve(r):reject(e));});}function exit(server){return new Promise((resolve,reject)=>{(0,_child_process.exec)(`curl -X POST -H "Content-Type: text/plain" ${server} -d exit`,(e,r)=>!e?resolve(r):reject(e));});}function createFactory(origin,destination){return async function create(filePath){const to=filePath.replace(origin,destination);log('create',to);try{await ensureDestinationM3U(to);return await(0,_promises.copyFile)(filePath,to);}catch(e){const{code}=e;if(code==='ENOENT'){error(`ENOENT in create for "${filePath}"`);}else{const{message}=e;error(message);}}};}function changeFactory(origin,destination){return async function change(filePath){const to=filePath.replace(origin,destination);log('change',to);try{await ensureDestinationM3U(to);return await(0,_promises.copyFile)(filePath,to);}catch(e){const{code}=e;if(code==='ENOENT'){error(`ENOENT in change for "${filePath}"`);}else{const{message}=e;error(message);}}};}function removeFactory(origin,destination){return async function remove(filePath){const to=filePath.replace(origin,destination);log('remove',to);try{return(0,_del.default)(to,{force:true});}catch({message}){error(message);}};}function queueRescanFactory(server,bounce){let t=null;let x=null;let y=null;return function enqueue(){if(t){clearTimeout(t);if(x){y=true;return;}}t=setTimeout(async function dequeue(){x=true;try{const response=await rescan(server);log(response.trim());t=null;x=null;if(y){y=null;enqueue();}}catch({message}){error(message);}},bounce);};}function queueRestartFactory(server,bounce){let t=null;let x=null;let y=null;return function enqueue(){if(t){clearTimeout(t);if(x){y=true;return;}}t=setTimeout(async function dequeue(){x=true;try{const response=await restart(server);log(response.trim());t=null;x=null;if(y){y=null;enqueue();}}catch({message}){error(message);}},bounce);};}function queueRelaunchFactory(server,bounce){let t=null;let x=null;let y=null;return function enqueue(){if(t){clearTimeout(t);if(x){y=true;return;}}t=setTimeout(async function dequeue(){x=true;try{const response=await relaunch(server);log(response.trim());t=null;x=null;if(y){y=null;enqueue();}}catch({message}){error(message);}},bounce);};}function ignorePatternFactory(ignore){const ignorePatterns=ignore.split(',');return function ignorePattern(filePath){return /(^|[/\\])\../.test(filePath)||(0,_anymatch.default)(ignorePatterns,filePath);};}async function execute(origin='.',destination='.',server='http://0.0.0.0:9790',ignore='',bounce=60000){let watcher;try{const o=_path.default.resolve(origin.replace('~',_os.default.homedir));if(!(await originDirExists(o)))throw new Error(`Origin "${origin}" does not exist.`);const d=_path.default.resolve(destination.replace('~',_os.default.homedir));const ignorePattern=ignorePatternFactory(ignore);watcher=_chokidar.default.watch(o,{ignored:ignorePattern});const create=createFactory(o,d);const change=changeFactory(o,d);const remove=removeFactory(o,d);await ensureDestinationDir(d);await removeAllM3UFromDestinationDir(d);const queueRescan=queueRescanFactory(server,bounce);watcher.on('add',async function handleAdd(filePath){try{await create(filePath);queueRescan();}catch({message}){error(message);}}).on('change',async function handleChange(filePath){try{await change(filePath);queueRescan();}catch({message}){error(message);}}).on('unlink',async function handleUnlink(filePath){try{await remove(filePath);queueRescan();}catch({message}){error(message);}}).on('error',({message})=>{error(`Error in watcher: "${message}"`);});queueRescan();}catch({message}){if(watcher)watcher.close();error(message);}}