diff --git a/.eslintrc.js b/.eslintrc.js index df44d24e580..6110795d319 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -469,7 +469,7 @@ module.exports = { }, { files: ['packages/@uppy/*/src/**/*.ts', 'packages/@uppy/*/src/**/*.tsx'], - excludedFiles: ['packages/@uppy/**/*.test.ts'], + excludedFiles: ['packages/@uppy/**/*.test.ts', 'packages/@uppy/core/src/mocks/*.ts'], rules: { '@typescript-eslint/explicit-function-return-type': 'error', }, diff --git a/package.json b/package.json index 2b3b52a5a57..6d7b459eb38 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "test:locale-packs": "yarn locale-packs:unused && yarn locale-packs:warnings", "test:locale-packs:unused": "yarn workspace @uppy-dev/locale-pack test unused", "test:locale-packs:warnings": "yarn workspace @uppy-dev/locale-pack test warnings", - "test:unit": "yarn run build:lib && yarn test:watch", + "test:unit": "yarn run build:lib && yarn test:watch --run", "test:watch": "vitest --environment jsdom --dir packages/@uppy", "test": "npm-run-all lint test:locale-packs:unused test:unit test:type test:companion", "uploadcdn": "yarn node ./bin/upload-to-cdn.js", diff --git a/packages/@uppy/companion-client/src/RequestClient.js b/packages/@uppy/companion-client/src/RequestClient.js index ffaac2fd280..972315b8efd 100644 --- a/packages/@uppy/companion-client/src/RequestClient.js +++ b/packages/@uppy/companion-client/src/RequestClient.js @@ -55,9 +55,6 @@ async function handleJSONResponse (res) { throw new HttpError({ statusCode: res.status, message: errMsg }) } -// todo pull out into core instead? -const allowedHeadersCache = new Map() - export default class RequestClient { static VERSION = packageJson.version @@ -84,11 +81,13 @@ export default class RequestClient { return stripSlash(companion && companion[host] ? companion[host] : host) } - async headers () { + async headers (emptyBody = false) { const defaultHeaders = { Accept: 'application/json', - 'Content-Type': 'application/json', - 'Uppy-Versions': `@uppy/companion-client=${RequestClient.VERSION}`, + ...(emptyBody ? undefined : { + // Passing those headers on requests with no data forces browsers to first make a preflight request. + 'Content-Type': 'application/json', + }), } return { @@ -117,88 +116,10 @@ export default class RequestClient { return `${this.hostname}/${url}` } - /* - Preflight was added to avoid breaking change between older Companion-client versions and - newer Companion versions and vice-versa. Usually the break will manifest via CORS errors because a - version of companion-client could be sending certain headers to a version of Companion server that - does not support those headers. In which case, the default preflight would lead to CORS. - So to avoid those errors, we do preflight ourselves, to see what headers the Companion server - we are communicating with allows. And based on that, companion-client knows what headers to - send and what headers to not send. - - The preflight only happens once throughout the life-cycle of a certain - Companion-client <-> Companion-server pair (allowedHeadersCache). - Subsequent requests use the cached result of the preflight. - However if there is an error retrieving the allowed headers, we will try again next time - */ - async preflight (path) { - const allowedHeadersCached = allowedHeadersCache.get(this.hostname) - if (allowedHeadersCached != null) return allowedHeadersCached - - const fallbackAllowedHeaders = [ - 'accept', - 'content-type', - 'uppy-auth-token', - ] - - const promise = (async () => { - try { - const response = await fetch(this.#getUrl(path), { method: 'OPTIONS' }) - - const header = response.headers.get('access-control-allow-headers') - if (header == null || header === '*') { - allowedHeadersCache.set(this.hostname, fallbackAllowedHeaders) - return fallbackAllowedHeaders - } - - this.uppy.log( - `[CompanionClient] adding allowed preflight headers to companion cache: ${this.hostname} ${header}`, - ) - - const allowedHeaders = header - .split(',') - .map((headerName) => headerName.trim().toLowerCase()) - allowedHeadersCache.set(this.hostname, allowedHeaders) - return allowedHeaders - } catch (err) { - this.uppy.log( - `[CompanionClient] unable to make preflight request ${err}`, - 'warning', - ) - // If the user gets a network error or similar, we should try preflight - // again next time, or else we might get incorrect behaviour. - allowedHeadersCache.delete(this.hostname) // re-fetch next time - return fallbackAllowedHeaders - } - })() - - allowedHeadersCache.set(this.hostname, promise) - return promise - } - - async preflightAndHeaders (path) { - const [allowedHeaders, headers] = await Promise.all([ - this.preflight(path), - this.headers(), - ]) - // filter to keep only allowed Headers - return Object.fromEntries( - Object.entries(headers).filter(([header]) => { - if (!allowedHeaders.includes(header.toLowerCase())) { - this.uppy.log( - `[CompanionClient] excluding disallowed header ${header}`, - ) - return false - } - return true - }), - ) - } - /** @protected */ async request ({ path, method = 'GET', data, skipPostResponse, signal }) { try { - const headers = await this.preflightAndHeaders(path) + const headers = await this.headers(!data) const response = await fetchWithNetworkError(this.#getUrl(path), { method, signal, @@ -280,7 +201,7 @@ export default class RequestClient { || (err.statusCode >= 500 && err.statusCode <= 599 && ![501, 505].includes(err.statusCode)) ) if (err instanceof HttpError && !isRetryableHttpError()) throw new AbortError(err); - + // p-retry will retry most other errors, // but it will not retry TypeError (except network error TypeErrors) throw err @@ -359,7 +280,7 @@ export default class RequestClient { socket.send(JSON.stringify({ action, payload: payload ?? {}, - })) + })) }; function sendState() { @@ -379,7 +300,7 @@ export default class RequestClient { socketAbortController?.abort?.() reject(err) } - + // todo instead implement the ability for users to cancel / retry *currently uploading files* in the UI function resetActivityTimeout() { clearTimeout(activityTimeout) @@ -414,7 +335,7 @@ export default class RequestClient { try { const { action, payload } = JSON.parse(e.data) - + switch (action) { case 'progress': { emitSocketProgress(this, payload, file) @@ -430,8 +351,8 @@ export default class RequestClient { const { message } = payload.error throw Object.assign(new Error(message), { cause: payload.error }) } - default: - this.uppy.log(`Companion socket unknown action ${action}`, 'warning') + default: + this.uppy.log(`Companion socket unknown action ${action}`, 'warning') } } catch (err) { onFatalError(err) @@ -444,7 +365,7 @@ export default class RequestClient { if (socket) socket.close() socket = undefined } - + socketAbortController.signal.addEventListener('abort', () => { closeSocket() }) diff --git a/packages/@uppy/companion/package.json b/packages/@uppy/companion/package.json index 3b39dd146c6..8e28728c101 100644 --- a/packages/@uppy/companion/package.json +++ b/packages/@uppy/companion/package.json @@ -63,7 +63,6 @@ "node-schedule": "2.1.0", "prom-client": "14.0.1", "redis": "4.2.0", - "semver": "7.5.3", "serialize-error": "^2.1.0", "serialize-javascript": "^6.0.0", "tus-js-client": "^3.0.0", diff --git a/packages/@uppy/companion/src/config/companion.js b/packages/@uppy/companion/src/config/companion.js index 59c4f0c9916..4ad236f76ae 100644 --- a/packages/@uppy/companion/src/config/companion.js +++ b/packages/@uppy/companion/src/config/companion.js @@ -18,7 +18,6 @@ const defaultOptions = { }, enableUrlEndpoint: true, // todo next major make this default false allowLocalUrls: false, - logClientVersion: true, periodicPingUrls: [], streamingUpload: false, clientSocketConnectTimeout: 60000, diff --git a/packages/@uppy/companion/src/server/controllers/connect.js b/packages/@uppy/companion/src/server/controllers/connect.js index 1e98927744c..7e8f9b8e5dd 100644 --- a/packages/@uppy/companion/src/server/controllers/connect.js +++ b/packages/@uppy/companion/src/server/controllers/connect.js @@ -19,10 +19,6 @@ module.exports = function connect (req, res) { state = oAuthState.addToState(state, { companionInstance: req.companion.buildURL('', true) }, secret) } - if (req.companion.clientVersion) { - state = oAuthState.addToState(state, { clientVersion: req.companion.clientVersion }, secret) - } - if (req.query.uppyPreAuthToken) { state = oAuthState.addToState(state, { preAuthToken: req.query.uppyPreAuthToken }, secret) } diff --git a/packages/@uppy/companion/src/server/helpers/version.js b/packages/@uppy/companion/src/server/helpers/version.js deleted file mode 100644 index f2b0dc2bb20..00000000000 --- a/packages/@uppy/companion/src/server/helpers/version.js +++ /dev/null @@ -1,15 +0,0 @@ -const semver = require('semver') - -/** - * checks if a version is greater than or equal to - * - * @param {string} v1 the LHS version - * @param {string} v2 the RHS version - * @returns {boolean} - */ -exports.gte = (v1, v2) => { - return semver.gte( - semver.coerce(v1).version, - semver.coerce(v2).version, - ) -} diff --git a/packages/@uppy/companion/src/server/middlewares.js b/packages/@uppy/companion/src/server/middlewares.js index c344ff1602c..7c9cf93cc1a 100644 --- a/packages/@uppy/companion/src/server/middlewares.js +++ b/packages/@uppy/companion/src/server/middlewares.js @@ -123,13 +123,13 @@ exports.cors = (options = {}) => (req, res, next) => { const exposeHeadersSet = new Set(existingExposeHeaders?.split(',')?.map((method) => method.trim().toLowerCase())) // exposed so it can be accessed for our custom uppy client preflight - exposeHeadersSet.add('access-control-allow-headers') + exposeHeadersSet.add('access-control-allow-headers') // todo remove in next major, see https://github.com/transloadit/uppy/pull/4462 if (options.sendSelfEndpoint) exposeHeadersSet.add('i-am') // Needed for basic operation: https://github.com/transloadit/uppy/issues/3021 const allowedHeaders = [ 'uppy-auth-token', - 'uppy-versions', + 'uppy-versions', // todo remove in the future? see https://github.com/transloadit/uppy/pull/4462 'uppy-credentials-params', 'authorization', 'origin', @@ -191,18 +191,12 @@ exports.getCompanionMiddleware = (options) => { * @param {Function} next */ const middleware = (req, res, next) => { - const versionFromQuery = req.query.uppyVersions ? decodeURIComponent(req.query.uppyVersions) : null req.companion = { options, s3Client: getS3Client(options), authToken: req.header('uppy-auth-token') || req.query.uppyAuthToken, - clientVersion: req.header('uppy-versions') || versionFromQuery || '1.0.0', buildURL: getURLBuilder(options), } - - if (options.logClientVersion) { - logger.info(`uppy client version ${req.companion.clientVersion}`, 'companion.client.version') - } next() } diff --git a/packages/@uppy/companion/test/__tests__/callback.js b/packages/@uppy/companion/test/__tests__/callback.js index 4eee609aa10..2ab5a689794 100644 --- a/packages/@uppy/companion/test/__tests__/callback.js +++ b/packages/@uppy/companion/test/__tests__/callback.js @@ -43,7 +43,7 @@ describe('test authentication callback', () => { test('the token gets sent via html', () => { // see mock ../../src/server/helpers/oauth-state above for state values return request(authServer) - .get(`/dropbox/send-token?uppyAuthToken=${token}&state=state-with-newer-version`) + .get(`/dropbox/send-token?uppyAuthToken=${token}`) .expect(200) .expect((res) => { const body = ` diff --git a/packages/@uppy/companion/test/mockoauthstate.js b/packages/@uppy/companion/test/mockoauthstate.js index 63fe9d8b83e..8a7db59057b 100644 --- a/packages/@uppy/companion/test/mockoauthstate.js +++ b/packages/@uppy/companion/test/mockoauthstate.js @@ -2,23 +2,11 @@ module.exports = () => { return { generateState: () => 'some-cool-nice-encrytpion', addToState: () => 'some-cool-nice-encrytpion', - getFromState: (state, key) => { + getFromState: (state) => { if (state === 'state-with-invalid-instance-url') { return 'http://localhost:3452' } - if (state === 'state-with-older-version' && key === 'clientVersion') { - return '@uppy/companion-client=1.0.1' - } - - if (state === 'state-with-newer-version' && key === 'clientVersion') { - return '@uppy/companion-client=1.0.3' - } - - if (state === 'state-with-newer-version-old-style' && key === 'clientVersion') { - return 'companion-client:1.0.2' - } - return 'http://localhost:3020' }, } diff --git a/packages/@uppy/core/src/Restricter.ts b/packages/@uppy/core/src/Restricter.ts index 07eafd64458..3d75cd741b0 100644 --- a/packages/@uppy/core/src/Restricter.ts +++ b/packages/@uppy/core/src/Restricter.ts @@ -1,7 +1,5 @@ /* eslint-disable max-classes-per-file, class-methods-use-this */ -// @ts-expect-error untyped import prettierBytes from '@transloadit/prettier-bytes' -// @ts-expect-error untyped import match from 'mime-match' import Translator from '@uppy/utils/lib/Translator' import type { Body, Meta, UppyFile } from '@uppy/utils/lib/UppyFile' diff --git a/packages/@uppy/core/src/UIPlugin.ts b/packages/@uppy/core/src/UIPlugin.ts index d7f0a5fe44c..338d8ecfc38 100644 --- a/packages/@uppy/core/src/UIPlugin.ts +++ b/packages/@uppy/core/src/UIPlugin.ts @@ -163,6 +163,7 @@ class UIPlugin< * This is the case with @uppy/react plugins, for example. */ render(state: Record): ComponentChild { + // eslint-disable-line @typescript-eslint/no-unused-vars throw new Error( 'Extend the render method to add your plugin to a DOM element', ) diff --git a/packages/@uppy/core/src/Uppy.test.ts b/packages/@uppy/core/src/Uppy.test.ts index 85495f498e1..f9bbb6b0775 100644 --- a/packages/@uppy/core/src/Uppy.test.ts +++ b/packages/@uppy/core/src/Uppy.test.ts @@ -516,7 +516,7 @@ describe('src/Core', () => { describe('preprocessors', () => { it('should add and remove preprocessor', () => { const core = new Core() - const preprocessor = () => {} + const preprocessor = Function.prototype expect(core.removePreProcessor(preprocessor)).toBe(false) core.addPreProcessor(preprocessor) expect(core.removePreProcessor(preprocessor)).toBe(true) @@ -635,7 +635,7 @@ describe('src/Core', () => { describe('postprocessors', () => { it('should add and remove postprocessor', () => { const core = new Core() - const postprocessor = () => {} + const postprocessor = Function.prototype expect(core.removePostProcessor(postprocessor)).toBe(false) core.addPostProcessor(postprocessor) expect(core.removePostProcessor(postprocessor)).toBe(true) @@ -752,7 +752,7 @@ describe('src/Core', () => { describe('uploaders', () => { it('should add and remove uploader', () => { const core = new Core() - const uploader = () => {} + const uploader = Function.prototype expect(core.removeUploader(uploader)).toBe(false) core.addUploader(uploader) expect(core.removeUploader(uploader)).toBe(true) @@ -1326,9 +1326,9 @@ describe('src/Core', () => { }) describe('restoring a file', () => { - it.skip('should restore a file', () => {}) + it.skip('should restore a file') - it.skip("should fail to restore a file if it doesn't exist", () => {}) + it.skip("should fail to restore a file if it doesn't exist") }) describe('get a file', () => { @@ -1861,7 +1861,7 @@ describe('src/Core', () => { }).not.toThrowError() }) - it.skip('should enforce the minNumberOfFiles rule', () => {}) + it.skip('should enforce the minNumberOfFiles rule') it('should enforce the allowedFileTypes rule', () => { const core = new Core({ @@ -2291,6 +2291,8 @@ describe('src/Core', () => { data: new File([sampleImage], { type: 'image/jpeg' }), }) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore accessing private field core[Symbol.for('uppy test: createUpload')]( Object.keys(core.getState().files), ) @@ -2312,6 +2314,7 @@ describe('src/Core', () => { strings: { test: 'beep boop', }, + pluralize: () => 0, }, }) diff --git a/packages/@uppy/core/src/Uppy.ts b/packages/@uppy/core/src/Uppy.ts index 08a760ee33d..e5240327ddb 100644 --- a/packages/@uppy/core/src/Uppy.ts +++ b/packages/@uppy/core/src/Uppy.ts @@ -327,7 +327,7 @@ export class Uppy { // Exposing uppy object on window for debugging and testing if (this.opts.debug && typeof window !== 'undefined') { - // @ts-expect-error string as index type is fine + // @ts-expect-error fine window[this.opts.id] = this } @@ -807,11 +807,10 @@ export class Uppy { // If a file has been recovered (Golden Retriever), but we were unable to recover its data (probably too large), // users are asked to re-select these half-recovered files and then this method will be called again. - // In order to keep the progress, meta and everthing else, we keep the existing file, + // In order to keep the progress, meta and everything else, we keep the existing file, // but we replace `data`, and we remove `isGhost`, because the file is no longer a ghost now const isGhost = existingFiles[newFile.id]?.isGhost if (isGhost) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars const existingFileState = existingFiles[newFile.id] newFile = { ...existingFileState, @@ -1338,7 +1337,7 @@ export class Uppy { if (typeof error === 'object' && error.message) { this.log(error.message, 'error') const newError = new Error( - this.i18n('failedToUpload', { file: file?.name }), + this.i18n('failedToUpload', { file: file?.name ?? '' }), ) as any // we may want a new custom error here newError.isUserFacing = true // todo maybe don't do this with all errors? newError.details = error.message @@ -1624,7 +1623,9 @@ export class Uppy { return undefined } - [Symbol.for('uppy test: getPlugins')](type: string): UnknownPlugin[] { + private [Symbol.for('uppy test: getPlugins')]( + type: string, + ): UnknownPlugin[] { return this.#plugins[type] } @@ -1799,9 +1800,9 @@ export class Uppy { return uploadID } - // @ts-expect-error same type as createUpload - [Symbol.for('uppy test: createUpload')](...args): string { - // @ts-expect-error same type as createUpload + // @ts-expect-error same as createUpload + private [Symbol.for('uppy test: createUpload')](...args): string { + // @ts-expect-error https://github.com/microsoft/TypeScript/issues/47595 return this.#createUpload(...args) } diff --git a/packages/@uppy/core/src/locale.ts b/packages/@uppy/core/src/locale.ts index 16a18cf3a46..92674805d65 100644 --- a/packages/@uppy/core/src/locale.ts +++ b/packages/@uppy/core/src/locale.ts @@ -58,6 +58,7 @@ export default { 0: 'Added %{smart_count} file from %{folder}', 1: 'Added %{smart_count} files from %{folder}', }, - additionalRestrictionsFailed: '%{count} additional restrictions were not fulfilled', + additionalRestrictionsFailed: + '%{count} additional restrictions were not fulfilled', }, } diff --git a/packages/@uppy/core/src/mocks/acquirerPlugin1.ts b/packages/@uppy/core/src/mocks/acquirerPlugin1.ts index 5b08d2b1adf..5fc46ba2f36 100644 --- a/packages/@uppy/core/src/mocks/acquirerPlugin1.ts +++ b/packages/@uppy/core/src/mocks/acquirerPlugin1.ts @@ -1,8 +1,8 @@ import { vi } from 'vitest' // eslint-disable-line import/no-extraneous-dependencies import UIPlugin from '../UIPlugin.ts' -export default class TestSelector1 extends UIPlugin { - constructor (uppy, opts) { +export default class TestSelector1 extends UIPlugin { + constructor(uppy, opts) { super(uppy, opts) this.type = 'acquirer' this.id = 'TestSelector1' @@ -15,7 +15,7 @@ export default class TestSelector1 extends UIPlugin { } } - run (results) { + run(results) { this.uppy.log({ class: this.constructor.name, method: 'run', @@ -25,11 +25,11 @@ export default class TestSelector1 extends UIPlugin { return Promise.resolve('success') } - update (state) { + update(state) { this.mocks.update(state) } - uninstall () { + uninstall() { this.mocks.uninstall() } } diff --git a/packages/@uppy/core/src/mocks/acquirerPlugin2.ts b/packages/@uppy/core/src/mocks/acquirerPlugin2.ts index 42da1f378c9..15e499c0bd1 100644 --- a/packages/@uppy/core/src/mocks/acquirerPlugin2.ts +++ b/packages/@uppy/core/src/mocks/acquirerPlugin2.ts @@ -1,8 +1,8 @@ import { vi } from 'vitest' // eslint-disable-line import/no-extraneous-dependencies import UIPlugin from '../UIPlugin.ts' -export default class TestSelector2 extends UIPlugin { - constructor (uppy, opts) { +export default class TestSelector2 extends UIPlugin { + constructor(uppy, opts) { super(uppy, opts) this.type = 'acquirer' this.id = 'TestSelector2' @@ -15,7 +15,7 @@ export default class TestSelector2 extends UIPlugin { } } - run (results) { + run(results) { this.uppy.log({ class: this.constructor.name, method: 'run', @@ -25,11 +25,11 @@ export default class TestSelector2 extends UIPlugin { return Promise.resolve('success') } - update (state) { + update(state) { this.mocks.update(state) } - uninstall () { + uninstall() { this.mocks.uninstall() } } diff --git a/packages/@uppy/core/src/mocks/invalidPluginWithoutId.ts b/packages/@uppy/core/src/mocks/invalidPluginWithoutId.ts index 6d4fcf3dde8..93fe3e4cc74 100644 --- a/packages/@uppy/core/src/mocks/invalidPluginWithoutId.ts +++ b/packages/@uppy/core/src/mocks/invalidPluginWithoutId.ts @@ -1,13 +1,17 @@ import UIPlugin from '../UIPlugin.ts' -export default class InvalidPluginWithoutName extends UIPlugin { - constructor (uppy, opts) { +export default class InvalidPluginWithoutName extends UIPlugin { + public type: string + + public name: string + + constructor(uppy, opts) { super(uppy, opts) this.type = 'acquirer' this.name = this.constructor.name } - run (results) { + run(results) { this.uppy.log({ class: this.constructor.name, method: 'run', diff --git a/packages/@uppy/core/src/mocks/invalidPluginWithoutType.ts b/packages/@uppy/core/src/mocks/invalidPluginWithoutType.ts index 2a2cbfaa248..96ebad2c8cc 100644 --- a/packages/@uppy/core/src/mocks/invalidPluginWithoutType.ts +++ b/packages/@uppy/core/src/mocks/invalidPluginWithoutType.ts @@ -1,13 +1,17 @@ import UIPlugin from '../UIPlugin.ts' -export default class InvalidPluginWithoutType extends UIPlugin { - constructor (uppy, opts) { +export default class InvalidPluginWithoutType extends UIPlugin { + public id: string + + public name: string + + constructor(uppy, opts) { super(uppy, opts) this.id = 'InvalidPluginWithoutType' this.name = this.constructor.name } - run (results) { + run(results) { this.uppy.log({ class: this.constructor.name, method: 'run', diff --git a/packages/@uppy/core/src/supportsUploadProgress.test.ts b/packages/@uppy/core/src/supportsUploadProgress.test.ts index 9586f4ef239..6dc2f8f478c 100644 --- a/packages/@uppy/core/src/supportsUploadProgress.test.ts +++ b/packages/@uppy/core/src/supportsUploadProgress.test.ts @@ -4,26 +4,54 @@ import supportsUploadProgress from './supportsUploadProgress.ts' describe('supportsUploadProgress', () => { it('returns true in working browsers', () => { // Firefox 64 (dev edition) - expect(supportsUploadProgress('Mozilla/5.0 (X11; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0')).toBe(true) + expect( + supportsUploadProgress( + 'Mozilla/5.0 (X11; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0', + ), + ).toBe(true) // Chromium 70 - expect(supportsUploadProgress('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36')).toBe(true) + expect( + supportsUploadProgress( + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36', + ), + ).toBe(true) // IE 11 - expect(supportsUploadProgress('Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko')).toBe(true) + expect( + supportsUploadProgress( + 'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko', + ), + ).toBe(true) // MS Edge 14 - expect(supportsUploadProgress('Chrome (AppleWebKit/537.1; Chrome50.0; Windows NT 6.3) AppleWebKit/537.36 (KHTML like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393')).toBe(true) + expect( + supportsUploadProgress( + 'Chrome (AppleWebKit/537.1; Chrome50.0; Windows NT 6.3) AppleWebKit/537.36 (KHTML like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393', + ), + ).toBe(true) // MS Edge 18, supposedly fixed - expect(supportsUploadProgress('Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/18.18218')).toBe(true) + expect( + supportsUploadProgress( + 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/18.18218', + ), + ).toBe(true) }) it('returns false in broken browsers', () => { // MS Edge 15, first broken version - expect(supportsUploadProgress('Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063')).toBe(false) + expect( + supportsUploadProgress( + 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063', + ), + ).toBe(false) // MS Edge 17 - expect(supportsUploadProgress('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134')).toBe(false) + expect( + supportsUploadProgress( + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134', + ), + ).toBe(false) }) }) diff --git a/packages/@uppy/provider-views/src/ProviderView/ProviderView.jsx b/packages/@uppy/provider-views/src/ProviderView/ProviderView.jsx index 517854347c2..314ee6bd101 100644 --- a/packages/@uppy/provider-views/src/ProviderView/ProviderView.jsx +++ b/packages/@uppy/provider-views/src/ProviderView/ProviderView.jsx @@ -242,9 +242,8 @@ export default class ProviderView extends View { } async handleAuth () { - const clientVersion = `@uppy/provider-views=${ProviderView.VERSION}` try { - await this.provider.login({ uppyVersions: clientVersion }) + await this.provider.login() this.plugin.setPluginState({ authenticated: true }) this.preFirstRender() } catch (e) { diff --git a/packages/@uppy/utils/src/Translator.ts b/packages/@uppy/utils/src/Translator.ts index 7435559d9a4..f882f96726b 100644 --- a/packages/@uppy/utils/src/Translator.ts +++ b/packages/@uppy/utils/src/Translator.ts @@ -7,9 +7,7 @@ export interface Locale { } export type OptionalPluralizeLocale = - | (Omit, 'pluralize'> & { - pluralize?: (n: number) => T - }) + | (Omit, 'pluralize'> & Partial, 'pluralize'>>) | undefined // eslint-disable-next-line no-use-before-define @@ -18,7 +16,7 @@ export type I18n = Translator['translate'] type Options = { smart_count?: number } & { - [key: string]: string | number | undefined + [key: string]: string | number } function insertReplacement( diff --git a/packages/@uppy/utils/src/emitSocketProgress.ts b/packages/@uppy/utils/src/emitSocketProgress.ts index fa3c0a242ea..4b1e26e5f83 100644 --- a/packages/@uppy/utils/src/emitSocketProgress.ts +++ b/packages/@uppy/utils/src/emitSocketProgress.ts @@ -5,7 +5,7 @@ import type { FileProgress } from './FileProgress' function emitSocketProgress( uploader: any, progressData: FileProgress, - file: UppyFile, + file: UppyFile, ): void { const { progress, bytesUploaded, bytesTotal } = progressData if (progress) { diff --git a/packages/@uppy/utils/src/fileFilters.ts b/packages/@uppy/utils/src/fileFilters.ts index 4b12936aba7..cdd67a74890 100644 --- a/packages/@uppy/utils/src/fileFilters.ts +++ b/packages/@uppy/utils/src/fileFilters.ts @@ -1,13 +1,18 @@ import type { UppyFile } from './UppyFile' -export function filterNonFailedFiles(files: UppyFile[]): UppyFile[] { - const hasError = (file: UppyFile): boolean => 'error' in file && !!file.error +export function filterNonFailedFiles( + files: UppyFile[], +): UppyFile[] { + const hasError = (file: UppyFile): boolean => + 'error' in file && !!file.error return files.filter((file) => !hasError(file)) } // Don't double-emit upload-started for Golden Retriever-restored files that were already started -export function filterFilesToEmitUploadStarted(files: UppyFile[]): UppyFile[] { +export function filterFilesToEmitUploadStarted( + files: UppyFile[], +): UppyFile[] { return files.filter( (file) => !file.progress?.uploadStarted || !file.isRestored, ) diff --git a/packages/@uppy/utils/src/findDOMElement.ts b/packages/@uppy/utils/src/findDOMElement.ts index 258153694fa..5282c61b44b 100644 --- a/packages/@uppy/utils/src/findDOMElement.ts +++ b/packages/@uppy/utils/src/findDOMElement.ts @@ -4,9 +4,9 @@ import isDOMElement from './isDOMElement.ts' * Find a DOM element. */ export default function findDOMElement( - element: HTMLElement | string, + element: Node | string, context = document, -): HTMLElement | null { +): Element | null { if (typeof element === 'string') { return context.querySelector(element) } diff --git a/packages/@uppy/utils/src/generateFileID.ts b/packages/@uppy/utils/src/generateFileID.ts index 17f3867fd97..aa41667e7dc 100644 --- a/packages/@uppy/utils/src/generateFileID.ts +++ b/packages/@uppy/utils/src/generateFileID.ts @@ -19,7 +19,7 @@ function encodeFilename(name: string): string { * Takes a file object and turns it into fileID, by converting file.name to lowercase, * removing extra characters and adding type, size and lastModified */ -export default function generateFileID(file: UppyFile): string { +export default function generateFileID(file: UppyFile): string { // It's tempting to do `[items].filter(Boolean).join('-')` here, but that // is slower! simple string concatenation is fast @@ -48,7 +48,7 @@ export default function generateFileID(file: UppyFile): string { // If the provider has a stable, unique ID, then we can use that to identify the file. // Then we don't have to generate our own ID, and we can add the same file many times if needed (different path) -function hasFileStableId(file: UppyFile): boolean { +function hasFileStableId(file: UppyFile): boolean { if (!file.isRemote || !file.remote) return false // These are the providers that it seems like have stable IDs for their files. The other's I haven't checked yet. const stableIdProviders = new Set([ @@ -61,7 +61,7 @@ function hasFileStableId(file: UppyFile): boolean { return stableIdProviders.has(file.remote.provider as any) } -export function getSafeFileId(file: UppyFile): string { +export function getSafeFileId(file: UppyFile): string { if (hasFileStableId(file)) return file.id const fileType = getFileType(file) diff --git a/packages/@uppy/utils/src/getFileType.test.ts b/packages/@uppy/utils/src/getFileType.test.ts index aa0175bccd8..2316961b218 100644 --- a/packages/@uppy/utils/src/getFileType.test.ts +++ b/packages/@uppy/utils/src/getFileType.test.ts @@ -8,7 +8,7 @@ describe('getFileType', () => { isRemote: true, type: 'audio/webm', name: 'foo.webm', - } as any as UppyFile + } as any as UppyFile expect(getFileType(file)).toEqual('audio/webm') }) @@ -17,7 +17,7 @@ describe('getFileType', () => { type: 'audio/webm', name: 'foo.webm', data: 'sdfsdfhq9efbicw', - } as any as UppyFile + } as any as UppyFile expect(getFileType(file)).toEqual('audio/webm') }) @@ -25,24 +25,24 @@ describe('getFileType', () => { const fileMP3 = { name: 'foo.mp3', data: 'sdfsfhfh329fhwihs', - } as any as UppyFile + } as any as UppyFile const fileYAML = { name: 'bar.yaml', data: 'sdfsfhfh329fhwihs', - } as any as UppyFile + } as any as UppyFile const fileMKV = { name: 'bar.mkv', data: 'sdfsfhfh329fhwihs', - } as any as UppyFile + } as any as UppyFile const fileDicom = { name: 'bar.dicom', data: 'sdfsfhfh329fhwihs', - } as any as UppyFile + } as any as UppyFile const fileWebp = { name: 'bar.webp', data: 'sdfsfhfh329fhwihs', - } as any as UppyFile - const toUpper = (file: UppyFile) => ({ + } as any as UppyFile + const toUpper = (file: UppyFile) => ({ ...file, name: file.name.toUpperCase(), }) @@ -62,7 +62,7 @@ describe('getFileType', () => { const file = { name: 'foobar', data: 'sdfsfhfh329fhwihs', - } as any as UppyFile + } as any as UppyFile expect(getFileType(file)).toEqual('application/octet-stream') }) }) diff --git a/private/js2ts/index.mjs b/private/js2ts/index.mjs index 1acb74ab3e3..92f10c63e1a 100755 --- a/private/js2ts/index.mjs +++ b/private/js2ts/index.mjs @@ -7,7 +7,7 @@ import { opendir, readFile, open, writeFile, rm } from 'node:fs/promises' import { argv } from 'node:process' -import { extname } from 'node:path' +import { basename, extname, join } from 'node:path' import { existsSync } from 'node:fs' const packageRoot = new URL(`../../packages/${argv[2]}/`, import.meta.url) @@ -58,12 +58,16 @@ try { for await (const dirent of dir) { if (!dirent.isDirectory()) { - const { path: filepath } = dirent - const ext = extname(filepath) + const { name } = dirent + const ext = extname(name) if (ext !== '.js' && ext !== '.jsx') continue // eslint-disable-line no-continue + const filePath = + basename(dirent.path) === name + ? dirent.path // Some versions of Node.js give the full path as dirent.path. + : join(dirent.path, name) // Others supply only the path to the parent. await writeFile( - filepath.slice(0, -ext.length) + ext.replace('js', 'ts'), - (await readFile(filepath, 'utf-8')) + `${filePath.slice(0, -ext.length)}${ext.replace('js', 'ts')}`, + (await readFile(filePath, 'utf-8')) .replace( // The following regex aims to capture all imports and reexports of local .js(x) files to replace it to .ts(x) // It's far from perfect and will have false positives and false negatives. @@ -78,7 +82,7 @@ for await (const dirent of dir) { `// @ts-ignore We don't want TS to generate types for the package.json${originalImport}`, ), ) - await rm(filepath) + await rm(filePath) } } diff --git a/yarn.lock b/yarn.lock index 9c4cf782bc4..66bb7bd31be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9332,7 +9332,6 @@ __metadata: node-schedule: 2.1.0 prom-client: 14.0.1 redis: 4.2.0 - semver: 7.5.3 serialize-error: ^2.1.0 serialize-javascript: ^6.0.0 supertest: 6.2.4