@vltpkg/vsr 0.2.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.
Files changed (83) hide show
  1. package/.editorconfig +13 -0
  2. package/.prettierrc +7 -0
  3. package/CONTRIBUTING.md +228 -0
  4. package/LICENSE.md +110 -0
  5. package/README.md +373 -0
  6. package/bin/vsr.ts +29 -0
  7. package/config.ts +124 -0
  8. package/debug-npm.js +19 -0
  9. package/drizzle.config.js +33 -0
  10. package/package.json +80 -0
  11. package/pnpm-workspace.yaml +5 -0
  12. package/src/api.ts +2246 -0
  13. package/src/assets/public/images/bg.png +0 -0
  14. package/src/assets/public/images/clients/logo-bun.png +0 -0
  15. package/src/assets/public/images/clients/logo-deno.png +0 -0
  16. package/src/assets/public/images/clients/logo-npm.png +0 -0
  17. package/src/assets/public/images/clients/logo-pnpm.png +0 -0
  18. package/src/assets/public/images/clients/logo-vlt.png +0 -0
  19. package/src/assets/public/images/clients/logo-yarn.png +0 -0
  20. package/src/assets/public/images/favicon/apple-touch-icon.png +0 -0
  21. package/src/assets/public/images/favicon/favicon-96x96.png +0 -0
  22. package/src/assets/public/images/favicon/favicon.ico +0 -0
  23. package/src/assets/public/images/favicon/favicon.svg +3 -0
  24. package/src/assets/public/images/favicon/site.webmanifest +21 -0
  25. package/src/assets/public/images/favicon/web-app-manifest-192x192.png +0 -0
  26. package/src/assets/public/images/favicon/web-app-manifest-512x512.png +0 -0
  27. package/src/assets/public/styles/styles.css +219 -0
  28. package/src/db/client.ts +544 -0
  29. package/src/db/migrations/0000_faulty_ricochet.sql +14 -0
  30. package/src/db/migrations/0000_initial.sql +29 -0
  31. package/src/db/migrations/0001_uuid_validation.sql +35 -0
  32. package/src/db/migrations/0001_wealthy_magdalene.sql +7 -0
  33. package/src/db/migrations/drop.sql +3 -0
  34. package/src/db/migrations/meta/0000_snapshot.json +104 -0
  35. package/src/db/migrations/meta/0001_snapshot.json +155 -0
  36. package/src/db/migrations/meta/_journal.json +20 -0
  37. package/src/db/schema.ts +41 -0
  38. package/src/index.ts +709 -0
  39. package/src/routes/access.ts +263 -0
  40. package/src/routes/auth.ts +93 -0
  41. package/src/routes/index.ts +135 -0
  42. package/src/routes/packages.ts +924 -0
  43. package/src/routes/search.ts +50 -0
  44. package/src/routes/static.ts +53 -0
  45. package/src/routes/tokens.ts +102 -0
  46. package/src/routes/users.ts +14 -0
  47. package/src/utils/auth.ts +145 -0
  48. package/src/utils/cache.ts +466 -0
  49. package/src/utils/database.ts +44 -0
  50. package/src/utils/packages.ts +337 -0
  51. package/src/utils/response.ts +100 -0
  52. package/src/utils/routes.ts +47 -0
  53. package/src/utils/spa.ts +14 -0
  54. package/src/utils/tracing.ts +63 -0
  55. package/src/utils/upstream.ts +131 -0
  56. package/test/README.md +91 -0
  57. package/test/access.test.js +760 -0
  58. package/test/cloudflare-waituntil.test.js +141 -0
  59. package/test/db.test.js +447 -0
  60. package/test/dist-tag.test.js +415 -0
  61. package/test/e2e.test.js +904 -0
  62. package/test/hono-context.test.js +250 -0
  63. package/test/integrity-validation.test.js +183 -0
  64. package/test/json-response.test.js +76 -0
  65. package/test/manifest-slimming.test.js +449 -0
  66. package/test/packument-consistency.test.js +351 -0
  67. package/test/packument-version-range.test.js +144 -0
  68. package/test/performance.test.js +162 -0
  69. package/test/route-with-waituntil.test.js +298 -0
  70. package/test/run-tests.js +151 -0
  71. package/test/setup-cache-tests.js +190 -0
  72. package/test/setup.js +64 -0
  73. package/test/stale-while-revalidate.test.js +273 -0
  74. package/test/static-assets.test.js +85 -0
  75. package/test/upstream-routing.test.js +86 -0
  76. package/test/utils/test-helpers.js +84 -0
  77. package/test/waituntil-correct.test.js +208 -0
  78. package/test/waituntil-demo.test.js +138 -0
  79. package/test/waituntil-readme.md +113 -0
  80. package/tsconfig.json +37 -0
  81. package/types.ts +446 -0
  82. package/vitest.config.js +95 -0
  83. package/wrangler.json +58 -0
