@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.
Files changed (3) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +316 -0
  3. 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
+ }