From b62b9255cf6754b0e15d4a3305c20c6a961a7b24 Mon Sep 17 00:00:00 2001 From: johaven Date: Thu, 29 Feb 2024 16:08:51 +0100 Subject: [PATCH 1/2] feat(core,common,platform-fastify): add webdav http methods support --- .../http/request-mapping.decorator.ts | 63 +++ packages/common/enums/http-status.enum.ts | 7 + packages/common/enums/request-method.enum.ts | 7 + .../interfaces/http/http-server.interface.ts | 14 + .../decorators/route-params.decorator.spec.ts | 423 +++++++++++++++++- packages/core/adapters/http-adapter.ts | 42 ++ .../core/helpers/router-method-factory.ts | 7 + .../helpers/router-method-factory.spec.ts | 18 + .../adapters/fastify-adapter.ts | 28 ++ 9 files changed, 608 insertions(+), 1 deletion(-) diff --git a/packages/common/decorators/http/request-mapping.decorator.ts b/packages/common/decorators/http/request-mapping.decorator.ts index 2b3506efcad..e707883cf46 100644 --- a/packages/common/decorators/http/request-mapping.decorator.ts +++ b/packages/common/decorators/http/request-mapping.decorator.ts @@ -118,3 +118,66 @@ export const All = createMappingDecorator(RequestMethod.ALL); * @publicApi */ export const Search = createMappingDecorator(RequestMethod.SEARCH); + +/** + * Route handler (method) Decorator. Routes Webdav PROPFIND requests to the specified path. + * + * @see [Routing](https://docs.nestjs.com/controllers#routing) + * + * @publicApi + */ +export const Propfind = createMappingDecorator(RequestMethod.PROPFIND); + +/** + * Route handler (method) Decorator. Routes Webdav PROPPATCH requests to the specified path. + * + * @see [Routing](https://docs.nestjs.com/controllers#routing) + * + * @publicApi + */ +export const Proppatch = createMappingDecorator(RequestMethod.PROPPATCH); + +/** + * Route handler (method) Decorator. Routes Webdav MKCOL requests to the specified path. + * + * @see [Routing](https://docs.nestjs.com/controllers#routing) + * + * @publicApi + */ +export const Mkcol = createMappingDecorator(RequestMethod.MKCOL); + +/** + * Route handler (method) Decorator. Routes Webdav COPY requests to the specified path. + * + * @see [Routing](https://docs.nestjs.com/controllers#routing) + * + * @publicApi + */ +export const Copy = createMappingDecorator(RequestMethod.COPY); + +/** + * Route handler (method) Decorator. Routes Webdav MOVE requests to the specified path. + * + * @see [Routing](https://docs.nestjs.com/controllers#routing) + * + * @publicApi + */ +export const Move = createMappingDecorator(RequestMethod.MOVE); + +/** + * Route handler (method) Decorator. Routes Webdav LOCK requests to the specified path. + * + * @see [Routing](https://docs.nestjs.com/controllers#routing) + * + * @publicApi + */ +export const Lock = createMappingDecorator(RequestMethod.LOCK); + +/** + * Route handler (method) Decorator. Routes Webdav UNLOCK requests to the specified path. + * + * @see [Routing](https://docs.nestjs.com/controllers#routing) + * + * @publicApi + */ +export const Unlock = createMappingDecorator(RequestMethod.UNLOCK); diff --git a/packages/common/enums/http-status.enum.ts b/packages/common/enums/http-status.enum.ts index 326001344c2..8d6da452686 100644 --- a/packages/common/enums/http-status.enum.ts +++ b/packages/common/enums/http-status.enum.ts @@ -13,6 +13,9 @@ export enum HttpStatus { NO_CONTENT = 204, RESET_CONTENT = 205, PARTIAL_CONTENT = 206, + MULTI_STATUS = 207, + ALREADY_REPORTED = 208, + CONTENT_DIFFERENT = 210, AMBIGUOUS = 300, MOVED_PERMANENTLY = 301, FOUND = 302, @@ -41,13 +44,17 @@ export enum HttpStatus { I_AM_A_TEAPOT = 418, MISDIRECTED = 421, UNPROCESSABLE_ENTITY = 422, + LOCKED = 423, FAILED_DEPENDENCY = 424, PRECONDITION_REQUIRED = 428, TOO_MANY_REQUESTS = 429, + UNRECOVERABLE_ERROR = 456, INTERNAL_SERVER_ERROR = 500, NOT_IMPLEMENTED = 501, BAD_GATEWAY = 502, SERVICE_UNAVAILABLE = 503, GATEWAY_TIMEOUT = 504, HTTP_VERSION_NOT_SUPPORTED = 505, + INSUFFICIENT_STORAGE = 507, + LOOP_DETECTED = 508, } diff --git a/packages/common/enums/request-method.enum.ts b/packages/common/enums/request-method.enum.ts index e28455633f4..9bd12a98ca5 100644 --- a/packages/common/enums/request-method.enum.ts +++ b/packages/common/enums/request-method.enum.ts @@ -8,4 +8,11 @@ export enum RequestMethod { OPTIONS, HEAD, SEARCH, + PROPFIND, + PROPPATCH, + MKCOL, + COPY, + MOVE, + LOCK, + UNLOCK, } diff --git a/packages/common/interfaces/http/http-server.interface.ts b/packages/common/interfaces/http/http-server.interface.ts index 28e8278b0fc..91494021e57 100644 --- a/packages/common/interfaces/http/http-server.interface.ts +++ b/packages/common/interfaces/http/http-server.interface.ts @@ -47,6 +47,20 @@ export interface HttpServer< put(path: string, handler: RequestHandler): any; patch(handler: RequestHandler): any; patch(path: string, handler: RequestHandler): any; + propfind?(handler: RequestHandler): any; + propfind?(path: string, handler: RequestHandler): any; + proppatch?(handler: RequestHandler): any; + proppatch?(path: string, handler: RequestHandler): any; + mkcol?(handler: RequestHandler): any; + mkcol?(path: string, handler: RequestHandler): any; + copy?(handler: RequestHandler): any; + copy?(path: string, handler: RequestHandler): any; + move?(handler: RequestHandler): any; + move?(path: string, handler: RequestHandler): any; + lock?(handler: RequestHandler): any; + lock?(path: string, handler: RequestHandler): any; + unlock?(handler: RequestHandler): any; + unlock?(path: string, handler: RequestHandler): any; all(path: string, handler: RequestHandler): any; all(handler: RequestHandler): any; options(handler: RequestHandler): any; diff --git a/packages/common/test/decorators/route-params.decorator.spec.ts b/packages/common/test/decorators/route-params.decorator.spec.ts index 3c4eabf5cbd..da3a85a9adb 100644 --- a/packages/common/test/decorators/route-params.decorator.spec.ts +++ b/packages/common/test/decorators/route-params.decorator.spec.ts @@ -1,7 +1,22 @@ import { expect } from 'chai'; import { Body, HostParam, Param, Query, Search } from '../../decorators'; import { RequestMethod } from '../../enums/request-method.enum'; -import { All, Delete, Get, ParseIntPipe, Patch, Post, Put } from '../../index'; +import { + All, + Delete, + Get, + ParseIntPipe, + Patch, + Post, + Put, + Propfind, + Proppatch, + Mkcol, + Move, + Copy, + Lock, + Unlock, +} from '../../index'; import { ROUTE_ARGS_METADATA } from '../../constants'; import { RouteParamtypes } from '../../enums/route-paramtypes.enum'; @@ -415,3 +430,409 @@ describe('Inheritance', () => { expect(methodUsingArray).to.be.eql(requestPropsUsingArray.method); }); }); + +describe('@PropFind', () => { + const requestPath = 'test'; + const requestProps = { + path: requestPath, + method: RequestMethod.PROPFIND, + }; + + const requestPathUsingArray = ['foo', 'bar']; + const requestPropsUsingArray = { + path: requestPathUsingArray, + method: RequestMethod.PROPFIND, + }; + + it('should enhance class with expected request metadata', () => { + class Test { + @Propfind(requestPath) + public static test() {} + + @Propfind(requestPathUsingArray) + public static testUsingArray() {} + } + + const path = Reflect.getMetadata('path', Test.test); + const method = Reflect.getMetadata('method', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + const methodUsingArray = Reflect.getMetadata('method', Test.testUsingArray); + + expect(path).to.be.eql(requestPath); + expect(method).to.be.eql(requestProps.method); + expect(pathUsingArray).to.be.eql(requestPathUsingArray); + expect(methodUsingArray).to.be.eql(requestPropsUsingArray.method); + }); + + it('should set path on "/" by default', () => { + class Test { + @Propfind() + public static test( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + + @Propfind([]) + public static testUsingArray( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + } + + const path = Reflect.getMetadata('path', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + + expect(path).to.be.eql('/'); + expect(pathUsingArray).to.be.eql('/'); + }); +}); + +describe('@PropPatch', () => { + const requestPath = 'test'; + const requestProps = { + path: requestPath, + method: RequestMethod.PROPPATCH, + }; + + const requestPathUsingArray = ['foo', 'bar']; + const requestPropsUsingArray = { + path: requestPathUsingArray, + method: RequestMethod.PROPPATCH, + }; + + it('should enhance class with expected request metadata', () => { + class Test { + @Proppatch(requestPath) + public static test() {} + + @Proppatch(requestPathUsingArray) + public static testUsingArray() {} + } + + const path = Reflect.getMetadata('path', Test.test); + const method = Reflect.getMetadata('method', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + const methodUsingArray = Reflect.getMetadata('method', Test.testUsingArray); + + expect(path).to.be.eql(requestPath); + expect(method).to.be.eql(requestProps.method); + expect(pathUsingArray).to.be.eql(requestPathUsingArray); + expect(methodUsingArray).to.be.eql(requestPropsUsingArray.method); + }); + + it('should set path on "/" by default', () => { + class Test { + @Proppatch() + public static test( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + + @Proppatch([]) + public static testUsingArray( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + } + + const path = Reflect.getMetadata('path', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + + expect(path).to.be.eql('/'); + expect(pathUsingArray).to.be.eql('/'); + }); +}); + +describe('@MkCol', () => { + const requestPath = 'test'; + const requestProps = { + path: requestPath, + method: RequestMethod.MKCOL, + }; + + const requestPathUsingArray = ['foo', 'bar']; + const requestPropsUsingArray = { + path: requestPathUsingArray, + method: RequestMethod.MKCOL, + }; + + it('should enhance class with expected request metadata', () => { + class Test { + @Mkcol(requestPath) + public static test() {} + + @Mkcol(requestPathUsingArray) + public static testUsingArray() {} + } + + const path = Reflect.getMetadata('path', Test.test); + const method = Reflect.getMetadata('method', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + const methodUsingArray = Reflect.getMetadata('method', Test.testUsingArray); + + expect(path).to.be.eql(requestPath); + expect(method).to.be.eql(requestProps.method); + expect(pathUsingArray).to.be.eql(requestPathUsingArray); + expect(methodUsingArray).to.be.eql(requestPropsUsingArray.method); + }); + + it('should set path on "/" by default', () => { + class Test { + @Mkcol() + public static test( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + + @Mkcol([]) + public static testUsingArray( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + } + + const path = Reflect.getMetadata('path', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + + expect(path).to.be.eql('/'); + expect(pathUsingArray).to.be.eql('/'); + }); +}); + +describe('@Copy', () => { + const requestPath = 'test'; + const requestProps = { + path: requestPath, + method: RequestMethod.COPY, + }; + + const requestPathUsingArray = ['foo', 'bar']; + const requestPropsUsingArray = { + path: requestPathUsingArray, + method: RequestMethod.COPY, + }; + + it('should enhance class with expected request metadata', () => { + class Test { + @Copy(requestPath) + public static test() {} + + @Copy(requestPathUsingArray) + public static testUsingArray() {} + } + + const path = Reflect.getMetadata('path', Test.test); + const method = Reflect.getMetadata('method', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + const methodUsingArray = Reflect.getMetadata('method', Test.testUsingArray); + + expect(path).to.be.eql(requestPath); + expect(method).to.be.eql(requestProps.method); + expect(pathUsingArray).to.be.eql(requestPathUsingArray); + expect(methodUsingArray).to.be.eql(requestPropsUsingArray.method); + }); + + it('should set path on "/" by default', () => { + class Test { + @Copy() + public static test( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + + @Copy([]) + public static testUsingArray( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + } + + const path = Reflect.getMetadata('path', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + + expect(path).to.be.eql('/'); + expect(pathUsingArray).to.be.eql('/'); + }); +}); + +describe('@Move', () => { + const requestPath = 'test'; + const requestProps = { + path: requestPath, + method: RequestMethod.MOVE, + }; + + const requestPathUsingArray = ['foo', 'bar']; + const requestPropsUsingArray = { + path: requestPathUsingArray, + method: RequestMethod.MOVE, + }; + + it('should enhance class with expected request metadata', () => { + class Test { + @Move(requestPath) + public static test() {} + + @Move(requestPathUsingArray) + public static testUsingArray() {} + } + + const path = Reflect.getMetadata('path', Test.test); + const method = Reflect.getMetadata('method', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + const methodUsingArray = Reflect.getMetadata('method', Test.testUsingArray); + + expect(path).to.be.eql(requestPath); + expect(method).to.be.eql(requestProps.method); + expect(pathUsingArray).to.be.eql(requestPathUsingArray); + expect(methodUsingArray).to.be.eql(requestPropsUsingArray.method); + }); + + it('should set path on "/" by default', () => { + class Test { + @Move() + public static test( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + + @Move([]) + public static testUsingArray( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + } + + const path = Reflect.getMetadata('path', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + + expect(path).to.be.eql('/'); + expect(pathUsingArray).to.be.eql('/'); + }); +}); + +describe('@Lock', () => { + const requestPath = 'test'; + const requestProps = { + path: requestPath, + method: RequestMethod.LOCK, + }; + + const requestPathUsingArray = ['foo', 'bar']; + const requestPropsUsingArray = { + path: requestPathUsingArray, + method: RequestMethod.LOCK, + }; + + it('should enhance class with expected request metadata', () => { + class Test { + @Lock(requestPath) + public static test() {} + + @Lock(requestPathUsingArray) + public static testUsingArray() {} + } + + const path = Reflect.getMetadata('path', Test.test); + const method = Reflect.getMetadata('method', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + const methodUsingArray = Reflect.getMetadata('method', Test.testUsingArray); + + expect(path).to.be.eql(requestPath); + expect(method).to.be.eql(requestProps.method); + expect(pathUsingArray).to.be.eql(requestPathUsingArray); + expect(methodUsingArray).to.be.eql(requestPropsUsingArray.method); + }); + + it('should set path on "/" by default', () => { + class Test { + @Lock() + public static test( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + + @Lock([]) + public static testUsingArray( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + } + + const path = Reflect.getMetadata('path', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + + expect(path).to.be.eql('/'); + expect(pathUsingArray).to.be.eql('/'); + }); +}); + +describe('@Unlock', () => { + const requestPath = 'test'; + const requestProps = { + path: requestPath, + method: RequestMethod.UNLOCK, + }; + + const requestPathUsingArray = ['foo', 'bar']; + const requestPropsUsingArray = { + path: requestPathUsingArray, + method: RequestMethod.UNLOCK, + }; + + it('should enhance class with expected request metadata', () => { + class Test { + @Unlock(requestPath) + public static test() {} + + @Unlock(requestPathUsingArray) + public static testUsingArray() {} + } + + const path = Reflect.getMetadata('path', Test.test); + const method = Reflect.getMetadata('method', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + const methodUsingArray = Reflect.getMetadata('method', Test.testUsingArray); + + expect(path).to.be.eql(requestPath); + expect(method).to.be.eql(requestProps.method); + expect(pathUsingArray).to.be.eql(requestPathUsingArray); + expect(methodUsingArray).to.be.eql(requestPropsUsingArray.method); + }); + + it('should set path on "/" by default', () => { + class Test { + @Unlock() + public static test( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + + @Unlock([]) + public static testUsingArray( + @Query() query, + @Param() params, + @HostParam() hostParams, + ) {} + } + + const path = Reflect.getMetadata('path', Test.test); + const pathUsingArray = Reflect.getMetadata('path', Test.testUsingArray); + + expect(path).to.be.eql('/'); + expect(pathUsingArray).to.be.eql('/'); + }); +}); diff --git a/packages/core/adapters/http-adapter.ts b/packages/core/adapters/http-adapter.ts index 6e079fe55dd..106e447ca41 100644 --- a/packages/core/adapters/http-adapter.ts +++ b/packages/core/adapters/http-adapter.ts @@ -62,6 +62,48 @@ export abstract class AbstractHttpAdapter< return this.instance.patch(...args); } + public propfind(handler: RequestHandler); + public propfind(path: any, handler: RequestHandler); + public propfind(...args: any[]) { + return this.instance.propfind(...args); + } + + public proppatch(handler: RequestHandler); + public proppatch(path: any, handler: RequestHandler); + public proppatch(...args: any[]) { + return this.instance.proppatch(...args); + } + + public mkcol(handler: RequestHandler); + public mkcol(path: any, handler: RequestHandler); + public mkcol(...args: any[]) { + return this.instance.mkcol(...args); + } + + public copy(handler: RequestHandler); + public copy(path: any, handler: RequestHandler); + public copy(...args: any[]) { + return this.instance.copy(...args); + } + + public move(handler: RequestHandler); + public move(path: any, handler: RequestHandler); + public move(...args: any[]) { + return this.instance.move(...args); + } + + public lock(handler: RequestHandler); + public lock(path: any, handler: RequestHandler); + public lock(...args: any[]) { + return this.instance.lock(...args); + } + + public unlock(handler: RequestHandler); + public unlock(path: any, handler: RequestHandler); + public unlock(...args: any[]) { + return this.instance.unlock(...args); + } + public all(handler: RequestHandler); public all(path: any, handler: RequestHandler); public all(...args: any[]) { diff --git a/packages/core/helpers/router-method-factory.ts b/packages/core/helpers/router-method-factory.ts index ff31c57e13a..6051303d67f 100644 --- a/packages/core/helpers/router-method-factory.ts +++ b/packages/core/helpers/router-method-factory.ts @@ -11,6 +11,13 @@ const REQUEST_METHOD_MAP = { [RequestMethod.OPTIONS]: 'options', [RequestMethod.HEAD]: 'head', [RequestMethod.SEARCH]: 'search', + [RequestMethod.PROPFIND]: 'propfind', + [RequestMethod.PROPPATCH]: 'proppatch', + [RequestMethod.MKCOL]: 'mkcol', + [RequestMethod.COPY]: 'copy', + [RequestMethod.MOVE]: 'move', + [RequestMethod.LOCK]: 'lock', + [RequestMethod.UNLOCK]: 'unlock', } as const satisfies Record; export class RouterMethodFactory { diff --git a/packages/core/test/helpers/router-method-factory.spec.ts b/packages/core/test/helpers/router-method-factory.spec.ts index 4f904519f74..6b3edfad54d 100644 --- a/packages/core/test/helpers/router-method-factory.spec.ts +++ b/packages/core/test/helpers/router-method-factory.spec.ts @@ -14,6 +14,13 @@ describe('RouterMethodFactory', () => { patch: () => {}, options: () => {}, head: () => {}, + propfind: () => {}, + proppatch: () => {}, + mkcol: () => {}, + copy: () => {}, + move: () => {}, + lock: () => {}, + unlock: () => {}, all: () => {}, }; beforeEach(() => { @@ -29,6 +36,17 @@ describe('RouterMethodFactory', () => { expect(factory.get(target, RequestMethod.PATCH)).to.equal(target.patch); expect(factory.get(target, RequestMethod.OPTIONS)).to.equal(target.options); expect(factory.get(target, RequestMethod.HEAD)).to.equal(target.head); + expect(factory.get(target, RequestMethod.PROPFIND)).to.equal( + target.propfind, + ); + expect(factory.get(target, RequestMethod.PROPPATCH)).to.equal( + target.proppatch, + ); + expect(factory.get(target, RequestMethod.MKCOL)).to.equal(target.mkcol); + expect(factory.get(target, RequestMethod.COPY)).to.equal(target.copy); + expect(factory.get(target, RequestMethod.MOVE)).to.equal(target.move); + expect(factory.get(target, RequestMethod.LOCK)).to.equal(target.lock); + expect(factory.get(target, RequestMethod.UNLOCK)).to.equal(target.unlock); expect(factory.get(target, -1 as any)).to.equal(target.use); }); }); diff --git a/packages/platform-fastify/adapters/fastify-adapter.ts b/packages/platform-fastify/adapters/fastify-adapter.ts index 6b99fa73d36..b7ec2c92d4c 100644 --- a/packages/platform-fastify/adapters/fastify-adapter.ts +++ b/packages/platform-fastify/adapters/fastify-adapter.ts @@ -320,6 +320,34 @@ export class FastifyAdapter< return this.injectRouteOptions('search', ...args); } + public propfind(...args: any[]) { + return this.injectRouteOptions('propfind', ...args); + } + + public proppatch(...args: any[]) { + return this.injectRouteOptions('proppatch', ...args); + } + + public mkcol(...args: any[]) { + return this.injectRouteOptions('mkcol', ...args); + } + + public copy(...args: any[]) { + return this.injectRouteOptions('copy', ...args); + } + + public move(...args: any[]) { + return this.injectRouteOptions('move', ...args); + } + + public lock(...args: any[]) { + return this.injectRouteOptions('lock', ...args); + } + + public unlock(...args: any[]) { + return this.injectRouteOptions('unlock', ...args); + } + public applyVersionFilter( handler: Function, version: VersionValue, From e1c1945a45021d980854b281bc7a648004d6f438 Mon Sep 17 00:00:00 2001 From: Johaven Date: Tue, 8 Oct 2024 13:49:56 +0200 Subject: [PATCH 2/2] fix(platform-fastify): uppercase methods --- .../platform-fastify/adapters/fastify-adapter.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/platform-fastify/adapters/fastify-adapter.ts b/packages/platform-fastify/adapters/fastify-adapter.ts index 6567088fda8..5345f3e3cec 100644 --- a/packages/platform-fastify/adapters/fastify-adapter.ts +++ b/packages/platform-fastify/adapters/fastify-adapter.ts @@ -321,31 +321,31 @@ export class FastifyAdapter< } public propfind(...args: any[]) { - return this.injectRouteOptions('propfind', ...args); + return this.injectRouteOptions('PROPFIND', ...args); } public proppatch(...args: any[]) { - return this.injectRouteOptions('proppatch', ...args); + return this.injectRouteOptions('PROPPATCH', ...args); } public mkcol(...args: any[]) { - return this.injectRouteOptions('mkcol', ...args); + return this.injectRouteOptions('MKCOL', ...args); } public copy(...args: any[]) { - return this.injectRouteOptions('copy', ...args); + return this.injectRouteOptions('COPY', ...args); } public move(...args: any[]) { - return this.injectRouteOptions('move', ...args); + return this.injectRouteOptions('MOVE', ...args); } public lock(...args: any[]) { - return this.injectRouteOptions('lock', ...args); + return this.injectRouteOptions('LOCK', ...args); } public unlock(...args: any[]) { - return this.injectRouteOptions('unlock', ...args); + return this.injectRouteOptions('UNLOCK', ...args); } public applyVersionFilter(