Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add fastify install command #696

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Fastify command line interface, available commands are:
* print-plugins prints the representation of the internal plugin tree used by avvio, useful for debugging.
* version the current fastify-cli version
* help help about commands
* install install Fastify plugins

Launch 'fastify help [command]' to know more about the commands.

Expand Down
14 changes: 8 additions & 6 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const generateSwagger = require('./generate-swagger')
const generateReadme = require('./generate-readme')
const printRoutes = require('./print-routes')
const printPlugins = require('./print-plugins')
const installPlugins = require('./install-plugins')
commist.register('start', start.cli)
commist.register('eject', eject.cli)
commist.register('generate', generate.cli)
Expand All @@ -29,16 +30,17 @@ commist.register('version', function () {
})
commist.register('print-routes', printRoutes.cli)
commist.register('print-plugins', printPlugins.cli)
commist.register('install', installPlugins.cli)

if (argv.help) {
const command = argv._.splice(2)[0]

help.toStdout(command)
} else {
const res = commist.parse(process.argv.splice(2))

if (res) {
// no command was recognized
help.toStdout(res)
}
commist.parseAsync(process.argv.splice(2)).then(res => {
if (res) {
// no command was recognized
help.toStdout(res)
}
})
}
1 change: 1 addition & 0 deletions help/help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ Fastify command line interface available commands are:
* print-plugins prints the representation of the internal plugin tree used by avvio, useful for debugging.
* version the current fastify-cli version
* help help about commands
* install install Fastify plugins

Launch 'fastify help [command]' to learn more about each command.
9 changes: 9 additions & 0 deletions help/install.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Usage: fastify install <FOLDER>

Launches an interactive CLI application that allows you to browse and install Fastify plugins.
Requires an existing `package.json` file in the specified folder.

OPTS

--search, -s
search for plugins containing the given word
244 changes: 244 additions & 0 deletions install-plugins.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
'use strict'

const argv = require('yargs-parser')
const { existsSync } = require('node:fs')
const { join } = require('node:path')
const log = require('./log')
const { prompt } = require('inquirer')
const { readFile, writeFile } = require('node:fs/promises')
const cliPkg = require('./package')
const chalk = require('chalk')

const kTopics ='topics'

