This PR adds comprehensive documentation for cnpmcore's internal APIs,
enabling users to make direct HTTP requests without needing the cnpm
client with outdated dependencies.
## Background
Users requested documentation for internal APIs to avoid using the cnpm
client, which has outdated dependencies like `bagpipe` (11 years old)
and `npm-request` (9 years old). The primary use case is package
synchronization functionality that was previously only accessible
through the cnpm CLI.
## Changes
### New Documentation: `docs/internal-api.md`
Created a comprehensive 988-line API reference covering:
**Package Sync API** - The primary requested functionality:
- `PUT /-/package/:fullname/syncs` - Modern sync API
- `PUT /:fullname/sync` - Legacy sync API (cnpmjs.org compatibility)
- `GET /-/package/:fullname/syncs/:taskId` - Check sync status
- `GET /-/package/:fullname/syncs/:taskId/log` - View sync logs
**Additional APIs documented:**
- **Token Management**: Create, list, delete authentication tokens
- **Hook Management**: CRUD operations for webhooks
- **Package Administration**: Block/unblock packages (admin only)
- **Registry Management**: Manage multiple npm registries
- **Binary Sync**: List and browse binary packages
- **User Management**: User registration and authentication
### Documentation Features
- Complete curl examples for all endpoints
- Request/response schemas with validation rules
- Authentication requirements clearly marked
- Error handling with HTTP status codes
- Security considerations and best practices
- Real-world workflow examples
### Updated README.md
Added reference to the new internal API documentation to make it
discoverable.
## Usage Examples
Users can now sync packages directly:
```bash
# Trigger package sync
curl -X PUT \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{"tips": "API sync request"}' \
https://your-registry.com/-/package/lodash/syncs
# Check sync status
curl -H "Authorization: Bearer your-token" \
https://your-registry.com/-/package/lodash/syncs/task-id
# View sync logs
curl -H "Authorization: Bearer your-token" \
https://your-registry.com/-/package/lodash/syncs/task-id/log
```
## Validation
All documented endpoints have been verified against the actual
implementation in the controllers. The API paths, parameters, and
response formats match the codebase exactly.
This enables users to extract sync functionality and other operations
without dealing with outdated cnpm dependencies, directly addressing the
issue's core request.
Fixes #709.
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: fengmk2 <156269+fengmk2@users.noreply.github.com>
Co-authored-by: MK (fengmk2) <fengmk2@gmail.com>
[skip ci]
19 KiB
CNPMCore Internal API Documentation
This document provides comprehensive documentation for cnpmcore's internal APIs that allow direct HTTP requests without using the cnpm client. These APIs enable package synchronization, administration, and other advanced operations.
Table of Contents
- Authentication
- Package Sync API
- Binary Sync API
- Token Management API
- Package Block/Admin API
- Registry Management API
- Hook Management API
- User Management API
- Common Schemas
Authentication
Most internal APIs require authentication using one of these methods:
Bearer Token Authentication
curl -H "Authorization: Bearer ${TOKEN}" https://your-registry.com/api/endpoint
Admin Access
Some APIs require admin privileges. Admin users are configured in the registry settings.
Package Sync API
The package sync functionality allows you to synchronize packages from external registries (like npmjs.org) to your private registry.
Create Sync Task (Modern API)
Trigger a package synchronization task.
PUT /-/package/:fullname/syncs
Authentication
Required. Must be authenticated user.
Parameters
fullname(string): Package name (can include scope, e.g.,@scope/package)
Request Body
{
"skipDependencies": false,
"syncDownloadData": false,
"force": false,
"forceSyncHistory": false,
"tips": "Custom sync reason",
"registryName": "optional-source-registry",
"specificVersions": "[\"1.0.0\", \"1.0.1\"]"
}
Request Body Schema
| Field | Type | Required | Description |
|---|---|---|---|
skipDependencies |
boolean | No | Skip syncing package dependencies |
syncDownloadData |
boolean | No | Sync download statistics data |
force |
boolean | No | Force immediate execution (admin only) |
forceSyncHistory |
boolean | No | Sync all historical versions (admin only) |
tips |
string | No | Custom reason/description for sync |
registryName |
string | No | Source registry name |
specificVersions |
string | No | JSON array of specific versions to sync |
Example Request
curl -X PUT \
-H "Authorization: Bearer your-token-here" \
-H "Content-Type: application/json" \
-d '{
"skipDependencies": false,
"syncDownloadData": false,
"force": false,
"tips": "Manual sync from API"
}' \
https://your-registry.com/-/package/lodash/syncs
Response
{
"ok": true,
"id": "sync-task-uuid",
"type": "package",
"state": "waiting"
}
Create Sync Task (Legacy API)
Legacy endpoint for compatibility with cnpmjs.org.
PUT /:fullname/sync
Parameters
fullname(string): Package namenodeps(query): Set to "true" to skip dependencies
Example Request
curl -X PUT \
-H "Authorization: Bearer your-token-here" \
"https://your-registry.com/lodash/sync?nodeps=false"
Response
{
"ok": true,
"logId": "sync-task-uuid"
}
Get Sync Task Status
Check the status of a sync task.
GET /-/package/:fullname/syncs/:taskId
Parameters
fullname(string): Package nametaskId(string): Task ID returned from sync creation
Example Request
curl -H "Authorization: Bearer your-token-here" \
https://your-registry.com/-/package/lodash/syncs/sync-task-uuid
Response
{
"ok": true,
"id": "sync-task-uuid",
"type": "package",
"state": "success",
"logUrl": "https://your-registry.com/-/package/lodash/syncs/sync-task-uuid/log"
}
Task States
waiting: Task is queuedprocessing: Task is currently runningsuccess: Task completed successfullyerror: Task failed
Get Sync Task Log
Retrieve the log for a sync task.
GET /-/package/:fullname/syncs/:taskId/log
Parameters
fullname(string): Package nametaskId(string): Task ID
Example Request
curl -H "Authorization: Bearer your-token-here" \
https://your-registry.com/-/package/lodash/syncs/sync-task-uuid/log
Response
Returns the log content as plain text or redirects to log URL.
Legacy Sync Status API
Legacy endpoint for checking sync status.
GET /:fullname/sync/log/:taskId
Example Request
curl -H "Authorization: Bearer your-token-here" \
https://your-registry.com/lodash/sync/log/sync-task-uuid
Response
{
"ok": true,
"syncDone": true,
"log": "[2024-01-01T12:00:00Z] [done] Sync lodash data: {...}",
"logUrl": "https://your-registry.com/-/package/lodash/syncs/sync-task-uuid/log"
}
Binary Sync API
Manage and sync binary packages (like Node.js, Python, etc.).
List All Binaries
Get a list of all available binary packages.
GET /-/binary/
Example Request
curl https://your-registry.com/-/binary/
Response
[
{
"name": "node/",
"category": "node/",
"description": "Node.js runtime",
"distUrl": "https://nodejs.org/dist/",
"repoUrl": "https://github.com/nodejs/node",
"type": "dir",
"url": "https://your-registry.com/-/binary/node/"
}
]
Browse Binary Directory
Browse files in a binary package directory.
GET /-/binary/:binaryName/:subpath
Parameters
binaryName(string): Binary package name (e.g., "node", "python")subpath(string): Path within the binary directorysince(query): Filter files modified since datelimit(query): Limit number of results (max 1000)
Example Request
curl https://your-registry.com/-/binary/node/v18.0.0/
Token Management API
Manage authentication tokens for users.
Create Token
Create a new authentication token.
POST /-/npm/v1/tokens
Authentication
Required. Must provide current password.
Request Body
{
"password": "current-password",
"readonly": false,
"automation": false,
"cidr_whitelist": ["127.0.0.1", "192.168.1.0/24"]
}
Request Body Schema
| Field | Type | Required | Description |
|---|---|---|---|
password |
string | Yes | Current user password (8-100 chars) |
readonly |
boolean | No | Create read-only token |
automation |
boolean | No | Mark token for automation use |
cidr_whitelist |
array | No | IP address restrictions (max 10) |
Example Request
curl -X POST \
-H "Authorization: Bearer existing-token" \
-H "Content-Type: application/json" \
-d '{
"password": "my-password",
"readonly": false,
"cidr_whitelist": ["127.0.0.1"]
}' \
https://your-registry.com/-/npm/v1/tokens
Response
{
"token": "npm_xxxxxxxxxxxxxxxxxxxx",
"key": "full-token-key-hash",
"cidr_whitelist": ["127.0.0.1"],
"readonly": false,
"automation": false,
"created": "2024-01-01T12:00:00.000Z",
"updated": "2024-01-01T12:00:00.000Z"
}
List Tokens
Get all tokens for the authenticated user.
GET /-/npm/v1/tokens
Authentication
Required.
Example Request
curl -H "Authorization: Bearer your-token" \
https://your-registry.com/-/npm/v1/tokens
Response
{
"objects": [
{
"token": "npm_xx...xx",
"key": "token-key-hash",
"cidr_whitelist": null,
"readonly": false,
"automation": false,
"created": "2024-01-01T12:00:00.000Z",
"updated": "2024-01-01T12:00:00.000Z",
"lastUsedAt": "2024-01-01T12:30:00.000Z"
}
],
"total": 1,
"urls": {}
}
Delete Token
Remove an authentication token.
DELETE /-/npm/v1/tokens/token/:tokenKey
Authentication
Required.
Parameters
tokenKey(string): The token key to delete
Example Request
curl -X DELETE \
-H "Authorization: Bearer your-token" \
https://your-registry.com/-/npm/v1/tokens/token/token-key-hash
Response
{
"ok": true
}
Package Block/Admin API
Administrative APIs for blocking and managing packages. Requires admin access.
Block Package
Block a package from being downloaded or published.
PUT /-/package/:fullname/blocks
Authentication
Required. Admin access only.
Parameters
fullname(string): Package name to block
Request Body
{
"reason": "Detailed reason for blocking this package"
}
Example Request
curl -X PUT \
-H "Authorization: Bearer admin-token" \
-H "Content-Type: application/json" \
-d '{
"reason": "Package contains malicious code"
}' \
https://your-registry.com/-/package/malicious-package/blocks
Response
{
"ok": true,
"id": "block-record-id",
"package_id": "package-internal-id"
}
Unblock Package
Remove a block from a package.
DELETE /-/package/:fullname/blocks
Authentication
Required. Admin access only.
Parameters
fullname(string): Package name to unblock
Example Request
curl -X DELETE \
-H "Authorization: Bearer admin-token" \
https://your-registry.com/-/package/malicious-package/blocks
Response
{
"ok": true
}
Get Package Block Status
Check if a package is blocked and why.
GET /-/package/:fullname/blocks
Parameters
fullname(string): Package name to check
Example Request
curl https://your-registry.com/-/package/some-package/blocks
Response
{
"blocked": true,
"reason": "Package contains malicious code (operator: admin/admin-id)",
"createdAt": "2024-01-01T12:00:00.000Z"
}
Registry Management API
Manage multiple npm registries and their configurations.
List Registries
Get all configured registries.
GET /-/registry
Query Parameters
pageSize(number): Results per page (1-100, default: 20)pageIndex(number): Page number (0-based, default: 0)
Example Request
curl "https://your-registry.com/-/registry?pageSize=10&pageIndex=0"
Response
{
"data": [
{
"registryId": "npmjs",
"name": "Official NPM Registry",
"host": "https://registry.npmjs.org",
"type": "npm",
"userPrefix": "npm:",
"changeStream": "https://replicate.npmjs.com",
"response": null
}
],
"total": 1
}
Get Registry Details
Get details for a specific registry.
GET /-/registry/:id
Parameters
id(string): Registry ID
Example Request
curl https://your-registry.com/-/registry/npmjs
Create Registry
Create a new registry configuration.
POST /-/registry
Authentication
Required. Admin access only.
Request Body
{
"name": "Custom Registry",
"host": "https://my-custom-registry.com",
"changeStream": "https://my-custom-registry.com/_changes",
"type": "cnpm"
}
Example Request
curl -X POST \
-H "Authorization: Bearer admin-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Custom Registry",
"host": "https://my-custom-registry.com",
"type": "cnpm"
}' \
https://your-registry.com/-/registry
Hook Management API
Manage webhooks that trigger on package events (publish, install, etc.).
Base Path: All hook endpoints use the base path /-/npm
Create Hook
Create a new webhook.
POST /-/npm/v1/hooks/hook
Authentication
Required.
Request Body
{
"type": "package",
"name": "hook-name",
"endpoint": "https://your-webhook-endpoint.com/hook",
"secret": "webhook-secret-key"
}
Request Body Schema
| Field | Type | Required | Description |
|---|---|---|---|
type |
string | Yes | Hook type (e.g., "package") |
name |
string | Yes | Hook name (1-428 chars) |
endpoint |
string | Yes | Webhook URL (1-2048 chars) |
secret |
string | Yes | Secret key for webhook verification (1-200 chars) |
Example Request
curl -X POST \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{
"type": "package",
"name": "my-webhook",
"endpoint": "https://my-server.com/webhook",
"secret": "my-secret-key"
}' \
https://your-registry.com/-/npm/v1/hooks/hook
Response
{
"id": "hook-uuid",
"name": "my-webhook",
"type": "package",
"endpoint": "https://my-server.com/webhook",
"created": "2024-01-01T12:00:00.000Z",
"updated": "2024-01-01T12:00:00.000Z",
"delivered": false,
"last_delivery": null
}
Update Hook
Update an existing webhook.
PUT /-/npm/v1/hooks/hook/:id
Authentication
Required. Must be hook owner.
Parameters
id(string): Hook ID
Request Body
{
"endpoint": "https://new-webhook-endpoint.com/hook",
"secret": "new-secret-key"
}
Example Request
curl -X PUT \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{
"endpoint": "https://updated-server.com/webhook",
"secret": "updated-secret"
}' \
https://your-registry.com/-/npm/v1/hooks/hook/hook-uuid
Delete Hook
Remove a webhook.
DELETE /-/npm/v1/hooks/hook/:id
Authentication
Required. Must be hook owner.
Parameters
id(string): Hook ID
Example Request
curl -X DELETE \
-H "Authorization: Bearer your-token" \
https://your-registry.com/-/npm/v1/hooks/hook/hook-uuid
Response
{
"id": "hook-uuid",
"name": "my-webhook",
"type": "package",
"endpoint": "https://my-server.com/webhook",
"created": "2024-01-01T12:00:00.000Z",
"updated": "2024-01-01T12:00:00.000Z",
"deleted": "2024-01-01T13:00:00.000Z"
}
List Hooks
Get all hooks for the authenticated user.
GET /-/npm/v1/hooks
Authentication
Required.
Example Request
curl -H "Authorization: Bearer your-token" \
https://your-registry.com/-/npm/v1/hooks
Response
{
"objects": [
{
"id": "hook-uuid",
"name": "my-webhook",
"type": "package",
"endpoint": "https://my-server.com/webhook",
"created": "2024-01-01T12:00:00.000Z",
"updated": "2024-01-01T12:00:00.000Z",
"delivered": true,
"last_delivery": "2024-01-01T12:30:00.000Z"
}
]
}
Get Hook Details
Get details for a specific hook.
GET /-/npm/v1/hooks/hook/:id
Authentication
Required. Must be hook owner.
Parameters
id(string): Hook ID
Example Request
curl -H "Authorization: Bearer your-token" \
https://your-registry.com/-/npm/v1/hooks/hook/hook-uuid
User Management API
Manage user accounts and authentication.
Create User / Login
Create a new user account or login existing user.
PUT /-/user/org.couchdb.user::username
Parameters
username(string): Username to create/login
Request Body
{
"_id": "org.couchdb.user:username",
"name": "username",
"password": "user-password",
"email": "user@example.com",
"type": "user",
"roles": [],
"date": "2024-01-01T12:00:00.000Z"
}
Request Body Schema
| Field | Type | Required | Description |
|---|---|---|---|
_id |
string | Yes | Must be "org.couchdb.user:" + username |
name |
string | Yes | Username (1-100 chars) |
password |
string | Yes | Password (8-100 chars) |
email |
string | No | Email address (valid email format) |
type |
string | Yes | Must be "user" |
roles |
array | No | User roles (usually empty) |
date |
string | No | Registration date |
Example Request
curl -X PUT \
-H "Content-Type: application/json" \
-d '{
"_id": "org.couchdb.user:johndoe",
"name": "johndoe",
"password": "securepassword123",
"email": "john@example.com",
"type": "user",
"roles": []
}' \
https://your-registry.com/-/user/org.couchdb.user:johndoe
Response (Success - New User)
{
"ok": true,
"id": "org.couchdb.user:johndoe",
"rev": "1-hash",
"token": "user-token-uuid"
}
Response (Success - Login)
{
"ok": true,
"id": "org.couchdb.user:johndoe",
"rev": "existing-rev-hash",
"token": "user-token-uuid"
}
Error Responses
401 Unauthorized: Wrong password for existing user403 Forbidden: Public registration disabled409 Conflict: User exists but email differs422 Unprocessable Entity: Username mismatch in URL/body
Common Schemas
Error Response
All APIs return errors in a consistent format:
{
"error": "error_code",
"reason": "Human readable error message"
}
Common HTTP Status Codes
200 OK: Request successful201 Created: Resource created successfully400 Bad Request: Invalid request parameters401 Unauthorized: Authentication required or invalid403 Forbidden: Insufficient permissions404 Not Found: Resource not found409 Conflict: Resource already exists500 Internal Server Error: Server error
Package Naming
Package names follow npm naming conventions:
- Unscoped:
package-name - Scoped:
@scope/package-name - Must match regex:
^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$
Examples
Complete Sync Workflow
- Trigger sync for a package:
curl -X PUT \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{"tips": "API sync request"}' \
https://your-registry.com/-/package/lodash/syncs
- Check sync status:
curl -H "Authorization: Bearer your-token" \
https://your-registry.com/-/package/lodash/syncs/task-id
- View sync logs:
curl -H "Authorization: Bearer your-token" \
https://your-registry.com/-/package/lodash/syncs/task-id/log
Batch Operations
For multiple packages, send individual requests or implement your own batch processing script using these APIs.
Error Handling
Always check the HTTP status code and response body for errors:
response=$(curl -s -w "%{http_code}" -H "Authorization: Bearer token" \
https://your-registry.com/-/package/nonexistent/syncs)
http_code=$(echo "$response" | tail -c 4)
body=$(echo "$response" | sed 's/...$//')
if [ "$http_code" -ne 201 ]; then
echo "Error: $body"
exit 1
fi
Rate Limiting
Be mindful of rate limits when making multiple API requests. Consider implementing:
- Delays between requests
- Exponential backoff for retries
- Concurrent request limits
Security Considerations
- Always use HTTPS in production
- Store tokens securely and rotate them regularly
- Use read-only tokens when possible
- Implement IP whitelisting for sensitive operations
- Monitor API usage for unusual patterns
For more information about cnpmcore, visit the official documentation.