This commit is contained in:
2025-08-18 23:06:34 +08:00
parent 0bc04fb659
commit ed18af0cad
1926 changed files with 275098 additions and 0 deletions

13
package/node_modules/libnpmpublish/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,13 @@
Copyright npm, Inc
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

120
package/node_modules/libnpmpublish/README.md generated vendored Normal file
View File

@@ -0,0 +1,120 @@
# libnpmpublish
[![npm version](https://img.shields.io/npm/v/libnpmpublish.svg)](https://npm.im/libnpmpublish)
[![license](https://img.shields.io/npm/l/libnpmpublish.svg)](https://npm.im/libnpmpublish)
[![CI - libnpmpublish](https://github.com/npm/cli/actions/workflows/ci-libnpmpublish.yml/badge.svg)](https://github.com/npm/cli/actions/workflows/ci-libnpmpublish.yml)
[`libnpmpublish`](https://github.com/npm/libnpmpublish) is a Node.js
library for programmatically publishing and unpublishing npm packages. Give
it a manifest as an object and a tarball as a Buffer, and it'll put them on
the registry for you.
## Table of Contents
* [Example](#example)
* [Install](#install)
* [API](#api)
* [publish/unpublish opts](#opts)
* [`publish()`](#publish)
* [`unpublish()`](#unpublish)
## Example
```js
const { publish, unpublish } = require('libnpmpublish')
```
## Install
`$ npm install libnpmpublish`
### API
#### <a name="opts"></a> `opts` for `libnpmpublish` commands
`libnpmpublish` uses
[`npm-registry-fetch`](https://npm.im/npm-registry-fetch). Most options
are passed through directly to that library, so please refer to [its own
`opts` documentation](http://npm.im/npm-registry-fetch#fetch-options) for
options that can be passed in.
A couple of options of note:
* `opts.defaultTag` - registers the published package with the given tag,
defaults to `latest`.
* `opts.access` - tells the registry whether this package should be
published as `public` or `restricted`. Only applies to scoped
packages. Defaults to `public`.
* `opts.token` - can be passed in and will be used as the authentication
token for the registry. For other ways to pass in auth details, see the
n-r-f docs.
* `opts.provenance` - when running in a supported CI environment, will trigger
the generation of a signed provenance statement to be published alongside
the package. Mutually exclusive with the `provenanceFile` option.
* `opts.provenanceFile` - specifies the path to an externally-generated
provenance statement to be published alongside the package. Mutually
exclusive with the `provenance` option. The specified file should be a
[Sigstore Bundle](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto)
containing a [DSSE](https://github.com/secure-systems-lab/dsse)-packaged
provenance statement.
#### <a name="publish"></a> `> libpub.publish(manifest, tarData, [opts]) -> Promise`
Sends the package represented by the `manifest` and `tarData` to the
configured registry.
`manifest` should be the parsed `package.json` for the package being
published (which can also be the manifest pulled from a packument, a git
repo, tarball, etc.)
`tarData` is a `Buffer` of the tarball being published.
If `opts.npmVersion` is passed in, it will be used as the `_npmVersion`
field in the outgoing packument. You may put your own user-agent string in
there to identify your publishes.
If `opts.algorithms` is passed in, it should be an array of hashing
algorithms to generate `integrity` hashes for. The default is `['sha512']`,
which means you end up with `dist.integrity = 'sha512-deadbeefbadc0ffee'`.
Any algorithm supported by your current node version is allowed -- npm
clients that do not support those algorithms will simply ignore the
unsupported hashes.
##### Example
```js
// note that pacote.manifest() and pacote.tarball() can also take
// any spec that npm can install. a folder shown here, since that's
// far and away the most common use case.
const path = '/a/path/to/your/source/code'
const pacote = require('pacote') // see: http://npm.im/pacote
const manifest = await pacote.manifest(path)
const tarData = await pacote.tarball(path)
await libpub.publish(manifest, tarData, {
npmVersion: 'my-pub-script@1.0.2',
token: 'my-auth-token-here'
}, opts)
// Package has been published to the npm registry.
```
#### <a name="unpublish"></a> `> libpub.unpublish(spec, [opts]) -> Promise`
Unpublishes `spec` from the appropriate registry. The registry in question may
have its own limitations on unpublishing.
`spec` should be either a string, or a valid
[`npm-package-arg`](https://npm.im/npm-package-arg) parsed spec object. For
legacy compatibility reasons, only `tag` and `version` specs will work as
expected. `range` specs will fail silently in most cases.
##### Example
```js
await libpub.unpublish('lodash', { token: 'i-am-the-worst'})
//
// `lodash` has now been unpublished, along with all its versions
```

4
package/node_modules/libnpmpublish/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,4 @@
module.exports = {
publish: require('./publish.js'),
unpublish: require('./unpublish.js'),
}

245
package/node_modules/libnpmpublish/lib/provenance.js generated vendored Normal file
View File

@@ -0,0 +1,245 @@
const sigstore = require('sigstore')
const { readFile } = require('node:fs/promises')
const ci = require('ci-info')
const { env } = process
const INTOTO_PAYLOAD_TYPE = 'application/vnd.in-toto+json'
const INTOTO_STATEMENT_V01_TYPE = 'https://in-toto.io/Statement/v0.1'
const INTOTO_STATEMENT_V1_TYPE = 'https://in-toto.io/Statement/v1'
const SLSA_PREDICATE_V02_TYPE = 'https://slsa.dev/provenance/v0.2'
const SLSA_PREDICATE_V1_TYPE = 'https://slsa.dev/provenance/v1'
const GITHUB_BUILDER_ID_PREFIX = 'https://github.com/actions/runner'
const GITHUB_BUILD_TYPE = 'https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1'
const GITLAB_BUILD_TYPE_PREFIX = 'https://github.com/npm/cli/gitlab'
const GITLAB_BUILD_TYPE_VERSION = 'v0alpha1'
const generateProvenance = async (subject, opts) => {
let payload
if (ci.GITHUB_ACTIONS) {
/* istanbul ignore next - not covering missing env var case */
const relativeRef = (env.GITHUB_WORKFLOW_REF || '').replace(env.GITHUB_REPOSITORY + '/', '')
const delimiterIndex = relativeRef.indexOf('@')
const workflowPath = relativeRef.slice(0, delimiterIndex)
const workflowRef = relativeRef.slice(delimiterIndex + 1)
payload = {
_type: INTOTO_STATEMENT_V1_TYPE,
subject,
predicateType: SLSA_PREDICATE_V1_TYPE,
predicate: {
buildDefinition: {
buildType: GITHUB_BUILD_TYPE,
externalParameters: {
workflow: {
ref: workflowRef,
repository: `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}`,
path: workflowPath,
},
},
internalParameters: {
github: {
event_name: env.GITHUB_EVENT_NAME,
repository_id: env.GITHUB_REPOSITORY_ID,
repository_owner_id: env.GITHUB_REPOSITORY_OWNER_ID,
},
},
resolvedDependencies: [
{
uri: `git+${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}@${env.GITHUB_REF}`,
digest: {
gitCommit: env.GITHUB_SHA,
},
},
],
},
runDetails: {
builder: { id: `${GITHUB_BUILDER_ID_PREFIX}/${env.RUNNER_ENVIRONMENT}` },
metadata: {
/* eslint-disable-next-line max-len */
invocationId: `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}/attempts/${env.GITHUB_RUN_ATTEMPT}`,
},
},
},
}
}
if (ci.GITLAB) {
payload = {
_type: INTOTO_STATEMENT_V01_TYPE,
subject,
predicateType: SLSA_PREDICATE_V02_TYPE,
predicate: {
buildType: `${GITLAB_BUILD_TYPE_PREFIX}/${GITLAB_BUILD_TYPE_VERSION}`,
builder: { id: `${env.CI_PROJECT_URL}/-/runners/${env.CI_RUNNER_ID}` },
invocation: {
configSource: {
uri: `git+${env.CI_PROJECT_URL}`,
digest: {
sha1: env.CI_COMMIT_SHA,
},
entryPoint: env.CI_JOB_NAME,
},
parameters: {
CI: env.CI,
CI_API_GRAPHQL_URL: env.CI_API_GRAPHQL_URL,
CI_API_V4_URL: env.CI_API_V4_URL,
CI_BUILD_BEFORE_SHA: env.CI_BUILD_BEFORE_SHA,
CI_BUILD_ID: env.CI_BUILD_ID,
CI_BUILD_NAME: env.CI_BUILD_NAME,
CI_BUILD_REF: env.CI_BUILD_REF,
CI_BUILD_REF_NAME: env.CI_BUILD_REF_NAME,
CI_BUILD_REF_SLUG: env.CI_BUILD_REF_SLUG,
CI_BUILD_STAGE: env.CI_BUILD_STAGE,
CI_COMMIT_BEFORE_SHA: env.CI_COMMIT_BEFORE_SHA,
CI_COMMIT_BRANCH: env.CI_COMMIT_BRANCH,
CI_COMMIT_REF_NAME: env.CI_COMMIT_REF_NAME,
CI_COMMIT_REF_PROTECTED: env.CI_COMMIT_REF_PROTECTED,
CI_COMMIT_REF_SLUG: env.CI_COMMIT_REF_SLUG,
CI_COMMIT_SHA: env.CI_COMMIT_SHA,
CI_COMMIT_SHORT_SHA: env.CI_COMMIT_SHORT_SHA,
CI_COMMIT_TIMESTAMP: env.CI_COMMIT_TIMESTAMP,
CI_COMMIT_TITLE: env.CI_COMMIT_TITLE,
CI_CONFIG_PATH: env.CI_CONFIG_PATH,
CI_DEFAULT_BRANCH: env.CI_DEFAULT_BRANCH,
CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX:
env.CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX,
CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX: env.CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX,
CI_DEPENDENCY_PROXY_SERVER: env.CI_DEPENDENCY_PROXY_SERVER,
CI_DEPENDENCY_PROXY_USER: env.CI_DEPENDENCY_PROXY_USER,
CI_JOB_ID: env.CI_JOB_ID,
CI_JOB_NAME: env.CI_JOB_NAME,
CI_JOB_NAME_SLUG: env.CI_JOB_NAME_SLUG,
CI_JOB_STAGE: env.CI_JOB_STAGE,
CI_JOB_STARTED_AT: env.CI_JOB_STARTED_AT,
CI_JOB_URL: env.CI_JOB_URL,
CI_NODE_TOTAL: env.CI_NODE_TOTAL,
CI_PAGES_DOMAIN: env.CI_PAGES_DOMAIN,
CI_PAGES_URL: env.CI_PAGES_URL,
CI_PIPELINE_CREATED_AT: env.CI_PIPELINE_CREATED_AT,
CI_PIPELINE_ID: env.CI_PIPELINE_ID,
CI_PIPELINE_IID: env.CI_PIPELINE_IID,
CI_PIPELINE_SOURCE: env.CI_PIPELINE_SOURCE,
CI_PIPELINE_URL: env.CI_PIPELINE_URL,
CI_PROJECT_CLASSIFICATION_LABEL: env.CI_PROJECT_CLASSIFICATION_LABEL,
CI_PROJECT_DESCRIPTION: env.CI_PROJECT_DESCRIPTION,
CI_PROJECT_ID: env.CI_PROJECT_ID,
CI_PROJECT_NAME: env.CI_PROJECT_NAME,
CI_PROJECT_NAMESPACE: env.CI_PROJECT_NAMESPACE,
CI_PROJECT_NAMESPACE_ID: env.CI_PROJECT_NAMESPACE_ID,
CI_PROJECT_PATH: env.CI_PROJECT_PATH,
CI_PROJECT_PATH_SLUG: env.CI_PROJECT_PATH_SLUG,
CI_PROJECT_REPOSITORY_LANGUAGES: env.CI_PROJECT_REPOSITORY_LANGUAGES,
CI_PROJECT_ROOT_NAMESPACE: env.CI_PROJECT_ROOT_NAMESPACE,
CI_PROJECT_TITLE: env.CI_PROJECT_TITLE,
CI_PROJECT_URL: env.CI_PROJECT_URL,
CI_PROJECT_VISIBILITY: env.CI_PROJECT_VISIBILITY,
CI_REGISTRY: env.CI_REGISTRY,
CI_REGISTRY_IMAGE: env.CI_REGISTRY_IMAGE,
CI_REGISTRY_USER: env.CI_REGISTRY_USER,
CI_RUNNER_DESCRIPTION: env.CI_RUNNER_DESCRIPTION,
CI_RUNNER_ID: env.CI_RUNNER_ID,
CI_RUNNER_TAGS: env.CI_RUNNER_TAGS,
CI_SERVER_HOST: env.CI_SERVER_HOST,
CI_SERVER_NAME: env.CI_SERVER_NAME,
CI_SERVER_PORT: env.CI_SERVER_PORT,
CI_SERVER_PROTOCOL: env.CI_SERVER_PROTOCOL,
CI_SERVER_REVISION: env.CI_SERVER_REVISION,
CI_SERVER_SHELL_SSH_HOST: env.CI_SERVER_SHELL_SSH_HOST,
CI_SERVER_SHELL_SSH_PORT: env.CI_SERVER_SHELL_SSH_PORT,
CI_SERVER_URL: env.CI_SERVER_URL,
CI_SERVER_VERSION: env.CI_SERVER_VERSION,
CI_SERVER_VERSION_MAJOR: env.CI_SERVER_VERSION_MAJOR,
CI_SERVER_VERSION_MINOR: env.CI_SERVER_VERSION_MINOR,
CI_SERVER_VERSION_PATCH: env.CI_SERVER_VERSION_PATCH,
CI_TEMPLATE_REGISTRY_HOST: env.CI_TEMPLATE_REGISTRY_HOST,
GITLAB_CI: env.GITLAB_CI,
GITLAB_FEATURES: env.GITLAB_FEATURES,
GITLAB_USER_ID: env.GITLAB_USER_ID,
GITLAB_USER_LOGIN: env.GITLAB_USER_LOGIN,
RUNNER_GENERATE_ARTIFACTS_METADATA: env.RUNNER_GENERATE_ARTIFACTS_METADATA,
},
environment: {
name: env.CI_RUNNER_DESCRIPTION,
architecture: env.CI_RUNNER_EXECUTABLE_ARCH,
server: env.CI_SERVER_URL,
project: env.CI_PROJECT_PATH,
job: {
id: env.CI_JOB_ID,
},
pipeline: {
id: env.CI_PIPELINE_ID,
ref: env.CI_CONFIG_PATH,
},
},
},
metadata: {
buildInvocationId: `${env.CI_JOB_URL}`,
completeness: {
parameters: true,
environment: true,
materials: false,
},
reproducible: false,
},
materials: [
{
uri: `git+${env.CI_PROJECT_URL}`,
digest: {
sha1: env.CI_COMMIT_SHA,
},
},
],
},
}
}
return sigstore.attest(Buffer.from(JSON.stringify(payload)), INTOTO_PAYLOAD_TYPE, opts)
}
const verifyProvenance = async (subject, provenancePath) => {
let provenanceBundle
try {
provenanceBundle = JSON.parse(await readFile(provenancePath))
} catch (err) {
err.message = `Invalid provenance provided: ${err.message}`
throw err
}
const payload = extractProvenance(provenanceBundle)
if (!payload.subject || !payload.subject.length) {
throw new Error('No subject found in sigstore bundle payload')
}
if (payload.subject.length > 1) {
throw new Error('Found more than one subject in the sigstore bundle payload')
}
const bundleSubject = payload.subject[0]
if (subject.name !== bundleSubject.name) {
throw new Error(
`Provenance subject ${bundleSubject.name} does not match the package: ${subject.name}`
)
}
if (subject.digest.sha512 !== bundleSubject.digest.sha512) {
throw new Error('Provenance subject digest does not match the package')
}
await sigstore.verify(provenanceBundle)
return provenanceBundle
}
const extractProvenance = (bundle) => {
if (!bundle?.dsseEnvelope?.payload) {
throw new Error('No dsseEnvelope with payload found in sigstore bundle')
}
try {
return JSON.parse(Buffer.from(bundle.dsseEnvelope.payload, 'base64').toString('utf8'))
} catch (err) {
err.message = `Failed to parse payload from dsseEnvelope: ${err.message}`
throw err
}
}
module.exports = {
generateProvenance,
verifyProvenance,
}

225
package/node_modules/libnpmpublish/lib/publish.js generated vendored Normal file
View File

@@ -0,0 +1,225 @@
const { fixer } = require('normalize-package-data')
const npmFetch = require('npm-registry-fetch')
const npa = require('npm-package-arg')
const { log } = require('proc-log')
const semver = require('semver')
const { URL } = require('node:url')
const ssri = require('ssri')
const ciInfo = require('ci-info')
const { generateProvenance, verifyProvenance } = require('./provenance')
const TLOG_BASE_URL = 'https://search.sigstore.dev/'
const publish = async (manifest, tarballData, opts) => {
if (manifest.private) {
throw Object.assign(
new Error(`This package has been marked as private
Remove the 'private' field from the package.json to publish it.`),
{ code: 'EPRIVATE' }
)
}
// spec is used to pick the appropriate registry/auth combo
const spec = npa.resolve(manifest.name, manifest.version)
opts = {
access: 'public',
algorithms: ['sha512'],
defaultTag: 'latest',
...opts,
spec,
}
const reg = npmFetch.pickRegistry(spec, opts)
const pubManifest = patchManifest(manifest, opts)
// registry-frontdoor cares about the access level,
// which is only configurable for scoped packages
if (!spec.scope && opts.access === 'restricted') {
throw Object.assign(
new Error("Can't restrict access to unscoped packages."),
{ code: 'EUNSCOPED' }
)
}
const { metadata, transparencyLogUrl } = await buildMetadata(
reg,
pubManifest,
tarballData,
spec,
opts
)
const res = await npmFetch(spec.escapedName, {
...opts,
method: 'PUT',
body: metadata,
ignoreBody: true,
})
if (transparencyLogUrl) {
res.transparencyLogUrl = transparencyLogUrl
}
return res
}
const patchManifest = (_manifest, opts) => {
const { npmVersion } = opts
// we only update top-level fields, so a shallow clone is fine
const manifest = { ..._manifest }
manifest._nodeVersion = process.versions.node
if (npmVersion) {
manifest._npmVersion = npmVersion
}
fixer.fixNameField(manifest, { strict: true, allowLegacyCase: true })
const version = semver.clean(manifest.version)
if (!version) {
throw Object.assign(
new Error('invalid semver: ' + manifest.version),
{ code: 'EBADSEMVER' }
)
}
manifest.version = version
return manifest
}
const buildMetadata = async (registry, manifest, tarballData, spec, opts) => {
const { access, defaultTag, algorithms, provenance, provenanceFile } = opts
const root = {
_id: manifest.name,
name: manifest.name,
description: manifest.description,
'dist-tags': {},
versions: {},
access,
}
root.versions[manifest.version] = manifest
const tag = manifest.tag || defaultTag
root['dist-tags'][tag] = manifest.version
const tarballName = `${manifest.name}-${manifest.version}.tgz`
const provenanceBundleName = `${manifest.name}-${manifest.version}.sigstore`
const tarballURI = `${manifest.name}/-/${tarballName}`
const integrity = ssri.fromData(tarballData, {
algorithms: [...new Set(['sha1'].concat(algorithms))],
})
manifest._id = `${manifest.name}@${manifest.version}`
manifest.dist = { ...manifest.dist }
// Don't bother having sha1 in the actual integrity field
manifest.dist.integrity = integrity.sha512[0].toString()
// Legacy shasum support
manifest.dist.shasum = integrity.sha1[0].hexDigest()
// NB: the CLI always fetches via HTTPS if the registry is HTTPS,
// regardless of what's here. This makes it so that installing
// from an HTTP-only mirror doesn't cause problems, though.
manifest.dist.tarball = new URL(tarballURI, registry).href
.replace(/^https:\/\//, 'http://')
root._attachments = {}
root._attachments[tarballName] = {
content_type: 'application/octet-stream',
data: tarballData.toString('base64'),
length: tarballData.length,
}
// Handle case where --provenance flag was set to true
let transparencyLogUrl
if (provenance === true || provenanceFile) {
let provenanceBundle
const subject = {
name: npa.toPurl(spec),
digest: { sha512: integrity.sha512[0].hexDigest() },
}
if (provenance === true) {
await ensureProvenanceGeneration(registry, spec, opts)
provenanceBundle = await generateProvenance([subject], opts)
/* eslint-disable-next-line max-len */
log.notice('publish', `Signed provenance statement with source and build information from ${ciInfo.name}`)
const tlogEntry = provenanceBundle?.verificationMaterial?.tlogEntries[0]
/* istanbul ignore else */
if (tlogEntry) {
transparencyLogUrl = `${TLOG_BASE_URL}?logIndex=${tlogEntry.logIndex}`
log.notice(
'publish',
`Provenance statement published to transparency log: ${transparencyLogUrl}`
)
}
} else {
provenanceBundle = await verifyProvenance(subject, provenanceFile)
}
const serializedBundle = JSON.stringify(provenanceBundle)
root._attachments[provenanceBundleName] = {
content_type: provenanceBundle.mediaType,
data: serializedBundle,
length: serializedBundle.length,
}
}
return {
metadata: root,
transparencyLogUrl,
}
}
// Check that all the prereqs are met for provenance generation
const ensureProvenanceGeneration = async (registry, spec, opts) => {
if (ciInfo.GITHUB_ACTIONS) {
// Ensure that the GHA OIDC token is available
if (!process.env.ACTIONS_ID_TOKEN_REQUEST_URL) {
throw Object.assign(
/* eslint-disable-next-line max-len */
new Error('Provenance generation in GitHub Actions requires "write" access to the "id-token" permission'),
{ code: 'EUSAGE' }
)
}
} else if (ciInfo.GITLAB) {
// Ensure that the Sigstore OIDC token is available
if (!process.env.SIGSTORE_ID_TOKEN) {
throw Object.assign(
/* eslint-disable-next-line max-len */
new Error('Provenance generation in GitLab CI requires "SIGSTORE_ID_TOKEN" with "sigstore" audience to be present in "id_tokens". For more info see:\nhttps://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html'),
{ code: 'EUSAGE' }
)
}
} else {
throw Object.assign(
new Error('Automatic provenance generation not supported for provider: ' + ciInfo.name),
{ code: 'EUSAGE' }
)
}
// Some registries (e.g. GH packages) require auth to check visibility,
// and always return 404 when no auth is supplied. In this case we assume
// the package is always private and require `--access public` to publish
// with provenance.
let visibility = { public: false }
if (opts.access !== 'public') {
try {
const res = await npmFetch
.json(`${registry}/-/package/${spec.escapedName}/visibility`, opts)
visibility = res
} catch (err) {
if (err.code !== 'E404') {
throw err
}
}
}
if (!visibility.public && opts.provenance === true && opts.access !== 'public') {
throw Object.assign(
/* eslint-disable-next-line max-len */
new Error("Can't generate provenance for new or private package, you must set `access` to public."),
{ code: 'EUSAGE' }
)
}
}
module.exports = publish

119
package/node_modules/libnpmpublish/lib/unpublish.js generated vendored Normal file
View File

@@ -0,0 +1,119 @@
'use strict'
const { URL } = require('node:url')
const npa = require('npm-package-arg')
const npmFetch = require('npm-registry-fetch')
const semver = require('semver')
// given a tarball url and a registry url, returns just the
// relevant pathname portion of it, so that it can be handled
// elegantly by npm-registry-fetch which only expects pathnames
// and handles the registry hostname via opts
const getPathname = (tarball, registry) => {
const registryUrl = new URL(registry).pathname.slice(1)
let tarballUrl = new URL(tarball).pathname.slice(1)
// test the tarball url to see if it starts with a possible
// pathname from the registry url, in that case strips that portion
// of it so that we only return the post-registry-url pathname
if (registryUrl) {
tarballUrl = tarballUrl.slice(registryUrl.length)
}
return tarballUrl
}
const unpublish = async (spec, opts) => {
spec = npa(spec)
// spec is used to pick the appropriate registry/auth combo.
opts = {
force: false,
...opts,
spec,
}
try {
const pkgUri = spec.escapedName
const pkg = await npmFetch.json(pkgUri, {
...opts,
query: { write: true },
})
const version = spec.rawSpec
const allVersions = pkg.versions || {}
const versionData = allVersions[version]
const rawSpecs = (!spec.rawSpec || spec.rawSpec === '*')
const onlyVersion = Object.keys(allVersions).length === 1
const noVersions = !Object.keys(allVersions).length
// if missing specific version,
// assumed unpublished
if (!versionData && !rawSpecs && !noVersions) {
return true
}
// unpublish all versions of a package:
// - no specs supplied "npm unpublish foo"
// - all specs ("*") "npm unpublish foo@*"
// - there was only one version
// - has no versions field on packument
if (rawSpecs || onlyVersion || noVersions) {
await npmFetch(`${pkgUri}/-rev/${pkg._rev}`, {
...opts,
method: 'DELETE',
ignoreBody: true,
})
return true
} else {
const dist = allVersions[version].dist
delete allVersions[version]
const latestVer = pkg['dist-tags'].latest
// deleting dist tags associated to version
Object.keys(pkg['dist-tags']).forEach(tag => {
if (pkg['dist-tags'][tag] === version) {
delete pkg['dist-tags'][tag]
}
})
if (latestVer === version) {
pkg['dist-tags'].latest = Object.keys(
allVersions
).sort(semver.compareLoose).pop()
}
delete pkg._revisions
delete pkg._attachments
// Update packument with removed versions
await npmFetch(`${pkgUri}/-rev/${pkg._rev}`, {
...opts,
method: 'PUT',
body: pkg,
ignoreBody: true,
})
// Remove the tarball itself
const { _rev } = await npmFetch.json(pkgUri, {
...opts,
query: { write: true },
})
const tarballUrl = getPathname(dist.tarball, opts.registry)
await npmFetch(`${tarballUrl}/-rev/${_rev}`, {
...opts,
method: 'DELETE',
ignoreBody: true,
})
return true
}
} catch (err) {
if (err.code !== 'E404') {
throw err
}
return true
}
}
module.exports = unpublish

64
package/node_modules/libnpmpublish/package.json generated vendored Normal file
View File

@@ -0,0 +1,64 @@
{
"name": "libnpmpublish",
"version": "9.0.9",
"description": "Programmatic API for the bits behind npm publish and unpublish",
"author": "GitHub Inc.",
"main": "lib/index.js",
"contributors": [
"Kat Marchán <kzm@zkat.tech>",
"Claudia Hernández <claudia@npmjs.com>"
],
"files": [
"bin/",
"lib/"
],
"license": "ISC",
"scripts": {
"lint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"",
"lintfix": "npm run lint -- --fix",
"test": "tap",
"posttest": "npm run lint",
"postlint": "template-oss-check",
"snap": "tap",
"template-oss-apply": "template-oss-apply --force"
},
"devDependencies": {
"@npmcli/eslint-config": "^4.0.0",
"@npmcli/mock-globals": "^1.0.0",
"@npmcli/mock-registry": "^1.0.0",
"@npmcli/template-oss": "4.22.0",
"nock": "^13.3.3",
"tap": "^16.3.8"
},
"repository": {
"type": "git",
"url": "git+https://github.com/npm/cli.git",
"directory": "workspaces/libnpmpublish"
},
"bugs": "https://github.com/npm/cli/issues",
"homepage": "https://npmjs.com/package/libnpmpublish",
"dependencies": {
"ci-info": "^4.0.0",
"normalize-package-data": "^6.0.1",
"npm-package-arg": "^11.0.2",
"npm-registry-fetch": "^17.0.1",
"proc-log": "^4.2.0",
"semver": "^7.3.7",
"sigstore": "^2.2.0",
"ssri": "^10.0.6"
},
"engines": {
"node": "^16.14.0 || >=18.0.0"
},
"templateOSS": {
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
"version": "4.22.0",
"content": "../../scripts/template-oss/index.js"
},
"tap": {
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
]
}
}