diff --git a/package-lock.json b/package-lock.json index 4b222de9c2..f89d825d05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1698,25 +1698,26 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "engines": { - "node": ">= 12" - } - }, "node_modules/@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dependencies": { - "@cspotcode/source-map-consumer": "0.8.0" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { "node": ">=12" } }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -6128,9 +6129,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001341", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz", - "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==", + "version": "1.0.30001342", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001342.tgz", + "integrity": "sha512-bn6sOCu7L7jcbBbyNhLg0qzXdJ/PMbybZTH/BA6Roet9wxYRm6Tr9D0s0uhLkOZ6MSG+QU6txUgdpr3MXIVqjA==", "funding": [ { "type": "opencollective", @@ -6820,9 +6821,9 @@ "hasInstallScript": true }, "node_modules/core-js-compat": { - "version": "3.22.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.5.tgz", - "integrity": "sha512-rEF75n3QtInrYICvJjrAgV03HwKiYvtKHdPtaba1KucG+cNZ4NJnH9isqt979e67KZlhpbCOTwnsvnIr+CVeOg==", + "version": "3.22.6", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.6.tgz", + "integrity": "sha512-dQ/SxlHcuiywaPIoSUCU6Fx+Mk/H5TXENqd/ZJcK85ta0ZcQkbzHwblxPeL0hF5o+NsT2uK3q9ZOG5TboiVuWw==", "dependencies": { "browserslist": "^4.20.3", "semver": "7.0.0" @@ -13068,22 +13069,22 @@ } }, "node_modules/mongodb-memory-server": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-8.5.2.tgz", - "integrity": "sha512-+4/zxz9TxpPMxaUEm0axQvSf+tS6GtPyc5MEjwkiprBGsH7aTe9GEjuHKnXGP8ObarHFpgW3kV4C4oEzYvxQIQ==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-8.6.0.tgz", + "integrity": "sha512-4I3qpIN3Ls5Vs8CPIl7SiT/rQUYmpgP27csDqgkSY7fu09mEqT3ieIC7cRhgx8wuRKr3rTotKMP4G1+Qw7+9Kw==", "hasInstallScript": true, "dependencies": { - "mongodb-memory-server-core": "8.5.2", - "tslib": "^2.3.1" + "mongodb-memory-server-core": "8.6.0", + "tslib": "^2.4.0" }, "engines": { "node": ">=12.22.0" } }, "node_modules/mongodb-memory-server-core": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-8.5.2.tgz", - "integrity": "sha512-JVQWZ0ZRWsEeX23cAxhetaJ9q5eILU01dKHrJBwHmMc79BKLdUI2iyIiGve6vyyzYNh4amBcUiWpnbgLmiTlrQ==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-8.6.0.tgz", + "integrity": "sha512-vuJfoK1TUPKwmspRxvkMUod34BInHmWF6li3nXlQ9bvaA2Xg4p3GsTkplyuwTBkLgeLL9AwIU0rk3CDwKpym1w==", "dependencies": { "@types/tmp": "^0.2.3", "async-mutex": "^0.3.2", @@ -13098,7 +13099,7 @@ "semver": "^7.3.7", "tar-stream": "^2.1.4", "tmp": "^0.2.1", - "tslib": "^2.3.1", + "tslib": "^2.4.0", "uuid": "^8.3.1", "yauzl": "^2.10.0" }, @@ -17437,11 +17438,11 @@ } }, "node_modules/ts-node": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", - "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.0.tgz", + "integrity": "sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==", "dependencies": { - "@cspotcode/source-map-support": "0.7.0", + "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", @@ -17452,7 +17453,7 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "bin": { @@ -19740,17 +19741,23 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==" - }, "@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "requires": { - "@cspotcode/source-map-consumer": "0.8.0" + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } } }, "@discoveryjs/json-ext": { @@ -23455,9 +23462,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001341", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz", - "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==" + "version": "1.0.30001342", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001342.tgz", + "integrity": "sha512-bn6sOCu7L7jcbBbyNhLg0qzXdJ/PMbybZTH/BA6Roet9wxYRm6Tr9D0s0uhLkOZ6MSG+QU6txUgdpr3MXIVqjA==" }, "caseless": { "version": "0.12.0", @@ -23996,9 +24003,9 @@ "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" }, "core-js-compat": { - "version": "3.22.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.5.tgz", - "integrity": "sha512-rEF75n3QtInrYICvJjrAgV03HwKiYvtKHdPtaba1KucG+cNZ4NJnH9isqt979e67KZlhpbCOTwnsvnIr+CVeOg==", + "version": "3.22.6", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.6.tgz", + "integrity": "sha512-dQ/SxlHcuiywaPIoSUCU6Fx+Mk/H5TXENqd/ZJcK85ta0ZcQkbzHwblxPeL0hF5o+NsT2uK3q9ZOG5TboiVuWw==", "requires": { "browserslist": "^4.20.3", "semver": "7.0.0" @@ -28920,12 +28927,12 @@ } }, "mongodb-memory-server": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-8.5.2.tgz", - "integrity": "sha512-+4/zxz9TxpPMxaUEm0axQvSf+tS6GtPyc5MEjwkiprBGsH7aTe9GEjuHKnXGP8ObarHFpgW3kV4C4oEzYvxQIQ==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-8.6.0.tgz", + "integrity": "sha512-4I3qpIN3Ls5Vs8CPIl7SiT/rQUYmpgP27csDqgkSY7fu09mEqT3ieIC7cRhgx8wuRKr3rTotKMP4G1+Qw7+9Kw==", "requires": { - "mongodb-memory-server-core": "8.5.2", - "tslib": "^2.3.1" + "mongodb-memory-server-core": "8.6.0", + "tslib": "^2.4.0" }, "dependencies": { "tslib": { @@ -28936,9 +28943,9 @@ } }, "mongodb-memory-server-core": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-8.5.2.tgz", - "integrity": "sha512-JVQWZ0ZRWsEeX23cAxhetaJ9q5eILU01dKHrJBwHmMc79BKLdUI2iyIiGve6vyyzYNh4amBcUiWpnbgLmiTlrQ==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-8.6.0.tgz", + "integrity": "sha512-vuJfoK1TUPKwmspRxvkMUod34BInHmWF6li3nXlQ9bvaA2Xg4p3GsTkplyuwTBkLgeLL9AwIU0rk3CDwKpym1w==", "requires": { "@types/tmp": "^0.2.3", "async-mutex": "^0.3.2", @@ -28953,7 +28960,7 @@ "semver": "^7.3.7", "tar-stream": "^2.1.4", "tmp": "^0.2.1", - "tslib": "^2.3.1", + "tslib": "^2.4.0", "uuid": "^8.3.1", "yauzl": "^2.10.0" }, @@ -32319,11 +32326,11 @@ } }, "ts-node": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", - "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.0.tgz", + "integrity": "sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==", "requires": { - "@cspotcode/source-map-support": "0.7.0", + "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", @@ -32334,7 +32341,7 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "dependencies": { diff --git a/packages/schema/package.json b/packages/schema/package.json index f7bb993654..1e34057527 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -55,6 +55,7 @@ "dependencies": { "@feathersjs/errors": "^5.0.0-pre.20", "@feathersjs/feathers": "^5.0.0-pre.20", + "@feathersjs/hooks": "^0.7.4", "@types/json-schema": "^7.0.11", "ajv": "^8.11.0", "json-schema": "^0.4.0", diff --git a/packages/schema/src/hooks/index.ts b/packages/schema/src/hooks/index.ts new file mode 100644 index 0000000000..740ddc8d82 --- /dev/null +++ b/packages/schema/src/hooks/index.ts @@ -0,0 +1,2 @@ +export * from './resolve'; +export * from './validate'; diff --git a/packages/schema/src/hooks.ts b/packages/schema/src/hooks/resolve.ts similarity index 72% rename from packages/schema/src/hooks.ts rename to packages/schema/src/hooks/resolve.ts index 1c2205c2c6..b9a3bf595d 100644 --- a/packages/schema/src/hooks.ts +++ b/packages/schema/src/hooks/resolve.ts @@ -1,7 +1,6 @@ import { HookContext, NextFunction } from '@feathersjs/feathers'; -import { BadRequest } from '../../errors/lib'; -import { Resolver, ResolverStatus } from './resolver'; -import { Schema } from './schema'; +import { compose } from '@feathersjs/hooks'; +import { Resolver, ResolverStatus } from '../resolver'; const getContext = (context: H) => { return { @@ -55,18 +54,21 @@ export const resolveQuery = (...resolvers: Resolver (...resolvers: Resolver[]) => async (context: H, next?: NextFunction) => { - const ctx = getContext(context); - const data = context.data; - const status = { - originalContext: context - }; - - if (Array.isArray(data)) { - context.data = await Promise.all(data.map(current => - runResolvers(resolvers, current, ctx, status) - )); - } else { - context.data = await runResolvers(resolvers, data, ctx, status); + if (context.method === 'create' || context.method === 'patch' || context.method === 'update') { + const ctx = getContext(context); + const data = context.data; + + const status = { + originalContext: context + }; + + if (Array.isArray(data)) { + context.data = await Promise.all(data.map(current => + runResolvers(resolvers, current, ctx, status) + )); + } else { + context.data = await runResolvers(resolvers, data, ctx, status); + } } if (typeof next === 'function') { @@ -144,43 +146,25 @@ export const resolveDispatch = (...resolvers: Resolve }); }; -export const validateQuery = (schema: Schema) => - async (context: H, next?: NextFunction) => { - const data = context?.params?.query || {}; - - try { - const query = await schema.validate(data); - - context.params = { - ...context.params, - query - } - - if (typeof next === 'function') { - return next(); - } - } catch (error: any) { - throw (error.ajv ? new BadRequest(error.message, error.errors) : error); - } - }; +export type ResolveAllSettings = { + data?: Resolver|Resolver[] + query?: Resolver|Resolver[] + result?: Resolver|Resolver[] + dispatch?: Resolver|Resolver[] +} -export const validateData = (schema: Schema) => - async (context: H, next?: NextFunction) => { - const data = context.data; +const getResolvers = ( + map: ResolveAllSettings, + name: keyof ResolveAllSettings +) => { + const value = map[name]; - try { - if (Array.isArray(data)) { - context.data = await Promise.all(data.map(current => - schema.validate(current) - )); - } else { - context.data = await schema.validate(data); - } - } catch (error: any) { - throw (error.ajv ? new BadRequest(error.message, error.errors) : error); - } + return Array.isArray(value) ? value : (value !== undefined ? [ value ] : []); +} - if (typeof next === 'function') { - return next(); - } - }; +export const resolveAll = (map: ResolveAllSettings) => compose([ + resolveDispatch(...getResolvers(map, 'dispatch')), + resolveResult(...getResolvers(map, 'result')), + resolveQuery(...getResolvers(map, 'query')), + resolveData(...getResolvers(map, 'data')) +]) diff --git a/packages/schema/src/hooks/validate.ts b/packages/schema/src/hooks/validate.ts new file mode 100644 index 0000000000..9b40a31262 --- /dev/null +++ b/packages/schema/src/hooks/validate.ts @@ -0,0 +1,44 @@ +import { HookContext, NextFunction } from '@feathersjs/feathers'; +import { BadRequest } from '../../../errors/lib'; +import { Schema } from '../schema'; + +export const validateQuery = (schema: Schema) => + async (context: H, next?: NextFunction) => { + const data = context?.params?.query || {}; + + try { + const query = await schema.validate(data); + + context.params = { + ...context.params, + query + } + + if (typeof next === 'function') { + return next(); + } + } catch (error: any) { + throw (error.ajv ? new BadRequest(error.message, error.errors) : error); + } + }; + + export const validateData = (schema: Schema) => + async (context: H, next?: NextFunction) => { + const data = context.data; + + try { + if (Array.isArray(data)) { + context.data = await Promise.all(data.map(current => + schema.validate(current) + )); + } else { + context.data = await schema.validate(data); + } + } catch (error: any) { + throw (error.ajv ? new BadRequest(error.message, error.errors) : error); + } + + if (typeof next === 'function') { + return next(); + } + }; diff --git a/packages/schema/test/fixture.ts b/packages/schema/test/fixture.ts index 1bc2677b4d..d139fc0a3b 100644 --- a/packages/schema/test/fixture.ts +++ b/packages/schema/test/fixture.ts @@ -6,7 +6,7 @@ import { GeneralError } from '@feathersjs/errors'; import { schema, resolve, Infer, resolveResult, resolveQuery, - resolveData, validateData, validateQuery, querySyntax, Combine, resolveDispatch + resolveData, validateData, validateQuery, querySyntax, Combine, resolveDispatch, resolveAll } from '../src'; import { AdapterParams } from '../../memory/node_modules/@feathersjs/adapter-commons/lib'; @@ -167,10 +167,12 @@ app.use('messages', memory()) app.use('paginatedMessages', memory({paginate: { default: 10 }})); app.service('messages').hooks([ - resolveDispatch(messageDispatchResolver), - validateQuery(messageQuerySchema), - resolveQuery(messageQueryResolver), - resolveResult(messageResultResolver) + resolveAll({ + dispatch: messageDispatchResolver, + result: messageResultResolver, + query: messageQueryResolver + }), + validateQuery(messageQuerySchema) ]); app.service('paginatedMessages').hooks([