const corePlugins = {
'authentication/authorization': {
[kTopics]: [
"auth",
"jwt",
"session",
"passport",
"authentication",
"authorization"
],
'@fastify/basic-auth': '@fastify/basic-auth: Basic auth plugin for Fastify. See https://github.com/fastify/fastify-basic-auth for more.',
'@fastify/bearer-auth': '@fastify/bearer-auth: Bearer auth plugin for Fastify. See https://github.com/fastify/fastify-bearer-auth for more.',
'@fastify/auth': '@fastify/auth: Run multiple auth functions in Fastify. See https://github.com/fastify/fastify-auth for more.',
'@fastify/jwt': '@fastify/jwt: JWT utils for Fastify, internally uses fast-jwt. See https://github.com/fastify/fastify-jwt for more.',
'@fastify/oauth2': '@fastify/oauth2: Wrap around simple-oauth2. See https://github.com/fastify/fastify-oauth2 for more.',
'@fastify/passport': '@fastify/passport: Use Passport strategies to authenticate requests and protect route. See https://github.com/fastify/fastify-passport for more.',
'@fastify/secure-session': '@fastify/secure-session: Create a secure stateless cookie session for Fastify. See https://github.com/fastify/fastify-secure-session for more.',
'@fastify/session': '@fastify/session: a session plugin for Fastify. See https://github.com/fastify/session for more.'
},
security: {
[kTopics]: [
"security",
"helmet",
"rate-limit",
"csrf"
],
'@fastify/csrf-protection': '@fastify/csrf-protection: A plugin for adding [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) protection to Fastify. See https://github.com/fastify/csrf-protection for more.',
'@fastify/helmet': '@fastify/helmet: Important security headers for Fastify. See https://github.com/fastify/fastify-helmet for more.',
'@fastify/rate-limit': '@fastify/rate-limit: A low overhead rate limiter for your routes. See https://github.com/fastify/fastify-rate-limit for more.',
'@fastify/cors': '@fastify/cors: Enables the use of CORS in a Fastify application. See https://github.com/fastify/fastify-cors for more.',
},
'database connection': {
[kTopics]: [
"sql",
"db",
"database",
"nosql"
],
'@fastify/mongodb': '@fastify/mongodb: Fastify MongoDB connection plugin, with which you can share the same MongoDB connection pool across every part of your server. See https://github.com/fastify/fastify-mongodb for more.',
'@fastify/leveldb': '@fastify/leveldb: Plugin to share a common LevelDB connection across Fastify. See https://github.com/fastify/fastify-leveldb for more.',
'@fastify/elasticsearch': '@fastify/elasticsearch: Plugin to share the same ES client. See https://github.com/fastify/fastify-elasticsearch for more.',
'@fastify/kafka': '@fastify/kafka: Plugin to interact with Apache Kafka. See https://github.com/fastify/fastify-kafka for more.',
'@fastify/mysql': '@fastify/mysql: Fastify MySQL connection plugin. See https://github.com/fastify/fastify-mysql for more.',
'@fastify/postgres': '@fastify/postgres: Fastify PostgreSQL connection plugin, with this you can share the same PostgreSQL connection pool in every part of your server. See https://github.com/fastify/fastify-postgres for more.',
'@fastify/redis': '@fastify/redis: Fastify Redis connection plugin, with which you can share the same Redis connection across every part of your server. See https://github.com/fastify/fastify-redis for more.'
},
'HTTP utility': {
[kTopics]: [
"http",
"caching",
"etag",
"compress",
"proxy",
"forward"
],
'@fastify/accepts': '@fastify/accepts: to have accepts in your request object. See https://github.com/fastify/fastify-accepts for more.',
'@fastify/accepts-serializer': '@fastify/accepts-serializer: to serialize to output according to the Accept header. See https://github.com/fastify/fastify-accepts-serializer for more.',
'@fastify/caching': '@fastify/caching: General server-side cache and ETag support. See https://github.com/fastify/fastify-caching for more.',
'@fastify/circuit-breaker': '@fastify/circuit-breaker: A low overhead circuit breaker for your routes. See https://github.com/fastify/fastify-circuit-breaker for more.',
'@fastify/compress': '@fastify/compress: Fastify compression utils. See https://github.com/fastify/fastify-compress for more.',
'@fastify/cookie': '@fastify/cookie: Parse and set cookie headers. See https://github.com/fastify/fastify-cookie for more.',
'@fastify/early-hints': '@fastify/early-hints: Plugin to add HTTP 103 feature based on RFC 8297. See https://github.com/fastify/fastify-early-hints for more.',
'@fastify/etag': '@fastify/etag: Automatically generate ETags for HTTP responses. See https://github.com/fastify/fastify-etag for more.',
'@fastify/flash': '@fastify/flash: Set and get flash messages using the session. See https://github.com/fastify/fastify-flash for more.',
'@fastify/formbody': '@fastify/formbody: Plugin to parse x-www-form-urlencoded bodies. See https://github.com/fastify/fastify-formbody for more.',
'@fastify/http-proxy': '@fastify/http-proxy: Proxy your HTTP requests to another server, with hooks. See https://github.com/fastify/fastify-http-proxy for more.',
'@fastify/multipart': '@fastify/multipart: Multipart support for Fastify. See https://github.com/fastify/fastify-multipart for more.',
'@fastify/reply-from': '@fastify/reply-from: Plugin to forward the current HTTP request to another server. See https://github.com/fastify/fastify-reply-from for more.',
'@fastify/sensible': '@fastify/sensible: Defaults for Fastify that everyone can agree on. It adds some useful decorators such as HTTP errors and assertions, but also more request and reply methods. See https://github.com/fastify/fastify-sensible for more.'
},
utilities: {
'@fastify/any-schema': '@fastify/any-schema: Save multiple schemas and decide which one to use to serialize the payload See https://github.com/fastify/any-schema-you-like for more.',
'@fastify/autoload': '@fastify/autoload: Require all plugins in a directory. See https://github.com/fastify/fastify-autoload for more.',
'@fastify/awilix': '@fastify/awilix: Dependency injection support for Fastify, based on awilix. See https://github.com/fastify/fastify-awilix for more.',
'@fastify/diagnostics-channel': '@fastify/diagnostics-channel: Plugin to deal with diagnostics_channel on Fastify See https://github.com/fastify/fastify-diagnostics-channel for more.',
'@fastify/env': '@fastify/env: Load and check configuration. See https://github.com/fastify/fastify-env for more.',
'@fastify/funky': '@fastify/funky: Makes functional programming in Fastify more convenient. Adds support for Fastify routes returning functional structures, such as Either, Task or plain parameterless function. See https://github.com/fastify/fastify-funky for more.',
'@fastify/hotwire': '@fastify/hotwire: Use the Hotwire pattern with Fastify. See https://github.com/fastify/fastify-hotwire for more.',
'@fastify/nextjs': '@fastify/nextjs: React server-side rendering support for Fastify with [Next](https://github.com/zeit/next.js/). See https://github.com/fastify/fastify-nextjs for more.',
'@fastify/one-line-logger': '@fastify/one-line-logger: Formats Fastify\'s logs into a nice one-line message. See https://github.com/fastify/one-line-logger for more.',
'@fastify/request-context': '@fastify/request-context: Request-scoped storage, based on AsyncLocalStorage (with fallback to cls-hooked), providing functionality similar to thread-local storages. See https://github.com/fastify/fastify-request-context for more.',
'@fastify/response-validation': '@fastify/response-validation: A simple plugin that enables response validation for Fastify. See https://github.com/fastify/fastify-response-validation for more.',
'@fastify/routes': '@fastify/routes: Plugin that provides a Map of routes. See https://github.com/fastify/fastify-routes for more.',
'@fastify/routes-stats': '@fastify/routes-stats: Provide stats for routes using node:perf_hooks. See https://github.com/fastify/fastify-routes-stats for more.',
'@fastify/schedule': '@fastify/schedule: Plugin for scheduling periodic jobs, based on [toad-scheduler](https://github.com/kibertoad/toad-scheduler). See https://github.com/fastify/fastify-schedule for more.',
'@fastify/soap-client': '@fastify/soap-client: a SOAP client plugin for Fastify. See https://github.com/fastify/fastify-soap-client for more.',
'@fastify/static': '@fastify/static: Plugin for serving static files as fast as possible. See https://github.com/fastify/fastify-static for more.',
'@fastify/swagger': '@fastify/swagger: Plugin for serving Swagger/OpenAPI documentation for Fastify, supporting dynamic generation. See https://github.com/fastify/fastify-swagger for more.',
'@fastify/swagger-ui': '@fastify/swagger-ui: Plugin for serving Swagger UI. See https://github.com/fastify/fastify-swagger-ui for more.',
'@fastify/throttle': '@fastify/throttle: Plugin for throttling the download speed of a request. See https://github.com/fastify/fastify-throttle for more.',
'@fastify/under-pressure': '@fastify/under-pressure: Measure process load with automatic handling of _"Service Unavailable"_ plugin for Fastify. See https://github.com/fastify/under-pressure for more.',
'@fastify/url-data': '@fastify/url-data: Decorate the Request object with a method to access raw URL components. See https://github.com/fastify/fastify-url-data for more.',
'@fastify/view': '@fastify/view: Templates rendering (ejs, pug, handlebars, marko) plugin support for Fastify. See https://github.com/fastify/point-of-view for more.',
'@fastify/vite': '@fastify/vite: Integration with Vite, allows for serving SPA/MPA/SSR Vite applications. See https://github.com/fastify/fastify-vite for more.',
'@fastify/websocket': '@fastify/websocket: WebSocket support for Fastify. Built upon ws. See https://github.com/fastify/fastify-websocket for more.'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be downloading this from a public resource, and not duplicate the data here. Otherwise maintaining this would be problematic.

cc @Fdawgs @Eomm, where do you think it would be better to have this metadata? Could it be part of the website?

},
serverless: {
[kTopics]: [
"aws",
"serverless"
],
'@fastify/aws-lambda': '@fastify/aws-lambda: allows you to easily build serverless web applications/services and RESTful APIs using Fastify on top of AWS Lambda and Amazon API Gateway. See https://github.com/fastify/aws-lambda-fastify for more.'
},
compatibility: {
[kTopics]: [
"compatibility",
"express"
],
'@fastify/middie': '@fastify/middie: Middleware engine for Fastify. See https://github.com/fastify/middie for more.',
'@fastify/express': '@fastify/express: Express compatibility layer for Fastify. See https://github.com/fastify/fastify-express for more.'
},
TypeScript: {
[kTopics]: [
"types",
"typescript"
],
'@fastify/type-provider-json-schema-to-ts': '@fastify/type-provider-json-schema-to-ts: Fastify type provider for json-schema-to-ts. See https://github.com/fastify/fastify-type-provider-json-schema-to-ts for more.',
'@fastify/type-provider-typebox': '@fastify/type-provider-typebox: Fastify type provider for Typebox. See https://github.com/fastify/fastify-type-provider-typebox for more.'
}
}

