@eik/service 2.3.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/main.js CHANGED
@@ -1,15 +1,16 @@
1
- import { PassThrough } from 'stream';
2
- import compression from '@fastify/compress';
3
- import createError from 'http-errors';
4
- import pino from 'pino';
5
- import cors from '@fastify/cors';
6
- import jwt from '@fastify/jwt';
7
- import eik from '@eik/core';
8
- import SinkMemory from '@eik/sink-memory';
9
- import SinkFileSystem from '@eik/sink-file-system';
10
-
11
- import config from './config.js';
12
- import * as utils from './utils.js';
1
+ import { PassThrough } from "stream";
2
+ import compression from "@fastify/compress";
3
+ import createError from "http-errors";
4
+ import pino from "pino";
5
+ import cors from "@fastify/cors";
6
+ import jwt from "@fastify/jwt";
7
+ import eik from "@eik/core";
8
+ import SinkMemory from "@eik/sink-memory";
9
+ import SinkFileSystem from "@eik/sink-file-system";
10
+ import zlib from "node:zlib";
11
+
12
+ import config from "./config.js";
13
+ import * as utils from "./utils.js";
13
14
 
14
15
  /**
15
16
  * @typedef {object} EikServiceOptions
@@ -24,891 +25,833 @@ import * as utils from './utils.js';
24
25
  */
25
26
 
