diff --git a/browser/src/core/browser.ts b/browser/src/core/browser.ts index 765baa0..b9157ac 100644 --- a/browser/src/core/browser.ts +++ b/browser/src/core/browser.ts @@ -1,11 +1,7 @@ -import { Helper } from './helper' import { rpc } from './rpc' +import { Helper } from './helper' +import { Validation } from './validation' import type * as T from '../types' -import { - RageFW_BrowserEvent, - RageFW_ClientEvent, - RageFW_ServerEvent, -} from '../types' /** Browser-side interactions */ export class Browser extends Helper { @@ -34,6 +30,8 @@ export class Browser extends Helper { * * @param eventName - The name of the event to register * @param callback - The callback function to be executed when the event is triggered + * @param [options] - Optional settings for callback execution + * @param [options.validation] - Validation schema to be checked before the callback executes * @returns {Browser} The current browser instance, enabling method chaining * * @example @@ -47,14 +45,27 @@ export class Browser extends Helper { public register( eventName: EventName, callback: T.RageFW_BrowserCallback, + options?: { + validation?: T.RageFW_ValidationOptions + }, ): Browser { this.log_('register', eventName, callback) rpc.register< Parameters, - ReturnType, + ReturnType | Promise, EventName - >(eventName, async (...data) => await callback(...data)) + >(eventName, async (...data) => { + if (!options?.validation) return await callback(...data) + + const validationSuccess = Validation.process( + data, + options?.validation, + ) + if (!validationSuccess) return + + return await callback(...data) + }) return this } diff --git a/browser/src/core/validation.ts b/browser/src/core/validation.ts new file mode 100644 index 0000000..30f202a --- /dev/null +++ b/browser/src/core/validation.ts @@ -0,0 +1,26 @@ +import type * as T from '../types' + +export class Validation { + constructor() {} + + public static process( + args: T.RageFW_BrowserArgs, + validationOptions?: T.RageFW_ValidationOptions, + ): boolean { + if (!validationOptions) return true + + if ('schema' in validationOptions) { + const validationResponse = validationOptions.schema.safeParse(args) + + if (validationResponse.success) { + return true + } else { + validationOptions.onError(validationResponse.error) + return false + } + } else { + const validationResponse = validationOptions.safeParse(args) + return validationResponse.success + } + } +} diff --git a/browser/src/types/index.ts b/browser/src/types/index.ts index 1b288ef..65c7310 100644 --- a/browser/src/types/index.ts +++ b/browser/src/types/index.ts @@ -1,3 +1,4 @@ export * from './browser' export * from './client' export * from './server' +export * from './validation' diff --git a/browser/src/types/validation.ts b/browser/src/types/validation.ts new file mode 100644 index 0000000..ecafdd3 --- /dev/null +++ b/browser/src/types/validation.ts @@ -0,0 +1,11 @@ +import type { z } from 'zod' + +export type RageFW_ValidationSchema = z.ZodTuple | z.ZodArray +export type RageFW_ValidationSchemaExtended = { + schema: RageFW_ValidationSchema + onError: (error: z.ZodError) => unknown +} + +export type RageFW_ValidationOptions = + | RageFW_ValidationSchema + | RageFW_ValidationSchemaExtended diff --git a/browser/tsup.config.ts b/browser/tsup.config.ts index af724fb..b1987c1 100644 --- a/browser/tsup.config.ts +++ b/browser/tsup.config.ts @@ -4,7 +4,6 @@ export default defineConfig({ entry: ['src/index.ts'], outDir: './dist', format: ['cjs'], - noExternal: ['rage-rpc'], experimentalDts: true, splitting: false, sourcemap: false, diff --git a/client/src/core/client.ts b/client/src/core/client.ts index bb1ba4a..ed94405 100644 --- a/client/src/core/client.ts +++ b/client/src/core/client.ts @@ -1,5 +1,6 @@ import { rpc } from './rpc' import { Middleware } from './middleware' +import { Validation } from './validation' import type * as T from '../types' /** Client-side interactions */ @@ -10,6 +11,7 @@ export class Client { * @param eventName - The name of the event to register * @param callback - The callback function to be executed when the event is triggered * @param [options] - Optional settings for callback execution + * @param [options.validation] - Validation schema to be checked before the callback executes * @param [options.middlewares] - Middleware functions to be checked before the callback executes * @returns {Client} The current client instance, enabling method chaining * @@ -44,6 +46,7 @@ export class Client { eventName: EventName, callback: T.RageFW_ClientCallback, options?: { + validation?: T.RageFW_ValidationOptions middlewares?: T.RageFW_MiddlewareOptions }, ): Client { @@ -52,9 +55,22 @@ export class Client { ReturnType | Promise, EventName >(eventName, async (...data) => { - if (!options?.middlewares) return await callback(...data) + if (!options?.middlewares && !options?.validation) + return await callback(...data) - await Middleware.process(options.middlewares, callback, data) + const validationSuccess = Validation.process( + data, + options?.validation, + ) + if (!validationSuccess) return + + const middlewaresSuccess = await Middleware.process( + data, + options?.middlewares, + ) + if (!middlewaresSuccess) return + + return await callback(...data) }) return this diff --git a/client/src/core/index.ts b/client/src/core/index.ts index bbd7d8f..375ef93 100644 --- a/client/src/core/index.ts +++ b/client/src/core/index.ts @@ -1,5 +1,4 @@ export * from './client' export * from './logger' -export * from './middleware' export * from './player' export * from './rpc' diff --git a/client/src/core/middleware.ts b/client/src/core/middleware.ts index 9c08fbf..11ae1a6 100644 --- a/client/src/core/middleware.ts +++ b/client/src/core/middleware.ts @@ -4,8 +4,8 @@ export class Middleware { constructor() {} private static async execute( - middlewares: T.RageFW_MiddlewareFunction[], args: T.RageFW_ClientArgs, + middlewares: T.RageFW_MiddlewareFunction[], ): Promise { for (let i = 0; i < middlewares.length; i++) { const result = await middlewares[i](...args) @@ -22,25 +22,25 @@ export class Middleware { } public static async process( - middlewareOptions: T.RageFW_MiddlewareOptions, - callback: T.RageFW_ClientCallback, args: T.RageFW_ClientArgs, - ) { + middlewareOptions?: T.RageFW_MiddlewareOptions, + ): Promise { + if (!middlewareOptions) return true + if (Array.isArray(middlewareOptions)) { const middlewaresResponse = await Middleware.execute( - middlewareOptions, args, + middlewareOptions, ) - - if (middlewaresResponse.success) return await callback(...args) + return middlewaresResponse.success } else { const middlewaresResponse = await Middleware.execute( - middlewareOptions.executables, args, + middlewareOptions.executables, ) if (middlewaresResponse.success) { - return await callback(...args) + return true } else { middlewareOptions.onError( middlewaresResponse.message ?? @@ -48,6 +48,7 @@ export class Middleware { middlewaresResponse.id + ' failed', ) + return false } } } diff --git a/client/src/core/validation.ts b/client/src/core/validation.ts new file mode 100644 index 0000000..2a7cb08 --- /dev/null +++ b/client/src/core/validation.ts @@ -0,0 +1,26 @@ +import type * as T from '../types' + +export class Validation { + constructor() {} + + public static process( + args: T.RageFW_ClientArgs, + validationOptions?: T.RageFW_ValidationOptions, + ): boolean { + if (!validationOptions) return true + + if ('schema' in validationOptions) { + const validationResponse = validationOptions.schema.safeParse(args) + + if (validationResponse.success) { + return true + } else { + validationOptions.onError(validationResponse.error) + return false + } + } else { + const validationResponse = validationOptions.safeParse(args) + return validationResponse.success + } + } +} diff --git a/client/src/types/index.ts b/client/src/types/index.ts index 915a170..9b35b7a 100644 --- a/client/src/types/index.ts +++ b/client/src/types/index.ts @@ -2,3 +2,4 @@ export * from './browser' export * from './client' export * from './middleware' export * from './server' +export * from './validation' diff --git a/client/src/types/validation.ts b/client/src/types/validation.ts new file mode 100644 index 0000000..ecafdd3 --- /dev/null +++ b/client/src/types/validation.ts @@ -0,0 +1,11 @@ +import type { z } from 'zod' + +export type RageFW_ValidationSchema = z.ZodTuple | z.ZodArray +export type RageFW_ValidationSchemaExtended = { + schema: RageFW_ValidationSchema + onError: (error: z.ZodError) => unknown +} + +export type RageFW_ValidationOptions = + | RageFW_ValidationSchema + | RageFW_ValidationSchemaExtended diff --git a/client/tsup.config.ts b/client/tsup.config.ts index af724fb..b1987c1 100644 --- a/client/tsup.config.ts +++ b/client/tsup.config.ts @@ -4,7 +4,6 @@ export default defineConfig({ entry: ['src/index.ts'], outDir: './dist', format: ['cjs'], - noExternal: ['rage-rpc'], experimentalDts: true, splitting: false, sourcemap: false, diff --git a/server/src/core/index.ts b/server/src/core/index.ts index ebed456..b6900db 100644 --- a/server/src/core/index.ts +++ b/server/src/core/index.ts @@ -1,5 +1,4 @@ export * from './logger' -export * from './middleware' export * from './player' export * from './rpc' export * from './server' diff --git a/server/src/core/middleware.ts b/server/src/core/middleware.ts index c319a03..abde15b 100644 --- a/server/src/core/middleware.ts +++ b/server/src/core/middleware.ts @@ -4,8 +4,8 @@ export class Middleware { constructor() {} private static async execute( - middlewares: T.RageFW_MiddlewareFunction[], args: T.RageFW_ServerArgs, + middlewares: T.RageFW_MiddlewareFunction[], ): Promise { for (let i = 0; i < middlewares.length; i++) { const result = await middlewares[i](...args) @@ -22,25 +22,25 @@ export class Middleware { } public static async process( - middlewareOptions: T.RageFW_MiddlewareOptions, - callback: T.RageFW_ServerCallback, args: T.RageFW_ServerArgs, - ) { + middlewareOptions?: T.RageFW_MiddlewareOptions, + ): Promise { + if (!middlewareOptions) return true + if (Array.isArray(middlewareOptions)) { const middlewaresResponse = await Middleware.execute( - middlewareOptions, args, + middlewareOptions, ) - - if (middlewaresResponse.success) return await callback(...args) + return middlewaresResponse.success } else { const middlewaresResponse = await Middleware.execute( - middlewareOptions.executables, args, + middlewareOptions.executables, ) if (middlewaresResponse.success) { - return await callback(...args) + return true } else { middlewareOptions.onError( middlewaresResponse.message ?? @@ -48,6 +48,7 @@ export class Middleware { middlewaresResponse.id + ' failed', ) + return false } } } diff --git a/server/src/core/server.ts b/server/src/core/server.ts index 428e23a..ce3a26a 100644 --- a/server/src/core/server.ts +++ b/server/src/core/server.ts @@ -1,5 +1,6 @@ import { rpc } from './rpc' import { Middleware } from './middleware' +import { Validation } from './validation' import type * as T from '../types' /** Server-side interactions */ @@ -10,6 +11,7 @@ export class Server { * @param eventName - The name of the event to register * @param callback - The callback function to be executed when the event is triggered * @param [options] - Optional settings for callback execution + * @param [options.validation] - Validation schema to be checked before the callback executes * @param [options.middlewares] - Middleware functions to be checked before the callback executes * @returns {Server} The current server instance, enabling method chaining * @@ -44,6 +46,7 @@ export class Server { eventName: EventName, callback: T.RageFW_ServerCallback, options?: { + validation?: T.RageFW_ValidationOptions middlewares?: T.RageFW_MiddlewareOptions }, ): Server { @@ -52,9 +55,22 @@ export class Server { ReturnType | Promise, EventName >(eventName, async (...data) => { - if (!options?.middlewares) return await callback(...data) + if (!options?.middlewares && !options?.validation) + return await callback(...data) - await Middleware.process(options.middlewares, callback, data) + const validationSuccess = Validation.process( + data, + options?.validation, + ) + if (!validationSuccess) return + + const middlewaresSuccess = await Middleware.process( + data, + options?.middlewares, + ) + if (!middlewaresSuccess) return + + return await callback(...data) }) return this @@ -90,7 +106,3 @@ export class Server { // return rpc.call(eventName, args) // } } - -// new Server() -// .register('customServerEvent', async (a, b, c) => true) -// .unregister('customServerEvent') diff --git a/server/src/core/validation.ts b/server/src/core/validation.ts new file mode 100644 index 0000000..3c50875 --- /dev/null +++ b/server/src/core/validation.ts @@ -0,0 +1,26 @@ +import type * as T from '../types' + +export class Validation { + constructor() {} + + public static process( + args: T.RageFW_ServerArgs, + validationOptions?: T.RageFW_ValidationOptions, + ): boolean { + if (!validationOptions) return true + + if ('schema' in validationOptions) { + const validationResponse = validationOptions.schema.safeParse(args) + + if (validationResponse.success) { + return true + } else { + validationOptions.onError(validationResponse.error) + return false + } + } else { + const validationResponse = validationOptions.safeParse(args) + return validationResponse.success + } + } +} diff --git a/server/src/types/index.ts b/server/src/types/index.ts index 915a170..9b35b7a 100644 --- a/server/src/types/index.ts +++ b/server/src/types/index.ts @@ -2,3 +2,4 @@ export * from './browser' export * from './client' export * from './middleware' export * from './server' +export * from './validation' diff --git a/server/src/types/validation.ts b/server/src/types/validation.ts new file mode 100644 index 0000000..ecafdd3 --- /dev/null +++ b/server/src/types/validation.ts @@ -0,0 +1,11 @@ +import type { z } from 'zod' + +export type RageFW_ValidationSchema = z.ZodTuple | z.ZodArray +export type RageFW_ValidationSchemaExtended = { + schema: RageFW_ValidationSchema + onError: (error: z.ZodError) => unknown +} + +export type RageFW_ValidationOptions = + | RageFW_ValidationSchema + | RageFW_ValidationSchemaExtended diff --git a/server/tsup.config.ts b/server/tsup.config.ts index af724fb..1a339b0 100644 --- a/server/tsup.config.ts +++ b/server/tsup.config.ts @@ -1,12 +1,12 @@ import { defineConfig } from 'tsup' export default defineConfig({ - entry: ['src/index.ts'], + entry: ['./src/index.ts'], outDir: './dist', format: ['cjs'], - noExternal: ['rage-rpc'], experimentalDts: true, splitting: false, sourcemap: false, clean: true, + bundle: false, })