mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-16 21:56:25 -05:00
feat: migrate yeoman generator to monorepo (#4683)
* feat: migrate geoman generator * Create README.md
This commit is contained in:
parent
117eb1ca42
commit
a528af49bc
34 changed files with 3257 additions and 304 deletions
5
.changeset/nervous-fireants-design.md
Normal file
5
.changeset/nervous-fireants-design.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'generator-verdaccio-plugin': major
|
||||
---
|
||||
|
||||
feat: migration to monorepo
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -53,3 +53,6 @@ e2e/ui/cypress/screenshots/**/*
|
|||
|
||||
# storybook
|
||||
packages/ui-components/storybook-static
|
||||
|
||||
# plugin generator
|
||||
packages/tools/generator-verdaccio-plugin/generators/
|
||||
|
|
|
@ -61,6 +61,9 @@
|
|||
"@types/http-errors": "2.0.4",
|
||||
"@types/jest": "29.5.11",
|
||||
"@types/jsonwebtoken": "9.0.5",
|
||||
"@types/yeoman-environment": "2.10.11",
|
||||
"@types/yeoman-generator": "5.2.14",
|
||||
"@types/yeoman-test": "4.0.6",
|
||||
"@types/lodash": "4.14.202",
|
||||
"@types/mime": "3.0.4",
|
||||
"@types/minimatch": "5.1.2",
|
||||
|
@ -127,7 +130,7 @@
|
|||
"verdaccio-auth-memory": "workspace:*",
|
||||
"verdaccio-htpasswd": "workspace:*",
|
||||
"verdaccio-memory": "workspace:*",
|
||||
"vitest": "0.34.6"
|
||||
"vitest": "1.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "husky install",
|
||||
|
|
3
packages/tools/generator-verdaccio-plugin/.babelrc
Normal file
3
packages/tools/generator-verdaccio-plugin/.babelrc
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "../../../.babelrc"
|
||||
}
|
41
packages/tools/generator-verdaccio-plugin/README.md
Normal file
41
packages/tools/generator-verdaccio-plugin/README.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
# Plugin Generator
|
||||
|
||||
[![verdaccio (latest)](https://img.shields.io/npm/v/generator-verdaccio-plugin/latest.svg)](https://www.npmjs.com/package/generator-verdaccio-plugin)
|
||||
[![verdaccio (downloads)](https://img.shields.io/npm/dy/generator-verdaccio-plugin.svg)](https://www.npmjs.com/package/generator-verdaccio-plugin)
|
||||
[![docker pulls](https://img.shields.io/docker/pulls/verdaccio/verdaccio.svg?maxAge=43200)](https://verdaccio.org/docs/en/docker.html)
|
||||
[![Backers](https://opencollective.com/verdaccio/tiers/backer/badge.svg?label=Backer&color=brightgreen)](https://opencollective.com/verdaccio)
|
||||
[![Stackshare](https://img.shields.io/badge/Follow%20on-StackShare-blue.svg?logo=stackshare&style=flat)](https://stackshare.io/verdaccio)
|
||||
[![Discord](https://img.shields.io/discord/388674437219745793?logo=discord)](http://chat.verdaccio.org/)
|
||||
[![Twitter followers](https://img.shields.io/twitter/follow/verdaccio_npm.svg?style=social&label=Follow)](https://twitter.com/verdaccio_npm)
|
||||
|
||||
Verdaccio plugin generator based in [Yeoman](http://yeoman.io) aims to help to scaffold plugins development
|
||||
|
||||
## Installation
|
||||
|
||||
First, install [Yeoman](http://yeoman.io) and generator-verdaccio-plugin using [npm](https://www.npmjs.com/) (we assume you have pre-installed [node.js](https://nodejs.org/)).
|
||||
|
||||
```bash
|
||||
npm install -g yo
|
||||
npm install -g generator-verdaccio-plugin
|
||||
```
|
||||
|
||||
Then generate your new project:
|
||||
|
||||
```bash
|
||||
yo verdaccio-plugin
|
||||
```
|
||||
|
||||
## Plugin Types Supported
|
||||
|
||||
- Authentication
|
||||
- Storage
|
||||
- Middleware
|
||||
|
||||
### Maintainers
|
||||
|
||||
- [Anix](https://github.com/anikethsaha)
|
||||
- [Juan Picado](https://github.com/juanpicado)
|
||||
|
||||
## License
|
||||
|
||||
MIT © [Juan Picado <@jotadeveloper>]()
|
|
@ -0,0 +1,11 @@
|
|||
const defaultConfigFiles = [
|
||||
'jest.config.js',
|
||||
'.editorconfig',
|
||||
'.gitignore',
|
||||
'package.json',
|
||||
'README.md',
|
||||
'.eslintrc',
|
||||
'.npmignore',
|
||||
];
|
||||
|
||||
module.exports = defaultConfigFiles;
|
3
packages/tools/generator-verdaccio-plugin/jest.config.js
Normal file
3
packages/tools/generator-verdaccio-plugin/jest.config.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
const config = require('../../../jest/config');
|
||||
|
||||
module.exports = Object.assign({}, config, {});
|
49
packages/tools/generator-verdaccio-plugin/package.json
Normal file
49
packages/tools/generator-verdaccio-plugin/package.json
Normal file
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "generator-verdaccio-plugin",
|
||||
"version": "4.1.0",
|
||||
"description": "plugin generator for verdaccio",
|
||||
"homepage": "https://github.com/verdaccio",
|
||||
"author": {
|
||||
"name": "Juan Picado <@jotadeveloper>",
|
||||
"email": "juanpicado19@gmail.com",
|
||||
"url": "https://github.com/verdaccio/generator-verdaccio-plugin"
|
||||
},
|
||||
"files": [
|
||||
"generators"
|
||||
],
|
||||
"keywords": [
|
||||
"verdaccio-plugin",
|
||||
"yeoman-generator"
|
||||
],
|
||||
"dependencies": {
|
||||
"chalk": "4.1.2",
|
||||
"lodash": "4.17.21",
|
||||
"yeoman-environment": "3.19.3",
|
||||
"yeoman-generator": "5.9.0",
|
||||
"yosay": "2.0.2",
|
||||
"@verdaccio/core": "workspace:7.0.0-next-7.16",
|
||||
"@verdaccio/config": "workspace:7.0.0-next-7.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/test-helper": "workspace:3.0.0-next-7.2",
|
||||
"@verdaccio/types": "workspace:12.0.0-next-7.3",
|
||||
"ts-jest": "29.1.0",
|
||||
"yeoman-assert": "3.1.1",
|
||||
"yeoman-test": "6.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">18.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/verdaccio/generator-verdaccio-plugin"
|
||||
},
|
||||
"scripts": {
|
||||
"type-check": "tsc --noEmit -p tsconfig.build.json",
|
||||
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
|
||||
"build": "babel src/ --out-dir generators/ --copy-files --extensions \".ts,.tsx\" --source-maps --ignore src/app/templates",
|
||||
"test": "vitest run --pool=forks",
|
||||
"lint": "eslint --max-warnings 0 \"**/*.{js,ts}\""
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
179
packages/tools/generator-verdaccio-plugin/src/app/index.ts
Normal file
179
packages/tools/generator-verdaccio-plugin/src/app/index.ts
Normal file
|
@ -0,0 +1,179 @@
|
|||
import chalk from 'chalk';
|
||||
import _ from 'lodash';
|
||||
import { resolve } from 'path';
|
||||
import Generator from 'yeoman-generator';
|
||||
import yosay from 'yosay';
|
||||
|
||||
type propsTypes = {
|
||||
name?: string;
|
||||
pluginType?: string;
|
||||
description?: string;
|
||||
githubUsername?: string;
|
||||
authorName?: string;
|
||||
authorEmail?: string;
|
||||
keywords?: string[];
|
||||
};
|
||||
|
||||
class PluginGenerator extends Generator {
|
||||
private props: propsTypes;
|
||||
private projectName = 'verdaccio-';
|
||||
private destinationPathName = 'verdaccio-';
|
||||
constructor(args, opts) {
|
||||
super(args, opts);
|
||||
this.props = {};
|
||||
}
|
||||
|
||||
prompting() {
|
||||
this.log(yosay(`Welcome to ${chalk.red('generator-verdaccio-plugin')} plugin generator!`));
|
||||
|
||||
const prompts = [
|
||||
{
|
||||
type: 'list',
|
||||
name: 'pluginType',
|
||||
require: true,
|
||||
message: 'What kind of plugin you want to create?',
|
||||
store: true,
|
||||
choices: [{ value: 'auth' }, { value: 'storage' }, { value: 'middleware' }],
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
require: true,
|
||||
message: `What's the plugin name? The prefix (verdaccio-xxx) will be added automatically`,
|
||||
default: 'customname',
|
||||
validate: function (input: string) {
|
||||
if (input.startsWith('verdaccio-')) {
|
||||
return false;
|
||||
} else if (input === '') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'description',
|
||||
message: 'Please, describe your plugin',
|
||||
default: 'An amazing verdaccio plugin',
|
||||
},
|
||||
{
|
||||
name: 'githubUsername',
|
||||
message: 'GitHub username or Organization',
|
||||
validate: function (input) {
|
||||
return input !== '';
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'authorName',
|
||||
message: "Author's Name",
|
||||
store: true,
|
||||
},
|
||||
{
|
||||
name: 'authorEmail',
|
||||
message: "Author's Email",
|
||||
store: true,
|
||||
},
|
||||
{
|
||||
name: 'keywords',
|
||||
message: 'Key your keywords (comma to split)',
|
||||
filter: function (keywords) {
|
||||
return _.uniq(_.words(keywords).concat(['verdaccio-']));
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return this.prompt(prompts).then(
|
||||
function (_props) {
|
||||
// To access props later use this.props.someAnswer;
|
||||
// @ts-ignore
|
||||
this.props = _props;
|
||||
const { name, githubUsername } = _props;
|
||||
// @ts-ignore
|
||||
this.props.license = 'MIT';
|
||||
if (githubUsername) {
|
||||
// @ts-ignore
|
||||
this.props.repository = githubUsername + '/' + name;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
this.projectName = `verdaccio-${name}`;
|
||||
|
||||
// @ts-ignore
|
||||
this.destinationPathName = resolve(this.projectName);
|
||||
// @ts-ignore
|
||||
this.props.name = this.projectName;
|
||||
}.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
packageJSON() {
|
||||
const { pluginType } = this.props;
|
||||
const pkgJsonLocation = `${pluginType}/_package.json`;
|
||||
this.fs.copyTpl(
|
||||
this.templatePath(pkgJsonLocation),
|
||||
this.destinationPath(resolve(this.destinationPathName, 'package.json')),
|
||||
this.props
|
||||
);
|
||||
}
|
||||
|
||||
writing() {
|
||||
this.fs.copy(
|
||||
this.templatePath(`common/gitignore`),
|
||||
this.destinationPath(resolve(this.destinationPathName, '.gitignore'))
|
||||
);
|
||||
this.fs.copy(
|
||||
this.templatePath(`common/npmignore`),
|
||||
this.destinationPath(resolve(this.destinationPathName, '.npmignore'))
|
||||
);
|
||||
this.fs.copy(
|
||||
this.templatePath(`common/jest.config.js`),
|
||||
this.destinationPath(resolve(this.destinationPathName, 'jest.config.js'))
|
||||
);
|
||||
this.fs.copyTpl(
|
||||
this.templatePath(`common/README.md`),
|
||||
this.destinationPath(resolve(this.destinationPathName, 'README.md')),
|
||||
this.props
|
||||
);
|
||||
this.fs.copyTpl(
|
||||
this.templatePath(`common/eslintrc`),
|
||||
this.destinationPath(resolve(this.destinationPathName, '.eslintrc')),
|
||||
this.props
|
||||
);
|
||||
this.fs.copyTpl(
|
||||
this.templatePath(`common/eslintignore`),
|
||||
this.destinationPath(resolve(this.destinationPathName, '.eslintignore')),
|
||||
this.props
|
||||
);
|
||||
|
||||
this.fs.copy(
|
||||
this.templatePath(`${this.props.pluginType}/src`),
|
||||
this.destinationPath(resolve(this.destinationPathName, 'src'))
|
||||
);
|
||||
|
||||
this.fs.copy(
|
||||
this.templatePath(`common/index.js`),
|
||||
this.destinationPath(resolve(this.destinationPathName, `index.js`))
|
||||
);
|
||||
|
||||
this.fs.copy(
|
||||
this.templatePath(`common/tsconfig.json`),
|
||||
this.destinationPath(resolve(this.destinationPathName, 'tsconfig.json'))
|
||||
);
|
||||
this.fs.copy(
|
||||
this.templatePath(`${this.props.pluginType}/types`),
|
||||
this.destinationPath(resolve(this.destinationPathName, 'types'))
|
||||
);
|
||||
|
||||
this.fs.copy(
|
||||
this.templatePath(`common/editorconfig`),
|
||||
this.destinationPath(resolve(this.destinationPathName, '.editorconfig'))
|
||||
);
|
||||
}
|
||||
|
||||
install() {
|
||||
process.chdir(this.projectName);
|
||||
// this.installDependencies({ npm: true, bower: false });
|
||||
}
|
||||
}
|
||||
|
||||
export default PluginGenerator;
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": 0
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "<%= name %>",
|
||||
"version": "0.0.1",
|
||||
"description": "<%= description %>",
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/commons-api": "10.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/node": "12.12.5",
|
||||
"@types/express": "4.17.13",
|
||||
"@typescript-eslint/eslint-plugin": "5.26.0",
|
||||
"@typescript-eslint/parser": "5.26.0",
|
||||
"@verdaccio/types": "10.5.2",
|
||||
"eslint": "8.21.0",
|
||||
"jest": "28.1.3",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
"keywords": ["<%= keywords %>]"],
|
||||
"license": "<%= license %>",
|
||||
"repository": "<%= repository %>",
|
||||
"author": "<%= authorName %> <<%= authorEmail %>>",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest .",
|
||||
"lint": "eslint \"**/*.{js,ts}\""
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
import { getInternalError } from '@verdaccio/commons-api';
|
||||
import {
|
||||
AuthAccessCallback,
|
||||
AuthCallback,
|
||||
IPluginAuth,
|
||||
Logger,
|
||||
PackageAccess,
|
||||
PluginOptions,
|
||||
RemoteUser,
|
||||
} from '@verdaccio/types';
|
||||
|
||||
import { CustomConfig } from '../types/index';
|
||||
|
||||
/**
|
||||
* Custom Verdaccio Authenticate Plugin.
|
||||
*/
|
||||
export default class AuthCustomPlugin implements IPluginAuth<CustomConfig> {
|
||||
public logger: Logger;
|
||||
private foo: string;
|
||||
public constructor(config: CustomConfig, options: PluginOptions<CustomConfig>) {
|
||||
this.logger = options.logger;
|
||||
this.foo = config.foo;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Authenticate an user.
|
||||
* @param user user to log
|
||||
* @param password provided password
|
||||
* @param cb callback function
|
||||
*/
|
||||
public authenticate(user: string, password: string, cb: AuthCallback): void {
|
||||
/**
|
||||
* This code is just an example for demostration purpose
|
||||
if (this.foo) {
|
||||
cb(null, ['group-foo', 'group-bar']);
|
||||
} else {
|
||||
cb(getInternalError("error, try again"), false);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered on each access request
|
||||
* @param user
|
||||
* @param pkg
|
||||
* @param cb
|
||||
*/
|
||||
public allow_access(user: RemoteUser, pkg: PackageAccess, cb: AuthAccessCallback): void {
|
||||
/**
|
||||
* This code is just an example for demostration purpose
|
||||
if (user.name === this.foo && pkg?.access?.includes[user.name]) {
|
||||
this.logger.debug({name: user.name}, 'your package has been granted for @{name}');
|
||||
cb(null, true)
|
||||
} else {
|
||||
this.logger.error({name: user.name}, '@{name} is not allowed to access this package');
|
||||
cb(getInternalError("error, try again"), false);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered on each publish request
|
||||
* @param user
|
||||
* @param pkg
|
||||
* @param cb
|
||||
*/
|
||||
public allow_publish(user: RemoteUser, pkg: PackageAccess, cb: AuthAccessCallback): void {
|
||||
/**
|
||||
* This code is just an example for demostration purpose
|
||||
if (user.name === this.foo && pkg?.access?.includes[user.name]) {
|
||||
this.logger.debug({name: user.name}, '@{name} has been granted to publish');
|
||||
cb(null, true)
|
||||
} else {
|
||||
this.logger.error({name: user.name}, '@{name} is not allowed to publish this package');
|
||||
cb(getInternalError("error, try again"), false);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public allow_unpublish(user: RemoteUser, pkg: PackageAccess, cb: AuthAccessCallback): void {
|
||||
/**
|
||||
* This code is just an example for demostration purpose
|
||||
if (user.name === this.foo && pkg?.access?.includes[user.name]) {
|
||||
this.logger.debug({name: user.name}, '@{name} has been granted to unpublish');
|
||||
cb(null, true)
|
||||
} else {
|
||||
this.logger.error({name: user.name}, '@{name} is not allowed to publish this package');
|
||||
cb(getInternalError("error, try again"), false);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { Config } from '@verdaccio/types';
|
||||
|
||||
export interface CustomConfig extends Config {
|
||||
foo: string;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
# <%= name %>
|
||||
|
||||
<%- (description || '').split('\n').map(function (line) {
|
||||
return '> ' + line
|
||||
}).join('\n') %>
|
||||
|
||||
---
|
||||
|
||||
## development
|
||||
|
||||
See the [verdaccio contributing guide](https://github.com/verdaccio/verdaccio/blob/master/CONTRIBUTING.md) for instructions setting up your development environment.
|
||||
Once you have completed that, use the following npm tasks.
|
||||
|
||||
- `npm run build`
|
||||
|
||||
Build a distributable archive
|
||||
|
||||
- `npm run test`
|
||||
|
||||
Run unit test
|
||||
|
||||
For more information about any of these commands run `npm run ${task} -- --help`.
|
|
@ -0,0 +1,12 @@
|
|||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# 2 space indentation
|
||||
[{.,}*.{js,yml,yaml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
lib/
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
npm-debug.log*
|
||||
node_modules
|
||||
/lib/
|
|
@ -0,0 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true,
|
||||
});
|
||||
exports.default = void 0;
|
||||
|
||||
let _index = _interopRequireDefault(require('./lib/index'));
|
||||
|
||||
function _interopRequireDefault(obj) {
|
||||
return obj && obj.__esModule ? obj : { default: obj };
|
||||
}
|
||||
|
||||
let _default = _index.default;
|
||||
exports.default = _default;
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
name: 'verdaccio-<%= name %>',
|
||||
preset: 'ts-jest',
|
||||
};
|
|
@ -0,0 +1,2 @@
|
|||
src/
|
||||
.eslintrc
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"allowJs": false,
|
||||
"noImplicitAny": false,
|
||||
"strict": true,
|
||||
"outDir": "./lib",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["src/*.ts", "types/*.ts"]
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "<%= name %>",
|
||||
"version": "0.0.1",
|
||||
"description": "<%= description %>",
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/commons-api": "10.2.0",
|
||||
"express": "4.18.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/node": "12.12.5",
|
||||
"@types/express": "4.17.13",
|
||||
"@typescript-eslint/eslint-plugin": "5.26.0",
|
||||
"@typescript-eslint/parser": "5.26.0",
|
||||
"@verdaccio/types": "10.5.2",
|
||||
"eslint": "8.21.0",
|
||||
"jest": "28.1.3",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
"keywords": ["<%= keywords %>"],
|
||||
"license": "<%= license %>",
|
||||
"repository": "<%= repository %>",
|
||||
"author": "<%= authorName %> <<%= authorEmail %>>",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest .",
|
||||
"lint": "eslint \"**/*.{js,ts}\""
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
import { Application, NextFunction, Request, Response, Router } from 'express';
|
||||
|
||||
import {
|
||||
IBasicAuth,
|
||||
IPluginMiddleware,
|
||||
IStorageManager,
|
||||
Logger,
|
||||
PluginOptions,
|
||||
} from '@verdaccio/types';
|
||||
|
||||
import { CustomConfig } from '../types/index';
|
||||
|
||||
export default class VerdaccioMiddlewarePlugin implements IPluginMiddleware<CustomConfig> {
|
||||
public logger: Logger;
|
||||
public foo: string;
|
||||
public constructor(config: CustomConfig, options: PluginOptions<CustomConfig>) {
|
||||
this.foo = config.foo !== undefined ? config.strict_ssl : true;
|
||||
this.logger = options.logger;
|
||||
}
|
||||
|
||||
public register_middlewares(
|
||||
app: Application,
|
||||
auth: IBasicAuth<CustomConfig>,
|
||||
/* eslint @typescript-eslint/no-unused-vars: off */
|
||||
_storage: IStorageManager<CustomConfig>
|
||||
): void {
|
||||
/**
|
||||
* This is just an example of implementation
|
||||
// eslint new-cap:off
|
||||
const router = Router();
|
||||
router.post(
|
||||
'/custom-endpoint',
|
||||
(req: Request, res: Response & { report_error?: Function }, next: NextFunction): void => {
|
||||
const encryptedString = auth.aesEncrypt(Buffer.from(this.foo, 'utf8'));
|
||||
res.setHeader('X-Verdaccio-Token-Plugin', encryptedString.toString());
|
||||
next();
|
||||
}
|
||||
);
|
||||
app.use('/-/npm/something-new', router);
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { Config } from '@verdaccio/types';
|
||||
|
||||
export interface CustomConfig extends Config {
|
||||
foo: string;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "<%= name %>",
|
||||
"version": "0.0.1",
|
||||
"description": "<%= description %>",
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/commons-api": "10.2.0",
|
||||
"@verdaccio/streams": "10.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/node": "12.12.5",
|
||||
"@types/express": "4.17.13",
|
||||
"@typescript-eslint/eslint-plugin": "5.32.0",
|
||||
"@typescript-eslint/parser": "5.32.0",
|
||||
"@verdaccio/types": "10.5.2",
|
||||
"eslint": "8.21.0",
|
||||
"jest": "28.1.3",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
"keywords": ["<%= keywords %>"],
|
||||
"license": "<%= license %>",
|
||||
"repository": "<%= repository %>",
|
||||
"author": "<%= authorName %> <<%= authorEmail %>>",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest .",
|
||||
"lint": "eslint \"**/*.{js,ts}\""
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
import { getConflict, getInternalError, getNotFound } from '@verdaccio/commons-api';
|
||||
import { ReadTarball, UploadTarball } from '@verdaccio/streams';
|
||||
import {
|
||||
Callback,
|
||||
CallbackAction,
|
||||
ILocalPackageManager,
|
||||
Logger,
|
||||
Package,
|
||||
PackageTransformer,
|
||||
ReadPackageCallback,
|
||||
StorageUpdateCallback,
|
||||
StorageWriteCallback,
|
||||
} from '@verdaccio/types';
|
||||
|
||||
import { CustomConfig } from '../types/index';
|
||||
|
||||
export default class StoragePluginManage implements ILocalPackageManager {
|
||||
public logger: Logger;
|
||||
public packageName: string;
|
||||
public config: CustomConfig;
|
||||
|
||||
public constructor(config: CustomConfig, packageName: string, logger: Logger) {
|
||||
this.logger = logger;
|
||||
this.packageName = packageName;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a metadata update and
|
||||
* @param name
|
||||
* @param updateHandler
|
||||
* @param onWrite
|
||||
* @param transformPackage
|
||||
* @param onEnd
|
||||
*/
|
||||
public updatePackage(
|
||||
name: string,
|
||||
updateHandler: StorageUpdateCallback,
|
||||
onWrite: StorageWriteCallback,
|
||||
transformPackage: PackageTransformer,
|
||||
onEnd: CallbackAction
|
||||
): void {
|
||||
/**
|
||||
* Example of implementation:
|
||||
this.customStore.get().then((pkg: Package) => {
|
||||
updateHandler(pkg, function onUpdateFinish(err) {
|
||||
if (err) {
|
||||
onEnd(err);
|
||||
} else {
|
||||
onWrite(name, pkg, onEnd);
|
||||
}
|
||||
})
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a specific file (tarball or package.json)
|
||||
* @param fileName
|
||||
* @param callback
|
||||
*/
|
||||
public deletePackage(fileName: string, callback: CallbackAction): void {
|
||||
/**
|
||||
* Example of implementation:
|
||||
this.customStore.delete(fileName, (err) => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a package (folder, path)
|
||||
* This happens after all versions ar tarballs have been removed.
|
||||
* @param callback
|
||||
*/
|
||||
public removePackage(callback: CallbackAction): void {
|
||||
/**
|
||||
* Example of implementation:
|
||||
this.customStore.removePackage((err) => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a new package (version).
|
||||
* @param name
|
||||
* @param data
|
||||
* @param callback
|
||||
*/
|
||||
public createPackage(name: string, data: Package, callback: CallbackAction): void {
|
||||
/**
|
||||
* Example of implementation:
|
||||
* this.customStore.create(name, data).then(err => {
|
||||
if (err.notFound) {
|
||||
callback(getNotFound());
|
||||
} else if (err.alreadyExist) {
|
||||
callback(getConflict());
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform write anobject to the storage.
|
||||
* Similar to updatePackage but without middleware handlers
|
||||
* @param pkgName package name
|
||||
* @param pkg package metadata
|
||||
* @param callback
|
||||
*/
|
||||
public savePackage(pkgName: string, pkg: Package, callback: CallbackAction): void {
|
||||
/*
|
||||
Example of implementation:
|
||||
this.cumstomStore.write(pkgName, pkgName).then(data => {
|
||||
callback(null);
|
||||
}).catch(err => {
|
||||
callback(getInternalError(err.message));
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a package from storage
|
||||
* @param pkgName package name
|
||||
* @param callback
|
||||
*/
|
||||
public readPackage(pkgName: string, callback: ReadPackageCallback): void {
|
||||
/**
|
||||
* Example of implementation:
|
||||
* this.customStorage.read(name, (err, pkg: Package) => {
|
||||
if (err.fooError) {
|
||||
callback(getInternalError(err))
|
||||
} else if (err.barError) {
|
||||
callback(getNotFound());
|
||||
} else {
|
||||
callback(null, pkg)
|
||||
}
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Create writtable stream (write a tarball)
|
||||
* @param name
|
||||
*/
|
||||
public writeTarball(name: string): UploadTarball {
|
||||
/**
|
||||
* Example of implementation:
|
||||
* const stream = new UploadTarball({});
|
||||
return stream;
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a readable stream (read a from a tarball)
|
||||
* @param name
|
||||
*/
|
||||
public readTarball(name: string): ReadTarball {
|
||||
/**
|
||||
* Example of implementation:
|
||||
* const stream = new ReadTarball({});
|
||||
return stream;
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export { default } from './plugin';
|
|
@ -0,0 +1,134 @@
|
|||
import { getInternalError } from '@verdaccio/commons-api';
|
||||
import {
|
||||
Callback,
|
||||
Config,
|
||||
IPackageStorage,
|
||||
IPluginStorage,
|
||||
Logger,
|
||||
PluginOptions,
|
||||
Token,
|
||||
TokenFilter,
|
||||
onEndSearchPackage,
|
||||
onSearchPackage,
|
||||
onValidatePackage,
|
||||
} from '@verdaccio/types';
|
||||
|
||||
import { CustomConfig } from '../types/index';
|
||||
import PackageStorage from './PackageStorage';
|
||||
|
||||
export default class VerdaccioStoragePlugin implements IPluginStorage<CustomConfig> {
|
||||
config: CustomConfig & Config;
|
||||
version?: string;
|
||||
public logger: Logger;
|
||||
public constructor(config: CustomConfig, options: PluginOptions<CustomConfig>) {
|
||||
this.config = config;
|
||||
this.logger = options.logger;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public async getSecret(): Promise<string> {
|
||||
/**
|
||||
* return await resolveSecret();
|
||||
*/
|
||||
}
|
||||
|
||||
public async setSecret(secret: string): Promise<any> {
|
||||
/**
|
||||
* return await getYourSecret();
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new element.
|
||||
* @param {*} name
|
||||
* @return {Error|*}
|
||||
*/
|
||||
public add(name: string, callback: Callback): void {}
|
||||
|
||||
/**
|
||||
* Perform a search in your registry
|
||||
* @param onPackage
|
||||
* @param onEnd
|
||||
* @param validateName
|
||||
*/
|
||||
public search(
|
||||
onPackage: onSearchPackage,
|
||||
onEnd: onEndSearchPackage,
|
||||
validateName: onValidatePackage
|
||||
): void {
|
||||
/**
|
||||
* Example of implementation:
|
||||
* try {
|
||||
* someApi.getPackages((items) => {
|
||||
* items.map(() => {
|
||||
* if (validateName(item.name)) {
|
||||
* onPackage(item);
|
||||
* }
|
||||
* });
|
||||
* onEnd();
|
||||
* } catch(err) {
|
||||
* onEnd(err);
|
||||
* }
|
||||
* });
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an element from the database.
|
||||
* @param {*} name
|
||||
* @return {Error|*}
|
||||
*/
|
||||
public remove(name: string, callback: Callback): void {
|
||||
/**
|
||||
* Example of implementation
|
||||
database.getPackage(name, (item, err) => {
|
||||
if (err) {
|
||||
callback(getInternalError('your own message here'));
|
||||
}
|
||||
|
||||
// if all goes well we return nothing
|
||||
callback(null);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all database elements.
|
||||
* @return {Array}
|
||||
*/
|
||||
public get(callback: Callback): void {
|
||||
/*
|
||||
Example of implementation
|
||||
database.getAll((allItems, err) => {
|
||||
callback(err, allItems);
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the `PackageStorage`
|
||||
* @param packageInfo
|
||||
*/
|
||||
public getPackageStorage(packageInfo: string): IPackageStorage {
|
||||
return new PackageStorage(this.config, packageInfo, this.logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* All methods for npm token support
|
||||
* more info here https://github.com/verdaccio/verdaccio/pull/1427
|
||||
*/
|
||||
|
||||
public saveToken(token: Token): Promise<any> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
public deleteToken(user: string, tokenKey: string): Promise<any> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
public readTokens(filter: TokenFilter): Promise<Token[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { Config } from '@verdaccio/types';
|
||||
|
||||
export interface CustomConfig extends Config {
|
||||
foo: string;
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { beforeEach, describe, test } from 'vitest';
|
||||
import assert from 'yeoman-assert';
|
||||
import helpers from 'yeoman-test';
|
||||
|
||||
import constants from '../helpers/constants';
|
||||
|
||||
describe('template generator', function () {
|
||||
// jest.setTimeout(10000);
|
||||
const name = 'test';
|
||||
const description = 'An amazing verdaccio plugin';
|
||||
const githubUsername = 'testing';
|
||||
const authorName = 'test';
|
||||
const authorEmail = 'test';
|
||||
const keywords = ['verdaccio, plugin, typescript'];
|
||||
const license = 'MIT';
|
||||
const repository = 'verdaccio/generator-test';
|
||||
const getBuildAsset = (tempRoot, item) => {
|
||||
const prefixPath = path.join(tempRoot, `/verdaccio-${name}`);
|
||||
return `${prefixPath}/${item}`;
|
||||
};
|
||||
|
||||
describe('generate app', function () {
|
||||
let tempRoot;
|
||||
|
||||
beforeEach(() => {
|
||||
tempRoot = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'generator-app'));
|
||||
});
|
||||
|
||||
const lang = 'typescript';
|
||||
|
||||
test('should check storage files', async function (done) {
|
||||
helpers
|
||||
.run(path.join(__dirname, '../src/app'))
|
||||
.cd(tempRoot)
|
||||
.withPrompts({
|
||||
name,
|
||||
lang,
|
||||
pluginType: 'storage',
|
||||
description,
|
||||
githubUsername,
|
||||
authorName,
|
||||
authorEmail,
|
||||
keywords,
|
||||
license,
|
||||
repository,
|
||||
})
|
||||
.then(function () {
|
||||
assert.file([
|
||||
...constants.map((item) => getBuildAsset(tempRoot, item)),
|
||||
getBuildAsset(tempRoot, '/index.js'),
|
||||
getBuildAsset(tempRoot, '/types/index.ts'),
|
||||
getBuildAsset(tempRoot, '/tsconfig.json'),
|
||||
getBuildAsset(tempRoot, '/src/index.ts'),
|
||||
getBuildAsset(tempRoot, '/src/plugin.ts'),
|
||||
getBuildAsset(tempRoot, '/src/PackageStorage.ts'),
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should check auth files', function (done) {
|
||||
helpers
|
||||
.run(path.join(__dirname, '../src/app'))
|
||||
.inDir(tempRoot)
|
||||
.withPrompts({
|
||||
name,
|
||||
lang,
|
||||
pluginType: 'auth',
|
||||
description,
|
||||
githubUsername,
|
||||
authorName,
|
||||
authorEmail,
|
||||
keywords,
|
||||
license,
|
||||
repository,
|
||||
})
|
||||
.then(function () {
|
||||
assert.file([
|
||||
...constants.map((item) => getBuildAsset(tempRoot, item)),
|
||||
getBuildAsset(tempRoot, '/src/index.ts'),
|
||||
getBuildAsset(tempRoot, '/index.js'),
|
||||
getBuildAsset(tempRoot, '/types/index.ts'),
|
||||
getBuildAsset(tempRoot, '/tsconfig.json'),
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('should check middleware files', function (done) {
|
||||
helpers
|
||||
.run(path.join(__dirname, '../src/app'))
|
||||
.inDir(tempRoot)
|
||||
.withPrompts({
|
||||
name,
|
||||
lang,
|
||||
pluginType: 'middleware',
|
||||
description,
|
||||
githubUsername,
|
||||
authorName,
|
||||
authorEmail,
|
||||
keywords,
|
||||
license,
|
||||
repository,
|
||||
})
|
||||
.then(function () {
|
||||
assert.file([
|
||||
...constants.map((item) => getBuildAsset(tempRoot, item)),
|
||||
getBuildAsset(tempRoot, '/src/index.ts'),
|
||||
getBuildAsset(tempRoot, '/index.js'),
|
||||
getBuildAsset(tempRoot, '/types/index.ts'),
|
||||
getBuildAsset(tempRoot, '/tsconfig.json'),
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./build",
|
||||
"noImplicitAny": false
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["src/**/*.test.ts"]
|
||||
}
|
17
packages/tools/generator-verdaccio-plugin/tsconfig.json
Normal file
17
packages/tools/generator-verdaccio-plugin/tsconfig.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.reference.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./build",
|
||||
"noImplicitAny": false
|
||||
},
|
||||
"include": ["src/**/*.ts", "types/*.d.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../config"
|
||||
},
|
||||
{
|
||||
"path": "../utils"
|
||||
}
|
||||
]
|
||||
}
|
2462
pnpm-lock.yaml
2462
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue