chore: setup featherjs project

This commit is contained in:
Elias Renman
2023-05-20 09:18:45 +02:00
parent ab69ce119a
commit 0040dc6384
26 changed files with 762 additions and 0 deletions

54
server/src/app.ts Normal file
View File

@@ -0,0 +1,54 @@
// For more information about this file see https://dove.feathersjs.com/guides/cli/application.html
import { feathers } from '@feathersjs/feathers'
import configuration from '@feathersjs/configuration'
import { koa, rest, bodyParser, errorHandler, parseAuthentication, cors, serveStatic } from '@feathersjs/koa'
import socketio from '@feathersjs/socketio'
import { configurationValidator } from './configuration'
import type { Application } from './declarations'
import { logError } from './hooks/log-error'
import { sqlite } from './sqlite'
import { services } from './services/index'
import { channels } from './channels'
const app: Application = koa(feathers())
// Load our app configuration (see config/ folder)
app.configure(configuration(configurationValidator))
// Set up Koa middleware
app.use(cors())
app.use(serveStatic(app.get('public')))
app.use(errorHandler())
app.use(parseAuthentication())
app.use(bodyParser())
// Configure services and transports
app.configure(rest())
app.configure(
socketio({
cors: {
origin: app.get('origins')
}
})
)
app.configure(channels)
app.configure(sqlite)
app.configure(services)
// Register hooks that run on all service methods
app.hooks({
around: {
all: [logError]
},
before: {},
after: {},
error: {}
})
// Register application setup and teardown hooks here
app.hooks({
setup: [],
teardown: []
})
export { app }

38
server/src/channels.ts Normal file
View File

@@ -0,0 +1,38 @@
// For more information about this file see https://dove.feathersjs.com/guides/cli/channels.html
import type { RealTimeConnection, Params } from '@feathersjs/feathers'
import type { AuthenticationResult } from '@feathersjs/authentication'
import '@feathersjs/transport-commons'
import type { Application, HookContext } from './declarations'
import { logger } from './logger'
export const channels = (app: Application) => {
logger.warn(
'Publishing all events to all authenticated users. See `channels.ts` and https://dove.feathersjs.com/api/channels.html for more information.'
)
app.on('connection', (connection: RealTimeConnection) => {
// On a new real-time connection, add it to the anonymous channel
app.channel('anonymous').join(connection)
})
app.on('login', (authResult: AuthenticationResult, { connection }: Params) => {
// connection can be undefined if there is no
// real-time connection, e.g. when logging in via REST
if (connection) {
// The connection is no longer anonymous, remove it
app.channel('anonymous').leave(connection)
// Add it to the authenticated user channel
app.channel('authenticated').join(connection)
}
})
// eslint-disable-next-line no-unused-vars
app.publish((data: any, context: HookContext) => {
// Here you can add event publishers to channels set up in `channels.js`
// To publish only for a specific event use `app.publish(eventname, () => {})`
// e.g. to publish all service events to all authenticated users use
return app.channel('authenticated')
})
}

34
server/src/client.ts Normal file
View File

@@ -0,0 +1,34 @@
// For more information about this file see https://dove.feathersjs.com/guides/cli/client.html
import { feathers } from '@feathersjs/feathers'
import type { TransportConnection, Application } from '@feathersjs/feathers'
import authenticationClient from '@feathersjs/authentication-client'
import type { AuthenticationClientOptions } from '@feathersjs/authentication-client'
export interface Configuration {
connection: TransportConnection<ServiceTypes>
}
export interface ServiceTypes {}
export type ClientApplication = Application<ServiceTypes, Configuration>
/**
* Returns a typed client for the server app.
*
* @param connection The REST or Socket.io Feathers client connection
* @param authenticationOptions Additional settings for the authentication client
* @see https://dove.feathersjs.com/api/client.html
* @returns The Feathers client application
*/
export const createClient = <Configuration = any>(
connection: TransportConnection<ServiceTypes>,
authenticationOptions: Partial<AuthenticationClientOptions> = {}
) => {
const client: ClientApplication = feathers()
client.configure(connection)
client.configure(authenticationClient(authenticationOptions))
client.set('connection', connection)
return client
}

