Skip to content

Commit 44172d9

Browse files
authored
feat(schema): Make schemas validation library independent and add TypeBox support (#2772)
1 parent b1844b1 commit 44172d9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1702
-1061
lines changed

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"update-dependencies": "ncu -u && lerna exec -- ncu -u -x node-fetch -x chalk -x axios",
3535
"clean": "find . -name node_modules -exec rm -rf '{}' + && find . -name package-lock.json -exec rm -rf '{}' +",
3636
"test:deno": "deno test --config deno/tsconfig.json deno/test.ts",
37-
"test": "npm run lint && npm run compile && c8 lerna run test"
37+
"test": "npm run lint && npm run compile && c8 lerna run test --ignore @feathersjs/tests"
3838
},
3939
"devDependencies": {
4040
"@typescript-eslint/eslint-plugin": "^5.39.0",
Lines changed: 2 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FromSchema } from '@feathersjs/schema'
1+
import { FromSchema, authenticationSettingsSchema } from '@feathersjs/schema'
22

33
export const defaultOptions = {
44
authStrategies: [] as string[],
@@ -11,115 +11,6 @@ export const defaultOptions = {
1111
}
1212
}
1313

14-
export const authenticationSettingsSchema = {
15-
type: 'object',
16-
required: ['secret', 'entity', 'authStrategies'],
17-
properties: {
18-
secret: {
19-
type: 'string',
20-
description: 'The JWT signing secret'
21-
},
22-
entity: {
23-
oneOf: [
24-
{
25-
type: 'null'
26-
},
27-
{
28-
type: 'string'
29-
}
30-
],
31-
description: 'The name of the authentication entity (e.g. user)'
32-
},
33-
entityId: {
34-
type: 'string',
35-
description: 'The name of the authentication entity id property'
36-
},
37-
service: {
38-
type: 'string',
39-
description: 'The path of the entity service'
40-
},
41-
authStrategies: {
42-
type: 'array',
43-
items: { type: 'string' },
44-
description: 'A list of authentication strategy names that are allowed to create JWT access tokens'
45-
},
46-
parseStrategies: {
47-
type: 'array',
48-
items: { type: 'string' },
49-
description:
50-
'A list of authentication strategy names that should parse HTTP headers for authentication information (defaults to `authStrategies`)'
51-
},
52-
jwtOptions: {
53-
type: 'object'
54-
},
55-
jwt: {
56-
type: 'object',
57-
properties: {
58-
header: {
59-
type: 'string',
60-
default: 'Authorization',
61-
description: 'The HTTP header containing the JWT'
62-
},
63-
schemes: {
64-
type: 'array',
65-
items: { type: 'string' },
66-
description: 'An array of schemes to support'
67-
}
68-
}
69-
},
70-
local: {
71-
type: 'object',
72-
required: ['usernameField', 'passwordField'],
73-
properties: {
74-
usernameField: {
75-
type: 'string',
76-
description: 'Name of the username field (e.g. `email`)'
77-
},
78-
passwordField: {
79-
type: 'string',
80-
description: 'Name of the password field (e.g. `password`)'
81-
},
82-
hashSize: {
83-
type: 'number',
84-
description: 'The BCrypt salt length'
85-
},
86-
errorMessage: {
87-
type: 'string',
88-
default: 'Invalid login',
89-
description: 'The error message to return on errors'
90-
},
91-
entityUsernameField: {
92-
type: 'string',
93-
description:
94-
'Name of the username field on the entity if authentication request data and entity field names are different'
95-
},
96-
entityPasswordField: {
97-
type: 'string',
98-
description:
99-
'Name of the password field on the entity if authentication request data and entity field names are different'
100-
}
101-
}
102-
},
103-
oauth: {
104-
type: 'object',
105-
properties: {
106-
redirect: {
107-
type: 'string'
108-
},
109-
origins: {
110-
type: 'array',
111-
items: { type: 'string' }
112-
},
113-
defaults: {
114-
type: 'object',
115-
properties: {
116-
key: { type: 'string' },
117-
secret: { type: 'string' }
118-
}
119-
}
120-
}
121-
}
122-
}
123-
} as const
14+
export { authenticationSettingsSchema }
12415

12516
export type AuthenticationConfiguration = FromSchema<typeof authenticationSettingsSchema>

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"@feathersjs/koa": "^5.0.0-pre.29",
7070
"@feathersjs/mongodb": "^5.0.0-pre.29",
7171
"@feathersjs/schema": "^5.0.0-pre.29",
72+
"@feathersjs/typebox": "^5.0.0-pre.29",
7273
"@feathersjs/socketio": "^5.0.0-pre.29",
7374
"@feathersjs/transport-commons": "^5.0.0-pre.29",
7475
"@types/mocha": "^10.0.0",

