@stacksjs/registry 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +316 -0
- package/package.json +35 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Open Web Foundation
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
# @stacksjs/registry
|
|
2
|
+
|
|
3
|
+
Pantry package registry backend. A simple, fast package registry that works with the Pantry CLI.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **npm-compatible API** - Works with the Pantry CLI out of the box
|
|
8
|
+
- **npm fallback** - Packages not in the registry fall back to npmjs automatically
|
|
9
|
+
- **Zig package support** - Host Zig packages with content-addressed hashing
|
|
10
|
+
- **S3 storage** - Tarball storage via S3 (or local filesystem for development)
|
|
11
|
+
- **Analytics** - Track download counts and package statistics
|
|
12
|
+
- **Simple metadata** - JSON file or DynamoDB for package metadata
|
|
13
|
+
- **Zero config** - Works out of the box for local development
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Start the registry server
|
|
19
|
+
bun run start
|
|
20
|
+
|
|
21
|
+
# Or in development mode with hot reload
|
|
22
|
+
bun run dev
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The server will start at `<http://localhost:3000>`.
|
|
26
|
+
|
|
27
|
+
## API Endpoints
|
|
28
|
+
|
|
29
|
+
### npm-compatible Packages
|
|
30
|
+
|
|
31
|
+
| Method | Endpoint | Description |
|
|
32
|
+
|--------|----------|-------------|
|
|
33
|
+
| GET | `/packages/{name}` | Get latest package metadata |
|
|
34
|
+
| GET | `/packages/{name}/{version}` | Get specific version metadata |
|
|
35
|
+
| GET | `/packages/{name}/{version}/tarball` | Download package tarball |
|
|
36
|
+
| GET | `/packages/{name}/versions` | List all versions |
|
|
37
|
+
| GET | `/search?q={query}` | Search packages |
|
|
38
|
+
| POST | `/publish` | Publish a package |
|
|
39
|
+
|
|
40
|
+
### Analytics
|
|
41
|
+
|
|
42
|
+
| Method | Endpoint | Description |
|
|
43
|
+
|--------|----------|-------------|
|
|
44
|
+
| GET | `/analytics/top` | Top downloaded packages |
|
|
45
|
+
| GET | `/analytics/{name}` | Package download stats |
|
|
46
|
+
| GET | `/analytics/{name}/timeline` | Download history (30 days) |
|
|
47
|
+
|
|
48
|
+
### Commit Packages (pkg-pr-new equivalent)
|
|
49
|
+
|
|
50
|
+
| Method | Endpoint | Description |
|
|
51
|
+
|--------|----------|-------------|
|
|
52
|
+
| POST | `/publish/commit` | Publish packages from a git commit |
|
|
53
|
+
| GET | `/commits/{sha}` | List all packages for a commit |
|
|
54
|
+
| GET | `/commits/{sha}/{name}` | Get commit package metadata |
|
|
55
|
+
| GET | `/commits/{sha}/{name}/tarball` | Download commit package tarball |
|
|
56
|
+
|
|
57
|
+
### Zig Packages
|
|
58
|
+
|
|
59
|
+
| Method | Endpoint | Description |
|
|
60
|
+
|--------|----------|-------------|
|
|
61
|
+
| GET | `/zig/packages/{name}` | Get Zig package metadata |
|
|
62
|
+
| GET | `/zig/packages/{name}/{version}` | Get specific version |
|
|
63
|
+
| GET | `/zig/packages/{name}/{version}/tarball` | Download tarball |
|
|
64
|
+
| GET | `/zig/packages/{name}/versions` | List all versions |
|
|
65
|
+
| GET | `/zig/hash/{hash}` | Lookup package by content hash |
|
|
66
|
+
| GET | `/zig/search?q={query}` | Search Zig packages |
|
|
67
|
+
| POST | `/zig/publish` | Publish a Zig package |
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
The registry can be configured via environment variables:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Server port
|
|
75
|
+
PORT=3000
|
|
76
|
+
|
|
77
|
+
# Base URL for tarball URLs
|
|
78
|
+
BASE_URL=https://registry.example.com
|
|
79
|
+
|
|
80
|
+
# S3 configuration (for production)
|
|
81
|
+
S3_BUCKET=my-registry-bucket
|
|
82
|
+
S3_REGION=us-east-1
|
|
83
|
+
|
|
84
|
+
# DynamoDB configuration (for production)
|
|
85
|
+
DYNAMODB_TABLE=registry-packages
|
|
86
|
+
DYNAMODB_ANALYTICS_TABLE=registry-analytics
|
|
87
|
+
|
|
88
|
+
# AWS credentials
|
|
89
|
+
AWS_ACCESS_KEY_ID=your-key
|
|
90
|
+
AWS_SECRET_ACCESS_KEY=your-secret
|
|
91
|
+
AWS_REGION=us-east-1
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Publishing npm Packages
|
|
95
|
+
|
|
96
|
+
To publish a package, send a `POST` request to `/publish` with:
|
|
97
|
+
|
|
98
|
+
**Multipart/form-data:**
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
curl -X POST http://localhost:3000/publish \
|
|
102
|
+
-H "Authorization: Bearer your-token" \
|
|
103
|
+
-F "metadata={\"name\":\"my-package\",\"version\":\"1.0.0\"}" \
|
|
104
|
+
-F "tarball=@my-package-1.0.0.tgz"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**JSON with base64 tarball:**
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
curl -X POST http://localhost:3000/publish \
|
|
111
|
+
-H "Authorization: Bearer your-token" \
|
|
112
|
+
-H "Content-Type: application/json" \
|
|
113
|
+
-d '{"metadata":{"name":"my-package","version":"1.0.0"},"tarball":"<base64-encoded-tarball>"}'
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Publishing Zig Packages
|
|
117
|
+
|
|
118
|
+
Zig packages are content-addressed - they're identified by their hash, not URL.
|
|
119
|
+
|
|
120
|
+
**Publish a Zig package:**
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
curl -X POST http://localhost:3000/zig/publish \
|
|
124
|
+
-H "Authorization: Bearer your-token" \
|
|
125
|
+
-F "tarball=@my-zig-lib-1.0.0.tar.gz" \
|
|
126
|
+
-F "manifest=$(cat build.zig.zon)" \
|
|
127
|
+
-F "description=My awesome Zig library"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Response includes everything needed for dependencies:**
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"success": true,
|
|
135
|
+
"hash": "12209f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
|
|
136
|
+
"tarballUrl": "http://localhost:3000/zig/packages/my-zig-lib/1.0.0/tarball",
|
|
137
|
+
"fetchCommand": "zig fetch --save http://localhost:3000/zig/packages/my-zig-lib/1.0.0/tarball",
|
|
138
|
+
"dependency": ".my_zig_lib = .{\n .url = \"http://...\",\n .hash = \"1220...\",\n},"
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Using in build.zig.zon:**
|
|
143
|
+
|
|
144
|
+
```zig
|
|
145
|
+
.dependencies = .{
|
|
146
|
+
.my_zig_lib = .{
|
|
147
|
+
.url = "https://registry.example.com/zig/packages/my-zig-lib/1.0.0/tarball",
|
|
148
|
+
.hash = "12209f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Or fetch directly:**
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
zig fetch --save https://registry.example.com/zig/packages/my-zig-lib/1.0.0/tarball
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Publishing Commit Packages
|
|
160
|
+
|
|
161
|
+
Publish packages from a specific git commit — equivalent to `pkg-pr-new publish`. Packages are stored temporarily (90-day expiry) and can be installed directly by commit SHA.
|
|
162
|
+
|
|
163
|
+
**Multipart/form-data (multiple packages):**
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
curl -X POST http://localhost:3000/publish/commit \
|
|
167
|
+
-H "Authorization: Bearer your-token" \
|
|
168
|
+
-F "sha=abc1234def5678" \
|
|
169
|
+
-F "repository=https://github.com/org/repo" \
|
|
170
|
+
-F "package:my-package=@my-package.tgz" \
|
|
171
|
+
-F "package:@scope/other=@other-package.tgz"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**JSON with base64 tarball:**
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
curl -X POST http://localhost:3000/publish/commit \
|
|
178
|
+
-H "Authorization: Bearer your-token" \
|
|
179
|
+
-H "Content-Type: application/json" \
|
|
180
|
+
-d '{
|
|
181
|
+
"sha": "abc1234def5678",
|
|
182
|
+
"name": "my-package",
|
|
183
|
+
"tarball": "<base64-encoded-tarball>",
|
|
184
|
+
"repository": "https://github.com/org/repo"
|
|
185
|
+
}'
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Installing a commit package:**
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npm install https://registry.example.com/commits/abc1234def5678/my-package/tarball
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Listing packages for a commit:**
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
curl http://localhost:3000/commits/abc1234def5678
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Infrastructure note:** Commit packages are stored under the `commits/` S3 prefix and automatically expire after 90 days via an S3 lifecycle rule.
|
|
201
|
+
|
|
202
|
+
## npm Fallback
|
|
203
|
+
|
|
204
|
+
When a package is not found in the registry, it automatically falls back to npmjs.org. This allows you to:
|
|
205
|
+
|
|
206
|
+
1. Use your own packages from your registry
|
|
207
|
+
2. Use any npm package without mirroring
|
|
208
|
+
|
|
209
|
+
## Programmatic Usage
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { Registry, createLocalRegistry, createServer } from '@stacksjs/registry'
|
|
213
|
+
|
|
214
|
+
// Create a local development registry
|
|
215
|
+
const registry = createLocalRegistry('http://localhost:3000')
|
|
216
|
+
|
|
217
|
+
// Or configure for production
|
|
218
|
+
const registry = new Registry({
|
|
219
|
+
s3Bucket: 'my-bucket',
|
|
220
|
+
s3Region: 'us-east-1',
|
|
221
|
+
dynamoTable: 'registry-packages',
|
|
222
|
+
baseUrl: 'https://registry.example.com',
|
|
223
|
+
npmFallback: true,
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
// Start the server
|
|
227
|
+
const { start, stop } = createServer(registry, 3000)
|
|
228
|
+
start()
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Storage Backends
|
|
232
|
+
|
|
233
|
+
### Local Storage (Development)
|
|
234
|
+
|
|
235
|
+
By default, the registry uses local file storage:
|
|
236
|
+
|
|
237
|
+
- Tarballs: `./.registry/tarballs/`
|
|
238
|
+
- Metadata: `./.registry/metadata.json`
|
|
239
|
+
|
|
240
|
+
### S3 Storage (Production)
|
|
241
|
+
|
|
242
|
+
Configure S3 for production tarball storage:
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
import { S3Storage } from '@stacksjs/registry'
|
|
246
|
+
|
|
247
|
+
const storage = new S3Storage('my-bucket', 'us-east-1')
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Deployment
|
|
251
|
+
|
|
252
|
+
### AWS Infrastructure
|
|
253
|
+
|
|
254
|
+
Deploy the required AWS resources using CloudFormation:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
aws cloudformation deploy \
|
|
258
|
+
--template-file infrastructure/cloudformation.yml \
|
|
259
|
+
--stack-name pantry-registry \
|
|
260
|
+
--parameter-overrides \
|
|
261
|
+
Environment=production \
|
|
262
|
+
RegistryDomain=registry.yourdomain.com \
|
|
263
|
+
--capabilities CAPABILITY_NAMED_IAM
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
This creates:
|
|
267
|
+
|
|
268
|
+
- S3 bucket for package tarballs
|
|
269
|
+
- DynamoDB table for metadata
|
|
270
|
+
- DynamoDB table for analytics
|
|
271
|
+
- IAM role with required permissions
|
|
272
|
+
|
|
273
|
+
### Docker Deployment
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
# Build
|
|
277
|
+
docker build -t pantry-registry .
|
|
278
|
+
|
|
279
|
+
# Run with environment variables
|
|
280
|
+
docker run -d \
|
|
281
|
+
-p 3000:3000 \
|
|
282
|
+
-e S3_BUCKET=pantry-registry-production-packages \
|
|
283
|
+
-e DYNAMODB_TABLE=pantry-registry-production-metadata \
|
|
284
|
+
-e DYNAMODB_ANALYTICS_TABLE=pantry-registry-production-analytics \
|
|
285
|
+
-e BASE_URL=https://registry.yourdomain.com \
|
|
286
|
+
-e AWS_REGION=us-east-1 \
|
|
287
|
+
-e AWS_ACCESS_KEY_ID=your-key \
|
|
288
|
+
-e AWS_SECRET_ACCESS_KEY=your-secret \
|
|
289
|
+
pantry-registry
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Environment Variables
|
|
293
|
+
|
|
294
|
+
| Variable | Description | Default |
|
|
295
|
+
|----------|-------------|---------|
|
|
296
|
+
| `PORT` | Server port | `3000` |
|
|
297
|
+
| `BASE_URL` | Public URL for the registry | `<http://localhost:3000>` |
|
|
298
|
+
| `S3_BUCKET` | S3 bucket for tarballs | `local` (file storage) |
|
|
299
|
+
| `DYNAMODB_TABLE` | DynamoDB table for metadata | `local` (file storage) |
|
|
300
|
+
| `DYNAMODB_ANALYTICS_TABLE` | DynamoDB table for analytics | (in-memory) |
|
|
301
|
+
| `AWS_REGION` | AWS region | `us-east-1` |
|
|
302
|
+
| `NPM_FALLBACK` | Enable npm fallback | `true` |
|
|
303
|
+
|
|
304
|
+
### Local Development
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# Start with file-based storage (default)
|
|
308
|
+
bun run dev
|
|
309
|
+
|
|
310
|
+
# Or with specific config
|
|
311
|
+
S3_BUCKET=local DYNAMODB_TABLE=local bun run start
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## License
|
|
315
|
+
|
|
316
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stacksjs/registry",
|
|
3
|
+
"version": "0.8.4",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Pantry package registry backend - S3 storage with DynamoDB metadata",
|
|
6
|
+
"author": "Stacks.js",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"types": "dist/index.d.ts",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "bun build ./src/index.ts --outdir ./dist --target bun",
|
|
21
|
+
"dev": "bun run --watch src/server.ts",
|
|
22
|
+
"start": "bun run src/server.ts",
|
|
23
|
+
"test": "bun test",
|
|
24
|
+
"test:analytics": "bun test src/analytics.test.ts",
|
|
25
|
+
"test:commit-publish": "bun test src/commit-publish.test.ts",
|
|
26
|
+
"typecheck": "bun --bun tsc --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@cwcss/crosswind": "^0.1.6"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"bun-types": "latest",
|
|
33
|
+
"typescript": "^5.7.0"
|
|
34
|
+
}
|
|
35
|
+
}
|