@push.rocks/smartregistry 1.4.0 → 1.5.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 +1 -1
- package/dist_ts/composer/classes.composerregistry.js +3 -17
- 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 +68 -0
- package/dist_ts/core/classes.registrystorage.js +195 -1
- package/dist_ts/core/interfaces.core.d.ts +13 -1
- package/dist_ts/pypi/classes.pypiregistry.d.ts +70 -0
- package/dist_ts/pypi/classes.pypiregistry.js +470 -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/package.json +1 -1
- package/readme.hints.md +333 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/composer/classes.composerregistry.ts +2 -18
- package/ts/core/classes.authmanager.ts +161 -2
- package/ts/core/classes.registrystorage.ts +227 -0
- package/ts/core/interfaces.core.ts +13 -1
- package/ts/pypi/classes.pypiregistry.ts +564 -0
- package/ts/pypi/helpers.pypi.ts +299 -0
- package/ts/pypi/index.ts +8 -0
- package/ts/pypi/interfaces.pypi.ts +316 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper functions for PyPI registry
|
|
3
|
+
* Package name normalization, HTML generation, etc.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Normalize package name according to PEP 503
|
|
7
|
+
* Lowercase and replace runs of [._-] with a single dash
|
|
8
|
+
* @param name - Package name
|
|
9
|
+
* @returns Normalized name
|
|
10
|
+
*/
|
|
11
|
+
export function normalizePypiPackageName(name) {
|
|
12
|
+
return name
|
|
13
|
+
.toLowerCase()
|
|
14
|
+
.replace(/[-_.]+/g, '-');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Escape HTML special characters to prevent XSS
|
|
18
|
+
* @param str - String to escape
|
|
19
|
+
* @returns Escaped string
|
|
20
|
+
*/
|
|
21
|
+
export function escapeHtml(str) {
|
|
22
|
+
return str
|
|
23
|
+
.replace(/&/g, '&')
|
|
24
|
+
.replace(/</g, '<')
|
|
25
|
+
.replace(/>/g, '>')
|
|
26
|
+
.replace(/"/g, '"')
|
|
27
|
+
.replace(/'/g, ''');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate PEP 503 compliant HTML for root index (all packages)
|
|
31
|
+
* @param packages - List of package names
|
|
32
|
+
* @returns HTML string
|
|
33
|
+
*/
|
|
34
|
+
export function generateSimpleRootHtml(packages) {
|
|
35
|
+
const links = packages
|
|
36
|
+
.map(pkg => {
|
|
37
|
+
const normalized = normalizePypiPackageName(pkg);
|
|
38
|
+
return ` <a href="${escapeHtml(normalized)}/">${escapeHtml(pkg)}</a>`;
|
|
39
|
+
})
|
|
40
|
+
.join('\n');
|
|
41
|
+
return `<!DOCTYPE html>
|
|
42
|
+
<html>
|
|
43
|
+
<head>
|
|
44
|
+
<meta name="pypi:repository-version" content="1.0">
|
|
45
|
+
<title>Simple Index</title>
|
|
46
|
+
</head>
|
|
47
|
+
<body>
|
|
48
|
+
<h1>Simple Index</h1>
|
|
49
|
+
${links}
|
|
50
|
+
</body>
|
|
51
|
+
</html>`;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Generate PEP 503 compliant HTML for package index (file list)
|
|
55
|
+
* @param packageName - Package name (normalized)
|
|
56
|
+
* @param files - List of files
|
|
57
|
+
* @param baseUrl - Base URL for downloads
|
|
58
|
+
* @returns HTML string
|
|
59
|
+
*/
|
|
60
|
+
export function generateSimplePackageHtml(packageName, files, baseUrl) {
|
|
61
|
+
const links = files
|
|
62
|
+
.map(file => {
|
|
63
|
+
// Build URL
|
|
64
|
+
let url = file.url;
|
|
65
|
+
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
|
66
|
+
// Relative URL - make it absolute
|
|
67
|
+
url = `${baseUrl}/packages/${packageName}/${file.filename}`;
|
|
68
|
+
}
|
|
69
|
+
// Add hash fragment
|
|
70
|
+
const hashName = Object.keys(file.hashes)[0];
|
|
71
|
+
const hashValue = file.hashes[hashName];
|
|
72
|
+
const fragment = hashName && hashValue ? `#${hashName}=${hashValue}` : '';
|
|
73
|
+
// Build data attributes
|
|
74
|
+
const dataAttrs = [];
|
|
75
|
+
if (file['requires-python']) {
|
|
76
|
+
const escaped = escapeHtml(file['requires-python']);
|
|
77
|
+
dataAttrs.push(`data-requires-python="${escaped}"`);
|
|
78
|
+
}
|
|
79
|
+
if (file['gpg-sig'] !== undefined) {
|
|
80
|
+
dataAttrs.push(`data-gpg-sig="${file['gpg-sig'] ? 'true' : 'false'}"`);
|
|
81
|
+
}
|
|
82
|
+
if (file.yanked) {
|
|
83
|
+
const reason = typeof file.yanked === 'string' ? file.yanked : '';
|
|
84
|
+
if (reason) {
|
|
85
|
+
dataAttrs.push(`data-yanked="${escapeHtml(reason)}"`);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
dataAttrs.push(`data-yanked=""`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const dataAttrStr = dataAttrs.length > 0 ? ' ' + dataAttrs.join(' ') : '';
|
|
92
|
+
return ` <a href="${escapeHtml(url)}${fragment}"${dataAttrStr}>${escapeHtml(file.filename)}</a>`;
|
|
93
|
+
})
|
|
94
|
+
.join('\n');
|
|
95
|
+
return `<!DOCTYPE html>
|
|
96
|
+
<html>
|
|
97
|
+
<head>
|
|
98
|
+
<meta name="pypi:repository-version" content="1.0">
|
|
99
|
+
<title>Links for ${escapeHtml(packageName)}</title>
|
|
100
|
+
</head>
|
|
101
|
+
<body>
|
|
102
|
+
<h1>Links for ${escapeHtml(packageName)}</h1>
|
|
103
|
+
${links}
|
|
104
|
+
</body>
|
|
105
|
+
</html>`;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Parse filename to extract package info
|
|
109
|
+
* Supports wheel and sdist formats
|
|
110
|
+
* @param filename - Package filename
|
|
111
|
+
* @returns Parsed info or null
|
|
112
|
+
*/
|
|
113
|
+
export function parsePackageFilename(filename) {
|
|
114
|
+
// Wheel format: {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl
|
|
115
|
+
const wheelMatch = filename.match(/^([a-zA-Z0-9_.-]+?)-([a-zA-Z0-9_.]+?)(?:-(\d+))?-([^-]+)-([^-]+)-([^-]+)\.whl$/);
|
|
116
|
+
if (wheelMatch) {
|
|
117
|
+
return {
|
|
118
|
+
name: wheelMatch[1],
|
|
119
|
+
version: wheelMatch[2],
|
|
120
|
+
filetype: 'bdist_wheel',
|
|
121
|
+
pythonVersion: wheelMatch[4],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Sdist tar.gz format: {name}-{version}.tar.gz
|
|
125
|
+
const sdistTarMatch = filename.match(/^([a-zA-Z0-9_.-]+?)-([a-zA-Z0-9_.]+)\.tar\.gz$/);
|
|
126
|
+
if (sdistTarMatch) {
|
|
127
|
+
return {
|
|
128
|
+
name: sdistTarMatch[1],
|
|
129
|
+
version: sdistTarMatch[2],
|
|
130
|
+
filetype: 'sdist',
|
|
131
|
+
pythonVersion: 'source',
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// Sdist zip format: {name}-{version}.zip
|
|
135
|
+
const sdistZipMatch = filename.match(/^([a-zA-Z0-9_.-]+?)-([a-zA-Z0-9_.]+)\.zip$/);
|
|
136
|
+
if (sdistZipMatch) {
|
|
137
|
+
return {
|
|
138
|
+
name: sdistZipMatch[1],
|
|
139
|
+
version: sdistZipMatch[2],
|
|
140
|
+
filetype: 'sdist',
|
|
141
|
+
pythonVersion: 'source',
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Calculate hash digest for a buffer
|
|
148
|
+
* @param data - Data to hash
|
|
149
|
+
* @param algorithm - Hash algorithm (sha256, md5, blake2b)
|
|
150
|
+
* @returns Hex-encoded hash
|
|
151
|
+
*/
|
|
152
|
+
export async function calculateHash(data, algorithm) {
|
|
153
|
+
const crypto = await import('crypto');
|
|
154
|
+
let hash;
|
|
155
|
+
if (algorithm === 'blake2b') {
|
|
156
|
+
// Node.js uses 'blake2b512' for blake2b
|
|
157
|
+
hash = crypto.createHash('blake2b512');
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
hash = crypto.createHash(algorithm);
|
|
161
|
+
}
|
|
162
|
+
hash.update(data);
|
|
163
|
+
return hash.digest('hex');
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Validate package name
|
|
167
|
+
* Must contain only ASCII letters, numbers, ., -, and _
|
|
168
|
+
* @param name - Package name
|
|
169
|
+
* @returns true if valid
|
|
170
|
+
*/
|
|
171
|
+
export function isValidPackageName(name) {
|
|
172
|
+
return /^[a-zA-Z0-9._-]+$/.test(name);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Validate version string (basic check)
|
|
176
|
+
* @param version - Version string
|
|
177
|
+
* @returns true if valid
|
|
178
|
+
*/
|
|
179
|
+
export function isValidVersion(version) {
|
|
180
|
+
// Basic check - allows numbers, letters, dots, hyphens, underscores
|
|
181
|
+
// More strict validation would follow PEP 440
|
|
182
|
+
return /^[a-zA-Z0-9._-]+$/.test(version);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Extract metadata from package metadata
|
|
186
|
+
* Filters and normalizes metadata fields
|
|
187
|
+
* @param metadata - Raw metadata object
|
|
188
|
+
* @returns Filtered metadata
|
|
189
|
+
*/
|
|
190
|
+
export function extractCoreMetadata(metadata) {
|
|
191
|
+
const coreFields = [
|
|
192
|
+
'metadata-version',
|
|
193
|
+
'name',
|
|
194
|
+
'version',
|
|
195
|
+
'platform',
|
|
196
|
+
'supported-platform',
|
|
197
|
+
'summary',
|
|
198
|
+
'description',
|
|
199
|
+
'description-content-type',
|
|
200
|
+
'keywords',
|
|
201
|
+
'home-page',
|
|
202
|
+
'download-url',
|
|
203
|
+
'author',
|
|
204
|
+
'author-email',
|
|
205
|
+
'maintainer',
|
|
206
|
+
'maintainer-email',
|
|
207
|
+
'license',
|
|
208
|
+
'classifier',
|
|
209
|
+
'requires-python',
|
|
210
|
+
'requires-dist',
|
|
211
|
+
'requires-external',
|
|
212
|
+
'provides-dist',
|
|
213
|
+
'project-url',
|
|
214
|
+
'provides-extra',
|
|
215
|
+
];
|
|
216
|
+
const result = {};
|
|
217
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
218
|
+
const normalizedKey = key.toLowerCase().replace(/_/g, '-');
|
|
219
|
+
if (coreFields.includes(normalizedKey)) {
|
|
220
|
+
result[normalizedKey] = value;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Generate JSON API response for package list (PEP 691)
|
|
227
|
+
* @param packages - List of package names
|
|
228
|
+
* @returns JSON object
|
|
229
|
+
*/
|
|
230
|
+
export function generateJsonRootResponse(packages) {
|
|
231
|
+
return {
|
|
232
|
+
meta: {
|
|
233
|
+
'api-version': '1.0',
|
|
234
|
+
},
|
|
235
|
+
projects: packages.map(name => ({ name })),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Generate JSON API response for package files (PEP 691)
|
|
240
|
+
* @param packageName - Package name (normalized)
|
|
241
|
+
* @param files - List of files
|
|
242
|
+
* @returns JSON object
|
|
243
|
+
*/
|
|
244
|
+
export function generateJsonPackageResponse(packageName, files) {
|
|
245
|
+
return {
|
|
246
|
+
meta: {
|
|
247
|
+
'api-version': '1.0',
|
|
248
|
+
},
|
|
249
|
+
name: packageName,
|
|
250
|
+
files: files.map(file => ({
|
|
251
|
+
filename: file.filename,
|
|
252
|
+
url: file.url,
|
|
253
|
+
hashes: file.hashes,
|
|
254
|
+
'requires-python': file['requires-python'],
|
|
255
|
+
'dist-info-metadata': file['dist-info-metadata'],
|
|
256
|
+
'gpg-sig': file['gpg-sig'],
|
|
257
|
+
yanked: file.yanked,
|
|
258
|
+
size: file.size,
|
|
259
|
+
'upload-time': file['upload-time'],
|
|
260
|
+
})),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5weXBpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvcHlwaS9oZWxwZXJzLnB5cGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBSUg7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsd0JBQXdCLENBQUMsSUFBWTtJQUNuRCxPQUFPLElBQUk7U0FDUixXQUFXLEVBQUU7U0FDYixPQUFPLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBQzdCLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLFVBQVUsQ0FBQyxHQUFXO0lBQ3BDLE9BQU8sR0FBRztTQUNQLE9BQU8sQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDO1NBQ3RCLE9BQU8sQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDO1NBQ3JCLE9BQU8sQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDO1NBQ3JCLE9BQU8sQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDO1NBQ3ZCLE9BQU8sQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUM7QUFDN0IsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsc0JBQXNCLENBQUMsUUFBa0I7SUFDdkQsTUFBTSxLQUFLLEdBQUcsUUFBUTtTQUNuQixHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUU7UUFDVCxNQUFNLFVBQVUsR0FBRyx3QkFBd0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNqRCxPQUFPLGdCQUFnQixVQUFVLENBQUMsVUFBVSxDQUFDLE1BQU0sVUFBVSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUM7SUFDM0UsQ0FBQyxDQUFDO1NBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRWQsT0FBTzs7Ozs7Ozs7RUFRUCxLQUFLOztRQUVDLENBQUM7QUFDVCxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLHlCQUF5QixDQUN2QyxXQUFtQixFQUNuQixLQUFrQixFQUNsQixP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
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PyPI Registry Module
|
|
3
|
+
* Python Package Index implementation
|
|
4
|
+
*/
|
|
5
|
+
export * from './interfaces.pypi.js';
|
|
6
|
+
export * from './classes.pypiregistry.js';
|
|
7
|
+
export * as pypiHelpers from './helpers.pypi.js';
|
|
8
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9weXBpL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUVILGNBQWMsc0JBQXNCLENBQUM7QUFDckMsY0FBYywyQkFBMkIsQ0FBQztBQUMxQyxPQUFPLEtBQUssV0FBVyxNQUFNLG1CQUFtQixDQUFDIn0=
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PyPI Registry Type Definitions
|
|
3
|
+
* Compliant with PEP 503 (Simple API), PEP 691 (JSON API), and PyPI upload API
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* File information for a package distribution
|
|
7
|
+
* Used in both PEP 503 HTML and PEP 691 JSON responses
|
|
8
|
+
*/
|
|
9
|
+
export interface IPypiFile {
|
|
10
|
+
/** Filename (e.g., "package-1.0.0-py3-none-any.whl") */
|
|
11
|
+
filename: string;
|
|
12
|
+
/** Download URL (absolute or relative) */
|
|
13
|
+
url: string;
|
|
14
|
+
/** Hash digests (multiple algorithms supported in JSON) */
|
|
15
|
+
hashes: Record<string, string>;
|
|
16
|
+
/** Python version requirement (PEP 345 format) */
|
|
17
|
+
'requires-python'?: string;
|
|
18
|
+
/** Whether distribution info metadata is available (PEP 658) */
|
|
19
|
+
'dist-info-metadata'?: boolean | {
|
|
20
|
+
sha256: string;
|
|
21
|
+
};
|
|
22
|
+
/** Whether GPG signature is available */
|
|
23
|
+
'gpg-sig'?: boolean;
|
|
24
|
+
/** Yank status: false or reason string */
|
|
25
|
+
yanked?: boolean | string;
|
|
26
|
+
/** File size in bytes */
|
|
27
|
+
size?: number;
|
|
28
|
+
/** Upload timestamp */
|
|
29
|
+
'upload-time'?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Package metadata stored internally
|
|
33
|
+
* Consolidated from multiple file uploads
|
|
34
|
+
*/
|
|
35
|
+
export interface IPypiPackageMetadata {
|
|
36
|
+
/** Normalized package name */
|
|
37
|
+
name: string;
|
|
38
|
+
/** Map of version to file list */
|
|
39
|
+
versions: Record<string, IPypiVersionMetadata>;
|
|
40
|
+
/** Timestamp of last update */
|
|
41
|
+
'last-modified'?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Metadata for a specific version
|
|
45
|
+
*/
|
|
46
|
+
export interface IPypiVersionMetadata {
|
|
47
|
+
/** Version string */
|
|
48
|
+
version: string;
|
|
49
|
+
/** Files for this version (wheels, sdists) */
|
|
50
|
+
files: IPypiFileMetadata[];
|
|
51
|
+
/** Core metadata fields */
|
|
52
|
+
metadata?: IPypiCoreMetadata;
|
|
53
|
+
/** Whether entire version is yanked */
|
|
54
|
+
yanked?: boolean | string;
|
|
55
|
+
/** Upload timestamp */
|
|
56
|
+
'upload-time'?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Internal file metadata
|
|
60
|
+
*/
|
|
61
|
+
export interface IPypiFileMetadata {
|
|
62
|
+
filename: string;
|
|
63
|
+
/** Storage key/path */
|
|
64
|
+
path: string;
|
|
65
|
+
/** File type: bdist_wheel or sdist */
|
|
66
|
+
filetype: 'bdist_wheel' | 'sdist';
|
|
67
|
+
/** Python version tag */
|
|
68
|
+
python_version: string;
|
|
69
|
+
/** Hash digests */
|
|
70
|
+
hashes: Record<string, string>;
|
|
71
|
+
/** File size in bytes */
|
|
72
|
+
size: number;
|
|
73
|
+
/** Python version requirement */
|
|
74
|
+
'requires-python'?: string;
|
|
75
|
+
/** Whether this file is yanked */
|
|
76
|
+
yanked?: boolean | string;
|
|
77
|
+
/** Upload timestamp */
|
|
78
|
+
'upload-time': string;
|
|
79
|
+
/** Uploader user ID */
|
|
80
|
+
'uploaded-by': string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Core metadata fields (subset of PEP 566)
|
|
84
|
+
* These are extracted from package uploads
|
|
85
|
+
*/
|
|
86
|
+
export interface IPypiCoreMetadata {
|
|
87
|
+
/** Metadata version */
|
|
88
|
+
'metadata-version': string;
|
|
89
|
+
/** Package name */
|
|
90
|
+
name: string;
|
|
91
|
+
/** Version string */
|
|
92
|
+
version: string;
|
|
93
|
+
/** Platform compatibility */
|
|
94
|
+
platform?: string;
|
|
95
|
+
/** Supported platforms */
|
|
96
|
+
'supported-platform'?: string;
|
|
97
|
+
/** Summary/description */
|
|
98
|
+
summary?: string;
|
|
99
|
+
/** Long description */
|
|
100
|
+
description?: string;
|
|
101
|
+
/** Description content type (text/plain, text/markdown, text/x-rst) */
|
|
102
|
+
'description-content-type'?: string;
|
|
103
|
+
/** Keywords */
|
|
104
|
+
keywords?: string;
|
|
105
|
+
/** Homepage URL */
|
|
106
|
+
'home-page'?: string;
|
|
107
|
+
/** Download URL */
|
|
108
|
+
'download-url'?: string;
|
|
109
|
+
/** Author name */
|
|
110
|
+
author?: string;
|
|
111
|
+
/** Author email */
|
|
112
|
+
'author-email'?: string;
|
|
113
|
+
/** Maintainer name */
|
|
114
|
+
maintainer?: string;
|
|
115
|
+
/** Maintainer email */
|
|
116
|
+
'maintainer-email'?: string;
|
|
117
|
+
/** License */
|
|
118
|
+
license?: string;
|
|
119
|
+
/** Classifiers (Trove classifiers) */
|
|
120
|
+
classifier?: string[];
|
|
121
|
+
/** Python version requirement */
|
|
122
|
+
'requires-python'?: string;
|
|
123
|
+
/** Dist name requirement */
|
|
124
|
+
'requires-dist'?: string[];
|
|
125
|
+
/** External requirement */
|
|
126
|
+
'requires-external'?: string[];
|
|
127
|
+
/** Provides dist */
|
|
128
|
+
'provides-dist'?: string[];
|
|
129
|
+
/** Project URLs */
|
|
130
|
+
'project-url'?: string[];
|
|
131
|
+
/** Provides extra */
|
|
132
|
+
'provides-extra'?: string[];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* PEP 503: Simple API root response (project list)
|
|
136
|
+
*/
|
|
137
|
+
export interface IPypiSimpleRootHtml {
|
|
138
|
+
/** List of project names */
|
|
139
|
+
projects: string[];
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* PEP 503: Simple API project response (file list)
|
|
143
|
+
*/
|
|
144
|
+
export interface IPypiSimpleProjectHtml {
|
|
145
|
+
/** Normalized project name */
|
|
146
|
+
name: string;
|
|
147
|
+
/** List of files */
|
|
148
|
+
files: IPypiFile[];
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* PEP 691: JSON API root response
|
|
152
|
+
*/
|
|
153
|
+
export interface IPypiJsonRoot {
|
|
154
|
+
/** API metadata */
|
|
155
|
+
meta: {
|
|
156
|
+
/** API version (e.g., "1.0") */
|
|
157
|
+
'api-version': string;
|
|
158
|
+
};
|
|
159
|
+
/** List of projects */
|
|
160
|
+
projects: Array<{
|
|
161
|
+
/** Project name */
|
|
162
|
+
name: string;
|
|
163
|
+
}>;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* PEP 691: JSON API project response
|
|
167
|
+
*/
|
|
168
|
+
export interface IPypiJsonProject {
|
|
169
|
+
/** Normalized project name */
|
|
170
|
+
name: string;
|
|
171
|
+
/** API metadata */
|
|
172
|
+
meta: {
|
|
173
|
+
/** API version (e.g., "1.0") */
|
|
174
|
+
'api-version': string;
|
|
175
|
+
};
|
|
176
|
+
/** List of files */
|
|
177
|
+
files: IPypiFile[];
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Upload form data (multipart/form-data fields)
|
|
181
|
+
* Based on PyPI legacy upload API
|
|
182
|
+
*/
|
|
183
|
+
export interface IPypiUploadForm {
|
|
184
|
+
/** Action type (always "file_upload") */
|
|
185
|
+
':action': 'file_upload';
|
|
186
|
+
/** Protocol version (always "1") */
|
|
187
|
+
protocol_version: '1';
|
|
188
|
+
/** File content (binary) */
|
|
189
|
+
content: Buffer;
|
|
190
|
+
/** File type */
|
|
191
|
+
filetype: 'bdist_wheel' | 'sdist';
|
|
192
|
+
/** Python version tag */
|
|
193
|
+
pyversion: string;
|
|
194
|
+
/** Package name */
|
|
195
|
+
name: string;
|
|
196
|
+
/** Version string */
|
|
197
|
+
version: string;
|
|
198
|
+
/** Metadata version */
|
|
199
|
+
metadata_version: string;
|
|
200
|
+
/** Hash digests (at least one required) */
|
|
201
|
+
md5_digest?: string;
|
|
202
|
+
sha256_digest?: string;
|
|
203
|
+
blake2_256_digest?: string;
|
|
204
|
+
/** Optional attestations */
|
|
205
|
+
attestations?: string;
|
|
206
|
+
/** Optional core metadata fields */
|
|
207
|
+
summary?: string;
|
|
208
|
+
description?: string;
|
|
209
|
+
description_content_type?: string;
|
|
210
|
+
author?: string;
|
|
211
|
+
author_email?: string;
|
|
212
|
+
maintainer?: string;
|
|
213
|
+
maintainer_email?: string;
|
|
214
|
+
license?: string;
|
|
215
|
+
keywords?: string;
|
|
216
|
+
home_page?: string;
|
|
217
|
+
download_url?: string;
|
|
218
|
+
requires_python?: string;
|
|
219
|
+
classifiers?: string[];
|
|
220
|
+
platform?: string;
|
|
221
|
+
[key: string]: any;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* JSON API upload response
|
|
225
|
+
*/
|
|
226
|
+
export interface IPypiUploadResponse {
|
|
227
|
+
/** Success message */
|
|
228
|
+
message?: string;
|
|
229
|
+
/** URL of uploaded file */
|
|
230
|
+
url?: string;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Error response structure
|
|
234
|
+
*/
|
|
235
|
+
export interface IPypiError {
|
|
236
|
+
/** Error message */
|
|
237
|
+
message: string;
|
|
238
|
+
/** HTTP status code */
|
|
239
|
+
status?: number;
|
|
240
|
+
/** Additional error details */
|
|
241
|
+
details?: string[];
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Search query parameters
|
|
245
|
+
*/
|
|
246
|
+
export interface IPypiSearchQuery {
|
|
247
|
+
/** Search term */
|
|
248
|
+
q?: string;
|
|
249
|
+
/** Page number */
|
|
250
|
+
page?: number;
|
|
251
|
+
/** Results per page */
|
|
252
|
+
per_page?: number;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Search result for a single package
|
|
256
|
+
*/
|
|
257
|
+
export interface IPypiSearchResult {
|
|
258
|
+
/** Package name */
|
|
259
|
+
name: string;
|
|
260
|
+
/** Latest version */
|
|
261
|
+
version: string;
|
|
262
|
+
/** Summary */
|
|
263
|
+
summary: string;
|
|
264
|
+
/** Description */
|
|
265
|
+
description?: string;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Search response structure
|
|
269
|
+
*/
|
|
270
|
+
export interface IPypiSearchResponse {
|
|
271
|
+
/** Search results */
|
|
272
|
+
results: IPypiSearchResult[];
|
|
273
|
+
/** Result count */
|
|
274
|
+
count: number;
|
|
275
|
+
/** Current page */
|
|
276
|
+
page: number;
|
|
277
|
+
/** Total pages */
|
|
278
|
+
pages: number;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Yank request
|
|
282
|
+
*/
|
|
283
|
+
export interface IPypiYankRequest {
|
|
284
|
+
/** Package name */
|
|
285
|
+
name: string;
|
|
286
|
+
/** Version to yank */
|
|
287
|
+
version: string;
|
|
288
|
+
/** Optional filename (specific file) */
|
|
289
|
+
filename?: string;
|
|
290
|
+
/** Reason for yanking */
|
|
291
|
+
reason?: string;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Yank response
|
|
295
|
+
*/
|
|
296
|
+
export interface IPypiYankResponse {
|
|
297
|
+
/** Success indicator */
|
|
298
|
+
success: boolean;
|
|
299
|
+
/** Message */
|
|
300
|
+
message?: string;
|
|
301
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PyPI Registry Type Definitions
|
|
3
|
+
* Compliant with PEP 503 (Simple API), PEP 691 (JSON API), and PyPI upload API
|
|
4
|
+
*/
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlcy5weXBpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvcHlwaS9pbnRlcmZhY2VzLnB5cGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHIn0=
|