mirror of
https://github.com/eliasrenman/gardentron.git
synced 2026-03-16 20:46:07 +01:00
chore: setup featherjs project
This commit is contained in:
121
server/.gitignore
vendored
Normal file
121
server/.gitignore
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
.env.production
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
.sqlite
|
||||
|
||||
lib/
|
||||
121
server/.npmignore
Normal file
121
server/.npmignore
Normal file
@@ -0,0 +1,121 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
.env.production
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
.sqlite
|
||||
|
||||
lib/
|
||||
9
server/.prettierrc
Normal file
9
server/.prettierrc
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"printWidth": 110,
|
||||
"semi": false,
|
||||
"trailingComma": "none",
|
||||
"singleQuote": true,
|
||||
"parser": "typescript"
|
||||
}
|
||||
10
server/config/custom-environment-variables.json
Normal file
10
server/config/custom-environment-variables.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"port": {
|
||||
"__name": "PORT",
|
||||
"__format": "number"
|
||||
},
|
||||
"host": "HOSTNAME",
|
||||
"authentication": {
|
||||
"secret": "FEATHERS_SECRET"
|
||||
}
|
||||
}
|
||||
17
server/config/default.json
Normal file
17
server/config/default.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"host": "localhost",
|
||||
"port": 3030,
|
||||
"public": "./public/",
|
||||
"origins": [
|
||||
"http://localhost:3030"
|
||||
],
|
||||
"paginate": {
|
||||
"default": 10,
|
||||
"max": 50
|
||||
},
|
||||
"sqlite": {
|
||||
"client": "sqlite3",
|
||||
"connection": "server.sqlite",
|
||||
"useNullAsDefault": true
|
||||
}
|
||||
}
|
||||
3
server/config/test.json
Normal file
3
server/config/test.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"port": 8998
|
||||
}
|
||||
7
server/knexfile.ts
Normal file
7
server/knexfile.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/databases.html
|
||||
import { app } from './src/app'
|
||||
|
||||
// Load our database connection info from the app configuration
|
||||
const config = app.get('sqlite')
|
||||
|
||||
module.exports = config
|
||||
10
server/node_modules/.yarn-integrity
generated
vendored
Normal file
10
server/node_modules/.yarn-integrity
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"systemParams": "linux-x64-108",
|
||||
"modulesFolders": [],
|
||||
"flags": [],
|
||||
"linkedModules": [],
|
||||
"topLevelPatterns": [],
|
||||
"lockfileEntries": {},
|
||||
"files": [],
|
||||
"artifacts": {}
|
||||
}
|
||||
48
server/package.json
Normal file
48
server/package.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "server",
|
||||
"description": "The server for handling two way communication with a iot Device",
|
||||
"version": "0.0.0",
|
||||
"homepage": "",
|
||||
"private": true,
|
||||
"keywords": [
|
||||
"feathers"
|
||||
],
|
||||
"author": {},
|
||||
"contributors": [],
|
||||
"bugs": {},
|
||||
"engines": {
|
||||
"node": ">= 18.16.0"
|
||||
},
|
||||
"feathers": {
|
||||
"language": "ts",
|
||||
"packager": "yarn",
|
||||
"database": "sqlite",
|
||||
"framework": "koa",
|
||||
"transports": [
|
||||
"rest",
|
||||
"websockets"
|
||||
],
|
||||
"schema": "typebox"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "src",
|
||||
"test": "test"
|
||||
},
|
||||
"files": [
|
||||
"lib/client.js",
|
||||
"lib/**/*.d.ts",
|
||||
"lib/**/*.shared.js"
|
||||
],
|
||||
"main": "lib/client",
|
||||
"scripts": {
|
||||
"dev": "nodemon -x ts-node src/index.ts",
|
||||
"compile": "shx rm -rf lib/ && tsc",
|
||||
"start": "node lib/",
|
||||
"prettier": "npx prettier \"**/*.ts\" --write",
|
||||
"mocha": "cross-env NODE_ENV=test mocha test/ --require ts-node/register --recursive --extension .ts --exit",
|
||||
"test": "cross-env NODE_ENV=test npm run migrate && npm run mocha",
|
||||
"bundle:client": "npm run compile && npm pack --pack-destination ./public",
|
||||
"migrate": "knex migrate:latest",
|
||||
"migrate:make": "knex migrate:make"
|
||||
}
|
||||
}
|
||||
37
server/public/index.html
Normal file
37
server/public/index.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>server</title>
|
||||
<meta name="description" content="The server for handling two way communication with a iot Device">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
img.logo {
|
||||
display: block;
|
||||
margin: auto auto;
|
||||
width: 30%;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img class="logo" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwMCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDI1NiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTEyOCA5LjEwMmM2NS42NjUgMCAxMTguODk4IDUzLjIzMyAxMTguODk4IDExOC44OTggMCA2NS42NjUtNTMuMjMzIDExOC44OTgtMTE4Ljg5OCAxMTguODk4QzYyLjMzNSAyNDYuODk4IDkuMTAyIDE5My42NjUgOS4xMDIgMTI4IDkuMTAyIDYyLjMzNSA2Mi4zMzUgOS4xMDIgMTI4IDkuMTAyTTEyOCAwQzU3LjQyMSAwIDAgNTcuNDIxIDAgMTI4YzAgNzAuNTc5IDU3LjQyMSAxMjggMTI4IDEyOCA3MC41NzkgMCAxMjgtNTcuNDIxIDEyOC0xMjhDMjU2IDU3LjQyMSAxOTguNTc5IDAgMTI4IDBtMjAuODMgMjUuNTI0Yy0xMC40My0xLjg5Ni0zNS42NTEgMzYuNDA5LTQzLjk5NCA1OS43MzQtLjYzNCAxLjc2OS0yLjA4NiA4LjI0OS0yLjA4NiA5Ljk1NSAwIDAgNi41MzEgMTQuMDU1IDguMzQzIDE3LjM1MS0zLjAzNC0xLjU4LTkuMzIzLTEzLjc1Ni05LjMyMy0xMy43NTYtMy4wMzQgNS43ODQtNS45NDIgMzIuMzQtNC45OTQgMzcuMjcxIDAgMCA2Ljc2MiAxMC4wNjIgOS4zODcgMTIuNTc4LTMuNjAzLTEuMjAxLTkuNjcxLTkuMzU1LTkuNjcxLTkuMzU1LTEuMTM4IDMuNTA4LS45MTYgMTAuODA3LS4zNzkgMTMuMjc0IDQuNTUxIDYuNjM3IDEwLjYxOSA3LjM5NiAxMC42MTkgNy4zOTZzLTYuNjM3IDY2LjE4MSAzLjQxMyA3MS4xMTFjNi4yNTgtMS4zMjcgNy43NzUtNzMuOTU2IDcuNzc1LTczLjk1NnM3LjU4NS41NjkgOS4yOTItMS4zMjdjMy44NTYtMi42NTUgMTIuODI2LTMwLjIyNCAxMi45NTgtMzQuMjAyIDAgMC0xMC40MSAxLjk1Mi0xNS40ODcgMy45MjQgMy44MjYtMy44IDE2LjA0OS02LjM1MiAxNi4wNDktNi4zNTIgMy4zMTUtMy45NzkgMTAuMjkxLTMxLjA0NyAxMC45OTQtMzkuMzkxLjE3Ni0yLjA5My41ODMtNC42NTcuMjY4LTguMzk4IDAgMC05Ljk0MSAyLjE3Ny0xMi4wMTQgMS40MjQgMi4xMDQtLjIzNyAxMi4yNjMtNC4xNCAxMi4yNjMtNC4xNCAxLjgwMS0xNi4yMTMgMi4zNTgtNDIuMDkxLTMuNDEzLTQzLjE0MXptLTM2LjM4IDE3MS42OTFjLS43OTUgMTkuNDk2LTEuMjk0IDI1LjAwNC0yLjExNSAyOS42MDEtLjM3OS44NTctLjc1OC45OTctMS4xMzgtLjA5NS0zLjQ3Ny0xNS45OTItMy4yMjQtMTM2LjQzOCAzNi40MDktMTkxLjI0MS0yMy4wNSA0Mi4wOTItMzMuNTM1IDEyMi44NjEtMzMuMTU2IDE2MS43MzV6IiBmaWxsPSIjMzMzIi8+PC9zdmc+" />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
42
server/readme.md
Normal file
42
server/readme.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# server
|
||||
|
||||
> The server for handling two way communication with a iot Device
|
||||
|
||||
## About
|
||||
|
||||
This project uses [Feathers](http://feathersjs.com). An open source framework for building APIs and real-time applications.
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Make sure you have [NodeJS](https://nodejs.org/) and [npm](https://www.npmjs.com/) installed.
|
||||
2. Install your dependencies
|
||||
|
||||
```
|
||||
cd path/to/server
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Start your app
|
||||
|
||||
```
|
||||
npm run compile # Compile TypeScript source
|
||||
npm run migrate # Run migrations to set up the database
|
||||
npm start
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Run `npm test` and all your tests in the `test/` directory will be run.
|
||||
|
||||
## Scaffolding
|
||||
|
||||
This app comes with a powerful command line interface for Feathers. Here are a few things it can do:
|
||||
|
||||
```
|
||||
$ npx feathers help # Show all commands
|
||||
$ npx feathers generate service # Generate a new Service
|
||||
```
|
||||
|
||||
## Help
|
||||
|
||||
For more information on all the things you can do with Feathers visit [docs.feathersjs.com](http://docs.feathersjs.com).
|
||||
54
server/src/app.ts
Normal file
54
server/src/app.ts
Normal 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
38
server/src/channels.ts
Normal 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
34
server/src/client.ts
Normal 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
|
||||
}
|
||||
17
server/src/configuration.ts
Normal file
17
server/src/configuration.ts
Normal 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)
|
||||
20
server/src/declarations.ts
Normal file
20
server/src/declarations.ts
Normal 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>
|
||||
18
server/src/hooks/log-error.ts
Normal file
18
server/src/hooks/log-error.ts
Normal 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
11
server/src/index.ts
Normal 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
10
server/src/logger.ts
Normal 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()]
|
||||
})
|
||||
6
server/src/services/index.ts
Normal file
6
server/src/services/index.ts
Normal 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
17
server/src/sqlite.ts
Normal 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
29
server/src/validators.ts
Normal 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
|
||||
)
|
||||
40
server/test/app.test.ts
Normal file
40
server/test/app.test.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/app.test.html
|
||||
import assert from 'assert'
|
||||
import axios from 'axios'
|
||||
import type { Server } from 'http'
|
||||
import { app } from '../src/app'
|
||||
|
||||
const port = app.get('port')
|
||||
const appUrl = `http://${app.get('host')}:${port}`
|
||||
|
||||
describe('Feathers application tests', () => {
|
||||
let server: Server
|
||||
|
||||
before(async () => {
|
||||
server = await app.listen(port)
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
await app.teardown()
|
||||
})
|
||||
|
||||
it('starts and shows the index page', async () => {
|
||||
const { data } = await axios.get<string>(appUrl)
|
||||
|
||||
assert.ok(data.indexOf('<html lang="en">') !== -1)
|
||||
})
|
||||
|
||||
it('shows a 404 JSON error', async () => {
|
||||
try {
|
||||
await axios.get(`${appUrl}/path/to/nowhere`, {
|
||||
responseType: 'json'
|
||||
})
|
||||
assert.fail('should never get here')
|
||||
} catch (error: any) {
|
||||
const { response } = error
|
||||
assert.strictEqual(response?.status, 404)
|
||||
assert.strictEqual(response?.data?.code, 404)
|
||||
assert.strictEqual(response?.data?.name, 'NotFound')
|
||||
}
|
||||
})
|
||||
})
|
||||
18
server/test/client.test.ts
Normal file
18
server/test/client.test.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import assert from 'assert'
|
||||
import axios from 'axios'
|
||||
import type { Server } from 'http'
|
||||
import { app } from '../src/app'
|
||||
import { createClient } from '../src/client'
|
||||
|
||||
import rest from '@feathersjs/rest-client'
|
||||
|
||||
const port = app.get('port')
|
||||
const appUrl = `http://${app.get('host')}:${port}`
|
||||
|
||||
describe('client tests', () => {
|
||||
const client = createClient(rest(appUrl).axios(axios))
|
||||
|
||||
it('initialized the client', () => {
|
||||
assert.ok(client)
|
||||
})
|
||||
})
|
||||
21
server/tsconfig.json
Normal file
21
server/tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"ts-node": {
|
||||
"files": true
|
||||
},
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"module": "commonjs",
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src",
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"test"
|
||||
]
|
||||
}
|
||||
4
server/yarn.lock
Normal file
4
server/yarn.lock
Normal file
@@ -0,0 +1,4 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user