diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index ed9f9cc1..00000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -coverage \ No newline at end of file diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 9d9c25e7..00000000 --- a/.eslintrc +++ /dev/null @@ -1,19 +0,0 @@ -{ - "parser": "@babel/eslint-parser", - "extends": ["airbnb-base", "prettier"], - "plugins": ["prettier"], - "parserOptions": { - "ecmaVersion": 11, - "sourceType": "module", - "requireConfigFile": false - }, - "rules": { - "import/prefer-default-export": "off", - "import/extensions": ["error", { - "js": "ignorePackages" - } - ], - "no-underscore-dangle": [0], - "no-restricted-syntax": [0] - } -} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0051c012..b6105cd8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,25 +12,21 @@ jobs: test: runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 + - uses: actions/setup-node@v4 with: node-version: 20 - - name: Install dependencies - run: npm install + - run: npm install - - name: Lint files - run: npm run lint + - run: npm run lint - - name: Run tests - run: npm run test + - run: npm run types - - name: Run semantic release - run: npx semantic-release + - run: npm run test + + - run: npx semantic-release env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 07303f91..83fe2717 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,8 +19,7 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -28,4 +27,6 @@ jobs: - run: npm run lint + - run: npm run types + - run: npm test diff --git a/.gitignore b/.gitignore index 5f79d76c..4a108a93 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ coverage .vscode .nyc_output/ .tap/ +types/ diff --git a/bin/eik-server.js b/bin/eik-server.js index 6951a5ee..2a041c62 100644 --- a/bin/eik-server.js +++ b/bin/eik-server.js @@ -1,6 +1,6 @@ #!/usr/bin/env node - -import Fastify from 'fastify' +/* eslint-disable no-unused-vars */ +import Fastify from 'fastify'; import Eik from '../lib/main.js'; const eik = new Eik(); @@ -22,5 +22,5 @@ try { await app.listen({ port: eik.config.get('http.port'), - host: eik.config.get('http.address') + host: eik.config.get('http.address'), }); diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..3eae3e6b --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,3 @@ +import config from '@eik/eslint-config'; + +export default config; diff --git a/lib/config.js b/lib/config.js index 8198657e..a1b8c095 100644 --- a/lib/config.js +++ b/lib/config.js @@ -1,3 +1,4 @@ +/* eslint-disable no-unused-vars */ import convict from 'convict'; import yaml from 'js-yaml'; import pino from 'pino'; @@ -9,7 +10,7 @@ const CWD = process.cwd(); let pack = {}; try { - pack = JSON.parse(fs.readFileSync(join(CWD, 'package.json'))); + pack = JSON.parse(fs.readFileSync(join(CWD, 'package.json'), 'utf-8')); } catch (error) { /* empty */ } @@ -29,11 +30,13 @@ convict.addFormat({ const file = fs.readFileSync(value); return file.toString(); } catch (error) { - throw new Error(`Config could not load secret from path: ${value}`); + throw new Error( + `Config could not load secret from path: ${value}`, + ); } } return value; - } + }, }); const conf = convict({ @@ -148,11 +151,12 @@ const conf = convict({ default: path.join(os.tmpdir(), '/eik'), env: 'SINK_PATH', }, - } + }, }); const env = conf.get('env'); +// @ts-expect-error This is in fact callable const logger = pino({ level: conf.get('log.level'), name: conf.get('name'), diff --git a/lib/main.js b/lib/main.js index 3714cfde..e0a53c64 100644 --- a/lib/main.js +++ b/lib/main.js @@ -8,7 +8,6 @@ import eik from '@eik/core'; import SinkMemory from '@eik/sink-memory'; import SinkFileSystem from '@eik/sink-file-system'; - import config from './config.js'; import * as utils from './utils.js'; @@ -27,14 +26,12 @@ const EikService = class EikService { */ constructor(options = {}) { let { sink, logger } = options; - const { - customSink, - notFoundCacheControl, - aliasCacheControl, - } = options; - this._notFoundCacheControl = notFoundCacheControl || 'public, max-age=5'; + const { customSink, notFoundCacheControl, aliasCacheControl } = options; + this._notFoundCacheControl = + notFoundCacheControl || 'public, max-age=5'; if (!logger) { + // @ts-expect-error This is in fact callable logger = pino({ // @ts-ignore level: config.get('log.level'), @@ -45,25 +42,52 @@ const EikService = class EikService { if (sink) { logger.info(`Using the provided sink ${sink.constructor.name}`); } else if (customSink) { - logger.warn('The `customSink` option is deprecated and will be removed at a later stage. Use `sink` to remove this warning.'); + logger.warn( + 'The `customSink` option is deprecated and will be removed at a later stage. Use `sink` to remove this warning.', + ); sink = customSink; } else if (config.get('sink.type') === 'mem') { - logger.info(`Server is running with a in memory sink. Uploaded files will be lost on restart!`); + logger.info( + `Server is running with a in memory sink. Uploaded files will be lost on restart!`, + ); sink = new SinkMemory(); } else { - logger.info(`Server is running with the file system sink. Uploaded files will be stored under "${config.get('sink.path')}"`); - sink = new SinkFileSystem({ sinkFsRootPath: config.get('sink.path') }); + logger.info( + `Server is running with the file system sink. Uploaded files will be stored under "${config.get('sink.path')}"`, + ); + sink = new SinkFileSystem({ + sinkFsRootPath: config.get('sink.path'), + }); } // Transform organization config - const organizations = config.get('organization.hostnames').map((hostname) => [hostname, config.get('organization.name')]); - - this._versionsGet = new eik.http.VersionsGet({ organizations, sink, logger }); - this._aliasPost = new eik.http.AliasPost({ organizations, sink, logger }); + const organizations = config + .get('organization.hostnames') + .map((hostname) => [hostname, config.get('organization.name')]); + + this._versionsGet = new eik.http.VersionsGet({ + organizations, + sink, + logger, + }); + this._aliasPost = new eik.http.AliasPost({ + organizations, + sink, + logger, + }); this._aliasDel = new eik.http.AliasDel({ organizations, sink, logger }); - this._aliasGet = new eik.http.AliasGet({ organizations, sink, logger, cacheControl: aliasCacheControl }); + this._aliasGet = new eik.http.AliasGet({ + organizations, + sink, + logger, + cacheControl: aliasCacheControl, + }); this._aliasPut = new eik.http.AliasPut({ organizations, sink, logger }); - this._authPost = new eik.http.AuthPost({ organizations, logger, authKey: config.get('basicAuth.key') }); + this._authPost = new eik.http.AuthPost({ + organizations, + logger, + authKey: config.get('basicAuth.key'), + }); this._pkgLog = new eik.http.PkgLog({ organizations, sink, logger }); this._pkgGet = new eik.http.PkgGet({ organizations, sink, logger }); this._pkgPut = new eik.http.PkgPut({ organizations, sink, logger }); @@ -84,7 +108,7 @@ const EikService = class EikService { }); for (const stm of streams) { - stm.on('error', err => { + stm.on('error', (err) => { logger.error(err); }); stm.pipe(str); @@ -108,7 +132,7 @@ const EikService = class EikService { sink.metrics, ); - metrics.on('error', err => { + metrics.on('error', (err) => { logger.error(err); }); @@ -119,18 +143,27 @@ const EikService = class EikService { // Print warnings - if (config.get('basicAuth.type') === 'key' && config.get('basicAuth.key') === config.default('basicAuth.key')) { - logger.warn('Server is running with default basic authorization key configured! For security purposes, it is highly recommended to set a custom value!') + if ( + config.get('basicAuth.type') === 'key' && + config.get('basicAuth.key') === config.default('basicAuth.key') + ) { + logger.warn( + 'Server is running with default basic authorization key configured! For security purposes, it is highly recommended to set a custom value!', + ); } if (config.get('jwt.secret') === config.default('jwt.secret')) { - logger.warn('Server is running with default jwt secret configured! For security purposes, it is highly recommended to set a custom value!') + logger.warn( + 'Server is running with default jwt secret configured! For security purposes, it is highly recommended to set a custom value!', + ); } // Print info const hosts = config.get('organization.hostnames').join(', '); - logger.info(`Files for "${hosts}" will be stored in the "${config.get('organization.name')}" organization space`); + logger.info( + `Files for "${hosts}" will be stored in the "${config.get('organization.name')}" organization space`, + ); } async health() { @@ -144,7 +177,9 @@ const EikService = class EikService { api() { return (app, options, done) => { if (!app.initialConfig.ignoreTrailingSlash) { - this.logger.warn('Fastify is configured with "ignoreTrailingSlash" set to "false". Its adviced to set "ignoreTrailingSlash" to "true"'); + this.logger.warn( + 'Fastify is configured with "ignoreTrailingSlash" set to "false". Its adviced to set "ignoreTrailingSlash" to "true"', + ); } app.register(cors); @@ -153,24 +188,27 @@ const EikService = class EikService { app.register(jwt, { secret: config.get('jwt.secret'), messages: { - badRequestErrorMessage: 'Autorization header is malformatted. Format is "Authorization: Bearer [token]"', - noAuthorizationInHeaderMessage: 'Autorization header is missing!', - authorizationTokenExpiredMessage: 'Authorization token expired', - authorizationTokenInvalid: 'Authorization token is invalid' - } + badRequestErrorMessage: + 'Autorization header is malformatted. Format is "Authorization: Bearer [token]"', + noAuthorizationInHeaderMessage: + 'Autorization header is missing!', + authorizationTokenExpiredMessage: + 'Authorization token expired', + authorizationTokenInvalid: 'Authorization token is invalid', + }, }); app.decorate('authenticate', async (request, reply) => { try { - await request.jwtVerify() + await request.jwtVerify(); } catch (error) { - reply.send(error) + reply.send(error); } }); const authOptions = { - preValidation: [app.authenticate] - } + preValidation: [app.authenticate], + }; // Handle multipart upload const _multipart = Symbol('multipart'); @@ -188,15 +226,17 @@ const EikService = class EikService { // 404 handling app.setNotFoundHandler((request, reply) => { - reply.header('cache-control', this._notFoundCacheControl); - reply.type('text/plain'); - reply.code(404); - reply.send('Not found'); + reply.header('cache-control', this._notFoundCacheControl); + reply.type('text/plain'); + reply.code(404); + reply.send('Not found'); }); // Error handling app.setErrorHandler((error, request, reply) => { - this.logger.debug('Error occured during request. Error is available on trace log level.'); + this.logger.debug( + 'Error occured during request. Error is available on trace log level.', + ); this.logger.trace(error); reply.header('cache-control', 'no-store'); if (error.statusCode) { @@ -212,15 +252,12 @@ const EikService = class EikService { reply.send(createError(error.statusCode || 500)); }); - // // Routes // const authPostRoutes = async (request, reply) => { - const outgoing = await this._authPost.handler( - request.raw, - ); + const outgoing = await this._authPost.handler(request.raw); // Workaround due to .jwt.sign() being able to only // deal with object literals for some reason :/ @@ -324,7 +361,6 @@ const EikService = class EikService { reply.redirect(outgoing.location); }; - const aliasGetRoute = async (request, reply) => { const params = utils.sanitizeParameters(request.raw.url); const outgoing = await this._aliasGet.handler( @@ -385,7 +421,6 @@ const EikService = class EikService { reply.send(outgoing.body); }; - // // Authentication // @@ -394,14 +429,16 @@ const EikService = class EikService { app.post(`/${eik.prop.base_auth}/login`, authPostRoutes); - // // Packages // // Get public package - scoped // curl -X GET http://localhost:4001/pkg/@cuz/fuzz/8.4.1/main/index.js - app.get(`/${eik.prop.base_pkg}/@:scope/:name/:version/*`, pkgGetRoute); + app.get( + `/${eik.prop.base_pkg}/@:scope/:name/:version/*`, + pkgGetRoute, + ); // Get public package - non-scoped // curl -X GET http://localhost:4001/pkg/fuzz/8.4.1/main/index.js @@ -409,7 +446,10 @@ const EikService = class EikService { // Get package overview - scoped // curl -X GET http://localhost:4001/pkg/@cuz/fuzz/8.4.1/ - app.get(`/${eik.prop.base_pkg}/@:scope/:name/:version`, pkgLogRoute); + app.get( + `/${eik.prop.base_pkg}/@:scope/:name/:version`, + pkgLogRoute, + ); // Get package overview - non-scoped // curl -X GET http://localhost:4001/pkg/fuzz/8.4.1/ @@ -425,12 +465,19 @@ const EikService = class EikService { // Put package - scoped // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/pkg/@cuz/fuzz/8.4.1/ - app.put(`/${eik.prop.base_pkg}/@:scope/:name/:version`, authOptions, pkgPutRoute); + app.put( + `/${eik.prop.base_pkg}/@:scope/:name/:version`, + authOptions, + pkgPutRoute, + ); // Put package - non-scoped // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/pkg/fuzz/8.4.1/ - app.put(`/${eik.prop.base_pkg}/:name/:version`, authOptions, pkgPutRoute); - + app.put( + `/${eik.prop.base_pkg}/:name/:version`, + authOptions, + pkgPutRoute, + ); // // NPM Packages @@ -438,7 +485,10 @@ const EikService = class EikService { // Get public NPM package - scoped // curl -X GET http://localhost:4001/npm/@cuz/fuzz/8.4.1/main/index.js - app.get(`/${eik.prop.base_npm}/@:scope/:name/:version/*`, pkgGetRoute); + app.get( + `/${eik.prop.base_npm}/@:scope/:name/:version/*`, + pkgGetRoute, + ); // Get public NPM package - non-scoped // curl -X GET http://localhost:4001/npm/fuzz/8.4.1/main/index.js @@ -446,7 +496,10 @@ const EikService = class EikService { // Get NPM package overview - scoped // curl -X GET http://localhost:4001/npm/@cuz/fuzz/8.4.1/ - app.get(`/${eik.prop.base_npm}/@:scope/:name/:version`, pkgLogRoute); + app.get( + `/${eik.prop.base_npm}/@:scope/:name/:version`, + pkgLogRoute, + ); // Get NPM package overview - non-scoped // curl -X GET http://localhost:4001/npm/fuzz/8.4.1/ @@ -462,12 +515,19 @@ const EikService = class EikService { // Put NPM package - scoped // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/npm/@cuz/fuzz/8.4.1/ - app.put(`/${eik.prop.base_npm}/@:scope/:name/:version`, authOptions, pkgPutRoute); + app.put( + `/${eik.prop.base_npm}/@:scope/:name/:version`, + authOptions, + pkgPutRoute, + ); // Put NPM package - non-scoped // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/npm/fuzz/8.4.1/ - app.put(`/${eik.prop.base_npm}/:name/:version`, authOptions, pkgPutRoute); - + app.put( + `/${eik.prop.base_npm}/:name/:version`, + authOptions, + pkgPutRoute, + ); // // Import Maps @@ -475,7 +535,10 @@ const EikService = class EikService { // Get map - scoped // curl -X GET http://localhost:4001/map/@cuz/buzz/4.2.2 - app.get(`/${eik.prop.base_map}/@:scope/:name/:version`, mapGetRoute); + app.get( + `/${eik.prop.base_map}/@:scope/:name/:version`, + mapGetRoute, + ); // Get map - non-scoped // curl -X GET http://localhost:4001/map/buzz/4.2.2 @@ -491,114 +554,205 @@ const EikService = class EikService { // Put map - scoped // curl -X PUT -i -F map=@import-map.json http://localhost:4001/map/@cuz/buzz/4.2.2 - app.put(`/${eik.prop.base_map}/@:scope/:name/:version`, authOptions, mapPutRoute); + app.put( + `/${eik.prop.base_map}/@:scope/:name/:version`, + authOptions, + mapPutRoute, + ); // Put map - non-scoped // curl -X PUT -i -F map=@import-map.json http://localhost:4001/map/buzz/4.2.2 - app.put(`/${eik.prop.base_map}/:name/:version`, authOptions, mapPutRoute); - + app.put( + `/${eik.prop.base_map}/:name/:version`, + authOptions, + mapPutRoute, + ); // // Alias Packages // // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/v8 - app.get(`/${eik.prop.base_pkg}/@:scope/:name/v:alias`, aliasGetRoute); + app.get( + `/${eik.prop.base_pkg}/@:scope/:name/v:alias`, + aliasGetRoute, + ); // curl -X GET -L http://localhost:4001/pkg/fuzz/v8 app.get(`/${eik.prop.base_pkg}/:name/v:alias`, aliasGetRoute); // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/v8/main/index.js - app.get(`/${eik.prop.base_pkg}/@:scope/:name/v:alias/*`, aliasGetRoute); + app.get( + `/${eik.prop.base_pkg}/@:scope/:name/v:alias/*`, + aliasGetRoute, + ); // curl -X GET -L http://localhost:4001/pkg/fuzz/v8/main/index.js app.get(`/${eik.prop.base_pkg}/:name/v:alias/*`, aliasGetRoute); // curl -X PUT -i -F version=8.4.1 http://localhost:4001/pkg/@cuz/fuzz/v8 - app.put(`/${eik.prop.base_pkg}/@:scope/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_pkg}/@:scope/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X PUT -i -F version=8.4.1 http://localhost:4001/pkg/fuzz/v8 - app.put(`/${eik.prop.base_pkg}/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_pkg}/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X POST -i -F version=8.4.1 http://localhost:4001/pkg/@cuz/lit-html/v8 - app.post(`/${eik.prop.base_pkg}/@:scope/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_pkg}/@:scope/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X POST -i -F version=8.4.1 http://localhost:4001/pkg/lit-html/v8 - app.post(`/${eik.prop.base_pkg}/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_pkg}/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X DELETE http://localhost:4001/pkg/@cuz/fuzz/v8 - app.delete(`/${eik.prop.base_pkg}/@:scope/:name/v:alias`, authOptions, aliasDelRoute); + app.delete( + `/${eik.prop.base_pkg}/@:scope/:name/v:alias`, + authOptions, + aliasDelRoute, + ); // curl -X DELETE http://localhost:4001/pkg/fuzz/v8 - app.delete(`/${eik.prop.base_pkg}/:name/v:alias`, authOptions, aliasDelRoute); - + app.delete( + `/${eik.prop.base_pkg}/:name/v:alias`, + authOptions, + aliasDelRoute, + ); // // Alias NPM Packages // // curl -X GET -L http://localhost:4001/npm/@cuz/fuzz/v8 - app.get(`/${eik.prop.base_npm}/@:scope/:name/v:alias`, aliasGetRoute); + app.get( + `/${eik.prop.base_npm}/@:scope/:name/v:alias`, + aliasGetRoute, + ); // curl -X GET -L http://localhost:4001/npm/fuzz/v8 app.get(`/${eik.prop.base_npm}/:name/v:alias`, aliasGetRoute); // curl -X GET -L http://localhost:4001/npm/@cuz/fuzz/v8/main/index.js - app.get(`/${eik.prop.base_npm}/@:scope/:name/v:alias/*`, aliasGetRoute); + app.get( + `/${eik.prop.base_npm}/@:scope/:name/v:alias/*`, + aliasGetRoute, + ); // curl -X GET -L http://localhost:4001/npm/fuzz/v8/main/index.js app.get(`/${eik.prop.base_npm}/:name/v:alias/*`, aliasGetRoute); // curl -X PUT -i -F version=8.4.1 http://localhost:4001/npm/@cuz/fuzz/v8 - app.put(`/${eik.prop.base_npm}/@:scope/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_npm}/@:scope/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X PUT -i -F version=8.4.1 http://localhost:4001/npm/fuzz/v8 - app.put(`/${eik.prop.base_npm}/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_npm}/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X POST -i -F version=8.4.1 http://localhost:4001/npm/@cuz/lit-html/v8 - app.post(`/${eik.prop.base_npm}/@:scope/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_npm}/@:scope/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X POST -i -F version=8.4.1 http://localhost:4001/npm/lit-html/v8 - app.post(`/${eik.prop.base_npm}/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_npm}/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X DELETE http://localhost:4001/npm/@cuz/fuzz/v8 - app.delete(`/${eik.prop.base_npm}/@:scope/:name/v:alias`, authOptions, aliasDelRoute); + app.delete( + `/${eik.prop.base_npm}/@:scope/:name/v:alias`, + authOptions, + aliasDelRoute, + ); // curl -X DELETE http://localhost:4001/npm/fuzz/v8 - app.delete(`/${eik.prop.base_npm}/:name/v:alias`, authOptions, aliasDelRoute); - + app.delete( + `/${eik.prop.base_npm}/:name/v:alias`, + authOptions, + aliasDelRoute, + ); // // Alias Import Maps // // curl -X GET -L http://localhost:4001/map/@cuz/buzz/v4 - app.get(`/${eik.prop.base_map}/@:scope/:name/v:alias`, aliasGetRoute); + app.get( + `/${eik.prop.base_map}/@:scope/:name/v:alias`, + aliasGetRoute, + ); // curl -X GET -L http://localhost:4001/map/buzz/v4 app.get(`/${eik.prop.base_map}/:name/v:alias`, aliasGetRoute); // curl -X PUT -i -F version=4.2.2 http://localhost:4001/map/@cuz/buzz/v4 - app.put(`/${eik.prop.base_map}/@:scope/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_map}/@:scope/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X PUT -i -F version=4.2.2 http://localhost:4001/map/buzz/v4 - app.put(`/${eik.prop.base_map}/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_map}/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X POST -i -F version=4.4.2 http://localhost:4001/map/@cuz/buzz/v4 - app.post(`/${eik.prop.base_map}/@:scope/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_map}/@:scope/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X POST -i -F version=4.4.2 http://localhost:4001/map/buzz/v4 - app.post(`/${eik.prop.base_map}/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_map}/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X DELETE http://localhost:4001/map/@cuz/buzz/v4 - app.delete(`/${eik.prop.base_map}/@:scope/:name/v:alias`, authOptions, aliasDelRoute); + app.delete( + `/${eik.prop.base_map}/@:scope/:name/v:alias`, + authOptions, + aliasDelRoute, + ); // curl -X DELETE http://localhost:4001/map/buzz/v4 - app.delete(`/${eik.prop.base_map}/:name/v:alias`, authOptions, aliasDelRoute); - + app.delete( + `/${eik.prop.base_map}/:name/v:alias`, + authOptions, + aliasDelRoute, + ); done(); - } + }; } }; diff --git a/lib/utils.js b/lib/utils.js index 624d7988..00ea6cac 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -44,9 +44,4 @@ const sanitizeParameters = (url = '') => { }; }; -export { - sanitizeParameters, - sanitizeExtras, - sanitizeAlias, - sanitizeName, -} +export { sanitizeParameters, sanitizeExtras, sanitizeAlias, sanitizeName }; diff --git a/package.json b/package.json index 7be5a13b..c3903d74 100644 --- a/package.json +++ b/package.json @@ -4,23 +4,28 @@ "description": "Eik REST API as a standalone HTTP service", "type": "module", "main": "./lib/main.js", + "types": "./types/main.d.ts", "bin": { "eik-server": "bin/eik-server.js", "eik-service": "bin/eik-server.js", "service": "bin/eik-server.js" }, "scripts": { + "lint": "eslint .", + "lint:fix": "eslint --fix .", "start": "node ./bin/eik-server.js | pino-pretty", "test": "cross-env LOG_LEVEL=fatal tap ./test --disable-coverage --allow-empty-coverage --serial=test", "test:snapshots": "cross-env LOG_LEVEL=fatal tap --snapshot --disable-coverage --allow-empty-coverage --serial=test", - "lint:fix": "eslint --fix .", - "lint": "eslint ." + "types": "run-s types:module types:test", + "types:module": "tsc", + "types:test": "tsc --project tsconfig.test.json" }, "files": [ "CHANGELOG.md", "package.json", "lib", - "bin" + "bin", + "types" ], "repository": { "type": "git", @@ -47,21 +52,20 @@ "pino": "8.21.0" }, "devDependencies": { - "@babel/eslint-parser": "7.25.1", - "@semantic-release/changelog": "6.0.3", - "@semantic-release/git": "10.0.1", - "cross-env": "^7.0.3", - "eslint": "8.57.0", - "eslint-config-airbnb-base": "15.0.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-import": "2.29.1", - "eslint-plugin-prettier": "5.2.1", + "@eik/eslint-config": "1.0.2", + "@eik/prettier-config": "1.0.1", + "@eik/semantic-release-config": "1.0.0", + "@eik/typescript-config": "1.0.0", + "cross-env": "7.0.3", + "eslint": "9.8.0", "form-data": "4.0.0", "node-fetch": "3.3.1", + "npm-run-all": "4.1.5", "pino-pretty": "10.3.1", "prettier": "3.3.3", - "semantic-release": "23.1.1", + "semantic-release": "24.0.0", "tap": "18.8.0", + "typescript": "5.5.4", "unique-slug": "4.0.0" } } diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 00000000..bf8643f8 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,3 @@ +import config from '@eik/prettier-config'; + +export default config; diff --git a/release.config.cjs b/release.config.cjs deleted file mode 100644 index c6a260da..00000000 --- a/release.config.cjs +++ /dev/null @@ -1,27 +0,0 @@ -module.exports = { - plugins: [ - '@semantic-release/commit-analyzer', - '@semantic-release/release-notes-generator', - '@semantic-release/changelog', - [ - '@semantic-release/npm', - { - tarballDir: 'release', - }, - ], - [ - '@semantic-release/github', - { - assets: 'release/*.tgz', - }, - ], - '@semantic-release/git', - ], - preset: 'angular', - branches: [ - { name: 'main' }, - { name: 'alpha', prerelease: true }, - { name: 'beta', prerelease: true }, - { name: 'next', prerelease: true }, - ], -}; diff --git a/release.config.js b/release.config.js new file mode 100644 index 00000000..720c8885 --- /dev/null +++ b/release.config.js @@ -0,0 +1,3 @@ +export default { + extends: '@eik/semantic-release-config', +}; diff --git a/test/400.test.js b/test/400.test.js index d7abada1..472fca61 100644 --- a/test/400.test.js +++ b/test/400.test.js @@ -33,7 +33,7 @@ tap.test('400 - GET request with non-existing hostname', async (t) => { headers: formData.getHeaders(), }); - const { token } = await res.json(); + const { token } = /** @type {{ token: string }} */ (await res.json()); formData = new FormData(); formData.append('package', fs.createReadStream(FIXTURE_PKG)); diff --git a/test/404.test.js b/test/404.test.js index b3ee7a3e..6bb4b2ee 100644 --- a/test/404.test.js +++ b/test/404.test.js @@ -3,7 +3,7 @@ import Fastify from 'fastify'; import fetch from 'node-fetch'; import tap from 'tap'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; tap.test('404 - POST request to non existing pathname', async (t) => { @@ -25,9 +25,13 @@ tap.test('404 - POST request to non existing pathname', async (t) => { body: formData, headers: formData.getHeaders(), }); - + t.equal(response.status, 404, 'server should respond with a 404 Not found'); - t.equal(response.headers.get('cache-control'), 'public, max-age=5', 'should contain "cache-control" set to "public, max-age=5"'); + t.equal( + response.headers.get('cache-control'), + 'public, max-age=5', + 'should contain "cache-control" set to "public, max-age=5"', + ); await app.close(); }); @@ -44,9 +48,13 @@ tap.test('404 - GET request to non existing pathname', async (t) => { const address = await app.listen({ port: 0, host: '127.0.0.1' }); const response = await fetch(`${address}/non/existent`); - + t.equal(response.status, 404, 'server should respond with a 404 Not found'); - t.equal(response.headers.get('cache-control'), 'public, max-age=5', 'should contain "cache-control" set to "public, max-age=5"'); + t.equal( + response.headers.get('cache-control'), + 'public, max-age=5', + 'should contain "cache-control" set to "public, max-age=5"', + ); await app.close(); }); diff --git a/test/alias.map.test.js b/test/alias.map.test.js index 261e7335..29f73131 100644 --- a/test/alias.map.test.js +++ b/test/alias.map.test.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -34,10 +34,10 @@ tap.beforeEach(async (t) => { headers: formData.getHeaders(), }); - const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const { token } = /** @type {{ token: string }} */ (await res.json()); + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + t.context = { address, headers, app, @@ -61,7 +61,11 @@ tap.test('alias map - no auth token on PUT - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias map - no auth token on PUT - non scoped', async (t) => { @@ -77,7 +81,11 @@ tap.test('alias map - no auth token on PUT - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias map - no auth token on POST - scoped', async (t) => { @@ -93,7 +101,11 @@ tap.test('alias map - no auth token on POST - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias map - no auth token on POST - non scoped', async (t) => { @@ -109,7 +121,11 @@ tap.test('alias map - no auth token on POST - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias map - no auth token on DELETE - scoped', async (t) => { @@ -121,7 +137,11 @@ tap.test('alias map - no auth token on DELETE - scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias map - no auth token on POST - non scoped', async (t) => { @@ -133,305 +153,469 @@ tap.test('alias map - no auth token on POST - non scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); -tap.test('alias map - put alias, then get map through alias - scoped', async (t) => { - const { headers, address } = t.context; - - // PUT map on server - const pkgFormData = new FormData(); - pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); - - const uploaded = await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/@cuz/fuzz/8.4.1`, 'on PUT of map, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/map/@cuz/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET map through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of map through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/map/@cuz/fuzz/8.4.1`, 'on GET of map through alias, server should respond with a location header'); - - // GET map from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of map, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias map - put alias, then get map through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - // PUT map on server - const pkgFormData = new FormData(); - pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); - - const uploaded = await fetch(`${address}/map/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/fuzz/8.4.1`, 'on PUT of map, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/map/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/map/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of map through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/map/fuzz/8.4.1`, 'on GET of map through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of map, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias map - put alias, then update alias, then get map through alias - scoped', async (t) => { - const { headers, address } = t.context; - - // PUT maps on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('map', fs.createReadStream(FIXTURE_MAP)); - await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('map', fs.createReadStream(FIXTURE_MAP_B)); - await fetch(`${address}/map/@cuz/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v8', 'on PUT of alias, alias should redirect to set "version"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v9', 'on POST of alias, alias should redirect to set "version"'); -}); - -tap.test('alias map - put alias, then update alias, then get map through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - // PUT maps on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('map', fs.createReadStream(FIXTURE_MAP)); - await fetch(`${address}/map/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('map', fs.createReadStream(FIXTURE_MAP_B)); - await fetch(`${address}/map/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/map/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v8', 'on PUT of alias, alias should redirect to set "version"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/map/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v9', 'on POST of alias, alias should redirect to set "version"'); -}); - -tap.test('alias map - put alias, then delete alias, then get map through alias - scoped', async (t) => { - const { headers, address } = t.context; - - // PUT map on server - const pkgFormData = new FormData(); - pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); - - const uploaded = await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/@cuz/fuzz/8.4.1`, 'on PUT of map, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v8', 'on PUT of alias, alias should redirect to set "version"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET map through alias from server - const errored = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of map through deleted alias, server should respond with a 404 Not Found'); -}); - -tap.test('alias map - put alias, then delete alias, then get map through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - // PUT map on server - const pkgFormData = new FormData(); - pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); - - const uploaded = await fetch(`${address}/map/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/fuzz/8.4.1`, 'on PUT of map, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/map/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v8', 'on PUT of alias, alias should redirect to set "version"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/map/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET map through alias from server - const errored = await fetch(`${address}/map/fuzz/v8`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of map through deleted alias, server should respond with a 404 Not Found'); -}); +tap.test( + 'alias map - put alias, then get map through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT map on server + const pkgFormData = new FormData(); + pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); + + const uploaded = await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/@cuz/fuzz/8.4.1`, + 'on PUT of map, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/map/@cuz/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET map through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of map through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/map/@cuz/fuzz/8.4.1`, + 'on GET of map through alias, server should respond with a location header', + ); + + // GET map from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of map, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias map - put alias, then get map through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT map on server + const pkgFormData = new FormData(); + pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); + + const uploaded = await fetch(`${address}/map/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/fuzz/8.4.1`, + 'on PUT of map, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/map/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/map/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of map through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/map/fuzz/8.4.1`, + 'on GET of map through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of map, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias map - put alias, then update alias, then get map through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT maps on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('map', fs.createReadStream(FIXTURE_MAP)); + await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('map', fs.createReadStream(FIXTURE_MAP_B)); + await fetch(`${address}/map/@cuz/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = /** @type {{ imports: { fuzz: string }}} */ ( + await aliasA.json() + ); + + t.equal( + aliasResponseA.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v8', + 'on PUT of alias, alias should redirect to set "version"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = /** @type {{ imports: { fuzz: string }}} */ ( + await aliasB.json() + ); + + t.equal( + aliasResponseB.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v9', + 'on POST of alias, alias should redirect to set "version"', + ); + }, +); + +tap.test( + 'alias map - put alias, then update alias, then get map through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT maps on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('map', fs.createReadStream(FIXTURE_MAP)); + await fetch(`${address}/map/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('map', fs.createReadStream(FIXTURE_MAP_B)); + await fetch(`${address}/map/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/map/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = /** @type {{ imports: { fuzz: string }}} */ ( + await aliasA.json() + ); + + t.equal( + aliasResponseA.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v8', + 'on PUT of alias, alias should redirect to set "version"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/map/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = /** @type {{ imports: { fuzz: string }}} */ ( + await aliasB.json() + ); + + t.equal( + aliasResponseB.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v9', + 'on POST of alias, alias should redirect to set "version"', + ); + }, +); + +tap.test( + 'alias map - put alias, then delete alias, then get map through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT map on server + const pkgFormData = new FormData(); + pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); + + const uploaded = await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/@cuz/fuzz/8.4.1`, + 'on PUT of map, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = /** @type {{ imports: { fuzz: string }}} */ ( + await alias.json() + ); + + t.equal( + aliasResponse.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v8', + 'on PUT of alias, alias should redirect to set "version"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET map through alias from server + const errored = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + errored.status, + 404, + 'on GET of map through deleted alias, server should respond with a 404 Not Found', + ); + }, +); + +tap.test( + 'alias map - put alias, then delete alias, then get map through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT map on server + const pkgFormData = new FormData(); + pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); + + const uploaded = await fetch(`${address}/map/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/fuzz/8.4.1`, + 'on PUT of map, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/map/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = /** @type {{ imports: { fuzz: string }}} */ ( + await alias.json() + ); + + t.equal( + aliasResponse.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v8', + 'on PUT of alias, alias should redirect to set "version"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/map/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET map through alias from server + const errored = await fetch(`${address}/map/fuzz/v8`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + errored.status, + 404, + 'on GET of map through deleted alias, server should respond with a 404 Not Found', + ); + }, +); diff --git a/test/alias.npm.test.js b/test/alias.npm.test.js index 086c333b..0079c4bb 100644 --- a/test/alias.npm.test.js +++ b/test/alias.npm.test.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -39,10 +39,10 @@ tap.beforeEach(async (t) => { headers: formData.getHeaders(), }); - const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const { token } = /** @type {{ token: string }} */ (await res.json()); + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + t.context = { address, headers, app, @@ -66,7 +66,11 @@ tap.test('alias package - no auth token on PUT - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on PUT - non scoped', async (t) => { @@ -82,7 +86,11 @@ tap.test('alias package - no auth token on PUT - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on POST - scoped', async (t) => { @@ -98,7 +106,11 @@ tap.test('alias package - no auth token on POST - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on POST - non scoped', async (t) => { @@ -114,7 +126,11 @@ tap.test('alias package - no auth token on POST - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on DELETE - scoped', async (t) => { @@ -125,7 +141,11 @@ tap.test('alias package - no auth token on DELETE - scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on DELETE of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on DELETE of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on DELETE - non scoped', async (t) => { @@ -136,413 +156,687 @@ tap.test('alias package - no auth token on DELETE - non scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on DELETE of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on DELETE of alias, server should respond with a 401 Unauthorized', + ); }); -tap.test('alias package - put alias, then get file overview through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/npm/@cuz/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/npm/@cuz/fuzz/8.4.1`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file overview through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/npm/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/npm/fuzz/8.4.1`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/npm/@cuz/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}/npm/@cuz/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/npm/@cuz/fuzz/8.4.1/main/index.js`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/npm/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}/npm/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/npm/fuzz/8.4.1/main/index.js`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then update alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - // PUT packages on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/npm/@cuz/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponseA.name, '@cuz/fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.version, '8.8.9', 'on POST of alias, alias should redirect to updated "version"'); - t.equal(aliasResponseB.name, '@cuz/fuzz', 'on POST of alias, alias should redirect to set "name"'); -}); - -tap.test('alias package - put alias, then update alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - // PUT packages on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/npm/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/npm/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/npm/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponseA.name, 'fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/npm/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.version, '8.8.9', 'on POST of alias, alias should redirect to updated "version"'); - t.equal(aliasResponseB.name, 'fuzz', 'on POST of alias, alias should redirect to set "name"'); -}); - -tap.test('alias package - put alias, then delete alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponse.name, '@cuz/fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET file through alias from server - const errored = await fetch(`${address}/npm/@cuz/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of file through deleted alias, server should respond with a 404 Not Found'); -}); - -tap.test('alias package - put alias, then delete alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponse.name, 'fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/npm/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET file through alias from server - const errored = await fetch(`${address}/npm/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of file through deleted alias, server should respond with a 404 Not Found'); -}); +tap.test( + 'alias package - put alias, then get file overview through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/npm/@cuz/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file overview through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/npm/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/npm/@cuz/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}/npm/@cuz/fuzz/v8/main/index.js`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1/main/index.js`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/npm/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch(`${address}/npm/fuzz/v8/main/index.js`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/npm/fuzz/8.4.1/main/index.js`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then update alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT packages on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/npm/@cuz/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = + /** @type {{ version: string; name: String; }} */ ( + await aliasA.json() + ); + + t.equal( + aliasResponseA.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponseA.name, + '@cuz/fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = + /** @type {{ version: string; name: String; }} */ ( + await aliasB.json() + ); + + t.equal( + aliasResponseB.version, + '8.8.9', + 'on POST of alias, alias should redirect to updated "version"', + ); + t.equal( + aliasResponseB.name, + '@cuz/fuzz', + 'on POST of alias, alias should redirect to set "name"', + ); + }, +); + +tap.test( + 'alias package - put alias, then update alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT packages on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/npm/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/npm/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/npm/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = + /** @type {{ version: string; name: String; }} */ ( + await aliasA.json() + ); + + t.equal( + aliasResponseA.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponseA.name, + 'fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/npm/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = + /** @type {{ version: string; name: String; }} */ ( + await aliasB.json() + ); + + t.equal( + aliasResponseB.version, + '8.8.9', + 'on POST of alias, alias should redirect to updated "version"', + ); + t.equal( + aliasResponseB.name, + 'fuzz', + 'on POST of alias, alias should redirect to set "name"', + ); + }, +); + +tap.test( + 'alias package - put alias, then delete alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = + /** @type {{ version: string; name: String; }} */ ( + await alias.json() + ); + + t.equal( + aliasResponse.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponse.name, + '@cuz/fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET file through alias from server + const errored = await fetch( + `${address}/npm/@cuz/fuzz/v8/main/index.js`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + errored.status, + 404, + 'on GET of file through deleted alias, server should respond with a 404 Not Found', + ); + }, +); + +tap.test( + 'alias package - put alias, then delete alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = + /** @type {{ version: string; name: String; }} */ ( + await alias.json() + ); + + t.equal( + aliasResponse.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponse.name, + 'fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/npm/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET file through alias from server + const errored = await fetch(`${address}/npm/fuzz/v8/main/index.js`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + errored.status, + 404, + 'on GET of file through deleted alias, server should respond with a 404 Not Found', + ); + }, +); diff --git a/test/alias.pkg.test.js b/test/alias.pkg.test.js index 1c8ac6ab..120cea06 100644 --- a/test/alias.pkg.test.js +++ b/test/alias.pkg.test.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -39,10 +39,10 @@ tap.beforeEach(async (t) => { headers: formData.getHeaders(), }); - const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const { token } = /** @type {{ token: string }} */ (await res.json()); + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + t.context = { address, headers, app, @@ -66,7 +66,11 @@ tap.test('alias package - no auth token on PUT - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on PUT - non scoped', async (t) => { @@ -82,7 +86,11 @@ tap.test('alias package - no auth token on PUT - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on POST - scoped', async (t) => { @@ -98,7 +106,11 @@ tap.test('alias package - no auth token on POST - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on POST - non scoped', async (t) => { @@ -114,7 +126,11 @@ tap.test('alias package - no auth token on POST - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on DELETE - scoped', async (t) => { @@ -125,7 +141,11 @@ tap.test('alias package - no auth token on DELETE - scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on DELETE of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on DELETE of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on DELETE - non scoped', async (t) => { @@ -136,413 +156,687 @@ tap.test('alias package - no auth token on DELETE - non scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on DELETE of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on DELETE of alias, server should respond with a 401 Unauthorized', + ); }); -tap.test('alias package - put alias, then get file overview through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/pkg/@cuz/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file overview through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/pkg/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/pkg/@cuz/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}/pkg/@cuz/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1/main/index.js`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/pkg/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}/pkg/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/pkg/fuzz/8.4.1/main/index.js`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then update alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - // PUT packages on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/pkg/@cuz/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponseA.name, '@cuz/fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.version, '8.8.9', 'on POST of alias, alias should redirect to updated "version"'); - t.equal(aliasResponseB.name, '@cuz/fuzz', 'on POST of alias, alias should redirect to set "name"'); -}); - -tap.test('alias package - put alias, then update alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - // PUT packages on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/pkg/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/pkg/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponseA.name, 'fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.version, '8.8.9', 'on POST of alias, alias should redirect to updated "version"'); - t.equal(aliasResponseB.name, 'fuzz', 'on POST of alias, alias should redirect to set "name"'); -}); - -tap.test('alias package - put alias, then delete alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponse.name, '@cuz/fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET file through alias from server - const errored = await fetch(`${address}/pkg/@cuz/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of file through deleted alias, server should respond with a 404 Not Found'); -}); - -tap.test('alias package - put alias, then delete alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponse.name, 'fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET file through alias from server - const errored = await fetch(`${address}/pkg/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of file through deleted alias, server should respond with a 404 Not Found'); -}); +tap.test( + 'alias package - put alias, then get file overview through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/pkg/@cuz/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file overview through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/pkg/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/pkg/@cuz/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}/pkg/@cuz/fuzz/v8/main/index.js`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1/main/index.js`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/pkg/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch(`${address}/pkg/fuzz/v8/main/index.js`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/pkg/fuzz/8.4.1/main/index.js`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then update alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT packages on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/pkg/@cuz/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = + /** @type {{ version: string; name: String; }} */ ( + await aliasA.json() + ); + + t.equal( + aliasResponseA.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponseA.name, + '@cuz/fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = + /** @type {{ version: string; name: String; }} */ ( + await aliasB.json() + ); + + t.equal( + aliasResponseB.version, + '8.8.9', + 'on POST of alias, alias should redirect to updated "version"', + ); + t.equal( + aliasResponseB.name, + '@cuz/fuzz', + 'on POST of alias, alias should redirect to set "name"', + ); + }, +); + +tap.test( + 'alias package - put alias, then update alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT packages on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/pkg/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/pkg/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = + /** @type {{ version: string; name: String; }} */ ( + await aliasA.json() + ); + + t.equal( + aliasResponseA.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponseA.name, + 'fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = + /** @type {{ version: string; name: String; }} */ ( + await aliasB.json() + ); + + t.equal( + aliasResponseB.version, + '8.8.9', + 'on POST of alias, alias should redirect to updated "version"', + ); + t.equal( + aliasResponseB.name, + 'fuzz', + 'on POST of alias, alias should redirect to set "name"', + ); + }, +); + +tap.test( + 'alias package - put alias, then delete alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = + /** @type {{ version: string; name: String; }} */ ( + await alias.json() + ); + + t.equal( + aliasResponse.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponse.name, + '@cuz/fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET file through alias from server + const errored = await fetch( + `${address}/pkg/@cuz/fuzz/v8/main/index.js`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + errored.status, + 404, + 'on GET of file through deleted alias, server should respond with a 404 Not Found', + ); + }, +); + +tap.test( + 'alias package - put alias, then delete alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = + /** @type {{ version: string; name: String; }} */ ( + await alias.json() + ); + + t.equal( + aliasResponse.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponse.name, + 'fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET file through alias from server + const errored = await fetch(`${address}/pkg/fuzz/v8/main/index.js`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + errored.status, + 404, + 'on GET of file through deleted alias, server should respond with a 404 Not Found', + ); + }, +); diff --git a/test/auth.test.js b/test/auth.test.js index b8132168..01b68242 100644 --- a/test/auth.test.js +++ b/test/auth.test.js @@ -3,7 +3,7 @@ import Fastify from 'fastify'; import fetch from 'node-fetch'; import tap from 'tap'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; tap.test('auth - authenticate - legal "key" value', async (t) => { @@ -26,17 +26,24 @@ tap.test('auth - authenticate - legal "key" value', async (t) => { headers: formData.getHeaders(), }); - const body = await response.json(); + const { token } = /** @type {{ token: string }} */ (await response.json()); - t.equal(response.status, 200, 'on POST of valid key, server should respond with a 200 OK'); - t.ok(body.token.length > 5, 'on POST of valid key, server should respond with a body with a token'); + t.equal( + response.status, + 200, + 'on POST of valid key, server should respond with a 200 OK', + ); + t.ok( + token.length > 5, + 'on POST of valid key, server should respond with a body with a token', + ); await app.close(); }); tap.test('auth - authenticate - illegal "key" value', async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); + const service = new Server({ customSink: sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -54,7 +61,11 @@ tap.test('auth - authenticate - illegal "key" value', async (t) => { headers: formData.getHeaders(), }); - t.equal(response.status, 401, 'on POST of valid key, server should respond with a 401 Unauthorized'); + t.equal( + response.status, + 401, + 'on POST of valid key, server should respond with a 401 Unauthorized', + ); await app.close(); }); diff --git a/test/http.cache.control.test.js b/test/http.cache.control.test.js index 5439decd..3d253e0d 100644 --- a/test/http.cache.control.test.js +++ b/test/http.cache.control.test.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -40,10 +40,10 @@ tap.beforeEach(async (t) => { headers: formData.getHeaders(), }); - const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const { token } = /** @type {{ token: string }} */ (await res.json()); + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + t.context = { address, headers, app, @@ -66,7 +66,11 @@ tap.test('cache-control - auth post', async (t) => { headers: formData.getHeaders(), }); - t.equal(response.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + response.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); }); tap.test('cache-control - package - non-scoped', async (t) => { @@ -80,34 +84,56 @@ tap.test('cache-control - package - non-scoped', async (t) => { method: 'PUT', body: formData, redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET file from server const fetched = await fetch(`${address}/pkg/fuzz/1.4.8/main/index.js`, { method: 'GET', }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/pkg/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); - + const nonExisting = await fetch( + `${address}/pkg/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET package overview from server const overview = await fetch(`${address}/pkg/fuzz/1.4.8`, { method: 'GET', }); - t.equal(overview.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + overview.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); // GET package versions overview from server const versions = await fetch(`${address}/pkg/fuzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - package - scoped', async (t) => { @@ -121,33 +147,59 @@ tap.test('cache-control - package - scoped', async (t) => { method: 'PUT', body: formData, redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET file from server - const fetched = await fetch(`${address}/pkg/@cuz/fuzz/1.4.8/main/index.js`, { - method: 'GET', - }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + const fetched = await fetch( + `${address}/pkg/@cuz/fuzz/1.4.8/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/pkg/@cuz/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); + const nonExisting = await fetch( + `${address}/pkg/@cuz/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET package overview from server const overview = await fetch(`${address}/pkg/@cuz/fuzz/1.4.8`, { method: 'GET', }); - t.equal(overview.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + overview.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); // GET package versions overview from server const versions = await fetch(`${address}/pkg/@cuz/fuzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - npm package - non-scoped', async (t) => { @@ -161,33 +213,56 @@ tap.test('cache-control - npm package - non-scoped', async (t) => { method: 'PUT', body: formData, redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET file from server const fetched = await fetch(`${address}/npm/fuzz/1.4.8/main/index.js`, { method: 'GET', }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/npm/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); + const nonExisting = await fetch( + `${address}/npm/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET package overview from server const overview = await fetch(`${address}/npm/fuzz/1.4.8`, { method: 'GET', }); - t.equal(overview.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + overview.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); // GET package versions overview from server const versions = await fetch(`${address}/npm/fuzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - npm package - scoped', async (t) => { @@ -201,33 +276,59 @@ tap.test('cache-control - npm package - scoped', async (t) => { method: 'PUT', body: formData, redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET file from server - const fetched = await fetch(`${address}/npm/@cuz/fuzz/1.4.8/main/index.js`, { - method: 'GET', - }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + const fetched = await fetch( + `${address}/npm/@cuz/fuzz/1.4.8/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/pkg/@cuz/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); + const nonExisting = await fetch( + `${address}/pkg/@cuz/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET package overview from server const overview = await fetch(`${address}/npm/@cuz/fuzz/1.4.8`, { method: 'GET', }); - t.equal(overview.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + overview.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); // GET package versions overview from server const versions = await fetch(`${address}/npm/@cuz/fuzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - map - non-scoped', async (t) => { @@ -240,28 +341,47 @@ tap.test('cache-control - map - non-scoped', async (t) => { const uploaded = await fetch(`${address}/map/buzz/4.2.2`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET map from server const fetched = await fetch(`${address}/map/buzz/4.2.2`, { method: 'GET', }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/map/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); + const nonExisting = await fetch( + `${address}/map/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET map versions overview from server const versions = await fetch(`${address}/map/buzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - map - scoped', async (t) => { @@ -274,28 +394,47 @@ tap.test('cache-control - map - scoped', async (t) => { const uploaded = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET map from server const fetched = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { method: 'GET', }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/map/@cuz/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); + const nonExisting = await fetch( + `${address}/map/@cuz/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET map versions overview from server const versions = await fetch(`${address}/map/@cuz/buzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias package - non-scoped', async (t) => { @@ -312,7 +451,7 @@ tap.test('cache-control - alias package - non-scoped', async (t) => { method: 'PUT', body: formDataA, redirect: 'manual', - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, }); // PUT files on server @@ -320,7 +459,7 @@ tap.test('cache-control - alias package - non-scoped', async (t) => { method: 'PUT', body: formDataB, redirect: 'manual', - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, }); // PUT alias on server @@ -330,17 +469,25 @@ tap.test('cache-control - alias package - non-scoped', async (t) => { const alias = await fetch(`${address}/pkg/fuzz/v8`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/pkg/fuzz/v8/main/index.js`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -349,17 +496,25 @@ tap.test('cache-control - alias package - non-scoped', async (t) => { const updated = await fetch(`${address}/pkg/fuzz/v8`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/pkg/fuzz/v8`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias package - scoped', async (t) => { @@ -376,7 +531,7 @@ tap.test('cache-control - alias package - scoped', async (t) => { method: 'PUT', body: formDataA, redirect: 'manual', - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, }); // PUT files on server @@ -384,7 +539,7 @@ tap.test('cache-control - alias package - scoped', async (t) => { method: 'PUT', body: formDataB, redirect: 'manual', - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, }); // PUT alias on server @@ -394,17 +549,25 @@ tap.test('cache-control - alias package - scoped', async (t) => { const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/pkg/@cuz/fuzz/v8/main/index.js`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -413,17 +576,25 @@ tap.test('cache-control - alias package - scoped', async (t) => { const updated = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias NPM package - non-scoped', async (t) => { @@ -440,7 +611,7 @@ tap.test('cache-control - alias NPM package - non-scoped', async (t) => { method: 'PUT', body: formDataA, redirect: 'manual', - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, }); // PUT files on server @@ -448,7 +619,7 @@ tap.test('cache-control - alias NPM package - non-scoped', async (t) => { method: 'PUT', body: formDataB, redirect: 'manual', - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, }); // PUT alias on server @@ -458,17 +629,25 @@ tap.test('cache-control - alias NPM package - non-scoped', async (t) => { const alias = await fetch(`${address}/npm/fuzz/v8`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/npm/fuzz/v8/main/index.js`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -477,17 +656,25 @@ tap.test('cache-control - alias NPM package - non-scoped', async (t) => { const updated = await fetch(`${address}/npm/fuzz/v8`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/npm/fuzz/v8`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias NPM package - scoped', async (t) => { @@ -504,7 +691,7 @@ tap.test('cache-control - alias NPM package - scoped', async (t) => { method: 'PUT', body: formDataA, redirect: 'manual', - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, }); // PUT files on server @@ -512,7 +699,7 @@ tap.test('cache-control - alias NPM package - scoped', async (t) => { method: 'PUT', body: formDataB, redirect: 'manual', - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, }); // PUT alias on server @@ -522,17 +709,25 @@ tap.test('cache-control - alias NPM package - scoped', async (t) => { const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/npm/@cuz/fuzz/v8/main/index.js`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -541,17 +736,25 @@ tap.test('cache-control - alias NPM package - scoped', async (t) => { const updated = await fetch(`${address}/npm/@cuz/fuzz/v8`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/npm/@cuz/fuzz/v8`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias map - non-scoped', async (t) => { @@ -567,14 +770,14 @@ tap.test('cache-control - alias map - non-scoped', async (t) => { await fetch(`${address}/map/buzz/4.2.2`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); await fetch(`${address}/map/buzz/4.4.2`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -585,17 +788,25 @@ tap.test('cache-control - alias map - non-scoped', async (t) => { const alias = await fetch(`${address}/map/buzz/v4`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/map/buzz/v4`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -604,17 +815,25 @@ tap.test('cache-control - alias map - non-scoped', async (t) => { const updated = await fetch(`${address}/map/buzz/v4`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/map/buzz/v4`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias map - scoped', async (t) => { @@ -630,14 +849,14 @@ tap.test('cache-control - alias map - scoped', async (t) => { await fetch(`${address}/map/@cuz/buzz/4.2.2`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); await fetch(`${address}/map/@cuz/buzz/4.4.2`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -648,17 +867,25 @@ tap.test('cache-control - alias map - scoped', async (t) => { const alias = await fetch(`${address}/map/@cuz/buzz/v4`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/map/@cuz/buzz/v4`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -667,15 +894,23 @@ tap.test('cache-control - alias map - scoped', async (t) => { const updated = await fetch(`${address}/map/@cuz/buzz/v4`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/map/@cuz/buzz/v4`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); diff --git a/test/http.etag.test.js b/test/http.etag.test.js index 17d650c8..e7c65fb5 100644 --- a/test/http.etag.test.js +++ b/test/http.etag.test.js @@ -2,14 +2,14 @@ import Fastify from 'fastify'; import fetch from 'node-fetch'; import tap from 'tap'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; // // Package GET // -tap.test('ETag - pkg:get - ETag and "If-None-Match" is matching', async t => { +tap.test('ETag - pkg:get - ETag and "If-None-Match" is matching', async (t) => { const sink = new Sink(); const service = new Server({ customSink: sink }); @@ -29,8 +29,16 @@ tap.test('ETag - pkg:get - ETag and "If-None-Match" is matching', async t => { const bodyA = await resA.text(); t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); const resB = await fetch(url, { method: 'GET', @@ -41,84 +49,130 @@ tap.test('ETag - pkg:get - ETag and "If-None-Match" is matching', async t => { const bodyB = await resB.text(); t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 304, 'second response should respond with http status 304'); + t.equal( + resB.status, + 304, + 'second response should respond with http status 304', + ); t.equal(bodyB, '', 'second response should respond with empty contents'); await app.close(); }); -tap.test('ETag - pkg:get - ETag and "If-None-Match" is NOT matching', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/pkg/fuzz/8.4.1/main/index.js`; - sink.set('/local/pkg/fuzz/8.4.1/main/index.js', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - headers: { - 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', - }, - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); - -tap.test('ETag - pkg:get - "If-None-Match" is NOT set on request', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/pkg/fuzz/8.4.1/main/index.js`; - sink.set('/local/pkg/fuzz/8.4.1/main/index.js', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); +tap.test( + 'ETag - pkg:get - ETag and "If-None-Match" is NOT matching', + async (t) => { + const sink = new Sink(); + const service = new Server({ + customSink: sink, + }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/pkg/fuzz/8.4.1/main/index.js`; + sink.set('/local/pkg/fuzz/8.4.1/main/index.js', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + headers: { + 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', + }, + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); + +tap.test( + 'ETag - pkg:get - "If-None-Match" is NOT set on request', + async (t) => { + const sink = new Sink(); + const service = new Server({ + customSink: sink, + }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/pkg/fuzz/8.4.1/main/index.js`; + sink.set('/local/pkg/fuzz/8.4.1/main/index.js', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); /* tap.test('ETag - pkg:get - ETags is configured to not be set', async t => { const sink = new Sink(); @@ -157,9 +211,9 @@ tap.test('ETag - pkg:get - ETags is configured to not be set', async t => { // Package LOG // -tap.test('ETag - pkg:log - ETag and "If-None-Match" is matching', async t => { +tap.test('ETag - pkg:log - ETag and "If-None-Match" is matching', async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); + const service = new Server({ customSink: sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -171,15 +225,22 @@ tap.test('ETag - pkg:log - ETag and "If-None-Match" is matching', async t => { const url = `${address}/pkg/fuzz/8.4.1`; sink.set('/local/pkg/fuzz/8.4.1.package.json', 'hello world'); - const resA = await fetch(url, { method: 'GET', }); const bodyA = await resA.text(); t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); const resB = await fetch(url, { method: 'GET', @@ -190,84 +251,130 @@ tap.test('ETag - pkg:log - ETag and "If-None-Match" is matching', async t => { const bodyB = await resB.text(); t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 304, 'second response should respond with http status 304'); + t.equal( + resB.status, + 304, + 'second response should respond with http status 304', + ); t.equal(bodyB, '', 'second response should respond with empty contents'); await app.close(); }); -tap.test('ETag - pkg:log - ETag and "If-None-Match" is NOT matching', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/pkg/fuzz/8.4.1`; - sink.set('/local/pkg/fuzz/8.4.1.package.json', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - headers: { - 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', - }, - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); - -tap.test('ETag - pkg:log - "If-None-Match" is NOT set on request', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/pkg/fuzz/8.4.1`; - sink.set('/local/pkg/fuzz/8.4.1.package.json', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); +tap.test( + 'ETag - pkg:log - ETag and "If-None-Match" is NOT matching', + async (t) => { + const sink = new Sink(); + const service = new Server({ + customSink: sink, + }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/pkg/fuzz/8.4.1`; + sink.set('/local/pkg/fuzz/8.4.1.package.json', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + headers: { + 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', + }, + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); + +tap.test( + 'ETag - pkg:log - "If-None-Match" is NOT set on request', + async (t) => { + const sink = new Sink(); + const service = new Server({ + customSink: sink, + }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/pkg/fuzz/8.4.1`; + sink.set('/local/pkg/fuzz/8.4.1.package.json', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); /* tap.test('ETag - pkg:log - ETags is configured to not be set', async t => { const sink = new Sink(); @@ -306,9 +413,9 @@ tap.test('ETag - pkg:log - ETags is configured to not be set', async t => { // Map GET // -tap.test('ETag - map:get - ETag and "If-None-Match" is matching', async t => { +tap.test('ETag - map:get - ETag and "If-None-Match" is matching', async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); + const service = new Server({ customSink: sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -320,15 +427,22 @@ tap.test('ETag - map:get - ETag and "If-None-Match" is matching', async t => { const url = `${address}/map/buzz/4.2.2`; sink.set('/local/map/buzz/4.2.2.import-map.json', 'hello world'); - const resA = await fetch(url, { method: 'GET', }); const bodyA = await resA.text(); t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); const resB = await fetch(url, { method: 'GET', @@ -339,84 +453,130 @@ tap.test('ETag - map:get - ETag and "If-None-Match" is matching', async t => { const bodyB = await resB.text(); t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 304, 'second response should respond with http status 304'); + t.equal( + resB.status, + 304, + 'second response should respond with http status 304', + ); t.equal(bodyB, '', 'second response should respond with empty contents'); await app.close(); }); -tap.test('ETag - map:get - ETag and "If-None-Match" is NOT matching', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/map/buzz/4.2.2`; - sink.set('/local/map/buzz/4.2.2.import-map.json', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - headers: { - 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', - }, - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); - -tap.test('ETag - map:get - "If-None-Match" is NOT set on request', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/map/buzz/4.2.2`; - sink.set('/local/map/buzz/4.2.2.import-map.json', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); +tap.test( + 'ETag - map:get - ETag and "If-None-Match" is NOT matching', + async (t) => { + const sink = new Sink(); + const service = new Server({ + customSink: sink, + }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/map/buzz/4.2.2`; + sink.set('/local/map/buzz/4.2.2.import-map.json', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + headers: { + 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', + }, + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); + +tap.test( + 'ETag - map:get - "If-None-Match" is NOT set on request', + async (t) => { + const sink = new Sink(); + const service = new Server({ + customSink: sink, + }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/map/buzz/4.2.2`; + sink.set('/local/map/buzz/4.2.2.import-map.json', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); /* tap.test('ETag - map:get - ETags is configured to not be set', async t => { const sink = new Sink(); @@ -450,4 +610,4 @@ tap.test('ETag - map:get - ETags is configured to not be set', async t => { await service.stop(); }); -*/ \ No newline at end of file +*/ diff --git a/test/http.override.cache.control.test.js b/test/http.override.cache.control.test.js index 00290071..10848b8a 100644 --- a/test/http.override.cache.control.test.js +++ b/test/http.override.cache.control.test.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -42,10 +42,9 @@ tap.beforeEach(async (t) => { headers: formData.getHeaders(), }); - const { token } = await res.json(); + const { token } = /** @type {{ token: string }} */ (await res.json()); const headers = { Authorization: `Bearer ${token}` }; - // eslint-disable-next-line no-param-reassign t.context = { address, headers, diff --git a/test/http.query.params.test.js b/test/http.query.params.test.js index c982e177..4759306a 100644 --- a/test/http.query.params.test.js +++ b/test/http.query.params.test.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -40,10 +40,10 @@ tap.beforeEach(async (t) => { headers: formData.getHeaders(), }); - const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const { token } = /** @type {{ token: string }} */ (await res.json()); + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + t.context = { address, headers, app, @@ -64,16 +64,23 @@ tap.test('query params - package', async (t) => { await fetch(`${address}/pkg/fuzz/8.4.1`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); // GET file from server - const downloaded = await fetch(`${address}/pkg/fuzz/8.4.1/main/index.js?foo=bar`, { - method: 'GET', - }); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); + const downloaded = await fetch( + `${address}/pkg/fuzz/8.4.1/main/index.js?foo=bar`, + { + method: 'GET', + }, + ); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); }); tap.test('query params - NPM package', async (t) => { @@ -86,16 +93,23 @@ tap.test('query params - NPM package', async (t) => { await fetch(`${address}/npm/fuzz/8.4.1`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); // GET file from server - const downloaded = await fetch(`${address}/npm/fuzz/8.4.1/main/index.js?foo=bar`, { - method: 'GET', - }); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); + const downloaded = await fetch( + `${address}/npm/fuzz/8.4.1/main/index.js?foo=bar`, + { + method: 'GET', + }, + ); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); }); tap.test('query params - map', async (t) => { @@ -108,7 +122,7 @@ tap.test('query params - map', async (t) => { await fetch(`${address}/map/buzz/4.2.2`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); @@ -117,5 +131,9 @@ tap.test('query params - map', async (t) => { method: 'GET', }); - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); }); diff --git a/test/map.test.js b/test/map.test.js index 0da3cd68..3ef0658e 100644 --- a/test/map.test.js +++ b/test/map.test.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -33,10 +33,10 @@ tap.beforeEach(async (t) => { headers: formData.getHeaders(), }); - const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const { token } = /** @type {{ token: string }} */ (await res.json()); + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + t.context = { address, headers, app, @@ -61,7 +61,11 @@ tap.test('import-map - no auth token on PUT - scoped', async (t) => { redirect: 'manual', }); - t.equal(uploaded.status, 401, 'on PUT of map, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of map, server should respond with a 401 Unauthorized', + ); }); tap.test('import-map - no auth token on PUT - non scoped', async (t) => { @@ -78,64 +82,104 @@ tap.test('import-map - no auth token on PUT - non scoped', async (t) => { redirect: 'manual', }); - t.equal(uploaded.status, 401, 'on PUT of map, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of map, server should respond with a 401 Unauthorized', + ); }); -tap.test('import-map - put map -> get map - scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('map', fs.createReadStream(FIXTURE_MAP)); - - // PUT map on server - const uploaded = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/@cuz/buzz/4.2.2`, 'on PUT of map, server should respond with a location header'); - - // GET map from server - const downloaded = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of map, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of map, response should match snapshot'); -}); - -tap.test('import-map - put map -> get map - non scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('map', fs.createReadStream(FIXTURE_MAP)); - - // PUT map on server - const uploaded = await fetch(`${address}/map/buzz/4.2.2`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/buzz/4.2.2`, 'on PUT of map, server should respond with a location header'); - - // GET map from server - const downloaded = await fetch(`${address}/map/buzz/4.2.2`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of map, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of map, response should match snapshot'); -}); +tap.test( + 'import-map - put map -> get map - scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('map', fs.createReadStream(FIXTURE_MAP)); + + // PUT map on server + const uploaded = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/@cuz/buzz/4.2.2`, + 'on PUT of map, server should respond with a location header', + ); + + // GET map from server + const downloaded = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { + method: 'GET', + }); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of map, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of map, response should match snapshot', + ); + }, +); + +tap.test( + 'import-map - put map -> get map - non scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('map', fs.createReadStream(FIXTURE_MAP)); + + // PUT map on server + const uploaded = await fetch(`${address}/map/buzz/4.2.2`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/buzz/4.2.2`, + 'on PUT of map, server should respond with a location header', + ); + + // GET map from server + const downloaded = await fetch(`${address}/map/buzz/4.2.2`, { + method: 'GET', + }); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of map, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of map, response should match snapshot', + ); + }, +); tap.test('import-map - get map versions - scoped', async (t) => { const { headers, address } = t.context; @@ -147,7 +191,7 @@ tap.test('import-map - get map versions - scoped', async (t) => { await fetch(`${address}/map/@cuz/buzz/4.2.2`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -156,7 +200,7 @@ tap.test('import-map - get map versions - scoped', async (t) => { await fetch(`${address}/map/@cuz/buzz/5.2.2`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -165,7 +209,7 @@ tap.test('import-map - get map versions - scoped', async (t) => { await fetch(`${address}/map/@cuz/buzz/4.9.2`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -176,8 +220,15 @@ tap.test('import-map - get map versions - scoped', async (t) => { const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET of map versions, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of map versions, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET of map versions, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of map versions, response should match snapshot', + ); }); tap.test('import-map - get map versions - non scoped', async (t) => { @@ -190,7 +241,7 @@ tap.test('import-map - get map versions - non scoped', async (t) => { await fetch(`${address}/map/buzz/4.2.2`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -199,7 +250,7 @@ tap.test('import-map - get map versions - non scoped', async (t) => { await fetch(`${address}/map/buzz/5.2.2`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -208,7 +259,7 @@ tap.test('import-map - get map versions - non scoped', async (t) => { await fetch(`${address}/map/buzz/4.9.2`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -219,6 +270,13 @@ tap.test('import-map - get map versions - non scoped', async (t) => { const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET of map versions, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of map versions, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET of map versions, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of map versions, response should match snapshot', + ); }); diff --git a/test/npm.test.js b/test/npm.test.js index 2da4a33d..76cb48b9 100644 --- a/test/npm.test.js +++ b/test/npm.test.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -39,10 +39,10 @@ tap.beforeEach(async (t) => { headers: formData.getHeaders(), }); - const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const { token } = /** @type {{ token: string }} */ (await res.json()); + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + t.context = { address, headers, app, @@ -67,7 +67,11 @@ tap.test('npm packages - no auth token on PUT - scoped', async (t) => { headers: formData.getHeaders(), }); - t.equal(uploaded.status, 401, 'on PUT of package, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of package, server should respond with a 401 Unauthorized', + ); }); tap.test('npm packages - no auth token on PUT - non scoped', async (t) => { @@ -84,62 +88,108 @@ tap.test('npm packages - no auth token on PUT - non scoped', async (t) => { headers: formData.getHeaders(), }); - t.equal(uploaded.status, 401, 'on PUT of package, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of package, server should respond with a 401 Unauthorized', + ); }); -tap.test('npm packages - put pkg -> get file - scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/@cuz/fuzz/1.4.8`, { - method: 'PUT', - body: formData, - redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/@cuz/fuzz/1.4.8`, 'on PUT of package, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}/npm/@cuz/fuzz/1.4.8/main/index.js`, { - method: 'GET', - }); - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of package, response should match snapshot'); -}); - -tap.test('npm packages - put pkg -> get file - non scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}/npm/fuzz/8.4.1/main/index.js`, { - method: 'GET', - }); - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of package, response should match snapshot'); -}); +tap.test( + 'npm packages - put pkg -> get file - scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/@cuz/fuzz/1.4.8`, { + method: 'PUT', + body: formData, + redirect: 'manual', + headers: { ...headers, ...formData.getHeaders() }, + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/@cuz/fuzz/1.4.8`, + 'on PUT of package, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}/npm/@cuz/fuzz/1.4.8/main/index.js`, + { + method: 'GET', + }, + ); + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of package, response should match snapshot', + ); + }, +); + +tap.test( + 'npm packages - put pkg -> get file - non scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}/npm/fuzz/8.4.1/main/index.js`, + { + method: 'GET', + }, + ); + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of package, response should match snapshot', + ); + }, +); tap.test('npm packages - get package overview - scoped', async (t) => { const { headers, address } = t.context; @@ -151,12 +201,20 @@ tap.test('npm packages - get package overview - scoped', async (t) => { const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1/`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); // GET package overview from server const downloaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1/`, { @@ -164,8 +222,15 @@ tap.test('npm packages - get package overview - scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('npm packages - get package overview - non scoped', async (t) => { @@ -178,12 +243,20 @@ tap.test('npm packages - get package overview - non scoped', async (t) => { const uploaded = await fetch(`${address}/npm/fuzz/8.4.1/`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); // GET package overview from server const downloaded = await fetch(`${address}/npm/fuzz/8.4.1/`, { @@ -191,8 +264,15 @@ tap.test('npm packages - get package overview - non scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('npm packages - get package versions - scoped', async (t) => { @@ -205,7 +285,7 @@ tap.test('npm packages - get package versions - scoped', async (t) => { await fetch(`${address}/npm/@cuz/fuzz/7.3.2/`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -214,7 +294,7 @@ tap.test('npm packages - get package versions - scoped', async (t) => { await fetch(`${address}/npm/@cuz/fuzz/8.4.1/`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -223,7 +303,7 @@ tap.test('npm packages - get package versions - scoped', async (t) => { await fetch(`${address}/npm/@cuz/fuzz/8.5.1/`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -233,8 +313,15 @@ tap.test('npm packages - get package versions - scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('npm packages - get package versions - non scoped', async (t) => { @@ -247,7 +334,7 @@ tap.test('npm packages - get package versions - non scoped', async (t) => { await fetch(`${address}/npm/fuzz/7.3.2/`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -256,7 +343,7 @@ tap.test('npm packages - get package versions - non scoped', async (t) => { await fetch(`${address}/npm/fuzz/8.4.1/`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -265,7 +352,7 @@ tap.test('npm packages - get package versions - non scoped', async (t) => { await fetch(`${address}/npm/fuzz/8.5.1/`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -275,6 +362,13 @@ tap.test('npm packages - get package versions - non scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); diff --git a/test/pkg-put-write-integrity.test.js b/test/pkg-put-write-integrity.test.js index 164fc2bc..adf6d2b6 100644 --- a/test/pkg-put-write-integrity.test.js +++ b/test/pkg-put-write-integrity.test.js @@ -27,7 +27,7 @@ const authentication = async (address) => { headers: formData.getHeaders(), }); - const { token } = await res.json(); + const { token } = /** @type {{ token: string }} */ (await res.json()); return { Authorization: `Bearer ${token}` }; }; diff --git a/test/pkg.test.js b/test/pkg.test.js index 8601d6f5..e0a751aa 100644 --- a/test/pkg.test.js +++ b/test/pkg.test.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -39,10 +39,10 @@ tap.beforeEach(async (t) => { headers: formData.getHeaders(), }); - const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const { token } = /** @type {{ token: string }} */ (await res.json()); + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + t.context = { address, headers, app, @@ -67,7 +67,11 @@ tap.test('packages - no auth token on PUT - scoped', async (t) => { headers: formData.getHeaders(), }); - t.equal(uploaded.status, 401, 'on PUT of package, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of package, server should respond with a 401 Unauthorized', + ); }); tap.test('packages - no auth token on PUT - non scoped', async (t) => { @@ -84,62 +88,108 @@ tap.test('packages - no auth token on PUT - non scoped', async (t) => { headers: formData.getHeaders(), }); - t.equal(uploaded.status, 401, 'on PUT of package, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of package, server should respond with a 401 Unauthorized', + ); }); -tap.test('packages - put pkg -> get file - scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/1.4.8`, { - method: 'PUT', - body: formData, - redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/@cuz/fuzz/1.4.8`, 'on PUT of package, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}/pkg/@cuz/fuzz/1.4.8/main/index.js`, { - method: 'GET', - }); - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of package, response should match snapshot'); -}); - -tap.test('packages - put pkg -> get file - non scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}/pkg/fuzz/8.4.1/main/index.js`, { - method: 'GET', - }); - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of package, response should match snapshot'); -}); +tap.test( + 'packages - put pkg -> get file - scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/1.4.8`, { + method: 'PUT', + body: formData, + redirect: 'manual', + headers: { ...headers, ...formData.getHeaders() }, + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/@cuz/fuzz/1.4.8`, + 'on PUT of package, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}/pkg/@cuz/fuzz/1.4.8/main/index.js`, + { + method: 'GET', + }, + ); + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of package, response should match snapshot', + ); + }, +); + +tap.test( + 'packages - put pkg -> get file - non scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}/pkg/fuzz/8.4.1/main/index.js`, + { + method: 'GET', + }, + ); + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of package, response should match snapshot', + ); + }, +); tap.test('packages - get package overview - scoped', async (t) => { const { headers, address } = t.context; @@ -151,12 +201,20 @@ tap.test('packages - get package overview - scoped', async (t) => { const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1/`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); // GET package overview from server const downloaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1/`, { @@ -164,8 +222,15 @@ tap.test('packages - get package overview - scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('packages - get package overview - non scoped', async (t) => { @@ -178,12 +243,20 @@ tap.test('packages - get package overview - non scoped', async (t) => { const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1/`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); // GET package overview from server const downloaded = await fetch(`${address}/pkg/fuzz/8.4.1/`, { @@ -191,8 +264,15 @@ tap.test('packages - get package overview - non scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('packages - get package versions - scoped', async (t) => { @@ -205,7 +285,7 @@ tap.test('packages - get package versions - scoped', async (t) => { await fetch(`${address}/pkg/@cuz/fuzz/7.3.2/`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -214,7 +294,7 @@ tap.test('packages - get package versions - scoped', async (t) => { await fetch(`${address}/pkg/@cuz/fuzz/8.4.1/`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -223,7 +303,7 @@ tap.test('packages - get package versions - scoped', async (t) => { await fetch(`${address}/pkg/@cuz/fuzz/8.5.1/`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -233,8 +313,15 @@ tap.test('packages - get package versions - scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('packages - get package versions - non scoped', async (t) => { @@ -247,7 +334,7 @@ tap.test('packages - get package versions - non scoped', async (t) => { await fetch(`${address}/pkg/fuzz/7.3.2/`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -256,7 +343,7 @@ tap.test('packages - get package versions - non scoped', async (t) => { await fetch(`${address}/pkg/fuzz/8.4.1/`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -265,7 +352,7 @@ tap.test('packages - get package versions - non scoped', async (t) => { await fetch(`${address}/pkg/fuzz/8.5.1/`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -275,6 +362,13 @@ tap.test('packages - get package versions - non scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..d29c97d9 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@eik/typescript-config/module.json", + "include": ["./lib/**/*.js"], + "compilerOptions": { + "outDir": "types" + } +} diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 00000000..2d07b9ab --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,4 @@ +{ + "extends": "@eik/typescript-config/test.json", + "include": ["./test/**/*.js"] +}