@vltpkg/vsr 0.0.0-26 → 0.0.0-27

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 (107) hide show
  1. package/LICENSE +10 -114
  2. package/dist/README.md +1 -0
  3. package/dist/assets/public/favicon.ico +0 -0
  4. package/dist/assets/public/fonts/courier-bold-italic.ttf +0 -0
  5. package/dist/assets/public/fonts/courier-bold.ttf +0 -0
  6. package/dist/assets/public/fonts/courier-italic.ttf +0 -0
  7. package/dist/assets/public/fonts/courier-regular.ttf +0 -0
  8. package/dist/assets/public/fonts/geist-mono.ttf +0 -0
  9. package/dist/assets/public/fonts/inter.ttf +0 -0
  10. package/dist/assets/public/index.html +70 -0
  11. package/dist/assets/public/index.js +1300 -0
  12. package/dist/assets/public/index.js.map +7 -0
  13. package/dist/assets/public/main.css +1 -0
  14. package/dist/bin/vsr.js +771 -0
  15. package/dist/index.js +28283 -0
  16. package/dist/index.js.map +8 -0
  17. package/package.json +6 -49
  18. package/DEPLOY.md +0 -163
  19. package/config.ts +0 -221
  20. package/drizzle.config.js +0 -40
  21. package/info/COMPARISONS.md +0 -37
  22. package/info/CONFIGURATION.md +0 -143
  23. package/info/CONTRIBUTING.md +0 -32
  24. package/info/DATABASE_SETUP.md +0 -108
  25. package/info/GRANULAR_ACCESS_TOKENS.md +0 -160
  26. package/info/PROJECT_STRUCTURE.md +0 -291
  27. package/info/ROADMAP.md +0 -27
  28. package/info/SUPPORT.md +0 -39
  29. package/info/TESTING.md +0 -301
  30. package/info/USER_SUPPORT.md +0 -31
  31. package/scripts/build-assets.js +0 -31
  32. package/scripts/build-bin.js +0 -62
  33. package/scripts/prepack.js +0 -27
  34. package/src/bin/vsr.ts +0 -484
  35. package/src/db/client.ts +0 -590
  36. package/src/db/migrations/0000_faulty_ricochet.sql +0 -14
  37. package/src/db/migrations/0000_initial.sql +0 -29
  38. package/src/db/migrations/0001_uuid_validation.sql +0 -35
  39. package/src/db/migrations/0001_wealthy_magdalene.sql +0 -7
  40. package/src/db/migrations/drop.sql +0 -3
  41. package/src/db/migrations/meta/0000_snapshot.json +0 -104
  42. package/src/db/migrations/meta/0001_snapshot.json +0 -155
  43. package/src/db/migrations/meta/_journal.json +0 -20
  44. package/src/db/schema.ts +0 -43
  45. package/src/index.ts +0 -434
  46. package/src/middleware/config.ts +0 -79
  47. package/src/middleware/telemetry.ts +0 -43
  48. package/src/queue/index.ts +0 -97
  49. package/src/routes/access.ts +0 -852
  50. package/src/routes/docs.ts +0 -63
  51. package/src/routes/misc.ts +0 -469
  52. package/src/routes/packages.ts +0 -2823
  53. package/src/routes/ping.ts +0 -39
  54. package/src/routes/search.ts +0 -131
  55. package/src/routes/static.ts +0 -74
  56. package/src/routes/tokens.ts +0 -259
  57. package/src/routes/users.ts +0 -68
  58. package/src/utils/auth.ts +0 -202
  59. package/src/utils/cache.ts +0 -587
  60. package/src/utils/config.ts +0 -50
  61. package/src/utils/database.ts +0 -69
  62. package/src/utils/docs.ts +0 -146
  63. package/src/utils/packages.ts +0 -453
  64. package/src/utils/response.ts +0 -125
  65. package/src/utils/routes.ts +0 -64
  66. package/src/utils/spa.ts +0 -52
  67. package/src/utils/tracing.ts +0 -52
  68. package/src/utils/upstream.ts +0 -172
  69. package/test/access.test.ts +0 -705
  70. package/test/audit.test.ts +0 -828
  71. package/test/dashboard.test.ts +0 -693
  72. package/test/dist-tags.test.ts +0 -678
  73. package/test/manifest.test.ts +0 -436
  74. package/test/packument.test.ts +0 -530
  75. package/test/ping.test.ts +0 -41
  76. package/test/search.test.ts +0 -472
  77. package/test/setup.ts +0 -130
  78. package/test/static.test.ts +0 -646
  79. package/test/tokens.test.ts +0 -389
  80. package/test/utils/auth.test.ts +0 -214
  81. package/test/utils/packages.test.ts +0 -235
  82. package/test/utils/response.test.ts +0 -184
  83. package/test/whoami.test.ts +0 -119
  84. package/tsconfig.json +0 -16
  85. package/tsconfig.worker.json +0 -3
  86. package/typedoc.mjs +0 -2
  87. package/types.ts +0 -598
  88. package/vitest.config.ts +0 -25
  89. package/vlt.json.example +0 -56
  90. package/wrangler.json +0 -65
  91. /package/{src → dist}/assets/public/images/bg.png +0 -0
  92. /package/{src → dist}/assets/public/images/clients/logo-bun.png +0 -0
  93. /package/{src → dist}/assets/public/images/clients/logo-deno.png +0 -0
  94. /package/{src → dist}/assets/public/images/clients/logo-npm.png +0 -0
  95. /package/{src → dist}/assets/public/images/clients/logo-pnpm.png +0 -0
  96. /package/{src → dist}/assets/public/images/clients/logo-vlt.png +0 -0
  97. /package/{src → dist}/assets/public/images/clients/logo-yarn.png +0 -0
  98. /package/{src → dist}/assets/public/images/favicon/apple-touch-icon.png +0 -0
  99. /package/{src → dist}/assets/public/images/favicon/favicon-96x96.png +0 -0
  100. /package/{src → dist}/assets/public/images/favicon/favicon.ico +0 -0
  101. /package/{src → dist}/assets/public/images/favicon/favicon.svg +0 -0
  102. /package/{src → dist}/assets/public/images/favicon/site.webmanifest +0 -0
  103. /package/{src → dist}/assets/public/images/favicon/web-app-manifest-192x192.png +0 -0
  104. /package/{src → dist}/assets/public/images/favicon/web-app-manifest-512x512.png +0 -0
  105. /package/{src → dist}/assets/public/styles/styles.css +0 -0
  106. /package/{src → dist}/bin/demo/package.json +0 -0
  107. /package/{src → dist}/bin/demo/vlt.json +0 -0
