feathersjs/feathers

View on GitHub
packages/generators/src/authentication/index.ts

Summary

Maintainability
A
1 hr
Test Coverage
import chalk from 'chalk'
import { dirname } from 'path'
import { runGenerators, prompt } from '@featherscloud/pinion'
import { fileURLToPath } from 'url'
import {
  addVersions,
  checkPreconditions,
  FeathersBaseContext,
  initializeBaseContext,
  install
} from '../commons.js'
import { generate as serviceGenerator, ServiceGeneratorContext } from '../service/index.js'

// Set __dirname in es module
const __dirname = dirname(fileURLToPath(import.meta.url))

export interface AuthenticationGeneratorContext extends ServiceGeneratorContext {
  service: string
  entity: string
  authStrategies: string[]
  dependencies: string[]
}

export type AuthenticationGeneratorArguments = FeathersBaseContext &
  Partial<Pick<AuthenticationGeneratorContext, 'service' | 'authStrategies' | 'path' | 'schema' | 'type'>>

export const generate = (ctx: AuthenticationGeneratorArguments) =>
  Promise.resolve(ctx)
    .then(initializeBaseContext())
    .then(checkPreconditions())
    .then(
      prompt((ctx: AuthenticationGeneratorArguments) => [
        {
          type: 'checkbox',
          name: 'authStrategies',
          when: !ctx.authStrategies,
          message: 'Which authentication methods do you want to use?',
          suffix: chalk.grey(' Other methods and providers can be added at any time.'),
          choices: [
            {
              name: 'Email + Password',
              value: 'local',
              checked: true
            },
            {
              name: 'Google',
              value: 'google'
            },
            {
              name: 'Facebook',
              value: 'facebook'
            },
            {
              name: 'Twitter',
              value: 'twitter'
            },
            {
              name: 'GitHub',
              value: 'github'
            },
            {
              name: 'Auth0',
              value: 'auth0'
            }
          ]
        },
        {
          name: 'service',
          type: 'input',
          when: !ctx.service,
          message: 'What is your authentication service name?',
          default: 'user'
        },
        {
          name: 'path',
          type: 'input',
          when: !ctx.path,
          message: 'What path should the service be registered on?',
          default: 'users'
        }
      ])
    )
    .then(async (ctx) => {
      const serviceContext = await serviceGenerator({
        ...ctx,
        name: ctx.service,
        isEntityService: true
      })

      return {
        ...ctx,
        entity: ctx.service,
        ...serviceContext
      }
    })
    .then(runGenerators(__dirname, 'templates'))
    .then((ctx) => ctx as AuthenticationGeneratorContext)
    .then((ctx) => {
      const dependencies: string[] = []

      dependencies.push('@feathersjs/authentication-oauth')

      if (ctx.authStrategies.includes('local')) {
        dependencies.push('@feathersjs/authentication-local')
      }

      if (ctx.dependencies) {
        return {
          ...ctx,
          dependencies: [...ctx.dependencies, ...dependencies]
        }
      }

      return install<AuthenticationGeneratorContext>(
        addVersions(dependencies, ctx.dependencyVersions),
        false,
        ctx.feathers.packager
      )(ctx)
    })