package/src/api.ts ADDED
@@ -0,0 +1,2246 @@
1
+ import packageJson from '../package.json' with { type: 'json' }
2
+ import wranglerJson from '../wrangler.json' with { type: 'json' }
3
+
4
+ const version = packageJson.version
5
+ const dev = wranglerJson.dev
6
+
7
+ const localhost = {
8
+ "url": `http://localhost:${dev.port}`,
9
+ "description": "localhost"
10
+ }
11
+ const npm = {
12
+ "url": "https://registry.npmjs.org",
13
+ "description": "npm public registry"
14
+ }
15
+ const year = new Date().getFullYear()
16
+
17
+ export const API = {
18
+ "openapi": "3.1.0",
19
+ "servers": [ localhost ],
20
+ "info": {
21
+ "title": `vlt serverless registry`,
22
+ "version": version,
23
+ "license": {
24
+ "identifier": "FSL-1.1-MIT",
25
+ "name": "Functional Source License, Version 1.1, MIT Future License",
26
+ "url": "https://fsl.software/FSL-1.1-MIT.template.md"
27
+ },
28
+ "description": `
29
+ The **vlt serverless registry** is the modern JavaScript package registry.
30
+
31
+ ### Compatible Clients
32
+
33
+ <table>
34
+ <tbody>
35
+ <tr>
36
+ <td><a href="https://vlt.sh" alt="vlt"><strong><code>vlt</code></strong></a></td>
37
+ <td><a href="https://npmjs.com/package/npm" alt="npm"><strong><code>npm</code></strong></a></td>
38
+ <td><a href="https://yarnpkg.com/" alt="yarn"><strong><code>yarn</code></strong></a></td>
39
+ <td><a href="https://pnpm.io/" alt="pnpm"><strong><code>pnpm</code></strong></a></td>
40
+ <td><a href="https://deno.com/" alt="deno"><strong><code>deno</code></strong></a></td>
41
+ <td><a href="https://bun.sh/" alt="bun"><strong><code>bun</code></strong></a></td>
42
+ </tr>
43
+ </tbody>
44
+ </table>
45
+
46
+ ### Features
47
+
48
+ <ul alt="features">
49
+ <li>Backwards compatible with npm & npm clients</li>
50
+ <li>Granular access control</li>
51
+ <li>Proxying upstream registries when configured</li>
52
+ <li>Package integrity validation for enhanced security</li>
53
+ <li>Minimized JSON responses when header set<br><code>Accept: application/vnd.npm.install-v1+json</code></li>
54
+ <li>Manifest slimming for performance</li>
55
+ <li>Manifest confusion checks on published packages</li>
56
+ <li>Semver range resolution for package manifests</li>
57
+ <li>Support for URL-encoded complex semver ranges<br><code>%3E%3D1.0.0%20%3C2.0.0</code> for <code>>=1.0.0 &lt;2.0.0</code></li>
58
+ <li>Dist-tag management for package versions</li>
59
+ <li>Protected "latest" dist-tag which cannot be deleted</li>
60
+ <li>Dist-tag operations restricted on proxied packages</li>
61
+ </ul>
62
+
63
+ ### Resources
64
+
65
+ <ul alt="resources">
66
+ <li><a href="https://vlt.sh">https://<strong>vlt.sh</strong></a></li>
67
+ <li><a href="https://github.com/vltpkg/vsr">https://github.com/<strong>vltpkg/vsr</strong></a></li>
68
+ <li><a href="https://discord.gg/vltpkg">https://discord.gg/<strong>vltpkg</strong></a></li>
69
+ <li><a href="https://x.com/vltpkg">https://x.com/<strong>vltpkg</strong></a></li>
70
+ </ul>
71
+
72
+ ##### Trademark Disclaimer
73
+
74
+ <p alt="trademark-disclaimer">All trademarks, logos and brand names are the property of their respective owners. All company, product and service names used in this website are for identification purposes only. Use of these names, trademarks and brands does not imply endorsement.</p>
75
+
76
+ ### License
77
+
78
+ <details alt="license">
79
+ <summary><strong>Functional Source License</strong>, Version 1.1, MIT Future License</summary>
80
+ <h1>Functional Source License,<br />Version 1.1,<br />MIT Future License</h1>
81
+ <h2>Abbreviation</h2>
82
+
83
+ FSL-1.1-MIT
84
+
85
+ <h2>Notice</h2>
86
+
87
+ Copyright ${year} vlt technology inc.
88
+
89
+ <h2>Terms and Conditions</h2>
90
+
91
+ <h3>Licensor ("We")</h3>
92
+
93
+ The party offering the Software under these Terms and Conditions.
94
+
95
+ <h3>The Software</h3>
96
+
97
+ The "Software" is each version of the software that we make available under
98
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
99
+ Conditions with the Software.
100
+
101
+ <h3>License Grant</h3>
102
+
103
+ Subject to your compliance with this License Grant and the Patents,
104
+ Redistribution and Trademark clauses below, we hereby grant you the right to
105
+ use, copy, modify, create derivative works, publicly perform, publicly display
106
+ and redistribute the Software for any Permitted Purpose identified below.
107
+
108
+ <h3>Permitted Purpose</h3>
109
+
110
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
111
+ means making the Software available to others in a commercial product or
112
+ service that:
113
+
114
+ 1. substitutes for the Software;
115
+
116
+ 2. substitutes for any other product or service we offer using the Software
117
+ that exists as of the date we make the Software available; or
118
+
119
+ 3. offers the same or substantially similar functionality as the Software.
120
+
121
+ Permitted Purposes specifically include using the Software:
122
+
123
+ 1. for your internal use and access;
124
+
125
+ 2. for non-commercial education;
126
+
127
+ 3. for non-commercial research; and
128
+
129
+ 4. in connection with professional services that you provide to a licensee
130
+ using the Software in accordance with these Terms and Conditions.
131
+
132
+ <h3>Patents</h3>
133
+
134
+ To the extent your use for a Permitted Purpose would necessarily infringe our
135
+ patents, the license grant above includes a license under our patents. If you
136
+ make a claim against any party that the Software infringes or contributes to
137
+ the infringement of any patent, then your patent license to the Software ends
138
+ immediately.
139
+
140
+ <h3>Redistribution</h3>
141
+
142
+ The Terms and Conditions apply to all copies, modifications and derivatives of
143
+ the Software.
144
+
145
+ If you redistribute any copies, modifications or derivatives of the Software,
146
+ you must include a copy of or a link to these Terms and Conditions and not
147
+ remove any copyright notices provided in or with the Software.
148
+
149
+ <h3>Disclaimer</h3>
150
+
151
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
152
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
153
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
154
+
155
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
156
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
157
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
158
+
159
+ <h3>Trademarks</h3>
160
+
161
+ Except for displaying the License Details and identifying us as the origin of
162
+ the Software, you have no right under these Terms and Conditions to use our
163
+ trademarks, trade names, service marks or product names.
164
+
165
+ <h2>Grant of Future License</h2>
166
+
167
+ We hereby irrevocably grant you an additional license to use the Software under
168
+ the MIT license that is effective on the second anniversary of the date we make
169
+ the Software available. On or after that date, you may use the Software under
170
+ the MIT license, in which case the following will apply:
171
+
172
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
173
+ this software and associated documentation files (the "Software"), to deal in
174
+ the Software without restriction, including without limitation the rights to
175
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
176
+ of the Software, and to permit persons to whom the Software is furnished to do
177
+ so, subject to the following conditions:
178
+
179
+ The above copyright notice and this permission notice shall be included in all
180
+ copies or substantial portions of the Software.
181
+
182
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
183
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
184
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
185
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
186
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
187
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
188
+ SOFTWARE.
189
+ </dialog>
190
+ `
191
+ },
192
+ "components": {
193
+ "securitySchemes": {
194
+ "bearerAuth": {
195
+ "type": "http",
196
+ "scheme": "bearer",
197
+ "bearerFormat": "Bearer <token>"
198
+ },
199
+ "basicAuth": {
200
+ "type": "http",
201
+ "scheme": "basic"
202
+ },
203
+ "apiKeyHeader": {
204
+ "type": "apiKey",
205
+ "in": "header",
206
+ "name": "X-API-Key"
207
+ },
208
+ "apiKeyQuery": {
209
+ "type": "apiKey",
210
+ "in": "query",
211
+ "name": "api_key"
212
+ },
213
+ "apiKeyCookie": {
214
+ "type": "apiKey",
215
+ "in": "cookie",
216
+ "name": "api_key"
217
+ },
218
+ "oAuth2": {
219
+ "type": "oauth2",
220
+ "flows": {
221
+ "authorizationCode": {
222
+ "authorizationUrl": "https://galaxy.scalar.com/oauth/authorize",
223
+ "tokenUrl": "https://galaxy.scalar.com/oauth/token",
224
+ "scopes": {
225
+ "read:account": "read your account information",
226
+ "write:planets": "modify planets in your account",
227
+ "read:planets": "read your planets"
228
+ }
229
+ },
230
+ "clientCredentials": {
231
+ "tokenUrl": "https://galaxy.scalar.com/oauth/token",
232
+ "scopes": {
233
+ "read:account": "read your account information",
234
+ "write:planets": "modify planets in your account",
235
+ "read:planets": "read your planets"
236
+ }
237
+ },
238
+ "implicit": {
239
+ "authorizationUrl": "https://galaxy.scalar.com/oauth/authorize",
240
+ "scopes": {
241
+ "read:account": "read your account information",
242
+ "write:planets": "modify planets in your account",
243
+ "read:planets": "read your planets"
244
+ }
245
+ },
246
+ "password": {
247
+ "tokenUrl": "https://galaxy.scalar.com/oauth/token",
248
+ "scopes": {
249
+ "read:account": "read your account information",
250
+ "write:planets": "modify planets in your account",
251
+ "read:planets": "read your planets"
252
+ }
253
+ }
254
+ }
255
+ }
256
+ },
257
+ "parameters": {
258
+ "minimalJsonHeader": {
259
+ "name": "Accept",
260
+ "in": "header",
261
+ "description": "Set to 'application/vnd.npm.install-v1+json' to receive minimal JSON responses without pretty-printing",
262
+ "required": false,
263
+ "schema": {
264
+ "type": "string",
265
+ "default": "application/json",
266
+ "enum": [
267
+ "application/json",
268
+ "application/vnd.npm.install-v1+json"
269
+ ]
270
+ }
271
+ },
272
+ "planetId": {
273
+ "name": "planetId",
274
+ "in": "path",
275
+ "required": true,
276
+ "schema": {
277
+ "type": "integer",
278
+ "format": "int64",
279
+ "examples": [
280
+ 1
281
+ ]
282
+ }
283
+ },
284
+ "limit": {
285
+ "name": "limit",
286
+ "in": "query",
287
+ "description": "The number of items to return",
288
+ "required": false,
289
+ "schema": {
290
+ "type": "integer",
291
+ "format": "int64",
292
+ "default": 10
293
+ }
294
+ },
295
+ "offset": {
296
+ "name": "offset",
297
+ "in": "query",
298
+ "description": "The number of items to skip before starting to collect the result set",
299
+ "required": false,
300
+ "schema": {
301
+ "type": "integer",
302
+ "format": "int64",
303
+ "default": 0
304
+ }
305
+ }
306
+ },
307
+ "responses": {
308
+ "BadRequest": {
309
+ "description": "Bad Request",
310
+ "content": {
311
+ "application/json": {
312
+ "schema": {
313
+ "$ref": "#/components/schemas/Error"
314
+ }
315
+ }
316
+ }
317
+ },
318
+ "Forbidden": {
319
+ "description": "Forbidden",
320
+ "content": {
321
+ "application/json": {
322
+ "schema": {
323
+ "$ref": "#/components/schemas/Error"
324
+ }
325
+ }
326
+ }
327
+ },
328
+ "NotFound": {
329
+ "description": "NotFound",
330
+ "content": {
331
+ "application/json": {
332
+ "schema": {
333
+ "$ref": "#/components/schemas/Error"
334
+ }
335
+ }
336
+ }
337
+ },
338
+ "Unauthorized": {
339
+ "description": "Unauthorized",
340
+ "content": {
341
+ "application/json": {
342
+ "schema": {
343
+ "$ref": "#/components/schemas/Error"
344
+ }
345
+ }
346
+ }
347
+ }
348
+ }
349
+ },
350
+ "security": [
351
+ {
352
+ "bearerAuth": []
353
+ }
354
+ ],
355
+ "tags": [
356
+ {
357
+ "name": "Users",
358
+ "description": "Some endpoints are public, but some require authentication. We provide all the required endpoints to create an account and authorize yourself."
359
+ },
360
+ {
361
+ "name": "Tokens",
362
+ "description": ""
363
+ },
364
+ {
365
+ "name": "Access",
366
+ "description": "Endpoints related to package access management"
367
+ },
368
+ {
369
+ "name": "Packages",
370
+ "description": "Package-related endpoints with enhanced features including consistent packument responses, manifest slimming to exclude sensitive data, and integrity validation for package tarballs. All endpoints are compatible with npm, yarn, pnpm, and other package managers."
371
+ },
372
+ {
373
+ "name": "Dist-Tags",
374
+ "description": "Endpoints for managing package distribution tags, including listing, adding, updating, and removing tags. The 'latest' tag is protected and cannot be deleted."
375
+ },
376
+ {
377
+ "name": "Search",
378
+ "description": "Endpoints for searching packages using text search."
379
+ },
380
+ {
381
+ "name": "Misc.",
382
+ "description": ""
383
+ }
384
+ ],
385
+ "paths": {
386
+ "/-/user": {
387
+ "get": {
388
+ "tags": ["Users"],
389
+ "summary": "Get User Profile",
390
+ "description": `Returns profile object associated with auth token
391
+ \`\`\`bash
392
+ $ npm profile
393
+ name: johnsmith
394
+ created: 2015-02-26T01:26:01.124Z
395
+ updated: 2023-01-10T21:55:32.118Z
396
+ \`\`\``,
397
+ "parameters": [
398
+ {
399
+ "$ref": "#/components/parameters/minimalJsonHeader"
400
+ }
401
+ ],
402
+ "responses": {
403
+ "200": {
404
+ "description": "User Profile",
405
+ "content": {
406
+ "application/json": {
407
+ "schema": {
408
+ "type": "object",
409
+ "example": {
410
+ "name": "johnsmith"
411
+ }
412
+ }
413
+ }
414
+ }
415
+ }
416
+ }
417
+ }
418
+ },
419
+ "/-/ping": {
420
+ "get": {
421
+ "tags": ["Misc."],
422
+ "summary": "Ping",
423
+ "description": `Check if the server is alive
424
+ \`\`\`bash
425
+ $ npm ping
426
+ npm notice PING http://localhost:1337/
427
+ npm notice PONG 13ms
428
+ \`\`\``,
429
+ "parameters": [
430
+ {
431
+ "$ref": "#/components/parameters/minimalJsonHeader"
432
+ }
433
+ ],
434
+ "security": [],
435
+ "responses": {
436
+ "200": {
437
+ "description": "Server is alive",
438
+ "content": {
439
+ "application/json": {
440
+ "schema": {
441
+ "type": "object",
442
+ "example": {}
443
+ }
444
+ }
445
+ }
446
+ }
447
+ }
448
+ }
449
+ },
450
+
451
+ "/": {
452
+ "get": {
453
+ "tags": ["Misc."],
454
+ "summary": "Documentation",
455
+ "description": "Get the registry docs",
456
+ "responses": {
457
+ "200": {
458
+ "description": "Retrieves the registry docs",
459
+ }
460
+ }
461
+ }
462
+ },
463
+ "/-/whoami": {
464
+ "get": {
465
+ "tags": ["Users"],
466
+ "summary": "Get User Username",
467
+ "description": `Returns username associated with auth token
468
+ \`\`\`bash
469
+ $ npm whoami
470
+ johnsmith
471
+ \`\`\``,
472
+ "parameters": [
473
+ {
474
+ "$ref": "#/components/parameters/minimalJsonHeader"
475
+ }
476
+ ],
477
+ "responses": {
478
+ "200": {
479
+ "description": "Retrieves a user name",
480
+ "content": {
481
+ "application/json": {
482
+ "schema": {
483
+ "type": "object",
484
+ "example": {
485
+ "username": "johnsmith"
486
+ }
487
+ }
488
+ }
489
+ }
490
+ }
491
+ }
492
+ }
493
+ },
494
+ "/-/tokens": {
495
+ "get": {
496
+ "tags": ["Tokens"],
497
+ "summary": "Get Token Profile",
498
+ "description": `Get tokens for the associative authenticated user
499
+
500
+ \`\`\`bash
501
+ $ npm token list
502
+ <token-type> token <partial-token>… with id <uuid> created <date-created>
503
+ \`\`\``,
504
+ "parameters": [
505
+ {
506
+ "$ref": "#/components/parameters/minimalJsonHeader"
507
+ }
508
+ ],
509
+ "responses": {
510
+ "200": {
511
+ "description": "Token Profile",
512
+ "content": {
513
+ "application/json": {
514
+ "schema": {
515
+ "type": "object",
516
+ "example": {
517
+ "objects": [
518
+ {
519
+ "cidr_whitelist": null,
520
+ "readonly": false,
521
+ "automation": null,
522
+ "created": null,
523
+ "updated": null,
524
+ "scope": [
525
+ {
526
+ "values": [
527
+ "*"
528
+ ],
529
+ "types": {
530
+ "pkg": {
531
+ "read": true,
532
+ "write": true
533
+ }
534
+ }
535
+ },
536
+ {
537
+ "values": [
538
+ "*"
539
+ ],
540
+ "types": {
541
+ "user": {
542
+ "read": true,
543
+ "write": true
544
+ }
545
+ }
546
+ }
547
+ ],
548
+ "key": "fff00131-d831-4517-84c0-1b53b1c85ba9",
549
+ "token": "a67a46ad-fe51-4fde-94fe-c56ee00fd638"
550
+ }
551
+ ],
552
+ "urls": {}
553
+ }
554
+ }
555
+ }
556
+ }
557
+ }
558
+ }
559
+ },
560
+ "post": {
561
+ "tags": ["Tokens"],
562
+ "summary": "Create Token",
563
+ "description": "Creates a token for authenticated user or provided UUID user (later requires global read+write user scope)",
564
+ "parameters": [
565
+ {
566
+ "$ref": "#/components/parameters/minimalJsonHeader"
567
+ }
568
+ ],
569
+ "headers": {
570
+ "Authorization": {
571
+ "description": "The number of allowed requests in the current period",
572
+ "schema": {
573
+ "type": "Authorization",
574
+ "bearerFormat": "Bearer <token>"
575
+ }
576
+ }
577
+ },
578
+ "requestBody": {
579
+ "description": "Scope of access/scopes for the new token",
580
+ "required": true,
581
+ "content": {
582
+ "application/json": {
583
+ "schema": {
584
+ "type": "object",
585
+ "example": {
586
+ "uuid": "admin",
587
+ "scope": [
588
+ {
589
+ "values": ["*"],
590
+ "types": { "pkg": { "read": true, "write": false }}
591
+ },
592
+ {
593
+ "values": [
594
+ "~admin"
595
+ ],
596
+ "types": {
597
+ "user": {
598
+ "read": true,
599
+ "write": true
600
+ }
601
+ }
602
+ }
603
+ ]
604
+ }
605
+ }
606
+ }
607
+ }
608
+ },
609
+ "responses": {
610
+ "201": {
611
+ "description": "Token created",
612
+ "content": {
613
+ "application/json": {
614
+ "schema": {
615
+ "type": "object",
616
+ "example": {
617
+ "uuid": "admin",
618
+ "token": "1ef5f713-15ff-6491-b62d-d16f6f04e6ac",
619
+ "scope": [
620
+ {
621
+ "values": [
622
+ "*"
623
+ ],
624
+ "types": {
625
+ "pkg": {
626
+ "read": true,
627
+ "write": false
628
+ }
629
+ }
630
+ },
631
+ {
632
+ "values": [
633
+ "~admin"
634
+ ],
635
+ "types": {
636
+ "user": {
637
+ "read": true,
638
+ "write": true
639
+ }
640
+ }
641
+ }
642
+ ]
643
+ }
644
+ }
645
+ }
646
+ }
647
+ }
648
+ }
649
+ },
650
+ "put": {
651
+ "tags": ["Tokens"],
652
+ "summary": "Update Token",
653
+ "description": "Update a token by the token itself",
654
+ "parameters": [
655
+ {
656
+ "$ref": "#/components/parameters/minimalJsonHeader"
657
+ }
658
+ ],
659
+ "responses": {
660
+ "200": {
661
+ "description": "Token updated"
662
+ }
663
+ }
664
+ },
665
+ "delete": {
666
+ "tags": ["Tokens"],
667
+ "summary": "Delete Token by Auth",
668
+ "description": `Revokes a token for the associative authenticated user
669
+
670
+ \`\`\`bash
671
+ $ npm token revoke <token>
672
+ \`\`\``,
673
+ "responses": {
674
+ "204": {
675
+ "description": "Token Deleted Response"
676
+ }
677
+ }
678
+ }
679
+ },
680
+ "/-/tokens/token/{token}": {
681
+ "delete": {
682
+ "tags": ["Tokens"],
683
+ "summary": "Delete Token by ID",
684
+ "description": "Delete a token by the token ID",
685
+ "parameters": [
686
+ {
687
+ "in": "path",
688
+ "name": "token",
689
+ "required": true,
690
+ "schema": {
691
+ "type": "string"
692
+ }
693
+ }
694
+ ],
695
+ "responses": {
696
+ "204": {
697
+ "description": "Token deleted"
698
+ }
699
+ }
700
+ }
701
+ },
702
+ "/{scope}/{pkg}": {
703
+ "get": {
704
+ "tags": ["Packages"],
705
+ "summary": "Get Scoped Package Packument",
706
+ "description": "Returns all published packages & metadata for the specific scoped package with a consistent packument structure including name, dist-tags, versions, and time fields",
707
+ "parameters": [
708
+ {
709
+ "in": "path",
710
+ "name": "scope",
711
+ "required": true,
712
+ "schema": {
713
+ "type": "string"
714
+ },
715
+ "description": "Package scope (with @ prefix)"
716
+ },
717
+ {
718
+ "in": "path",
719
+ "name": "pkg",
720
+ "required": true,
721
+ "schema": {
722
+ "type": "string"
723
+ },
724
+ "description": "Package name without scope"
725
+ },
726
+ {
727
+ "in": "query",
728
+ "name": "versionRange",
729
+ "required": false,
730
+ "schema": {
731
+ "type": "string"
732
+ },
733
+ "description": "Semver range to filter package versions"
734
+ },
735
+ {
736
+ "$ref": "#/components/parameters/minimalJsonHeader"
737
+ }
738
+ ],
739
+ "responses": {
740
+ "200": {
741
+ "description": "Package packument",
742
+ "content": {
743
+ "application/json": {
744
+ "schema": {
745
+ "type": "object",
746
+ "properties": {
747
+ "name": {
748
+ "type": "string",
749
+ "description": "The package name with scope"
750
+ },
751
+ "dist-tags": {
752
+ "type": "object",
753
+ "description": "Distribution tags, mapping tag names to versions",
754
+ "properties": {
755
+ "latest": {
756
+ "type": "string",
757
+ "description": "The latest version"
758
+ }
759
+ },
760
+ "additionalProperties": {
761
+ "type": "string"
762
+ }
763
+ },
764
+ "versions": {
765
+ "type": "object",
766
+ "description": "All package versions with slimmed manifests",
767
+ "additionalProperties": {
768
+ "type": "object"
769
+ }
770
+ },
771
+ "time": {
772
+ "type": "object",
773
+ "description": "Timestamps for package modifications and version publications",
774
+ "properties": {
775
+ "modified": {
776
+ "type": "string",
777
+ "format": "date-time"
778
+ }
779
+ },
780
+ "additionalProperties": {
781
+ "type": "string",
782
+ "format": "date-time"
783
+ }
784
+ }
785
+ }
786
+ }
787
+ }
788
+ }
789
+ },
790
+ "404": {
791
+ "description": "Not found"
792
+ }
793
+ }
794
+ },
795
+ "put": {
796
+ "tags": ["Packages"],
797
+ "summary": "Publish Scoped Package",
798
+ "description": "Publishes a scoped package by storing the full manifest in the database while returning a slimmed version that excludes sensitive data. The stored package includes proper versioning and integrity information.",
799
+ "parameters": [
800
+ {
801
+ "in": "path",
802
+ "name": "scope",
803
+ "required": true,
804
+ "schema": {
805
+ "type": "string"
806
+ },
807
+ "description": "Package scope (with @ prefix)"
808
+ },
809
+ {
810
+ "in": "path",
811
+ "name": "pkg",
812
+ "required": true,
813
+ "schema": {
814
+ "type": "string"
815
+ },
816
+ "description": "Package name without scope"
817
+ }
818
+ ],
819
+ "requestBody": {
820
+ "description": "Package data",
821
+ "required": true,
822
+ "content": {
823
+ "application/json": {
824
+ "schema": {
825
+ "type": "object",
826
+ "required": ["name", "version"],
827
+ "properties": {
828
+ "name": {
829
+ "type": "string",
830
+ "description": "Package name with scope"
831
+ },
832
+ "version": {
833
+ "type": "string",
834
+ "description": "Package version"
835
+ },
836
+ "description": {
837
+ "type": "string",
838
+ "description": "Package description"
839
+ }
840
+ }
841
+ }
842
+ }
843
+ }
844
+ },
845
+ "responses": {
846
+ "200": {
847
+ "description": "Package published",
848
+ "content": {
849
+ "application/json": {
850
+ "schema": {
851
+ "type": "object",
852
+ "properties": {
853
+ "success": {
854
+ "type": "boolean",
855
+ "example": true
856
+ },
857
+ "name": {
858
+ "type": "string"
859
+ },
860
+ "version": {
861
+ "type": "string"
862
+ },
863
+ "manifest": {
864
+ "type": "object",
865
+ "description": "Slimmed version of the published manifest"
866
+ }
867
+ }
868
+ }
869
+ }
870
+ }
871
+ },
872
+ "400": {
873
+ "description": "Invalid request"
874
+ },
875
+ "409": {
876
+ "description": "Conflict"
877
+ }
878
+ }
879
+ }
880
+ },
881
+ "/{pkg}": {
882
+ "get": {
883
+ "tags": ["Packages"],
884
+ "summary": "Get Package Packument",
885
+ "description": "Returns all published packages & metadata for the specific package with a consistent packument structure including name, dist-tags, versions, and time fields.",
886
+ "operationId": "getPackagePackument",
887
+ "parameters": [
888
+ {
889
+ "name": "pkg",
890
+ "in": "path",
891
+ "required": true,
892
+ "description": "Package name",
893
+ "schema": {
894
+ "type": "string"
895
+ }
896
+ },
897
+ {
898
+ "in": "query",
899
+ "name": "versionRange",
900
+ "required": false,
901
+ "schema": {
902
+ "type": "string"
903
+ },
904
+ "description": "Semver range to filter package versions"
905
+ },
906
+ {
907
+ "$ref": "#/components/parameters/minimalJsonHeader"
908
+ }
909
+ ],
910
+ "responses": {
911
+ "200": {
912
+ "description": "Package packument",
913
+ "content": {
914
+ "application/json": {
915
+ "schema": {
916
+ "type": "object",
917
+ "properties": {
918
+ "name": {
919
+ "type": "string",
920
+ "description": "Package name"
921
+ },
922
+ "dist-tags": {
923
+ "type": "object",
924
+ "description": "Distribution tags, mapping tag names to versions",
925
+ "properties": {
926
+ "latest": {
927
+ "type": "string",
928
+ "description": "The latest version"
929
+ }
930
+ },
931
+ "additionalProperties": {
932
+ "type": "string"
933
+ }
934
+ },
935
+ "versions": {
936
+ "type": "object",
937
+ "description": "All package versions with slimmed manifests",
938
+ "additionalProperties": {
939
+ "type": "object"
940
+ }
941
+ },
942
+ "time": {
943
+ "type": "object",
944
+ "description": "Timestamps for package modifications and version publications",
945
+ "properties": {
946
+ "modified": {
947
+ "type": "string",
948
+ "format": "date-time"
949
+ }
950
+ },
951
+ "additionalProperties": {
952
+ "type": "string",
953
+ "format": "date-time"
954
+ }
955
+ }
956
+ }
957
+ }
958
+ }
959
+ }
960
+ },
961
+ "404": {
962
+ "description": "Package not found",
963
+ "content": {
964
+ "application/json": {
965
+ "schema": {
966
+ "type": "object",
967
+ "properties": {
968
+ "error": {
969
+ "type": "string"
970
+ }
971
+ }
972
+ }
973
+ }
974
+ }
975
+ }
976
+ }
977
+ },
978
+ "put": {
979
+ "tags": ["Packages"],
980
+ "summary": "Publish Package",
981
+ "description": "Publishes a package by storing the full manifest in the database while returning a slimmed version that excludes sensitive data. The stored package includes proper versioning and integrity information.",
982
+ "parameters": [
983
+ {
984
+ "in": "path",
985
+ "name": "pkg",
986
+ "required": true,
987
+ "schema": {
988
+ "type": "string"
989
+ },
990
+ "description": "Package name"
991
+ }
992
+ ],
993
+ "requestBody": {
994
+ "description": "Package data",
995
+ "required": true,
996
+ "content": {
997
+ "application/json": {
998
+ "schema": {
999
+ "type": "object",
1000
+ "required": ["name", "version"],
1001
+ "properties": {
1002
+ "name": {
1003
+ "type": "string",
1004
+ "description": "Package name"
1005
+ },
1006
+ "version": {
1007
+ "type": "string",
1008
+ "description": "Package version"
1009
+ },
1010
+ "description": {
1011
+ "type": "string",
1012
+ "description": "Package description"
1013
+ }
1014
+ }
1015
+ }
1016
+ }
1017
+ }
1018
+ },
1019
+ "responses": {
1020
+ "200": {
1021
+ "description": "Package published",
1022
+ "content": {
1023
+ "application/json": {
1024
+ "schema": {
1025
+ "type": "object",
1026
+ "properties": {
1027
+ "success": {
1028
+ "type": "boolean",
1029
+ "example": true
1030
+ },
1031
+ "name": {
1032
+ "type": "string"
1033
+ },
1034
+ "version": {
1035
+ "type": "string"
1036
+ },
1037
+ "manifest": {
1038
+ "type": "object",
1039
+ "description": "Slimmed version of the published manifest"
1040
+ }
1041
+ }
1042
+ }
1043
+ }
1044
+ }
1045
+ },
1046
+ "400": {
1047
+ "description": "Invalid request"
1048
+ },
1049
+ "409": {
1050
+ "description": "Conflict"
1051
+ }
1052
+ }
1053
+ }
1054
+ },
1055
+ "/{scope}/{pkg}/{version}": {
1056
+ "get": {
1057
+ "tags": ["Packages"],
1058
+ "summary": "Get Scoped Package Manifest",
1059
+ "description": "Returns the slimmed package manifest for a specific scoped package version with consistent fields and without sensitive data. Supports explicit versions, dist tags, semver ranges, and URL-encoded complex range (e.g., %3E%3D1.0.0%20%3C2.0.0 for '>=1.0.0 <2.0.0')",
1060
+ "parameters": [
1061
+ {
1062
+ "in": "path",
1063
+ "name": "scope",
1064
+ "required": true,
1065
+ "schema": {
1066
+ "type": "string"
1067
+ },
1068
+ "description": "Package scope (with @ prefix)"
1069
+ },
1070
+ {
1071
+ "in": "path",
1072
+ "name": "pkg",
1073
+ "required": true,
1074
+ "schema": {
1075
+ "type": "string"
1076
+ },
1077
+ "description": "Package name without scope"
1078
+ },
1079
+ {
1080
+ "in": "path",
1081
+ "name": "version",
1082
+ "required": true,
1083
+ "schema": {
1084
+ "type": "string"
1085
+ },
1086
+ "description": "Package version. Can be an explicit version (e.g., 1.0.0), dist tag (e.g., latest), semver range (e.g., >=1.0.0), or URL-encoded complex range (e.g., %3E%3D1.0.0%20%3C2.0.0 for '>=1.0.0 <2.0.0')"
1087
+ },
1088
+ {
1089
+ "$ref": "#/components/parameters/minimalJsonHeader"
1090
+ }
1091
+ ],
1092
+ "responses": {
1093
+ "200": {
1094
+ "description": "Package manifest",
1095
+ "content": {
1096
+ "application/json": {
1097
+ "schema": {
1098
+ "type": "object",
1099
+ "properties": {
1100
+ "name": {
1101
+ "type": "string",
1102
+ "description": "Package name"
1103
+ },
1104
+ "version": {
1105
+ "type": "string",
1106
+ "description": "Package version"
1107
+ },
1108
+ "description": {
1109
+ "type": "string",
1110
+ "description": "Package description"
1111
+ },
1112
+ "dist": {
1113
+ "type": "object",
1114
+ "description": "Distribution information",
1115
+ "properties": {
1116
+ "tarball": {
1117
+ "type": "string",
1118
+ "description": "URL to the package tarball"
1119
+ },
1120
+ "shasum": {
1121
+ "type": "string",
1122
+ "description": "SHA-1 hash of the tarball"
1123
+ },
1124
+ "integrity": {
1125
+ "type": "string",
1126
+ "description": "SRI integrity hash of the tarball"
1127
+ }
1128
+ }
1129
+ }
1130
+ }
1131
+ }
1132
+ }
1133
+ }
1134
+ },
1135
+ "404": {
1136
+ "description": "Not found"
1137
+ }
1138
+ }
1139
+ }
1140
+ },
1141
+ "/{pkg}/{version}": {
1142
+ "get": {
1143
+ "tags": ["Packages"],
1144
+ "summary": "Get Package Manifest",
1145
+ "description": "Returns the package manifest for a specific version. Supports explicit versions (e.g., 1.0.0), dist tags (e.g., latest), semver ranges (e.g., >=1.0.0, *), and URL-encoded complex semver ranges with spaces and special characters.",
1146
+ "operationId": "getPackageManifest",
1147
+ "parameters": [
1148
+ {
1149
+ "in": "path",
1150
+ "name": "pkg",
1151
+ "required": true,
1152
+ "schema": {
1153
+ "type": "string"
1154
+ },
1155
+ "description": "Package name"
1156
+ },
1157
+ {
1158
+ "in": "path",
1159
+ "name": "version",
1160
+ "required": true,
1161
+ "schema": {
1162
+ "type": "string"
1163
+ },
1164
+ "description": "Package version. Can be an explicit version (e.g., 1.0.0), dist tag (e.g., latest), semver range (e.g., >=1.0.0), or URL-encoded complex range (e.g., %3E%3D1.0.0%20%3C2.0.0 for '>=1.0.0 <2.0.0')"
1165
+ },
1166
+ {
1167
+ "$ref": "#/components/parameters/minimalJsonHeader"
1168
+ }
1169
+ ],
1170
+ "responses": {
1171
+ "200": {
1172
+ "description": "Package manifest",
1173
+ "content": {
1174
+ "application/json": {
1175
+ "schema": {
1176
+ "type": "object",
1177
+ "properties": {
1178
+ "name": {
1179
+ "type": "string",
1180
+ "description": "Package name"
1181
+ },
1182
+ "version": {
1183
+ "type": "string",
1184
+ "description": "Package version"
1185
+ },
1186
+ "description": {
1187
+ "type": "string",
1188
+ "description": "Package description"
1189
+ },
1190
+ "dist": {
1191
+ "type": "object",
1192
+ "description": "Distribution information",
1193
+ "properties": {
1194
+ "tarball": {
1195
+ "type": "string",
1196
+ "description": "URL to the package tarball"
1197
+ },
1198
+ "shasum": {
1199
+ "type": "string",
1200
+ "description": "SHA-1 hash of the tarball"
1201
+ },
1202
+ "integrity": {
1203
+ "type": "string",
1204
+ "description": "SRI integrity hash of the tarball"
1205
+ }
1206
+ }
1207
+ }
1208
+ }
1209
+ }
1210
+ }
1211
+ }
1212
+ },
1213
+ "404": {
1214
+ "description": "Not found"
1215
+ }
1216
+ }
1217
+ }
1218
+ },
1219
+ "/{scope}/{pkg}/-/{tarball}": {
1220
+ "get": {
1221
+ "tags": ["Packages"],
1222
+ "summary": "Get Scoped Package Tarball",
1223
+ "description": "Retrieves the scoped package tarball with support for integrity validation",
1224
+ "parameters": [
1225
+ {
1226
+ "in": "path",
1227
+ "name": "scope",
1228
+ "required": true,
1229
+ "schema": {
1230
+ "type": "string"
1231
+ },
1232
+ "description": "Package scope (with @ prefix)"
1233
+ },
1234
+ {
1235
+ "in": "path",
1236
+ "name": "pkg",
1237
+ "required": true,
1238
+ "schema": {
1239
+ "type": "string"
1240
+ },
1241
+ "description": "Package name without scope"
1242
+ },
1243
+ {
1244
+ "in": "path",
1245
+ "name": "tarball",
1246
+ "required": true,
1247
+ "schema": {
1248
+ "type": "string"
1249
+ },
1250
+ "description": "Tarball filename"
1251
+ },
1252
+ {
1253
+ "in": "header",
1254
+ "name": "accepts-integrity",
1255
+ "required": false,
1256
+ "schema": {
1257
+ "type": "string"
1258
+ },
1259
+ "description": "SRI integrity hash for validation"
1260
+ }
1261
+ ],
1262
+ "responses": {
1263
+ "200": {
1264
+ "description": "Package tarball",
1265
+ "content": {
1266
+ "application/octet-stream": {
1267
+ "schema": {
1268
+ "type": "string",
1269
+ "format": "binary"
1270
+ }
1271
+ }
1272
+ }
1273
+ },
1274
+ "400": {
1275
+ "description": "Integrity validation failed",
1276
+ "content": {
1277
+ "application/json": {
1278
+ "schema": {
1279
+ "type": "object",
1280
+ "properties": {
1281
+ "error": {
1282
+ "type": "string",
1283
+ "example": "Integrity check failed"
1284
+ },
1285
+ "code": {
1286
+ "type": "string",
1287
+ "example": "EINTEGRITY"
1288
+ },
1289
+ "expected": {
1290
+ "type": "string",
1291
+ "example": "sha512-abcdefghijklmnopqrstuvwxyz0123456789"
1292
+ },
1293
+ "actual": {
1294
+ "type": "string",
1295
+ "example": "sha512-differenthashvaluefortestingwhenthingsdonotmatch"
1296
+ }
1297
+ }
1298
+ }
1299
+ }
1300
+ }
1301
+ },
1302
+ "404": {
1303
+ "description": "Not found"
1304
+ }
1305
+ }
1306
+ }
1307
+ },
1308
+ "/{pkg}/-/{tarball}": {
1309
+ "get": {
1310
+ "tags": ["Packages"],
1311
+ "summary": "Get Package Tarball",
1312
+ "description": "Retrieves the package tarball with support for integrity validation",
1313
+ "parameters": [
1314
+ {
1315
+ "in": "path",
1316
+ "name": "pkg",
1317
+ "required": true,
1318
+ "schema": {
1319
+ "type": "string"
1320
+ },
1321
+ "description": "Package name"
1322
+ },
1323
+ {
1324
+ "in": "path",
1325
+ "name": "tarball",
1326
+ "required": true,
1327
+ "schema": {
1328
+ "type": "string"
1329
+ },
1330
+ "description": "Tarball filename"
1331
+ },
1332
+ {
1333
+ "in": "header",
1334
+ "name": "accepts-integrity",
1335
+ "required": false,
1336
+ "schema": {
1337
+ "type": "string"
1338
+ },
1339
+ "description": "SRI integrity hash for validation"
1340
+ }
1341
+ ],
1342
+ "responses": {
1343
+ "200": {
1344
+ "description": "Package tarball",
1345
+ "content": {
1346
+ "application/octet-stream": {
1347
+ "schema": {
1348
+ "type": "string",
1349
+ "format": "binary"
1350
+ }
1351
+ }
1352
+ }
1353
+ },
1354
+ "400": {
1355
+ "description": "Integrity validation failed",
1356
+ "content": {
1357
+ "application/json": {
1358
+ "schema": {
1359
+ "type": "object",
1360
+ "properties": {
1361
+ "error": {
1362
+ "type": "string",
1363
+ "example": "Integrity check failed"
1364
+ },
1365
+ "code": {
1366
+ "type": "string",
1367
+ "example": "EINTEGRITY"
1368
+ },
1369
+ "expected": {
1370
+ "type": "string",
1371
+ "example": "sha512-abcdefghijklmnopqrstuvwxyz0123456789"
1372
+ },
1373
+ "actual": {
1374
+ "type": "string",
1375
+ "example": "sha512-differenthashvaluefortestingwhenthingsdonotmatch"
1376
+ }
1377
+ }
1378
+ }
1379
+ }
1380
+ }
1381
+ },
1382
+ "404": {
1383
+ "description": "Not found"
1384
+ }
1385
+ }
1386
+ }
1387
+ },
1388
+ "/-/package/{pkg}/dist-tags": {
1389
+ "get": {
1390
+ "tags": ["Dist-Tags"],
1391
+ "summary": "List Dist-Tags",
1392
+ "description": "Lists all dist-tags for a given package",
1393
+ "parameters": [
1394
+ {
1395
+ "in": "path",
1396
+ "name": "pkg",
1397
+ "required": true,
1398
+ "schema": {
1399
+ "type": "string"
1400
+ },
1401
+ "description": "Package name"
1402
+ },
1403
+ {
1404
+ "$ref": "#/components/parameters/minimalJsonHeader"
1405
+ }
1406
+ ],
1407
+ "responses": {
1408
+ "200": {
1409
+ "description": "Map of dist-tags to versions",
1410
+ "content": {
1411
+ "application/json": {
1412
+ "schema": {
1413
+ "type": "object",
1414
+ "additionalProperties": {
1415
+ "type": "string"
1416
+ },
1417
+ "example": {
1418
+ "latest": "1.0.0",
1419
+ "beta": "1.1.0-beta.1"
1420
+ }
1421
+ }
1422
+ }
1423
+ }
1424
+ },
1425
+ "404": {
1426
+ "description": "Package not found"
1427
+ }
1428
+ }
1429
+ }
1430
+ },
1431
+
1432
+ "/-/package/{pkg}/dist-tags/{tag}": {
1433
+ "get": {
1434
+ "tags": ["Dist-Tags"],
1435
+ "summary": "Get Specific Dist-Tag",
1436
+ "description": "Gets a specific dist-tag for a given package",
1437
+ "parameters": [
1438
+ {
1439
+ "in": "path",
1440
+ "name": "pkg",
1441
+ "required": true,
1442
+ "schema": {
1443
+ "type": "string"
1444
+ },
1445
+ "description": "Package name"
1446
+ },
1447
+ {
1448
+ "in": "path",
1449
+ "name": "tag",
1450
+ "required": true,
1451
+ "schema": {
1452
+ "type": "string"
1453
+ },
1454
+ "description": "Tag name"
1455
+ },
1456
+ {
1457
+ "$ref": "#/components/parameters/minimalJsonHeader"
1458
+ }
1459
+ ],
1460
+ "responses": {
1461
+ "200": {
1462
+ "description": "Version for the specified tag",
1463
+ "content": {
1464
+ "application/json": {
1465
+ "schema": {
1466
+ "type": "string",
1467
+ "example": "1.0.0"
1468
+ }
1469
+ }
1470
+ }
1471
+ },
1472
+ "404": {
1473
+ "description": "Package or tag not found"
1474
+ }
1475
+ }
1476
+ },
1477
+ "put": {
1478
+ "tags": ["Dist-Tags"],
1479
+ "summary": "Add/Update Dist-Tag",
1480
+ "description": "Adds or updates a dist-tag for a given package",
1481
+ "parameters": [
1482
+ {
1483
+ "in": "path",
1484
+ "name": "pkg",
1485
+ "required": true,
1486
+ "schema": {
1487
+ "type": "string"
1488
+ },
1489
+ "description": "Package name"
1490
+ },
1491
+ {
1492
+ "in": "path",
1493
+ "name": "tag",
1494
+ "required": true,
1495
+ "schema": {
1496
+ "type": "string"
1497
+ },
1498
+ "description": "Tag name"
1499
+ },
1500
+ {
1501
+ "$ref": "#/components/parameters/minimalJsonHeader"
1502
+ }
1503
+ ],
1504
+ "requestBody": {
1505
+ "description": "Version to tag",
1506
+ "required": true,
1507
+ "content": {
1508
+ "text/plain": {
1509
+ "schema": {
1510
+ "type": "string",
1511
+ "example": "1.0.0"
1512
+ }
1513
+ }
1514
+ }
1515
+ },
1516
+ "responses": {
1517
+ "201": {
1518
+ "description": "Updated map of dist-tags to versions",
1519
+ "content": {
1520
+ "application/json": {
1521
+ "schema": {
1522
+ "type": "object",
1523
+ "additionalProperties": {
1524
+ "type": "string"
1525
+ },
1526
+ "example": {
1527
+ "latest": "1.0.0",
1528
+ "beta": "1.1.0-beta.1"
1529
+ }
1530
+ }
1531
+ }
1532
+ }
1533
+ },
1534
+ "404": {
1535
+ "description": "Package or version not found"
1536
+ }
1537
+ }
1538
+ },
1539
+ "delete": {
1540
+ "tags": ["Dist-Tags"],
1541
+ "summary": "Delete Dist-Tag",
1542
+ "description": "Deletes a dist-tag for a given package. The 'latest' tag cannot be deleted.",
1543
+ "parameters": [
1544
+ {
1545
+ "in": "path",
1546
+ "name": "pkg",
1547
+ "required": true,
1548
+ "schema": {
1549
+ "type": "string"
1550
+ },
1551
+ "description": "Package name"
1552
+ },
1553
+ {
1554
+ "in": "path",
1555
+ "name": "tag",
1556
+ "required": true,
1557
+ "schema": {
1558
+ "type": "string"
1559
+ },
1560
+ "description": "Tag name"
1561
+ },
1562
+ {
1563
+ "$ref": "#/components/parameters/minimalJsonHeader"
1564
+ }
1565
+ ],
1566
+ "responses": {
1567
+ "200": {
1568
+ "description": "Updated map of dist-tags to versions",
1569
+ "content": {
1570
+ "application/json": {
1571
+ "schema": {
1572
+ "type": "object",
1573
+ "additionalProperties": {
1574
+ "type": "string"
1575
+ },
1576
+ "example": {
1577
+ "latest": "1.0.0"
1578
+ }
1579
+ }
1580
+ }
1581
+ }
1582
+ },
1583
+ "400": {
1584
+ "description": "Bad request, e.g., attempting to delete the 'latest' tag"
1585
+ },
1586
+ "404": {
1587
+ "description": "Package or tag not found"
1588
+ }
1589
+ }
1590
+ }
1591
+ },
1592
+
1593
+ "/-/package/@{scope}/{pkg}/dist-tags": {
1594
+ "get": {
1595
+ "tags": ["Dist-Tags"],
1596
+ "summary": "List Dist-Tags (Scoped Package)",
1597
+ "description": "Lists all dist-tags for a given scoped package",
1598
+ "parameters": [
1599
+ {
1600
+ "in": "path",
1601
+ "name": "scope",
1602
+ "required": true,
1603
+ "schema": {
1604
+ "type": "string"
1605
+ },
1606
+ "description": "Package scope (without @ prefix)"
1607
+ },
1608
+ {
1609
+ "in": "path",
1610
+ "name": "pkg",
1611
+ "required": true,
1612
+ "schema": {
1613
+ "type": "string"
1614
+ },
1615
+ "description": "Package name without scope"
1616
+ },
1617
+ {
1618
+ "$ref": "#/components/parameters/minimalJsonHeader"
1619
+ }
1620
+ ],
1621
+ "responses": {
1622
+ "200": {
1623
+ "description": "Map of dist-tags to versions",
1624
+ "content": {
1625
+ "application/json": {
1626
+ "schema": {
1627
+ "type": "object",
1628
+ "additionalProperties": {
1629
+ "type": "string"
1630
+ },
1631
+ "example": {
1632
+ "latest": "1.0.0",
1633
+ "beta": "1.1.0-beta.1"
1634
+ }
1635
+ }
1636
+ }
1637
+ }
1638
+ },
1639
+ "404": {
1640
+ "description": "Package not found"
1641
+ }
1642
+ }
1643
+ }
1644
+ },
1645
+
1646
+ "/-/package/@{scope}/{pkg}/dist-tags/{tag}": {
1647
+ "get": {
1648
+ "tags": ["Dist-Tags"],
1649
+ "summary": "Get Specific Dist-Tag (Scoped Package)",
1650
+ "description": "Gets a specific dist-tag for a given scoped package",
1651
+ "parameters": [
1652
+ {
1653
+ "in": "path",
1654
+ "name": "scope",
1655
+ "required": true,
1656
+ "schema": {
1657
+ "type": "string"
1658
+ },
1659
+ "description": "Package scope (without @ prefix)"
1660
+ },
1661
+ {
1662
+ "in": "path",
1663
+ "name": "pkg",
1664
+ "required": true,
1665
+ "schema": {
1666
+ "type": "string"
1667
+ },
1668
+ "description": "Package name without scope"
1669
+ },
1670
+ {
1671
+ "in": "path",
1672
+ "name": "tag",
1673
+ "required": true,
1674
+ "schema": {
1675
+ "type": "string"
1676
+ },
1677
+ "description": "Tag name"
1678
+ },
1679
+ {
1680
+ "$ref": "#/components/parameters/minimalJsonHeader"
1681
+ }
1682
+ ],
1683
+ "responses": {
1684
+ "200": {
1685
+ "description": "Version for the specified tag",
1686
+ "content": {
1687
+ "application/json": {
1688
+ "schema": {
1689
+ "type": "string",
1690
+ "example": "1.0.0"
1691
+ }
1692
+ }
1693
+ }
1694
+ },
1695
+ "404": {
1696
+ "description": "Package or tag not found"
1697
+ }
1698
+ }
1699
+ },
1700
+ "put": {
1701
+ "tags": ["Dist-Tags"],
1702
+ "summary": "Add/Update Dist-Tag (Scoped Package)",
1703
+ "description": "Adds or updates a dist-tag for a given scoped package",
1704
+ "parameters": [
1705
+ {
1706
+ "in": "path",
1707
+ "name": "scope",
1708
+ "required": true,
1709
+ "schema": {
1710
+ "type": "string"
1711
+ },
1712
+ "description": "Package scope (without @ prefix)"
1713
+ },
1714
+ {
1715
+ "in": "path",
1716
+ "name": "pkg",
1717
+ "required": true,
1718
+ "schema": {
1719
+ "type": "string"
1720
+ },
1721
+ "description": "Package name without scope"
1722
+ },
1723
+ {
1724
+ "in": "path",
1725
+ "name": "tag",
1726
+ "required": true,
1727
+ "schema": {
1728
+ "type": "string"
1729
+ },
1730
+ "description": "Tag name"
1731
+ },
1732
+ {
1733
+ "$ref": "#/components/parameters/minimalJsonHeader"
1734
+ }
1735
+ ],
1736
+ "requestBody": {
1737
+ "description": "Version to tag",
1738
+ "required": true,
1739
+ "content": {
1740
+ "text/plain": {
1741
+ "schema": {
1742
+ "type": "string",
1743
+ "example": "1.0.0"
1744
+ }
1745
+ }
1746
+ }
1747
+ },
1748
+ "responses": {
1749
+ "201": {
1750
+ "description": "Updated map of dist-tags to versions",
1751
+ "content": {
1752
+ "application/json": {
1753
+ "schema": {
1754
+ "type": "object",
1755
+ "additionalProperties": {
1756
+ "type": "string"
1757
+ },
1758
+ "example": {
1759
+ "latest": "1.0.0",
1760
+ "beta": "1.1.0-beta.1"
1761
+ }
1762
+ }
1763
+ }
1764
+ }
1765
+ },
1766
+ "404": {
1767
+ "description": "Package or version not found"
1768
+ }
1769
+ }
1770
+ },
1771
+ "delete": {
1772
+ "tags": ["Dist-Tags"],
1773
+ "summary": "Delete Dist-Tag (Scoped Package)",
1774
+ "description": "Deletes a dist-tag for a given scoped package. The 'latest' tag cannot be deleted.",
1775
+ "parameters": [
1776
+ {
1777
+ "in": "path",
1778
+ "name": "scope",
1779
+ "required": true,
1780
+ "schema": {
1781
+ "type": "string"
1782
+ },
1783
+ "description": "Package scope (without @ prefix)"
1784
+ },
1785
+ {
1786
+ "in": "path",
1787
+ "name": "pkg",
1788
+ "required": true,
1789
+ "schema": {
1790
+ "type": "string"
1791
+ },
1792
+ "description": "Package name without scope"
1793
+ },
1794
+ {
1795
+ "in": "path",
1796
+ "name": "tag",
1797
+ "required": true,
1798
+ "schema": {
1799
+ "type": "string"
1800
+ },
1801
+ "description": "Tag name"
1802
+ },
1803
+ {
1804
+ "$ref": "#/components/parameters/minimalJsonHeader"
1805
+ }
1806
+ ],
1807
+ "responses": {
1808
+ "200": {
1809
+ "description": "Updated map of dist-tags to versions",
1810
+ "content": {
1811
+ "application/json": {
1812
+ "schema": {
1813
+ "type": "object",
1814
+ "additionalProperties": {
1815
+ "type": "string"
1816
+ },
1817
+ "example": {
1818
+ "latest": "1.0.0"
1819
+ }
1820
+ }
1821
+ }
1822
+ }
1823
+ },
1824
+ "400": {
1825
+ "description": "Bad request, e.g., attempting to delete the 'latest' tag"
1826
+ },
1827
+ "404": {
1828
+ "description": "Package or tag not found"
1829
+ }
1830
+ }
1831
+ }
1832
+ },
1833
+ "/-/package/{pkg}/access": {
1834
+ "get": {
1835
+ "tags": ["Access"],
1836
+ "summary": "Get Package Access Status",
1837
+ "description": "Returns the access status of a package (private or public)",
1838
+ "parameters": [
1839
+ {
1840
+ "in": "path",
1841
+ "name": "pkg",
1842
+ "required": true,
1843
+ "schema": {
1844
+ "type": "string"
1845
+ },
1846
+ "description": "Package name (including scope if applicable)"
1847
+ }
1848
+ ],
1849
+ "responses": {
1850
+ "200": {
1851
+ "description": "Package access status",
1852
+ "content": {
1853
+ "application/json": {
1854
+ "schema": {
1855
+ "type": "object",
1856
+ "properties": {
1857
+ "status": {
1858
+ "type": "string",
1859
+ "enum": ["private", "public"],
1860
+ "description": "Access status of the package"
1861
+ }
1862
+ }
1863
+ }
1864
+ }
1865
+ }
1866
+ },
1867
+ "401": {
1868
+ "description": "Authentication required"
1869
+ },
1870
+ "403": {
1871
+ "description": "Insufficient permissions"
1872
+ },
1873
+ "404": {
1874
+ "description": "Package not found"
1875
+ }
1876
+ },
1877
+ "security": [
1878
+ {
1879
+ "bearerAuth": []
1880
+ },
1881
+ {
1882
+ "basicAuth": []
1883
+ }
1884
+ ]
1885
+ },
1886
+ "put": {
1887
+ "tags": ["Access"],
1888
+ "summary": "Set Package Access Status",
1889
+ "description": "Sets the access status of a package to private or public. Currently, only private access is supported.",
1890
+ "parameters": [
1891
+ {
1892
+ "in": "path",
1893
+ "name": "pkg",
1894
+ "required": true,
1895
+ "schema": {
1896
+ "type": "string"
1897
+ },
1898
+ "description": "Package name (including scope if applicable)"
1899
+ }
1900
+ ],
1901
+ "requestBody": {
1902
+ "description": "Access status to set",
1903
+ "required": true,
1904
+ "content": {
1905
+ "application/json": {
1906
+ "schema": {
1907
+ "type": "object",
1908
+ "required": ["status"],
1909
+ "properties": {
1910
+ "status": {
1911
+ "type": "string",
1912
+ "enum": ["private", "public"],
1913
+ "description": "Desired access status"
1914
+ }
1915
+ }
1916
+ }
1917
+ }
1918
+ }
1919
+ },
1920
+ "responses": {
1921
+ "200": {
1922
+ "description": "Package access status updated",
1923
+ "content": {
1924
+ "application/json": {
1925
+ "schema": {
1926
+ "type": "object",
1927
+ "properties": {
1928
+ "status": {
1929
+ "type": "string",
1930
+ "enum": ["private", "public"],
1931
+ "description": "New access status of the package"
1932
+ }
1933
+ }
1934
+ }
1935
+ }
1936
+ }
1937
+ },
1938
+ "400": {
1939
+ "description": "Invalid request"
1940
+ },
1941
+ "401": {
1942
+ "description": "Authentication required"
1943
+ },
1944
+ "403": {
1945
+ "description": "Insufficient permissions"
1946
+ },
1947
+ "404": {
1948
+ "description": "Package not found"
1949
+ }
1950
+ },
1951
+ "security": [
1952
+ {
1953
+ "bearerAuth": []
1954
+ },
1955
+ {
1956
+ "basicAuth": []
1957
+ }
1958
+ ]
1959
+ }
1960
+ },
1961
+ "/-/package/list": {
1962
+ "get": {
1963
+ "tags": ["Access"],
1964
+ "summary": "List User Packages",
1965
+ "description": "Lists packages a user has access to",
1966
+ "parameters": [
1967
+ {
1968
+ "in": "query",
1969
+ "name": "user",
1970
+ "required": false,
1971
+ "schema": {
1972
+ "type": "string"
1973
+ },
1974
+ "description": "Username to list packages for. If not specified, returns packages for the authenticated user."
1975
+ }
1976
+ ],
1977
+ "responses": {
1978
+ "200": {
1979
+ "description": "List of packages with access details",
1980
+ "content": {
1981
+ "application/json": {
1982
+ "schema": {
1983
+ "type": "array",
1984
+ "items": {
1985
+ "type": "object",
1986
+ "properties": {
1987
+ "name": {
1988
+ "type": "string",
1989
+ "description": "Package name"
1990
+ },
1991
+ "permission": {
1992
+ "type": "string",
1993
+ "enum": ["read-only", "read-write"],
1994
+ "description": "User's permission level"
1995
+ }
1996
+ }
1997
+ }
1998
+ }
1999
+ }
2000
+ }
2001
+ },
2002
+ "401": {
2003
+ "description": "Authentication required"
2004
+ },
2005
+ "403": {
2006
+ "description": "Insufficient permissions"
2007
+ }
2008
+ },
2009
+ "security": [
2010
+ {
2011
+ "bearerAuth": []
2012
+ },
2013
+ {
2014
+ "basicAuth": []
2015
+ }
2016
+ ]
2017
+ }
2018
+ },
2019
+ "/-/package/{pkg}/collaborators/{username}": {
2020
+ "put": {
2021
+ "tags": ["Access"],
2022
+ "summary": "Grant Package Access",
2023
+ "description": "Grants access to a package for a user",
2024
+ "parameters": [
2025
+ {
2026
+ "in": "path",
2027
+ "name": "pkg",
2028
+ "required": true,
2029
+ "schema": {
2030
+ "type": "string"
2031
+ },
2032
+ "description": "Package name (including scope if applicable)"
2033
+ },
2034
+ {
2035
+ "in": "path",
2036
+ "name": "username",
2037
+ "required": true,
2038
+ "schema": {
2039
+ "type": "string"
2040
+ },
2041
+ "description": "Username to grant access to"
2042
+ }
2043
+ ],
2044
+ "requestBody": {
2045
+ "description": "Permission level to grant",
2046
+ "required": true,
2047
+ "content": {
2048
+ "application/json": {
2049
+ "schema": {
2050
+ "type": "object",
2051
+ "required": ["permission"],
2052
+ "properties": {
2053
+ "permission": {
2054
+ "type": "string",
2055
+ "enum": ["read-only", "read-write"],
2056
+ "description": "Permission level to grant"
2057
+ }
2058
+ }
2059
+ }
2060
+ }
2061
+ }
2062
+ },
2063
+ "responses": {
2064
+ "200": {
2065
+ "description": "Access granted successfully",
2066
+ "content": {
2067
+ "application/json": {
2068
+ "schema": {
2069
+ "type": "object",
2070
+ "properties": {
2071
+ "name": {
2072
+ "type": "string",
2073
+ "description": "Package name"
2074
+ },
2075
+ "collaborators": {
2076
+ "type": "object",
2077
+ "additionalProperties": {
2078
+ "type": "string",
2079
+ "enum": ["read-only", "read-write"]
2080
+ },
2081
+ "description": "Map of usernames to permission levels"
2082
+ }
2083
+ }
2084
+ }
2085
+ }
2086
+ }
2087
+ },
2088
+ "401": {
2089
+ "description": "Authentication required"
2090
+ },
2091
+ "403": {
2092
+ "description": "Insufficient permissions"
2093
+ },
2094
+ "404": {
2095
+ "description": "Package not found or user not found"
2096
+ }
2097
+ },
2098
+ "security": [
2099
+ {
2100
+ "bearerAuth": []
2101
+ },
2102
+ {
2103
+ "basicAuth": []
2104
+ }
2105
+ ]
2106
+ },
2107
+ "delete": {
2108
+ "tags": ["Access"],
2109
+ "summary": "Revoke Package Access",
2110
+ "description": "Revokes a user's access to a package",
2111
+ "parameters": [
2112
+ {
2113
+ "in": "path",
2114
+ "name": "pkg",
2115
+ "required": true,
2116
+ "schema": {
2117
+ "type": "string"
2118
+ },
2119
+ "description": "Package name (including scope if applicable)"
2120
+ },
2121
+ {
2122
+ "in": "path",
2123
+ "name": "username",
2124
+ "required": true,
2125
+ "schema": {
2126
+ "type": "string"
2127
+ },
2128
+ "description": "Username to revoke access from"
2129
+ }
2130
+ ],
2131
+ "responses": {
2132
+ "200": {
2133
+ "description": "Access revoked successfully",
2134
+ "content": {
2135
+ "application/json": {
2136
+ "schema": {
2137
+ "type": "object",
2138
+ "properties": {
2139
+ "name": {
2140
+ "type": "string",
2141
+ "description": "Package name"
2142
+ },
2143
+ "collaborators": {
2144
+ "type": "object",
2145
+ "additionalProperties": {
2146
+ "type": "string",
2147
+ "enum": ["read-only", "read-write"]
2148
+ },
2149
+ "description": "Map of remaining usernames to permission levels"
2150
+ }
2151
+ }
2152
+ }
2153
+ }
2154
+ }
2155
+ },
2156
+ "401": {
2157
+ "description": "Authentication required"
2158
+ },
2159
+ "403": {
2160
+ "description": "Insufficient permissions"
2161
+ },
2162
+ "404": {
2163
+ "description": "Package not found or user not found"
2164
+ }
2165
+ },
2166
+ "security": [
2167
+ {
2168
+ "bearerAuth": []
2169
+ },
2170
+ {
2171
+ "basicAuth": []
2172
+ }
2173
+ ]
2174
+ }
2175
+ },
2176
+ "/-/search": {
2177
+ "get": {
2178
+ "tags": ["Search"],
2179
+ "summary": "Search Packages",
2180
+ "description": "Search for packages by text query. Returns packages matching the search criteria.",
2181
+ "parameters": [
2182
+ {
2183
+ "in": "query",
2184
+ "name": "text",
2185
+ "required": true,
2186
+ "schema": {
2187
+ "type": "string"
2188
+ },
2189
+ "description": "Search text to find matching packages"
2190
+ },
2191
+ {
2192
+ "$ref": "#/components/parameters/minimalJsonHeader"
2193
+ }
2194
+ ],
2195
+ "security": [],
2196
+ "responses": {
2197
+ "200": {
2198
+ "description": "Search results",
2199
+ "content": {
2200
+ "application/json": {
2201
+ "schema": {
2202
+ "type": "array",
2203
+ "items": {
2204
+ "type": "object",
2205
+ "properties": {
2206
+ "name": {
2207
+ "type": "string",
2208
+ "description": "Package name"
2209
+ },
2210
+ "tags": {
2211
+ "type": "object",
2212
+ "description": "Distribution tags for the package",
2213
+ "additionalProperties": {
2214
+ "type": "string"
2215
+ },
2216
+ "example": {
2217
+ "latest": "1.0.0"
2218
+ }
2219
+ }
2220
+ }
2221
+ }
2222
+ }
2223
+ }
2224
+ }
2225
+ },
2226
+ "400": {
2227
+ "description": "Bad request, e.g., missing text parameter",
2228
+ "content": {
2229
+ "application/json": {
2230
+ "schema": {
2231
+ "type": "object",
2232
+ "properties": {
2233
+ "error": {
2234
+ "type": "string",
2235
+ "example": "Query parameter is required"
2236
+ }
2237
+ }
2238
+ }
2239
+ }
2240
+ }
2241
+ }
2242
+ }
2243
+ }
2244
+ }
2245
+ }
2246
+ }