Merge pull request #2889 from code-asher/remove-fs-extra
This commit is contained in:
commit
95a0740ca1
@ -25,7 +25,7 @@
|
|||||||
"_____": "",
|
"_____": "",
|
||||||
"fmt": "./ci/dev/fmt.sh",
|
"fmt": "./ci/dev/fmt.sh",
|
||||||
"lint": "./ci/dev/lint.sh",
|
"lint": "./ci/dev/lint.sh",
|
||||||
"test": "./ci/dev/test.sh",
|
"test": "echo 'Run yarn test:unit or yarn test:e2e' && exit 1",
|
||||||
"ci": "./ci/dev/ci.sh",
|
"ci": "./ci/dev/ci.sh",
|
||||||
"watch": "VSCODE_IPC_HOOK_CLI= NODE_OPTIONS=--max_old_space_size=32384 ts-node ./ci/dev/watch.ts",
|
"watch": "VSCODE_IPC_HOOK_CLI= NODE_OPTIONS=--max_old_space_size=32384 ts-node ./ci/dev/watch.ts",
|
||||||
"icons": "./ci/dev/gen_icons.sh",
|
"icons": "./ci/dev/gen_icons.sh",
|
||||||
@ -38,7 +38,6 @@
|
|||||||
"@types/compression": "^1.7.0",
|
"@types/compression": "^1.7.0",
|
||||||
"@types/cookie-parser": "^1.4.2",
|
"@types/cookie-parser": "^1.4.2",
|
||||||
"@types/express": "^4.17.8",
|
"@types/express": "^4.17.8",
|
||||||
"@types/fs-extra": "^8.0.1",
|
|
||||||
"@types/http-proxy": "^1.17.4",
|
"@types/http-proxy": "^1.17.4",
|
||||||
"@types/js-yaml": "^3.12.3",
|
"@types/js-yaml": "^3.12.3",
|
||||||
"@types/node": "^12.12.7",
|
"@types/node": "^12.12.7",
|
||||||
@ -84,7 +83,6 @@
|
|||||||
"cookie-parser": "^1.4.5",
|
"cookie-parser": "^1.4.5",
|
||||||
"env-paths": "^2.2.0",
|
"env-paths": "^2.2.0",
|
||||||
"express": "^5.0.0-alpha.8",
|
"express": "^5.0.0-alpha.8",
|
||||||
"fs-extra": "^9.0.1",
|
|
||||||
"http-proxy": "^1.18.0",
|
"http-proxy": "^1.18.0",
|
||||||
"httpolyglot": "^0.1.2",
|
"httpolyglot": "^0.1.2",
|
||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^3.13.1",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { field, Level, logger } from "@coder/logger"
|
import { field, Level, logger } from "@coder/logger"
|
||||||
import * as fs from "fs-extra"
|
import { promises as fs } from "fs"
|
||||||
import yaml from "js-yaml"
|
import yaml from "js-yaml"
|
||||||
import * as os from "os"
|
import * as os from "os"
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
@ -385,7 +385,6 @@ export async function setDefaults(cliArgs: Args, configArgs?: ConfigArgs): Promi
|
|||||||
const args = Object.assign({}, configArgs || {}, cliArgs)
|
const args = Object.assign({}, configArgs || {}, cliArgs)
|
||||||
|
|
||||||
if (!args["user-data-dir"]) {
|
if (!args["user-data-dir"]) {
|
||||||
await copyOldMacOSDataDir()
|
|
||||||
args["user-data-dir"] = paths.data
|
args["user-data-dir"] = paths.data
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,13 +509,22 @@ export async function readConfigFile(configPath?: string): Promise<ConfigArgs> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await fs.pathExists(configPath))) {
|
await fs.mkdir(path.dirname(configPath), { recursive: true })
|
||||||
await fs.outputFile(configPath, await defaultConfigFile())
|
|
||||||
|
try {
|
||||||
|
await fs.writeFile(configPath, await defaultConfigFile(), {
|
||||||
|
flag: "wx", // wx means to fail if the path exists.
|
||||||
|
})
|
||||||
logger.info(`Wrote default config file to ${humanPath(configPath)}`)
|
logger.info(`Wrote default config file to ${humanPath(configPath)}`)
|
||||||
|
} catch (error) {
|
||||||
|
// EEXIST is fine; we don't want to overwrite existing configurations.
|
||||||
|
if (error.code !== "EEXIST") {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const configFile = await fs.readFile(configPath)
|
const configFile = await fs.readFile(configPath, "utf8")
|
||||||
return parseConfigFile(configFile.toString(), configPath)
|
return parseConfigFile(configFile, configPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -599,21 +607,6 @@ function bindAddrFromAllSources(...argsConfig: Args[]): Addr {
|
|||||||
return addr
|
return addr
|
||||||
}
|
}
|
||||||
|
|
||||||
async function copyOldMacOSDataDir(): Promise<void> {
|
|
||||||
if (os.platform() !== "darwin") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (await fs.pathExists(paths.data)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the old data directory exists, we copy it in.
|
|
||||||
const oldDataDir = path.join(os.homedir(), "Library/Application Support", "code-server")
|
|
||||||
if (await fs.pathExists(oldDataDir)) {
|
|
||||||
await fs.copy(oldDataDir, paths.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const shouldRunVsCodeCli = (args: Args): boolean => {
|
export const shouldRunVsCodeCli = (args: Args): boolean => {
|
||||||
return !!args["list-extensions"] || !!args["install-extension"] || !!args["uninstall-extension"]
|
return !!args["list-extensions"] || !!args["install-extension"] || !!args["uninstall-extension"]
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { logger } from "@coder/logger"
|
import { logger } from "@coder/logger"
|
||||||
import { Query } from "express-serve-static-core"
|
import { Query } from "express-serve-static-core"
|
||||||
import * as fs from "fs-extra"
|
import { promises as fs } from "fs"
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
import { paths } from "./util"
|
import { paths } from "./util"
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import * as fs from "fs-extra"
|
import { promises as fs } from "fs"
|
||||||
import * as net from "net"
|
import * as net from "net"
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
import * as tls from "tls"
|
import * as tls from "tls"
|
||||||
@ -75,7 +75,7 @@ export class SocketProxyProvider {
|
|||||||
this._proxyServer = this.findFreeSocketPath(this.proxyPipe)
|
this._proxyServer = this.findFreeSocketPath(this.proxyPipe)
|
||||||
.then((pipe) => {
|
.then((pipe) => {
|
||||||
this.proxyPipe = pipe
|
this.proxyPipe = pipe
|
||||||
return Promise.all([fs.mkdirp(tmpdir), fs.remove(this.proxyPipe)])
|
return Promise.all([fs.mkdir(tmpdir, { recursive: true }), fs.rmdir(this.proxyPipe, { recursive: true })])
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as cp from "child_process"
|
import * as cp from "child_process"
|
||||||
import * as crypto from "crypto"
|
import * as crypto from "crypto"
|
||||||
import envPaths from "env-paths"
|
import envPaths from "env-paths"
|
||||||
import * as fs from "fs-extra"
|
import { promises as fs } from "fs"
|
||||||
import * as net from "net"
|
import * as net from "net"
|
||||||
import * as os from "os"
|
import * as os from "os"
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
@ -58,8 +58,11 @@ export const generateCertificate = async (hostname: string): Promise<{ cert: str
|
|||||||
const certPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.crt`)
|
const certPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.crt`)
|
||||||
const certKeyPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.key`)
|
const certKeyPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.key`)
|
||||||
|
|
||||||
const checks = await Promise.all([fs.pathExists(certPath), fs.pathExists(certKeyPath)])
|
// Try generating the certificates if we can't access them (which probably
|
||||||
if (!checks[0] || !checks[1]) {
|
// means they don't exist).
|
||||||
|
try {
|
||||||
|
await Promise.all([fs.access(certPath), fs.access(certKeyPath)])
|
||||||
|
} catch (error) {
|
||||||
// Require on demand so openssl isn't required if you aren't going to
|
// Require on demand so openssl isn't required if you aren't going to
|
||||||
// generate certificates.
|
// generate certificates.
|
||||||
const pem = require("pem") as typeof import("pem")
|
const pem = require("pem") as typeof import("pem")
|
||||||
@ -86,9 +89,10 @@ DNS.1 = ${hostname}
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
await fs.mkdirp(paths.data)
|
await fs.mkdir(paths.data, { recursive: true })
|
||||||
await Promise.all([fs.writeFile(certPath, certs.certificate), fs.writeFile(certKeyPath, certs.serviceKey)])
|
await Promise.all([fs.writeFile(certPath, certs.certificate), fs.writeFile(certKeyPath, certs.serviceKey)])
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cert: certPath,
|
cert: certPath,
|
||||||
certKey: certKeyPath,
|
certKey: certKeyPath,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Level, logger } from "@coder/logger"
|
import { Level, logger } from "@coder/logger"
|
||||||
import * as fs from "fs-extra"
|
import { promises as fs } from "fs"
|
||||||
import * as net from "net"
|
import * as net from "net"
|
||||||
import * as os from "os"
|
import * as os from "os"
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
@ -339,14 +339,14 @@ describe("cli", () => {
|
|||||||
const vscodeIpcPath = path.join(os.tmpdir(), "vscode-ipc")
|
const vscodeIpcPath = path.join(os.tmpdir(), "vscode-ipc")
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await fs.remove(testDir)
|
await fs.rmdir(testDir, { recursive: true })
|
||||||
await fs.mkdirp(testDir)
|
await fs.mkdir(testDir, { recursive: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
delete process.env.VSCODE_IPC_HOOK_CLI
|
delete process.env.VSCODE_IPC_HOOK_CLI
|
||||||
args = { _: [] }
|
args = { _: [] }
|
||||||
await fs.remove(vscodeIpcPath)
|
await fs.rmdir(vscodeIpcPath, { recursive: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should use existing if inside code-server", async () => {
|
it("should use existing if inside code-server", async () => {
|
||||||
@ -360,7 +360,7 @@ describe("cli", () => {
|
|||||||
|
|
||||||
it("should use existing if --reuse-window is set", async () => {
|
it("should use existing if --reuse-window is set", async () => {
|
||||||
args["reuse-window"] = true
|
args["reuse-window"] = true
|
||||||
await expect(await shouldOpenInExistingInstance(args)).toStrictEqual(undefined)
|
await expect(shouldOpenInExistingInstance(args)).resolves.toStrictEqual(undefined)
|
||||||
|
|
||||||
await fs.writeFile(vscodeIpcPath, "test")
|
await fs.writeFile(vscodeIpcPath, "test")
|
||||||
await expect(shouldOpenInExistingInstance(args)).resolves.toStrictEqual("test")
|
await expect(shouldOpenInExistingInstance(args)).resolves.toStrictEqual("test")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { field, logger } from "@coder/logger"
|
import { field, logger } from "@coder/logger"
|
||||||
import * as fs from "fs-extra"
|
import { promises as fs } from "fs"
|
||||||
import * as net from "net"
|
import * as net from "net"
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
import * as tls from "tls"
|
import * as tls from "tls"
|
||||||
@ -45,14 +45,14 @@ describe("SocketProxyProvider", () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const cert = await generateCertificate("localhost")
|
const cert = await generateCertificate("localhost")
|
||||||
const options = {
|
const options = {
|
||||||
cert: fs.readFileSync(cert.cert),
|
cert: await fs.readFile(cert.cert),
|
||||||
key: fs.readFileSync(cert.certKey),
|
key: await fs.readFile(cert.certKey),
|
||||||
rejectUnauthorized: false,
|
rejectUnauthorized: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.mkdirp(path.join(tmpdir, "tests"))
|
await fs.mkdir(path.join(tmpdir, "tests"), { recursive: true })
|
||||||
const socketPath = await provider.findFreeSocketPath(path.join(tmpdir, "tests/tls-socket-proxy"))
|
const socketPath = await provider.findFreeSocketPath(path.join(tmpdir, "tests/tls-socket-proxy"))
|
||||||
await fs.remove(socketPath)
|
await fs.rmdir(socketPath, { recursive: true })
|
||||||
|
|
||||||
return new Promise<void>((_resolve) => {
|
return new Promise<void>((_resolve) => {
|
||||||
const resolved: { [key: string]: boolean } = { client: false, server: false }
|
const resolved: { [key: string]: boolean } = { client: false, server: false }
|
||||||
@ -110,10 +110,10 @@ describe("SocketProxyProvider", () => {
|
|||||||
provider.stop() // We don't need more proxies.
|
provider.stop() // We don't need more proxies.
|
||||||
|
|
||||||
proxy.write("server proxy->client")
|
proxy.write("server proxy->client")
|
||||||
const dataFromServerToClient = await (await getData(fromServerToClient)).toString()
|
const dataFromServerToClient = (await getData(fromServerToClient)).toString()
|
||||||
expect(dataFromServerToClient).toBe("server proxy->client")
|
expect(dataFromServerToClient).toBe("server proxy->client")
|
||||||
client.write("client->server proxy")
|
client.write("client->server proxy")
|
||||||
const dataFromClientToProxy = await (await getData(fromClientToProxy)).toString()
|
const dataFromClientToProxy = (await getData(fromClientToProxy)).toString()
|
||||||
expect(dataFromClientToProxy).toBe("client->server proxy")
|
expect(dataFromClientToProxy).toBe("client->server proxy")
|
||||||
expect(errors).toEqual(0)
|
expect(errors).toEqual(0)
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import * as fs from "fs-extra"
|
import { promises as fs } from "fs"
|
||||||
import * as http from "http"
|
import * as http from "http"
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
import { SettingsProvider, UpdateSettings } from "../../src/node/settings"
|
import { SettingsProvider, UpdateSettings } from "../../src/node/settings"
|
||||||
@ -53,8 +53,8 @@ describe.skip("update", () => {
|
|||||||
host: "localhost",
|
host: "localhost",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
await fs.remove(path.join(tmpdir, "tests/updates"))
|
await fs.rmdir(path.join(tmpdir, "tests/updates"), { recursive: true })
|
||||||
await fs.mkdirp(path.join(tmpdir, "tests/updates"))
|
await fs.mkdir(path.join(tmpdir, "tests/updates"), { recursive: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
36
yarn.lock
36
yarn.lock
@ -1197,13 +1197,6 @@
|
|||||||
"@types/qs" "*"
|
"@types/qs" "*"
|
||||||
"@types/serve-static" "*"
|
"@types/serve-static" "*"
|
||||||
|
|
||||||
"@types/fs-extra@^8.0.1":
|
|
||||||
version "8.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.1.1.tgz#1e49f22d09aa46e19b51c0b013cb63d0d923a068"
|
|
||||||
integrity sha512-TcUlBem321DFQzBNuz8p0CLLKp0VvF/XH9E4KHNmgwyp4E3AfgI5cjiIVZWlbfThBop2qxFIh4+LeY6hVWWZ2w==
|
|
||||||
dependencies:
|
|
||||||
"@types/node" "*"
|
|
||||||
|
|
||||||
"@types/http-proxy@^1.17.4":
|
"@types/http-proxy@^1.17.4":
|
||||||
version "1.17.5"
|
version "1.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.5.tgz#c203c5e6e9dc6820d27a40eb1e511c70a220423d"
|
resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.5.tgz#c203c5e6e9dc6820d27a40eb1e511c70a220423d"
|
||||||
@ -1721,11 +1714,6 @@ asynckit@^0.4.0:
|
|||||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||||
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
||||||
|
|
||||||
at-least-node@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
|
|
||||||
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
|
|
||||||
|
|
||||||
atob@^2.1.2:
|
atob@^2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||||
@ -3726,16 +3714,6 @@ fs-extra@^8.1.0:
|
|||||||
jsonfile "^4.0.0"
|
jsonfile "^4.0.0"
|
||||||
universalify "^0.1.0"
|
universalify "^0.1.0"
|
||||||
|
|
||||||
fs-extra@^9.0.1:
|
|
||||||
version "9.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc"
|
|
||||||
integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==
|
|
||||||
dependencies:
|
|
||||||
at-least-node "^1.0.0"
|
|
||||||
graceful-fs "^4.2.0"
|
|
||||||
jsonfile "^6.0.1"
|
|
||||||
universalify "^1.0.0"
|
|
||||||
|
|
||||||
fs-minipass@^2.0.0:
|
fs-minipass@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
|
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
|
||||||
@ -4730,15 +4708,6 @@ jsonfile@^4.0.0:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
graceful-fs "^4.1.6"
|
graceful-fs "^4.1.6"
|
||||||
|
|
||||||
jsonfile@^6.0.1:
|
|
||||||
version "6.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179"
|
|
||||||
integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==
|
|
||||||
dependencies:
|
|
||||||
universalify "^1.0.0"
|
|
||||||
optionalDependencies:
|
|
||||||
graceful-fs "^4.1.6"
|
|
||||||
|
|
||||||
jsprim@^1.2.2:
|
jsprim@^1.2.2:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
||||||
@ -7980,11 +7949,6 @@ universalify@^0.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
||||||
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
|
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
|
||||||
|
|
||||||
universalify@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d"
|
|
||||||
integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==
|
|
||||||
|
|
||||||
unpipe@1.0.0, unpipe@~1.0.0:
|
unpipe@1.0.0, unpipe@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||||
|
Reference in New Issue
Block a user