const categories = Object.keys(corePlugins)

async function generate (dir, plugins) {
process.chdir(dir)

const raw = await readFile('package.json', 'utf8')
const pkg = JSON.parse(raw)

const dependencies = {}
for (const p of plugins) {
dependencies[p] = cliPkg.devDependencies[p]
}

pkg.dependencies = Object.assign(pkg.dependencies || {}, dependencies)

log('debug', 'updated package.json, saving')

await writeFile('package.json', JSON.stringify(pkg, null, 2))

log('debug', `run '${chalk.bold('npm install')}' to install the dependencies`)
}

async function cli (args) {
const opts = argv(args)
const dir = opts._[0] || '.'
const searchFor = opts.s || opts.search

if (!existsSync(join(dir, 'package.json'))) {
log('error', 'a package.json file must already exist')
process.exit(1)
}

const pluginsToBeInstalled = []

if (searchFor) {
log('info', `Search for plugins that match '${searchFor}'...`)

const includePaths = []

for(const category of categories) {
if (corePlugins[category][kTopics]?.some(topic => topic.includes(searchFor))) {
for(const [name, _] of Object.entries(corePlugins[category])) {
if (name !== kTopics) {
includePaths.push([category, name])
}
}
} else {
for(const [name, desc] of Object.entries(corePlugins[category])) {
if (desc.includes(searchFor) && name !== kTopics) {
includePaths.push([category, name])
}
}
}
}

if (includePaths.length === 0) {
log('info', `No plugins were found.`)
} else {
const res = await prompt({
type: 'checkbox',
message: 'Select plugins',
name: 'plugins',
choices: includePaths.map(([category, name]) => { return { name: corePlugins[category][name], value: name } })
})

pluginsToBeInstalled.push(...res.plugins)
}

} else {
for (const category of categories) {
const res1 = await prompt({ message: `Install ${category} plugins?`, type: 'confirm', name: 'answer' })

if (res1.answer) {
const res2 = await prompt({
type: 'checkbox',
message: 'Select plugins',
name: 'plugins',
choices: Object.entries(corePlugins[category]).filter(([name, _]) => name !== kTopics).map(([name, desc]) => { return { name: desc, value: name } })
})

pluginsToBeInstalled.push(...res2.plugins)
}
}
}

if (pluginsToBeInstalled.length > 0) {
const res = await prompt({
type: 'confirm',
name: 'answer',
message: `Should ${pluginsToBeInstalled.join(', ')} be added as dependencies in '${join(dir, 'package.json')}'?`
})

if (res.answer) {
await generate(dir, pluginsToBeInstalled)
} else {
log('info', 'No plugins will be added.')
}
} else {
log('info', 'No plugins will be installed.')
}
}