26
27
  const EikService = class EikService {
27
- /**
28
- * @param {EikServiceOptions} [options={}]
29
- */
30
- constructor(options = {}) {
31
- let { sink, logger } = options;
32
- const {
33
- customSink,
34
- notFoundCacheControl,
35
- aliasCacheControl,
36
- pkgMaxFileSize = 10000000,
37
- mapMaxFileSize = 1000000,
38
- imgMaxFileSize = 20000000,
39
- } = options;
40
- this._notFoundCacheControl =
41
- notFoundCacheControl || 'public, max-age=5';
42
-
43
- if (!logger) {
44
- // @ts-expect-error This is in fact callable
45
- logger = pino({
46
- // @ts-ignore
47
- level: config.get('log.level'),
48
- name: config.get('name'),
49
- });
50
- }
51
-
52
- if (sink) {
53
- logger.info(`Using the provided sink ${sink.constructor.name}`);
54
- } else if (customSink) {
55
- logger.warn(
56
- 'The `customSink` option is deprecated and will be removed at a later stage. Use `sink` to remove this warning.',
57
- );
58
- sink = customSink;
59
- } else if (config.get('sink.type') === 'mem') {
60
- logger.info(
61
- `Server is running with a in memory sink. Uploaded files will be lost on restart!`,
62
- );
63
- sink = new SinkMemory();
64
- } else {
65
- logger.info(
66
- `Server is running with the file system sink. Uploaded files will be stored under "${config.get('sink.path')}"`,
67
- );
68
- sink = new SinkFileSystem({
69
- sinkFsRootPath: config.get('sink.path'),
70
- });
71
- }
72
-
73
- // Transform organization config
74
- const organizations = config
75
- .get('organization.hostnames')
76
- .map((hostname) => [hostname, config.get('organization.name')]);
77
-
78
- this._versionsGet = new eik.http.VersionsGet({
79
- organizations,
80
- sink,
81
- logger,
82
- });
83
- this._aliasPost = new eik.http.AliasPost({
84
- organizations,
85
- sink,
86
- logger,
87
- });
88
- this._aliasDel = new eik.http.AliasDel({ organizations, sink, logger });
89
- this._aliasGet = new eik.http.AliasGet({
90
- organizations,
91
- sink,
92
- logger,
93
- cacheControl: aliasCacheControl,
94
- });
95
- this._aliasPut = new eik.http.AliasPut({ organizations, sink, logger });
96
- this._authPost = new eik.http.AuthPost({
97
- organizations,
98
- logger,
99
- authKey: config.get('basicAuth.key'),
100
- });
101
- this._pkgLog = new eik.http.PkgLog({ organizations, sink, logger });
102
- this._pkgGet = new eik.http.PkgGet({ organizations, sink, logger });
103
- this._pkgPut = new eik.http.PkgPut({
104
- organizations,
105
- sink,
106
- logger,
107
- pkgMaxFileSize,
108
- });
109
- this._imgPut = new eik.http.PkgPut({
110
- organizations,
111
- sink,
112
- logger,
113
- pkgMaxFileSize: imgMaxFileSize,
114
- });
115
- this._mapGet = new eik.http.MapGet({ organizations, sink, logger });
116
- this._mapPut = new eik.http.MapPut({
117
- organizations,
118
- sink,
119
- logger,
120
- mapMaxFileSize,
121
- });
122
-
123
- const mergeStreams = (...streams) => {
124
- const str = new PassThrough({ objectMode: true });
125
-
126
- // Avoid hitting the max listeners limit when multiple
127
- // streams is piped into the same stream.
128
- str.on('pipe', () => {
129
- str.setMaxListeners(str.getMaxListeners() + 1);
130
- });
131
-
132
- str.on('unpipe', () => {
133
- str.setMaxListeners(str.getMaxListeners() - 1);
134
- });
135
-
136
- for (const stm of streams) {
137
- stm.on('error', (err) => {
138
- logger.error(err);
139
- });
140
- stm.pipe(str);
141
- }
142
- return str;
143
- };
144
-
145
- // pipe metrics
146
- const metrics = mergeStreams(
147
- this._versionsGet.metrics,
148
- this._aliasPost.metrics,
149
- this._aliasDel.metrics,
150
- this._aliasGet.metrics,
151
- this._aliasPut.metrics,
152
- this._authPost.metrics,
153
- this._pkgLog.metrics,
154
- this._pkgGet.metrics,
155
- this._pkgPut.metrics,
156
- this._mapGet.metrics,
157
- this._mapPut.metrics,
158
- sink.metrics,
159
- );
160
-
161
- metrics.on('error', (err) => {
162
- logger.error(err);
163
- });
164
-
165
- this.metrics = metrics;
166
- this.config = config;
167
- this.logger = logger;
168
- this.sink = sink;
169
-
170
- // Print warnings
171
-
172
- if (
173
- config.get('basicAuth.type') === 'key' &&
174
- config.get('basicAuth.key') === config.default('basicAuth.key')
175
- ) {
176
- logger.warn(
177
- 'Server is running with default basic authorization key configured! For security purposes, it is highly recommended to set a custom value!',
178
- );
179
- }
180
-
181
- if (config.get('jwt.secret') === config.default('jwt.secret')) {
182
- logger.warn(
183
- 'Server is running with default jwt secret configured! For security purposes, it is highly recommended to set a custom value!',
184
- );
185
- }
186
-
187
- // Print info
188
-
189
- const hosts = config.get('organization.hostnames').join(', ');
190
- logger.info(
191
- `Files for "${hosts}" will be stored in the "${config.get('organization.name')}" organization space`,
192
- );
193
- }
194
-
195
- async health() {
196
- const health = new eik.HealthCheck({
197
- logger: this.logger,
198
- sink: this.sink,
199
- });
200
- await health.check();
201
- }
202
-
203
- api() {
204
- return (app, options, done) => {
205
- if (!app.initialConfig.ignoreTrailingSlash) {
206
- this.logger.warn(
207
- 'Fastify is configured with "ignoreTrailingSlash" set to "false". Its adviced to set "ignoreTrailingSlash" to "true"',
208
- );
209
- }
210
-
211
- app.register(cors);
212
-
213
- // Authentication
214
- app.register(jwt, {
215
- secret: config.get('jwt.secret'),
216
- messages: {
217
- badRequestErrorMessage:
218
- 'Autorization header is malformatted. Format is "Authorization: Bearer [token]"',
219
- noAuthorizationInHeaderMessage:
220
- 'Autorization header is missing!',
221
- authorizationTokenExpiredMessage:
222
- 'Authorization token expired',
223
- authorizationTokenInvalid: 'Authorization token is invalid',
224
- },
225
- });
226
-
227
- app.decorate('authenticate', async (request, reply) => {
228
- try {
229
- await request.jwtVerify();
230
- } catch (error) {
231
- reply.send(error);
232
- }
233
- });
234
-
235
- const authOptions = {
236
- preValidation: [app.authenticate],
237
- };
238
-
239
- // Handle multipart upload
240
- const _multipart = Symbol('multipart');
241
-
242
- function setMultipart(req, payload, cb) {
243
- req.raw[_multipart] = true;
244
- cb();
245
- }
246
- app.addContentTypeParser('multipart', setMultipart);
247
-
248
- // Compression
249
- app.register(compression, {
250
- global: config.get('compression.global'),
251
- });
252
-
253
- // 404 handling
254
- app.setNotFoundHandler((request, reply) => {
255
- reply.header('cache-control', this._notFoundCacheControl);
256
- reply.type('text/plain');
257
- reply.code(404);
258
- reply.send('Not found');
259
- });
260
-
261
- // Error handling
262
- app.setErrorHandler((error, request, reply) => {
263
- this.logger.debug(
264
- 'Error occured during request. Error is available on trace log level.',
265
- );
266
- this.logger.trace(error);
267
- reply.header('cache-control', 'no-store');
268
- if (error.statusCode) {
269
- if (error.statusCode === 404) {
270
- reply.header(
271
- 'cache-control',
272
- this._notFoundCacheControl,
273
- );
274
- }
275
- reply.send(error);
276
- return;
277
- }
278
- reply.send(createError(error.statusCode || 500));
279
- });
280
-
281
- //
282
- // Routes
283
- //
284
-
285
- const authPostRoutes = async (request, reply) => {
286
- const outgoing = await this._authPost.handler(request.raw);
287
-
288
- // Workaround due to .jwt.sign() being able to only
289
- // deal with object literals for some reason :/
290
- const body = JSON.parse(JSON.stringify(outgoing.body));
291
-
292
- const token = app.jwt.sign(body, {
293
- expiresIn: config.get('jwt.expire'),
294
- });
295
-
296
- reply.header('cache-control', outgoing.cacheControl);
297
- reply.type(outgoing.mimeType);
298
- reply.code(outgoing.statusCode);
299
- reply.send({ token });
300
- };
301
-
302
- const pkgGetRoute = async (request, reply) => {
303
- const params = utils.sanitizeParameters(request.raw.url);
304
- const outgoing = await this._pkgGet.handler(
305
- request.raw,
306
- params.type,
307
- params.name,
308
- params.version,
309
- params.extras,
310
- );
311
- reply.header('cache-control', outgoing.cacheControl);
312
- reply.header('etag', outgoing.etag);
313
- reply.type(outgoing.mimeType);
314
- reply.code(outgoing.statusCode);
315
- return reply.send(outgoing.stream);
316
- };
317
-
318
- const pkgLogRoute = async (request, reply) => {
319
- const params = utils.sanitizeParameters(request.raw.url);
320
- const outgoing = await this._pkgLog.handler(
321
- request.raw,
322
- params.type,
323
- params.name,
324
- params.version,
325
- );
326
- reply.header('cache-control', outgoing.cacheControl);
327
- reply.header('etag', outgoing.etag);
328
- reply.type(outgoing.mimeType);
329
- reply.code(outgoing.statusCode);
330
- return reply.send(outgoing.stream);
331
- };
332
-
333
- const versionsGetRoute = async (request, reply) => {
334
- const params = utils.sanitizeParameters(request.raw.url);
335
- const outgoing = await this._versionsGet.handler(
336
- request.raw,
337
- params.type,
338
- params.name,
339
- );
340
- reply.header('cache-control', outgoing.cacheControl);
341
- reply.header('etag', outgoing.etag);
342
- reply.type(outgoing.mimeType);
343
- reply.code(outgoing.statusCode);
344
- return reply.send(outgoing.stream);
345
- };
346
-
347
- const pkgPutRoute = async (request, reply) => {
348
- const params = utils.sanitizeParameters(request.raw.url);
349
- const outgoing = await this._pkgPut.handler(
350
- request.raw,
351
- request.user,
352
- params.type,
353
- params.name,
354
- params.version,
355
- );
356
- reply.header('cache-control', outgoing.cacheControl);
357
- reply.type(outgoing.mimeType);
358
- reply.code(outgoing.statusCode);
359
- reply.redirect(outgoing.location);
360
- };
361
-
362
- const imgPutRoute = async (request, reply) => {
363
- const params = utils.sanitizeParameters(request.raw.url);
364
- const outgoing = await this._imgPut.handler(
365
- request.raw,
366
- request.user,
367
- params.type,
368
- params.name,
369
- params.version,
370
- );
371
- reply.header('cache-control', outgoing.cacheControl);
372
- reply.type(outgoing.mimeType);
373
- reply.code(outgoing.statusCode);
374
- reply.redirect(outgoing.location);
375
- };
376
-
377
- const mapGetRoute = async (request, reply) => {
378
- const params = utils.sanitizeParameters(request.raw.url);
379
- const outgoing = await this._mapGet.handler(
380
- request.raw,
381
- params.name,
382
- params.version,
383
- );
384
- reply.header('cache-control', outgoing.cacheControl);
385
- reply.header('etag', outgoing.etag);
386
- reply.type(outgoing.mimeType);
387
- reply.code(outgoing.statusCode);
388
- return reply.send(outgoing.stream);
389
- };
390
-
391
- const mapPutRoute = async (request, reply) => {
392
- const params = utils.sanitizeParameters(request.raw.url);
393
- const outgoing = await this._mapPut.handler(
394
- request.raw,
395
- request.user,
396
- params.name,
397
- params.version,
398
- );
399
- reply.header('cache-control', outgoing.cacheControl);
400
- reply.type(outgoing.mimeType);
401
- reply.code(outgoing.statusCode);
402
- reply.redirect(outgoing.location);
403
- };
404
-
405
- const aliasGetRoute = async (request, reply) => {
406
- const params = utils.sanitizeParameters(request.raw.url);
407
- const outgoing = await this._aliasGet.handler(
408
- request.raw,
409
- params.type,
410
- params.name,
411
- params.alias,
412
- params.extras,
413
- );
414
- reply.header('cache-control', outgoing.cacheControl);
415
- reply.type(outgoing.mimeType);
416
- reply.code(outgoing.statusCode);
417
- reply.redirect(outgoing.location);
418
- };
419
-
420
- const aliasPutRoute = async (request, reply) => {
421
- const params = utils.sanitizeParameters(request.raw.url);
422
- const outgoing = await this._aliasPut.handler(
423
- request.raw,
424
- request.user,
425
- params.type,
426
- params.name,
427
- params.alias,
428
- );
429
- reply.header('cache-control', outgoing.cacheControl);
430
- reply.type(outgoing.mimeType);
431
- reply.code(outgoing.statusCode);
432
- reply.redirect(outgoing.location);
433
- };
434
-
435
- const aliasPostRoute = async (request, reply) => {
436
- const params = utils.sanitizeParameters(request.raw.url);
437
- const outgoing = await this._aliasPost.handler(
438
- request.raw,
439
- request.user,
440
- params.type,
441
- params.name,
442
- params.alias,
443
- );
444
- reply.header('cache-control', outgoing.cacheControl);
445
- reply.type(outgoing.mimeType);
446
- reply.code(outgoing.statusCode);
447
- reply.redirect(outgoing.location);
448
- };
449
-
450
- const aliasDelRoute = async (request, reply) => {
451
- const params = utils.sanitizeParameters(request.raw.url);
452
- const outgoing = await this._aliasDel.handler(
453
- request.raw,
454
- request.user,
455
- params.type,
456
- params.name,
457
- params.alias,
458
- );
459
- reply.header('cache-control', outgoing.cacheControl);
460
- reply.type(outgoing.mimeType);
461
- reply.code(outgoing.statusCode);
462
- reply.send(outgoing.body);
463
- };
464
-
465
- //
466
- // Authentication
467
- //
468
-
469
- // curl -X POST -i -F key=foo http://localhost:4001/auth/login
470
-
471
- app.post(`/${eik.prop.base_auth}/login`, authPostRoutes);
472
-
473
- //
474
- // Packages
475
- //
476
-
477
- // Get public package - scoped
478
- // curl -X GET http://localhost:4001/pkg/@cuz/fuzz/8.4.1/main/index.js
479
- app.get(
480
- `/${eik.prop.base_pkg}/@:scope/:name/:version/*`,
481
- pkgGetRoute,
482
- );
483
-
484
- // Get public package - non-scoped
485
- // curl -X GET http://localhost:4001/pkg/fuzz/8.4.1/main/index.js
486
- app.get(`/${eik.prop.base_pkg}/:name/:version/*`, pkgGetRoute);
487
-
488
- // Get package overview - scoped
489
- // curl -X GET http://localhost:4001/pkg/@cuz/fuzz/8.4.1/
490
- app.get(
491
- `/${eik.prop.base_pkg}/@:scope/:name/:version`,
492
- pkgLogRoute,
493
- );
494
-
495
- // Get package overview - non-scoped
496
- // curl -X GET http://localhost:4001/pkg/fuzz/8.4.1/
497
- app.get(`/${eik.prop.base_pkg}/:name/:version`, pkgLogRoute);
498
-
499
- // Get package versions - scoped
500
- // curl -X GET http://localhost:4001/pkg/@cuz/fuzz/
501
- app.get(`/${eik.prop.base_pkg}/@:scope/:name`, versionsGetRoute);
502
-
503
- // Get package versions - non-scoped
504
- // curl -X GET http://localhost:4001/pkg/fuzz/
505
- app.get(`/${eik.prop.base_pkg}/:name`, versionsGetRoute);
506
-
507
- // Put package - scoped
508
- // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/pkg/@cuz/fuzz/8.4.1/
509
- app.put(
510
- `/${eik.prop.base_pkg}/@:scope/:name/:version`,
511
- authOptions,
512
- pkgPutRoute,
513
- );
514
-
515
- // Put package - non-scoped
516
- // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/pkg/fuzz/8.4.1/
517
- app.put(
518
- `/${eik.prop.base_pkg}/:name/:version`,
519
- authOptions,
520
- pkgPutRoute,
521
- );
522
-
523
- //
524
- // NPM Packages
525
- //
526
-
527
- // Get public NPM package - scoped
528
- // curl -X GET http://localhost:4001/npm/@cuz/fuzz/8.4.1/main/index.js
529
- app.get(
530
- `/${eik.prop.base_npm}/@:scope/:name/:version/*`,
531
- pkgGetRoute,
532
- );
533
-
534
- // Get public NPM package - non-scoped
535
- // curl -X GET http://localhost:4001/npm/fuzz/8.4.1/main/index.js
536
- app.get(`/${eik.prop.base_npm}/:name/:version/*`, pkgGetRoute);
537
-
538
- // Get NPM package overview - scoped
539
- // curl -X GET http://localhost:4001/npm/@cuz/fuzz/8.4.1/
540
- app.get(
541
- `/${eik.prop.base_npm}/@:scope/:name/:version`,
542
- pkgLogRoute,
543
- );
544
-
545
- // Get NPM package overview - non-scoped
546
- // curl -X GET http://localhost:4001/npm/fuzz/8.4.1/
547
- app.get(`/${eik.prop.base_npm}/:name/:version`, pkgLogRoute);
548
-
549
- // Get NPM package versions - scoped
550
- // curl -X GET http://localhost:4001/npm/@cuz/fuzz/
551
- app.get(`/${eik.prop.base_npm}/@:scope/:name`, versionsGetRoute);
552
-
553
- // Get NPM package versions - non-scoped
554
- // curl -X GET http://localhost:4001/npm/fuzz/
555
- app.get(`/${eik.prop.base_npm}/:name`, versionsGetRoute);
556
-
557
- // Put NPM package - scoped
558
- // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/npm/@cuz/fuzz/8.4.1/
559
- app.put(
560
- `/${eik.prop.base_npm}/@:scope/:name/:version`,
561
- authOptions,
562
- pkgPutRoute,
563
- );
564
-
565
- // Put NPM package - non-scoped
566
- // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/npm/fuzz/8.4.1/
567
- app.put(
568
- `/${eik.prop.base_npm}/:name/:version`,
569
- authOptions,
570
- pkgPutRoute,
571
- );
572
-
573
- //
574
- // Image Packages
575
- //
576
-
577
- // Get public IMG package - scoped
578
- // curl -X GET http://localhost:4001/img/@cuz/fuzz/8.4.1/main/picture.jpg
579
- app.get(
580
- `/${eik.prop.base_img}/@:scope/:name/:version/*`,
581
- pkgGetRoute,
582
- );
583
-
584
- // Get public IMG package - non-scoped
585
- // curl -X GET http://localhost:4001/img/fuzz/8.4.1/main/picture.jpg
586
- app.get(`/${eik.prop.base_img}/:name/:version/*`, pkgGetRoute);
587
-
588
- // Get IMG package overview - scoped
589
- // curl -X GET http://localhost:4001/img/@cuz/fuzz/8.4.1/
590
- app.get(
591
- `/${eik.prop.base_img}/@:scope/:name/:version`,
592
- pkgLogRoute,
593
- );
594
-
595
- // Get IMG package overview - non-scoped
596
- // curl -X GET http://localhost:4001/img/fuzz/8.4.1/
597
- app.get(`/${eik.prop.base_img}/:name/:version`, pkgLogRoute);
598
-
599
- // Get IMG package versions - scoped
600
- // curl -X GET http://localhost:4001/img/@cuz/fuzz/
601
- app.get(`/${eik.prop.base_img}/@:scope/:name`, versionsGetRoute);
602
-
603
- // Get IMG package versions - non-scoped
604
- // curl -X GET http://localhost:4001/img/fuzz/
605
- app.get(`/${eik.prop.base_img}/:name`, versionsGetRoute);
606
-
607
- // Put IMG package - scoped
608
- // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/img/@cuz/fuzz/8.4.1/
609
- app.put(
610
- `/${eik.prop.base_img}/@:scope/:name/:version`,
611
- authOptions,
612
- imgPutRoute,
613
- );
614
-
615
- // Put IMG package - non-scoped
616
- // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/img/fuzz/8.4.1/
617
- app.put(
618
- `/${eik.prop.base_img}/:name/:version`,
619
- authOptions,
620
- imgPutRoute,
621
- );
622
-
623
- //
624
- // Import Maps
625
- //
626
-
627
- // Get map - scoped
628
- // curl -X GET http://localhost:4001/map/@cuz/buzz/4.2.2
629
- app.get(
630
- `/${eik.prop.base_map}/@:scope/:name/:version`,
631
- mapGetRoute,
632
- );
633
-
634
- // Get map - non-scoped
635
- // curl -X GET http://localhost:4001/map/buzz/4.2.2
636
- app.get(`/${eik.prop.base_map}/:name/:version`, mapGetRoute);
637
-
638
- // Get map versions - scoped
639
- // curl -X GET http://localhost:4001/map/@cuz/buzz
640
- app.get(`/${eik.prop.base_map}/@:scope/:name`, versionsGetRoute);
641
-
642
- // Get map versions - non-scoped
643
- // curl -X GET http://localhost:4001/map/buzz
644
- app.get(`/${eik.prop.base_map}/:name`, versionsGetRoute);
645
-
646
- // Put map - scoped
647
- // curl -X PUT -i -F map=@import-map.json http://localhost:4001/map/@cuz/buzz/4.2.2
648
- app.put(
649
- `/${eik.prop.base_map}/@:scope/:name/:version`,
650
- authOptions,
651
- mapPutRoute,
652
- );
653
-
654
- // Put map - non-scoped
655
- // curl -X PUT -i -F map=@import-map.json http://localhost:4001/map/buzz/4.2.2
656
- app.put(
657
- `/${eik.prop.base_map}/:name/:version`,
658
- authOptions,
659
- mapPutRoute,
660
- );
661
-
662
- //
663
- // Alias Packages
664
- //
665
-
666
- // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/v8
667
- app.get(
668
- `/${eik.prop.base_pkg}/@:scope/:name/v:alias`,
669
- aliasGetRoute,
670
- );
671
-
672
- // curl -X GET -L http://localhost:4001/pkg/fuzz/v8
673
- app.get(`/${eik.prop.base_pkg}/:name/v:alias`, aliasGetRoute);
674
-
675
- // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/v8/main/index.js
676
- app.get(
677
- `/${eik.prop.base_pkg}/@:scope/:name/v:alias/*`,
678
- aliasGetRoute,
679
- );
680
-
681
- // curl -X GET -L http://localhost:4001/pkg/fuzz/v8/main/index.js
682
- app.get(`/${eik.prop.base_pkg}/:name/v:alias/*`, aliasGetRoute);
683
-
684
- // curl -X PUT -i -F version=8.4.1 http://localhost:4001/pkg/@cuz/fuzz/v8
685
- app.put(
686
- `/${eik.prop.base_pkg}/@:scope/:name/v:alias`,
687
- authOptions,
688
- aliasPutRoute,
689
- );
690
-
691
- // curl -X PUT -i -F version=8.4.1 http://localhost:4001/pkg/fuzz/v8
692
- app.put(
693
- `/${eik.prop.base_pkg}/:name/v:alias`,
694
- authOptions,
695
- aliasPutRoute,
696
- );
697
-
698
- // curl -X POST -i -F version=8.4.1 http://localhost:4001/pkg/@cuz/lit-html/v8
699
- app.post(
700
- `/${eik.prop.base_pkg}/@:scope/:name/v:alias`,
701
- authOptions,
702
- aliasPostRoute,
703
- );
704
-
705
- // curl -X POST -i -F version=8.4.1 http://localhost:4001/pkg/lit-html/v8
706
- app.post(
707
- `/${eik.prop.base_pkg}/:name/v:alias`,
708
- authOptions,
709
- aliasPostRoute,
710
- );
711
-
712
- // curl -X DELETE http://localhost:4001/pkg/@cuz/fuzz/v8
713
- app.delete(
714
- `/${eik.prop.base_pkg}/@:scope/:name/v:alias`,
715
- authOptions,
716
- aliasDelRoute,
717
- );
718
-
719
- // curl -X DELETE http://localhost:4001/pkg/fuzz/v8
720
- app.delete(
721
- `/${eik.prop.base_pkg}/:name/v:alias`,
722
- authOptions,
723
- aliasDelRoute,
724
- );
725
-
726
- //
727
- // Alias NPM Packages
728
- //
729
-
730
- // curl -X GET -L http://localhost:4001/npm/@cuz/fuzz/v8
731
- app.get(
732
- `/${eik.prop.base_npm}/@:scope/:name/v:alias`,
733
- aliasGetRoute,
734
- );
735
-
736
- // curl -X GET -L http://localhost:4001/npm/fuzz/v8
737
- app.get(`/${eik.prop.base_npm}/:name/v:alias`, aliasGetRoute);
738
-
739
- // curl -X GET -L http://localhost:4001/npm/@cuz/fuzz/v8/main/index.js
740
- app.get(
741
- `/${eik.prop.base_npm}/@:scope/:name/v:alias/*`,
742
- aliasGetRoute,
743
- );
744
-
745
- // curl -X GET -L http://localhost:4001/npm/fuzz/v8/main/index.js
746
- app.get(`/${eik.prop.base_npm}/:name/v:alias/*`, aliasGetRoute);
747
-
748
- // curl -X PUT -i -F version=8.4.1 http://localhost:4001/npm/@cuz/fuzz/v8
749
- app.put(
750
- `/${eik.prop.base_npm}/@:scope/:name/v:alias`,
751
- authOptions,
752
- aliasPutRoute,
753
- );
754
-
755
- // curl -X PUT -i -F version=8.4.1 http://localhost:4001/npm/fuzz/v8
756
- app.put(
757
- `/${eik.prop.base_npm}/:name/v:alias`,
758
- authOptions,
759
- aliasPutRoute,
760
- );
761
-
762
- // curl -X POST -i -F version=8.4.1 http://localhost:4001/npm/@cuz/lit-html/v8
763
- app.post(
764
- `/${eik.prop.base_npm}/@:scope/:name/v:alias`,
765
- authOptions,
766
- aliasPostRoute,
767
- );
768
-
769
- // curl -X POST -i -F version=8.4.1 http://localhost:4001/npm/lit-html/v8
770
- app.post(
771
- `/${eik.prop.base_npm}/:name/v:alias`,
772
- authOptions,
773
- aliasPostRoute,
774
- );
775
-
776
- // curl -X DELETE http://localhost:4001/npm/@cuz/fuzz/v8
777
- app.delete(
778
- `/${eik.prop.base_npm}/@:scope/:name/v:alias`,
779
- authOptions,
780
- aliasDelRoute,
781
- );
782
-
783
- // curl -X DELETE http://localhost:4001/npm/fuzz/v8
784
- app.delete(
785
- `/${eik.prop.base_npm}/:name/v:alias`,
786
- authOptions,
787
- aliasDelRoute,
788
- );
789
-
790
- //
791
- // Alias Image Packages
792
- //
793
-
794
- // curl -X GET -L http://localhost:4001/img/@cuz/fuzz/v8
795
- app.get(
796
- `/${eik.prop.base_img}/@:scope/:name/v:alias`,
797
- aliasGetRoute,
798
- );
799
-
800
- // curl -X GET -L http://localhost:4001/img/fuzz/v8
801
- app.get(`/${eik.prop.base_img}/:name/v:alias`, aliasGetRoute);
802
-
803
- // curl -X GET -L http://localhost:4001/img/@cuz/fuzz/v8/main/index.js
804
- app.get(
805
- `/${eik.prop.base_img}/@:scope/:name/v:alias/*`,
806
- aliasGetRoute,
807
- );
808
-
809
- // curl -X GET -L http://localhost:4001/img/fuzz/v8/main/index.js
810
- app.get(`/${eik.prop.base_img}/:name/v:alias/*`, aliasGetRoute);
811
-
812
- // curl -X PUT -i -F version=8.4.1 http://localhost:4001/img/@cuz/fuzz/v8
813
- app.put(
814
- `/${eik.prop.base_img}/@:scope/:name/v:alias`,
815
- authOptions,
816
- aliasPutRoute,
817
- );
818
-
819
- // curl -X PUT -i -F version=8.4.1 http://localhost:4001/img/fuzz/v8
820
- app.put(
821
- `/${eik.prop.base_img}/:name/v:alias`,
822
- authOptions,
823
- aliasPutRoute,
824
- );
825
-
826
- // curl -X POST -i -F version=8.4.1 http://localhost:4001/img/@cuz/lit-html/v8
827
- app.post(
828
- `/${eik.prop.base_img}/@:scope/:name/v:alias`,
829
- authOptions,
830
- aliasPostRoute,
831
- );
832
-
833
- // curl -X POST -i -F version=8.4.1 http://localhost:4001/img/lit-html/v8
834
- app.post(
835
- `/${eik.prop.base_img}/:name/v:alias`,
836
- authOptions,
837
- aliasPostRoute,
838
- );
839
-
840
- // curl -X DELETE http://localhost:4001/img/@cuz/fuzz/v8
841
- app.delete(
842
- `/${eik.prop.base_img}/@:scope/:name/v:alias`,
843
- authOptions,
844
- aliasDelRoute,
845
- );
846
-
847
- // curl -X DELETE http://localhost:4001/img/fuzz/v8
848
- app.delete(
849
- `/${eik.prop.base_img}/:name/v:alias`,
850
- authOptions,
851
- aliasDelRoute,
852
- );
853
-
854
- //
855
- // Alias Import Maps
856
- //
857
-
858
- // curl -X GET -L http://localhost:4001/map/@cuz/buzz/v4
859
- app.get(
860
- `/${eik.prop.base_map}/@:scope/:name/v:alias`,
861
- aliasGetRoute,
862
- );
863
-
864
- // curl -X GET -L http://localhost:4001/map/buzz/v4
865
- app.get(`/${eik.prop.base_map}/:name/v:alias`, aliasGetRoute);
866
-
867
- // curl -X PUT -i -F version=4.2.2 http://localhost:4001/map/@cuz/buzz/v4
868
- app.put(
869
- `/${eik.prop.base_map}/@:scope/:name/v:alias`,
870
- authOptions,
871
- aliasPutRoute,
872
- );
873
-
874
- // curl -X PUT -i -F version=4.2.2 http://localhost:4001/map/buzz/v4
875
- app.put(
876
- `/${eik.prop.base_map}/:name/v:alias`,
877
- authOptions,
878
- aliasPutRoute,
879
- );
880
-
881
- // curl -X POST -i -F version=4.4.2 http://localhost:4001/map/@cuz/buzz/v4
882
- app.post(
883
- `/${eik.prop.base_map}/@:scope/:name/v:alias`,
884
- authOptions,
885
- aliasPostRoute,
886
- );
887
-
888
- // curl -X POST -i -F version=4.4.2 http://localhost:4001/map/buzz/v4
889
- app.post(
890
- `/${eik.prop.base_map}/:name/v:alias`,
891
- authOptions,
892
- aliasPostRoute,
893
- );
894
-
895
- // curl -X DELETE http://localhost:4001/map/@cuz/buzz/v4
896
- app.delete(
897
- `/${eik.prop.base_map}/@:scope/:name/v:alias`,
898
- authOptions,
899
- aliasDelRoute,
900
- );
901
-
902
- // curl -X DELETE http://localhost:4001/map/buzz/v4
903
- app.delete(
904
- `/${eik.prop.base_map}/:name/v:alias`,
905
- authOptions,
906
- aliasDelRoute,
907
- );
908
-
909
- done();
910
- };
911
- }
28
+ /**
29
+ * @param {EikServiceOptions} [options={}]
30
+ */
31
+ constructor(options = {}) {
32
+ let { sink, logger } = options;
33
+ const {
34
+ customSink,
35
+ notFoundCacheControl,
36
+ aliasCacheControl,
37
+ pkgMaxFileSize = 10000000,
38
+ mapMaxFileSize = 1000000,
39
+ imgMaxFileSize = 20000000,
40
+ } = options;
41
+ this._notFoundCacheControl = notFoundCacheControl || "public, max-age=5";
42
+
43
+ if (!logger) {
44
+ // @ts-expect-error This is in fact callable
45
+ logger = pino({
46
+ // @ts-ignore
47
+ level: config.get("log.level"),
48
+ name: config.get("name"),
49
+ });
50
+ }
51
+
52
+ if (sink) {
53
+ logger.info(`Using the provided sink ${sink.constructor.name}`);
54
+ } else if (customSink) {
55
+ logger.warn(
56
+ "The `customSink` option is deprecated and will be removed at a later stage. Use `sink` to remove this warning.",
57
+ );
58
+ sink = customSink;
59
+ } else if (config.get("sink.type") === "mem") {
60
+ logger.info(
61
+ `Server is running with a in memory sink. Uploaded files will be lost on restart!`,
62
+ );
63
+ sink = new SinkMemory();
64
+ } else {
65
+ logger.info(
66
+ `Server is running with the file system sink. Uploaded files will be stored under "${config.get("sink.path")}"`,
67
+ );
68
+ sink = new SinkFileSystem({
69
+ sinkFsRootPath: config.get("sink.path"),
70
+ });
71
+ }
72
+
73
+ // Transform organization config
74
+ const organizations = config
75
+ .get("organization.hostnames")
76
+ .map((hostname) => [hostname, config.get("organization.name")]);
77
+
78
+ this._versionsGet = new eik.http.VersionsGet({
79
+ organizations,
80
+ sink,
81
+ logger,
82
+ });
83
+ this._aliasPost = new eik.http.AliasPost({
84
+ organizations,
85
+ sink,
86
+ logger,
87
+ });
88
+ this._aliasDel = new eik.http.AliasDel({ organizations, sink, logger });
89
+ this._aliasGet = new eik.http.AliasGet({
90
+ organizations,
91
+ sink,
92
+ logger,
93
+ cacheControl: aliasCacheControl,
94
+ });
95
+ this._aliasPut = new eik.http.AliasPut({ organizations, sink, logger });
96
+ this._authPost = new eik.http.AuthPost({
97
+ organizations,
98
+ logger,
99
+ authKey: config.get("basicAuth.key"),
100
+ });
101
+ this._pkgLog = new eik.http.PkgLog({ organizations, sink, logger });
102
+ this._pkgGet = new eik.http.PkgGet({ organizations, sink, logger });
103
+ this._pkgPut = new eik.http.PkgPut({
104
+ organizations,
105
+ sink,
106
+ logger,
107
+ pkgMaxFileSize,
108
+ });
109
+ this._imgPut = new eik.http.PkgPut({
110
+ organizations,
111
+ sink,
112
+ logger,
113
+ pkgMaxFileSize: imgMaxFileSize,
114
+ });
115
+ this._mapGet = new eik.http.MapGet({ organizations, sink, logger });
116
+ this._mapPut = new eik.http.MapPut({
117
+ organizations,
118
+ sink,
119
+ logger,
120
+ mapMaxFileSize,
121
+ });
122
+
123
+ const mergeStreams = (...streams) => {
124
+ const str = new PassThrough({ objectMode: true });
125
+
126
+ // Avoid hitting the max listeners limit when multiple
127
+ // streams is piped into the same stream.
128
+ str.on("pipe", () => {
129
+ str.setMaxListeners(str.getMaxListeners() + 1);
130
+ });
131
+
132
+ str.on("unpipe", () => {
133
+ str.setMaxListeners(str.getMaxListeners() - 1);
134
+ });
135
+
136
+ for (const stm of streams) {
137
+ stm.on("error", (err) => {
138
+ logger.error(err);
139
+ });
140
+ stm.pipe(str);
141
+ }
142
+ return str;
143
+ };
144
+
145
+ // pipe metrics
146
+ const metrics = mergeStreams(
147
+ this._versionsGet.metrics,
148
+ this._aliasPost.metrics,
149
+ this._aliasDel.metrics,
150
+ this._aliasGet.metrics,
151
+ this._aliasPut.metrics,
152
+ this._authPost.metrics,
153
+ this._pkgLog.metrics,
154
+ this._pkgGet.metrics,
155
+ this._pkgPut.metrics,
156
+ this._mapGet.metrics,
157
+ this._mapPut.metrics,
158
+ sink.metrics,
159
+ );
160
+
161
+ metrics.on("error", (err) => {
162
+ logger.error(err);
163
+ });
164
+
165
+ this.metrics = metrics;
166
+ this.config = config;
167
+ this.logger = logger;
168
+ this.sink = sink;
169
+
170
+ // Print warnings
171
+
172
+ if (
173
+ config.get("basicAuth.type") === "key" &&
174
+ config.get("basicAuth.key") === config.default("basicAuth.key")
175
+ ) {
176
+ logger.warn(
177
+ "Server is running with default basic authorization key configured! For security purposes, it is highly recommended to set a custom value!",
178
+ );
179
+ }
180
+
181
+ if (config.get("jwt.secret") === config.default("jwt.secret")) {
182
+ logger.warn(
183
+ "Server is running with default jwt secret configured! For security purposes, it is highly recommended to set a custom value!",
184
+ );
185
+ }
186
+
187
+ // Print info
188
+
189
+ const hosts = config.get("organization.hostnames").join(", ");
190
+ logger.info(
191
+ `Files for "${hosts}" will be stored in the "${config.get("organization.name")}" organization space`,
192
+ );
193
+ }
194
+
195
+ async health() {
196
+ const health = new eik.HealthCheck({
197
+ logger: this.logger,
198
+ sink: this.sink,
199
+ });
200
+ await health.check();
201
+ }
202
+
203
+ api() {
204
+ /** @param {import('fastify').FastifyInstance} app */
205
+ return async (app) => {
206
+ if (!app.initialConfig.ignoreTrailingSlash) {
207
+ this.logger.warn(
208
+ 'Fastify is configured with "ignoreTrailingSlash" set to "false". Its adviced to set "ignoreTrailingSlash" to "true"',
209
+ );
210
+ }
211
+
212
+ await app.register(cors);
213
+
214
+ // Authentication
215
+ app.register(jwt, {
216
+ secret: config.get("jwt.secret"),
217
+ messages: {
218
+ badRequestErrorMessage:
219
+ 'Autorization header is malformatted. Format is "Authorization: Bearer [token]"',
220
+ noAuthorizationInHeaderMessage: "Autorization header is missing!",
221
+ authorizationTokenExpiredMessage: "Authorization token expired",
222
+ authorizationTokenInvalid: "Authorization token is invalid",
223
+ },
224
+ });
225
+
226
+ app.decorate("authenticate", async (request, reply) => {
227
+ try {
228
+ await request.jwtVerify();
229
+ } catch (error) {
230
+ reply.send(error);
231
+ }
232
+ });
233
+
234
+ const authOptions = {
235
+ // @ts-expect-error We decorate it above
236
+ preValidation: [app.authenticate],
237
+ };
238
+
239
+ // Handle multipart upload
240
+ const _multipart = Symbol("multipart");
241
+
242
+ function setMultipart(req, payload, cb) {
243
+ req.raw[_multipart] = true;
244
+ cb();
245
+ }
246
+ app.addContentTypeParser("multipart/form-data", setMultipart);
247
+
248
+ // Compression
249
+ await app.register(compression, {
250
+ global: config.get("compression.global"),
251
+ brotliOptions: {
252
+ // The default is 4 (was 11 before @fastify/compress@^7.0.0).
253
+ // 5 sees benefits for file sizes above 64Kb, of which we have several.
254
+ // https://github.com/fastify/fastify-compress/pull/278#issuecomment-1914778795
255
+ [zlib.constants.BROTLI_PARAM_QUALITY]: 5,
256
+ },
257
+ });
258
+
259
+ // 404 handling
260
+ app.setNotFoundHandler((request, reply) => {
261
+ reply.header("cache-control", this._notFoundCacheControl);
262
+ reply.type("text/plain");
263
+ reply.code(404);
264
+ reply.send("Not found");
265
+ });
266
+
267
+ // Error handling
268
+ app.setErrorHandler((error, request, reply) => {
269
+ this.logger.debug(
270
+ "Error occured during request. Error is available on trace log level.",
271
+ );
272
+ this.logger.trace(error);
273
+ reply.header("cache-control", "no-store");
274
+ if (error.statusCode) {
275
+ if (error.statusCode === 404) {
276
+ reply.header("cache-control", this._notFoundCacheControl);
277
+ }
278
+ reply.send(error);
279
+ return;
280
+ }
281
+ reply.send(createError(error.statusCode || 500));
282
+ });
283
+
284
+ //
285
+ // Routes
286
+ //
287
+
288
+ const authPostRoutes = async (request, reply) => {
289
+ const outgoing = await this._authPost.handler(request.raw);
290
+
291
+ // Workaround due to .jwt.sign() being able to only
292
+ // deal with object literals for some reason :/
293
+ const body = JSON.parse(JSON.stringify(outgoing.body));
294
+
295
+ const token = app.jwt.sign(body, {
296
+ expiresIn: config.get("jwt.expire"),
297
+ });
298
+
299
+ reply.header("cache-control", outgoing.cacheControl);
300
+ reply.type(outgoing.mimeType);
301
+ reply.code(outgoing.statusCode);
302
+ reply.send({ token });
303
+ };
304
+
305
+ const pkgGetRoute = async (request, reply) => {
306
+ const params = utils.sanitizeParameters(request.raw.url);
307
+ const outgoing = await this._pkgGet.handler(
308
+ request.raw,
309
+ params.type,
310
+ params.name,
311
+ params.version,
312
+ params.extras,
313
+ );
314
+ reply.header("cache-control", outgoing.cacheControl);
315
+ reply.header("etag", outgoing.etag);
316
+ reply.type(outgoing.mimeType);
317
+ reply.code(outgoing.statusCode);
318
+ return reply.send(outgoing.stream);
319
+ };
320
+
321
+ const pkgLogRoute = async (request, reply) => {
322
+ const params = utils.sanitizeParameters(request.raw.url);
323
+ const outgoing = await this._pkgLog.handler(
324
+ request.raw,
325
+ params.type,
326
+ params.name,
327
+ params.version,
328
+ );
329
+ reply.header("cache-control", outgoing.cacheControl);
330
+ reply.header("etag", outgoing.etag);
331
+ reply.type(outgoing.mimeType);
332
+ reply.code(outgoing.statusCode);
333
+ return reply.send(outgoing.stream);
334
+ };
335
+
336
+ const versionsGetRoute = async (request, reply) => {
337
+ const params = utils.sanitizeParameters(request.raw.url);
338
+ const outgoing = await this._versionsGet.handler(
339
+ request.raw,
340
+ params.type,
341
+ params.name,
342
+ );
343
+ reply.header("cache-control", outgoing.cacheControl);
344
+ reply.header("etag", outgoing.etag);
345
+ reply.type(outgoing.mimeType);
346
+ reply.code(outgoing.statusCode);
347
+ return reply.send(outgoing.stream);
348
+ };
349
+
350
+ const pkgPutRoute = async (request, reply) => {
351
+ const params = utils.sanitizeParameters(request.raw.url);
352
+ const outgoing = await this._pkgPut.handler(
353
+ request.raw,
354
+ request.user,
355
+ params.type,
356
+ params.name,
357
+ params.version,
358
+ );
359
+ reply.header("cache-control", outgoing.cacheControl);
360
+ reply.type(outgoing.mimeType);
361
+ reply.code(outgoing.statusCode);
362
+ reply.redirect(outgoing.location);
363
+ };
364
+
365
+ const imgPutRoute = async (request, reply) => {
366
+ const params = utils.sanitizeParameters(request.raw.url);
367
+ const outgoing = await this._imgPut.handler(
368
+ request.raw,
369
+ request.user,
370
+ params.type,
371
+ params.name,
372
+ params.version,
373
+ );
374
+ reply.header("cache-control", outgoing.cacheControl);
375
+ reply.type(outgoing.mimeType);
376
+ reply.code(outgoing.statusCode);
377
+ reply.redirect(outgoing.location);
378
+ };
379
+
380
+ const mapGetRoute = async (request, reply) => {
381
+ const params = utils.sanitizeParameters(request.raw.url);
382
+ const outgoing = await this._mapGet.handler(
383
+ request.raw,
384
+ params.name,
385
+ params.version,
386
+ );
387
+ reply.header("cache-control", outgoing.cacheControl);
388
+ reply.header("etag", outgoing.etag);
389
+ reply.type(outgoing.mimeType);
390
+ reply.code(outgoing.statusCode);
391
+ return reply.send(outgoing.stream);
392
+ };
393
+
394
+ const mapPutRoute = async (request, reply) => {
395
+ const params = utils.sanitizeParameters(request.raw.url);
396
+ const outgoing = await this._mapPut.handler(
397
+ request.raw,
398
+ request.user,
399
+ params.name,
400
+ params.version,
401
+ );
402
+ reply.header("cache-control", outgoing.cacheControl);
403
+ reply.type(outgoing.mimeType);
404
+ reply.code(outgoing.statusCode);
405
+ reply.redirect(outgoing.location);
406
+ };
407
+
408
+ const aliasGetRoute = async (request, reply) => {
409
+ const params = utils.sanitizeParameters(request.raw.url);
410
+ const outgoing = await this._aliasGet.handler(
411
+ request.raw,
412
+ params.type,
413
+ params.name,
414
+ params.alias,
415
+ params.extras,
416
+ );
417
+ reply.header("cache-control", outgoing.cacheControl);
418
+ reply.type(outgoing.mimeType);
419
+ reply.code(outgoing.statusCode);
420
+ reply.redirect(outgoing.location);
421
+ };
422
+
423
+ const aliasPutRoute = async (request, reply) => {
424
+ const params = utils.sanitizeParameters(request.raw.url);
425
+ const outgoing = await this._aliasPut.handler(
426
+ request.raw,
427
+ request.user,
428
+ params.type,
429
+ params.name,
430
+ params.alias,
431
+ );
432
+ reply.header("cache-control", outgoing.cacheControl);
433
+ reply.type(outgoing.mimeType);
434
+ reply.code(outgoing.statusCode);
435
+ reply.redirect(outgoing.location);
436
+ };
437
+
438
+ const aliasPostRoute = async (request, reply) => {
439
+ const params = utils.sanitizeParameters(request.raw.url);
440
+ const outgoing = await this._aliasPost.handler(
441
+ request.raw,
442
+ request.user,
443
+ params.type,
444
+ params.name,
445
+ params.alias,
446
+ );
447
+ reply.header("cache-control", outgoing.cacheControl);
448
+ reply.type(outgoing.mimeType);
449
+ reply.code(outgoing.statusCode);
450
+ reply.redirect(outgoing.location);
451
+ };
452
+
453
+ const aliasDelRoute = async (request, reply) => {
454
+ const params = utils.sanitizeParameters(request.raw.url);
455
+ const outgoing = await this._aliasDel.handler(
456
+ request.raw,
457
+ request.user,
458
+ params.type,
459
+ params.name,
460
+ params.alias,
461
+ );
462
+ reply.header("cache-control", outgoing.cacheControl);
463
+ reply.type(outgoing.mimeType);
464
+ reply.code(outgoing.statusCode);
465
+ reply.send(outgoing.body);
466
+ };
467
+
468
+ //
469
+ // Authentication
470
+ //
471
+
472
+ // curl -X POST -i -F key=foo http://localhost:4001/auth/login
473
+
474
+ app.post(`/${eik.prop.base_auth}/login`, authPostRoutes);
475
+
476
+ //
477
+ // Packages
478
+ //
479
+
480
+ // Get public package - scoped
481
+ // curl -X GET http://localhost:4001/pkg/@cuz/fuzz/8.4.1/main/index.js
482
+ app.get(`/${eik.prop.base_pkg}/@:scope/:name/:version/*`, pkgGetRoute);
483
+
484
+ // Get public package - non-scoped
485
+ // curl -X GET http://localhost:4001/pkg/fuzz/8.4.1/main/index.js
486
+ app.get(`/${eik.prop.base_pkg}/:name/:version/*`, pkgGetRoute);
487
+
488
+ // Get package overview - scoped
489
+ // curl -X GET http://localhost:4001/pkg/@cuz/fuzz/8.4.1/
490
+ app.get(`/${eik.prop.base_pkg}/@:scope/:name/:version`, pkgLogRoute);
491
+
492
+ // Get package overview - non-scoped
493
+ // curl -X GET http://localhost:4001/pkg/fuzz/8.4.1/
494
+ app.get(`/${eik.prop.base_pkg}/:name/:version`, pkgLogRoute);
495
+
496
+ // Get package versions - scoped
497
+ // curl -X GET http://localhost:4001/pkg/@cuz/fuzz/
498
+ app.get(`/${eik.prop.base_pkg}/@:scope/:name`, versionsGetRoute);
499
+
500
+ // Get package versions - non-scoped
501
+ // curl -X GET http://localhost:4001/pkg/fuzz/
502
+ app.get(`/${eik.prop.base_pkg}/:name`, versionsGetRoute);
503
+
504
+ // Put package - scoped
505
+ // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/pkg/@cuz/fuzz/8.4.1/
506
+ app.put(
507
+ `/${eik.prop.base_pkg}/@:scope/:name/:version`,
508
+ authOptions,
509
+ pkgPutRoute,
510
+ );
511
+
512
+ // Put package - non-scoped
513
+ // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/pkg/fuzz/8.4.1/
514
+ app.put(`/${eik.prop.base_pkg}/:name/:version`, authOptions, pkgPutRoute);
515
+
516
+ //
517
+ // NPM Packages
518
+ //
519
+
520
+ // Get public NPM package - scoped
521
+ // curl -X GET http://localhost:4001/npm/@cuz/fuzz/8.4.1/main/index.js
522
+ app.get(`/${eik.prop.base_npm}/@:scope/:name/:version/*`, pkgGetRoute);
523
+
524
+ // Get public NPM package - non-scoped
525
+ // curl -X GET http://localhost:4001/npm/fuzz/8.4.1/main/index.js
526
+ app.get(`/${eik.prop.base_npm}/:name/:version/*`, pkgGetRoute);
527
+
528
+ // Get NPM package overview - scoped
529
+ // curl -X GET http://localhost:4001/npm/@cuz/fuzz/8.4.1/
530
+ app.get(`/${eik.prop.base_npm}/@:scope/:name/:version`, pkgLogRoute);
531
+
532
+ // Get NPM package overview - non-scoped
533
+ // curl -X GET http://localhost:4001/npm/fuzz/8.4.1/
534
+ app.get(`/${eik.prop.base_npm}/:name/:version`, pkgLogRoute);
535
+
536
+ // Get NPM package versions - scoped
537
+ // curl -X GET http://localhost:4001/npm/@cuz/fuzz/
538
+ app.get(`/${eik.prop.base_npm}/@:scope/:name`, versionsGetRoute);
539
+
540
+ // Get NPM package versions - non-scoped
541
+ // curl -X GET http://localhost:4001/npm/fuzz/
542
+ app.get(`/${eik.prop.base_npm}/:name`, versionsGetRoute);
543
+
544
+ // Put NPM package - scoped
545
+ // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/npm/@cuz/fuzz/8.4.1/
546
+ app.put(
547
+ `/${eik.prop.base_npm}/@:scope/:name/:version`,
548
+ authOptions,
549
+ pkgPutRoute,
550
+ );
551
+
552
+ // Put NPM package - non-scoped
553
+ // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/npm/fuzz/8.4.1/
554
+ app.put(`/${eik.prop.base_npm}/:name/:version`, authOptions, pkgPutRoute);
555
+
556
+ //
557
+ // Image Packages
558
+ //
559
+
560
+ // Get public IMG package - scoped
561
+ // curl -X GET http://localhost:4001/img/@cuz/fuzz/8.4.1/main/picture.jpg
562
+ app.get(`/${eik.prop.base_img}/@:scope/:name/:version/*`, pkgGetRoute);
563
+
564
+ // Get public IMG package - non-scoped
565
+ // curl -X GET http://localhost:4001/img/fuzz/8.4.1/main/picture.jpg
566
+ app.get(`/${eik.prop.base_img}/:name/:version/*`, pkgGetRoute);
567
+
568
+ // Get IMG package overview - scoped
569
+ // curl -X GET http://localhost:4001/img/@cuz/fuzz/8.4.1/
570
+ app.get(`/${eik.prop.base_img}/@:scope/:name/:version`, pkgLogRoute);
571
+
572
+ // Get IMG package overview - non-scoped
573
+ // curl -X GET http://localhost:4001/img/fuzz/8.4.1/
574
+ app.get(`/${eik.prop.base_img}/:name/:version`, pkgLogRoute);
575
+
576
+ // Get IMG package versions - scoped
577
+ // curl -X GET http://localhost:4001/img/@cuz/fuzz/
578
+ app.get(`/${eik.prop.base_img}/@:scope/:name`, versionsGetRoute);
579
+
580
+ // Get IMG package versions - non-scoped
581
+ // curl -X GET http://localhost:4001/img/fuzz/
582
+ app.get(`/${eik.prop.base_img}/:name`, versionsGetRoute);
583
+
584
+ // Put IMG package - scoped
585
+ // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/img/@cuz/fuzz/8.4.1/
586
+ app.put(
587
+ `/${eik.prop.base_img}/@:scope/:name/:version`,
588
+ authOptions,
589
+ imgPutRoute,
590
+ );
591
+
592
+ // Put IMG package - non-scoped
593
+ // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/img/fuzz/8.4.1/
594
+ app.put(`/${eik.prop.base_img}/:name/:version`, authOptions, imgPutRoute);
595
+
596
+ //
597
+ // Import Maps
598
+ //
599
+
600
+ // Get map - scoped
601
+ // curl -X GET http://localhost:4001/map/@cuz/buzz/4.2.2
602
+ app.get(`/${eik.prop.base_map}/@:scope/:name/:version`, mapGetRoute);
603
+
604
+ // Get map - non-scoped
605
+ // curl -X GET http://localhost:4001/map/buzz/4.2.2
606
+ app.get(`/${eik.prop.base_map}/:name/:version`, mapGetRoute);
607
+
608
+ // Get map versions - scoped
609
+ // curl -X GET http://localhost:4001/map/@cuz/buzz
610
+ app.get(`/${eik.prop.base_map}/@:scope/:name`, versionsGetRoute);
611
+
612
+ // Get map versions - non-scoped
613
+ // curl -X GET http://localhost:4001/map/buzz
614
+ app.get(`/${eik.prop.base_map}/:name`, versionsGetRoute);
615
+
616
+ // Put map - scoped
617
+ // curl -X PUT -i -F map=@import-map.json http://localhost:4001/map/@cuz/buzz/4.2.2
618
+ app.put(
619
+ `/${eik.prop.base_map}/@:scope/:name/:version`,
620
+ authOptions,
621
+ mapPutRoute,
622
+ );
623
+
624
+ // Put map - non-scoped
625
+ // curl -X PUT -i -F map=@import-map.json http://localhost:4001/map/buzz/4.2.2
626
+ app.put(`/${eik.prop.base_map}/:name/:version`, authOptions, mapPutRoute);
627
+
628
+ //
629
+ // Alias Packages
630
+ //
631
+
632
+ // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/v8
633
+ app.get(`/${eik.prop.base_pkg}/@:scope/:name/v:alias`, aliasGetRoute);
634
+
635
+ // curl -X GET -L http://localhost:4001/pkg/fuzz/v8
636
+ app.get(`/${eik.prop.base_pkg}/:name/v:alias`, aliasGetRoute);
637
+
638
+ // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/v8/main/index.js
639
+ app.get(`/${eik.prop.base_pkg}/@:scope/:name/v:alias/*`, aliasGetRoute);
640
+
641
+ // curl -X GET -L http://localhost:4001/pkg/fuzz/v8/main/index.js
642
+ app.get(`/${eik.prop.base_pkg}/:name/v:alias/*`, aliasGetRoute);
643
+
644
+ // curl -X PUT -i -F version=8.4.1 http://localhost:4001/pkg/@cuz/fuzz/v8
645
+ app.put(
646
+ `/${eik.prop.base_pkg}/@:scope/:name/v:alias`,
647
+ authOptions,
648
+ aliasPutRoute,
649
+ );
650
+
651
+ // curl -X PUT -i -F version=8.4.1 http://localhost:4001/pkg/fuzz/v8
652
+ app.put(
653
+ `/${eik.prop.base_pkg}/:name/v:alias`,
654
+ authOptions,
655
+ aliasPutRoute,
656
+ );
657
+
658
+ // curl -X POST -i -F version=8.4.1 http://localhost:4001/pkg/@cuz/lit-html/v8
659
+ app.post(
660
+ `/${eik.prop.base_pkg}/@:scope/:name/v:alias`,
661
+ authOptions,
662
+ aliasPostRoute,
663
+ );
664
+
665
+ // curl -X POST -i -F version=8.4.1 http://localhost:4001/pkg/lit-html/v8
666
+ app.post(
667
+ `/${eik.prop.base_pkg}/:name/v:alias`,
668
+ authOptions,
669
+ aliasPostRoute,
670
+ );
671
+
672
+ // curl -X DELETE http://localhost:4001/pkg/@cuz/fuzz/v8
673
+ app.delete(
674
+ `/${eik.prop.base_pkg}/@:scope/:name/v:alias`,
675
+ authOptions,
676
+ aliasDelRoute,
677
+ );
678
+
679
+ // curl -X DELETE http://localhost:4001/pkg/fuzz/v8
680
+ app.delete(
681
+ `/${eik.prop.base_pkg}/:name/v:alias`,
682
+ authOptions,
683
+ aliasDelRoute,
684
+ );
685
+
686
+ //
687
+ // Alias NPM Packages
688
+ //
689
+
690
+ // curl -X GET -L http://localhost:4001/npm/@cuz/fuzz/v8
691
+ app.get(`/${eik.prop.base_npm}/@:scope/:name/v:alias`, aliasGetRoute);
692
+
693
+ // curl -X GET -L http://localhost:4001/npm/fuzz/v8
694
+ app.get(`/${eik.prop.base_npm}/:name/v:alias`, aliasGetRoute);
695
+
696
+ // curl -X GET -L http://localhost:4001/npm/@cuz/fuzz/v8/main/index.js
697
+ app.get(`/${eik.prop.base_npm}/@:scope/:name/v:alias/*`, aliasGetRoute);
698
+
699
+ // curl -X GET -L http://localhost:4001/npm/fuzz/v8/main/index.js
700
+ app.get(`/${eik.prop.base_npm}/:name/v:alias/*`, aliasGetRoute);
701
+
702
+ // curl -X PUT -i -F version=8.4.1 http://localhost:4001/npm/@cuz/fuzz/v8
703
+ app.put(
704
+ `/${eik.prop.base_npm}/@:scope/:name/v:alias`,
705
+ authOptions,
706
+ aliasPutRoute,
707
+ );
708
+
709
+ // curl -X PUT -i -F version=8.4.1 http://localhost:4001/npm/fuzz/v8
710
+ app.put(
711
+ `/${eik.prop.base_npm}/:name/v:alias`,
712
+ authOptions,
713
+ aliasPutRoute,
714
+ );
715
+
716
+ // curl -X POST -i -F version=8.4.1 http://localhost:4001/npm/@cuz/lit-html/v8
717
+ app.post(
718
+ `/${eik.prop.base_npm}/@:scope/:name/v:alias`,
719
+ authOptions,
720
+ aliasPostRoute,
721
+ );
722
+
723
+ // curl -X POST -i -F version=8.4.1 http://localhost:4001/npm/lit-html/v8
724
+ app.post(
725
+ `/${eik.prop.base_npm}/:name/v:alias`,
726
+ authOptions,
727
+ aliasPostRoute,
728
+ );
729
+
730
+ // curl -X DELETE http://localhost:4001/npm/@cuz/fuzz/v8
731
+ app.delete(
732
+ `/${eik.prop.base_npm}/@:scope/:name/v:alias`,
733
+ authOptions,
734
+ aliasDelRoute,
735
+ );
736
+
737
+ // curl -X DELETE http://localhost:4001/npm/fuzz/v8
738
+ app.delete(
739
+ `/${eik.prop.base_npm}/:name/v:alias`,
740
+ authOptions,
741
+ aliasDelRoute,
742
+ );
743
+
744
+ //
745
+ // Alias Image Packages
746
+ //
747
+
748
+ // curl -X GET -L http://localhost:4001/img/@cuz/fuzz/v8
749
+ app.get(`/${eik.prop.base_img}/@:scope/:name/v:alias`, aliasGetRoute);
750
+
751
+ // curl -X GET -L http://localhost:4001/img/fuzz/v8
752
+ app.get(`/${eik.prop.base_img}/:name/v:alias`, aliasGetRoute);
753
+
754
+ // curl -X GET -L http://localhost:4001/img/@cuz/fuzz/v8/main/index.js
755
+ app.get(`/${eik.prop.base_img}/@:scope/:name/v:alias/*`, aliasGetRoute);
756
+
757
+ // curl -X GET -L http://localhost:4001/img/fuzz/v8/main/index.js
758
+ app.get(`/${eik.prop.base_img}/:name/v:alias/*`, aliasGetRoute);
759
+
760
+ // curl -X PUT -i -F version=8.4.1 http://localhost:4001/img/@cuz/fuzz/v8
761
+ app.put(
762
+ `/${eik.prop.base_img}/@:scope/:name/v:alias`,
763
+ authOptions,
764
+ aliasPutRoute,
765
+ );
766
+
767
+ // curl -X PUT -i -F version=8.4.1 http://localhost:4001/img/fuzz/v8
768
+ app.put(
769
+ `/${eik.prop.base_img}/:name/v:alias`,
770
+ authOptions,
771
+ aliasPutRoute,
772
+ );
773
+
774
+ // curl -X POST -i -F version=8.4.1 http://localhost:4001/img/@cuz/lit-html/v8
775
+ app.post(
776
+ `/${eik.prop.base_img}/@:scope/:name/v:alias`,
777
+ authOptions,
778
+ aliasPostRoute,
779
+ );
780
+
781
+ // curl -X POST -i -F version=8.4.1 http://localhost:4001/img/lit-html/v8
782
+ app.post(
783
+ `/${eik.prop.base_img}/:name/v:alias`,
784
+ authOptions,
785
+ aliasPostRoute,
786
+ );
787
+
788
+ // curl -X DELETE http://localhost:4001/img/@cuz/fuzz/v8
789
+ app.delete(
790
+ `/${eik.prop.base_img}/@:scope/:name/v:alias`,
791
+ authOptions,
792
+ aliasDelRoute,
793
+ );
794
+
795
+ // curl -X DELETE http://localhost:4001/img/fuzz/v8
796
+ app.delete(
797
+ `/${eik.prop.base_img}/:name/v:alias`,
798
+ authOptions,
799
+ aliasDelRoute,
800
+ );
801
+
802
+ //
803
+ // Alias Import Maps
804
+ //
805
+
806
+ // curl -X GET -L http://localhost:4001/map/@cuz/buzz/v4
807
+ app.get(`/${eik.prop.base_map}/@:scope/:name/v:alias`, aliasGetRoute);
808
+
809
+ // curl -X GET -L http://localhost:4001/map/buzz/v4
810
+ app.get(`/${eik.prop.base_map}/:name/v:alias`, aliasGetRoute);
811
+
812
+ // curl -X PUT -i -F version=4.2.2 http://localhost:4001/map/@cuz/buzz/v4
813
+ app.put(
814
+ `/${eik.prop.base_map}/@:scope/:name/v:alias`,
815
+ authOptions,
816
+ aliasPutRoute,
817
+ );
818
+
819
+ // curl -X PUT -i -F version=4.2.2 http://localhost:4001/map/buzz/v4
820
+ app.put(
821
+ `/${eik.prop.base_map}/:name/v:alias`,
822
+ authOptions,
823
+ aliasPutRoute,
824
+ );
825
+
826
+ // curl -X POST -i -F version=4.4.2 http://localhost:4001/map/@cuz/buzz/v4
827
+ app.post(
828
+ `/${eik.prop.base_map}/@:scope/:name/v:alias`,
829
+ authOptions,
830
+ aliasPostRoute,
831
+ );
832
+
833
+ // curl -X POST -i -F version=4.4.2 http://localhost:4001/map/buzz/v4
834
+ app.post(
835
+ `/${eik.prop.base_map}/:name/v:alias`,
836
+ authOptions,
837
+ aliasPostRoute,
838
+ );
839
+
840
+ // curl -X DELETE http://localhost:4001/map/@cuz/buzz/v4
841
+ app.delete(
842
+ `/${eik.prop.base_map}/@:scope/:name/v:alias`,
843
+ authOptions,
844
+ aliasDelRoute,
845
+ );
846
+
847
+ // curl -X DELETE http://localhost:4001/map/buzz/v4
848
+ app.delete(
849
+ `/${eik.prop.base_map}/:name/v:alias`,
850
+ authOptions,
851
+ aliasDelRoute,
852
+ );
853
+ };
854
+ }
912
855
  };
913
856
 
914
857
  export default EikService;