View File

@@ -0,0 +1,17 @@
import { Type, getValidator, defaultAppConfiguration } from '@feathersjs/typebox'
import type { Static } from '@feathersjs/typebox'
import { dataValidator } from './validators'
export const configurationSchema = Type.Intersect([
defaultAppConfiguration,
Type.Object({
host: Type.String(),
port: Type.Number(),
public: Type.String()
})
])
export type ApplicationConfiguration = Static<typeof configurationSchema>
export const configurationValidator = getValidator(configurationSchema, dataValidator)

View File

@@ -0,0 +1,20 @@
// For more information about this file see https://dove.feathersjs.com/guides/cli/typescript.html
import { HookContext as FeathersHookContext, NextFunction } from '@feathersjs/feathers'
import { Application as FeathersApplication } from '@feathersjs/koa'
import { ApplicationConfiguration } from './configuration'
export { NextFunction }
// The types for app.get(name) and app.set(name)
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Configuration extends ApplicationConfiguration {}
// A mapping of service names to types. Will be extended in service files.
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface ServiceTypes {}
// The application instance type that will be used everywhere else
export type Application = FeathersApplication<ServiceTypes, Configuration>
// The context for hook functions - can be typed with a service class
export type HookContext<S = any> = FeathersHookContext<Application, S>

View File

@@ -0,0 +1,18 @@
// For more information about this file see https://dove.feathersjs.com/guides/cli/log-error.html
import type { HookContext, NextFunction } from '../declarations'
import { logger } from '../logger'
export const logError = async (context: HookContext, next: NextFunction) => {
try {
await next()
} catch (error: any) {
logger.error(error.stack)
// Log validation errors
if (error.data) {
logger.error('Data: %O', error.data)
}
throw error
}
}

11
server/src/index.ts Normal file
View File

@@ -0,0 +1,11 @@
import { app } from './app'
import { logger } from './logger'
const port = app.get('port')
const host = app.get('host')
process.on('unhandledRejection', (reason) => logger.error('Unhandled Rejection %O', reason))
app.listen(port).then(() => {
logger.info(`Feathers app listening on http://${host}:${port}`)
})

10
server/src/logger.ts Normal file
View File

@@ -0,0 +1,10 @@
// For more information about this file see https://dove.feathersjs.com/guides/cli/logging.html
import { createLogger, format, transports } from 'winston'
// Configure the Winston logger. For the complete documentation see https://github.com/winstonjs/winston
export const logger = createLogger({
// To see more detailed errors, change this to 'debug'
level: 'info',
format: format.combine(format.splat(), format.simple()),
transports: [new transports.Console()]
})

View File

@@ -0,0 +1,6 @@
// For more information about this file see https://dove.feathersjs.com/guides/cli/application.html#configure-functions
import type { Application } from '../declarations'
export const services = (app: Application) => {
// All services will be registered here
}

17
server/src/sqlite.ts Normal file
View File

@@ -0,0 +1,17 @@
// For more information about this file see https://dove.feathersjs.com/guides/cli/databases.html
import knex from 'knex'
import type { Knex } from 'knex'
import type { Application } from './declarations'
declare module './declarations' {
interface Configuration {
sqliteClient: Knex
}
}
export const sqlite = (app: Application) => {
const config = app.get('sqlite')
const db = knex(config!)
app.set('sqliteClient', db)
}

29
server/src/validators.ts Normal file
View File

@@ -0,0 +1,29 @@
// For more information about this file see https://dove.feathersjs.com/guides/cli/validators.html
import { Ajv, addFormats } from '@feathersjs/schema'
import type { FormatsPluginOptions } from '@feathersjs/schema'
const formats: FormatsPluginOptions = [
'date-time',
'time',
'date',
'email',
'hostname',
'ipv4',
'ipv6',
'uri',
'uri-reference',
'uuid',
'uri-template',
'json-pointer',
'relative-json-pointer',
'regex'
]
export const dataValidator: Ajv = addFormats(new Ajv({}), formats)
export const queryValidator: Ajv = addFormats(
new Ajv({
coerceTypes: true
}),
formats
)