module.exports = {
generate,
cli
}

if (require.main === module) {
cli(process.argv.slice(2))
}
65 changes: 63 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"fastify-plugin": "^4.0.0",
"generify": "^4.0.0",
"help-me": "^4.0.1",
"inquirer": "^8.2.6",
"is-docker": "^2.0.0",
"make-promises-safe": "^5.1.0",
"pino-pretty": "^10.1.0",
Expand All @@ -71,9 +72,69 @@
"yargs-parser": "^21.1.1"
},
"devDependencies": {
"@fastify/autoload": "^5.0.0",
"@fastify/accepts": "^4.3.0",
"@fastify/accepts-serializer": "^5.2.0",
"@fastify/any-schema": "^3.1.0",
"@fastify/auth": "^4.4.0",
"@fastify/autoload": "^5.8.0",
"@fastify/awilix": "^4.0.0",
"@fastify/aws-lambda": "^3.5.0",
"@fastify/basic-auth": "^5.1.1",
"@fastify/bearer-auth": "^9.3.0",
"@fastify/caching": "^8.3.0",
"@fastify/circuit-breaker": "^3.2.0",
"@fastify/compress": "^6.5.0",
"@fastify/cookie": "^9.2.0",
"@fastify/cors": "^8.5.0",
"@fastify/csrf-protection": "^6.4.1",
"@fastify/diagnostics-channel": "^4.2.0",
"@fastify/early-hints": "^1.0.1",
"@fastify/elasticsearch": "^3.1.0",
"@fastify/env": "^4.3.0",
"@fastify/etag": "^5.1.0",
"@fastify/express": "^2.3.0",
"@fastify/flash": "^5.1.0",
"@fastify/formbody": "^7.4.0",
"@fastify/funky": "^3.1.0",
"@fastify/helmet": "^11.1.1",
"@fastify/hotwire": "^2.1.0",
"@fastify/http-proxy": "^9.3.0",
"@fastify/jwt": "^8.0.0",
"@fastify/kafka": "^2.2.1",
"@fastify/leveldb": "^5.1.0",
"@fastify/middie": "^8.3.0",
"@fastify/mongodb": "^8.0.0",
"@fastify/multipart": "^8.1.0",
"@fastify/mysql": "^4.2.0",
"@fastify/nextjs": "^10.0.1",
"@fastify/oauth2": "^7.8.0",
"@fastify/one-line-logger": "^1.2.0",
"@fastify/passport": "^2.4.0",
"@fastify/postgres": "^5.2.2",
"@fastify/pre-commit": "^2.0.2",
"@fastify/sensible": "^5.0.0",
"@fastify/rate-limit": "^9.1.0",
"@fastify/redis": "^6.1.1",
"@fastify/reply-from": "^9.7.0",
"@fastify/request-context": "^5.1.0",
"@fastify/response-validation": "^2.5.1",
"@fastify/routes": "^5.1.0",
"@fastify/routes-stats": "^3.4.0",
"@fastify/schedule": "^4.1.1",
"@fastify/secure-session": "^7.1.0",
"@fastify/sensible": "^5.5.0",
"@fastify/session": "^10.7.0",
"@fastify/soap-client": "^2.2.0",
"@fastify/static": "^6.12.0",
"@fastify/swagger": "^8.13.0",
"@fastify/swagger-ui": "^2.0.1",
"@fastify/throttle": "^2.0.1",
"@fastify/type-provider-json-schema-to-ts": "^2.2.2",
"@fastify/type-provider-typebox": "^4.0.0",
"@fastify/under-pressure": "^8.3.0",
"@fastify/url-data": "^5.4.0",
"@fastify/view": "^8.2.0",
"@fastify/vite": "^5.0.6",
"@fastify/websocket": "^8.3.1",
"@types/node": "^20.4.4",
"@types/tap": "^15.0.5",
"c8": "^9.0.0",
Expand Down
Loading