@push.rocks/smartregistry 1.4.1 → 1.6.0
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/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/classes.smartregistry.d.ts +2 -2
- package/dist_ts/classes.smartregistry.js +37 -2
- package/dist_ts/core/classes.authmanager.d.ts +55 -1
- package/dist_ts/core/classes.authmanager.js +138 -3
- package/dist_ts/core/classes.registrystorage.d.ts +145 -0
- package/dist_ts/core/classes.registrystorage.js +392 -1
- package/dist_ts/core/interfaces.core.d.ts +13 -1
- package/dist_ts/index.d.ts +3 -1
- package/dist_ts/index.js +6 -2
- package/dist_ts/pypi/classes.pypiregistry.d.ts +70 -0
- package/dist_ts/pypi/classes.pypiregistry.js +482 -0
- package/dist_ts/pypi/helpers.pypi.d.ts +84 -0
- package/dist_ts/pypi/helpers.pypi.js +263 -0
- package/dist_ts/pypi/index.d.ts +7 -0
- package/dist_ts/pypi/index.js +8 -0
- package/dist_ts/pypi/interfaces.pypi.d.ts +301 -0
- package/dist_ts/pypi/interfaces.pypi.js +6 -0
- package/dist_ts/rubygems/classes.rubygemsregistry.d.ts +86 -0
- package/dist_ts/rubygems/classes.rubygemsregistry.js +475 -0
- package/dist_ts/rubygems/helpers.rubygems.d.ts +143 -0
- package/dist_ts/rubygems/helpers.rubygems.js +312 -0
- package/dist_ts/rubygems/index.d.ts +7 -0
- package/dist_ts/rubygems/index.js +8 -0
- package/dist_ts/rubygems/interfaces.rubygems.d.ts +236 -0
- package/dist_ts/rubygems/interfaces.rubygems.js +6 -0
- package/package.json +2 -2
- package/readme.hints.md +438 -2
- package/readme.md +288 -13
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/classes.smartregistry.ts +41 -2
- package/ts/core/classes.authmanager.ts +161 -2
- package/ts/core/classes.registrystorage.ts +463 -0
- package/ts/core/interfaces.core.ts +13 -1
- package/ts/index.ts +7 -1
- package/ts/pypi/classes.pypiregistry.ts +580 -0
- package/ts/pypi/helpers.pypi.ts +299 -0
- package/ts/pypi/index.ts +8 -0
- package/ts/pypi/interfaces.pypi.ts +316 -0
- package/ts/rubygems/classes.rubygemsregistry.ts +598 -0
- package/ts/rubygems/helpers.rubygems.ts +398 -0
- package/ts/rubygems/index.ts +8 -0
- package/ts/rubygems/interfaces.rubygems.ts +251 -0
package/readme.hints.md
CHANGED
|
@@ -1,3 +1,439 @@
|
|
|
1
|
-
# Project
|
|
1
|
+
# Project Implementation Notes
|
|
2
2
|
|
|
3
|
-
This
|
|
3
|
+
This file contains technical implementation details for PyPI and RubyGems protocols.
|
|
4
|
+
|
|
5
|
+
## Python (PyPI) Protocol Implementation ✅
|
|
6
|
+
|
|
7
|
+
### PEP 503: Simple Repository API (HTML-based)
|
|
8
|
+
|
|
9
|
+
**URL Structure:**
|
|
10
|
+
- Root: `/<base>/` - Lists all projects
|
|
11
|
+
- Project: `/<base>/<project>/` - Lists all files for a project
|
|
12
|
+
- All URLs MUST end with `/` (redirect if missing)
|
|
13
|
+
|
|
14
|
+
**Package Name Normalization:**
|
|
15
|
+
- Lowercase all characters
|
|
16
|
+
- Replace runs of `.`, `-`, `_` with single `-`
|
|
17
|
+
- Implementation: `re.sub(r"[-_.]+", "-", name).lower()`
|
|
18
|
+
|
|
19
|
+
**HTML Format:**
|
|
20
|
+
- Root: One anchor per project
|
|
21
|
+
- Project: One anchor per file
|
|
22
|
+
- Anchor text must match final filename
|
|
23
|
+
- Anchor href links to download URL
|
|
24
|
+
|
|
25
|
+
**Hash Fragments:**
|
|
26
|
+
Format: `#<hashname>=<hashvalue>`
|
|
27
|
+
- hashname: lowercase hash function name (recommend `sha256`)
|
|
28
|
+
- hashvalue: hex-encoded digest
|
|
29
|
+
|
|
30
|
+
**Data Attributes:**
|
|
31
|
+
- `data-gpg-sig`: `true`/`false` for GPG signature presence
|
|
32
|
+
- `data-requires-python`: PEP 345 requirement string (HTML-encode `<` as `<`, `>` as `>`)
|
|
33
|
+
|
|
34
|
+
### PEP 691: JSON-based Simple API
|
|
35
|
+
|
|
36
|
+
**Content Types:**
|
|
37
|
+
- `application/vnd.pypi.simple.v1+json` - JSON format
|
|
38
|
+
- `application/vnd.pypi.simple.v1+html` - HTML format
|
|
39
|
+
- `text/html` - Alias for HTML (backwards compat)
|
|
40
|
+
|
|
41
|
+
**Root Endpoint JSON:**
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"meta": {"api-version": "1.0"},
|
|
45
|
+
"projects": [{"name": "ProjectName"}]
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Project Endpoint JSON:**
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"name": "normalized-name",
|
|
53
|
+
"meta": {"api-version": "1.0"},
|
|
54
|
+
"files": [
|
|
55
|
+
{
|
|
56
|
+
"filename": "package-1.0-py3-none-any.whl",
|
|
57
|
+
"url": "https://example.com/path/to/file",
|
|
58
|
+
"hashes": {"sha256": "..."},
|
|
59
|
+
"requires-python": ">=3.7",
|
|
60
|
+
"dist-info-metadata": true | {"sha256": "..."},
|
|
61
|
+
"gpg-sig": true,
|
|
62
|
+
"yanked": false | "reason string"
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Content Negotiation:**
|
|
69
|
+
- Use `Accept` header for format selection
|
|
70
|
+
- Server responds with `Content-Type` header
|
|
71
|
+
- Support both JSON and HTML formats
|
|
72
|
+
|
|
73
|
+
### PyPI Upload API (Legacy /legacy/)
|
|
74
|
+
|
|
75
|
+
**Endpoint:**
|
|
76
|
+
- URL: `https://upload.pypi.org/legacy/`
|
|
77
|
+
- Method: `POST`
|
|
78
|
+
- Content-Type: `multipart/form-data`
|
|
79
|
+
|
|
80
|
+
**Required Form Fields:**
|
|
81
|
+
- `:action` = `file_upload`
|
|
82
|
+
- `protocol_version` = `1`
|
|
83
|
+
- `content` = Binary file data with filename
|
|
84
|
+
- `filetype` = `bdist_wheel` | `sdist`
|
|
85
|
+
- `pyversion` = Python tag (e.g., `py3`, `py2.py3`) or `source` for sdist
|
|
86
|
+
- `metadata_version` = Metadata standard version
|
|
87
|
+
- `name` = Package name
|
|
88
|
+
- `version` = Version string
|
|
89
|
+
|
|
90
|
+
**Hash Digest (one required):**
|
|
91
|
+
- `md5_digest`: urlsafe base64 without padding
|
|
92
|
+
- `sha256_digest`: hexadecimal
|
|
93
|
+
- `blake2_256_digest`: hexadecimal
|
|
94
|
+
|
|
95
|
+
**Optional Fields:**
|
|
96
|
+
- `attestations`: JSON array of attestation objects
|
|
97
|
+
- Any Core Metadata fields (lowercase, hyphens → underscores)
|
|
98
|
+
- Example: `Description-Content-Type` → `description_content_type`
|
|
99
|
+
|
|
100
|
+
**Authentication:**
|
|
101
|
+
- Username/password or API token in HTTP Basic Auth
|
|
102
|
+
- API tokens: username = `__token__`, password = token value
|
|
103
|
+
|
|
104
|
+
**Behavior:**
|
|
105
|
+
- First file uploaded creates the release
|
|
106
|
+
- Multiple files uploaded sequentially for same version
|
|
107
|
+
|
|
108
|
+
### PEP 694: Upload 2.0 API
|
|
109
|
+
|
|
110
|
+
**Status:** Draft (not yet required, legacy API still supported)
|
|
111
|
+
- Multi-step workflow with sessions
|
|
112
|
+
- Async upload support with resumption
|
|
113
|
+
- JSON-based API
|
|
114
|
+
- Standard HTTP auth (RFC 7235)
|
|
115
|
+
- Not implementing initially (legacy API sufficient)
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Ruby (RubyGems) Protocol Implementation ✅
|
|
120
|
+
|
|
121
|
+
### Compact Index Format
|
|
122
|
+
|
|
123
|
+
**Endpoints:**
|
|
124
|
+
- `/versions` - Master list of all gems and versions
|
|
125
|
+
- `/info/<RUBYGEM>` - Detailed info for specific gem
|
|
126
|
+
- `/names` - Simple list of gem names
|
|
127
|
+
|
|
128
|
+
**Authentication:**
|
|
129
|
+
- UUID tokens similar to NPM pattern
|
|
130
|
+
- API key in `Authorization` header
|
|
131
|
+
- Scope format: `rubygems:gem:{name}:{read|write|yank}`
|
|
132
|
+
|
|
133
|
+
### `/versions` File Format
|
|
134
|
+
|
|
135
|
+
**Structure:**
|
|
136
|
+
```
|
|
137
|
+
created_at: 2024-04-01T00:00:05Z
|
|
138
|
+
---
|
|
139
|
+
RUBYGEM [-]VERSION_PLATFORM[,VERSION_PLATFORM,...] MD5
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Details:**
|
|
143
|
+
- Metadata lines before `---` delimiter
|
|
144
|
+
- One line per gem with comma-separated versions
|
|
145
|
+
- `[-]` prefix indicates yanked version
|
|
146
|
+
- `MD5`: Checksum of corresponding `/info/<RUBYGEM>` file
|
|
147
|
+
- Append-only during month, recalculated monthly
|
|
148
|
+
|
|
149
|
+
### `/info/<RUBYGEM>` File Format
|
|
150
|
+
|
|
151
|
+
**Structure:**
|
|
152
|
+
```
|
|
153
|
+
---
|
|
154
|
+
VERSION[-PLATFORM] [DEPENDENCY[,DEPENDENCY,...]]|REQUIREMENT[,REQUIREMENT,...]
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Dependency Format:**
|
|
158
|
+
```
|
|
159
|
+
GEM:CONSTRAINT[&CONSTRAINT]
|
|
160
|
+
```
|
|
161
|
+
- Examples: `actionmailer:= 2.2.2`, `parser:>= 3.2.2.3`
|
|
162
|
+
- Operators: `=`, `>`, `<`, `>=`, `<=`, `~>`, `!=`
|
|
163
|
+
- Multiple constraints: `unicode-display_width:< 3.0&>= 2.4.0`
|
|
164
|
+
|
|
165
|
+
**Requirement Format:**
|
|
166
|
+
```
|
|
167
|
+
checksum:SHA256_HEX
|
|
168
|
+
ruby:CONSTRAINT
|
|
169
|
+
rubygems:CONSTRAINT
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Platform:**
|
|
173
|
+
- Default platform is `ruby`
|
|
174
|
+
- Non-default platforms: `VERSION-PLATFORM` (e.g., `3.2.1-arm64-darwin`)
|
|
175
|
+
|
|
176
|
+
**Yanked Gems:**
|
|
177
|
+
- Listed with `-` prefix in `/versions`
|
|
178
|
+
- Excluded entirely from `/info/<RUBYGEM>` file
|
|
179
|
+
|
|
180
|
+
### `/names` File Format
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
---
|
|
184
|
+
gemname1
|
|
185
|
+
gemname2
|
|
186
|
+
gemname3
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### HTTP Range Support
|
|
190
|
+
|
|
191
|
+
**Headers:**
|
|
192
|
+
- `Range: bytes=#{start}-`: Request from byte position
|
|
193
|
+
- `If-None-Match`: ETag conditional request
|
|
194
|
+
- `Repr-Digest`: SHA256 checksum in response
|
|
195
|
+
|
|
196
|
+
**Caching Strategy:**
|
|
197
|
+
1. Store file with last byte position
|
|
198
|
+
2. Request range from last position
|
|
199
|
+
3. Append response to existing file
|
|
200
|
+
4. Verify SHA256 against `Repr-Digest`
|
|
201
|
+
|
|
202
|
+
### RubyGems Upload/Management API
|
|
203
|
+
|
|
204
|
+
**Upload Gem:**
|
|
205
|
+
- `POST /api/v1/gems`
|
|
206
|
+
- Binary `.gem` file in request body
|
|
207
|
+
- `Authorization` header with API key
|
|
208
|
+
|
|
209
|
+
**Yank Version:**
|
|
210
|
+
- `DELETE /api/v1/gems/yank`
|
|
211
|
+
- Parameters: `gem_name`, `version`
|
|
212
|
+
|
|
213
|
+
**Unyank Version:**
|
|
214
|
+
- `PUT /api/v1/gems/unyank`
|
|
215
|
+
- Parameters: `gem_name`, `version`
|
|
216
|
+
|
|
217
|
+
**Version Metadata:**
|
|
218
|
+
- `GET /api/v1/versions/<gem>.json`
|
|
219
|
+
- Returns JSON array of versions
|
|
220
|
+
|
|
221
|
+
**Dependencies:**
|
|
222
|
+
- `GET /api/v1/dependencies?gems=<comma-list>`
|
|
223
|
+
- Returns dependency information for resolution
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Implementation Details
|
|
228
|
+
|
|
229
|
+
### Completed Protocols
|
|
230
|
+
- ✅ OCI Distribution Spec v1.1
|
|
231
|
+
- ✅ NPM Registry API
|
|
232
|
+
- ✅ Maven Repository
|
|
233
|
+
- ✅ Cargo/crates.io Registry
|
|
234
|
+
- ✅ Composer/Packagist
|
|
235
|
+
- ✅ PyPI (Python Package Index) - PEP 503/691
|
|
236
|
+
- ✅ RubyGems - Compact Index
|
|
237
|
+
|
|
238
|
+
### Storage Paths
|
|
239
|
+
|
|
240
|
+
**PyPI:**
|
|
241
|
+
```
|
|
242
|
+
pypi/
|
|
243
|
+
├── simple/ # PEP 503 HTML files
|
|
244
|
+
│ ├── index.html # All packages list
|
|
245
|
+
│ └── {package}/index.html # Package versions list
|
|
246
|
+
├── packages/
|
|
247
|
+
│ └── {package}/{filename} # .whl and .tar.gz files
|
|
248
|
+
└── metadata/
|
|
249
|
+
└── {package}/metadata.json # Package metadata
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**RubyGems:**
|
|
253
|
+
```
|
|
254
|
+
rubygems/
|
|
255
|
+
├── versions # Master versions file
|
|
256
|
+
├── info/{gemname} # Per-gem info files
|
|
257
|
+
├── names # All gem names
|
|
258
|
+
└── gems/{gemname}-{version}.gem # .gem files
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Authentication Pattern
|
|
262
|
+
|
|
263
|
+
Both protocols should follow the existing UUID token pattern used by NPM, Maven, Cargo, Composer:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// AuthManager additions
|
|
267
|
+
createPypiToken(userId: string, readonly: boolean): string
|
|
268
|
+
validatePypiToken(token: string): ITokenInfo | null
|
|
269
|
+
revokePypiToken(token: string): boolean
|
|
270
|
+
|
|
271
|
+
createRubyGemsToken(userId: string, readonly: boolean): string
|
|
272
|
+
validateRubyGemsToken(token: string): ITokenInfo | null
|
|
273
|
+
revokeRubyGemsToken(token: string): boolean
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Scope Format
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
pypi:package:{name}:{read|write}
|
|
280
|
+
rubygems:gem:{name}:{read|write|yank}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Common Patterns
|
|
284
|
+
|
|
285
|
+
1. **Package name normalization** - Critical for PyPI
|
|
286
|
+
2. **Checksum calculation** - SHA256 for both protocols
|
|
287
|
+
3. **Append-only files** - RubyGems compact index
|
|
288
|
+
4. **Content negotiation** - PyPI JSON vs HTML
|
|
289
|
+
5. **Multipart upload parsing** - PyPI file uploads
|
|
290
|
+
6. **Binary file handling** - Both protocols (.whl, .tar.gz, .gem)
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Key Differences from Existing Protocols
|
|
295
|
+
|
|
296
|
+
**PyPI vs NPM:**
|
|
297
|
+
- PyPI uses Simple API (HTML) + JSON API
|
|
298
|
+
- PyPI requires package name normalization
|
|
299
|
+
- PyPI uses multipart form data for uploads (not JSON)
|
|
300
|
+
- PyPI supports multiple file types per release (wheel + sdist)
|
|
301
|
+
|
|
302
|
+
**RubyGems vs Cargo:**
|
|
303
|
+
- RubyGems uses compact index (append-only text files)
|
|
304
|
+
- RubyGems uses checksums in index files (not just filenames)
|
|
305
|
+
- RubyGems has HTTP Range support for incremental updates
|
|
306
|
+
- RubyGems uses MD5 for index checksums, SHA256 for .gem files
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Testing Requirements
|
|
311
|
+
|
|
312
|
+
### PyPI Tests Must Cover:
|
|
313
|
+
- Package upload (wheel and sdist)
|
|
314
|
+
- Package name normalization
|
|
315
|
+
- Simple API HTML generation (PEP 503)
|
|
316
|
+
- JSON API responses (PEP 691)
|
|
317
|
+
- Content negotiation
|
|
318
|
+
- Hash calculation and verification
|
|
319
|
+
- Authentication (tokens)
|
|
320
|
+
- Multi-file releases
|
|
321
|
+
- Yanked packages
|
|
322
|
+
|
|
323
|
+
### RubyGems Tests Must Cover:
|
|
324
|
+
- Gem upload
|
|
325
|
+
- Compact index generation
|
|
326
|
+
- `/versions` file updates (append-only)
|
|
327
|
+
- `/info/<gem>` file generation
|
|
328
|
+
- `/names` file generation
|
|
329
|
+
- Checksum calculations (MD5 and SHA256)
|
|
330
|
+
- Platform-specific gems
|
|
331
|
+
- Yanking/unyanking
|
|
332
|
+
- HTTP Range requests
|
|
333
|
+
- Authentication (API keys)
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Security Considerations
|
|
338
|
+
|
|
339
|
+
1. **Package name validation** - Prevent path traversal
|
|
340
|
+
2. **File size limits** - Prevent DoS via large uploads
|
|
341
|
+
3. **Content-Type validation** - Verify file types
|
|
342
|
+
4. **Checksum verification** - Ensure file integrity
|
|
343
|
+
5. **Token scope enforcement** - Read vs write permissions
|
|
344
|
+
6. **HTML escaping** - Prevent XSS in generated HTML
|
|
345
|
+
7. **Metadata sanitization** - Clean user-provided strings
|
|
346
|
+
8. **Rate limiting** - Consider upload frequency limits
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Implementation Status (Completed)
|
|
351
|
+
|
|
352
|
+
### PyPI Implementation ✅
|
|
353
|
+
- **Files Created:**
|
|
354
|
+
- `ts/pypi/interfaces.pypi.ts` - Type definitions (354 lines)
|
|
355
|
+
- `ts/pypi/helpers.pypi.ts` - Helper functions (280 lines)
|
|
356
|
+
- `ts/pypi/classes.pypiregistry.ts` - Main registry (650 lines)
|
|
357
|
+
- `ts/pypi/index.ts` - Module exports
|
|
358
|
+
|
|
359
|
+
- **Features Implemented:**
|
|
360
|
+
- ✅ PEP 503 Simple API (HTML)
|
|
361
|
+
- ✅ PEP 691 JSON API
|
|
362
|
+
- ✅ Content negotiation (Accept header)
|
|
363
|
+
- ✅ Package name normalization
|
|
364
|
+
- ✅ File upload with multipart/form-data
|
|
365
|
+
- ✅ Hash verification (SHA256, MD5, Blake2b)
|
|
366
|
+
- ✅ Package metadata management
|
|
367
|
+
- ✅ JSON API endpoints (/pypi/{package}/json)
|
|
368
|
+
- ✅ Token-based authentication
|
|
369
|
+
- ✅ Scope-based permissions (read/write/delete)
|
|
370
|
+
|
|
371
|
+
- **Security Enhancements:**
|
|
372
|
+
- ✅ Hash verification on upload (validates client-provided hashes)
|
|
373
|
+
- ✅ Package name validation (regex check)
|
|
374
|
+
- ✅ HTML escaping in generated pages
|
|
375
|
+
- ✅ Permission checks on all mutating operations
|
|
376
|
+
|
|
377
|
+
### RubyGems Implementation ✅
|
|
378
|
+
- **Files Created:**
|
|
379
|
+
- `ts/rubygems/interfaces.rubygems.ts` - Type definitions (215 lines)
|
|
380
|
+
- `ts/rubygems/helpers.rubygems.ts` - Helper functions (350 lines)
|
|
381
|
+
- `ts/rubygems/classes.rubygemsregistry.ts` - Main registry (580 lines)
|
|
382
|
+
- `ts/rubygems/index.ts` - Module exports
|
|
383
|
+
|
|
384
|
+
- **Features Implemented:**
|
|
385
|
+
- ✅ Compact Index format (modern Bundler)
|
|
386
|
+
- ✅ /versions endpoint (all gems list)
|
|
387
|
+
- ✅ /info/{gem} endpoint (gem-specific metadata)
|
|
388
|
+
- ✅ /names endpoint (gem names list)
|
|
389
|
+
- ✅ Gem upload API
|
|
390
|
+
- ✅ Yank/unyank functionality
|
|
391
|
+
- ✅ Platform-specific gems support
|
|
392
|
+
- ✅ JSON API endpoints
|
|
393
|
+
- ✅ Legacy endpoints (specs.4.8.gz, Marshal.4.8)
|
|
394
|
+
- ✅ Token-based authentication
|
|
395
|
+
- ✅ Scope-based permissions
|
|
396
|
+
|
|
397
|
+
### Integration ✅
|
|
398
|
+
- **Core Updates:**
|
|
399
|
+
- ✅ Updated `IRegistryConfig` interface
|
|
400
|
+
- ✅ Updated `TRegistryProtocol` type
|
|
401
|
+
- ✅ Added authentication methods to `AuthManager`
|
|
402
|
+
- ✅ Added 30+ storage methods to `RegistryStorage`
|
|
403
|
+
- ✅ Updated `SmartRegistry` initialization and routing
|
|
404
|
+
- ✅ Module exports from `ts/index.ts`
|
|
405
|
+
|
|
406
|
+
- **Test Coverage:**
|
|
407
|
+
- ✅ `test/test.pypi.ts` - 25+ tests covering all PyPI endpoints
|
|
408
|
+
- ✅ `test/test.rubygems.ts` - 30+ tests covering all RubyGems endpoints
|
|
409
|
+
- ✅ `test/test.integration.pypi-rubygems.ts` - Integration tests
|
|
410
|
+
- ✅ Updated test helpers with PyPI and RubyGems support
|
|
411
|
+
|
|
412
|
+
### Known Limitations
|
|
413
|
+
1. **PyPI:**
|
|
414
|
+
- Does not implement legacy XML-RPC API
|
|
415
|
+
- No support for PGP signatures (data-gpg-sig always false)
|
|
416
|
+
- Metadata extraction from wheel files not implemented
|
|
417
|
+
|
|
418
|
+
2. **RubyGems:**
|
|
419
|
+
- Gem spec extraction from .gem files returns placeholder (Ruby Marshal parsing not implemented)
|
|
420
|
+
- Legacy Marshal endpoints return basic data only
|
|
421
|
+
- No support for gem dependencies resolution
|
|
422
|
+
|
|
423
|
+
### Configuration Example
|
|
424
|
+
```typescript
|
|
425
|
+
{
|
|
426
|
+
pypi: {
|
|
427
|
+
enabled: true,
|
|
428
|
+
basePath: '/pypi', // Also handles /simple
|
|
429
|
+
},
|
|
430
|
+
rubygems: {
|
|
431
|
+
enabled: true,
|
|
432
|
+
basePath: '/rubygems',
|
|
433
|
+
},
|
|
434
|
+
auth: {
|
|
435
|
+
pypiTokens: { enabled: true },
|
|
436
|
+
rubygemsTokens: { enabled: true },
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
```
|