diff --git a/apps/browser/transcode.html b/apps/browser/transcode.html
index a1dec53..81a24a1 100644
--- a/apps/browser/transcode.html
+++ b/apps/browser/transcode.html
@@ -21,8 +21,8 @@
ffmpeg.on(FFmpeg.DOWNLOAD, ({ url, total, received, done }) => {
console.log(`downloading ${url}, progress: ${received / total * 100} %, done: ${done}`);
});
- ffmpeg.on(FFmpeg.PROGRESS, (p) => {
- message.innerHTML = `${p * 100} %`;
+ ffmpeg.on(FFmpeg.PROGRESS, ({ progress }) => {
+ message.innerHTML = `${progress * 100} %`;
});
ffmpeg.on(FFmpeg.LOG, ({ message }) => {
console.log(message);
diff --git a/package-lock.json b/package-lock.json
index 9ebb080..60c4732 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,10 +12,12 @@
],
"devDependencies": {
"chai": "^4.3.6",
+ "http-server": "^14.1.1",
"lerna": "^5.4.3",
"mocha": "^10.0.0",
"mocha-headless-chrome": "^4.0.0",
- "npm-run-all": "^4.1.5"
+ "npm-run-all": "^4.1.5",
+ "start-server-and-test": "^1.14.0"
}
},
"apps/browser": {
@@ -157,6 +159,21 @@
"integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==",
"dev": true
},
+ "node_modules/@hapi/hoek": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
+ "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==",
+ "dev": true
+ },
+ "node_modules/@hapi/topo": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz",
+ "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==",
+ "dev": true,
+ "dependencies": {
+ "@hapi/hoek": "^9.0.0"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.10.4",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz",
@@ -2225,6 +2242,27 @@
"url": "https://opencollective.com/parcel"
}
},
+ "node_modules/@sideway/address": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
+ "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==",
+ "dev": true,
+ "dependencies": {
+ "@hapi/hoek": "^9.0.0"
+ }
+ },
+ "node_modules/@sideway/formula": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
+ "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==",
+ "dev": true
+ },
+ "node_modules/@sideway/pinpoint": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
+ "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
+ "dev": true
+ },
"node_modules/@tootallnate/once": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@@ -3075,6 +3113,15 @@
"node": "*"
}
},
+ "node_modules/async": {
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
+ "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.14"
+ }
+ },
"node_modules/at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
@@ -3084,6 +3131,15 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/axios": {
+ "version": "0.21.4",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
+ "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
+ "dev": true,
+ "dependencies": {
+ "follow-redirects": "^1.14.0"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -3110,6 +3166,18 @@
}
]
},
+ "node_modules/basic-auth": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+ "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "5.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/before-after-hook": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
@@ -3185,6 +3253,12 @@
"node": ">= 6"
}
},
+ "node_modules/bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -3484,6 +3558,15 @@
"node": "*"
}
},
+ "node_modules/check-more-types": {
+ "version": "2.24.0",
+ "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz",
+ "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@@ -4008,6 +4091,15 @@
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
},
+ "node_modules/corser": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
+ "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
"node_modules/cosmiconfig": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
@@ -4830,6 +4922,33 @@
"node": ">=0.10.0"
}
},
+ "node_modules/event-stream": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
+ "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==",
+ "dev": true,
+ "dependencies": {
+ "duplexer": "~0.1.1",
+ "from": "~0",
+ "map-stream": "~0.1.0",
+ "pause-stream": "0.0.11",
+ "split": "0.3",
+ "stream-combiner": "~0.0.4",
+ "through": "~2.3.1"
+ }
+ },
+ "node_modules/event-stream/node_modules/split": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
+ "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==",
+ "dev": true,
+ "dependencies": {
+ "through": "2"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
@@ -5066,6 +5185,32 @@
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
"dev": true
},
+ "node_modules/follow-redirects": {
+ "version": "1.15.2",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+ "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/from": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
+ "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==",
+ "dev": true
+ },
"node_modules/fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -5601,12 +5746,38 @@
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
+ "node_modules/html-encoding-sniffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
+ "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
+ "dev": true,
+ "dependencies": {
+ "whatwg-encoding": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/http-cache-semantics": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
"dev": true
},
+ "node_modules/http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "dev": true,
+ "dependencies": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/http-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
@@ -5621,6 +5792,103 @@
"node": ">= 6"
}
},
+ "node_modules/http-server": {
+ "version": "14.1.1",
+ "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz",
+ "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==",
+ "dev": true,
+ "dependencies": {
+ "basic-auth": "^2.0.1",
+ "chalk": "^4.1.2",
+ "corser": "^2.0.1",
+ "he": "^1.2.0",
+ "html-encoding-sniffer": "^3.0.0",
+ "http-proxy": "^1.18.1",
+ "mime": "^1.6.0",
+ "minimist": "^1.2.6",
+ "opener": "^1.5.1",
+ "portfinder": "^1.0.28",
+ "secure-compare": "3.0.1",
+ "union": "~0.5.0",
+ "url-join": "^4.0.1"
+ },
+ "bin": {
+ "http-server": "bin/http-server"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/http-server/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/http-server/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/http-server/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/http-server/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/http-server/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/http-server/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
@@ -6342,6 +6610,19 @@
"node": ">=0.10.0"
}
},
+ "node_modules/joi": {
+ "version": "17.6.2",
+ "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.2.tgz",
+ "integrity": "sha512-+gqqdh1xc1wb+Lor0J9toqgeReyDOCqOdG8QSdRcEvwrcRiFQZneUCGKjFjuyBWUb3uaFOgY56yMaZ5FIc+H4w==",
+ "dev": true,
+ "dependencies": {
+ "@hapi/hoek": "^9.0.0",
+ "@hapi/topo": "^5.0.0",
+ "@sideway/address": "^4.1.3",
+ "@sideway/formula": "^3.0.0",
+ "@sideway/pinpoint": "^2.0.0"
+ }
+ },
"node_modules/js-sdsl": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz",
@@ -6481,6 +6762,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/lazy-ass": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
+ "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==",
+ "dev": true,
+ "engines": {
+ "node": "> 0.8"
+ }
+ },
"node_modules/lerna": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/lerna/-/lerna-5.5.1.tgz",
@@ -6920,6 +7210,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/map-stream": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
+ "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==",
+ "dev": true
+ },
"node_modules/marked": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.1.0.tgz",
@@ -7122,6 +7418,18 @@
"node": ">=8.6"
}
},
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true,
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@@ -8510,6 +8818,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/opener": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
+ "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
+ "dev": true,
+ "bin": {
+ "opener": "bin/opener-bin.js"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -8952,6 +9269,15 @@
"node": "*"
}
},
+ "node_modules/pause-stream": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+ "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
+ "dev": true,
+ "dependencies": {
+ "through": "~2.3"
+ }
+ },
"node_modules/pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -9010,6 +9336,41 @@
"node": ">=8"
}
},
+ "node_modules/portfinder": {
+ "version": "1.0.32",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
+ "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==",
+ "dev": true,
+ "dependencies": {
+ "async": "^2.6.4",
+ "debug": "^3.2.7",
+ "mkdirp": "^0.5.6"
+ },
+ "engines": {
+ "node": ">= 0.12.0"
+ }
+ },
+ "node_modules/portfinder/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/portfinder/node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -9107,6 +9468,21 @@
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"dev": true
},
+ "node_modules/ps-tree": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz",
+ "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==",
+ "dev": true,
+ "dependencies": {
+ "event-stream": "=3.3.4"
+ },
+ "bin": {
+ "ps-tree": "bin/ps-tree.js"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@@ -9136,6 +9512,21 @@
"teleport": ">=0.2.0"
}
},
+ "node_modules/qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dev": true,
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -9415,6 +9806,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+ "dev": true
+ },
"node_modules/resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
@@ -9600,6 +9997,12 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/secure-compare": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
+ "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==",
+ "dev": true
+ },
"node_modules/semver": {
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
@@ -9862,6 +10265,55 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
+ "node_modules/start-server-and-test": {
+ "version": "1.14.0",
+ "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.14.0.tgz",
+ "integrity": "sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw==",
+ "dev": true,
+ "dependencies": {
+ "bluebird": "3.7.2",
+ "check-more-types": "2.24.0",
+ "debug": "4.3.2",
+ "execa": "5.1.1",
+ "lazy-ass": "1.6.0",
+ "ps-tree": "1.2.0",
+ "wait-on": "6.0.0"
+ },
+ "bin": {
+ "server-test": "src/bin/start.js",
+ "start-server-and-test": "src/bin/start.js",
+ "start-test": "src/bin/start.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/start-server-and-test/node_modules/debug": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+ "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/stream-combiner": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
+ "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==",
+ "dev": true,
+ "dependencies": {
+ "duplexer": "~0.1.1"
+ }
+ },
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -10631,6 +11083,18 @@
"through": "^2.3.8"
}
},
+ "node_modules/union": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
+ "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==",
+ "dev": true,
+ "dependencies": {
+ "qs": "^6.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
"node_modules/unique-filename": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz",
@@ -10716,6 +11180,12 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/url-join": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
+ "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
+ "dev": true
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -10777,6 +11247,25 @@
"integrity": "sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==",
"dev": true
},
+ "node_modules/wait-on": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.0.tgz",
+ "integrity": "sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw==",
+ "dev": true,
+ "dependencies": {
+ "axios": "^0.21.1",
+ "joi": "^17.4.0",
+ "lodash": "^4.17.21",
+ "minimist": "^1.2.5",
+ "rxjs": "^7.1.0"
+ },
+ "bin": {
+ "wait-on": "bin/wait-on"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/walk-up-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-1.0.0.tgz",
@@ -10963,6 +11452,30 @@
"node": ">=4.0"
}
},
+ "node_modules/whatwg-encoding": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
+ "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
+ "dev": true,
+ "dependencies": {
+ "iconv-lite": "0.6.3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/whatwg-encoding/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
@@ -11436,6 +11949,7 @@
"@typescript-eslint/eslint-plugin": "^5.37.0",
"@typescript-eslint/parser": "^5.37.0",
"eslint": "^8.23.1",
+ "http-server": "^14.1.1",
"npm-run-all": "^4.1.5",
"rimraf": "^3.0.2",
"ts-loader": "^9.4.1",
@@ -11606,6 +12120,7 @@
"@typescript-eslint/parser": "^5.37.0",
"eslint": "^8.23.1",
"events": "^3.3.0",
+ "http-server": "^14.1.1",
"npm-run-all": "^4.1.5",
"rimraf": "^3.0.2",
"ts-loader": "^9.4.1",
@@ -11644,6 +12159,21 @@
"integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==",
"dev": true
},
+ "@hapi/hoek": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
+ "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==",
+ "dev": true
+ },
+ "@hapi/topo": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz",
+ "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==",
+ "dev": true,
+ "requires": {
+ "@hapi/hoek": "^9.0.0"
+ }
+ },
"@humanwhocodes/config-array": {
"version": "0.10.4",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz",
@@ -13280,6 +13810,27 @@
"node-gyp-build": "^4.3.0"
}
},
+ "@sideway/address": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
+ "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==",
+ "dev": true,
+ "requires": {
+ "@hapi/hoek": "^9.0.0"
+ }
+ },
+ "@sideway/formula": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
+ "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==",
+ "dev": true
+ },
+ "@sideway/pinpoint": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
+ "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
+ "dev": true
+ },
"@tootallnate/once": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@@ -13948,12 +14499,30 @@
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true
},
+ "async": {
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
+ "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ },
"at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
"dev": true
},
+ "axios": {
+ "version": "0.21.4",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
+ "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
+ "dev": true,
+ "requires": {
+ "follow-redirects": "^1.14.0"
+ }
+ },
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -13966,6 +14535,15 @@
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true
},
+ "basic-auth": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+ "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
"before-after-hook": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
@@ -14030,6 +14608,12 @@
}
}
},
+ "bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true
+ },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -14245,6 +14829,12 @@
"integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==",
"dev": true
},
+ "check-more-types": {
+ "version": "2.24.0",
+ "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz",
+ "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==",
+ "dev": true
+ },
"chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@@ -14660,6 +15250,12 @@
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
},
+ "corser": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
+ "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==",
+ "dev": true
+ },
"cosmiconfig": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
@@ -15279,6 +15875,32 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
+ "event-stream": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
+ "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==",
+ "dev": true,
+ "requires": {
+ "duplexer": "~0.1.1",
+ "from": "~0",
+ "map-stream": "~0.1.0",
+ "pause-stream": "0.0.11",
+ "split": "0.3",
+ "stream-combiner": "~0.0.4",
+ "through": "~2.3.1"
+ },
+ "dependencies": {
+ "split": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
+ "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==",
+ "dev": true,
+ "requires": {
+ "through": "2"
+ }
+ }
+ }
+ },
"eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
@@ -15463,6 +16085,18 @@
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
"dev": true
},
+ "follow-redirects": {
+ "version": "1.15.2",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+ "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+ "dev": true
+ },
+ "from": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
+ "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==",
+ "dev": true
+ },
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -15860,12 +16494,32 @@
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
+ "html-encoding-sniffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
+ "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
+ "dev": true,
+ "requires": {
+ "whatwg-encoding": "^2.0.0"
+ }
+ },
"http-cache-semantics": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
"dev": true
},
+ "http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "dev": true,
+ "requires": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ }
+ },
"http-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
@@ -15877,6 +16531,78 @@
"debug": "4"
}
},
+ "http-server": {
+ "version": "14.1.1",
+ "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz",
+ "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==",
+ "dev": true,
+ "requires": {
+ "basic-auth": "^2.0.1",
+ "chalk": "^4.1.2",
+ "corser": "^2.0.1",
+ "he": "^1.2.0",
+ "html-encoding-sniffer": "^3.0.0",
+ "http-proxy": "^1.18.1",
+ "mime": "^1.6.0",
+ "minimist": "^1.2.6",
+ "opener": "^1.5.1",
+ "portfinder": "^1.0.28",
+ "secure-compare": "3.0.1",
+ "union": "~0.5.0",
+ "url-join": "^4.0.1"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
"https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
@@ -16401,6 +17127,19 @@
"integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
"dev": true
},
+ "joi": {
+ "version": "17.6.2",
+ "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.2.tgz",
+ "integrity": "sha512-+gqqdh1xc1wb+Lor0J9toqgeReyDOCqOdG8QSdRcEvwrcRiFQZneUCGKjFjuyBWUb3uaFOgY56yMaZ5FIc+H4w==",
+ "dev": true,
+ "requires": {
+ "@hapi/hoek": "^9.0.0",
+ "@hapi/topo": "^5.0.0",
+ "@sideway/address": "^4.1.3",
+ "@sideway/formula": "^3.0.0",
+ "@sideway/pinpoint": "^2.0.0"
+ }
+ },
"js-sdsl": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz",
@@ -16514,6 +17253,12 @@
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true
},
+ "lazy-ass": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
+ "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==",
+ "dev": true
+ },
"lerna": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/lerna/-/lerna-5.5.1.tgz",
@@ -16866,6 +17611,12 @@
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
"dev": true
},
+ "map-stream": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
+ "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==",
+ "dev": true
+ },
"marked": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.1.0.tgz",
@@ -17020,6 +17771,12 @@
"picomatch": "^2.3.1"
}
},
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true
+ },
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@@ -18064,6 +18821,12 @@
"is-wsl": "^2.2.0"
}
},
+ "opener": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
+ "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
+ "dev": true
+ },
"optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -18389,6 +19152,15 @@
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
"dev": true
},
+ "pause-stream": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+ "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
+ "dev": true,
+ "requires": {
+ "through": "~2.3"
+ }
+ },
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -18429,6 +19201,37 @@
"find-up": "^4.0.0"
}
},
+ "portfinder": {
+ "version": "1.0.32",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
+ "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==",
+ "dev": true,
+ "requires": {
+ "async": "^2.6.4",
+ "debug": "^3.2.7",
+ "mkdirp": "^0.5.6"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.6"
+ }
+ }
+ }
+ },
"prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -18508,6 +19311,15 @@
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"dev": true
},
+ "ps-tree": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz",
+ "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==",
+ "dev": true,
+ "requires": {
+ "event-stream": "=3.3.4"
+ }
+ },
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@@ -18530,6 +19342,15 @@
"integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
"dev": true
},
+ "qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dev": true,
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
"queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -18737,6 +19558,12 @@
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
"dev": true
},
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+ "dev": true
+ },
"resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
@@ -18868,6 +19695,12 @@
"ajv-keywords": "^3.5.2"
}
},
+ "secure-compare": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
+ "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==",
+ "dev": true
+ },
"semver": {
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
@@ -19081,6 +19914,41 @@
"minipass": "^3.1.1"
}
},
+ "start-server-and-test": {
+ "version": "1.14.0",
+ "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.14.0.tgz",
+ "integrity": "sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw==",
+ "dev": true,
+ "requires": {
+ "bluebird": "3.7.2",
+ "check-more-types": "2.24.0",
+ "debug": "4.3.2",
+ "execa": "5.1.1",
+ "lazy-ass": "1.6.0",
+ "ps-tree": "1.2.0",
+ "wait-on": "6.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+ "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ }
+ }
+ },
+ "stream-combiner": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
+ "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==",
+ "dev": true,
+ "requires": {
+ "duplexer": "~0.1.1"
+ }
+ },
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -19647,6 +20515,15 @@
"through": "^2.3.8"
}
},
+ "union": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
+ "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==",
+ "dev": true,
+ "requires": {
+ "qs": "^6.4.0"
+ }
+ },
"unique-filename": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz",
@@ -19703,6 +20580,12 @@
"punycode": "^2.1.0"
}
},
+ "url-join": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
+ "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
+ "dev": true
+ },
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -19758,6 +20641,19 @@
"integrity": "sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==",
"dev": true
},
+ "wait-on": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.0.tgz",
+ "integrity": "sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw==",
+ "dev": true,
+ "requires": {
+ "axios": "^0.21.1",
+ "joi": "^17.4.0",
+ "lodash": "^4.17.21",
+ "minimist": "^1.2.5",
+ "rxjs": "^7.1.0"
+ }
+ },
"walk-up-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-1.0.0.tgz",
@@ -19888,6 +20784,26 @@
"dev": true,
"peer": true
},
+ "whatwg-encoding": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
+ "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
+ "dev": true,
+ "requires": {
+ "iconv-lite": "0.6.3"
+ },
+ "dependencies": {
+ "iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ }
+ }
+ }
+ },
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
diff --git a/package.json b/package.json
index 105c720..b4f6b14 100644
--- a/package.json
+++ b/package.json
@@ -5,13 +5,18 @@
"lint": "npm-run-all lint:*",
"lint:packages": "lerna run lint",
"lint:root": "eslint tests",
- "test": "npm-run-all test:*:*",
- "test:browser": "mocha-headless-chrome -a allow-file-access-from-files -a enable-features=SharedArrayBuffer",
- "test:browser:mt": "npm run test:browser -- -f tests/*-mt.test.html",
- "test:browser:st": "npm run test:browser -- -f tests/*-st.test.html",
+ "pretest": "lerna run build",
+ "test": "server-test test:browser:server http://localhost:3000 test:all",
+ "test:all": "npm-run-all test:*:*:*",
+ "test:browser": "mocha-headless-chrome -t 60000 -a allow-file-access-from-files -a enable-features=SharedArrayBuffer",
+ "test:browser:core:mt": "npm run test:browser -- -f tests/ffmpeg-core-mt.test.html",
+ "test:browser:core:st": "npm run test:browser -- -f tests/ffmpeg-core-st.test.html",
+ "test:browser:ffmpeg:mt": "npm run test:browser -- -f tests/ffmpeg-mt.test.html",
+ "test:browser:ffmpeg:st": "npm run test:browser -- -f tests/ffmpeg-st.test.html",
+ "test:browser:server": "http-server -c-1 --cors -p 3000 .",
"test:node": "mocha --exit --bail",
- "test:node:mt": "npm run test:node -- --require tests/test-helper-mt.js tests/*.test.js",
- "test:node:st": "npm run test:node -- --require tests/test-helper-st.js tests/*.test.js"
+ "test:node:core:mt": "npm run test:node -- --require tests/test-helper-mt.js tests/ffmpeg-core.test.js",
+ "test:node:core:st": "npm run test:node -- --require tests/test-helper-st.js tests/ffmpeg-core.test.js"
},
"workspaces": [
"packages/*",
@@ -19,9 +24,11 @@
],
"devDependencies": {
"chai": "^4.3.6",
+ "http-server": "^14.1.1",
"lerna": "^5.4.3",
"mocha": "^10.0.0",
"mocha-headless-chrome": "^4.0.0",
- "npm-run-all": "^4.1.5"
+ "npm-run-all": "^4.1.5",
+ "start-server-and-test": "^1.14.0"
}
}
diff --git a/packages/ffmpeg/package.json b/packages/ffmpeg/package.json
index 5d71c8a..cf80c8f 100644
--- a/packages/ffmpeg/package.json
+++ b/packages/ffmpeg/package.json
@@ -1,7 +1,7 @@
{
"name": "@ffmpeg/ffmpeg",
"version": "0.11.5",
- "description": "FFmpeg WebAssembly version",
+ "description": "FFmpeg WebAssembly version for browser",
"main": "./dist/umd/ffmpeg.js",
"types": "./dist/umd/ffmpeg.d.ts",
"exports": {
@@ -12,14 +12,15 @@
}
},
"scripts": {
- "dev": "webpack --watch -c webpack.dev.config.js",
+ "dev": "webpack -w --mode development",
"lint": "eslint src",
"clean": "rimraf dist",
"build:umd": "webpack",
"build:d": "tsc -p tsconfig.d.json",
"build:esm": "tsc -p tsconfig.esm.json",
"build": "npm-run-all clean build:*",
- "docs": "typedoc --entryPointStrategy expand ./src"
+ "docs": "typedoc --entryPointStrategy expand ./src",
+ "docs:serve": "http-server docs"
},
"files": [
"dist",
@@ -52,6 +53,7 @@
"@typescript-eslint/eslint-plugin": "^5.37.0",
"@typescript-eslint/parser": "^5.37.0",
"eslint": "^8.23.1",
+ "http-server": "^14.1.1",
"npm-run-all": "^4.1.5",
"rimraf": "^3.0.2",
"ts-loader": "^9.4.1",
diff --git a/packages/ffmpeg/src/classes.ts b/packages/ffmpeg/src/classes.ts
index 2f55c98..f18ccb3 100644
--- a/packages/ffmpeg/src/classes.ts
+++ b/packages/ffmpeg/src/classes.ts
@@ -4,15 +4,73 @@ import {
CallbackData,
Callbacks,
DownloadProgressEvent,
+ FFFSPaths,
FFMessageEventCallback,
FFMessageLoadConfig,
- IsDone,
+ OK,
IsFirst,
LogEvent,
Message,
Progress,
+ FileData,
} from "./types";
import { getMessageID } from "./utils";
+import { ERROR_TERMINATED, ERROR_NOT_LOADED } from "./errors";
+
+export declare interface FFmpeg {
+ /**
+ * Listen to download progress events from `ffmpeg.load()`.
+ *
+ * @example
+ * ```ts
+ * ffmpeg.on(FFmpeg.DOWNLOAD, ({ url, total, received, delta, done }) => {
+ * // ...
+ * })
+ * ```
+ *
+ * @category Event
+ */
+ on(
+ event: typeof FFmpeg.DOWNLOAD,
+ listener: (data: DownloadProgressEvent) => void
+ ): this;
+ /**
+ * Listen to log events from `ffmpeg.exec()`.
+ *
+ * @example
+ * ```ts
+ * ffmpeg.on(FFmpeg.LOG, ({ message }) => {
+ * // ...
+ * })
+ * ```
+ *
+ * @remarks
+ * log includes output to stdout and stderr.
+ *
+ * @category Event
+ */
+ on(event: typeof FFmpeg.LOG, listener: (log: LogEvent) => void): this;
+ /**
+ * Listen to progress events from `ffmpeg.exec()`.
+ *
+ * @example
+ * ```ts
+ * ffmpeg.on(FFmpeg.PROGRESS, ({ progress }) => {
+ * // ...
+ * })
+ * ```
+ *
+ * @remarks
+ * The progress events are accurate only when the length of
+ * input and output video/audio file are the same.
+ *
+ * @category Event
+ */
+ on(
+ event: typeof FFmpeg.PROGRESS,
+ listener: (progress: Progress) => void
+ ): this;
+}
/**
* Provides APIs to interact with ffmpeg web worker.
@@ -27,80 +85,56 @@ export class FFmpeg extends EventEmitter {
/** @event */ static readonly LOG = "log" as const;
/** @event */ static readonly PROGRESS = "progress" as const;
+ #worker: Worker | null = null;
/**
- * Listen to download progress events from `ffmpeg.load()`.
+ * #resolves and #rejects tracks Promise resolves and rejects to
+ * be called when we receive message from web worker.
*
- * @category Event
*/
- on(
- event: typeof FFmpeg.DOWNLOAD,
- listener: (data: DownloadProgressEvent) => void
- ): this;
- /**
- * Listen to log events from `ffmpeg.exec()`.
- *
- * @remarks
- * log includes output to stdout and stderr.
- *
- * @category Event
- */
- on(event: typeof FFmpeg.LOG, listener: (log: LogEvent) => void): this;
- /**
- * Listen to progress events from `ffmpeg.exec()`.
- *
- * @remarks
- * The progress events are accurate only when the length of
- * input and output video/audio file are the same.
- *
- * @category Event
- */
- on(
- event: typeof FFmpeg.PROGRESS,
- listener: (progress: Progress) => void
- ): this;
- on(event: string, listener: any): this {
- return this;
- }
-
- #worker: Worker;
#resolves: Callbacks = {};
#rejects: Callbacks = {};
constructor() {
super();
- this.#worker = new Worker(new URL("./worker.ts", import.meta.url));
- this.#registerHandlers();
}
- /** register worker message event handlers.
+ /**
+ * register worker message event handlers.
*/
#registerHandlers = () => {
- this.#worker.onmessage = ({
- data: { id, type, data },
- }: FFMessageEventCallback) => {
- switch (type) {
- case FFMessageType.LOAD:
- case FFMessageType.EXEC:
- case FFMessageType.WRITE_FILE:
- case FFMessageType.READ_FILE:
- this.#resolves[id](data);
- break;
- case FFMessageType.DOWNLOAD:
- this.emit(FFmpeg.DOWNLOAD, data as DownloadProgressEvent);
- break;
- case FFMessageType.LOG:
- this.emit(FFmpeg.LOG, data as LogEvent);
- break;
- case FFMessageType.PROGRESS:
- this.emit(FFmpeg.PROGRESS, data as Progress);
- break;
- case FFMessageType.ERROR:
- this.#rejects[id](data);
- break;
- }
- delete this.#resolves[id];
- delete this.#rejects[id];
- };
+ if (this.#worker) {
+ this.#worker.onmessage = ({
+ data: { id, type, data },
+ }: FFMessageEventCallback) => {
+ switch (type) {
+ case FFMessageType.LOAD:
+ case FFMessageType.EXEC:
+ case FFMessageType.WRITE_FILE:
+ case FFMessageType.READ_FILE:
+ case FFMessageType.DELETE_FILE:
+ case FFMessageType.RENAME:
+ case FFMessageType.CREATE_DIR:
+ case FFMessageType.LIST_DIR:
+ case FFMessageType.DELETE_DIR:
+ this.#resolves[id](data);
+ break;
+ case FFMessageType.DOWNLOAD:
+ this.emit(FFmpeg.DOWNLOAD, data as DownloadProgressEvent);
+ break;
+ case FFMessageType.LOG:
+ this.emit(FFmpeg.LOG, data as LogEvent);
+ break;
+ case FFMessageType.PROGRESS:
+ this.emit(FFmpeg.PROGRESS, data as Progress);
+ break;
+ case FFMessageType.ERROR:
+ this.#rejects[id](data);
+ break;
+ }
+ delete this.#resolves[id];
+ delete this.#rejects[id];
+ };
+ }
};
/**
@@ -109,13 +143,18 @@ export class FFmpeg extends EventEmitter {
#send = (
{ type, data }: Message,
trans: Transferable[] = []
- ): Promise =>
- new Promise((resolve, reject) => {
+ ): Promise => {
+ if (!this.#worker) {
+ return Promise.reject(ERROR_NOT_LOADED);
+ }
+
+ return new Promise((resolve, reject) => {
const id = getMessageID();
- this.#worker.postMessage({ id, type, data }, trans);
+ this.#worker && this.#worker.postMessage({ id, type, data }, trans);
this.#resolves[id] = resolve;
this.#rejects[id] = reject;
});
+ };
/**
* Loads ffmpeg-core inside web worker. It is required to call this method first
@@ -124,11 +163,16 @@ export class FFmpeg extends EventEmitter {
* @category FFmpeg
* @returns `true` if ffmpeg core is loaded for the first time.
*/
- public load = (config: FFMessageLoadConfig): Promise =>
- this.#send({
+ public load = (config: FFMessageLoadConfig = {}): Promise => {
+ if (!this.#worker) {
+ this.#worker = new Worker(new URL("./worker.ts", import.meta.url));
+ this.#registerHandlers();
+ }
+ return this.#send({
type: FFMessageType.LOAD,
data: config,
}) as Promise;
+ };
/**
* Execute ffmpeg command.
@@ -166,7 +210,28 @@ export class FFmpeg extends EventEmitter {
}) as Promise;
/**
- * Write data to ffmpeg.wasm in memory file system.
+ * Terminate all ongoing API calls and terminate web worker.
+ * `FFmpeg.load()` must be called again before calling any other APIs.
+ *
+ * @category FFmpeg
+ */
+ public terminate = (): void => {
+ const ids = Object.keys(this.#rejects);
+ // rejects all incomplete Promises.
+ for (const id of ids) {
+ this.#rejects[id](ERROR_TERMINATED);
+ delete this.#rejects[id];
+ delete this.#resolves[id];
+ }
+
+ if (this.#worker) {
+ this.#worker.terminate();
+ this.#worker = null;
+ }
+ };
+
+ /**
+ * Write data to ffmpeg.wasm.
*
* @example
* ```ts
@@ -178,25 +243,22 @@ export class FFmpeg extends EventEmitter {
*
* @category File System
*/
- public writeFile = (
- path: string,
- bin: Uint8Array | string
- ): Promise => {
+ public writeFile = (path: string, data: FileData): Promise => {
const trans: Transferable[] = [];
- if (bin instanceof Uint8Array) {
- trans.push(bin.buffer);
+ if (data instanceof Uint8Array) {
+ trans.push(data.buffer);
}
return this.#send(
{
type: FFMessageType.WRITE_FILE,
- data: { path, bin },
+ data: { path, data },
},
trans
- ) as Promise;
+ ) as Promise;
};
/**
- * Read data from ffmpeg.wasm in memory file system.
+ * Read data from ffmpeg.wasm.
*
* @example
* ```ts
@@ -207,9 +269,74 @@ export class FFmpeg extends EventEmitter {
*
* @category File System
*/
- public readFile = (path: string): Promise =>
+ public readFile = (
+ path: string,
+ /**
+ * File content encoding, supports two encodings:
+ * - utf8: read file as text file, return data in string type.
+ * - binary: read file as binary file, return data in Uint8Array type.
+ *
+ * @defaultValue binary
+ */
+ encoding = "binary"
+ ): Promise =>
this.#send({
type: FFMessageType.READ_FILE,
+ data: { path, encoding },
+ }) as Promise;
+
+ /**
+ * Delete a file.
+ *
+ * @category File System
+ */
+ public deleteFile = (path: string): Promise =>
+ this.#send({
+ type: FFMessageType.DELETE_FILE,
data: { path },
- }) as Promise;
+ }) as Promise;
+
+ /**
+ * Rename a file or directory.
+ *
+ * @category File System
+ */
+ public rename = (oldPath: string, newPath: string): Promise =>
+ this.#send({
+ type: FFMessageType.RENAME,
+ data: { oldPath, newPath },
+ }) as Promise;
+
+ /**
+ * Create a directory.
+ *
+ * @category File System
+ */
+ public createDir = (path: string): Promise =>
+ this.#send({
+ type: FFMessageType.CREATE_DIR,
+ data: { path },
+ }) as Promise;
+
+ /**
+ * List directory contents.
+ *
+ * @category File System
+ */
+ public listDir = (path: string): Promise =>
+ this.#send({
+ type: FFMessageType.LIST_DIR,
+ data: { path },
+ }) as Promise;
+
+ /**
+ * Delete an empty directory.
+ *
+ * @category File System
+ */
+ public deleteDir = (path: string): Promise =>
+ this.#send({
+ type: FFMessageType.DELETE_DIR,
+ data: { path },
+ }) as Promise;
}
diff --git a/packages/ffmpeg/src/const.ts b/packages/ffmpeg/src/const.ts
index 4e46dfd..f01f071 100644
--- a/packages/ffmpeg/src/const.ts
+++ b/packages/ffmpeg/src/const.ts
@@ -3,13 +3,18 @@ export const MIME_TYPE_JAVASCRIPT = "text/javascript";
export const MIME_TYPE_WASM = "application/wasm";
export const CORE_VERSION = "0.12.0";
-export const CORE_URL = `https://unpkg.com/@ffmpeg/core@${CORE_VERSION}/dist/umd/ffmpeg-core.js`;
+export const CORE_URL = `https://unpkg.com/@ffmpeg/core@${CORE_VERSION}/dist/ffmpeg-core.js`;
export enum FFMessageType {
LOAD = "load",
- WRITE_FILE = "WRITE_FILE",
EXEC = "EXEC",
+ WRITE_FILE = "WRITE_FILE",
READ_FILE = "READ_FILE",
+ DELETE_FILE = "DELETE_FILE",
+ RENAME = "RENAME",
+ CREATE_DIR = "CREATE_DIR",
+ LIST_DIR = "LIST_DIR",
+ DELETE_DIR = "DELETE_DIR",
ERROR = "ERROR",
DOWNLOAD = "DOWNLOAD",
diff --git a/packages/ffmpeg/src/errors.ts b/packages/ffmpeg/src/errors.ts
index 9d98e51..afac3e2 100644
--- a/packages/ffmpeg/src/errors.ts
+++ b/packages/ffmpeg/src/errors.ts
@@ -11,3 +11,4 @@ export const ERROR_NOT_LOADED = new Error(
export const ERROR_INCOMPLETED_DOWNLOAD = new Error(
"failed to complete download"
);
+export const ERROR_TERMINATED = new Error("called FFmpeg.terminate()");
diff --git a/packages/ffmpeg/src/types.ts b/packages/ffmpeg/src/types.ts
index 87476e9..66f6927 100644
--- a/packages/ffmpeg/src/types.ts
+++ b/packages/ffmpeg/src/types.ts
@@ -1,4 +1,5 @@
export type FFFSPath = string;
+export type FFFSPaths = FFFSPath[];
/**
* ffmpeg-core loading configuration.
@@ -48,25 +49,56 @@ export interface FFMessageLoadConfig {
thread?: boolean;
}
-export interface FFMessageWriteFileData {
- path: FFFSPath;
- bin: Uint8Array | string;
-}
-
export interface FFMessageExecData {
args: string[];
timeout?: number;
}
+export interface FFMessageWriteFileData {
+ path: FFFSPath;
+ data: FileData;
+}
+
export interface FFMessageReadFileData {
path: FFFSPath;
+ encoding: string;
+}
+
+export interface FFMessageDeleteFileData {
+ path: FFFSPath;
+}
+
+export interface FFMessageRenameData {
+ oldPath: FFFSPath;
+ newPath: FFFSPath;
+}
+
+export interface FFMessageCreateDirData {
+ path: FFFSPath;
+}
+
+export interface FFMessageListDirData {
+ path: FFFSPath;
+}
+
+/**
+ * @remarks
+ * Only deletes empty directory.
+ */
+export interface FFMessageDeleteDirData {
+ path: FFFSPath;
}
export type FFMessageData =
| FFMessageLoadConfig
- | FFMessageWriteFileData
| FFMessageExecData
- | FFMessageReadFileData;
+ | FFMessageWriteFileData
+ | FFMessageReadFileData
+ | FFMessageDeleteFileData
+ | FFMessageRenameData
+ | FFMessageCreateDirData
+ | FFMessageListDirData
+ | FFMessageDeleteDirData;
export interface Message {
type: string;
@@ -94,12 +126,15 @@ export interface LogEvent {
message: string;
}
+export interface Progress {
+ progress: number;
+}
+
export type ExitCode = number;
export type ErrorMessage = string;
-export type FileData = Uint8Array;
-export type Progress = number;
+export type FileData = Uint8Array | string;
export type IsFirst = boolean;
-export type IsDone = boolean;
+export type OK = boolean;
export type CallbackData =
| FileData
@@ -109,8 +144,9 @@ export type CallbackData =
| LogEvent
| Progress
| IsFirst
- | IsDone
+ | OK
| Error
+ | FFFSPaths
| undefined;
export interface Callbacks {
diff --git a/packages/ffmpeg/src/utils.ts b/packages/ffmpeg/src/utils.ts
index 70016eb..d18a75e 100644
--- a/packages/ffmpeg/src/utils.ts
+++ b/packages/ffmpeg/src/utils.ts
@@ -16,36 +16,56 @@ export const getMessageID = (() => {
/**
* Download content of a URL with progress.
+ *
+ * Progress only works when Content-Length is provided by the server.
+ *
*/
export const downloadWithProgress = async (
url: string | URL,
cb: ProgressCallback
-): Promise => {
+): Promise => {
const resp = await fetch(url);
- const reader = resp.body?.getReader();
- if (!reader) throw ERROR_RESPONSE_BODY_READER;
+ let buf;
- const total = parseInt(resp.headers.get(HeaderContentLength) || "0");
- if (total === 0) throw ERROR_ZERO_CONTENT_LENGTH;
+ try {
+ const total = parseInt(resp.headers.get(HeaderContentLength) || "0");
+ if (total === 0) throw ERROR_ZERO_CONTENT_LENGTH;
- const data = new Uint8Array(total);
- let received = 0;
- for (;;) {
- const { done, value } = await reader.read();
- const delta = value ? value.length : 0;
+ const reader = resp.body?.getReader();
+ if (!reader) throw ERROR_RESPONSE_BODY_READER;
- if (done) {
- if (total !== received) throw ERROR_INCOMPLETED_DOWNLOAD;
+ const data = new Uint8Array(total);
+ let received = 0;
+ for (;;) {
+ const { done, value } = await reader.read();
+ const delta = value ? value.length : 0;
+
+ if (done) {
+ if (total !== received) throw ERROR_INCOMPLETED_DOWNLOAD;
+ cb({ url, total, received, delta, done });
+ break;
+ }
+
+ data.set(value, received);
+ received += delta;
cb({ url, total, received, delta, done });
- break;
}
- data.set(value, received);
- received += delta;
- cb({ url, total, received, delta, done });
+ buf = data.buffer;
+ } catch (e) {
+ console.log(`failed to send download progress event: `, e);
+ // Fetch arrayBuffer directly when it is not possible to get progress.
+ buf = await resp.arrayBuffer();
+ cb({
+ url,
+ total: buf.byteLength,
+ received: buf.byteLength,
+ delta: 0,
+ done: true,
+ });
}
- return data;
+ return buf;
};
/**
@@ -58,5 +78,7 @@ export const toBlobURL = async (
cb: ProgressCallback
): Promise =>
URL.createObjectURL(
- new Blob([(await downloadWithProgress(url, cb)).buffer], { type: mimeType })
+ new Blob([await downloadWithProgress(url, cb)], {
+ type: mimeType,
+ })
);
diff --git a/packages/ffmpeg/src/worker.ts b/packages/ffmpeg/src/worker.ts
index 2f82c1a..1f38e50 100644
--- a/packages/ffmpeg/src/worker.ts
+++ b/packages/ffmpeg/src/worker.ts
@@ -6,13 +6,20 @@ import type { FFmpegCoreModule, FFmpegCoreModuleFactory } from "@ffmpeg/types";
import type {
FFMessageEvent,
FFMessageLoadConfig,
- FFMessageWriteFileData,
FFMessageExecData,
+ FFMessageWriteFileData,
FFMessageReadFileData,
+ FFMessageDeleteFileData,
+ FFMessageRenameData,
+ FFMessageCreateDirData,
+ FFMessageListDirData,
+ FFMessageDeleteDirData,
CallbackData,
IsFirst,
- IsDone,
+ OK,
ExitCode,
+ FFFSPaths,
+ FileData,
} from "./types";
import { toBlobURL } from "./utils";
import {
@@ -53,18 +60,15 @@ const load = async ({
self.postMessage({ type: FFMessageType.DOWNLOAD, data })
);
if (thread) {
- try {
- workerURL = await toBlobURL(workerURL, MIME_TYPE_JAVASCRIPT, (data) =>
- self.postMessage({ type: FFMessageType.DOWNLOAD, data })
- );
- // eslint-disable-next-line
- } catch (e) {}
+ workerURL = await toBlobURL(workerURL, MIME_TYPE_JAVASCRIPT, (data) =>
+ self.postMessage({ type: FFMessageType.DOWNLOAD, data })
+ );
}
}
importScripts(coreURL);
ffmpeg = await (self as WorkerGlobalScope).createFFmpegCore({
- // Fixed `Overload resolution failed.` when using multi-threaded ffmpeg-core.
+ // Fix `Overload resolution failed.` when using multi-threaded ffmpeg-core.
mainScriptUrlOrBlob: coreURL,
locateFile: (path: string, prefix: string): string => {
if (path.endsWith(".wasm")) return wasmURL;
@@ -75,17 +79,12 @@ const load = async ({
ffmpeg.setLogger((data) =>
self.postMessage({ type: FFMessageType.LOG, data })
);
- ffmpeg.setProgress((data: number) =>
- self.postMessage({ type: FFMessageType.PROGRESS, data })
+ ffmpeg.setProgress((progress: number) =>
+ self.postMessage({ type: FFMessageType.PROGRESS, data: { progress } })
);
return first;
};
-const writeFile = ({ path, bin }: FFMessageWriteFileData): IsDone => {
- ffmpeg.FS.writeFile(path, bin);
- return true;
-};
-
const exec = ({ args, timeout = -1 }: FFMessageExecData): ExitCode => {
ffmpeg.setTimeout(timeout);
ffmpeg.exec(...args);
@@ -94,8 +93,40 @@ const exec = ({ args, timeout = -1 }: FFMessageExecData): ExitCode => {
return ret;
};
-const readFile = ({ path }: FFMessageReadFileData): Uint8Array =>
- ffmpeg.FS.readFile(path);
+const writeFile = ({ path, data }: FFMessageWriteFileData): OK => {
+ ffmpeg.FS.writeFile(path, data);
+ return true;
+};
+
+const readFile = ({ path, encoding }: FFMessageReadFileData): FileData =>
+ ffmpeg.FS.readFile(path, { encoding });
+
+// TODO: check if deletion works.
+const deleteFile = ({ path }: FFMessageDeleteFileData): OK => {
+ ffmpeg.FS.unlink(path);
+ return true;
+};
+
+const rename = ({ oldPath, newPath }: FFMessageRenameData): OK => {
+ ffmpeg.FS.rename(oldPath, newPath);
+ return true;
+};
+
+// TODO: check if creation works.
+const createDir = ({ path }: FFMessageCreateDirData): OK => {
+ ffmpeg.FS.mkdir(path);
+ return true;
+};
+
+const listDir = ({ path }: FFMessageListDirData): FFFSPaths => {
+ return ffmpeg.FS.readdir(path);
+};
+
+// TODO: check if deletion works.
+const deleteDir = ({ path }: FFMessageDeleteDirData): OK => {
+ ffmpeg.FS.rmdir(path);
+ return true;
+};
self.onmessage = async ({
data: { id, type, data: _data },
@@ -109,15 +140,30 @@ self.onmessage = async ({
case FFMessageType.LOAD:
data = await load(_data as FFMessageLoadConfig);
break;
- case FFMessageType.WRITE_FILE:
- data = writeFile(_data as FFMessageWriteFileData);
- break;
case FFMessageType.EXEC:
data = exec(_data as FFMessageExecData);
break;
+ case FFMessageType.WRITE_FILE:
+ data = writeFile(_data as FFMessageWriteFileData);
+ break;
case FFMessageType.READ_FILE:
data = readFile(_data as FFMessageReadFileData);
break;
+ case FFMessageType.DELETE_FILE:
+ data = deleteFile(_data as FFMessageDeleteFileData);
+ break;
+ case FFMessageType.RENAME:
+ data = rename(_data as FFMessageRenameData);
+ break;
+ case FFMessageType.CREATE_DIR:
+ data = createDir(_data as FFMessageCreateDirData);
+ break;
+ case FFMessageType.LIST_DIR:
+ data = listDir(_data as FFMessageListDirData);
+ break;
+ case FFMessageType.DELETE_DIR:
+ data = deleteDir(_data as FFMessageDeleteDirData);
+ break;
default:
throw ERROR_UNKNOWN_MESSAGE_TYPE;
}
diff --git a/packages/ffmpeg/webpack.dev.config.js b/packages/ffmpeg/webpack.dev.config.js
deleted file mode 100644
index 329de5a..0000000
--- a/packages/ffmpeg/webpack.dev.config.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const path = require("path");
-
-module.exports = {
- mode: "development",
- devtool: "source-map",
- entry: "./src/index.ts",
- module: {
- rules: [
- {
- test: /\.ts$/,
- loader: "ts-loader",
- options: {
- transpileOnly: false,
- },
- },
- ],
- },
- resolve: {
- extensions: [".ts"],
- },
- output: {
- path: path.resolve(__dirname, "dist/umd"),
- filename: "ffmpeg.js",
- library: "FFmpegWASM",
- libraryTarget: "umd",
- },
-};
diff --git a/packages/types/types/index.d.ts b/packages/types/types/index.d.ts
index 2385dc8..c6a0a1a 100644
--- a/packages/types/types/index.d.ts
+++ b/packages/types/types/index.d.ts
@@ -4,12 +4,18 @@ export type Pointer = number;
export type StringPointer = Pointer;
export type StringArrayPointer = Pointer;
+export interface ReadFileOptions {
+ encdoing: string;
+}
+
export interface FS {
- mkdir: (fileName: string) => void;
- readFile: (fileName: string) => Uint8Array;
- readdir: (pathName: string) => string[];
- unlink: (fileName: string) => void;
- writeFile: (fileName: string, binaryData: Uint8Array | string) => void;
+ mkdir: (path: string) => void;
+ rmdir: (path: string) => void;
+ rename: (oldPath: string, newPath: string) => void;
+ writeFile: (path: string, data: Uint8Array | string) => void;
+ readFile: (path: string, opts: OptionReadFile) => Uint8Array | string;
+ readdir: (path: string) => string[];
+ unlink: (path: string) => void;
}
export interface Log {
diff --git a/tests/.eslintrc.json b/tests/.eslintrc.json
index b548f41..398d3e1 100644
--- a/tests/.eslintrc.json
+++ b/tests/.eslintrc.json
@@ -1,10 +1,13 @@
{
"extends": "eslint:recommended",
"globals": {
- "expect": true,
- "createFFmpegCore": true,
+ "CORE_URL": true,
+ "FFMPEG_TYPE": true,
+ "FFmpegWASM": true,
"VIDEO_1S_MP4": true,
- "FFMPEG_TYPE": true
+ "b64ToUint8Array": true,
+ "createFFmpegCore": true,
+ "expect": true
},
"env": {
"node": true,
diff --git a/tests/ffmpeg-core-mt.test.html b/tests/ffmpeg-core-mt.test.html
index a53d7f0..7793122 100644
--- a/tests/ffmpeg-core-mt.test.html
+++ b/tests/ffmpeg-core-mt.test.html
@@ -10,7 +10,7 @@
-
+
diff --git a/tests/ffmpeg-core-st.test.html b/tests/ffmpeg-core-st.test.html
index faecbe6..58bf10f 100644
--- a/tests/ffmpeg-core-st.test.html
+++ b/tests/ffmpeg-core-st.test.html
@@ -10,7 +10,7 @@
-
+
diff --git a/tests/ffmpeg-core.test.js b/tests/ffmpeg-core.test.js
index a08a1bf..efb4708 100644
--- a/tests/ffmpeg-core.test.js
+++ b/tests/ffmpeg-core.test.js
@@ -1,31 +1,21 @@
-let ffmpeg;
+let core;
const genName = (name) => `[ffmpeg-core][${FFMPEG_TYPE}] ${name}`;
-const b64ToUint8Array = (b64) => {
- const bin = atob(b64);
- const len = bin.length;
- const bytes = new Uint8Array(len);
- for (let i = 0; i < len; i++) {
- bytes[i] = bin.charCodeAt(i);
- }
- return bytes;
-};
-
const reset = () => {
- ffmpeg.reset();
- ffmpeg.setLogger(() => {});
- ffmpeg.setProgress(() => {});
+ core.reset();
+ core.setLogger(() => {});
+ core.setProgress(() => {});
};
before(async () => {
- ffmpeg = await createFFmpegCore();
- ffmpeg.FS.writeFile("video.mp4", b64ToUint8Array(VIDEO_1S_MP4));
+ core = await createFFmpegCore();
+ core.FS.writeFile("video.mp4", b64ToUint8Array(VIDEO_1S_MP4));
});
describe(genName("createFFmpeg()"), () => {
it("should be OK", () => {
- expect(ffmpeg).to.be.ok;
+ expect(core).to.be.ok;
});
});
@@ -33,16 +23,16 @@ describe(genName("reset()"), () => {
beforeEach(reset);
it("should exist", () => {
- expect("reset" in ffmpeg).to.be.true;
+ expect("reset" in core).to.be.true;
});
it("should reset ret and timeout", () => {
- ffmpeg.ret = 1024;
- ffmpeg.timeout = 1024;
+ core.ret = 1024;
+ core.timeout = 1024;
- ffmpeg.reset();
+ core.reset();
- expect(ffmpeg.ret).to.equal(-1);
- expect(ffmpeg.timeout).to.equal(-1);
+ expect(core.ret).to.equal(-1);
+ expect(core.timeout).to.equal(-1);
});
});
@@ -50,18 +40,18 @@ describe(genName("exec()"), () => {
beforeEach(reset);
it("should exist", () => {
- expect("exec" in ffmpeg).to.be.true;
+ expect("exec" in core).to.be.true;
});
it("should output help", () => {
- expect(ffmpeg.exec("-h")).to.equal(0);
+ expect(core.exec("-h")).to.equal(0);
});
it("should transcode", () => {
- expect(ffmpeg.exec("-i", "video.mp4", "video.avi")).to.equal(0);
- const out = ffmpeg.FS.readFile("video.avi");
+ expect(core.exec("-i", "video.mp4", "video.avi")).to.equal(0);
+ const out = core.FS.readFile("video.avi");
expect(out.length).to.not.equal(0);
- ffmpeg.FS.unlink("video.avi");
+ core.FS.unlink("video.avi");
});
});
@@ -69,12 +59,12 @@ describe(genName("setTimeout()"), () => {
beforeEach(reset);
it("should exist", () => {
- expect("setTimeout" in ffmpeg).to.be.true;
+ expect("setTimeout" in core).to.be.true;
});
it("should timeout", () => {
- ffmpeg.setTimeout(1); // timeout after 1ms
- expect(ffmpeg.exec("-i", "video.mp4", "video.avi")).to.equal(1);
+ core.setTimeout(1); // timeout after 1ms
+ expect(core.exec("-i", "video.mp4", "video.avi")).to.equal(1);
});
});
@@ -82,13 +72,13 @@ describe(genName("setLogger()"), () => {
beforeEach(reset);
it("should exist", () => {
- expect("setLogger" in ffmpeg).to.be.true;
+ expect("setLogger" in core).to.be.true;
});
it("should handle logs", () => {
const logs = [];
- ffmpeg.setLogger(({ message }) => logs.push(message));
- ffmpeg.exec("-h");
+ core.setLogger(({ message }) => logs.push(message));
+ core.exec("-h");
expect(logs.length).to.not.equal(0);
});
});
@@ -97,14 +87,14 @@ describe(genName("setProgress()"), () => {
beforeEach(reset);
it("should exist", () => {
- expect("setProgress" in ffmpeg).to.be.true;
+ expect("setProgress" in core).to.be.true;
});
it("should handle progress", () => {
let progress = 0;
- ffmpeg.setProgress((_progress) => (progress = _progress));
- expect(ffmpeg.exec("-i", "video.mp4", "video.avi")).to.equal(0);
+ core.setProgress((_progress) => (progress = _progress));
+ expect(core.exec("-i", "video.mp4", "video.avi")).to.equal(0);
expect(progress).to.equal(1);
- ffmpeg.FS.unlink("video.avi");
+ core.FS.unlink("video.avi");
});
});
diff --git a/tests/ffmpeg-mt.test.html b/tests/ffmpeg-mt.test.html
new file mode 100644
index 0000000..0d9c473
--- /dev/null
+++ b/tests/ffmpeg-mt.test.html
@@ -0,0 +1,25 @@
+
+
+
+
+ FFmpeg Unit Test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/ffmpeg-st.test.html b/tests/ffmpeg-st.test.html
new file mode 100644
index 0000000..bddf59c
--- /dev/null
+++ b/tests/ffmpeg-st.test.html
@@ -0,0 +1,25 @@
+
+
+
+
+ FFmpeg Unit Test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/ffmpeg.test.js b/tests/ffmpeg.test.js
new file mode 100644
index 0000000..01c9643
--- /dev/null
+++ b/tests/ffmpeg.test.js
@@ -0,0 +1,171 @@
+const { FFmpeg } = FFmpegWASM;
+
+const genName = (name) => `[ffmpeg][${FFMPEG_TYPE}] ${name}`;
+
+const createFFmpeg = async () => {
+ const ffmpeg = new FFmpeg();
+ await ffmpeg.load({
+ coreURL: CORE_URL,
+ thread: FFMPEG_TYPE === "mt",
+ });
+ return ffmpeg;
+};
+
+describe(genName("new FFmpeg()"), () => {
+ it("should be OK", () => {
+ expect(new FFmpeg()).to.be.ok;
+ });
+});
+
+describe(genName("FFmpeg.load()"), function () {
+ // it("should work without any args", async () => {
+ // const ffmpeg = new FFmpeg();
+ // await ffmpeg.load();
+ // expect(ffmpeg).to.be.ok;
+ // });
+
+ it("should work when blob is false", async () => {
+ const ffmpeg = new FFmpeg();
+ await ffmpeg.load({
+ coreURL: CORE_URL,
+ blob: false,
+ thread: FFMPEG_TYPE === "mt",
+ });
+ expect(ffmpeg).to.be.ok;
+ ffmpeg.terminate();
+ });
+
+ it("should receive download progress events", async () => {
+ const ffmpeg = new FFmpeg();
+ let done = false;
+ ffmpeg.on(FFmpeg.DOWNLOAD, ({ done: _done }) => {
+ done = _done;
+ });
+ await ffmpeg.load({
+ coreURL: CORE_URL,
+ thread: FFMPEG_TYPE === "mt",
+ });
+ expect(done).to.be.true;
+ ffmpeg.terminate();
+ });
+});
+
+describe(
+ genName(
+ "FFmpeg directory APIs (createDir(), listDir(), deleteDir(), rename())"
+ ),
+ function () {
+ let ffmpeg;
+
+ before(async () => {
+ ffmpeg = await createFFmpeg();
+ });
+
+ after(() => {
+ ffmpeg.terminate();
+ });
+
+ it("should list root dir", async () => {
+ const files = await ffmpeg.listDir("/");
+ expect(files).to.have.lengthOf(6);
+ });
+
+ it("should create a dir", async () => {
+ await ffmpeg.createDir("/dir1");
+ const files = await ffmpeg.listDir("/");
+ expect(files).to.include("dir1");
+ });
+
+ it("should delete a dir", async () => {
+ await ffmpeg.createDir("/dir2");
+ await ffmpeg.deleteDir("/dir2");
+ const files = await ffmpeg.listDir("/");
+ expect(files).to.not.include("dir2");
+ });
+
+ it("should rename a dir", async () => {
+ await ffmpeg.createDir("/dir3");
+ await ffmpeg.rename("/dir3", "/dir4");
+ const files = await ffmpeg.listDir("/");
+ expect(files).to.not.include("dir3");
+ expect(files).to.include("dir4");
+ });
+ }
+);
+
+describe(
+ genName(
+ "FFmpeg files APIs (readFile(), writeFile(), deleteFile(), rename())"
+ ),
+ function () {
+ let ffmpeg;
+
+ before(async () => {
+ ffmpeg = await createFFmpeg();
+ });
+
+ after(() => {
+ ffmpeg.terminate();
+ });
+
+ it("should write/read a text file", async () => {
+ const text = "foo";
+ await ffmpeg.writeFile("/file1", text);
+ const data = await ffmpeg.readFile("/file1", "utf8");
+ const files = await ffmpeg.listDir("/");
+ expect(files).to.include("file1");
+ expect(data).to.equal(text);
+ });
+
+ it("should write a binary file", async () => {
+ const bin = [1, 2, 3];
+ await ffmpeg.writeFile("/file2", Uint8Array.from(bin));
+ const data = await ffmpeg.readFile("/file2");
+ const files = await ffmpeg.listDir("/");
+ expect(files).to.include("file2");
+ expect(data).to.deep.equal(Uint8Array.from(bin));
+ });
+ }
+);
+
+describe(genName("FFmpeg.exec()"), function () {
+ let ffmpeg;
+
+ before(async () => {
+ ffmpeg = await createFFmpeg();
+ await ffmpeg.writeFile("video.mp4", b64ToUint8Array(VIDEO_1S_MP4));
+ });
+
+ after(() => {
+ ffmpeg.terminate();
+ });
+
+ it("should output help with exit code 0", async () => {
+ let m;
+ const listener = ({ message }) => {
+ m = message;
+ };
+ ffmpeg.on(FFmpeg.LOG, listener);
+ const ret = await ffmpeg.exec(["-h"]);
+ expect(ret).to.equal(0);
+ expect(m).to.be.a("string");
+ ffmpeg.removeListener(FFmpeg.LOG, listener);
+ });
+
+ it("should transcode mp4 to avi", async () => {
+ let p;
+ const listener = ({ progress }) => {
+ p = progress;
+ };
+ ffmpeg.on(FFmpeg.PROGRESS, listener);
+ const ret = await ffmpeg.exec(["-i", "video.mp4", "video.avi"]);
+ expect(ret).to.equal(0);
+ expect(p).to.equal(1);
+ ffmpeg.removeListener(FFmpeg.PROGRESS, listener);
+ });
+
+ it("should stop if timeout", async () => {
+ const ret = await ffmpeg.exec(["-i", "video.mp4", "video.avi"], 1);
+ expect(ret).to.equal(1);
+ });
+});
diff --git a/tests/constants.js b/tests/test-helper-browser.js
similarity index 95%
rename from tests/constants.js
rename to tests/test-helper-browser.js
index 46a3ce5..1f1aedd 100644
--- a/tests/constants.js
+++ b/tests/test-helper-browser.js
@@ -1,7 +1,19 @@
const VIDEO_1S_MP4 =
"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";
+
+const b64ToUint8Array = (b64) => {
+ const bin = atob(b64);
+ const len = bin.length;
+ const bytes = new Uint8Array(len);
+ for (let i = 0; i < len; i++) {
+ bytes[i] = bin.charCodeAt(i);
+ }
+ return bytes;
+};
+
if (typeof module !== "undefined") {
module.exports = {
VIDEO_1S_MP4,
+ b64ToUint8Array,
};
}
diff --git a/tests/test-helper-mt.js b/tests/test-helper-mt.js
index ba4f1ba..bdefd9d 100644
--- a/tests/test-helper-mt.js
+++ b/tests/test-helper-mt.js
@@ -1,11 +1,11 @@
const chai = require("chai");
-const constants = require("./constants");
+const browser = require("./test-helper-browser");
global.expect = chai.expect;
global.createFFmpegCore = require("../packages/core-mt");
global.atob = require("./util").atob;
global.FFMPEG_TYPE = "mt";
-Object.keys(constants).forEach((key) => {
- global[key] = constants[key];
+Object.keys(browser).forEach((key) => {
+ global[key] = browser[key];
});
diff --git a/tests/test-helper-st.js b/tests/test-helper-st.js
index 26c98af..859a43c 100644
--- a/tests/test-helper-st.js
+++ b/tests/test-helper-st.js
@@ -1,11 +1,11 @@
const chai = require("chai");
-const constants = require("./constants");
+const browser = require("./test-helper-browser");
global.expect = chai.expect;
global.createFFmpegCore = require("../packages/core");
global.atob = require("./util").atob;
global.FFMPEG_TYPE = "st";
-Object.keys(constants).forEach((key) => {
- global[key] = constants[key];
+Object.keys(browser).forEach((key) => {
+ global[key] = browser[key];
});