From 934ca92b4e621d18ee4d1700cbe49c03188b78f3 Mon Sep 17 00:00:00 2001 From: Michael Garvin Date: Fri, 20 Mar 2026 10:44:33 -0700 Subject: [PATCH 01/14] fix: remove spaces --- api/base.yaml | 8 ++-- api/registry.npmjs.com/token.yaml | 36 ++++++++-------- api/registry.npmjs.com/trust.yaml | 72 +++++++++++++++---------------- 3 files changed, 58 insertions(+), 58 deletions(-) diff --git a/api/base.yaml b/api/base.yaml index e6217cd..2e7b080 100644 --- a/api/base.yaml +++ b/api/base.yaml @@ -27,28 +27,28 @@ tags: **Token Types:** - **1. npm Session Token (`npmSessionToken`)** + **1. npm Session Token (`npmSessionToken`)** Traditional npm session tokens created via `npm login`. These tokens: - Are tied to a user account - Inherit the user's permissions - Have limited expiration - **Required for:** User account management, token creation/management - **2. npm Access Token (`npmAccessToken`)** + **2. npm Access Token (`npmAccessToken`)** Fine-grained tokens with specific permissions: - Can be scoped to specific packages and organizations - Can be scoped to specific operations (read, write, publish) - Have configurable expiration - **Supported for:** Most package operations where explicitly documented - **3. OIDC id_token (`oidcIdToken`)** + **3. OIDC id_token (`oidcIdToken`)** Tokens from supported Identity Providers (CI/CD systems): - From GitHub Actions, GitLab CI, CircleCI, etc. - Must have `aud` claim set to `npm:registry.npmjs.org` - Short-lived tokens - **Required for:** OIDC token exchange only - **4. OIDC Exchange Token (`oidcExchangeToken`)** + **4. OIDC Exchange Token (`oidcExchangeToken`)** Short-lived tokens obtained from OIDC token exchange: - Package-scoped permissions - Limited lifetime (typically 1 hour) diff --git a/api/registry.npmjs.com/token.yaml b/api/registry.npmjs.com/token.yaml index ef5617f..7f8adf8 100644 --- a/api/registry.npmjs.com/token.yaml +++ b/api/registry.npmjs.com/token.yaml @@ -7,14 +7,14 @@ paths: description: | Create a new npm access token with customizable permissions, scope restrictions, expiration, and CIDR IP range limitations. - + **Requirements:** - Must be authenticated - **Two-factor authentication is required for this endpoint** - If 2FA is enabled on your account, provide the OTP via the `npm-otp` header - If 2FA is not enabled, an email OTP will be sent and must be provided via the `npm-otp` header - For WebAuthn users, the OTP is returned in the `doneUrl` after authentication - + **Important notices:** - All responses include security notices via the `npm-notice` header regarding token limitations operationId: createToken @@ -27,9 +27,9 @@ paths: pattern: '^Bearer .+' description: | Bearer token for authentication. Must be an npm access token. - + **Format:** `Bearer ` - + **Accepted token types:** - npm access token (traditional user token created via `npm login`) - name: npm-otp @@ -39,7 +39,7 @@ paths: type: string description: | One-time password for two-factor authentication. Always required for this endpoint. - + **How to obtain the OTP:** - If 2FA is enabled on your account, provide the OTP from your configured 2FA method - If 2FA is not enabled, an email OTP will be sent and must be provided (format: `<8-digit-otp-from-email>`) @@ -275,17 +275,17 @@ paths: properties: error: type: string - + get: tags: - Tokens summary: List npm access tokens description: | List all access tokens associated with the authenticated user's account. - + **Requirements:** - Must be authenticated with a valid Bearer token - + **Response includes:** - All responses include security notices via the `npm-notice` header - Tokens are redacted for security: format is `npm_aBcD...7890` (first 8 chars including prefix + ... + last 4 chars) @@ -300,7 +300,7 @@ paths: pattern: '^Bearer .+' description: | Bearer token for authentication. Must be an npm access token. - + **Format:** `Bearer ` - name: page in: query @@ -379,7 +379,7 @@ paths: type: string format: date-time description: Timestamp when the token was last updated - accessed: + accessed: type: string format: date-time description: Timestamp when the token was last accessed @@ -443,7 +443,7 @@ paths: properties: message: type: string - + /-/npm/v1/tokens/token/{token}: delete: tags: @@ -453,11 +453,11 @@ paths: Delete an npm access token. The token can be specified as: - A UUID (token identifier) - An npm-prefixed token (format: `npm_` followed by 36 alphanumeric characters) - + **Requirements:** - Must be authenticated with a valid Bearer token - May require 2FA OTP depending on user settings - + **Web authentication flow:** - When `npm-auth-type=web` and `npm-command=token` headers are present and 2FA is required, returns authentication URLs instead of an error @@ -480,7 +480,7 @@ paths: pattern: '^Bearer .+' description: | Bearer token for authentication. Must be an npm access token. - + **Format:** `Bearer ` - name: npm-otp in: header @@ -617,7 +617,7 @@ components: 2. **No 2FA enabled + npm-otp header omitted**: Returns error requesting email OTP. An email is automatically sent to the user's registered email address 3. **2FA enabled + npm-otp header omitted (legacy flow)**: Returns 2FA error with npm-notice header containing WebAuthn URL. This is for older CLI versions without web auth support 4. **2FA enabled + npm-otp header omitted (web auth flow)**: Returns authentication URLs (authUrl and doneUrl) when both npm-auth-type=web and npm-command=token headers are present - + headers: npm-notice: description: | @@ -659,7 +659,7 @@ components: summary: "No 2FA enabled + npm-otp header omitted" description: | When user has no 2FA enabled and omits the `npm-otp` header. - + An email OTP is automatically sent to the user's registered email address. The user should check their email and retry the request with the received OTP. value: @@ -668,7 +668,7 @@ components: summary: "2FA enabled + npm-otp header omitted (legacy flow)" description: | When user has 2FA enabled, omits the `npm-otp` header, and doesn't include web auth headers. This is a legacy notice supported in older versions of the CLI without support for `npm-auth-type=web`. - + **Response includes npm-notice header:** > `npm-notice: Open https://www.npmjs.com/login/ to use your security key for authentication` @@ -680,4 +680,4 @@ components: When user has 2FA enabled, omits the `npm-otp` header, and includes both `npm-auth-type=web` and `npm-command=token` headers. value: authUrl: "https://www.npmjs.com/auth/cli/00000000-0000-0000-0000-000000000000" - doneUrl: "https://registry.npmjs.org/-/v1/done?authId=00000000-0000-0000-0000-000000000000" \ No newline at end of file + doneUrl: "https://registry.npmjs.org/-/v1/done?authId=00000000-0000-0000-0000-000000000000" diff --git a/api/registry.npmjs.com/trust.yaml b/api/registry.npmjs.com/trust.yaml index 295577f..2b68d29 100644 --- a/api/registry.npmjs.com/trust.yaml +++ b/api/registry.npmjs.com/trust.yaml @@ -6,15 +6,15 @@ paths: summary: Get all trusted publisher configurations for package description: | Retrieve all trusted publisher configurations for a package. - + This endpoint allows users with write permission to the package to view all existing trusted publisher configurations that have been set up for OIDC token exchange for their package. - + ## Configuration Structure - - The structure of the payload follows a specific design. Each trusted provider has their own unique set of claims. - In order to keep things clear and consistent, the properties to create a provider match the claims structure. - The caveat is when a claim requires partial matching through parsing. + + The structure of the payload follows a specific design. Each trusted provider has their own unique set of claims. + In order to keep things clear and consistent, the properties to create a provider match the claims structure. + The caveat is when a claim requires partial matching through parsing. - All configurations MUST include a `type` and `claims` object - Top-level "claims" MUST match the cloud provider's exact claim properties @@ -22,7 +22,7 @@ paths: - Claims MAY use an object structure to define one or multiple partial matching rules - Partial matching properties MUST be defined and documented by this API specification - This documentation SHALL only provide matches for specifically defined claim items - + ## Requirements - Package MUST exist - User MUST have write permission to the package @@ -45,10 +45,10 @@ paths: pattern: '^Bearer .+' description: | Authentication header. Supports both Bearer authentication. - + **Formats:** - `Bearer ` - npm access token or granular access token - + **Accepted token types:** - npm access token (traditional user token) - name: npm-otp @@ -163,11 +163,11 @@ paths: examples: 2fa_disabled: summary: "Please enable 2fa for your account" - value: + value: message: "Please enable 2fa for your account" insufficient_permissions: summary: "Insufficient permissions to view configurations" - value: + value: message: "Insufficient permissions to access trusted publisher configurations for this package" "404": description: Package not found @@ -181,7 +181,7 @@ paths: examples: package_not_found: summary: "Package not found" - value: + value: message: "Package not found" post: tags: @@ -189,11 +189,11 @@ paths: summary: Add trusted publisher configuration for package description: | Configure trusted publisher settings for a package to enable OIDC token exchange. - + This endpoint allows users with write permission to the package to establish trust with CI/CD providers (GitHub Actions, GitLab CI, CircleCI, etc.) so that those services can publish to the package without requiring long-lived npm tokens. - + ## Requirements - Package MUST exist - User MUST have write permission to the package @@ -216,10 +216,10 @@ paths: pattern: '^Bearer .+' description: | Authentication header. Supports both Bearer authentication. - + **Formats:** - `Bearer ` - npm access token or granular access token - + **Accepted token types:** - npm access token (traditional user token) - name: npm-otp @@ -322,7 +322,7 @@ paths: examples: invalid_config: summary: "Invalid trusted publisher configuration" - value: + value: message: "Invalid trusted publisher configuration" "401": description: Unauthorized - missing or invalid authentication / OTP @@ -360,7 +360,7 @@ paths: summary: "No Authorization header provided" description: | When no Authorization header is provided or the token is invalid. - value: + value: message: "Unauthorized" web_auth_flow: summary: "2FA enabled + npm-otp header omitted (web auth flow)" @@ -381,7 +381,7 @@ paths: examples: 2fa_disabled: summary: "Please enable 2fa for your account" - value: + value: message: "Please enable 2fa for your account" "404": description: Package not found @@ -395,7 +395,7 @@ paths: examples: package_not_found: summary: "Package not found" - value: + value: message: "Package not found" "409": description: Conflict - Configuration already exists @@ -409,7 +409,7 @@ paths: examples: config_limit_reached: summary: "Config already exists" - value: + value: message: "trusted publisher config already exists for the package. Please delete and re-create." /-/package/{package}/trust/{config-uuid}: delete: @@ -418,10 +418,10 @@ paths: summary: Delete trusted publisher configuration description: | Delete a specific trusted publisher configuration for a package by its UUID. - + This endpoint allows users with write permission to the package to remove an existing trusted publisher configuration that was previously set up for OIDC token exchange. - + ## Requirements - Package MUST exist - User MUST have write permission to the package @@ -451,10 +451,10 @@ paths: pattern: '^Bearer .+' description: | Authentication header. Supports both Bearer authentication. - + **Formats:** - `Bearer ` - npm access token or granular access token - + **Accepted token types:** - npm access token (traditional user token) - name: npm-otp @@ -485,7 +485,7 @@ paths: examples: invalid_uuid: summary: "Invalid UUID format" - value: + value: message: "Invalid trusted publisher config id format" "401": description: Unauthorized - missing or invalid authentication / OTP @@ -523,7 +523,7 @@ paths: summary: "No Authorization header provided" description: | When no Authorization header is provided or the token is invalid. - value: + value: message: "Unauthorized" web_auth_flow: summary: "2FA enabled + npm-otp header omitted (web auth flow)" @@ -544,11 +544,11 @@ paths: examples: 2fa_disabled: summary: "Please enable 2fa for your account" - value: + value: message: "Please enable 2fa for your account" insufficient_permissions: summary: "Insufficient permissions to delete configuration" - value: + value: message: "Insufficient permissions to access trusted publisher config for the package" "404": description: Package or configuration not found @@ -562,11 +562,11 @@ paths: examples: package_not_found: summary: "Package not found" - value: + value: message: "Package not found" config_not_found: summary: "Configuration not found" - value: + value: message: "Trusted publisher configuration not found for the package" components: @@ -579,7 +579,7 @@ components: - $ref: '#/components/schemas/GitHubActionsConfig' - $ref: '#/components/schemas/GitLabPipelinesConfig' - $ref: '#/components/schemas/CircleCIConfig' - + OidcConfigsCreate: type: array description: Array of OIDC trusted publisher configurations to create @@ -588,7 +588,7 @@ components: - $ref: '#/components/schemas/GitHubActionsConfigCreate' - $ref: '#/components/schemas/GitLabPipelinesConfigCreate' - $ref: '#/components/schemas/CircleCIConfigCreate' - + GitHubActionsConfig: type: object required: @@ -629,7 +629,7 @@ components: type: string description: GitHub environment name example: production - + GitHubActionsConfigCreate: type: object required: @@ -665,7 +665,7 @@ components: type: string description: GitHub environment name example: production - + GitLabPipelinesConfig: type: object required: @@ -706,7 +706,7 @@ components: type: string description: GitLab environment name example: production - + CircleCIConfig: type: object required: From bb4a434cd12b52dac440b1fe8060c0049663eb71 Mon Sep 17 00:00:00 2001 From: Michael Garvin Date: Fri, 20 Mar 2026 10:30:30 -0700 Subject: [PATCH 02/14] feat: add new package/org/user access endpoint These are all the `npm access` endpoints --- api/base.yaml | 3 +- api/merge-config.yaml | 1 + api/registry.npmjs.com/access.yaml | 218 +++++++++++++++++++++++++++++ api/shared-components.yaml | 24 ++++ 4 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 api/registry.npmjs.com/access.yaml create mode 100644 api/shared-components.yaml diff --git a/api/base.yaml b/api/base.yaml index 2e7b080..7b084f2 100644 --- a/api/base.yaml +++ b/api/base.yaml @@ -91,6 +91,7 @@ x-tagGroups: - Tokens - OIDC - Trust + - Access components: securitySchemes: @@ -141,4 +142,4 @@ components: Short-lived npm registry token obtained by exchanging an OIDC id_token via the `/oidc/token/exchange` endpoint. These tokens are package-scoped and have limited lifetime (typically 1 hour). - \ No newline at end of file + diff --git a/api/merge-config.yaml b/api/merge-config.yaml index 75667d8..e8b6568 100644 --- a/api/merge-config.yaml +++ b/api/merge-config.yaml @@ -1,5 +1,6 @@ inputs: - inputFile: base.yaml + - inputFile: registry.npmjs.com/access.yaml - inputFile: registry.npmjs.com/oidc.yaml - inputFile: registry.npmjs.com/token.yaml - inputFile: registry.npmjs.com/trust.yaml diff --git a/api/registry.npmjs.com/access.yaml b/api/registry.npmjs.com/access.yaml new file mode 100644 index 0000000..49cad0e --- /dev/null +++ b/api/registry.npmjs.com/access.yaml @@ -0,0 +1,218 @@ +components: + parameters: + OrgName: + name: orgName + in: path + required: true + schema: + type: string + description: Name of an org + PackageName: + name: escapedPackageName + in: path + required: true + schema: + type: string + description: The name of a package. Scoped packages need their "/" to be url encoded to "%2F" + example: "@npmcli%2Farborist" + TeamName: + name: teamName + in: path + required: true + schema: + type: string + description: Name of a team + responses: + PackageAccessLevels: + description: "Packages with their access levels" + content: + epplication/json: + schema: + type: object + additionalProperties: + type: string + example: + "@npmcli/arborist": "read-write" + "@npmcli/config": "read-only" + PackageVisibility: + description: "Packages with their visibility" + content: + application/json: + schema: + type: object + additionalProperties: + type: string + example: + "@npmcli/arborist": "public" + "@npmcli/hidden": "private" + UserAccessLevels: + description: "User access levels" + content: + epplication/json: + schema: + type: object + additionalProperties: + type: string + example: + "npm": "read-write" + "microsoft": "read-only" + Unauthorized: + description: "Unauthorized" + headers: + www-authenticate: + description: Authentication challenge (e.g., "OTP" when OTP is required) + schema: + type: string + npm-notice: + description: Additional notice information + schema: + type: string + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Error message +paths: + /-/team/{orgName}/{teamName}/package: + parameters: + - $ref: '#/components/parameters/OrgName' + - $ref: '#/components/parameters/TeamName' + - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" + get: + tags: + - Access + summary: Get all packages for a team + description: Get all of the packages a team has access to, as well a the access level that team has for each package. + operationId: getTeamPackageGrants + security: + - npmSessionToken: [] + responses: + "200": + $ref: '#/components/responses/PackageAccessLevels' + "401": + $ref: '#/components/responses/Unauthorized' + put: + tags: + - Access + summary: Grant access to a package for a team + operationId: createTeamPackageGrant + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + package: + type: string + description: The name of the package to give access to + permissions: + type: string + enum: + - read-only + - read-write + description: The access level of the package to grant to the team + security: + - npmSessionToken: [] + responses: + "201": + $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' + "401": + $ref: '#/components/responses/Unauthorized' + delete: + summary: Remove access to a package for a team + operationId: deleteTeamPackageGrant + security: + - npmSessionToken: [] + responses: + "204": + $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' + "401": + $ref: '#/components/responses/Unauthorized' + /-/org/{orgName}/package: + parameters: + - $ref: "#/components/parameters/OrgName" + - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" + get: + tags: + - Access + summary: Get all packages for an org + description: Get all of the packages an org has access to, as well a the access level that org has for each pacakge. + operationId: getOrgPackages + security: + - npmSessionToken: [] + responses: + "200": + $ref: '#/components/responses/PackageAccessLevels' + "401": + $ref: '#/components/responses/Unauthorized' + /-/package/{escapedPackageName}/collaborators: + parameters: + - $ref: '#/components/parameters/PackageName' + - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" + get: + tags: + - Access + summary: Get all of the users that have access to a package, as well as the access level that user has for each package. + operationId: getPackageCollaborators + security: + - npmSessionToken: [] + responses: + "200": + $ref: '#/components/responses/UserAccessLevels' + "401": + $ref: '#/components/responses/Unauthorized' + /-/package/{escapedPackageName}/visibility: + parameters: + - $ref: '#/components/parameters/PackageName' + - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" + get: + tags: + - Access + summary: Get the visibility of a package. + operationId: getPackageVisibility + security: + - npmSessionToken: [] + responses: + "200": + $ref: '#/components/responses/PackageVisibility' + "401": + $ref: '#/components/responses/Unauthorized' + /-/package/{escapedPackageName}/access: + post: + tags: + - Access + summary: Sets the various access levels for a package. + operationId: setPackageAccess + parameters: + - $ref: '#/components/parameters/PackageName' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + # cidr_whitelist? + access: + type: string + enum: + - public + - private + description: Visibility of a package + publish_requires_tfa: + type: boolean + description: Whether publishing this package requires multifactor auth + automation_token_overrides_tfa: + type: boolean + description: Whether or not automation tokens override the requirement for multifactor auth + security: + - npmSessionToken: [] + responses: + "200": + $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' + "401": + $ref: '#/components/responses/Unauthorized' diff --git a/api/shared-components.yaml b/api/shared-components.yaml new file mode 100644 index 0000000..e8efb09 --- /dev/null +++ b/api/shared-components.yaml @@ -0,0 +1,24 @@ +components: + parameters: + RequiredBearerToken: + name: Authorization + in: header + required: true + schema: + type: string + pattern: '^Bearer .+' + description: | + Bearer token for authentication. Must be an npm access token. + + **Format:** `Bearer ` + + **Accepted token types:** + - npm access token (traditional user token created via `npm login`) + responses: + EmptySuccess: + description: "Success" + content: + "*/*": + schema: + not: + {} From 2ed5388870e794bf99ef1f596db23a987e4b688c Mon Sep 17 00:00:00 2001 From: Michael Garvin Date: Fri, 20 Mar 2026 14:29:46 -0700 Subject: [PATCH 03/14] feat: add org membership endpoints These are all the `npm org` endpoints --- api/base.yaml | 1 + api/merge-config.yaml | 1 + api/registry.npmjs.com/access.yaml | 64 ++++------------- api/registry.npmjs.com/org.yaml | 111 +++++++++++++++++++++++++++++ api/shared-components.yaml | 34 +++++++++ 5 files changed, 162 insertions(+), 49 deletions(-) create mode 100644 api/registry.npmjs.com/org.yaml diff --git a/api/base.yaml b/api/base.yaml index 7b084f2..be37558 100644 --- a/api/base.yaml +++ b/api/base.yaml @@ -92,6 +92,7 @@ x-tagGroups: - OIDC - Trust - Access + - Org components: securitySchemes: diff --git a/api/merge-config.yaml b/api/merge-config.yaml index e8b6568..57a2854 100644 --- a/api/merge-config.yaml +++ b/api/merge-config.yaml @@ -2,6 +2,7 @@ inputs: - inputFile: base.yaml - inputFile: registry.npmjs.com/access.yaml - inputFile: registry.npmjs.com/oidc.yaml + - inputFile: registry.npmjs.com/org.yaml - inputFile: registry.npmjs.com/token.yaml - inputFile: registry.npmjs.com/trust.yaml diff --git a/api/registry.npmjs.com/access.yaml b/api/registry.npmjs.com/access.yaml index 49cad0e..e2fe00a 100644 --- a/api/registry.npmjs.com/access.yaml +++ b/api/registry.npmjs.com/access.yaml @@ -1,20 +1,5 @@ components: parameters: - OrgName: - name: orgName - in: path - required: true - schema: - type: string - description: Name of an org - PackageName: - name: escapedPackageName - in: path - required: true - schema: - type: string - description: The name of a package. Scoped packages need their "/" to be url encoded to "%2F" - example: "@npmcli%2Farborist" TeamName: name: teamName in: path @@ -26,7 +11,7 @@ components: PackageAccessLevels: description: "Packages with their access levels" content: - epplication/json: + application/json: schema: type: object additionalProperties: @@ -48,7 +33,7 @@ components: UserAccessLevels: description: "User access levels" content: - epplication/json: + application/json: schema: type: object additionalProperties: @@ -56,29 +41,10 @@ components: example: "npm": "read-write" "microsoft": "read-only" - Unauthorized: - description: "Unauthorized" - headers: - www-authenticate: - description: Authentication challenge (e.g., "OTP" when OTP is required) - schema: - type: string - npm-notice: - description: Additional notice information - schema: - type: string - content: - application/json: - schema: - type: object - properties: - error: - type: string - description: Error message paths: /-/team/{orgName}/{teamName}/package: parameters: - - $ref: '#/components/parameters/OrgName' + - $ref: './api/shared-components.yaml#/components/parameters/OrgName' - $ref: '#/components/parameters/TeamName' - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" get: @@ -93,7 +59,7 @@ paths: "200": $ref: '#/components/responses/PackageAccessLevels' "401": - $ref: '#/components/responses/Unauthorized' + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' put: tags: - Access @@ -121,7 +87,7 @@ paths: "201": $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' "401": - $ref: '#/components/responses/Unauthorized' + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' delete: summary: Remove access to a package for a team operationId: deleteTeamPackageGrant @@ -131,10 +97,10 @@ paths: "204": $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' "401": - $ref: '#/components/responses/Unauthorized' + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' /-/org/{orgName}/package: parameters: - - $ref: "#/components/parameters/OrgName" + - $ref: './api/shared-components.yaml#/components/parameters/OrgName' - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" get: tags: @@ -148,10 +114,10 @@ paths: "200": $ref: '#/components/responses/PackageAccessLevels' "401": - $ref: '#/components/responses/Unauthorized' + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' /-/package/{escapedPackageName}/collaborators: parameters: - - $ref: '#/components/parameters/PackageName' + - $ref: './api/shared-components.yaml#/components/parameters/EscapedPackageName' - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" get: tags: @@ -164,10 +130,10 @@ paths: "200": $ref: '#/components/responses/UserAccessLevels' "401": - $ref: '#/components/responses/Unauthorized' + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' /-/package/{escapedPackageName}/visibility: parameters: - - $ref: '#/components/parameters/PackageName' + - $ref: './api/shared-components.yaml#/components/parameters/EscapedPackageName' - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" get: tags: @@ -180,15 +146,15 @@ paths: "200": $ref: '#/components/responses/PackageVisibility' "401": - $ref: '#/components/responses/Unauthorized' + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' /-/package/{escapedPackageName}/access: + parameters: + - $ref: './api/shared-components.yaml#/components/parameters/EscapedPackageName' post: tags: - Access summary: Sets the various access levels for a package. operationId: setPackageAccess - parameters: - - $ref: '#/components/parameters/PackageName' requestBody: required: true content: @@ -215,4 +181,4 @@ paths: "200": $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' "401": - $ref: '#/components/responses/Unauthorized' + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' diff --git a/api/registry.npmjs.com/org.yaml b/api/registry.npmjs.com/org.yaml new file mode 100644 index 0000000..6c11288 --- /dev/null +++ b/api/registry.npmjs.com/org.yaml @@ -0,0 +1,111 @@ +components: + responses: + OrgMembers: + description: "Org members with their access levels" + content: + application/json: + schema: + type: object + additionalProperties: + type: string + example: + "npm": "owner" + "npm-cli-bot": "developer" + OrgInvite: + description: "Confirmation about the org membership or invite that was generated" + headers: + npm-notice: + description: Additional info about the invite sent to the user + schema: + type: string + content: + application/json: + schema: + type: object + properties: + org: + type: object + properties: + name: + type: string + description: The name of the org + size: + type: string + description: current size of the org, including invites + user: + type: string + description: The username that was invited or edited + role: + type: string + description: The role that the user was given in the org +paths: + /-/org/{orgName}/user: + parameters: + - $ref: './api/shared-components.yaml#/components/parameters/OrgName' + - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" + get: + tags: + - Org + summary: Get users in an org + description: Get all of the users in an org, along with their access levels in that org + operationId: getOrgMembership + security: + - npmSessionToken: [] + responses: + "200": + $ref: '#/components/responses/OrgMembers' + "401": + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' + put: + tags: + - Org + summary: Set user membership in an org + description: Set a user's membership in an org. If the user is not already a member, an invite will be sent. + operationId: changeOrgMembership + security: + - npmSessionToken: [] + requestBody: + required: true + content: + application;/json: + schema: + type: object + properties: + user: + type: string + description: Username to grant membership to org + role: + type: string + enum: + - developer + - admin + - owner + description: Role to give user in org + responses: + "201": + $ref: '#/components/responses/OrgInvite' + "401": + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' + delete: + tags: + - Org + summary: Remove user membership in an org + description: Remove a user's membership in an org + operationId: deleteOrgMembership + security: + - npmSessionToken: [] + requestBody: + required: true + content: + application;/json: + schema: + type: object + properties: + user: + type: string + description: Username to remove from the org + responses: + "204": + $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' + "401": + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' diff --git a/api/shared-components.yaml b/api/shared-components.yaml index e8efb09..9cb88bc 100644 --- a/api/shared-components.yaml +++ b/api/shared-components.yaml @@ -1,5 +1,20 @@ components: parameters: + EscapedPackageName: + name: escapedPackageName + in: path + required: true + schema: + type: string + description: The name of a package. Scoped packages need their "/" to be url encoded to "%2F" + example: "@npmcli%2Farborist" + OrgName: + name: orgName + in: path + required: true + schema: + type: string + description: Name of an org RequiredBearerToken: name: Authorization in: header @@ -22,3 +37,22 @@ components: schema: not: {} + Unauthorized: + description: "Unauthorized" + headers: + www-authenticate: + description: Authentication challenge (e.g., "OTP" when OTP is required) + schema: + type: string + npm-notice: + description: Additional notice information + schema: + type: string + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Error message From a0b2ed5ad982cb9db77509178c2274b93c01e6a7 Mon Sep 17 00:00:00 2001 From: Michael Garvin Date: Mon, 23 Mar 2026 11:27:53 -0700 Subject: [PATCH 04/14] feat: add team membership endpoints These are all the `npm team` endpoints --- api/base.yaml | 1 + api/merge-config.yaml | 1 + api/registry.npmjs.com/access.yaml | 64 +++++------ api/registry.npmjs.com/team.yaml | 166 +++++++++++++++++++++++++++++ api/shared-components.yaml | 19 +++- 5 files changed, 210 insertions(+), 41 deletions(-) create mode 100644 api/registry.npmjs.com/team.yaml diff --git a/api/base.yaml b/api/base.yaml index be37558..fca310c 100644 --- a/api/base.yaml +++ b/api/base.yaml @@ -93,6 +93,7 @@ x-tagGroups: - Trust - Access - Org + - Team components: securitySchemes: diff --git a/api/merge-config.yaml b/api/merge-config.yaml index 57a2854..7a117b0 100644 --- a/api/merge-config.yaml +++ b/api/merge-config.yaml @@ -3,6 +3,7 @@ inputs: - inputFile: registry.npmjs.com/access.yaml - inputFile: registry.npmjs.com/oidc.yaml - inputFile: registry.npmjs.com/org.yaml + - inputFile: registry.npmjs.com/team.yaml - inputFile: registry.npmjs.com/token.yaml - inputFile: registry.npmjs.com/trust.yaml diff --git a/api/registry.npmjs.com/access.yaml b/api/registry.npmjs.com/access.yaml index e2fe00a..af27dd0 100644 --- a/api/registry.npmjs.com/access.yaml +++ b/api/registry.npmjs.com/access.yaml @@ -1,15 +1,7 @@ components: - parameters: - TeamName: - name: teamName - in: path - required: true - schema: - type: string - description: Name of a team responses: PackageAccessLevels: - description: "Packages with their access levels" + description: 'Packages with their access levels' content: application/json: schema: @@ -17,10 +9,10 @@ components: additionalProperties: type: string example: - "@npmcli/arborist": "read-write" - "@npmcli/config": "read-only" + '@npmcli/arborist': read-write + '@npmcli/config': read-only PackageVisibility: - description: "Packages with their visibility" + description: 'Packages with their visibility' content: application/json: schema: @@ -28,10 +20,10 @@ components: additionalProperties: type: string example: - "@npmcli/arborist": "public" - "@npmcli/hidden": "private" + '@npmcli/arborist': public + '@npmcli/hidden': private UserAccessLevels: - description: "User access levels" + description: User access levels content: application/json: schema: @@ -39,14 +31,14 @@ components: additionalProperties: type: string example: - "npm": "read-write" - "microsoft": "read-only" + npm: read-write + microsoft: read-only paths: /-/team/{orgName}/{teamName}/package: parameters: - $ref: './api/shared-components.yaml#/components/parameters/OrgName' - - $ref: '#/components/parameters/TeamName' - - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" + - $ref: './api/shared-components.yaml#/components/parameters/TeamName' + - $ref: './api/shared-components.yaml#/components/parameters/RequiredBearerToken' get: tags: - Access @@ -56,9 +48,9 @@ paths: security: - npmSessionToken: [] responses: - "200": + '200': $ref: '#/components/responses/PackageAccessLevels' - "401": + '401': $ref: './api/shared-components.yaml#/components/responses/Unauthorized' put: tags: @@ -84,9 +76,9 @@ paths: security: - npmSessionToken: [] responses: - "201": + '201': $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' - "401": + '401': $ref: './api/shared-components.yaml#/components/responses/Unauthorized' delete: summary: Remove access to a package for a team @@ -94,14 +86,14 @@ paths: security: - npmSessionToken: [] responses: - "204": + '204': $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' - "401": + '401': $ref: './api/shared-components.yaml#/components/responses/Unauthorized' /-/org/{orgName}/package: parameters: - $ref: './api/shared-components.yaml#/components/parameters/OrgName' - - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" + - $ref: './api/shared-components.yaml#/components/parameters/RequiredBearerToken' get: tags: - Access @@ -111,14 +103,14 @@ paths: security: - npmSessionToken: [] responses: - "200": + '200': $ref: '#/components/responses/PackageAccessLevels' - "401": + '401': $ref: './api/shared-components.yaml#/components/responses/Unauthorized' /-/package/{escapedPackageName}/collaborators: parameters: - $ref: './api/shared-components.yaml#/components/parameters/EscapedPackageName' - - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" + - $ref: './api/shared-components.yaml#/components/parameters/RequiredBearerToken' get: tags: - Access @@ -127,14 +119,14 @@ paths: security: - npmSessionToken: [] responses: - "200": + '200': $ref: '#/components/responses/UserAccessLevels' - "401": + '401': $ref: './api/shared-components.yaml#/components/responses/Unauthorized' /-/package/{escapedPackageName}/visibility: parameters: - $ref: './api/shared-components.yaml#/components/parameters/EscapedPackageName' - - $ref: "./api/shared-components.yaml#/components/parameters/RequiredBearerToken" + - $ref: './api/shared-components.yaml#/components/parameters/RequiredBearerToken' get: tags: - Access @@ -143,9 +135,9 @@ paths: security: - npmSessionToken: [] responses: - "200": + '200': $ref: '#/components/responses/PackageVisibility' - "401": + '401': $ref: './api/shared-components.yaml#/components/responses/Unauthorized' /-/package/{escapedPackageName}/access: parameters: @@ -178,7 +170,7 @@ paths: security: - npmSessionToken: [] responses: - "200": + '200': $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' - "401": + '401': $ref: './api/shared-components.yaml#/components/responses/Unauthorized' diff --git a/api/registry.npmjs.com/team.yaml b/api/registry.npmjs.com/team.yaml new file mode 100644 index 0000000..e036cf2 --- /dev/null +++ b/api/registry.npmjs.com/team.yaml @@ -0,0 +1,166 @@ +components: + responses: + TeamUsers: + description: The users in a team + content: + application/json: + schema: + type: array + items: + type: string + description: A username of a user in the team + example: + - npm + - npm-cli-bot + OrgTeams: + description: The teams in an org + content: + application/json: + schema: + type: array + items: + type: string + description: The teams in the org, in the format of orgname:teamname + example: + - '@npmcli:wombats' + +paths: + /-/org/{orgName}/team: + parameters: + - $ref: './api/shared-components.yaml#/components/parameters/OrgName' + - $ref: './api/shared-components.yaml#/components/parameters/RequiredBearerToken' + get: + tags: + - Org + summary: Get teams in an org + description: Get all of the teams in an org + operationId: getScopeTeams + security: + - npmSessionToken: [] + responses: + '200': + $ref: '#/components/responses/OrgTeams' + '401': + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' + put: + tags: + - Team + summary: Create a new team + description: Create a new team for an org + operationId: putScopeTeam + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + description: The name of the team to create + description: + type: string + description: The description of the team to create + example: { name: 'wombats', description: 'All developers' } + security: + - npmSessionToken: [] + responses: + '201': + description: Team was created successfully + content: + application/json: + schema: + type: object + properties: + name: + type: string + description: The name of the team that was created + example: + name: wombats + '401': + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' + /-/org/{orgName}/{teamName}: + parameters: + - $ref: './api/shared-components.yaml#/components/parameters/OrgName' + - $ref: './api/shared-components.yaml#/components/parameters/TeamName' + - $ref: './api/shared-components.yaml#/components/parameters/RequiredBearerToken' + delete: + tags: + - Team + summary: Delete a team + description: Delete a team from a given org + operationId: deleteTeam + security: + - npmSessionToken: [] + responses: + '204': + $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' + '401': + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' + /-/org/{orgName}/{teamName}/user: + parameters: + - $ref: './api/shared-components.yaml#/components/parameters/OrgName' + - $ref: './api/shared-components.yaml#/components/parameters/TeamName' + - $ref: './api/shared-components.yaml#/components/parameters/RequiredBearerToken' + get: + tags: + - Team + summary: Get all users in a team + description: Get all users in a team + operationId: getTeamMembership + security: + - npmSessionToken: [] + responses: + '200': + $ref: '#/components/responses/TeamUsers' + '401': + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' + put: + tags: + - Team + summary: Add a user to a team + description: Add a user to a team in an org. The user must already be a member of the org. + operationId: createTeamMembership + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + description: The username of the user to add to the team + example: + user: npm-cli-bot + security: + - npmSessionToken: [] + responses: + '201': + $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' + '401': + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' + delete: + tags: + - Team + summary: Remove a user from a team + operationId: deleteTeamMembership + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + user: + type: string + description: The username of the user to remove from the team + example: + user: npm-cli-bot + security: + - npmSessionToken: [] + responses: + '204': + $ref: './api/shared-components.yaml#/components/responses/EmptySuccess' + '401': + $ref: './api/shared-components.yaml#/components/responses/Unauthorized' diff --git a/api/shared-components.yaml b/api/shared-components.yaml index 9cb88bc..4225329 100644 --- a/api/shared-components.yaml +++ b/api/shared-components.yaml @@ -6,8 +6,8 @@ components: required: true schema: type: string - description: The name of a package. Scoped packages need their "/" to be url encoded to "%2F" - example: "@npmcli%2Farborist" + description: The name of a package. Scoped packages need "/" to be url encoded to "%2F" + example: '@npmcli%2Farborist' OrgName: name: orgName in: path @@ -15,6 +15,13 @@ components: schema: type: string description: Name of an org + TeamName: + name: teamName + in: path + required: true + schema: + type: string + description: Name of a team RequiredBearerToken: name: Authorization in: header @@ -31,14 +38,14 @@ components: - npm access token (traditional user token created via `npm login`) responses: EmptySuccess: - description: "Success" + description: Success content: - "*/*": + '*/*': schema: not: {} Unauthorized: - description: "Unauthorized" + description: Unauthorized headers: www-authenticate: description: Authentication challenge (e.g., "OTP" when OTP is required) @@ -56,3 +63,5 @@ components: error: type: string description: Error message + example: + error: Missing "Bearer" header. From 61be6048c49d78d86ca141cc78ec767a86a6f545 Mon Sep 17 00:00:00 2001 From: Michael Garvin Date: Mon, 23 Mar 2026 15:03:43 -0700 Subject: [PATCH 05/14] feat: add search endpoint This is the `npm search` endpoint --- api/base.yaml | 15 +-- api/merge-config.yaml | 1 + api/registry.npmjs.com/search.yaml | 143 +++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 7 deletions(-) create mode 100644 api/registry.npmjs.com/search.yaml diff --git a/api/base.yaml b/api/base.yaml index fca310c..fee61d0 100644 --- a/api/base.yaml +++ b/api/base.yaml @@ -19,7 +19,7 @@ tags: x-displayName: Introduction description: | This is the API documentation for the npm registry. For information about the npm registry, website, and command-line interface (CLI), please refer to [https://docs.npmjs.com](https://docs.npmjs.com). - + - name: Authentication x-displayName: Authentication & Authorization description: | @@ -94,6 +94,7 @@ x-tagGroups: - Access - Org - Team + - Search components: securitySchemes: @@ -105,12 +106,12 @@ components: description: | OIDC id_token from a supported Identity Provider (IdP) such as GitHub Actions, GitLab CI, or CircleCI. The `aud` (audience) claim must be set to `npm:registry.npmjs.org`. - + **Supported Identity Providers:** - GitHub Actions - GitLab CI - CircleCI - + # Traditional npm user access tokens npmSessionToken: type: http @@ -118,7 +119,7 @@ components: description: | Traditional npm session token created via `npm login`. These tokens are tied to a user account and inherit the user's permissions. - + # Granular Access Tokens (GAT) - fine-grained tokens with specific permissions npmAccessToken: type: http @@ -126,7 +127,7 @@ components: description: | Granular Access Token (GAT) with fine-grained permissions. These tokens can be scoped to specific packages and operations. - + # Alias for npmAccessToken - for backward compatibility granularAccessToken: type: http @@ -135,7 +136,7 @@ components: Granular Access Token (GAT) with fine-grained permissions. These tokens can be scoped to specific packages and operations. (Alias for npmAccessToken) - + # Short-lived tokens obtained from OIDC token exchange oidcExchangeToken: type: http @@ -144,4 +145,4 @@ components: Short-lived npm registry token obtained by exchanging an OIDC id_token via the `/oidc/token/exchange` endpoint. These tokens are package-scoped and have limited lifetime (typically 1 hour). - + diff --git a/api/merge-config.yaml b/api/merge-config.yaml index 7a117b0..17cc03a 100644 --- a/api/merge-config.yaml +++ b/api/merge-config.yaml @@ -3,6 +3,7 @@ inputs: - inputFile: registry.npmjs.com/access.yaml - inputFile: registry.npmjs.com/oidc.yaml - inputFile: registry.npmjs.com/org.yaml + - inputFile: registry.npmjs.com/search.yaml - inputFile: registry.npmjs.com/team.yaml - inputFile: registry.npmjs.com/token.yaml - inputFile: registry.npmjs.com/trust.yaml diff --git a/api/registry.npmjs.com/search.yaml b/api/registry.npmjs.com/search.yaml new file mode 100644 index 0000000..dc129c9 --- /dev/null +++ b/api/registry.npmjs.com/search.yaml @@ -0,0 +1,143 @@ +components: + responses: + SearchResults: + description: The users in a team + content: + application/json: + schema: + type: object + properties: + objects: + type: array + items: + type: object + properties: + downloads: + type: object + properties: + monthly: + type: number + description: Download count for this package in the last month + weekly: + type: number + description: Download count for this package in the last week + dependents: + type: number + description: The number of packages that list this package as a dependency + updated: + type: string + format: date-time + description: When the package was last updated + searchScore: + type: number + description: Search score of this result, same as score.final + package: + type: object + properties: + name: + type: string + description: The name of the package + keywords: + type: array + items: + type: string + description: A keyword associated with this package + version: + type: string + description: The latest version of this package. + description: + type: string + description: The description of this package from its package.json + sanitized_name: + type: string + description: The name of the package with some characters changed to help with indexing + publisher: + type: object + properties: + username: + type: string + email: + type: string + description: Information about the user that published the latest version of this package + maintainers: + type: array + items: + type: object + properties: + username: + type: string + email: + type: string + description: Information about the users who own this package + license: + type: string + description: SPDX license for this package + date: + type: string + format: date-time + description: Timestamp of when the latest version of this package was published + links: + type: object + properties: + homepage: + type: string + description: The main homepage for this package + repository: + type: string + description: The repository for this package's source code + bugs: + type: string + description: Where to report bugs for this package + npm: + type: string + description: This package's main page on the npm website + score: + type: object + properties: + final: + type: number + description: Search score of this result, same as sesarchScore + detail: + type: object + description: Legacy "pqm" values of this result. These are hard coded and left in for legacy purposes, all set to "1" + flags: + type: object + properties: + insecure: + type: number + description: Legacy attribute. Always set to 0. + total: + type: number + description: The total number of items in the search results + time: + type: string + description: The current time +paths: + /-/v1/search: + get: + parameters: + - name: text + in: query + required: true + schema: + type: string + description: The search query text + - name: size + in: query + schema: + type: number + description: The number of search results to return + - name: from + in: query + schema: + type: number + description: The starting index of the search results + tags: + - Search + summary: Search for packages on the registry + description: Search for packages on the registry + operationId: getsearch + security: [] + responses: + '200': + $ref: '#/components/responses/SearchResults' From 54caf8f0c39f6c09873de16ed01b09197e50b5b3 Mon Sep 17 00:00:00 2001 From: Michael Garvin Date: Mon, 23 Mar 2026 15:48:40 -0700 Subject: [PATCH 06/14] fix: deal with no-invalid-media-type-examples warning The error was misleading, evidently if only one of the oneOf entries has required fields, the linter has problem with the one that has required fields --- api/registry.npmjs.com/token.yaml | 2 +- api/registry.npmjs.com/trust.yaml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/registry.npmjs.com/token.yaml b/api/registry.npmjs.com/token.yaml index 7f8adf8..9a72410 100644 --- a/api/registry.npmjs.com/token.yaml +++ b/api/registry.npmjs.com/token.yaml @@ -579,7 +579,7 @@ paths: summary: "Invalid OTP provided" value: error: "invalid OTP" - webAuthFlow: + web_auth_flow: summary: "Web authentication flow (2FA required)" description: | When user has 2FA enabled and includes both `npm-auth-type=web` and `npm-command=token` headers. diff --git a/api/registry.npmjs.com/trust.yaml b/api/registry.npmjs.com/trust.yaml index 2b68d29..adac647 100644 --- a/api/registry.npmjs.com/trust.yaml +++ b/api/registry.npmjs.com/trust.yaml @@ -125,6 +125,7 @@ paths: properties: message: type: string + required: [message] - type: object description: Web authentication flow response properties: @@ -343,6 +344,7 @@ paths: properties: message: type: string + required: [message] - type: object description: Web authentication flow response properties: @@ -506,6 +508,7 @@ paths: properties: message: type: string + required: [message] - type: object description: Web authentication flow response properties: From 545e3b9496c6e7dabc649e70650d636bfb6c6af9 Mon Sep 17 00:00:00 2001 From: Michael Garvin Date: Mon, 23 Mar 2026 15:51:44 -0700 Subject: [PATCH 07/14] fix: add 4xx response to search fixes last linting error --- api/registry.npmjs.com/search.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/api/registry.npmjs.com/search.yaml b/api/registry.npmjs.com/search.yaml index dc129c9..249bf98 100644 --- a/api/registry.npmjs.com/search.yaml +++ b/api/registry.npmjs.com/search.yaml @@ -1,5 +1,18 @@ components: responses: + MissingField: + description: A required parameter was missing + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Message explaining what was missing from the request + code: + type: string + description: Error code for this response SearchResults: description: The users in a team content: @@ -141,3 +154,5 @@ paths: responses: '200': $ref: '#/components/responses/SearchResults' + '400': + $ref: '#/components/responses/MissingField' From 5a4138d97dc4ae7ab6b7134a656c4927b485b4f9 Mon Sep 17 00:00:00 2001 From: Michael Garvin Date: Mon, 23 Mar 2026 15:54:25 -0700 Subject: [PATCH 08/14] fix: set time field to date-time format --- api/registry.npmjs.com/search.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/api/registry.npmjs.com/search.yaml b/api/registry.npmjs.com/search.yaml index 249bf98..a77f813 100644 --- a/api/registry.npmjs.com/search.yaml +++ b/api/registry.npmjs.com/search.yaml @@ -124,6 +124,7 @@ components: description: The total number of items in the search results time: type: string + format: date-time description: The current time paths: /-/v1/search: From ae5f75b8b7b9f4abceda3a20c1b1a433b7894555 Mon Sep 17 00:00:00 2001 From: Michael Garvin Date: Mon, 23 Mar 2026 15:55:56 -0700 Subject: [PATCH 09/14] fix: search results description --- api/registry.npmjs.com/search.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/registry.npmjs.com/search.yaml b/api/registry.npmjs.com/search.yaml index a77f813..58fc76c 100644 --- a/api/registry.npmjs.com/search.yaml +++ b/api/registry.npmjs.com/search.yaml @@ -14,7 +14,7 @@ components: type: string description: Error code for this response SearchResults: - description: The users in a team + description: Search results content: application/json: schema: From 2707603433e9808019cdd3b6aca558fa9a141910 Mon Sep 17 00:00:00 2001 From: Gar Date: Tue, 24 Mar 2026 09:54:53 -0700 Subject: [PATCH 10/14] fix: typo Co-authored-by: Michael Smith --- api/registry.npmjs.com/org.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/registry.npmjs.com/org.yaml b/api/registry.npmjs.com/org.yaml index 6c11288..609e373 100644 --- a/api/registry.npmjs.com/org.yaml +++ b/api/registry.npmjs.com/org.yaml @@ -67,7 +67,7 @@ paths: requestBody: required: true content: - application;/json: + application/json: schema: type: object properties: From 0a6b13831759463fbc5f0f95c455391cd500a6d0 Mon Sep 17 00:00:00 2001 From: Gar Date: Tue, 24 Mar 2026 09:55:24 -0700 Subject: [PATCH 11/14] fix: typo Co-authored-by: Michael Smith --- api/registry.npmjs.com/org.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/registry.npmjs.com/org.yaml b/api/registry.npmjs.com/org.yaml index 609e373..9503fd2 100644 --- a/api/registry.npmjs.com/org.yaml +++ b/api/registry.npmjs.com/org.yaml @@ -97,7 +97,7 @@ paths: requestBody: required: true content: - application;/json: + application/json: schema: type: object properties: From d1ea3dfaa5edfcd75bc1e30126eae99228e2a453 Mon Sep 17 00:00:00 2001 From: Gar Date: Tue, 24 Mar 2026 09:55:42 -0700 Subject: [PATCH 12/14] fix: typo Co-authored-by: Michael Smith --- api/registry.npmjs.com/access.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/registry.npmjs.com/access.yaml b/api/registry.npmjs.com/access.yaml index af27dd0..f2c5189 100644 --- a/api/registry.npmjs.com/access.yaml +++ b/api/registry.npmjs.com/access.yaml @@ -43,7 +43,7 @@ paths: tags: - Access summary: Get all packages for a team - description: Get all of the packages a team has access to, as well a the access level that team has for each package. + description: Get all of the packages a team has access to, as well as the access level that team has for each package. operationId: getTeamPackageGrants security: - npmSessionToken: [] From c1476b25b0b403b45ca7b9de922885da5b6a584e Mon Sep 17 00:00:00 2001 From: Gar Date: Tue, 24 Mar 2026 09:55:56 -0700 Subject: [PATCH 13/14] fix: typo Co-authored-by: Michael Smith --- api/registry.npmjs.com/search.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/registry.npmjs.com/search.yaml b/api/registry.npmjs.com/search.yaml index 58fc76c..46ce1a1 100644 --- a/api/registry.npmjs.com/search.yaml +++ b/api/registry.npmjs.com/search.yaml @@ -109,7 +109,7 @@ components: properties: final: type: number - description: Search score of this result, same as sesarchScore + description: Search score of this result, same as searchScore detail: type: object description: Legacy "pqm" values of this result. These are hard coded and left in for legacy purposes, all set to "1" From 6ffa659c237b7603bcbe23642b5256c1f7dbe45b Mon Sep 17 00:00:00 2001 From: Gar Date: Tue, 24 Mar 2026 09:58:00 -0700 Subject: [PATCH 14/14] fix: add tag --- api/registry.npmjs.com/access.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/registry.npmjs.com/access.yaml b/api/registry.npmjs.com/access.yaml index f2c5189..b9f2373 100644 --- a/api/registry.npmjs.com/access.yaml +++ b/api/registry.npmjs.com/access.yaml @@ -81,6 +81,8 @@ paths: '401': $ref: './api/shared-components.yaml#/components/responses/Unauthorized' delete: + tags: + - Access summary: Remove access to a package for a team operationId: deleteTeamPackageGrant security: