Files
pnpm/store/server/src/createServer.ts
Brandon Cheng e9aa6f682a chore(deps): update TypeScript 5.1.6 -> 5.2.2 (#7016)
* test: use sha512 integrity in fixtures to fix ci break

* test: update snapshots for sha512 fixture change

* chore(deps): remove unneeded peer dependency exception

The `peerDependencyRules.allowedVersions` exception on
`@typescript-eslint/eslint-plugin` no longer seems to be necessary.
Removing it does not introduce any new peer dependency errors on
`pnpm install`.

I suspect this was needed for the
`eslint-config-standard-with-typescript` dependency in the past, but a
@typescript-eslint/eslint-plugin upgrade made it no longer necessary.

* chore(deps): update @typescript-eslint dependencies 5.62.0 -> 6.5.0

@typescript-eslint 6.5.0 is the first version to introduce support for
TypeScript 5.2.

https://github.com/typescript-eslint/typescript-eslint/releases/tag/v6.5.0

```
=============

WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.

You may find that it works just fine, or you may not.

SUPPORTED TYPESCRIPT VERSIONS: >=3.3.1 <5.2.0

YOUR TYPESCRIPT VERSION: 5.2.2

Please only submit bug reports when using the officially supported version.
```

* chore(deps): update eslint-config-standard-with-typescript 37.0.0 -> 39.0.0

Version 38.0.0 is the first version to support @typescript-eslint v6.
https://github.com/standard/eslint-config-standard-with-typescript/releases/tag/v38.0.0

Otherwise the following error appears.

```
> eslint "src/**/*.ts" "test/**/*.ts" "--fix"

Oops! Something went wrong! :(

ESLint: 8.47.0

Error: ../../.eslintrc.json » @pnpm/eslint-config » eslint-config-standard-with-typescript:
        Configuration for rule "@typescript-eslint/restrict-plus-operands" is invalid:
        Value {"checkCompoundAssignments":true} should NOT have additional properties.

    at ConfigValidator.validateRuleOptions (/Users/gluxon/Developer/pnpm/node_modules/.pnpm/@eslint+eslintrc@2.1.2/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2039:23)
    at /Users/gluxon/Developer/pnpm/node_modules/.pnpm/@eslint+eslintrc@2.1.2/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2094:18
```

* chore: remove unnecessary disables for restrict-template-expressions

The `@typescript-eslint/restrict-template-expressions` rule relaxed
what types are allowed in template expressions.

c13ce0b4f7 (diff-b852e1e199d2976eee1183fc84ac12a5d42fc61f0ae4b1c290dd54d621546db0)

Many of these disables were for interpolated values that had an `any`
type.

* chore: remove unnecessary disables for restrict-plus-operands

The original error was:

```
Invalid operand for a '+' operation. Operands must each be a number or string. Got `any`. eslint@typescript-eslint/restrict-plus-operands
```

It look like the newer version now allows `any`.

* style: fix errors of prefer-optional-chain and prefer-nullish-coalescing

The `@typescript-eslint/prefer-optional-chain` and
`@typescript-eslint/prefer-nullish-coalescing` rules got a bit
smarter. This commit applies autofixes. I believe the changes should be
equivalent to what existed before.

Example of the new `@typescript-eslint/prefer-optional-chain` lints.

```
pnpm/pkg-manifest/exportable-manifest/src/index.ts
  71:10  error  Prefer using an optional chain expression instead, as it's more concise and easier to read  @typescript-eslint/prefer-optional-chain
  87:10  error  Prefer using an optional chain expression instead, as it's more concise and easier to read  @typescript-eslint/prefer-optional-chain
```

Example of the new `@typescript-eslint/prefer-nullish-coalescing` lints.

```
pnpm/fs/find-packages/src/index.ts
  32:38  error  Prefer using nullish coalescing operator (`??`) instead of a ternary expression, as it is simpler to read  @typescript-eslint/prefer-nullish-coalescing
```

* chore(deps): update TypeScript 5.1.6 -> 5.2.2

* chore(deps): update @yarnpkg/core->@types/lodash override to 4.14.197

This fixes a compilation error that appears on TypeScript 5.2.2. This
error was fixed in a later version of `@types/lodash`.

https://github.com/DefinitelyTyped/DefinitelyTyped/pull/66123

```
../node_modules/.pnpm/@types+lodash@4.14.181/node_modules/@types/lodash/index.d.ts:45:15 - error TS2428: All declarations of 'WeakMap' must have identical type parameters.

45     interface WeakMap<K extends object, V> { }
                 ~~~~~~~

Found 4 errors.
```
2023-08-31 16:27:01 +03:00

194 lines
5.9 KiB
TypeScript

import http, { type IncomingMessage, type Server, type ServerResponse } from 'http'
import { globalInfo } from '@pnpm/logger'
import {
type BundledManifestFunction,
type PackageFilesResponse,
type RequestPackageOptions,
type StoreController,
type WantedDependency,
} from '@pnpm/store-controller-types'
import { locking } from './lock'
interface RequestBody {
msgId: string
wantedDependency: WantedDependency
options: RequestPackageOptions
prefix: string
opts: {
addDependencies: string[]
removeDependencies: string[]
prune: boolean
}
storePath: string
id: string
searchQueries: string[]
}
export function createServer (
store: StoreController,
opts: {
path?: string
port?: number
hostname?: string
ignoreStopRequests?: boolean
ignoreUploadRequests?: boolean
}
) {
const rawManifestPromises: Record<string, BundledManifestFunction> = {}
const filesPromises: Record<string, () => Promise<PackageFilesResponse>> = {}
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
const lock = locking<void>()
const server = http.createServer(async (req: IncomingMessage, res: ServerResponse) => {
if (req.method !== 'POST') {
res.statusCode = 405 // Method Not Allowed
const responseError = { error: `Only POST is allowed, received ${req.method ?? 'unknown'}` }
res.setHeader('Allow', 'POST')
res.end(JSON.stringify(responseError))
return
}
const bodyPromise = new Promise<RequestBody>((resolve, reject) => {
let body: any = '' // eslint-disable-line
req.on('data', (data) => {
body += data
})
req.on('end', async () => {
try {
if (body.length > 0) {
body = JSON.parse(body)
} else {
body = {}
}
resolve(body)
} catch (e: any) { // eslint-disable-line
reject(e)
}
})
})
try {
let body: RequestBody
switch (req.url) {
case '/requestPackage': {
try {
body = await bodyPromise
const pkgResponse = await store.requestPackage(body.wantedDependency, body.options)
if (pkgResponse['bundledManifest']) {
rawManifestPromises[body.msgId] = pkgResponse['bundledManifest']
// @ts-expect-error
pkgResponse.body['fetchingBundledManifestInProgress'] = true
}
if (pkgResponse['files']) {
filesPromises[body.msgId] = pkgResponse['files']
}
res.end(JSON.stringify(pkgResponse.body))
} catch (err: any) { // eslint-disable-line
res.end(JSON.stringify({
error: {
message: err.message,
...JSON.parse(JSON.stringify(err)),
},
}))
}
break
}
case '/fetchPackage': {
try {
body = await bodyPromise
const pkgResponse = store.fetchPackage(body.options as any) // eslint-disable-line
if (pkgResponse['bundledManifest']) { // eslint-disable-line
rawManifestPromises[body.msgId] = pkgResponse['bundledManifest'] // eslint-disable-line
}
if (pkgResponse['files']) { // eslint-disable-line
filesPromises[body.msgId] = pkgResponse['files'] // eslint-disable-line
}
res.end(JSON.stringify({ filesIndexFile: pkgResponse.filesIndexFile }))
} catch (err: any) { // eslint-disable-line
res.end(JSON.stringify({
error: {
message: err.message,
...JSON.parse(JSON.stringify(err)),
},
}))
}
break
}
case '/packageFilesResponse': {
body = await bodyPromise
const filesResponse = await filesPromises[body.msgId]()
delete filesPromises[body.msgId]
res.end(JSON.stringify(filesResponse))
break
}
case '/rawManifestResponse': {
body = await bodyPromise
const manifestResponse = await rawManifestPromises[body.msgId]()
delete rawManifestPromises[body.msgId]
res.end(JSON.stringify(manifestResponse))
break
}
case '/prune':
// Disable store pruning when a server is running
res.statusCode = 403
res.end()
break
case '/importPackage': {
const importPackageBody = (await bodyPromise) as any // eslint-disable-line @typescript-eslint/no-explicit-any
await store.importPackage(importPackageBody.to, importPackageBody.opts)
res.end(JSON.stringify('OK'))
break
}
case '/upload': {
// Do not return an error status code, just ignore the upload request entirely
if (opts.ignoreUploadRequests) {
res.statusCode = 403
res.end()
break
}
const uploadBody = (await bodyPromise) as any // eslint-disable-line @typescript-eslint/no-explicit-any
await lock(uploadBody.builtPkgLocation, async () => store.upload(uploadBody.builtPkgLocation, uploadBody.opts))
res.end(JSON.stringify('OK'))
break
}
case '/stop':
if (opts.ignoreStopRequests) {
res.statusCode = 403
res.end()
break
}
globalInfo('Got request to stop the server')
await close()
res.end(JSON.stringify('OK'))
globalInfo('Server stopped')
break
default: {
res.statusCode = 404
const error = { error: `${req.url!} does not match any route` }
res.end(JSON.stringify(error))
}
}
} catch (e: any) { // eslint-disable-line
res.statusCode = 503
const jsonErr = JSON.parse(JSON.stringify(e))
jsonErr.message = e.message
res.end(JSON.stringify(jsonErr))
}
})
let listener: Server
if (opts.path) {
listener = server.listen(opts.path)
} else {
listener = server.listen(opts.port, opts.hostname)
}
return { close }
async function close () {
listener.close()
return store.close()
}
}