@@ -1,389 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { env } from 'cloudflare:test'
3
- import { app } from '../src/index.ts'
4
-
5
- describe('Token Management Endpoints', () => {
6
- describe('Root Registry Token Management', () => {
7
- describe('GET /-/tokens', () => {
8
- it('should require authentication for token listing', async () => {
9
- const res = await app.request('/-/tokens', {}, env)
10
- expect([200, 400, 401].includes(res.status)).toBe(true)
11
- expect(res.headers.get('content-type')).toContain(
12
- 'application/json',
13
- )
14
- })
15
-
16
- it('should handle authenticated token listing', async () => {
17
- const res = await app.request(
18
- '/-/tokens',
19
- {
20
- headers: {
21
- Authorization: 'Bearer test-admin-token-12345',
22
- },
23
- },
24
- env,
25
- )
26
- expect([200, 400, 401].includes(res.status)).toBe(true)
27
- expect(res.headers.get('content-type')).toContain(
28
- 'application/json',
29
- )
30
- })
31
-
32
- it('should return proper JSON structure for token list', async () => {
33
- const res = await app.request('/-/tokens', {}, env)
34
- expect([200, 400, 401].includes(res.status)).toBe(true)
35
- if (res.status === 200) {
36
- const data = (await res.json()) as any
37
- expect(data).toBeDefined()
38
- }
39
- })
40
- })
41
-
42
- describe('POST /-/tokens', () => {
43
- it('should handle token creation requests', async () => {
44
- const res = await app.request(
45
- '/-/tokens',
46
- {
47
- method: 'POST',
48
- headers: {
49
- 'Content-Type': 'application/json',
50
- },
51
- body: JSON.stringify({
52
- password: 'test-password',
53
- readonly: false,
54
- cidr_whitelist: [],
55
- }),
56
- },
57
- env,
58
- )
59
- expect([200, 400, 401, 500].includes(res.status)).toBe(true)
60
- expect(res.headers.get('content-type')).toContain(
61
- 'application/json',
62
- )
63
- })
64
-
65
- it('should handle token creation with readonly flag', async () => {
66
- const res = await app.request(
67
- '/-/tokens',
68
- {
69
- method: 'POST',
70
- headers: {
71
- 'Content-Type': 'application/json',
72
- },
73
- body: JSON.stringify({
74
- password: 'test-password',
75
- readonly: true,
76
- cidr_whitelist: [],
77
- }),
78
- },
79
- env,
80
- )
81
- expect([200, 400, 401, 500].includes(res.status)).toBe(true)
82
- expect(res.headers.get('content-type')).toContain(
83
- 'application/json',
84
- )
85
- })
86
-
87
- it('should validate required fields for token creation', async () => {
88
- const res = await app.request(
89
- '/-/tokens',
90
- {
91
- method: 'POST',
92
- headers: {
93
- 'Content-Type': 'application/json',
94
- },
95
- body: JSON.stringify({}),
96
- },
97
- env,
98
- )
99
- expect([400, 401, 500].includes(res.status)).toBe(true)
100
- })
101
- })
102
-
103
- describe('PUT /-/tokens', () => {
104
- it('should handle token update requests', async () => {
105
- const res = await app.request(
106
- '/-/tokens',
107
- {
108
- method: 'PUT',
109
- headers: {
110
- 'Content-Type': 'application/json',
111
- },
112
- body: JSON.stringify({
113
- token: 'existing-token',
114
- readonly: true,
115
- }),
116
- },
117
- env,
118
- )
119
- expect([200, 400, 401, 404, 500].includes(res.status)).toBe(
120
- true,
121
- )
122
- expect(res.headers.get('content-type')).toContain(
123
- 'application/json',
124
- )
125
- })
126
-
127
- it('should handle token scope updates', async () => {
128
- const res = await app.request(
129
- '/-/tokens',
130
- {
131
- method: 'PUT',
132
- headers: {
133
- 'Content-Type': 'application/json',
134
- },
135
- body: JSON.stringify({
136
- token: 'existing-token',
137
- cidr_whitelist: ['192.168.1.0/24'],
138
- }),
139
- },
140
- env,
141
- )
142
- expect([200, 400, 401, 404, 500].includes(res.status)).toBe(
143
- true,
144
- )
145
- })
146
- })
147
-
148
- describe('DELETE /-/tokens/{token}', () => {
149
- it('should handle token deletion requests', async () => {
150
- const res = await app.request(
151
- '/-/tokens/test-token-to-delete',
152
- {
153
- method: 'DELETE',
154
- },
155
- env,
156
- )
157
- expect([200, 401, 404, 500].includes(res.status)).toBe(true)
158
- if (res.status !== 404) {
159
- expect(res.headers.get('content-type')).toContain(
160
- 'application/json',
161
- )
162
- }
163
- })
164
-
165
- it('should require valid token for deletion', async () => {
166
- const res = await app.request(
167
- '/-/tokens/invalid-token',
168
- {
169
- method: 'DELETE',
170
- },
171
- env,
172
- )
173
- expect([401, 404, 500].includes(res.status)).toBe(true)
174
- })
175
-
176
- it('should handle authenticated token deletion', async () => {
177
- const res = await app.request(
178
- '/-/tokens/test-token-to-delete',
179
- {
180
- method: 'DELETE',
181
- headers: {
182
- Authorization: 'Bearer test-admin-token-12345',
183
- },
184
- },
185
- env,
186
- )
187
- expect([200, 404, 500].includes(res.status)).toBe(true)
188
- })
189
- })
190
- })
191
-
192
- describe('Upstream Registry Token Management', () => {
193
- describe('Upstream Token Endpoints', () => {
194
- it('should handle upstream token listing', async () => {
195
- const res = await app.request('/npm/-/tokens', {}, env)
196
- expect([200, 400, 401].includes(res.status)).toBe(true)
197
- expect(res.headers.get('content-type')).toContain(
198
- 'application/json',
199
- )
200
- })
201
-
202
- it('should handle upstream token creation', async () => {
203
- const res = await app.request(
204
- '/npm/-/tokens',
205
- {
206
- method: 'POST',
207
- headers: {
208
- 'Content-Type': 'application/json',
209
- },
210
- body: JSON.stringify({
211
- password: 'test-password',
212
- readonly: false,
213
- }),
214
- },
215
- env,
216
- )
217
- expect([200, 400, 401, 500].includes(res.status)).toBe(true)
218
- })
219
-
220
- it('should handle upstream token updates', async () => {
221
- const res = await app.request(
222
- '/npm/-/tokens',
223
- {
224
- method: 'PUT',
225
- headers: {
226
- 'Content-Type': 'application/json',
227
- },
228
- body: JSON.stringify({
229
- token: 'existing-token',
230
- readonly: true,
231
- }),
232
- },
233
- env,
234
- )
235
- expect([200, 400, 401, 404, 500].includes(res.status)).toBe(
236
- true,
237
- )
238
- })
239
-
240
- it('should handle upstream token deletion', async () => {
241
- const res = await app.request(
242
- '/npm/-/tokens/test-token',
243
- {
244
- method: 'DELETE',
245
- },
246
- env,
247
- )
248
- expect([200, 401, 404, 500].includes(res.status)).toBe(true)
249
- })
250
- })
251
-
252
- describe('Different Upstream Registries', () => {
253
- it('should handle JSR token management', async () => {
254
- const res = await app.request('/jsr/-/tokens', {}, env)
255
- expect([200, 400, 401].includes(res.status)).toBe(true)
256
- })
257
-
258
- it('should handle custom upstream token management', async () => {
259
- const res = await app.request('/custom/-/tokens', {}, env)
260
- expect([200, 400, 401].includes(res.status)).toBe(true)
261
- })
262
-
263
- it('should handle local upstream token management', async () => {
264
- const res = await app.request('/local/-/tokens', {}, env)
265
- expect([200, 400, 401].includes(res.status)).toBe(true)
266
- })
267
- })
268
- })
269
-
270
- describe('Token Response Structure', () => {
271
- describe('Token List Response', () => {
272
- it('should return proper structure for token listing', async () => {
273
- const res = await app.request('/-/tokens', {}, env)
274
- expect([200, 400, 401].includes(res.status)).toBe(true)
275
- if (res.status === 200) {
276
- const data = (await res.json()) as any
277
- expect(data).toBeDefined()
278
- // Token list structure validation would depend on actual implementation
279
- }
280
- })
281
- })
282
-
283
- describe('Token Creation Response', () => {
284
- it('should return token details on successful creation', async () => {
285
- const res = await app.request(
286
- '/-/tokens',
287
- {
288
- method: 'POST',
289
- headers: {
290
- 'Content-Type': 'application/json',
291
- },
292
- body: JSON.stringify({
293
- password: 'test-password',
294
- readonly: false,
295
- }),
296
- },
297
- env,
298
- )
299
- if (res.status === 200) {
300
- const data = (await res.json()) as any
301
- expect(data).toBeDefined()
302
- // Would validate token structure based on implementation
303
- }
304
- })
305
- })
306
- })
307
-
308
- describe('Error Handling', () => {
309
- describe('Invalid Requests', () => {
310
- it('should handle malformed JSON in token creation', async () => {
311
- const res = await app.request(
312
- '/-/tokens',
313
- {
314
- method: 'POST',
315
- headers: {
316
- 'Content-Type': 'application/json',
317
- },
318
- body: 'invalid-json',
319
- },
320
- env,
321
- )
322
- expect([400, 500].includes(res.status)).toBe(true)
323
- })
324
-
325
- it('should handle missing content-type header', async () => {
326
- const res = await app.request(
327
- '/-/tokens',
328
- {
329
- method: 'POST',
330
- body: JSON.stringify({
331
- password: 'test-password',
332
- }),
333
- },
334
- env,
335
- )
336
- expect([400, 415, 500].includes(res.status)).toBe(true)
337
- })
338
- })
339
-
340
- describe('Authentication Errors', () => {
341
- it('should handle invalid authentication tokens', async () => {
342
- const res = await app.request(
343
- '/-/tokens/some-token',
344
- {
345
- method: 'DELETE',
346
- headers: {
347
- Authorization: 'Bearer invalid-token',
348
- },
349
- },
350
- env,
351
- )
352
- expect([401, 404, 500].includes(res.status)).toBe(true)
353
- })
354
-
355
- it('should handle malformed authorization headers', async () => {
356
- const res = await app.request(
357
- '/-/tokens/some-token',
358
- {
359
- method: 'DELETE',
360
- headers: {
361
- Authorization: 'InvalidFormat',
362
- },
363
- },
364
- env,
365
- )
366
- expect([401, 404, 500].includes(res.status)).toBe(true)
367
- })
368
- })
369
- })
370
-
371
- describe('Response Headers and Caching', () => {
372
- describe('Content-Type Headers', () => {
373
- it('should set appropriate content-type for token responses', async () => {
374
- const res = await app.request('/-/tokens', {}, env)
375
- expect(res.headers.get('content-type')).toContain(
376
- 'application/json',
377
- )
378
- })
379
- })
380
-
381
- describe('Security Headers', () => {
382
- it('should include security headers in token responses', async () => {
383
- const res = await app.request('/-/tokens', {}, env)
384
- // Security headers would be validated based on implementation
385
- expect(res.status).toBeDefined()
386
- })
387
- })
388
- })
389
- })
@@ -1,214 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest'
2
- import {
3
- getTokenFromHeader,
4
- parseTokenAccess,
5
- } from '../../src/utils/auth.ts'
6
- import type { HonoContext, TokenScope } from '../../types.ts'
7
-
8
- describe('Auth Utils', () => {
9
- describe('getTokenFromHeader', () => {
10
- it('should extract token from Bearer authorization header', () => {
11
- const mockContext = {
12
- req: {
13
- header: vi.fn().mockReturnValue('Bearer test-token-12345'),
14
- },
15
- } as unknown as HonoContext
16
-
17
- const token = getTokenFromHeader(mockContext)
18
- expect(token).toBe('test-token-12345')
19
- expect(mockContext.req.header).toHaveBeenCalledWith(
20
- 'Authorization',
21
- )
22
- })
23
-
24
- it('should handle Bearer token with extra whitespace', () => {
25
- const mockContext = {
26
- req: {
27
- header: vi
28
- .fn()
29
- .mockReturnValue('Bearer test-token-with-spaces '),
30
- },
31
- } as unknown as HonoContext
32
-
33
- const token = getTokenFromHeader(mockContext)
34
- expect(token).toBe('test-token-with-spaces')
35
- })
36
-
37
- it('should return null for missing authorization header', () => {
38
- const mockContext = {
39
- req: {
40
- header: vi.fn().mockReturnValue(undefined),
41
- },
42
- } as unknown as HonoContext
43
-
44
- const token = getTokenFromHeader(mockContext)
45
- expect(token).toBeNull()
46
- })
47
-
48
- it('should return null for non-Bearer authorization header', () => {
49
- const mockContext = {
50
- req: {
51
- header: vi.fn().mockReturnValue('Basic dXNlcjpwYXNz'),
52
- },
53
- } as unknown as HonoContext
54
-
55
- const token = getTokenFromHeader(mockContext)
56
- expect(token).toBeNull()
57
- })
58
-
59
- it('should return empty string for malformed Bearer header', () => {
60
- const mockContext = {
61
- req: {
62
- header: vi.fn().mockReturnValue('Bearer '),
63
- },
64
- } as unknown as HonoContext
65
-
66
- const token = getTokenFromHeader(mockContext)
67
- expect(token).toBe('')
68
- })
69
- })
70
-
71
- describe('parseTokenAccess', () => {
72
- it('should parse read-only access for any package', () => {
73
- const scope: TokenScope[] = [
74
- {
75
- types: { pkg: { read: true, write: false } },
76
- values: ['*'],
77
- },
78
- ]
79
-
80
- const access = parseTokenAccess({
81
- scope,
82
- uuid: 'test-user-uuid',
83
- })
84
-
85
- expect(access.anyPackage).toBe(true)
86
- expect(access.specificPackage).toBe(false)
87
- expect(access.readAccess).toBe(true)
88
- expect(access.writeAccess).toBe(false)
89
- expect(access.methods).toEqual(['get'])
90
- })
91
-
92
- it('should parse write access for specific package', () => {
93
- const scope: TokenScope[] = [
94
- {
95
- types: { pkg: { read: false, write: true } },
96
- values: ['my-package'],
97
- },
98
- ]
99
-
100
- const access = parseTokenAccess({
101
- scope,
102
- pkg: 'my-package',
103
- uuid: 'test-user-uuid',
104
- })
105
-
106
- expect(access.anyPackage).toBe(false)
107
- expect(access.specificPackage).toBe(true)
108
- expect(access.readAccess).toBe(false)
109
- expect(access.writeAccess).toBe(true)
110
- expect(access.methods).toEqual(['put', 'post', 'delete'])
111
- })
112
-
113
- it('should parse user-specific access', () => {
114
- const scope: TokenScope[] = [
115
- {
116
- types: { user: { read: true, write: true } },
117
- values: ['~test-user-uuid'],
118
- },
119
- ]
120
-
121
- const access = parseTokenAccess({
122
- scope,
123
- uuid: 'test-user-uuid',
124
- })
125
-
126
- expect(access.anyUser).toBe(false)
127
- expect(access.specificUser).toBe(true)
128
- expect(access.readAccess).toBe(true)
129
- expect(access.writeAccess).toBe(true)
130
- expect(access.methods).toEqual(['get', 'put', 'post', 'delete'])
131
- })
132
-
133
- it('should parse wildcard user access', () => {
134
- const scope: TokenScope[] = [
135
- {
136
- types: { user: { read: true, write: false } },
137
- values: ['*'],
138
- },
139
- ]
140
-
141
- const access = parseTokenAccess({
142
- scope,
143
- uuid: 'any-user-uuid',
144
- })
145
-
146
- expect(access.anyUser).toBe(true)
147
- expect(access.specificUser).toBe(false)
148
- expect(access.readAccess).toBe(true)
149
- expect(access.writeAccess).toBe(false)
150
- })
151
-
152
- it('should handle multiple scopes with combined permissions', () => {
153
- const scope: TokenScope[] = [
154
- {
155
- types: { pkg: { read: true, write: false } },
156
- values: ['package-1'],
157
- },
158
- {
159
- types: { pkg: { read: false, write: true } },
160
- values: ['package-1'],
161
- },
162
- ]
163
-
164
- const access = parseTokenAccess({
165
- scope,
166
- pkg: 'package-1',
167
- uuid: 'test-user-uuid',
168
- })
169
-
170
- expect(access.specificPackage).toBe(true)
171
- expect(access.readAccess).toBe(true)
172
- expect(access.writeAccess).toBe(true)
173
- expect(access.methods).toEqual(['get', 'put', 'post', 'delete'])
174
- })
175
-
176
- it('should handle empty scope array', () => {
177
- const scope: TokenScope[] = []
178
-
179
- const access = parseTokenAccess({
180
- scope,
181
- uuid: 'test-user-uuid',
182
- })
183
-
184
- expect(access.anyUser).toBe(false)
185
- expect(access.specificUser).toBe(false)
186
- expect(access.anyPackage).toBe(false)
187
- expect(access.specificPackage).toBe(false)
188
- expect(access.readAccess).toBe(false)
189
- expect(access.writeAccess).toBe(false)
190
- expect(access.methods).toEqual([])
191
- })
192
-
193
- it('should handle scope with no matching package', () => {
194
- const scope: TokenScope[] = [
195
- {
196
- types: { pkg: true, user: false },
197
- values: ['other-package'],
198
- methods: ['get', 'put'],
199
- },
200
- ]
201
-
202
- const access = parseTokenAccess({
203
- scope,
204
- pkg: 'my-package',
205
- uuid: 'test-user-uuid',
206
- })
207
-
208
- expect(access.specificPackage).toBe(false)
209
- expect(access.readAccess).toBe(false)
210
- expect(access.writeAccess).toBe(false)
211
- expect(access.methods).toEqual([])
212
- })
213
- })
214
- })