@verdaccio/store 6.0.0-6-next.21 → 6.0.0-6-next.24
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/CHANGELOG.md +92 -0
- package/build/index.d.ts +5 -4
- package/build/index.js +31 -15
- package/build/index.js.map +1 -1
- package/build/lib/TransFormResults.d.ts +15 -0
- package/build/lib/TransFormResults.js +61 -0
- package/build/lib/TransFormResults.js.map +1 -0
- package/build/lib/search-utils.d.ts +4 -0
- package/build/lib/search-utils.js +59 -0
- package/build/lib/search-utils.js.map +1 -0
- package/build/lib/star-utils.d.ts +14 -0
- package/build/{star-utils.js → lib/star-utils.js} +16 -2
- package/build/lib/star-utils.js.map +1 -0
- package/build/lib/storage-utils.d.ts +82 -0
- package/build/{storage-utils.js → lib/storage-utils.js} +173 -60
- package/build/lib/storage-utils.js.map +1 -0
- package/build/lib/uplink-util.d.ts +10 -0
- package/build/lib/uplink-util.js +49 -0
- package/build/lib/uplink-util.js.map +1 -0
- package/build/lib/versions-utils.d.ts +28 -0
- package/build/lib/versions-utils.js +104 -0
- package/build/lib/versions-utils.js.map +1 -0
- package/build/local-storage.d.ts +3 -165
- package/build/local-storage.js +6 -1166
- package/build/local-storage.js.map +1 -1
- package/build/storage.d.ts +242 -86
- package/build/storage.js +1681 -548
- package/build/storage.js.map +1 -1
- package/build/type.d.ts +42 -19
- package/build/type.js.map +1 -1
- package/jest.config.js +8 -2
- package/package.json +71 -71
- package/src/index.ts +5 -4
- package/src/lib/TransFormResults.ts +42 -0
- package/src/lib/search-utils.ts +50 -0
- package/src/{star-utils.ts → lib/star-utils.ts} +16 -5
- package/src/lib/storage-utils.ts +362 -0
- package/src/lib/uplink-util.ts +41 -0
- package/src/lib/versions-utils.ts +87 -0
- package/src/local-storage.ts +7 -1217
- package/src/storage.ts +1683 -635
- package/src/type.ts +47 -21
- package/test/fixtures/config/getTarballNext-getupstream.yaml +17 -0
- package/test/fixtures/config/syncDoubleUplinksMetadata.yaml +25 -0
- package/test/fixtures/config/syncNoUplinksMetadata.yaml +17 -0
- package/test/fixtures/config/syncSingleUplinksMetadata.yaml +21 -0
- package/test/fixtures/config/updateManifest-1.yaml +16 -0
- package/test/fixtures/manifests/foo-npmjs.json +253 -0
- package/test/fixtures/manifests/foo-verdaccio.json +253 -0
- package/test/fixtures/tarball.tgz +0 -0
- package/test/helpers.ts +22 -0
- package/test/local-store.__disabled__.ts +553 -0
- package/test/search.spec.ts +4 -5
- package/test/star.spec.ts +31 -0
- package/test/storage-utils.spec.ts +129 -42
- package/test/storage.spec.ts +943 -33
- package/test/versions.spec.ts +109 -0
- package/tsconfig.json +6 -3
- package/build/search.d.ts +0 -35
- package/build/search.js +0 -198
- package/build/search.js.map +0 -1
- package/build/star-utils.d.ts +0 -9
- package/build/star-utils.js.map +0 -1
- package/build/storage-utils.d.ts +0 -39
- package/build/storage-utils.js.map +0 -1
- package/build/uplink-util.d.ts +0 -7
- package/build/uplink-util.js +0 -38
- package/build/uplink-util.js.map +0 -1
- package/src/search.ts +0 -175
- package/src/storage-utils.ts +0 -263
- package/src/uplink-util.ts +0 -32
- package/test/local-storage.spec.ts +0 -583
package/test/storage.spec.ts
CHANGED
|
@@ -1,17 +1,36 @@
|
|
|
1
|
+
import { pseudoRandomBytes } from 'crypto';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import MockDate from 'mockdate';
|
|
1
4
|
import nock from 'nock';
|
|
2
5
|
import * as httpMocks from 'node-mocks-http';
|
|
6
|
+
import os from 'os';
|
|
7
|
+
import path from 'path';
|
|
3
8
|
|
|
4
|
-
import { Config } from '@verdaccio/config';
|
|
5
|
-
import { HEADERS, errorUtils } from '@verdaccio/core';
|
|
9
|
+
import { Config, getDefaultConfig } from '@verdaccio/config';
|
|
10
|
+
import { API_ERROR, DIST_TAGS, HEADERS, HEADER_TYPE, errorUtils, fileUtils } from '@verdaccio/core';
|
|
6
11
|
import { setup } from '@verdaccio/logger';
|
|
7
|
-
import {
|
|
8
|
-
|
|
12
|
+
import {
|
|
13
|
+
addNewVersion,
|
|
14
|
+
generateLocalPackageMetadata,
|
|
15
|
+
generatePackageMetadata,
|
|
16
|
+
generateRemotePackageMetadata,
|
|
17
|
+
} from '@verdaccio/test-helper';
|
|
18
|
+
import { AbbreviatedManifest, Manifest, Version } from '@verdaccio/types';
|
|
9
19
|
|
|
10
20
|
import { Storage } from '../src';
|
|
21
|
+
import manifestFooRemoteNpmjs from './fixtures/manifests/foo-npmjs.json';
|
|
22
|
+
import { configExample } from './helpers';
|
|
11
23
|
|
|
12
|
-
|
|
24
|
+
function generateRandomStorage() {
|
|
25
|
+
const tempStorage = pseudoRandomBytes(5).toString('hex');
|
|
26
|
+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), '/verdaccio-test'));
|
|
13
27
|
|
|
14
|
-
|
|
28
|
+
return path.join(tempRoot, tempStorage);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
setup({ type: 'stdout', format: 'pretty', level: 'trace' });
|
|
32
|
+
|
|
33
|
+
const domain = 'https://registry.npmjs.org';
|
|
15
34
|
const fakeHost = 'localhost:4873';
|
|
16
35
|
const fooManifest = generatePackageMetadata('foo', '1.0.0');
|
|
17
36
|
|
|
@@ -21,31 +40,846 @@ describe('storage', () => {
|
|
|
21
40
|
nock.abortPendingRequests();
|
|
22
41
|
jest.clearAllMocks();
|
|
23
42
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
43
|
+
|
|
44
|
+
describe('updateManifest', () => {
|
|
45
|
+
test('create private package', async () => {
|
|
46
|
+
const mockDate = '2018-01-14T11:17:40.712Z';
|
|
47
|
+
MockDate.set(mockDate);
|
|
48
|
+
const pkgName = 'upstream';
|
|
49
|
+
const requestOptions = {
|
|
50
|
+
host: 'localhost',
|
|
51
|
+
protocol: 'http',
|
|
52
|
+
headers: {},
|
|
53
|
+
};
|
|
54
|
+
const config = new Config(
|
|
55
|
+
configExample(
|
|
56
|
+
{
|
|
57
|
+
...getDefaultConfig(),
|
|
58
|
+
storage: generateRandomStorage(),
|
|
59
|
+
},
|
|
60
|
+
'./fixtures/config/updateManifest-1.yaml',
|
|
61
|
+
__dirname
|
|
62
|
+
)
|
|
63
|
+
);
|
|
64
|
+
const storage = new Storage(config);
|
|
65
|
+
await storage.init(config);
|
|
66
|
+
const bodyNewManifest = generatePackageMetadata(pkgName, '1.0.0');
|
|
67
|
+
await storage.updateManifest(bodyNewManifest, {
|
|
68
|
+
signal: new AbortController().signal,
|
|
69
|
+
name: pkgName,
|
|
70
|
+
uplinksLook: true,
|
|
71
|
+
revision: '1',
|
|
72
|
+
requestOptions,
|
|
73
|
+
});
|
|
74
|
+
const manifest = (await storage.getPackageByOptions({
|
|
75
|
+
name: pkgName,
|
|
76
|
+
uplinksLook: true,
|
|
77
|
+
requestOptions,
|
|
78
|
+
})) as Manifest;
|
|
79
|
+
expect(manifest.name).toEqual(pkgName);
|
|
80
|
+
expect(manifest._id).toEqual(pkgName);
|
|
81
|
+
expect(Object.keys(manifest.versions)).toEqual(['1.0.0']);
|
|
82
|
+
expect(manifest.time).toEqual({
|
|
83
|
+
'1.0.0': mockDate,
|
|
84
|
+
created: mockDate,
|
|
85
|
+
modified: mockDate,
|
|
86
|
+
});
|
|
87
|
+
expect(manifest[DIST_TAGS]).toEqual({ latest: '1.0.0' });
|
|
88
|
+
expect(manifest.readme).toEqual('# test');
|
|
89
|
+
expect(manifest._attachments).toEqual({});
|
|
90
|
+
expect(typeof manifest._rev).toBeTruthy();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// TODO: Review triggerUncaughtException exception on abort
|
|
94
|
+
test.skip('abort creating a private package', async () => {
|
|
95
|
+
const mockDate = '2018-01-14T11:17:40.712Z';
|
|
96
|
+
MockDate.set(mockDate);
|
|
97
|
+
const pkgName = 'upstream';
|
|
98
|
+
const config = new Config(
|
|
99
|
+
configExample(
|
|
100
|
+
{
|
|
101
|
+
storage: generateRandomStorage(),
|
|
102
|
+
},
|
|
103
|
+
'./fixtures/config/updateManifest-1.yaml',
|
|
104
|
+
__dirname
|
|
105
|
+
)
|
|
106
|
+
);
|
|
107
|
+
const storage = new Storage(config);
|
|
108
|
+
await storage.init(config);
|
|
109
|
+
const ac = new AbortController();
|
|
110
|
+
setTimeout(() => {
|
|
111
|
+
ac.abort();
|
|
112
|
+
}, 10);
|
|
113
|
+
const bodyNewManifest = generatePackageMetadata(pkgName, '1.0.0');
|
|
114
|
+
await expect(
|
|
115
|
+
storage.updateManifest(bodyNewManifest, {
|
|
116
|
+
signal: ac.signal,
|
|
117
|
+
name: pkgName,
|
|
118
|
+
uplinksLook: true,
|
|
119
|
+
revision: '1',
|
|
120
|
+
requestOptions: {
|
|
121
|
+
host: 'localhost',
|
|
122
|
+
protocol: 'http',
|
|
123
|
+
headers: {},
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
).rejects.toThrow('should throw here');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('create private package with multiple consecutive versions', async () => {
|
|
130
|
+
const mockDate = '2018-01-14T11:17:40.712Z';
|
|
131
|
+
MockDate.set(mockDate);
|
|
132
|
+
const settings = {
|
|
133
|
+
uplinksLook: true,
|
|
134
|
+
revision: '1',
|
|
135
|
+
requestOptions: {
|
|
136
|
+
host: 'localhost',
|
|
137
|
+
protocol: 'http',
|
|
138
|
+
headers: {},
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
const pkgName = 'upstream';
|
|
142
|
+
// const storage = generateRandomStorage();
|
|
143
|
+
const config = new Config(
|
|
144
|
+
configExample(
|
|
145
|
+
{
|
|
146
|
+
storage: await fileUtils.createTempStorageFolder('storage-test'),
|
|
147
|
+
},
|
|
148
|
+
'./fixtures/config/updateManifest-1.yaml',
|
|
149
|
+
__dirname
|
|
150
|
+
)
|
|
151
|
+
);
|
|
152
|
+
const storage = new Storage(config);
|
|
153
|
+
await storage.init(config);
|
|
154
|
+
// create a package
|
|
155
|
+
const bodyNewManifest1 = generatePackageMetadata(pkgName, '1.0.0');
|
|
156
|
+
await storage.updateManifest(bodyNewManifest1, {
|
|
157
|
+
signal: new AbortController().signal,
|
|
158
|
+
name: pkgName,
|
|
159
|
+
...settings,
|
|
160
|
+
});
|
|
161
|
+
// publish second version
|
|
162
|
+
const bodyNewManifest2 = generatePackageMetadata(pkgName, '1.0.1');
|
|
163
|
+
await storage.updateManifest(bodyNewManifest2, {
|
|
164
|
+
signal: new AbortController().signal,
|
|
165
|
+
name: pkgName,
|
|
166
|
+
...settings,
|
|
167
|
+
});
|
|
168
|
+
// retrieve package metadata
|
|
169
|
+
const manifest = (await storage.getPackageByOptions({
|
|
170
|
+
name: pkgName,
|
|
171
|
+
uplinksLook: true,
|
|
172
|
+
requestOptions: {
|
|
173
|
+
host: 'localhost',
|
|
174
|
+
protocol: 'http',
|
|
175
|
+
headers: {},
|
|
176
|
+
},
|
|
177
|
+
})) as Manifest;
|
|
178
|
+
expect(manifest.name).toEqual(pkgName);
|
|
179
|
+
expect(manifest._id).toEqual(pkgName);
|
|
180
|
+
expect(Object.keys(manifest.versions)).toEqual(['1.0.0', '1.0.1']);
|
|
181
|
+
expect(manifest.time).toEqual({
|
|
182
|
+
'1.0.0': mockDate,
|
|
183
|
+
'1.0.1': mockDate,
|
|
184
|
+
created: mockDate,
|
|
185
|
+
modified: mockDate,
|
|
186
|
+
});
|
|
187
|
+
expect(manifest[DIST_TAGS]).toEqual({ latest: '1.0.1' });
|
|
188
|
+
expect(manifest.readme).toEqual('# test');
|
|
189
|
+
expect(manifest._attachments).toEqual({});
|
|
190
|
+
expect(typeof manifest._rev).toBeTruthy();
|
|
191
|
+
// verify the version structure is correct
|
|
192
|
+
const manifestVersion = (await storage.getPackageByOptions({
|
|
193
|
+
name: pkgName,
|
|
194
|
+
version: '1.0.1',
|
|
195
|
+
uplinksLook: true,
|
|
196
|
+
requestOptions: {
|
|
197
|
+
host: 'localhost',
|
|
198
|
+
protocol: 'http',
|
|
199
|
+
headers: {},
|
|
200
|
+
},
|
|
201
|
+
})) as Version;
|
|
202
|
+
expect(manifestVersion.name).toEqual(pkgName);
|
|
203
|
+
expect(manifestVersion.version).toEqual('1.0.1');
|
|
204
|
+
expect(manifestVersion._id).toEqual(`${pkgName}@1.0.1`);
|
|
205
|
+
expect(manifestVersion.description).toEqual('package generated');
|
|
206
|
+
expect(manifestVersion.dist).toEqual({
|
|
207
|
+
integrity:
|
|
208
|
+
'sha512-6gHiERpiDgtb3hjqpQH5/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr9cmE6dUBf+XoPoH4g==',
|
|
209
|
+
shasum: '2c03764f651a9f016ca0b7620421457b619151b9',
|
|
210
|
+
tarball: 'http://localhost:5555/upstream/-/upstream-1.0.1.tgz',
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
expect(manifestVersion.contributors).toEqual([]);
|
|
214
|
+
expect(manifestVersion.main).toEqual('index.js');
|
|
215
|
+
expect(manifestVersion.author).toEqual({ name: 'User NPM', email: 'user@domain.com' });
|
|
216
|
+
expect(manifestVersion.dependencies).toEqual({ verdaccio: '^2.7.2' });
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test('fails if version already exist', async () => {
|
|
220
|
+
const settings = {
|
|
221
|
+
uplinksLook: true,
|
|
222
|
+
revision: '1',
|
|
223
|
+
requestOptions: {
|
|
224
|
+
host: 'localhost',
|
|
225
|
+
protocol: 'http',
|
|
226
|
+
headers: {},
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
const pkgName = 'upstream';
|
|
230
|
+
const config = new Config(
|
|
231
|
+
configExample(
|
|
232
|
+
{
|
|
233
|
+
storage: generateRandomStorage(),
|
|
234
|
+
},
|
|
235
|
+
'./fixtures/config/getTarballNext-getupstream.yaml',
|
|
236
|
+
__dirname
|
|
237
|
+
)
|
|
238
|
+
);
|
|
239
|
+
const storage = new Storage(config);
|
|
240
|
+
await storage.init(config);
|
|
241
|
+
const bodyNewManifest1 = generatePackageMetadata(pkgName, '1.0.0');
|
|
242
|
+
const bodyNewManifest2 = generatePackageMetadata(pkgName, '1.0.0');
|
|
243
|
+
await storage.updateManifest(bodyNewManifest1, {
|
|
244
|
+
signal: new AbortController().signal,
|
|
245
|
+
name: pkgName,
|
|
246
|
+
...settings,
|
|
247
|
+
});
|
|
248
|
+
await expect(
|
|
249
|
+
storage.updateManifest(bodyNewManifest2, {
|
|
250
|
+
signal: new AbortController().signal,
|
|
251
|
+
name: pkgName,
|
|
252
|
+
...settings,
|
|
253
|
+
})
|
|
254
|
+
).rejects.toThrow(API_ERROR.PACKAGE_EXIST);
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
describe('getTarballNext', () => {
|
|
259
|
+
test('should not found a package anywhere', (done) => {
|
|
27
260
|
const config = new Config(
|
|
28
261
|
configExample({
|
|
29
|
-
|
|
262
|
+
...getDefaultConfig(),
|
|
263
|
+
storage: generateRandomStorage(),
|
|
264
|
+
})
|
|
265
|
+
);
|
|
266
|
+
const storage = new Storage(config);
|
|
267
|
+
storage.init(config).then(() => {
|
|
268
|
+
const abort = new AbortController();
|
|
269
|
+
storage
|
|
270
|
+
.getTarballNext('some-tarball', 'some-tarball-1.0.0.tgz', {
|
|
271
|
+
signal: abort.signal,
|
|
272
|
+
})
|
|
273
|
+
.then((stream) => {
|
|
274
|
+
stream.on('error', (err) => {
|
|
275
|
+
expect(err).toEqual(errorUtils.getNotFound(API_ERROR.NO_PACKAGE));
|
|
276
|
+
done();
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test('should create a package if tarball is requested and does not exist locally', (done) => {
|
|
283
|
+
const pkgName = 'upstream';
|
|
284
|
+
const upstreamManifest = generateRemotePackageMetadata(
|
|
285
|
+
pkgName,
|
|
286
|
+
'1.0.0',
|
|
287
|
+
'https://registry.something.org'
|
|
288
|
+
);
|
|
289
|
+
nock('https://registry.verdaccio.org').get(`/${pkgName}`).reply(201, upstreamManifest);
|
|
290
|
+
nock('https://registry.something.org')
|
|
291
|
+
.get(`/${pkgName}/-/${pkgName}-1.0.0.tgz`)
|
|
292
|
+
// types does not match here with documentation
|
|
293
|
+
// @ts-expect-error
|
|
294
|
+
.replyWithFile(201, path.join(__dirname, 'fixtures/tarball.tgz'), {
|
|
295
|
+
[HEADER_TYPE.CONTENT_LENGTH]: 277,
|
|
296
|
+
});
|
|
297
|
+
const config = new Config(
|
|
298
|
+
configExample(
|
|
299
|
+
{
|
|
300
|
+
storage: generateRandomStorage(),
|
|
301
|
+
},
|
|
302
|
+
'./fixtures/config/getTarballNext-getupstream.yaml',
|
|
303
|
+
__dirname
|
|
304
|
+
)
|
|
305
|
+
);
|
|
306
|
+
const storage = new Storage(config);
|
|
307
|
+
storage.init(config).then(() => {
|
|
308
|
+
const abort = new AbortController();
|
|
309
|
+
storage
|
|
310
|
+
.getTarballNext(pkgName, `${pkgName}-1.0.0.tgz`, {
|
|
311
|
+
signal: abort.signal,
|
|
312
|
+
})
|
|
313
|
+
.then((stream) => {
|
|
314
|
+
stream.on('data', (dat) => {
|
|
315
|
+
expect(dat).toBeDefined();
|
|
316
|
+
});
|
|
317
|
+
stream.on('end', () => {
|
|
318
|
+
done();
|
|
319
|
+
});
|
|
320
|
+
stream.on('error', () => {
|
|
321
|
+
done('this should not happen');
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
test('should serve fetch tarball from upstream without dist info local', (done) => {
|
|
328
|
+
const pkgName = 'upstream';
|
|
329
|
+
const upstreamManifest = addNewVersion(
|
|
330
|
+
generateRemotePackageMetadata(pkgName, '1.0.0'),
|
|
331
|
+
'1.0.1'
|
|
332
|
+
);
|
|
333
|
+
nock('https://registry.verdaccio.org').get(`/${pkgName}`).reply(201, upstreamManifest);
|
|
334
|
+
nock('http://localhost:5555')
|
|
335
|
+
.get(`/${pkgName}/-/${pkgName}-1.0.1.tgz`)
|
|
336
|
+
// types does not match here with documentation
|
|
337
|
+
// @ts-expect-error
|
|
338
|
+
.replyWithFile(201, path.join(__dirname, 'fixtures/tarball.tgz'), {
|
|
339
|
+
[HEADER_TYPE.CONTENT_LENGTH]: 277,
|
|
340
|
+
});
|
|
341
|
+
const config = new Config(
|
|
342
|
+
configExample(
|
|
343
|
+
{
|
|
344
|
+
storage: generateRandomStorage(),
|
|
345
|
+
},
|
|
346
|
+
'./fixtures/config/getTarballNext-getupstream.yaml',
|
|
347
|
+
__dirname
|
|
348
|
+
)
|
|
349
|
+
);
|
|
350
|
+
const storage = new Storage(config);
|
|
351
|
+
storage.init(config).then(() => {
|
|
352
|
+
const ac = new AbortController();
|
|
353
|
+
const bodyNewManifest = generatePackageMetadata(pkgName, '1.0.0');
|
|
354
|
+
storage
|
|
355
|
+
.updateManifest(bodyNewManifest, {
|
|
356
|
+
signal: ac.signal,
|
|
357
|
+
name: pkgName,
|
|
358
|
+
uplinksLook: true,
|
|
359
|
+
revision: '1',
|
|
360
|
+
requestOptions: {
|
|
361
|
+
host: 'localhost',
|
|
362
|
+
protocol: 'http',
|
|
363
|
+
headers: {},
|
|
364
|
+
},
|
|
365
|
+
})
|
|
366
|
+
.then(() => {
|
|
367
|
+
const abort = new AbortController();
|
|
368
|
+
storage
|
|
369
|
+
.getTarballNext(pkgName, `${pkgName}-1.0.1.tgz`, {
|
|
370
|
+
signal: abort.signal,
|
|
371
|
+
})
|
|
372
|
+
.then((stream) => {
|
|
373
|
+
stream.on('data', (dat) => {
|
|
374
|
+
expect(dat).toBeDefined();
|
|
375
|
+
});
|
|
376
|
+
stream.on('end', () => {
|
|
377
|
+
done();
|
|
378
|
+
});
|
|
379
|
+
stream.on('error', () => {
|
|
380
|
+
done('this should not happen');
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
test('should serve fetch tarball from upstream without with info local', (done) => {
|
|
388
|
+
const pkgName = 'upstream';
|
|
389
|
+
const upstreamManifest = addNewVersion(
|
|
390
|
+
addNewVersion(generateRemotePackageMetadata(pkgName, '1.0.0'), '1.0.1'),
|
|
391
|
+
'1.0.2'
|
|
392
|
+
);
|
|
393
|
+
nock('https://registry.verdaccio.org')
|
|
394
|
+
.get(`/${pkgName}`)
|
|
395
|
+
.times(10)
|
|
396
|
+
.reply(201, upstreamManifest);
|
|
397
|
+
nock('http://localhost:5555')
|
|
398
|
+
.get(`/${pkgName}/-/${pkgName}-1.0.0.tgz`)
|
|
399
|
+
// types does not match here with documentation
|
|
400
|
+
// @ts-expect-error
|
|
401
|
+
.replyWithFile(201, path.join(__dirname, 'fixtures/tarball.tgz'), {
|
|
402
|
+
[HEADER_TYPE.CONTENT_LENGTH]: 277,
|
|
403
|
+
});
|
|
404
|
+
const storagePath = generateRandomStorage();
|
|
405
|
+
const config = new Config(
|
|
406
|
+
configExample(
|
|
407
|
+
{
|
|
408
|
+
storage: storagePath,
|
|
409
|
+
},
|
|
410
|
+
'./fixtures/config/getTarballNext-getupstream.yaml',
|
|
411
|
+
__dirname
|
|
412
|
+
)
|
|
413
|
+
);
|
|
414
|
+
const storage = new Storage(config);
|
|
415
|
+
storage.init(config).then(() => {
|
|
416
|
+
const req = httpMocks.createRequest({
|
|
417
|
+
method: 'GET',
|
|
418
|
+
connection: { remoteAddress: fakeHost },
|
|
419
|
+
headers: {
|
|
420
|
+
host: fakeHost,
|
|
421
|
+
[HEADERS.FORWARDED_PROTO]: 'http',
|
|
422
|
+
},
|
|
423
|
+
url: '/',
|
|
424
|
+
});
|
|
425
|
+
return storage
|
|
426
|
+
.getPackageByOptions({
|
|
427
|
+
name: pkgName,
|
|
428
|
+
uplinksLook: true,
|
|
429
|
+
requestOptions: {
|
|
430
|
+
headers: req.headers as any,
|
|
431
|
+
protocol: req.protocol,
|
|
432
|
+
host: req.get('host') as string,
|
|
433
|
+
},
|
|
434
|
+
})
|
|
435
|
+
.then(() => {
|
|
436
|
+
const abort = new AbortController();
|
|
437
|
+
storage
|
|
438
|
+
.getTarballNext(pkgName, `${pkgName}-1.0.0.tgz`, {
|
|
439
|
+
signal: abort.signal,
|
|
440
|
+
})
|
|
441
|
+
.then((stream) => {
|
|
442
|
+
stream.on('data', (dat) => {
|
|
443
|
+
expect(dat).toBeDefined();
|
|
444
|
+
});
|
|
445
|
+
stream.on('end', () => {
|
|
446
|
+
done();
|
|
447
|
+
});
|
|
448
|
+
stream.once('error', () => {
|
|
449
|
+
done('this should not happen');
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
test('should serve local cache', (done) => {
|
|
457
|
+
const pkgName = 'upstream';
|
|
458
|
+
const config = new Config(
|
|
459
|
+
configExample(
|
|
460
|
+
{
|
|
461
|
+
storage: generateRandomStorage(),
|
|
462
|
+
},
|
|
463
|
+
'./fixtures/config/getTarballNext-getupstream.yaml',
|
|
464
|
+
__dirname
|
|
465
|
+
)
|
|
466
|
+
);
|
|
467
|
+
const storage = new Storage(config);
|
|
468
|
+
storage.init(config).then(() => {
|
|
469
|
+
const ac = new AbortController();
|
|
470
|
+
const bodyNewManifest = generatePackageMetadata(pkgName, '1.0.0');
|
|
471
|
+
storage
|
|
472
|
+
.updateManifest(bodyNewManifest, {
|
|
473
|
+
signal: ac.signal,
|
|
474
|
+
name: pkgName,
|
|
475
|
+
uplinksLook: true,
|
|
476
|
+
revision: '1',
|
|
477
|
+
requestOptions: {
|
|
478
|
+
host: 'localhost',
|
|
479
|
+
protocol: 'http',
|
|
480
|
+
headers: {},
|
|
481
|
+
},
|
|
482
|
+
})
|
|
483
|
+
.then(() => {
|
|
484
|
+
const abort = new AbortController();
|
|
485
|
+
storage
|
|
486
|
+
.getTarballNext(pkgName, `${pkgName}-1.0.0.tgz`, {
|
|
487
|
+
signal: abort.signal,
|
|
488
|
+
})
|
|
489
|
+
.then((stream) => {
|
|
490
|
+
stream.on('data', (dat) => {
|
|
491
|
+
expect(dat).toBeDefined();
|
|
492
|
+
});
|
|
493
|
+
stream.on('end', () => {
|
|
494
|
+
done();
|
|
495
|
+
});
|
|
496
|
+
stream.on('error', () => {
|
|
497
|
+
done('this should not happen');
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
describe('syncUplinksMetadataNext()', () => {
|
|
506
|
+
describe('error handling', () => {
|
|
507
|
+
test('should handle double failure on uplinks with timeout', async () => {
|
|
508
|
+
const fooManifest = generatePackageMetadata('timeout', '8.0.0');
|
|
509
|
+
|
|
510
|
+
nock('https://registry.domain.com')
|
|
511
|
+
.get('/timeout')
|
|
512
|
+
.times(10)
|
|
513
|
+
.delayConnection(2000)
|
|
514
|
+
.reply(201, manifestFooRemoteNpmjs);
|
|
515
|
+
|
|
516
|
+
const config = new Config(
|
|
517
|
+
configExample(
|
|
518
|
+
{
|
|
519
|
+
storage: generateRandomStorage(),
|
|
520
|
+
},
|
|
521
|
+
'./fixtures/config/syncDoubleUplinksMetadata.yaml',
|
|
522
|
+
__dirname
|
|
523
|
+
)
|
|
524
|
+
);
|
|
525
|
+
|
|
526
|
+
const storage = new Storage(config);
|
|
527
|
+
await storage.init(config);
|
|
528
|
+
await expect(
|
|
529
|
+
storage.syncUplinksMetadataNext(fooManifest.name, null, {
|
|
530
|
+
retry: { limit: 0 },
|
|
531
|
+
timeout: {
|
|
532
|
+
lookup: 100,
|
|
533
|
+
connect: 50,
|
|
534
|
+
secureConnect: 50,
|
|
535
|
+
socket: 500,
|
|
536
|
+
// send: 10000,
|
|
537
|
+
response: 1000,
|
|
538
|
+
},
|
|
539
|
+
})
|
|
540
|
+
).rejects.toThrow('ETIMEDOUT');
|
|
541
|
+
}, 10000);
|
|
542
|
+
|
|
543
|
+
test('should handle one proxy fails', async () => {
|
|
544
|
+
const fooManifest = generatePackageMetadata('foo', '8.0.0');
|
|
545
|
+
nock('https://registry.verdaccio.org').get('/foo').replyWithError('service in holidays');
|
|
546
|
+
const config = new Config(
|
|
547
|
+
configExample(
|
|
548
|
+
{
|
|
549
|
+
storage: generateRandomStorage(),
|
|
550
|
+
},
|
|
551
|
+
'./fixtures/config/syncSingleUplinksMetadata.yaml',
|
|
552
|
+
__dirname
|
|
553
|
+
)
|
|
554
|
+
);
|
|
555
|
+
const storage = new Storage(config);
|
|
556
|
+
await storage.init(config);
|
|
557
|
+
await expect(
|
|
558
|
+
storage.syncUplinksMetadataNext(fooManifest.name, null, {
|
|
559
|
+
retry: { limit: 0 },
|
|
560
|
+
})
|
|
561
|
+
).rejects.toThrow(API_ERROR.NO_PACKAGE);
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
test('should handle one proxy reply 304', async () => {
|
|
565
|
+
const fooManifest = generatePackageMetadata('foo-no-data', '8.0.0');
|
|
566
|
+
nock('https://registry.verdaccio.org').get('/foo-no-data').reply(304);
|
|
567
|
+
const config = new Config(
|
|
568
|
+
configExample(
|
|
569
|
+
{
|
|
570
|
+
storage: generateRandomStorage(),
|
|
571
|
+
},
|
|
572
|
+
'./fixtures/config/syncSingleUplinksMetadata.yaml',
|
|
573
|
+
__dirname
|
|
574
|
+
)
|
|
575
|
+
);
|
|
576
|
+
const storage = new Storage(config);
|
|
577
|
+
await storage.init(config);
|
|
578
|
+
const [manifest] = await storage.syncUplinksMetadataNext(fooManifest.name, fooManifest, {
|
|
579
|
+
retry: 0,
|
|
580
|
+
});
|
|
581
|
+
expect(manifest).toBe(fooManifest);
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
describe('success scenarios', () => {
|
|
586
|
+
test('should handle one proxy success', async () => {
|
|
587
|
+
const fooManifest = generateLocalPackageMetadata('foo', '8.0.0');
|
|
588
|
+
nock('https://registry.verdaccio.org').get('/foo').reply(201, manifestFooRemoteNpmjs);
|
|
589
|
+
const config = new Config(
|
|
590
|
+
configExample(
|
|
591
|
+
{
|
|
592
|
+
storage: generateRandomStorage(),
|
|
593
|
+
},
|
|
594
|
+
'./fixtures/config/syncSingleUplinksMetadata.yaml',
|
|
595
|
+
__dirname
|
|
596
|
+
)
|
|
597
|
+
);
|
|
598
|
+
const storage = new Storage(config);
|
|
599
|
+
await storage.init(config);
|
|
600
|
+
|
|
601
|
+
const [response] = await storage.syncUplinksMetadataNext(fooManifest.name, fooManifest);
|
|
602
|
+
expect(response).not.toBeNull();
|
|
603
|
+
expect((response as Manifest).name).toEqual(fooManifest.name);
|
|
604
|
+
expect(Object.keys((response as Manifest).versions)).toEqual([
|
|
605
|
+
'8.0.0',
|
|
606
|
+
'1.0.0',
|
|
607
|
+
'0.0.3',
|
|
608
|
+
'0.0.4',
|
|
609
|
+
'0.0.5',
|
|
610
|
+
'0.0.6',
|
|
611
|
+
'0.0.7',
|
|
612
|
+
]);
|
|
613
|
+
expect(Object.keys((response as Manifest).time)).toEqual([
|
|
614
|
+
'modified',
|
|
615
|
+
'created',
|
|
616
|
+
'8.0.0',
|
|
617
|
+
'1.0.0',
|
|
618
|
+
'0.0.3',
|
|
619
|
+
'0.0.4',
|
|
620
|
+
'0.0.5',
|
|
621
|
+
'0.0.6',
|
|
622
|
+
'0.0.7',
|
|
623
|
+
]);
|
|
624
|
+
expect((response as Manifest)[DIST_TAGS].latest).toEqual('8.0.0');
|
|
625
|
+
expect((response as Manifest).time['8.0.0']).toBeDefined();
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
test('should handle one proxy success with no local cache manifest', async () => {
|
|
629
|
+
nock('https://registry.verdaccio.org').get('/foo').reply(201, manifestFooRemoteNpmjs);
|
|
630
|
+
const config = new Config(
|
|
631
|
+
configExample(
|
|
632
|
+
{
|
|
633
|
+
storage: generateRandomStorage(),
|
|
634
|
+
},
|
|
635
|
+
'./fixtures/config/syncSingleUplinksMetadata.yaml',
|
|
636
|
+
__dirname
|
|
637
|
+
)
|
|
638
|
+
);
|
|
639
|
+
const storage = new Storage(config);
|
|
640
|
+
await storage.init(config);
|
|
641
|
+
|
|
642
|
+
const [response] = await storage.syncUplinksMetadataNext(fooManifest.name, null);
|
|
643
|
+
// the latest from the remote manifest
|
|
644
|
+
expect(response).not.toBeNull();
|
|
645
|
+
expect((response as Manifest).name).toEqual(fooManifest.name);
|
|
646
|
+
expect((response as Manifest)[DIST_TAGS].latest).toEqual('0.0.7');
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
test('should handle no proxy found with local cache manifest', async () => {
|
|
650
|
+
const fooManifest = generatePackageMetadata('foo', '8.0.0');
|
|
651
|
+
nock('https://registry.verdaccio.org').get('/foo').reply(201, manifestFooRemoteNpmjs);
|
|
652
|
+
const config = new Config(
|
|
653
|
+
configExample(
|
|
654
|
+
{
|
|
655
|
+
storage: generateRandomStorage(),
|
|
656
|
+
},
|
|
657
|
+
'./fixtures/config/syncNoUplinksMetadata.yaml',
|
|
658
|
+
__dirname
|
|
659
|
+
)
|
|
660
|
+
);
|
|
661
|
+
const storage = new Storage(config);
|
|
662
|
+
await storage.init(config);
|
|
663
|
+
|
|
664
|
+
const [response] = await storage.syncUplinksMetadataNext(fooManifest.name, fooManifest);
|
|
665
|
+
expect(response).not.toBeNull();
|
|
666
|
+
expect((response as Manifest).name).toEqual(fooManifest.name);
|
|
667
|
+
expect((response as Manifest)[DIST_TAGS].latest).toEqual('8.0.0');
|
|
668
|
+
});
|
|
669
|
+
test.todo('should handle double proxy with last one success');
|
|
670
|
+
});
|
|
671
|
+
describe('options', () => {
|
|
672
|
+
test('should handle disable uplinks via options.uplinksLook=false', async () => {
|
|
673
|
+
const fooManifest = generatePackageMetadata('foo', '8.0.0');
|
|
674
|
+
nock('https://registry.verdaccio.org').get('/foo').reply(201, manifestFooRemoteNpmjs);
|
|
675
|
+
const config = new Config(
|
|
676
|
+
configExample(
|
|
677
|
+
{
|
|
678
|
+
storage: generateRandomStorage(),
|
|
679
|
+
},
|
|
680
|
+
'./fixtures/config/syncSingleUplinksMetadata.yaml',
|
|
681
|
+
__dirname
|
|
682
|
+
)
|
|
683
|
+
);
|
|
684
|
+
const storage = new Storage(config);
|
|
685
|
+
await storage.init(config);
|
|
686
|
+
|
|
687
|
+
const [response] = await storage.syncUplinksMetadataNext(fooManifest.name, fooManifest, {
|
|
688
|
+
uplinksLook: false,
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
expect((response as Manifest).name).toEqual(fooManifest.name);
|
|
692
|
+
expect((response as Manifest)[DIST_TAGS].latest).toEqual('8.0.0');
|
|
693
|
+
});
|
|
694
|
+
});
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
describe('getLocalDatabaseNext', () => {
|
|
698
|
+
test('should return 0 local packages', async () => {
|
|
699
|
+
const config = new Config(
|
|
700
|
+
configExample({
|
|
701
|
+
...getDefaultConfig(),
|
|
702
|
+
storage: generateRandomStorage(),
|
|
30
703
|
})
|
|
31
704
|
);
|
|
32
705
|
const storage = new Storage(config);
|
|
33
706
|
await storage.init(config);
|
|
707
|
+
await expect(storage.getLocalDatabaseNext()).resolves.toHaveLength(0);
|
|
708
|
+
});
|
|
34
709
|
|
|
35
|
-
|
|
36
|
-
|
|
710
|
+
test('should return 1 local packages', async () => {
|
|
711
|
+
const config = new Config(
|
|
712
|
+
configExample({
|
|
713
|
+
...getDefaultConfig(),
|
|
714
|
+
storage: generateRandomStorage(),
|
|
715
|
+
})
|
|
716
|
+
);
|
|
717
|
+
const req = httpMocks.createRequest({
|
|
718
|
+
method: 'GET',
|
|
719
|
+
connection: { remoteAddress: fakeHost },
|
|
720
|
+
headers: {
|
|
721
|
+
host: 'host',
|
|
722
|
+
},
|
|
723
|
+
url: '/',
|
|
37
724
|
});
|
|
725
|
+
const storage = new Storage(config);
|
|
726
|
+
await storage.init(config);
|
|
727
|
+
const manifest = generatePackageMetadata('foo');
|
|
728
|
+
const ac = new AbortController();
|
|
729
|
+
await storage.updateManifest(manifest, {
|
|
730
|
+
signal: ac.signal,
|
|
731
|
+
name: 'foo',
|
|
732
|
+
uplinksLook: false,
|
|
733
|
+
requestOptions: {
|
|
734
|
+
headers: req.headers as any,
|
|
735
|
+
protocol: req.protocol,
|
|
736
|
+
host: req.get('host') as string,
|
|
737
|
+
},
|
|
738
|
+
});
|
|
739
|
+
const response = await storage.getLocalDatabaseNext();
|
|
740
|
+
expect(response).toHaveLength(1);
|
|
741
|
+
expect(response[0]).toEqual(expect.objectContaining({ name: 'foo', version: '1.0.0' }));
|
|
38
742
|
});
|
|
39
743
|
});
|
|
40
744
|
|
|
41
|
-
|
|
42
|
-
|
|
745
|
+
describe('tokens', () => {
|
|
746
|
+
describe('saveToken', () => {
|
|
747
|
+
test('should retrieve tokens created', async () => {
|
|
748
|
+
const config = new Config(
|
|
749
|
+
configExample({
|
|
750
|
+
...getDefaultConfig(),
|
|
751
|
+
storage: generateRandomStorage(),
|
|
752
|
+
})
|
|
753
|
+
);
|
|
754
|
+
const storage = new Storage(config);
|
|
755
|
+
await storage.init(config);
|
|
756
|
+
await storage.saveToken({
|
|
757
|
+
user: 'foo',
|
|
758
|
+
token: 'secret',
|
|
759
|
+
key: 'key',
|
|
760
|
+
created: 'created',
|
|
761
|
+
readonly: true,
|
|
762
|
+
});
|
|
763
|
+
const tokens = await storage.readTokens({ user: 'foo' });
|
|
764
|
+
expect(tokens).toEqual([
|
|
765
|
+
{ user: 'foo', token: 'secret', key: 'key', readonly: true, created: 'created' },
|
|
766
|
+
]);
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
test('should delete a token created', async () => {
|
|
770
|
+
const config = new Config(
|
|
771
|
+
configExample({
|
|
772
|
+
...getDefaultConfig(),
|
|
773
|
+
storage: generateRandomStorage(),
|
|
774
|
+
})
|
|
775
|
+
);
|
|
776
|
+
const storage = new Storage(config);
|
|
777
|
+
await storage.init(config);
|
|
778
|
+
await storage.saveToken({
|
|
779
|
+
user: 'foo',
|
|
780
|
+
token: 'secret',
|
|
781
|
+
key: 'key',
|
|
782
|
+
created: 'created',
|
|
783
|
+
readonly: true,
|
|
784
|
+
});
|
|
785
|
+
const tokens = await storage.readTokens({ user: 'foo' });
|
|
786
|
+
expect(tokens).toHaveLength(1);
|
|
787
|
+
await storage.deleteToken('foo', 'key');
|
|
788
|
+
const tokens2 = await storage.readTokens({ user: 'foo' });
|
|
789
|
+
expect(tokens2).toHaveLength(0);
|
|
790
|
+
});
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
describe('removeTarball', () => {
|
|
795
|
+
test('should fail on remove tarball of package does not exist', async () => {
|
|
796
|
+
const config = new Config(
|
|
797
|
+
configExample({
|
|
798
|
+
...getDefaultConfig(),
|
|
799
|
+
storage: generateRandomStorage(),
|
|
800
|
+
})
|
|
801
|
+
);
|
|
802
|
+
const storage = new Storage(config);
|
|
803
|
+
await storage.init(config);
|
|
804
|
+
await expect(storage.removeTarball('foo', 'foo-1.0.0.tgz', 'rev')).rejects.toThrow(
|
|
805
|
+
API_ERROR.NO_PACKAGE
|
|
806
|
+
);
|
|
807
|
+
});
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
describe('removePackage', () => {
|
|
811
|
+
test('should remove entirely a package', async () => {
|
|
812
|
+
const config = new Config(
|
|
813
|
+
configExample({
|
|
814
|
+
...getDefaultConfig(),
|
|
815
|
+
storage: generateRandomStorage(),
|
|
816
|
+
})
|
|
817
|
+
);
|
|
818
|
+
const req = httpMocks.createRequest({
|
|
819
|
+
method: 'GET',
|
|
820
|
+
connection: { remoteAddress: fakeHost },
|
|
821
|
+
headers: {
|
|
822
|
+
host: fakeHost,
|
|
823
|
+
[HEADERS.FORWARDED_PROTO]: 'http',
|
|
824
|
+
},
|
|
825
|
+
url: '/',
|
|
826
|
+
});
|
|
827
|
+
const storage = new Storage(config);
|
|
828
|
+
await storage.init(config);
|
|
829
|
+
|
|
830
|
+
const manifest = generatePackageMetadata('foo');
|
|
831
|
+
const ac = new AbortController();
|
|
832
|
+
// 1. publish a package
|
|
833
|
+
await storage.updateManifest(manifest, {
|
|
834
|
+
signal: ac.signal,
|
|
835
|
+
name: 'foo',
|
|
836
|
+
uplinksLook: false,
|
|
837
|
+
requestOptions: {
|
|
838
|
+
headers: req.headers as any,
|
|
839
|
+
protocol: req.protocol,
|
|
840
|
+
host: req.get('host') as string,
|
|
841
|
+
},
|
|
842
|
+
});
|
|
843
|
+
// 2. request package (should be available in the local cache)
|
|
844
|
+
const manifest1 = (await storage.getPackageByOptions({
|
|
845
|
+
name: 'foo',
|
|
846
|
+
uplinksLook: false,
|
|
847
|
+
requestOptions: {
|
|
848
|
+
headers: req.headers as any,
|
|
849
|
+
protocol: req.protocol,
|
|
850
|
+
host: req.get('host') as string,
|
|
851
|
+
},
|
|
852
|
+
})) as Manifest;
|
|
853
|
+
const _rev = manifest1._rev;
|
|
854
|
+
// 3. remove the tarball
|
|
855
|
+
await expect(
|
|
856
|
+
storage.removeTarball(manifest1.name, 'foo-1.0.0.tgz', _rev)
|
|
857
|
+
).resolves.toBeDefined();
|
|
858
|
+
// 4. remove the package
|
|
859
|
+
await storage.removePackage(manifest1.name, _rev);
|
|
860
|
+
// 5. fails if package does not exist anymore in storage
|
|
861
|
+
await expect(
|
|
862
|
+
storage.getPackageByOptions({
|
|
863
|
+
name: 'foo',
|
|
864
|
+
uplinksLook: false,
|
|
865
|
+
requestOptions: {
|
|
866
|
+
headers: req.headers as any,
|
|
867
|
+
protocol: req.protocol,
|
|
868
|
+
host: req.get('host') as string,
|
|
869
|
+
},
|
|
870
|
+
})
|
|
871
|
+
).rejects.toThrowError('package does not exist on uplink: foo');
|
|
872
|
+
});
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
describe('get packages getPackageByOptions()', () => {
|
|
43
876
|
describe('with uplinks', () => {
|
|
44
877
|
test('should get 201 and merge from uplink', async () => {
|
|
45
878
|
nock(domain).get('/foo').reply(201, fooManifest);
|
|
46
879
|
const config = new Config(
|
|
47
880
|
configExample({
|
|
48
|
-
|
|
881
|
+
...getDefaultConfig(),
|
|
882
|
+
storage: generateRandomStorage(),
|
|
49
883
|
})
|
|
50
884
|
);
|
|
51
885
|
const req = httpMocks.createRequest({
|
|
@@ -63,11 +897,10 @@ describe('storage', () => {
|
|
|
63
897
|
storage.getPackageByOptions({
|
|
64
898
|
name: 'foo',
|
|
65
899
|
uplinksLook: true,
|
|
66
|
-
req,
|
|
67
900
|
requestOptions: {
|
|
68
901
|
headers: req.headers as any,
|
|
69
902
|
protocol: req.protocol,
|
|
70
|
-
host: req.get('host'),
|
|
903
|
+
host: req.get('host') as string,
|
|
71
904
|
},
|
|
72
905
|
})
|
|
73
906
|
).resolves.toEqual(expect.objectContaining({ name: 'foo' }));
|
|
@@ -77,7 +910,8 @@ describe('storage', () => {
|
|
|
77
910
|
nock(domain).get('/foo').reply(201, fooManifest);
|
|
78
911
|
const config = new Config(
|
|
79
912
|
configExample({
|
|
80
|
-
|
|
913
|
+
...getDefaultConfig(),
|
|
914
|
+
storage: generateRandomStorage(),
|
|
81
915
|
})
|
|
82
916
|
);
|
|
83
917
|
const req = httpMocks.createRequest({
|
|
@@ -96,11 +930,10 @@ describe('storage', () => {
|
|
|
96
930
|
name: 'foo',
|
|
97
931
|
version: '1.0.0',
|
|
98
932
|
uplinksLook: true,
|
|
99
|
-
req,
|
|
100
933
|
requestOptions: {
|
|
101
934
|
headers: req.headers as any,
|
|
102
935
|
protocol: req.protocol,
|
|
103
|
-
host: req.get('host'),
|
|
936
|
+
host: req.get('host') as string,
|
|
104
937
|
},
|
|
105
938
|
})
|
|
106
939
|
).resolves.toEqual(expect.objectContaining({ name: 'foo' }));
|
|
@@ -110,7 +943,8 @@ describe('storage', () => {
|
|
|
110
943
|
nock(domain).get('/foo').reply(201, fooManifest);
|
|
111
944
|
const config = new Config(
|
|
112
945
|
configExample({
|
|
113
|
-
|
|
946
|
+
...getDefaultConfig(),
|
|
947
|
+
storage: generateRandomStorage(),
|
|
114
948
|
})
|
|
115
949
|
);
|
|
116
950
|
const req = httpMocks.createRequest({
|
|
@@ -129,11 +963,10 @@ describe('storage', () => {
|
|
|
129
963
|
name: 'foo',
|
|
130
964
|
version: 'latest',
|
|
131
965
|
uplinksLook: true,
|
|
132
|
-
req,
|
|
133
966
|
requestOptions: {
|
|
134
967
|
headers: req.headers as any,
|
|
135
968
|
protocol: req.protocol,
|
|
136
|
-
host: req.get('host'),
|
|
969
|
+
host: req.get('host') as string,
|
|
137
970
|
},
|
|
138
971
|
})
|
|
139
972
|
).resolves.toEqual(expect.objectContaining({ name: 'foo' }));
|
|
@@ -143,7 +976,8 @@ describe('storage', () => {
|
|
|
143
976
|
nock(domain).get('/foo').reply(201, fooManifest);
|
|
144
977
|
const config = new Config(
|
|
145
978
|
configExample({
|
|
146
|
-
|
|
979
|
+
...getDefaultConfig(),
|
|
980
|
+
storage: generateRandomStorage(),
|
|
147
981
|
})
|
|
148
982
|
);
|
|
149
983
|
const req = httpMocks.createRequest({
|
|
@@ -162,11 +996,10 @@ describe('storage', () => {
|
|
|
162
996
|
name: 'foo',
|
|
163
997
|
version: '1.0.0-does-not-exist',
|
|
164
998
|
uplinksLook: true,
|
|
165
|
-
req,
|
|
166
999
|
requestOptions: {
|
|
167
1000
|
headers: req.headers as any,
|
|
168
1001
|
protocol: req.protocol,
|
|
169
|
-
host: req.get('host'),
|
|
1002
|
+
host: req.get('host') as string,
|
|
170
1003
|
},
|
|
171
1004
|
})
|
|
172
1005
|
).rejects.toThrow(
|
|
@@ -178,7 +1011,13 @@ describe('storage', () => {
|
|
|
178
1011
|
nock(domain).get('/foo2').reply(404);
|
|
179
1012
|
const config = new Config(
|
|
180
1013
|
configExample({
|
|
181
|
-
|
|
1014
|
+
...getDefaultConfig(),
|
|
1015
|
+
uplinks: {
|
|
1016
|
+
npmjs: {
|
|
1017
|
+
url: domain,
|
|
1018
|
+
},
|
|
1019
|
+
},
|
|
1020
|
+
storage: generateRandomStorage(),
|
|
182
1021
|
})
|
|
183
1022
|
);
|
|
184
1023
|
const req = httpMocks.createRequest({
|
|
@@ -196,11 +1035,10 @@ describe('storage', () => {
|
|
|
196
1035
|
storage.getPackageByOptions({
|
|
197
1036
|
name: 'foo2',
|
|
198
1037
|
uplinksLook: true,
|
|
199
|
-
req,
|
|
200
1038
|
requestOptions: {
|
|
201
1039
|
headers: req.headers as any,
|
|
202
1040
|
protocol: req.protocol,
|
|
203
|
-
host: req.get('host'),
|
|
1041
|
+
host: req.get('host') as string,
|
|
204
1042
|
},
|
|
205
1043
|
})
|
|
206
1044
|
).rejects.toThrow(errorUtils.getNotFound());
|
|
@@ -213,7 +1051,13 @@ describe('storage', () => {
|
|
|
213
1051
|
});
|
|
214
1052
|
const config = new Config(
|
|
215
1053
|
configExample({
|
|
216
|
-
|
|
1054
|
+
...getDefaultConfig(),
|
|
1055
|
+
uplinks: {
|
|
1056
|
+
npmjs: {
|
|
1057
|
+
url: domain,
|
|
1058
|
+
},
|
|
1059
|
+
},
|
|
1060
|
+
storage: generateRandomStorage(),
|
|
217
1061
|
})
|
|
218
1062
|
);
|
|
219
1063
|
const req = httpMocks.createRequest({
|
|
@@ -231,14 +1075,80 @@ describe('storage', () => {
|
|
|
231
1075
|
storage.getPackageByOptions({
|
|
232
1076
|
name: 'foo2',
|
|
233
1077
|
uplinksLook: true,
|
|
234
|
-
|
|
1078
|
+
retry: { limit: 0 },
|
|
235
1079
|
requestOptions: {
|
|
236
1080
|
headers: req.headers as any,
|
|
237
1081
|
protocol: req.protocol,
|
|
238
|
-
host: req.get('host'),
|
|
1082
|
+
host: req.get('host') as string,
|
|
239
1083
|
},
|
|
240
1084
|
})
|
|
241
|
-
).rejects.toThrow(errorUtils.getServiceUnavailable());
|
|
1085
|
+
).rejects.toThrow(errorUtils.getServiceUnavailable('ETIMEDOUT'));
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
test('should fetch abbreviated version of manifest ', async () => {
|
|
1089
|
+
const fooManifest = generateLocalPackageMetadata('foo', '1.0.0');
|
|
1090
|
+
nock(domain).get('/foo').reply(201, fooManifest);
|
|
1091
|
+
const config = new Config(
|
|
1092
|
+
configExample({
|
|
1093
|
+
...getDefaultConfig(),
|
|
1094
|
+
storage: generateRandomStorage(),
|
|
1095
|
+
})
|
|
1096
|
+
);
|
|
1097
|
+
const req = httpMocks.createRequest({
|
|
1098
|
+
method: 'GET',
|
|
1099
|
+
connection: { remoteAddress: fakeHost },
|
|
1100
|
+
headers: {
|
|
1101
|
+
host: fakeHost,
|
|
1102
|
+
[HEADERS.FORWARDED_PROTO]: 'http',
|
|
1103
|
+
},
|
|
1104
|
+
url: '/',
|
|
1105
|
+
});
|
|
1106
|
+
const storage = new Storage(config);
|
|
1107
|
+
await storage.init(config);
|
|
1108
|
+
|
|
1109
|
+
const manifest = (await storage.getPackageByOptions({
|
|
1110
|
+
name: 'foo',
|
|
1111
|
+
uplinksLook: true,
|
|
1112
|
+
requestOptions: {
|
|
1113
|
+
headers: req.headers as any,
|
|
1114
|
+
protocol: req.protocol,
|
|
1115
|
+
host: req.get('host') as string,
|
|
1116
|
+
},
|
|
1117
|
+
abbreviated: true,
|
|
1118
|
+
})) as AbbreviatedManifest;
|
|
1119
|
+
const { versions, name } = manifest;
|
|
1120
|
+
expect(name).toEqual('foo');
|
|
1121
|
+
expect(Object.keys(versions)).toEqual(['1.0.0']);
|
|
1122
|
+
expect(manifest[DIST_TAGS]).toEqual({ latest: '1.0.0' });
|
|
1123
|
+
const version = versions['1.0.0'];
|
|
1124
|
+
expect(Object.keys(version)).toEqual([
|
|
1125
|
+
'name',
|
|
1126
|
+
'version',
|
|
1127
|
+
'description',
|
|
1128
|
+
'deprecated',
|
|
1129
|
+
'bin',
|
|
1130
|
+
'dist',
|
|
1131
|
+
'engines',
|
|
1132
|
+
'funding',
|
|
1133
|
+
'directories',
|
|
1134
|
+
'dependencies',
|
|
1135
|
+
'devDependencies',
|
|
1136
|
+
'peerDependencies',
|
|
1137
|
+
'optionalDependencies',
|
|
1138
|
+
'bundleDependencies',
|
|
1139
|
+
'_hasShrinkwrap',
|
|
1140
|
+
'hasInstallScript',
|
|
1141
|
+
]);
|
|
1142
|
+
expect(manifest.modified).toBeDefined();
|
|
1143
|
+
// special case for pnpm/rfcs/pull/2
|
|
1144
|
+
expect(manifest.time).toBeDefined();
|
|
1145
|
+
// fields must not have
|
|
1146
|
+
// @ts-expect-error
|
|
1147
|
+
expect(manifest.readme).not.toBeDefined();
|
|
1148
|
+
// @ts-expect-error
|
|
1149
|
+
expect(manifest._attachments).not.toBeDefined();
|
|
1150
|
+
// @ts-expect-error
|
|
1151
|
+
expect(manifest._rev).not.toBeDefined();
|
|
242
1152
|
});
|
|
243
1153
|
});
|
|
244
1154
|
});
|