packages/cli/src/app/index.ts

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,14 @@ export const generate = (ctx: AppGeneratorArguments) =>
7070
type: 'input',
7171
when: !ctx.name,
7272
message: 'What is the name of your application?',
73-
default: ctx.cwd.split(sep).pop()
73+
default: ctx.cwd.split(sep).pop(),
74+
validate: (input) => {
75+
if (ctx.dependencyVersions[input]) {
76+
return `Application can not have the same name as a dependency`
77+
}
78+
79+
return true
80+
}
7481
},
7582
{
7683
name: 'description',
@@ -109,37 +116,44 @@ export const generate = (ctx: AppGeneratorArguments) =>
109116
{ value: 'pnpm', name: 'pnpm' }
110117
]
111118
},
119+
{
120+
type: 'list',
121+
name: 'schema',
122+
when: !ctx.schema,
123+
message: 'What is your preferred schema (model) definition format?',
124+
choices: [
125+
{ value: 'typebox', name: `TypeBox ${chalk.grey('(recommended)')}` },
126+
{ value: 'json', name: 'JSON schema' }
127+
]
128+
},
112129
...connectionPrompts(ctx),
113130
...authenticationPrompts({
114131
...ctx,
115-
service: 'users',
132+
service: 'user',
133+
path: 'users',
116134
entity: 'user'
117135
})
118136
])
119137
)
120138
.then(runGenerators(__dirname, 'templates'))
121139
.then(copyFiles(fromFile(__dirname, 'static'), toFile('.')))
122140
.then(initializeBaseContext())
123-
.then(
124-
when<AppGeneratorContext>(
125-
({ authStrategies }) => authStrategies.length > 0,
126-
async (ctx) => {
127-
const { dependencies } = await connectionGenerator(ctx)
141+
.then(async (ctx) => {
142+
const { dependencies } = await connectionGenerator(ctx)
128143

129-
return {
130-
...ctx,
131-
dependencies
132-
}
133-
}
134-
)
135-
)
144+
return {
145+
...ctx,
146+
dependencies
147+
}
148+
})
136149
.then(
137150
when<AppGeneratorContext>(
138151
({ authStrategies }) => authStrategies.length > 0,
139152
async (ctx) => {
140153
const { dependencies } = await authenticationGenerator({
141154
...ctx,
142-
service: 'users',
155+
service: 'user',
156+
path: 'users',
143157
entity: 'user'
144158
})
145159

@@ -152,7 +166,7 @@ export const generate = (ctx: AppGeneratorArguments) =>
152166
)
153167
.then(
154168
install<AppGeneratorContext>(
155-
({ transports, framework, dependencyVersions, dependencies }) => {
169+
({ transports, framework, dependencyVersions, dependencies, schema }) => {
156170
const hasSocketio = transports.includes('websockets')
157171

158172
dependencies.push(
@@ -177,6 +191,10 @@ export const generate = (ctx: AppGeneratorArguments) =>
177191
dependencies.push('@feathersjs/express', 'compression')
178192
}
179193

194+
if (schema === 'typebox') {
195+
dependencies.push('@feathersjs/typebox')
196+
}
197+
180198
return addVersions(dependencies, dependencyVersions)
181199
},
182200
false,

packages/cli/src/app/templates/app.tpl.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@ import { koa, rest, bodyParser, errorHandler, parseAuthentication, cors } from '
99
${transports.includes('websockets') ? "import socketio from '@feathersjs/socketio'" : ''}
1010
1111
import type { Application } from './declarations'
12-
import { configurationSchema } from './configuration'
12+
import { configurationValidator } from './schemas/configuration'
1313
import { logErrorHook } from './logger'
1414
import { services } from './services/index'
1515
import { channels } from './channels'
1616
1717
const app: Application = koa(feathers())
1818
1919
// Load our app configuration (see config/ folder)
20-
app.configure(configuration(configurationSchema))
20+
app.configure(configuration(configurationValidator))
2121
2222
// Set up Koa middleware
23+
app.use(cors())
2324
app.use(serveStatic(app.get('public')))
2425
app.use(errorHandler())
25-
app.use(cors())
2626
app.use(parseAuthentication())
2727
app.use(bodyParser())
2828
@@ -69,15 +69,15 @@ import configuration from '@feathersjs/configuration'
6969
${transports.includes('websockets') ? "import socketio from '@feathersjs/socketio'" : ''}
7070
7171
import type { Application } from './declarations'
72-
import { configurationSchema } from './configuration'
72+
import { configurationValidator } from './schemas/configuration'
7373
import { logger, logErrorHook } from './logger'
7474
import { services } from './services/index'
7575
import { channels } from './channels'
7676
7777
const app: Application = express(feathers())
7878
7979
// Load app configuration
80-
app.configure(configuration(configurationSchema))
80+
app.configure(configuration(configurationValidator))
8181
app.use(cors())
8282
app.use(compress())
8383
app.use(json())

packages/cli/src/app/templates/client.tpl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const template = ({}: AppGeneratorContext) => /* ts */ `import { feathers } from
66
import type { Paginated, ClientService, TransportConnection, Params } from '@feathersjs/feathers'
77
88
export interface ServiceTypes {
9-
// A mapping of client side services
9+
//
1010
}
1111
1212
export const createClient = <Configuration = any> (connection: TransportConnection<ServiceTypes>) => {

packages/cli/src/app/templates/configuration.tpl.ts

Lines changed: 0 additions & 49 deletions
This file was deleted.

packages/cli/src/app/templates/declarations.tpl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ const template = ({
55
framework
66
}: AppGeneratorContext) => /* ts */ `import { HookContext as FeathersHookContext, NextFunction } from '@feathersjs/feathers'
77
import { Application as FeathersApplication } from '@feathersjs/${framework}'
8-
import { ConfigurationSchema } from './configuration'
8+
import { ApplicationConfiguration } from './schemas/configuration'
99
1010
export { NextFunction }
1111
12-
export interface Configuration extends ConfigurationSchema {}
12+
export interface Configuration extends ApplicationConfiguration {}
1313
1414
// A mapping of service names to types. Will be extended in service files.
1515
export interface ServiceTypes {}

0 commit comments

Comments
 (0)