equipped 5.1.10 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/dist/cjs/dbs/mongo/changes.cjs +5 -1
- package/dist/cjs/dbs/mongo/changes.cjs.map +1 -1
- package/dist/cjs/dbs/mongo/changes.min.cjs +1 -1
- package/dist/cjs/dbs/mongo/changes.min.cjs.map +1 -1
- package/dist/cjs/errors/index.cjs +1 -2
- package/dist/cjs/errors/index.cjs.map +1 -1
- package/dist/cjs/errors/index.min.cjs +1 -1
- package/dist/cjs/errors/index.min.cjs.map +1 -1
- package/dist/cjs/errors/types/tokenExpired.cjs +12 -0
- package/dist/cjs/errors/types/tokenExpired.cjs.map +1 -0
- package/dist/cjs/errors/types/{refreshTokenMisusedError.min.cjs → tokenExpired.min.cjs} +2 -2
- package/dist/cjs/errors/types/tokenExpired.min.cjs.map +1 -0
- package/dist/cjs/events/types/kafka.cjs +13 -16
- package/dist/cjs/events/types/kafka.cjs.map +1 -1
- package/dist/cjs/events/types/kafka.min.cjs +1 -1
- package/dist/cjs/events/types/kafka.min.cjs.map +1 -1
- package/dist/cjs/instance/index.cjs.map +1 -1
- package/dist/cjs/instance/index.min.cjs.map +1 -1
- package/dist/cjs/server/impls/base.cjs +17 -17
- package/dist/cjs/server/impls/base.cjs.map +1 -1
- package/dist/cjs/server/impls/base.min.cjs +1 -1
- package/dist/cjs/server/impls/base.min.cjs.map +1 -1
- package/dist/cjs/server/impls/express.cjs +2 -13
- package/dist/cjs/server/impls/express.cjs.map +1 -1
- package/dist/cjs/server/impls/express.min.cjs +1 -1
- package/dist/cjs/server/impls/express.min.cjs.map +1 -1
- package/dist/cjs/server/impls/fastify.cjs +3 -14
- package/dist/cjs/server/impls/fastify.cjs.map +1 -1
- package/dist/cjs/server/impls/fastify.min.cjs +1 -1
- package/dist/cjs/server/impls/fastify.min.cjs.map +1 -1
- package/dist/cjs/server/index.cjs +1 -1
- package/dist/cjs/server/index.cjs.map +1 -1
- package/dist/cjs/server/index.min.cjs +1 -1
- package/dist/cjs/server/index.min.cjs.map +1 -1
- package/dist/cjs/server/middlewares/requireAuthUser.cjs +9 -52
- package/dist/cjs/server/middlewares/requireAuthUser.cjs.map +1 -1
- package/dist/cjs/server/middlewares/requireAuthUser.min.cjs +1 -1
- package/dist/cjs/server/middlewares/requireAuthUser.min.cjs.map +1 -1
- package/dist/cjs/server/pipes.cjs +23 -8
- package/dist/cjs/server/pipes.cjs.map +1 -1
- package/dist/cjs/server/pipes.min.cjs +1 -1
- package/dist/cjs/server/pipes.min.cjs.map +1 -1
- package/dist/cjs/server/requests-auth-methods/apiKeys.cjs +21 -0
- package/dist/cjs/server/requests-auth-methods/apiKeys.cjs.map +1 -0
- package/dist/cjs/server/requests-auth-methods/apiKeys.min.cjs +2 -0
- package/dist/cjs/server/requests-auth-methods/apiKeys.min.cjs.map +1 -0
- package/dist/cjs/server/requests-auth-methods/base.cjs +20 -0
- package/dist/cjs/server/requests-auth-methods/base.cjs.map +1 -0
- package/dist/cjs/server/requests-auth-methods/base.min.cjs +2 -0
- package/dist/cjs/server/requests-auth-methods/base.min.cjs.map +1 -0
- package/dist/cjs/server/{requests-auth → requests-auth-methods}/index.cjs +2 -1
- package/dist/cjs/server/requests-auth-methods/index.cjs.map +1 -0
- package/dist/cjs/server/{requests-auth → requests-auth-methods}/index.min.cjs +1 -1
- package/dist/cjs/server/requests-auth-methods/index.min.cjs.map +1 -0
- package/dist/cjs/server/requests-auth-methods/jwt.cjs +78 -0
- package/dist/cjs/server/requests-auth-methods/jwt.cjs.map +1 -0
- package/dist/cjs/server/requests-auth-methods/jwt.min.cjs +2 -0
- package/dist/cjs/server/requests-auth-methods/jwt.min.cjs.map +1 -0
- package/dist/cjs/server/requests.cjs +1 -9
- package/dist/cjs/server/requests.cjs.map +1 -1
- package/dist/cjs/server/requests.min.cjs +1 -1
- package/dist/cjs/server/requests.min.cjs.map +1 -1
- package/dist/cjs/server/routes.cjs +1 -2
- package/dist/cjs/server/routes.cjs.map +1 -1
- package/dist/cjs/server/routes.min.cjs +1 -1
- package/dist/cjs/server/routes.min.cjs.map +1 -1
- package/dist/cjs/server/sockets.cjs +2 -4
- package/dist/cjs/server/sockets.cjs.map +1 -1
- package/dist/cjs/server/sockets.min.cjs +1 -1
- package/dist/cjs/server/sockets.min.cjs.map +1 -1
- package/dist/cjs/server/types.cjs +1 -1
- package/dist/cjs/server/types.cjs.map +1 -1
- package/dist/cjs/server/types.min.cjs +1 -1
- package/dist/cjs/server/types.min.cjs.map +1 -1
- package/dist/esm/dbs/mongo/changes.min.mjs +1 -1
- package/dist/esm/dbs/mongo/changes.min.mjs.map +1 -1
- package/dist/esm/dbs/mongo/changes.mjs +5 -1
- package/dist/esm/dbs/mongo/changes.mjs.map +1 -1
- package/dist/esm/errors/index.min.mjs +1 -1
- package/dist/esm/errors/index.min.mjs.map +1 -1
- package/dist/esm/errors/index.mjs +1 -2
- package/dist/esm/errors/index.mjs.map +1 -1
- package/dist/esm/errors/types/tokenExpired.min.mjs +2 -0
- package/dist/esm/errors/types/tokenExpired.min.mjs.map +1 -0
- package/dist/esm/errors/types/tokenExpired.mjs +12 -0
- package/dist/esm/errors/types/tokenExpired.mjs.map +1 -0
- package/dist/esm/events/types/kafka.min.mjs +1 -1
- package/dist/esm/events/types/kafka.min.mjs.map +1 -1
- package/dist/esm/events/types/kafka.mjs +13 -16
- package/dist/esm/events/types/kafka.mjs.map +1 -1
- package/dist/esm/instance/index.min.mjs +1 -1
- package/dist/esm/instance/index.min.mjs.map +1 -1
- package/dist/esm/instance/index.mjs.map +1 -1
- package/dist/esm/server/impls/base.min.mjs +1 -1
- package/dist/esm/server/impls/base.min.mjs.map +1 -1
- package/dist/esm/server/impls/base.mjs +9 -9
- package/dist/esm/server/impls/base.mjs.map +1 -1
- package/dist/esm/server/impls/express.min.mjs +1 -1
- package/dist/esm/server/impls/express.min.mjs.map +1 -1
- package/dist/esm/server/impls/express.mjs +2 -13
- package/dist/esm/server/impls/express.mjs.map +1 -1
- package/dist/esm/server/impls/fastify.min.mjs +1 -1
- package/dist/esm/server/impls/fastify.min.mjs.map +1 -1
- package/dist/esm/server/impls/fastify.mjs +2 -13
- package/dist/esm/server/impls/fastify.mjs.map +1 -1
- package/dist/esm/server/index.min.mjs +1 -1
- package/dist/esm/server/index.min.mjs.map +1 -1
- package/dist/esm/server/index.mjs +1 -1
- package/dist/esm/server/index.mjs.map +1 -1
- package/dist/esm/server/middlewares/requireAuthUser.min.mjs +1 -1
- package/dist/esm/server/middlewares/requireAuthUser.min.mjs.map +1 -1
- package/dist/esm/server/middlewares/requireAuthUser.mjs +9 -52
- package/dist/esm/server/middlewares/requireAuthUser.mjs.map +1 -1
- package/dist/esm/server/pipes.min.mjs +1 -1
- package/dist/esm/server/pipes.min.mjs.map +1 -1
- package/dist/esm/server/pipes.mjs +23 -8
- package/dist/esm/server/pipes.mjs.map +1 -1
- package/dist/esm/server/requests-auth-methods/apiKeys.min.mjs +2 -0
- package/dist/esm/server/requests-auth-methods/apiKeys.min.mjs.map +1 -0
- package/dist/esm/server/requests-auth-methods/apiKeys.mjs +21 -0
- package/dist/esm/server/requests-auth-methods/apiKeys.mjs.map +1 -0
- package/dist/esm/server/requests-auth-methods/base.min.mjs +2 -0
- package/dist/esm/server/requests-auth-methods/base.min.mjs.map +1 -0
- package/dist/esm/server/requests-auth-methods/base.mjs +20 -0
- package/dist/esm/server/requests-auth-methods/base.mjs.map +1 -0
- package/dist/esm/server/requests-auth-methods/index.min.mjs +2 -0
- package/dist/esm/server/requests-auth-methods/index.min.mjs.map +1 -0
- package/dist/esm/server/requests-auth-methods/index.mjs +4 -0
- package/dist/esm/server/requests-auth-methods/index.mjs.map +1 -0
- package/dist/esm/server/requests-auth-methods/jwt.min.mjs +2 -0
- package/dist/esm/server/requests-auth-methods/jwt.min.mjs.map +1 -0
- package/dist/esm/server/requests-auth-methods/jwt.mjs +78 -0
- package/dist/esm/server/requests-auth-methods/jwt.mjs.map +1 -0
- package/dist/esm/server/requests.min.mjs +1 -1
- package/dist/esm/server/requests.min.mjs.map +1 -1
- package/dist/esm/server/requests.mjs +1 -9
- package/dist/esm/server/requests.mjs.map +1 -1
- package/dist/esm/server/routes.min.mjs +1 -1
- package/dist/esm/server/routes.min.mjs.map +1 -1
- package/dist/esm/server/routes.mjs +1 -2
- package/dist/esm/server/routes.mjs.map +1 -1
- package/dist/esm/server/sockets.min.mjs +1 -1
- package/dist/esm/server/sockets.min.mjs.map +1 -1
- package/dist/esm/server/sockets.mjs +2 -4
- package/dist/esm/server/sockets.mjs.map +1 -1
- package/dist/esm/server/types.min.mjs +1 -1
- package/dist/esm/server/types.min.mjs.map +1 -1
- package/dist/esm/server/types.mjs +1 -1
- package/dist/esm/server/types.mjs.map +1 -1
- package/dist/types/cache/index.d.ts +7 -1
- package/dist/types/dbs/mongo/changes.js +5 -1
- package/dist/types/errors/index.d.ts +7 -12
- package/dist/types/errors/index.js +1 -2
- package/dist/types/errors/types/tokenExpired.js +11 -0
- package/dist/types/events/types/kafka.js +13 -16
- package/dist/types/{fastify-CDJ2WuLy.d.ts → fastify-B6FUtYe9.d.ts} +5 -4
- package/dist/types/index.d.ts +4 -4
- package/dist/types/instance/index.d.ts +63 -16
- package/dist/types/{requestError-DqkM5BfW.d.ts → requestError-7N-ngghg.d.ts} +97 -80
- package/dist/types/server/impls/base.js +9 -9
- package/dist/types/server/impls/express.js +2 -13
- package/dist/types/server/impls/fastify.js +2 -13
- package/dist/types/server/index.d.ts +62 -20
- package/dist/types/server/index.js +1 -1
- package/dist/types/server/middlewares/requireAuthUser.js +9 -52
- package/dist/types/server/pipes.js +23 -8
- package/dist/types/server/requests-auth-methods/apiKeys.js +20 -0
- package/dist/types/server/requests-auth-methods/base.js +19 -0
- package/dist/types/server/requests-auth-methods/index.js +3 -0
- package/dist/types/server/requests-auth-methods/jwt.js +77 -0
- package/dist/types/server/requests.js +1 -9
- package/dist/types/server/routes.js +1 -2
- package/dist/types/server/sockets.js +2 -4
- package/dist/types/server/types.js +1 -1
- package/dist/types/{validationError-BMKfV51p.d.ts → validationError-BB4cfdZa.d.ts} +1 -1
- package/dist/types/validations/index.d.ts +3 -9
- package/package.json +13 -12
- package/dist/cjs/errors/types/authorizationExpired.cjs +0 -12
- package/dist/cjs/errors/types/authorizationExpired.cjs.map +0 -1
- package/dist/cjs/errors/types/authorizationExpired.min.cjs +0 -2
- package/dist/cjs/errors/types/authorizationExpired.min.cjs.map +0 -1
- package/dist/cjs/errors/types/refreshTokenMisusedError.cjs +0 -12
- package/dist/cjs/errors/types/refreshTokenMisusedError.cjs.map +0 -1
- package/dist/cjs/errors/types/refreshTokenMisusedError.min.cjs.map +0 -1
- package/dist/cjs/server/middlewares/parseAuthUser.cjs +0 -21
- package/dist/cjs/server/middlewares/parseAuthUser.cjs.map +0 -1
- package/dist/cjs/server/middlewares/parseAuthUser.min.cjs +0 -2
- package/dist/cjs/server/middlewares/parseAuthUser.min.cjs.map +0 -1
- package/dist/cjs/server/requests-auth/apiKeys.cjs +0 -6
- package/dist/cjs/server/requests-auth/apiKeys.cjs.map +0 -1
- package/dist/cjs/server/requests-auth/apiKeys.min.cjs +0 -2
- package/dist/cjs/server/requests-auth/apiKeys.min.cjs.map +0 -1
- package/dist/cjs/server/requests-auth/index.cjs.map +0 -1
- package/dist/cjs/server/requests-auth/index.min.cjs.map +0 -1
- package/dist/cjs/server/requests-auth/tokens.cjs +0 -92
- package/dist/cjs/server/requests-auth/tokens.cjs.map +0 -1
- package/dist/cjs/server/requests-auth/tokens.min.cjs +0 -2
- package/dist/cjs/server/requests-auth/tokens.min.cjs.map +0 -1
- package/dist/esm/errors/types/authorizationExpired.min.mjs +0 -2
- package/dist/esm/errors/types/authorizationExpired.min.mjs.map +0 -1
- package/dist/esm/errors/types/authorizationExpired.mjs +0 -12
- package/dist/esm/errors/types/authorizationExpired.mjs.map +0 -1
- package/dist/esm/errors/types/refreshTokenMisusedError.min.mjs +0 -2
- package/dist/esm/errors/types/refreshTokenMisusedError.min.mjs.map +0 -1
- package/dist/esm/errors/types/refreshTokenMisusedError.mjs +0 -12
- package/dist/esm/errors/types/refreshTokenMisusedError.mjs.map +0 -1
- package/dist/esm/server/middlewares/parseAuthUser.min.mjs +0 -2
- package/dist/esm/server/middlewares/parseAuthUser.min.mjs.map +0 -1
- package/dist/esm/server/middlewares/parseAuthUser.mjs +0 -21
- package/dist/esm/server/middlewares/parseAuthUser.mjs.map +0 -1
- package/dist/esm/server/requests-auth/apiKeys.min.mjs +0 -2
- package/dist/esm/server/requests-auth/apiKeys.min.mjs.map +0 -1
- package/dist/esm/server/requests-auth/apiKeys.mjs +0 -6
- package/dist/esm/server/requests-auth/apiKeys.mjs.map +0 -1
- package/dist/esm/server/requests-auth/index.min.mjs +0 -2
- package/dist/esm/server/requests-auth/index.min.mjs.map +0 -1
- package/dist/esm/server/requests-auth/index.mjs +0 -3
- package/dist/esm/server/requests-auth/index.mjs.map +0 -1
- package/dist/esm/server/requests-auth/tokens.min.mjs +0 -2
- package/dist/esm/server/requests-auth/tokens.min.mjs.map +0 -1
- package/dist/esm/server/requests-auth/tokens.mjs +0 -92
- package/dist/esm/server/requests-auth/tokens.mjs.map +0 -1
- package/dist/types/base-8yVXb67P.d.ts +0 -8
- package/dist/types/errors/types/authorizationExpired.js +0 -11
- package/dist/types/errors/types/refreshTokenMisusedError.js +0 -11
- package/dist/types/server/middlewares/parseAuthUser.js +0 -20
- package/dist/types/server/requests-auth/apiKeys.js +0 -5
- package/dist/types/server/requests-auth/index.js +0 -2
- package/dist/types/server/requests-auth/tokens.js +0 -91
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/instance/index.ts"],"sourcesContent":["import pino, { type Logger } from 'pino'\nimport { ulid } from 'ulid'\nimport { type ConditionalObjectKeys, type Pipe, type PipeInput, v } from 'valleyed'\n\nimport { EquippedError } from '../errors'\nimport { type HookCb, type HookEvent, type HookRecord, runHooks } from './hooks'\nimport {\n\tcachePipe,\n\ttype CacheTypes,\n\tdbPipe,\n\ttype DbTypes,\n\teventBusPipe,\n\ttype EventBusTypes,\n\tinstanceSettingsPipe,\n\tjobsPipe,\n\ttype JobTypes,\n\tserverTypePipe,\n\ttype ServerTypes,\n\ttype Settings,\n\ttype SettingsInput,\n} from './settings'\n\nexport class Instance {\n\tstatic #id: string | undefined\n\tstatic #instance: Instance\n\tstatic #hooks: Partial<Record<HookEvent, HookRecord[]>> = {}\n\treadonly settings: Readonly<Settings>\n\treadonly log: Logger<never>\n\n\tprivate constructor(settings: Settings) {\n\t\tInstance.#instance = this\n\t\tthis.settings = Object.freeze(settings)\n\t\tthis.log = pino<never>({\n\t\t\tlevel: this.settings.log.level,\n\t\t\tserializers: {\n\t\t\t\terr: pino.stdSerializers.err,\n\t\t\t\terror: pino.stdSerializers.err,\n\t\t\t\treq: pino.stdSerializers.req,\n\t\t\t\tres: pino.stdSerializers.res,\n\t\t\t},\n\t\t\tmixin: () => ({\n\t\t\t\tinstanceId: Instance.#id,\n\t\t\t}),\n\t\t})\n\t\tInstance.#registerOnExitHandler()\n\t}\n\n\talias(id: string) {\n\t\tif (Instance.#id !== undefined) return Instance.crash(new EquippedError('Instance already has an alias', {}))\n\t\tInstance.#id = id\n\t}\n\n\tget id() {\n\t\tif (Instance.#id === undefined) return Instance.crash(new EquippedError('Instance doesnt have an alias yet', {}))\n\t\treturn Instance.#id\n\t}\n\n\tgetScopedName(name: string, key = '.') {\n\t\treturn [this.settings.app.name, name].join(key)\n\t}\n\n\tcreateCache<T extends PipeInput<ReturnType<typeof cachePipe
|
|
1
|
+
{"version":3,"sources":["../../../src/instance/index.ts"],"sourcesContent":["import pino, { type Logger } from 'pino'\nimport { ulid } from 'ulid'\nimport { type ConditionalObjectKeys, type Pipe, type PipeInput, v } from 'valleyed'\n\nimport { EquippedError } from '../errors'\nimport { type HookCb, type HookEvent, type HookRecord, runHooks } from './hooks'\nimport {\n\tcachePipe,\n\ttype CacheTypes,\n\tdbPipe,\n\ttype DbTypes,\n\teventBusPipe,\n\ttype EventBusTypes,\n\tinstanceSettingsPipe,\n\tjobsPipe,\n\ttype JobTypes,\n\tserverTypePipe,\n\ttype ServerTypes,\n\ttype Settings,\n\ttype SettingsInput,\n} from './settings'\n\nexport class Instance {\n\tstatic #id: string | undefined\n\tstatic #instance: Instance\n\tstatic #hooks: Partial<Record<HookEvent, HookRecord[]>> = {}\n\treadonly settings: Readonly<Settings>\n\treadonly log: Logger<never>\n\n\tprivate constructor(settings: Settings) {\n\t\tInstance.#instance = this\n\t\tthis.settings = Object.freeze(settings)\n\t\tthis.log = pino<never>({\n\t\t\tlevel: this.settings.log.level,\n\t\t\tserializers: {\n\t\t\t\terr: pino.stdSerializers.err,\n\t\t\t\terror: pino.stdSerializers.err,\n\t\t\t\treq: pino.stdSerializers.req,\n\t\t\t\tres: pino.stdSerializers.res,\n\t\t\t},\n\t\t\tmixin: () => ({\n\t\t\t\tinstanceId: Instance.#id,\n\t\t\t}),\n\t\t})\n\t\tInstance.#registerOnExitHandler()\n\t}\n\n\talias(id: string) {\n\t\tif (Instance.#id !== undefined) return Instance.crash(new EquippedError('Instance already has an alias', {}))\n\t\tInstance.#id = id\n\t}\n\n\tget id() {\n\t\tif (Instance.#id === undefined) return Instance.crash(new EquippedError('Instance doesnt have an alias yet', {}))\n\t\treturn Instance.#id\n\t}\n\n\tgetScopedName(name: string, key = '.') {\n\t\treturn [this.settings.app.name, name].join(key)\n\t}\n\n\tcreateCache<T extends keyof CacheTypes>(input: ConditionalObjectKeys<Extract<PipeInput<ReturnType<typeof cachePipe>>, { type: T }>>) {\n\t\treturn v.assert(cachePipe(), input) as CacheTypes[T]\n\t}\n\n\tcreateJobs<T extends keyof JobTypes>(input: ConditionalObjectKeys<Extract<PipeInput<ReturnType<typeof jobsPipe>>, { type: T }>>) {\n\t\treturn v.assert(jobsPipe(), input) as JobTypes[T]\n\t}\n\n\tcreateEventBus<T extends keyof EventBusTypes>(input: ConditionalObjectKeys<Extract<PipeInput<ReturnType<typeof eventBusPipe>>, { type: T }>>) {\n\t\treturn v.assert(eventBusPipe(), input) as EventBusTypes[T]\n\t}\n\n\tcreateDb<T extends keyof DbTypes>(input: ConditionalObjectKeys<Extract<PipeInput<ReturnType<typeof dbPipe>>, { db: { type: T } }>>) {\n\t\treturn v.assert(dbPipe(), input) as DbTypes[T]\n\t}\n\n\tcreateServer<T extends keyof ServerTypes>(input: ConditionalObjectKeys<Extract<PipeInput<ReturnType<typeof serverTypePipe>>, { type: T }>>) {\n\t\treturn v.assert(serverTypePipe(), input) as ServerTypes[T]\n\t}\n\n\tasync start() {\n\t\ttry {\n\t\t\tawait runHooks(Instance.#hooks['setup'] ?? [])\n\t\t\tawait runHooks(Instance.#hooks['start'] ?? [])\n\t\t} catch (error) {\n\t\t\tInstance.crash(new EquippedError(`Error starting instance`, {}, error))\n\t\t}\n\t}\n\n\tstatic envs<E extends object>(envsPipe: Pipe<unknown, E>): E {\n\t\tconst envValidity = v.validate(envsPipe, process.env)\n\t\tif (!envValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Environment variables are not valid\\n${envValidity.error.toString()}`, {\n\t\t\t\t\tmessages: envValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn envValidity.value\n\t}\n\n\tstatic create(settings: SettingsInput) {\n\t\tif (Instance.#instance) return Instance.crash(new EquippedError('Instance has been initialized already', {}))\n\t\tconst settingsValidity = v.validate(instanceSettingsPipe(), settings)\n\t\tif (!settingsValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Settings are not valid\\n${settingsValidity.error.toString()}`, {\n\t\t\t\t\tmessages: settingsValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn new Instance(settingsValidity.value)\n\t}\n\n\tstatic get() {\n\t\tif (!Instance.#instance)\n\t\t\treturn Instance.crash(\n\t\t\t\tnew EquippedError('Has not been initialized. Make sure an instance has been created before you get an instance', {}),\n\t\t\t)\n\t\treturn Instance.#instance\n\t}\n\n\tstatic on(event: HookEvent, cb: HookCb, order: number) {\n\t\tInstance.#hooks[event] ??= []\n\t\tInstance.#hooks[event].push({ cb, order })\n\t}\n\n\tstatic #registerOnExitHandler() {\n\t\tconst signals = {\n\t\t\tSIGHUP: 1,\n\t\t\tSIGINT: 2,\n\t\t\tSIGTERM: 15,\n\t\t}\n\n\t\tObject.entries(signals).forEach(([signal, code]) => {\n\t\t\tprocess.on(signal, async () => {\n\t\t\t\tawait runHooks(Instance.#hooks['close'] ?? [], () => {})\n\t\t\t\tprocess.exit(128 + code)\n\t\t\t})\n\t\t})\n\t}\n\n\tstatic resolveBeforeCrash<T>(cb: () => Promise<T>) {\n\t\tconst value = cb()\n\t\tInstance.on('close', async () => await value, 10)\n\t\treturn value\n\t}\n\n\tstatic crash(error: EquippedError): never {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(error)\n\t\tprocess.exit(1)\n\t}\n\n\tstatic createId(opts?: { prefix?: string; time?: Date }) {\n\t\treturn `${opts?.prefix ?? ''}${ulid(opts?.time?.getTime())}`\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Server as C}from"socket.io";import
|
|
1
|
+
import"cors";import{Server as C}from"socket.io";import j from"supertest";import{PipeError as O,v as a}from"valleyed";import{EquippedError as $,NotFoundError as D,RequestError as T}from "../../errors/index.min.mjs";import{Instance as b}from "../../instance/index.min.mjs";import{pipeErrorToValidationError as S}from "../../validations/index.min.mjs";import{requestLocalStorage as H,responseLocalStorage as A}from "../../validations/valleyed.min.mjs";import{OpenApi as M}from "../openapi.min.mjs";import{Response as y}from "../requests.min.mjs";import"../routes";import{SocketEmitter as V}from "../sockets.min.mjs";import{Methods as l,StatusCodes as k}from "../types.min.mjs";const x=Object.entries(k).filter(([,f])=>f>399).map(([f,o])=>({status:o,contentType:"application/json",pipe:a.meta(a.array(a.object({message:a.string(),field:a.optional(a.string())})),{$refId:`Errors.${f}Response`,description:`${f} Response`})}));class Y{constructor(o,s,n){this.config=s;this.implementations=n;this.server=o,this.#e=new M(s);const p=new C(o,{cors:this.cors});this.socket=new V(p,s),this.addRouter(this.#e.router())}#t=[];#s=new Map;#e;socket;server;get cors(){return{origin:this.config.cors?.origin,methods:(this.config.cors?.methods??Object.values(l)).filter(o=>o!==l.options).map(o=>o.toUpperCase()),credentials:this.config.cors?.credentials}}addRouter(...o){o.map(s=>s.routes).forEach(s=>this.addRoute(...s))}addRoute(...o){o.forEach(s=>{this.#t.push(async()=>{const{method:n,path:p,schema:r={},onError:c,middlewares:d=[]}=s,i=`(${n.toUpperCase()}) ${this.#e.cleanPath(p)}`;if(this.#s.get(i))throw new $(`Route key ${i} already registered. All route keys must be unique`,{route:s,key:i});d.forEach(h=>h.onSetup?.(s)),c?.onSetup?.(s);const{validateRequest:R,validateResponse:q,jsonSchema:v}=this.#o(n,r);this.#s.set(i,!0),await this.#e.register(s,v),this.implementations.registerRoute(n,this.#e.cleanPath(p),async(h,w)=>{const g=await R(await this.implementations.parseRequest(h));try{for(const u of d)await u.cb(g,this.config);const e=await s.handler(g,this.config),t=e instanceof y?e:new y({body:e,status:k.Ok,headers:{},piped:!1});return await this.implementations.handleResponse(w,await q(t))}catch(e){if(c?.cb){const t=await c.cb(g,this.config,e),u=t instanceof y?t:new y({body:t,status:k.BadRequest,headers:{}});return await this.implementations.handleResponse(w,await q(u))}throw e}})})})}#o(o,s){const n=s?.defaultStatusCode??k.Ok,p=s?.defaultContentType??"application/json";let r=n,c=p;const d={response:{},request:{}},i={},R={};[{key:"params",type:"request"},{key:"headers",type:"request"},{key:"cookies",type:"request"},{key:"query",type:"request"},{key:"body",type:"request",skip:![l.post,l.put,l.patch].includes(o)},{key:"response",type:"response"},{key:"responseHeaders",type:"response"},{key:"responseCookies",type:"response"}].forEach(e=>{const t=s[e.key]??a.any();if(!e.skip&&(e.type==="request"&&(i[e.key]=t,d.request[e.key]=a.schema(t)),e.type==="response")){const u=x.concat({status:n,contentType:c,pipe:t});R[e.key]=a.any().pipe(m=>{const E=u.find(P=>P.status===r)?.pipe;if(!E)throw O.root(`schema not defined for status code: ${r}`,m);return a.assert(E,m)}),d.response[e.key]=u.map(m=>({status:m.status,contentType:m.contentType,schema:a.schema(m.pipe)}))}});const v=a.object(i);a.compile(v,{allErrors:!0});const h=a.object(R);return a.compile(h,{allErrors:!0}),{jsonSchema:d,validateRequest:async e=>{if(!Object.keys(i))return e;const t=H.run(e,()=>a.validate(v,{params:e.params,headers:e.headers,query:e.query,body:e.body,cookies:e.cookies}));if(!t.valid)throw S(t.error);return e.params=t.value.params,e.headers=t.value.headers,e.query=t.value.query,e.body=t.value.body,e.cookies=t.value.cookies,e},validateResponse:async e=>{if(!Object.keys(R))return e;r=e.status,c=e.contentType;const t=A.run(e,()=>a.validate(h,{responseHeaders:e.headers,responseCookies:Object.fromEntries(Object.entries(e.cookies).map(([u,m])=>[u,m.value])),response:e.body}));if(!t.valid)throw S(t.error);return e.body=t.value.response,e.headers=t.value.responseHeaders,e.cookieValues=t.value.responseCookies,e}}}test(){return j(this.server)}async start(){const o=this.config.port,s=b.get(),{app:n}=s.settings;this.config.healthPath&&this.addRoute({method:l.get,path:this.config.healthPath,handler:async r=>r.res({body:`${s.id}(${n.name}) service running`,contentType:"text/plain"})}),this.implementations.registerNotFoundHandler(async r=>{const c=await this.implementations.parseRequest(r);throw new D(`Route ${c.path} not found`)}),this.implementations.registerErrorHandler(async(r,c,d)=>{b.get().log.error({error:r},"Uncaught error in route handler");const i=r instanceof T?new y({body:r.serializedErrors,status:r.statusCode}):new y({body:[{message:"Something went wrong",data:r.message}],status:k.BadRequest});return await this.implementations.handleResponse(d,i)}),await Promise.all(this.#t.map(r=>r()));const p=await this.implementations.start(o);return p&&b.get().log.info(`${s.id}(${n.name}) service listening on port ${o}`),p}}export{Y as Server};
|
|
2
2
|
//# sourceMappingURL=base.min.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/server/impls/base.ts"],"sourcesContent":["import type http from 'http'\n\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { type Pipe, PipeError, v } from 'valleyed'\n\nimport { EquippedError, NotFoundError, RequestError } from '../../errors'\nimport { Instance } from '../../instance'\nimport { pipeErrorToValidationError } from '../../validations'\nimport { requestLocalStorage, responseLocalStorage } from '../../validations/valleyed'\nimport { parseAuthUser } from '../middlewares/parseAuthUser'\nimport { OpenApi, type OpenApiSchemaDef } from '../openapi'\nimport type { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, type MethodsEnum, type RouteDef, StatusCodes, type Route } from '../types'\n\ntype RequestValidator = (req: Request<any>) => Promise<Request<any>>\ntype ResponseValidator = (res: Response<any>) => Promise<Response<any>>\n\nconst errorsSchemas = Object.entries(StatusCodes)\n\t.filter(([, value]) => value > 399)\n\t.map(([key, value]) => ({\n\t\tstatus: value,\n\t\tcontentType: 'application/json',\n\t\tpipe: v.meta(v.array(v.object({ message: v.string(), field: v.optional(v.string()) })), {\n\t\t\t$refId: `Errors.${key}Response`,\n\t\t\tdescription: `${key} Response`,\n\t\t}) as Pipe<any, any>,\n\t}))\n\nexport abstract class Server<Req = any, Res = any> {\n\t#queue: (() => void | Promise<void>)[] = []\n\t#routesByKey = new Map<string, boolean>()\n\t#openapi: OpenApi\n\tsocket: SocketEmitter\n\tprotected server: http.Server\n\tprotected cors = {\n\t\torigin: '*',\n\t\tmethods: Object.values(Methods)\n\t\t\t.filter((m) => m !== Methods.options)\n\t\t\t.map((m) => m.toUpperCase()),\n\t}\n\n\tconstructor(\n\t\tserver: http.Server,\n\t\tprivate config: ServerConfig,\n\t\tprivate implementations: {\n\t\t\tparseRequest: (req: Req) => Promise<Request<any>>\n\t\t\thandleResponse: (res: Res, response: Response<any>) => Promise<void>\n\t\t\tregisterRoute: (method: MethodsEnum, path: string, cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterErrorHandler: (cb: (error: Error, req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterNotFoundHandler: (cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tstart: (port: number) => Promise<boolean>\n\t\t},\n\t) {\n\t\tthis.server = server\n\t\tthis.#openapi = new OpenApi(config)\n\t\tconst socketInstance = new SocketServer(server, { cors: this.cors })\n\t\tthis.socket = new SocketEmitter(socketInstance, config)\n\t\tthis.addRouter(this.#openapi.router())\n\t}\n\n\taddRouter(...routers: Router<any>[]) {\n\t\trouters.map((router) => router.routes).forEach((routes) => this.addRoute(...routes))\n\t}\n\n\taddRoute<T extends RouteDef>(...routes: Route<T>[]) {\n\t\troutes.forEach((route) => {\n\t\t\tthis.#queue.push(async () => {\n\t\t\t\tconst { method, path, schema = {}, onError, middlewares = [] } = route\n\n\t\t\t\tconst key = `(${method.toUpperCase()}) ${this.#openapi.cleanPath(path)}`\n\t\t\t\tif (this.#routesByKey.get(key))\n\t\t\t\t\tthrow new EquippedError(`Route key ${key} already registered. All route keys must be unique`, { route, key })\n\n\t\t\t\tmiddlewares.unshift(parseAuthUser as any)\n\t\t\t\tmiddlewares.forEach((m) => m.onSetup?.(route as any))\n\t\t\t\tonError?.onSetup?.(route as any)\n\n\t\t\t\tconst { validateRequest, validateResponse, jsonSchema } = this.#resolveSchema(method, schema)\n\n\t\t\t\tthis.#routesByKey.set(key, true)\n\t\t\t\tawait this.#openapi.register(route, jsonSchema)\n\t\t\t\tthis.implementations.registerRoute(method, this.#openapi.cleanPath(path), async (req: Req, res: Res) => {\n\t\t\t\t\tconst request = await validateRequest(await this.implementations.parseRequest(req))\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor (const middleware of middlewares) await middleware.cb(request, this.config)\n\t\t\t\t\t\tconst rawRes = await route.handler(request, this.config)\n\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\trawRes instanceof Response\n\t\t\t\t\t\t\t\t? rawRes\n\t\t\t\t\t\t\t\t: new Response({ body: rawRes, status: StatusCodes.Ok, headers: {}, piped: false })\n\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (onError?.cb) {\n\t\t\t\t\t\t\tconst rawResponse = await onError.cb(request, this.config, error as Error)\n\t\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\t\trawResponse instanceof Response\n\t\t\t\t\t\t\t\t\t? rawResponse\n\t\t\t\t\t\t\t\t\t: new Response({ body: rawResponse, status: StatusCodes.BadRequest, headers: {} })\n\t\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t}\n\n\t#resolveSchema(method: MethodsEnum, schema: RouteDef) {\n\t\tconst defaultStatusCode = schema?.defaultStatusCode ?? StatusCodes.Ok\n\t\tconst defaultContentType = schema?.defaultContentType ?? 'application/json'\n\t\tlet status = defaultStatusCode\n\t\tlet contentType = defaultContentType\n\t\tconst jsonSchema: OpenApiSchemaDef = { response: {}, request: {} }\n\t\tconst requestPipeDefs: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params' | 'cookies'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders' | 'responseCookies'> = {}\n\n\t\tconst defs: {\n\t\t\tkey: Exclude<keyof RouteDef, `default${string}` | 'context'>\n\t\t\ttype: keyof OpenApiSchemaDef\n\t\t\tskip?: boolean\n\t\t}[] = [\n\t\t\t{ key: 'params', type: 'request' },\n\t\t\t{ key: 'headers', type: 'request' },\n\t\t\t{ key: 'cookies', type: 'request' },\n\t\t\t{ key: 'query', type: 'request' },\n\t\t\t{ key: 'body', type: 'request', skip: !(<MethodsEnum[]>[Methods.post, Methods.put, Methods.patch]).includes(method) },\n\t\t\t{ key: 'response', type: 'response' },\n\t\t\t{ key: 'responseHeaders', type: 'response' },\n\t\t\t{ key: 'responseCookies', type: 'response' },\n\t\t]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipeDefs[def.key] = pipe\n\t\t\t\tjsonSchema.request[def.key as keyof typeof jsonSchema.request] = v.schema(pipe)\n\t\t\t}\n\t\t\tif (def.type === 'response') {\n\t\t\t\tconst pipeRecords = errorsSchemas.concat({ status: defaultStatusCode, contentType, pipe })\n\t\t\t\tresponsePipeDefs[def.key] = v.any().pipe((input) => {\n\t\t\t\t\tconst p = pipeRecords.find((r) => r.status === status)?.pipe\n\t\t\t\t\tif (!p) throw PipeError.root(`schema not defined for status code: ${status}`, input)\n\t\t\t\t\treturn v.assert(p, input)\n\t\t\t\t})\n\t\t\t\tjsonSchema.response[def.key as keyof typeof jsonSchema.response] = pipeRecords.map((record) => ({\n\t\t\t\t\tstatus: record.status,\n\t\t\t\t\tcontentType: record.contentType,\n\t\t\t\t\tschema: v.schema(record.pipe),\n\t\t\t\t}))\n\t\t\t}\n\t\t})\n\t\tconst requestPipe = v.object(requestPipeDefs)\n\t\tv.compile(requestPipe, { allErrors: true })\n\t\tconst responsePipe = v.object(responsePipeDefs)\n\t\tv.compile(responsePipe, { allErrors: true })\n\t\tconst validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipeDefs)) return request\n\t\t\tconst context = schema.context ? await schema.context(request) : {}\n\t\t\trequest.context = context\n\t\t\tconst validity = requestLocalStorage.run(request, () =>\n\t\t\t\tv.validate(requestPipe, {\n\t\t\t\t\tparams: request.params,\n\t\t\t\t\theaders: request.headers,\n\t\t\t\t\tquery: request.query,\n\t\t\t\t\tbody: request.body,\n\t\t\t\t\tcookies: request.cookies,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\trequest.params = validity.value.params!\n\t\t\trequest.headers = validity.value.headers!\n\t\t\trequest.query = validity.value.query!\n\t\t\trequest.body = validity.value.body!\n\t\t\trequest.cookies = validity.value.cookies!\n\t\t\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipeDefs)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(responsePipe, {\n\t\t\t\t\tresponseHeaders: response.headers,\n\t\t\t\t\tresponseCookies: response.cookies,\n\t\t\t\t\tresponse: response.body,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\tresponse.body = validity.value.response!\n\t\t\tresponse.headers = validity.value.responseHeaders!\n\t\t\tresponse.cookieValues = validity.value.responseCookies!\n\t\t\treturn response\n\t\t}\n\t\treturn {\n\t\t\tjsonSchema,\n\t\t\tvalidateRequest,\n\t\t\tvalidateResponse,\n\t\t}\n\t}\n\n\ttest() {\n\t\treturn supertest(this.server)\n\t}\n\n\tasync start() {\n\t\tconst port = this.config.port\n\t\tconst instance = Instance.get()\n\t\tconst { app } = instance.settings\n\t\tif (this.config.healthPath)\n\t\t\tthis.addRoute({\n\t\t\t\tmethod: Methods.get,\n\t\t\t\tpath: this.config.healthPath,\n\t\t\t\thandler: async (req) =>\n\t\t\t\t\treq.res({\n\t\t\t\t\t\tbody: `${instance.id}(${app.name}) service running`,\n\t\t\t\t\t\tcontentType: 'text/plain',\n\t\t\t\t\t}),\n\t\t\t})\n\n\t\tthis.implementations.registerNotFoundHandler(async (req) => {\n\t\t\tconst request = await this.implementations.parseRequest(req)\n\t\t\tthrow new NotFoundError(`Route ${request.path} not found`)\n\t\t})\n\t\tthis.implementations.registerErrorHandler(async (error, _, res) => {\n\t\t\tInstance.get().log.error({ error }, 'Uncaught error in route handler')\n\t\t\tconst response =\n\t\t\t\terror instanceof RequestError\n\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\tbody: error.serializedErrors,\n\t\t\t\t\t\t\tstatus: error.statusCode,\n\t\t\t\t\t\t})\n\t\t\t\t\t: new Response({\n\t\t\t\t\t\t\tbody: [{ message: 'Something went wrong', data: error.message }],\n\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t})\n\t\t\treturn await this.implementations.handleResponse(res, response)\n\t\t})\n\n\t\tawait Promise.all(this.#queue.map((cb) => cb()))\n\t\tconst started = await this.implementations.start(port)\n\t\tif (started) Instance.get().log.info(`${instance.id}(${app.name}) service listening on port ${port}`)\n\t\treturn started\n\t}\n}\n"],"mappings":"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","names":["SocketServer","supertest","PipeError","v","EquippedError","NotFoundError","RequestError","Instance","pipeErrorToValidationError","requestLocalStorage","responseLocalStorage","parseAuthUser","OpenApi","Response","SocketEmitter","Methods","StatusCodes","errorsSchemas","value","key","Server","server","config","implementations","#openapi","socketInstance","#queue","#routesByKey","m","routers","router","routes","route","method","path","schema","onError","middlewares","validateRequest","validateResponse","jsonSchema","#resolveSchema","req","res","request","middleware","rawRes","response","error","rawResponse","defaultStatusCode","defaultContentType","status","contentType","requestPipeDefs","responsePipeDefs","def","pipe","pipeRecords","input","p","r","record","requestPipe","responsePipe","context","validity","port","instance","app","_","cb","started"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/server/impls/base.ts"],"sourcesContent":["import type http from 'node:http'\n\nimport { type CorsOptions } from 'cors'\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { type Pipe, PipeError, v } from 'valleyed'\n\nimport { EquippedError, NotFoundError, RequestError } from '../../errors'\nimport { Instance } from '../../instance'\nimport { pipeErrorToValidationError } from '../../validations'\nimport { requestLocalStorage, responseLocalStorage } from '../../validations/valleyed'\nimport { OpenApi, type OpenApiSchemaDef } from '../openapi'\nimport type { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, type MethodsEnum, type Route, type RouteDef, StatusCodes } from '../types'\n\ntype RequestValidator = (req: Request<any>) => Promise<Request<any>>\ntype ResponseValidator = (res: Response<any>) => Promise<Response<any>>\n\nconst errorsSchemas = Object.entries(StatusCodes)\n\t.filter(([, value]) => value > 399)\n\t.map(([key, value]) => ({\n\t\tstatus: value,\n\t\tcontentType: 'application/json',\n\t\tpipe: v.meta(v.array(v.object({ message: v.string(), field: v.optional(v.string()) })), {\n\t\t\t$refId: `Errors.${key}Response`,\n\t\t\tdescription: `${key} Response`,\n\t\t}) as Pipe<any, any>,\n\t}))\n\nexport abstract class Server<Req = any, Res = any> {\n\t#queue: (() => void | Promise<void>)[] = []\n\t#routesByKey = new Map<string, boolean>()\n\t#openapi: OpenApi\n\tsocket: SocketEmitter\n\tprotected server: http.Server\n\tprotected get cors() {\n\t\treturn {\n\t\t\torigin: this.config.cors?.origin,\n\t\t\tmethods: (this.config.cors?.methods ?? Object.values(Methods)).filter((m) => m !== Methods.options).map((m) => m.toUpperCase()),\n\t\t\tcredentials: this.config.cors?.credentials,\n\t\t} satisfies CorsOptions\n\t}\n\n\tconstructor(\n\t\tserver: http.Server,\n\t\tprivate config: ServerConfig,\n\t\tprivate implementations: {\n\t\t\tparseRequest: (req: Req) => Promise<Request<any>>\n\t\t\thandleResponse: (res: Res, response: Response<any>) => Promise<void>\n\t\t\tregisterRoute: (method: MethodsEnum, path: string, cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterErrorHandler: (cb: (error: Error, req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterNotFoundHandler: (cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tstart: (port: number) => Promise<boolean>\n\t\t},\n\t) {\n\t\tthis.server = server\n\t\tthis.#openapi = new OpenApi(config)\n\t\tconst socketInstance = new SocketServer(server, { cors: this.cors })\n\t\tthis.socket = new SocketEmitter(socketInstance, config)\n\t\tthis.addRouter(this.#openapi.router())\n\t}\n\n\taddRouter(...routers: Router<any>[]) {\n\t\trouters.map((router) => router.routes).forEach((routes) => this.addRoute(...routes))\n\t}\n\n\taddRoute<T extends RouteDef>(...routes: Route<T>[]) {\n\t\troutes.forEach((route) => {\n\t\t\tthis.#queue.push(async () => {\n\t\t\t\tconst { method, path, schema = {}, onError, middlewares = [] } = route\n\n\t\t\t\tconst key = `(${method.toUpperCase()}) ${this.#openapi.cleanPath(path)}`\n\t\t\t\tif (this.#routesByKey.get(key))\n\t\t\t\t\tthrow new EquippedError(`Route key ${key} already registered. All route keys must be unique`, { route, key })\n\n\t\t\t\tmiddlewares.forEach((m) => m.onSetup?.(route as any))\n\t\t\t\tonError?.onSetup?.(route as any)\n\n\t\t\t\tconst { validateRequest, validateResponse, jsonSchema } = this.#resolveSchema(method, schema)\n\n\t\t\t\tthis.#routesByKey.set(key, true)\n\t\t\t\tawait this.#openapi.register(route, jsonSchema)\n\t\t\t\tthis.implementations.registerRoute(method, this.#openapi.cleanPath(path), async (req: Req, res: Res) => {\n\t\t\t\t\tconst request = await validateRequest(await this.implementations.parseRequest(req))\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor (const middleware of middlewares) await middleware.cb(request, this.config)\n\t\t\t\t\t\tconst rawRes = await route.handler(request, this.config)\n\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\trawRes instanceof Response\n\t\t\t\t\t\t\t\t? rawRes\n\t\t\t\t\t\t\t\t: new Response({ body: rawRes, status: StatusCodes.Ok, headers: {}, piped: false })\n\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (onError?.cb) {\n\t\t\t\t\t\t\tconst rawResponse = await onError.cb(request, this.config, error as Error)\n\t\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\t\trawResponse instanceof Response\n\t\t\t\t\t\t\t\t\t? rawResponse\n\t\t\t\t\t\t\t\t\t: new Response({ body: rawResponse, status: StatusCodes.BadRequest, headers: {} })\n\t\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t}\n\n\t#resolveSchema(method: MethodsEnum, schema: RouteDef) {\n\t\tconst defaultStatusCode = schema?.defaultStatusCode ?? StatusCodes.Ok\n\t\tconst defaultContentType = schema?.defaultContentType ?? 'application/json'\n\t\tlet status = defaultStatusCode\n\t\tlet contentType = defaultContentType\n\t\tconst jsonSchema: OpenApiSchemaDef = { response: {}, request: {} }\n\t\tconst requestPipeDefs: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params' | 'cookies'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders' | 'responseCookies'> = {}\n\n\t\tconst defs: {\n\t\t\tkey: Exclude<keyof RouteDef, `default${string}` | 'context'>\n\t\t\ttype: keyof OpenApiSchemaDef\n\t\t\tskip?: boolean\n\t\t}[] = [\n\t\t\t{ key: 'params', type: 'request' },\n\t\t\t{ key: 'headers', type: 'request' },\n\t\t\t{ key: 'cookies', type: 'request' },\n\t\t\t{ key: 'query', type: 'request' },\n\t\t\t{ key: 'body', type: 'request', skip: !(<MethodsEnum[]>[Methods.post, Methods.put, Methods.patch]).includes(method) },\n\t\t\t{ key: 'response', type: 'response' },\n\t\t\t{ key: 'responseHeaders', type: 'response' },\n\t\t\t{ key: 'responseCookies', type: 'response' },\n\t\t]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipeDefs[def.key] = pipe\n\t\t\t\tjsonSchema.request[def.key as keyof typeof jsonSchema.request] = v.schema(pipe)\n\t\t\t}\n\t\t\tif (def.type === 'response') {\n\t\t\t\tconst pipeRecords = errorsSchemas.concat({ status: defaultStatusCode, contentType, pipe })\n\t\t\t\tresponsePipeDefs[def.key] = v.any().pipe((input) => {\n\t\t\t\t\tconst p = pipeRecords.find((r) => r.status === status)?.pipe\n\t\t\t\t\tif (!p) throw PipeError.root(`schema not defined for status code: ${status}`, input)\n\t\t\t\t\treturn v.assert(p, input)\n\t\t\t\t})\n\t\t\t\tjsonSchema.response[def.key as keyof typeof jsonSchema.response] = pipeRecords.map((record) => ({\n\t\t\t\t\tstatus: record.status,\n\t\t\t\t\tcontentType: record.contentType,\n\t\t\t\t\tschema: v.schema(record.pipe),\n\t\t\t\t}))\n\t\t\t}\n\t\t})\n\t\tconst requestPipe = v.object(requestPipeDefs)\n\t\tv.compile(requestPipe, { allErrors: true })\n\t\tconst responsePipe = v.object(responsePipeDefs)\n\t\tv.compile(responsePipe, { allErrors: true })\n\t\tconst validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipeDefs)) return request\n\t\t\tconst validity = requestLocalStorage.run(request, () =>\n\t\t\t\tv.validate(requestPipe, {\n\t\t\t\t\tparams: request.params,\n\t\t\t\t\theaders: request.headers,\n\t\t\t\t\tquery: request.query,\n\t\t\t\t\tbody: request.body,\n\t\t\t\t\tcookies: request.cookies,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\trequest.params = validity.value.params!\n\t\t\trequest.headers = validity.value.headers!\n\t\t\trequest.query = validity.value.query!\n\t\t\trequest.body = validity.value.body!\n\t\t\trequest.cookies = validity.value.cookies!\n\t\t\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipeDefs)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(responsePipe, {\n\t\t\t\t\tresponseHeaders: response.headers,\n\t\t\t\t\tresponseCookies: Object.fromEntries(Object.entries(response.cookies).map(([key, val]) => [key, val.value] as const)),\n\t\t\t\t\tresponse: response.body,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\tresponse.body = validity.value.response!\n\t\t\tresponse.headers = validity.value.responseHeaders!\n\t\t\tresponse.cookieValues = validity.value.responseCookies!\n\t\t\treturn response\n\t\t}\n\t\treturn {\n\t\t\tjsonSchema,\n\t\t\tvalidateRequest,\n\t\t\tvalidateResponse,\n\t\t}\n\t}\n\n\ttest() {\n\t\treturn supertest(this.server)\n\t}\n\n\tasync start() {\n\t\tconst port = this.config.port\n\t\tconst instance = Instance.get()\n\t\tconst { app } = instance.settings\n\t\tif (this.config.healthPath)\n\t\t\tthis.addRoute({\n\t\t\t\tmethod: Methods.get,\n\t\t\t\tpath: this.config.healthPath,\n\t\t\t\thandler: async (req) =>\n\t\t\t\t\treq.res({\n\t\t\t\t\t\tbody: `${instance.id}(${app.name}) service running`,\n\t\t\t\t\t\tcontentType: 'text/plain',\n\t\t\t\t\t}),\n\t\t\t})\n\n\t\tthis.implementations.registerNotFoundHandler(async (req) => {\n\t\t\tconst request = await this.implementations.parseRequest(req)\n\t\t\tthrow new NotFoundError(`Route ${request.path} not found`)\n\t\t})\n\t\tthis.implementations.registerErrorHandler(async (error, _, res) => {\n\t\t\tInstance.get().log.error({ error }, 'Uncaught error in route handler')\n\t\t\tconst response =\n\t\t\t\terror instanceof RequestError\n\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\tbody: error.serializedErrors,\n\t\t\t\t\t\t\tstatus: error.statusCode,\n\t\t\t\t\t\t})\n\t\t\t\t\t: new Response({\n\t\t\t\t\t\t\tbody: [{ message: 'Something went wrong', data: error.message }],\n\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t})\n\t\t\treturn await this.implementations.handleResponse(res, response)\n\t\t})\n\n\t\tawait Promise.all(this.#queue.map((cb) => cb()))\n\t\tconst started = await this.implementations.start(port)\n\t\tif (started) Instance.get().log.info(`${instance.id}(${app.name}) service listening on port ${port}`)\n\t\treturn started\n\t}\n}\n"],"mappings":"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","names":["SocketServer","supertest","PipeError","v","EquippedError","NotFoundError","RequestError","Instance","pipeErrorToValidationError","requestLocalStorage","responseLocalStorage","OpenApi","Response","SocketEmitter","Methods","StatusCodes","errorsSchemas","value","key","Server","server","config","implementations","#openapi","socketInstance","#queue","#routesByKey","m","routers","router","routes","route","method","path","schema","onError","middlewares","validateRequest","validateResponse","jsonSchema","#resolveSchema","req","res","request","middleware","rawRes","response","error","rawResponse","defaultStatusCode","defaultContentType","status","contentType","requestPipeDefs","responsePipeDefs","def","pipe","pipeRecords","input","p","r","record","requestPipe","responsePipe","validity","val","port","instance","app","_","cb","started"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {} from "cors";
|
|
1
2
|
import { Server as SocketServer } from "socket.io";
|
|
2
3
|
import supertest from "supertest";
|
|
3
4
|
import { PipeError, v } from "valleyed";
|
|
@@ -5,7 +6,6 @@ import { EquippedError, NotFoundError, RequestError } from "../../errors/index.m
|
|
|
5
6
|
import { Instance } from "../../instance/index.mjs";
|
|
6
7
|
import { pipeErrorToValidationError } from "../../validations/index.mjs";
|
|
7
8
|
import { requestLocalStorage, responseLocalStorage } from "../../validations/valleyed.mjs";
|
|
8
|
-
import { parseAuthUser } from "../middlewares/parseAuthUser.mjs";
|
|
9
9
|
import { OpenApi } from "../openapi.mjs";
|
|
10
10
|
import { Response } from "../requests.mjs";
|
|
11
11
|
import { Router } from "../routes.mjs";
|
|
@@ -34,10 +34,13 @@ class Server {
|
|
|
34
34
|
#openapi;
|
|
35
35
|
socket;
|
|
36
36
|
server;
|
|
37
|
-
cors
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
get cors() {
|
|
38
|
+
return {
|
|
39
|
+
origin: this.config.cors?.origin,
|
|
40
|
+
methods: (this.config.cors?.methods ?? Object.values(Methods)).filter((m) => m !== Methods.options).map((m) => m.toUpperCase()),
|
|
41
|
+
credentials: this.config.cors?.credentials
|
|
42
|
+
};
|
|
43
|
+
}
|
|
41
44
|
addRouter(...routers) {
|
|
42
45
|
routers.map((router) => router.routes).forEach((routes) => this.addRoute(...routes));
|
|
43
46
|
}
|
|
@@ -48,7 +51,6 @@ class Server {
|
|
|
48
51
|
const key = `(${method.toUpperCase()}) ${this.#openapi.cleanPath(path)}`;
|
|
49
52
|
if (this.#routesByKey.get(key))
|
|
50
53
|
throw new EquippedError(`Route key ${key} already registered. All route keys must be unique`, { route, key });
|
|
51
|
-
middlewares.unshift(parseAuthUser);
|
|
52
54
|
middlewares.forEach((m) => m.onSetup?.(route));
|
|
53
55
|
onError?.onSetup?.(route);
|
|
54
56
|
const { validateRequest, validateResponse, jsonSchema } = this.#resolveSchema(method, schema);
|
|
@@ -118,8 +120,6 @@ class Server {
|
|
|
118
120
|
v.compile(responsePipe, { allErrors: true });
|
|
119
121
|
const validateRequest = async (request) => {
|
|
120
122
|
if (!Object.keys(requestPipeDefs)) return request;
|
|
121
|
-
const context = schema.context ? await schema.context(request) : {};
|
|
122
|
-
request.context = context;
|
|
123
123
|
const validity = requestLocalStorage.run(
|
|
124
124
|
request,
|
|
125
125
|
() => v.validate(requestPipe, {
|
|
@@ -146,7 +146,7 @@ class Server {
|
|
|
146
146
|
response,
|
|
147
147
|
() => v.validate(responsePipe, {
|
|
148
148
|
responseHeaders: response.headers,
|
|
149
|
-
responseCookies: response.cookies,
|
|
149
|
+
responseCookies: Object.fromEntries(Object.entries(response.cookies).map(([key, val]) => [key, val.value])),
|
|
150
150
|
response: response.body
|
|
151
151
|
})
|
|
152
152
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/server/impls/base.ts"],"sourcesContent":["import type http from 'http'\n\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { type Pipe, PipeError, v } from 'valleyed'\n\nimport { EquippedError, NotFoundError, RequestError } from '../../errors'\nimport { Instance } from '../../instance'\nimport { pipeErrorToValidationError } from '../../validations'\nimport { requestLocalStorage, responseLocalStorage } from '../../validations/valleyed'\nimport { parseAuthUser } from '../middlewares/parseAuthUser'\nimport { OpenApi, type OpenApiSchemaDef } from '../openapi'\nimport type { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, type MethodsEnum, type RouteDef, StatusCodes, type Route } from '../types'\n\ntype RequestValidator = (req: Request<any>) => Promise<Request<any>>\ntype ResponseValidator = (res: Response<any>) => Promise<Response<any>>\n\nconst errorsSchemas = Object.entries(StatusCodes)\n\t.filter(([, value]) => value > 399)\n\t.map(([key, value]) => ({\n\t\tstatus: value,\n\t\tcontentType: 'application/json',\n\t\tpipe: v.meta(v.array(v.object({ message: v.string(), field: v.optional(v.string()) })), {\n\t\t\t$refId: `Errors.${key}Response`,\n\t\t\tdescription: `${key} Response`,\n\t\t}) as Pipe<any, any>,\n\t}))\n\nexport abstract class Server<Req = any, Res = any> {\n\t#queue: (() => void | Promise<void>)[] = []\n\t#routesByKey = new Map<string, boolean>()\n\t#openapi: OpenApi\n\tsocket: SocketEmitter\n\tprotected server: http.Server\n\tprotected cors = {\n\t\torigin: '*',\n\t\tmethods: Object.values(Methods)\n\t\t\t.filter((m) => m !== Methods.options)\n\t\t\t.map((m) => m.toUpperCase()),\n\t}\n\n\tconstructor(\n\t\tserver: http.Server,\n\t\tprivate config: ServerConfig,\n\t\tprivate implementations: {\n\t\t\tparseRequest: (req: Req) => Promise<Request<any>>\n\t\t\thandleResponse: (res: Res, response: Response<any>) => Promise<void>\n\t\t\tregisterRoute: (method: MethodsEnum, path: string, cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterErrorHandler: (cb: (error: Error, req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterNotFoundHandler: (cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tstart: (port: number) => Promise<boolean>\n\t\t},\n\t) {\n\t\tthis.server = server\n\t\tthis.#openapi = new OpenApi(config)\n\t\tconst socketInstance = new SocketServer(server, { cors: this.cors })\n\t\tthis.socket = new SocketEmitter(socketInstance, config)\n\t\tthis.addRouter(this.#openapi.router())\n\t}\n\n\taddRouter(...routers: Router<any>[]) {\n\t\trouters.map((router) => router.routes).forEach((routes) => this.addRoute(...routes))\n\t}\n\n\taddRoute<T extends RouteDef>(...routes: Route<T>[]) {\n\t\troutes.forEach((route) => {\n\t\t\tthis.#queue.push(async () => {\n\t\t\t\tconst { method, path, schema = {}, onError, middlewares = [] } = route\n\n\t\t\t\tconst key = `(${method.toUpperCase()}) ${this.#openapi.cleanPath(path)}`\n\t\t\t\tif (this.#routesByKey.get(key))\n\t\t\t\t\tthrow new EquippedError(`Route key ${key} already registered. All route keys must be unique`, { route, key })\n\n\t\t\t\tmiddlewares.unshift(parseAuthUser as any)\n\t\t\t\tmiddlewares.forEach((m) => m.onSetup?.(route as any))\n\t\t\t\tonError?.onSetup?.(route as any)\n\n\t\t\t\tconst { validateRequest, validateResponse, jsonSchema } = this.#resolveSchema(method, schema)\n\n\t\t\t\tthis.#routesByKey.set(key, true)\n\t\t\t\tawait this.#openapi.register(route, jsonSchema)\n\t\t\t\tthis.implementations.registerRoute(method, this.#openapi.cleanPath(path), async (req: Req, res: Res) => {\n\t\t\t\t\tconst request = await validateRequest(await this.implementations.parseRequest(req))\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor (const middleware of middlewares) await middleware.cb(request, this.config)\n\t\t\t\t\t\tconst rawRes = await route.handler(request, this.config)\n\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\trawRes instanceof Response\n\t\t\t\t\t\t\t\t? rawRes\n\t\t\t\t\t\t\t\t: new Response({ body: rawRes, status: StatusCodes.Ok, headers: {}, piped: false })\n\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (onError?.cb) {\n\t\t\t\t\t\t\tconst rawResponse = await onError.cb(request, this.config, error as Error)\n\t\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\t\trawResponse instanceof Response\n\t\t\t\t\t\t\t\t\t? rawResponse\n\t\t\t\t\t\t\t\t\t: new Response({ body: rawResponse, status: StatusCodes.BadRequest, headers: {} })\n\t\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t}\n\n\t#resolveSchema(method: MethodsEnum, schema: RouteDef) {\n\t\tconst defaultStatusCode = schema?.defaultStatusCode ?? StatusCodes.Ok\n\t\tconst defaultContentType = schema?.defaultContentType ?? 'application/json'\n\t\tlet status = defaultStatusCode\n\t\tlet contentType = defaultContentType\n\t\tconst jsonSchema: OpenApiSchemaDef = { response: {}, request: {} }\n\t\tconst requestPipeDefs: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params' | 'cookies'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders' | 'responseCookies'> = {}\n\n\t\tconst defs: {\n\t\t\tkey: Exclude<keyof RouteDef, `default${string}` | 'context'>\n\t\t\ttype: keyof OpenApiSchemaDef\n\t\t\tskip?: boolean\n\t\t}[] = [\n\t\t\t{ key: 'params', type: 'request' },\n\t\t\t{ key: 'headers', type: 'request' },\n\t\t\t{ key: 'cookies', type: 'request' },\n\t\t\t{ key: 'query', type: 'request' },\n\t\t\t{ key: 'body', type: 'request', skip: !(<MethodsEnum[]>[Methods.post, Methods.put, Methods.patch]).includes(method) },\n\t\t\t{ key: 'response', type: 'response' },\n\t\t\t{ key: 'responseHeaders', type: 'response' },\n\t\t\t{ key: 'responseCookies', type: 'response' },\n\t\t]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipeDefs[def.key] = pipe\n\t\t\t\tjsonSchema.request[def.key as keyof typeof jsonSchema.request] = v.schema(pipe)\n\t\t\t}\n\t\t\tif (def.type === 'response') {\n\t\t\t\tconst pipeRecords = errorsSchemas.concat({ status: defaultStatusCode, contentType, pipe })\n\t\t\t\tresponsePipeDefs[def.key] = v.any().pipe((input) => {\n\t\t\t\t\tconst p = pipeRecords.find((r) => r.status === status)?.pipe\n\t\t\t\t\tif (!p) throw PipeError.root(`schema not defined for status code: ${status}`, input)\n\t\t\t\t\treturn v.assert(p, input)\n\t\t\t\t})\n\t\t\t\tjsonSchema.response[def.key as keyof typeof jsonSchema.response] = pipeRecords.map((record) => ({\n\t\t\t\t\tstatus: record.status,\n\t\t\t\t\tcontentType: record.contentType,\n\t\t\t\t\tschema: v.schema(record.pipe),\n\t\t\t\t}))\n\t\t\t}\n\t\t})\n\t\tconst requestPipe = v.object(requestPipeDefs)\n\t\tv.compile(requestPipe, { allErrors: true })\n\t\tconst responsePipe = v.object(responsePipeDefs)\n\t\tv.compile(responsePipe, { allErrors: true })\n\t\tconst validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipeDefs)) return request\n\t\t\tconst context = schema.context ? await schema.context(request) : {}\n\t\t\trequest.context = context\n\t\t\tconst validity = requestLocalStorage.run(request, () =>\n\t\t\t\tv.validate(requestPipe, {\n\t\t\t\t\tparams: request.params,\n\t\t\t\t\theaders: request.headers,\n\t\t\t\t\tquery: request.query,\n\t\t\t\t\tbody: request.body,\n\t\t\t\t\tcookies: request.cookies,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\trequest.params = validity.value.params!\n\t\t\trequest.headers = validity.value.headers!\n\t\t\trequest.query = validity.value.query!\n\t\t\trequest.body = validity.value.body!\n\t\t\trequest.cookies = validity.value.cookies!\n\t\t\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipeDefs)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(responsePipe, {\n\t\t\t\t\tresponseHeaders: response.headers,\n\t\t\t\t\tresponseCookies: response.cookies,\n\t\t\t\t\tresponse: response.body,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\tresponse.body = validity.value.response!\n\t\t\tresponse.headers = validity.value.responseHeaders!\n\t\t\tresponse.cookieValues = validity.value.responseCookies!\n\t\t\treturn response\n\t\t}\n\t\treturn {\n\t\t\tjsonSchema,\n\t\t\tvalidateRequest,\n\t\t\tvalidateResponse,\n\t\t}\n\t}\n\n\ttest() {\n\t\treturn supertest(this.server)\n\t}\n\n\tasync start() {\n\t\tconst port = this.config.port\n\t\tconst instance = Instance.get()\n\t\tconst { app } = instance.settings\n\t\tif (this.config.healthPath)\n\t\t\tthis.addRoute({\n\t\t\t\tmethod: Methods.get,\n\t\t\t\tpath: this.config.healthPath,\n\t\t\t\thandler: async (req) =>\n\t\t\t\t\treq.res({\n\t\t\t\t\t\tbody: `${instance.id}(${app.name}) service running`,\n\t\t\t\t\t\tcontentType: 'text/plain',\n\t\t\t\t\t}),\n\t\t\t})\n\n\t\tthis.implementations.registerNotFoundHandler(async (req) => {\n\t\t\tconst request = await this.implementations.parseRequest(req)\n\t\t\tthrow new NotFoundError(`Route ${request.path} not found`)\n\t\t})\n\t\tthis.implementations.registerErrorHandler(async (error, _, res) => {\n\t\t\tInstance.get().log.error({ error }, 'Uncaught error in route handler')\n\t\t\tconst response =\n\t\t\t\terror instanceof RequestError\n\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\tbody: error.serializedErrors,\n\t\t\t\t\t\t\tstatus: error.statusCode,\n\t\t\t\t\t\t})\n\t\t\t\t\t: new Response({\n\t\t\t\t\t\t\tbody: [{ message: 'Something went wrong', data: error.message }],\n\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t})\n\t\t\treturn await this.implementations.handleResponse(res, response)\n\t\t})\n\n\t\tawait Promise.all(this.#queue.map((cb) => cb()))\n\t\tconst started = await this.implementations.start(port)\n\t\tif (started) Instance.get().log.info(`${instance.id}(${app.name}) service listening on port ${port}`)\n\t\treturn started\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/server/impls/base.ts"],"sourcesContent":["import type http from 'node:http'\n\nimport { type CorsOptions } from 'cors'\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { type Pipe, PipeError, v } from 'valleyed'\n\nimport { EquippedError, NotFoundError, RequestError } from '../../errors'\nimport { Instance } from '../../instance'\nimport { pipeErrorToValidationError } from '../../validations'\nimport { requestLocalStorage, responseLocalStorage } from '../../validations/valleyed'\nimport { OpenApi, type OpenApiSchemaDef } from '../openapi'\nimport type { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, type MethodsEnum, type Route, type RouteDef, StatusCodes } from '../types'\n\ntype RequestValidator = (req: Request<any>) => Promise<Request<any>>\ntype ResponseValidator = (res: Response<any>) => Promise<Response<any>>\n\nconst errorsSchemas = Object.entries(StatusCodes)\n\t.filter(([, value]) => value > 399)\n\t.map(([key, value]) => ({\n\t\tstatus: value,\n\t\tcontentType: 'application/json',\n\t\tpipe: v.meta(v.array(v.object({ message: v.string(), field: v.optional(v.string()) })), {\n\t\t\t$refId: `Errors.${key}Response`,\n\t\t\tdescription: `${key} Response`,\n\t\t}) as Pipe<any, any>,\n\t}))\n\nexport abstract class Server<Req = any, Res = any> {\n\t#queue: (() => void | Promise<void>)[] = []\n\t#routesByKey = new Map<string, boolean>()\n\t#openapi: OpenApi\n\tsocket: SocketEmitter\n\tprotected server: http.Server\n\tprotected get cors() {\n\t\treturn {\n\t\t\torigin: this.config.cors?.origin,\n\t\t\tmethods: (this.config.cors?.methods ?? Object.values(Methods)).filter((m) => m !== Methods.options).map((m) => m.toUpperCase()),\n\t\t\tcredentials: this.config.cors?.credentials,\n\t\t} satisfies CorsOptions\n\t}\n\n\tconstructor(\n\t\tserver: http.Server,\n\t\tprivate config: ServerConfig,\n\t\tprivate implementations: {\n\t\t\tparseRequest: (req: Req) => Promise<Request<any>>\n\t\t\thandleResponse: (res: Res, response: Response<any>) => Promise<void>\n\t\t\tregisterRoute: (method: MethodsEnum, path: string, cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterErrorHandler: (cb: (error: Error, req: Req, res: Res) => Promise<void>) => void\n\t\t\tregisterNotFoundHandler: (cb: (req: Req, res: Res) => Promise<void>) => void\n\t\t\tstart: (port: number) => Promise<boolean>\n\t\t},\n\t) {\n\t\tthis.server = server\n\t\tthis.#openapi = new OpenApi(config)\n\t\tconst socketInstance = new SocketServer(server, { cors: this.cors })\n\t\tthis.socket = new SocketEmitter(socketInstance, config)\n\t\tthis.addRouter(this.#openapi.router())\n\t}\n\n\taddRouter(...routers: Router<any>[]) {\n\t\trouters.map((router) => router.routes).forEach((routes) => this.addRoute(...routes))\n\t}\n\n\taddRoute<T extends RouteDef>(...routes: Route<T>[]) {\n\t\troutes.forEach((route) => {\n\t\t\tthis.#queue.push(async () => {\n\t\t\t\tconst { method, path, schema = {}, onError, middlewares = [] } = route\n\n\t\t\t\tconst key = `(${method.toUpperCase()}) ${this.#openapi.cleanPath(path)}`\n\t\t\t\tif (this.#routesByKey.get(key))\n\t\t\t\t\tthrow new EquippedError(`Route key ${key} already registered. All route keys must be unique`, { route, key })\n\n\t\t\t\tmiddlewares.forEach((m) => m.onSetup?.(route as any))\n\t\t\t\tonError?.onSetup?.(route as any)\n\n\t\t\t\tconst { validateRequest, validateResponse, jsonSchema } = this.#resolveSchema(method, schema)\n\n\t\t\t\tthis.#routesByKey.set(key, true)\n\t\t\t\tawait this.#openapi.register(route, jsonSchema)\n\t\t\t\tthis.implementations.registerRoute(method, this.#openapi.cleanPath(path), async (req: Req, res: Res) => {\n\t\t\t\t\tconst request = await validateRequest(await this.implementations.parseRequest(req))\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor (const middleware of middlewares) await middleware.cb(request, this.config)\n\t\t\t\t\t\tconst rawRes = await route.handler(request, this.config)\n\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\trawRes instanceof Response\n\t\t\t\t\t\t\t\t? rawRes\n\t\t\t\t\t\t\t\t: new Response({ body: rawRes, status: StatusCodes.Ok, headers: {}, piped: false })\n\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tif (onError?.cb) {\n\t\t\t\t\t\t\tconst rawResponse = await onError.cb(request, this.config, error as Error)\n\t\t\t\t\t\t\tconst response =\n\t\t\t\t\t\t\t\trawResponse instanceof Response\n\t\t\t\t\t\t\t\t\t? rawResponse\n\t\t\t\t\t\t\t\t\t: new Response({ body: rawResponse, status: StatusCodes.BadRequest, headers: {} })\n\t\t\t\t\t\t\treturn await this.implementations.handleResponse(res, await validateResponse(response))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t}\n\n\t#resolveSchema(method: MethodsEnum, schema: RouteDef) {\n\t\tconst defaultStatusCode = schema?.defaultStatusCode ?? StatusCodes.Ok\n\t\tconst defaultContentType = schema?.defaultContentType ?? 'application/json'\n\t\tlet status = defaultStatusCode\n\t\tlet contentType = defaultContentType\n\t\tconst jsonSchema: OpenApiSchemaDef = { response: {}, request: {} }\n\t\tconst requestPipeDefs: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params' | 'cookies'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders' | 'responseCookies'> = {}\n\n\t\tconst defs: {\n\t\t\tkey: Exclude<keyof RouteDef, `default${string}` | 'context'>\n\t\t\ttype: keyof OpenApiSchemaDef\n\t\t\tskip?: boolean\n\t\t}[] = [\n\t\t\t{ key: 'params', type: 'request' },\n\t\t\t{ key: 'headers', type: 'request' },\n\t\t\t{ key: 'cookies', type: 'request' },\n\t\t\t{ key: 'query', type: 'request' },\n\t\t\t{ key: 'body', type: 'request', skip: !(<MethodsEnum[]>[Methods.post, Methods.put, Methods.patch]).includes(method) },\n\t\t\t{ key: 'response', type: 'response' },\n\t\t\t{ key: 'responseHeaders', type: 'response' },\n\t\t\t{ key: 'responseCookies', type: 'response' },\n\t\t]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipeDefs[def.key] = pipe\n\t\t\t\tjsonSchema.request[def.key as keyof typeof jsonSchema.request] = v.schema(pipe)\n\t\t\t}\n\t\t\tif (def.type === 'response') {\n\t\t\t\tconst pipeRecords = errorsSchemas.concat({ status: defaultStatusCode, contentType, pipe })\n\t\t\t\tresponsePipeDefs[def.key] = v.any().pipe((input) => {\n\t\t\t\t\tconst p = pipeRecords.find((r) => r.status === status)?.pipe\n\t\t\t\t\tif (!p) throw PipeError.root(`schema not defined for status code: ${status}`, input)\n\t\t\t\t\treturn v.assert(p, input)\n\t\t\t\t})\n\t\t\t\tjsonSchema.response[def.key as keyof typeof jsonSchema.response] = pipeRecords.map((record) => ({\n\t\t\t\t\tstatus: record.status,\n\t\t\t\t\tcontentType: record.contentType,\n\t\t\t\t\tschema: v.schema(record.pipe),\n\t\t\t\t}))\n\t\t\t}\n\t\t})\n\t\tconst requestPipe = v.object(requestPipeDefs)\n\t\tv.compile(requestPipe, { allErrors: true })\n\t\tconst responsePipe = v.object(responsePipeDefs)\n\t\tv.compile(responsePipe, { allErrors: true })\n\t\tconst validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipeDefs)) return request\n\t\t\tconst validity = requestLocalStorage.run(request, () =>\n\t\t\t\tv.validate(requestPipe, {\n\t\t\t\t\tparams: request.params,\n\t\t\t\t\theaders: request.headers,\n\t\t\t\t\tquery: request.query,\n\t\t\t\t\tbody: request.body,\n\t\t\t\t\tcookies: request.cookies,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\trequest.params = validity.value.params!\n\t\t\trequest.headers = validity.value.headers!\n\t\t\trequest.query = validity.value.query!\n\t\t\trequest.body = validity.value.body!\n\t\t\trequest.cookies = validity.value.cookies!\n\t\t\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipeDefs)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(responsePipe, {\n\t\t\t\t\tresponseHeaders: response.headers,\n\t\t\t\t\tresponseCookies: Object.fromEntries(Object.entries(response.cookies).map(([key, val]) => [key, val.value] as const)),\n\t\t\t\t\tresponse: response.body,\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tif (!validity.valid) throw pipeErrorToValidationError(validity.error)\n\t\t\tresponse.body = validity.value.response!\n\t\t\tresponse.headers = validity.value.responseHeaders!\n\t\t\tresponse.cookieValues = validity.value.responseCookies!\n\t\t\treturn response\n\t\t}\n\t\treturn {\n\t\t\tjsonSchema,\n\t\t\tvalidateRequest,\n\t\t\tvalidateResponse,\n\t\t}\n\t}\n\n\ttest() {\n\t\treturn supertest(this.server)\n\t}\n\n\tasync start() {\n\t\tconst port = this.config.port\n\t\tconst instance = Instance.get()\n\t\tconst { app } = instance.settings\n\t\tif (this.config.healthPath)\n\t\t\tthis.addRoute({\n\t\t\t\tmethod: Methods.get,\n\t\t\t\tpath: this.config.healthPath,\n\t\t\t\thandler: async (req) =>\n\t\t\t\t\treq.res({\n\t\t\t\t\t\tbody: `${instance.id}(${app.name}) service running`,\n\t\t\t\t\t\tcontentType: 'text/plain',\n\t\t\t\t\t}),\n\t\t\t})\n\n\t\tthis.implementations.registerNotFoundHandler(async (req) => {\n\t\t\tconst request = await this.implementations.parseRequest(req)\n\t\t\tthrow new NotFoundError(`Route ${request.path} not found`)\n\t\t})\n\t\tthis.implementations.registerErrorHandler(async (error, _, res) => {\n\t\t\tInstance.get().log.error({ error }, 'Uncaught error in route handler')\n\t\t\tconst response =\n\t\t\t\terror instanceof RequestError\n\t\t\t\t\t? new Response({\n\t\t\t\t\t\t\tbody: error.serializedErrors,\n\t\t\t\t\t\t\tstatus: error.statusCode,\n\t\t\t\t\t\t})\n\t\t\t\t\t: new Response({\n\t\t\t\t\t\t\tbody: [{ message: 'Something went wrong', data: error.message }],\n\t\t\t\t\t\t\tstatus: StatusCodes.BadRequest,\n\t\t\t\t\t\t})\n\t\t\treturn await this.implementations.handleResponse(res, response)\n\t\t})\n\n\t\tawait Promise.all(this.#queue.map((cb) => cb()))\n\t\tconst started = await this.implementations.start(port)\n\t\tif (started) Instance.get().log.info(`${instance.id}(${app.name}) service listening on port ${port}`)\n\t\treturn started\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import d from"http";import l from"cookie-parser";import y from"cors";import p from"express";import h from"express-fileupload";import{rateLimit as f}from"express-rate-limit";import b from"helmet";import{pinoHttp as x}from"pino-http";import{Instance as c}from "../../instance/index.min.mjs";import{getMediaDuration as g}from "../../utilities/index.min.mjs";import{Request as R}from "../requests.min.mjs";import{StatusCodes as S}from "../types.min.mjs";import{Server as v}from "./base.min.mjs";class C extends v{#e;constructor(i){const t=p(),u=c.get();super(d.createServer(t),i,{parseRequest:async e=>{const s=Object.fromEntries(await Promise.all(Object.entries(e.files??{}).map(async([o,r])=>{const a=Array.isArray(r)?r:[r],m=await Promise.all(a.map(async n=>({name:n.name,type:n.mimetype,size:n.size,isTruncated:n.truncated,data:n.data,duration:await g(n.data)})));return[o,m]})));return new R({ip:e.ip,body:e.body??{},cookies:e.cookies??{},params:e.params??{},query:e.query??{},method:e.method,path:e.path,headers:e.headers,files:s})},handleResponse:async(e,s)=>{if(s.piped)s.body.pipe(e);else{Object.entries(s.headers).forEach(([r,a])=>e.header(r,a)),Object.entries(s.cookies).forEach(([r,{value:a,...m}])=>e.cookie(r,a,m));const o=s.body===null||s.body===void 0?"json":"send";e.status(s.status)[o](s.body).end()}},registerRoute:(e,s,o)=>{this.#e[e]?.(s,o)},registerErrorHandler:e=>{this.#e.use(async(s,o,r,a)=>e(s,o,r))},registerNotFoundHandler:e=>{this.#e.use(e)},start:async e=>new Promise((s,o)=>{try{const r=this.server.listen({host:"0.0.0.0",port:e},async()=>s(!0));c.on("close",r.close,1)}catch(r){o(r)}})}),this.#e=t,t.disable("x-powered-by"),i.requests.log&&t.use(x({logger:u.log})),t.use(p.json()),t.use(p.text()),t.use(l()),t.use(b({crossOriginResourcePolicy:{policy:"cross-origin"},contentSecurityPolicy:!1})),t.use(y(this.cors)),t.use(p.urlencoded({extended:!1})),i.publicPath&&t.use(p.static(i.publicPath)),t.use(h({limits:{fileSize:u.settings.utils.maxFileUploadSizeInMb*1024*1024},useTempFiles:!1})),i.requests.rateLimit.enabled&&t.use(f({windowMs:i.requests.rateLimit.periodInMs,limit:i.requests.rateLimit.limit,handler:(e,s)=>s.status(S.TooManyRequests).json([{message:"Too Many Requests"}])}))}}export{C as ExpressServer};
|
|
2
2
|
//# sourceMappingURL=express.min.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/server/impls/express.ts"],"sourcesContent":["import http from 'http'\n\nimport cookie from 'cookie-parser'\nimport cors from 'cors'\nimport express from 'express'\nimport fileUpload from 'express-fileupload'\nimport { rateLimit } from 'express-rate-limit'\n// import slowDown from 'express-slow-down'\nimport helmet from 'helmet'\nimport { pinoHttp } from 'pino-http'\n\nimport { Instance } from '../../instance'\nimport { getMediaDuration } from '../../utilities'\nimport type { ServerConfig } from '../pipes'\nimport { Request } from '../requests'\nimport { type IncomingFile, StatusCodes } from '../types'\nimport { Server } from './base'\n\nexport class ExpressServer extends Server<express.Request, express.Response> {\n\t#expressApp: express.Express\n\n\tconstructor(config: ServerConfig) {\n\t\tconst app = express()\n\t\tconst instance = Instance.get()\n\t\tsuper(http.createServer(app), config, {\n\t\t\tparseRequest: async (req) => {\n\t\t\t\tconst
|
|
1
|
+
{"version":3,"sources":["../../../../src/server/impls/express.ts"],"sourcesContent":["import http from 'http'\n\nimport cookie from 'cookie-parser'\nimport cors from 'cors'\nimport express from 'express'\nimport fileUpload from 'express-fileupload'\nimport { rateLimit } from 'express-rate-limit'\n// import slowDown from 'express-slow-down'\nimport helmet from 'helmet'\nimport { pinoHttp } from 'pino-http'\n\nimport { Instance } from '../../instance'\nimport { getMediaDuration } from '../../utilities'\nimport type { ServerConfig } from '../pipes'\nimport { Request } from '../requests'\nimport { type IncomingFile, StatusCodes } from '../types'\nimport { Server } from './base'\n\nexport class ExpressServer extends Server<express.Request, express.Response> {\n\t#expressApp: express.Express\n\n\tconstructor(config: ServerConfig) {\n\t\tconst app = express()\n\t\tconst instance = Instance.get()\n\t\tsuper(http.createServer(app), config, {\n\t\t\tparseRequest: async (req) => {\n\t\t\t\tconst files = Object.fromEntries(\n\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\tObject.entries(req.files ?? {}).map(async ([key, file]) => {\n\t\t\t\t\t\t\tconst uploads = Array.isArray(file) ? file : [file]\n\t\t\t\t\t\t\tconst fileArray: IncomingFile[] = await Promise.all(\n\t\t\t\t\t\t\t\tuploads.map(async (f) => ({\n\t\t\t\t\t\t\t\t\tname: f.name,\n\t\t\t\t\t\t\t\t\ttype: f.mimetype,\n\t\t\t\t\t\t\t\t\tsize: f.size,\n\t\t\t\t\t\t\t\t\tisTruncated: f.truncated,\n\t\t\t\t\t\t\t\t\tdata: f.data,\n\t\t\t\t\t\t\t\t\tduration: await getMediaDuration(f.data),\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn <const>[key, fileArray]\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\n\t\t\t\treturn new Request<any>({\n\t\t\t\t\tip: req.ip,\n\t\t\t\t\tbody: req.body ?? {},\n\t\t\t\t\tcookies: req.cookies ?? {},\n\t\t\t\t\tparams: req.params ?? {},\n\t\t\t\t\tquery: req.query ?? {},\n\t\t\t\t\tmethod: <any>req.method,\n\t\t\t\t\tpath: req.path,\n\t\t\t\t\theaders: req.headers,\n\t\t\t\t\tfiles,\n\t\t\t\t})\n\t\t\t},\n\t\t\thandleResponse: async (res, response) => {\n\t\t\t\tif (!response.piped) {\n\t\t\t\t\tObject.entries(response.headers).forEach(([key, value]) => res.header(key, value as string))\n\t\t\t\t\tObject.entries(response.cookies).forEach(([key, { value, ...opts }]) => res.cookie(key, value, opts))\n\t\t\t\t\tconst type = response.body === null || response.body === undefined ? 'json' : 'send'\n\t\t\t\t\tres.status(response.status)[type](response.body).end()\n\t\t\t\t} else {\n\t\t\t\t\tresponse.body.pipe(res)\n\t\t\t\t}\n\t\t\t},\n\t\t\tregisterRoute: (method, path, cb) => {\n\t\t\t\tthis.#expressApp[method]?.(path, cb)\n\t\t\t},\n\t\t\tregisterErrorHandler: (cb) => {\n\t\t\t\tthis.#expressApp.use(async (err, req, res, _next) => cb(err, req, res))\n\t\t\t},\n\t\t\tregisterNotFoundHandler: (cb) => {\n\t\t\t\tthis.#expressApp.use(cb)\n\t\t\t},\n\t\t\tstart: async (port) =>\n\t\t\t\tnew Promise((resolve: (s: boolean) => void, reject: (e: Error) => void) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst app = this.server.listen({ host: '0.0.0.0', port }, async () => resolve(true))\n\t\t\t\t\t\tInstance.on('close', app.close, 1)\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treject(<Error>err)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t})\n\t\tthis.#expressApp = app\n\n\t\tapp.disable('x-powered-by')\n\t\tif (config.requests.log) app.use(pinoHttp({ logger: instance.log }))\n\t\tapp.use(express.json())\n\t\tapp.use(express.text())\n\t\tapp.use(cookie())\n\t\tapp.use(\n\t\t\thelmet({\n\t\t\t\tcrossOriginResourcePolicy: { policy: 'cross-origin' },\n\t\t\t\tcontentSecurityPolicy: false,\n\t\t\t}),\n\t\t)\n\t\tapp.use(cors(this.cors))\n\t\tapp.use(express.urlencoded({ extended: false }))\n\t\tif (config.publicPath) app.use(express.static(config.publicPath))\n\t\tapp.use(\n\t\t\tfileUpload({\n\t\t\t\tlimits: { fileSize: instance.settings.utils.maxFileUploadSizeInMb * 1024 * 1024 },\n\t\t\t\tuseTempFiles: false,\n\t\t\t}),\n\t\t)\n\t\tif (config.requests.rateLimit.enabled)\n\t\t\tapp.use(\n\t\t\t\trateLimit({\n\t\t\t\t\twindowMs: config.requests.rateLimit.periodInMs,\n\t\t\t\t\tlimit: config.requests.rateLimit.limit,\n\t\t\t\t\thandler: (_: express.Request, res: express.Response) =>\n\t\t\t\t\t\tres.status(StatusCodes.TooManyRequests).json([{ message: 'Too Many Requests' }]),\n\t\t\t\t}),\n\t\t\t)\n\t\t/* if (this.settings.slowdown.enabled) app.use(slowDown({\n\t\t\twindowMs: this.settings.slowdown.periodInMs,\n\t\t\tdelayAfter: this.settings.slowdown.delayAfter,\n\t\t\tdelayMs: this.settings.slowdown.delayInMs\n\t\t})) */\n\t}\n}\n"],"mappings":"AAAA,OAAOA,MAAU,OAEjB,OAAOC,MAAY,gBACnB,OAAOC,MAAU,OACjB,OAAOC,MAAa,UACpB,OAAOC,MAAgB,qBACvB,OAAS,aAAAC,MAAiB,qBAE1B,OAAOC,MAAY,SACnB,OAAS,YAAAC,MAAgB,YAEzB,OAAS,YAAAC,MAAgB,iBACzB,OAAS,oBAAAC,MAAwB,kBAEjC,OAAS,WAAAC,MAAe,cACxB,OAA4B,eAAAC,MAAmB,WAC/C,OAAS,UAAAC,MAAc,SAEhB,MAAMC,UAAsBD,CAA0C,CAC5EE,GAEA,YAAYC,EAAsB,CACjC,MAAMC,EAAMb,EAAQ,EACdc,EAAWT,EAAS,IAAI,EAC9B,MAAMR,EAAK,aAAagB,CAAG,EAAGD,EAAQ,CACrC,aAAc,MAAOG,GAAQ,CAC5B,MAAMC,EAAQ,OAAO,YACpB,MAAM,QAAQ,IACb,OAAO,QAAQD,EAAI,OAAS,CAAC,CAAC,EAAE,IAAI,MAAO,CAACE,EAAKC,CAAI,IAAM,CAC1D,MAAMC,EAAU,MAAM,QAAQD,CAAI,EAAIA,EAAO,CAACA,CAAI,EAC5CE,EAA4B,MAAM,QAAQ,IAC/CD,EAAQ,IAAI,MAAOE,IAAO,CACzB,KAAMA,EAAE,KACR,KAAMA,EAAE,SACR,KAAMA,EAAE,KACR,YAAaA,EAAE,UACf,KAAMA,EAAE,KACR,SAAU,MAAMf,EAAiBe,EAAE,IAAI,CACxC,EAAE,CACH,EACA,MAAc,CAACJ,EAAKG,CAAS,CAC9B,CAAC,CACF,CACD,EAEA,OAAO,IAAIb,EAAa,CACvB,GAAIQ,EAAI,GACR,KAAMA,EAAI,MAAQ,CAAC,EACnB,QAASA,EAAI,SAAW,CAAC,EACzB,OAAQA,EAAI,QAAU,CAAC,EACvB,MAAOA,EAAI,OAAS,CAAC,EACrB,OAAaA,EAAI,OACjB,KAAMA,EAAI,KACV,QAASA,EAAI,QACb,MAAAC,CACD,CAAC,CACF,EACA,eAAgB,MAAOM,EAAKC,IAAa,CACxC,GAAKA,EAAS,MAMbA,EAAS,KAAK,KAAKD,CAAG,MANF,CACpB,OAAO,QAAQC,EAAS,OAAO,EAAE,QAAQ,CAAC,CAACN,EAAKO,CAAK,IAAMF,EAAI,OAAOL,EAAKO,CAAe,CAAC,EAC3F,OAAO,QAAQD,EAAS,OAAO,EAAE,QAAQ,CAAC,CAACN,EAAK,CAAE,MAAAO,EAAO,GAAGC,CAAK,CAAC,IAAMH,EAAI,OAAOL,EAAKO,EAAOC,CAAI,CAAC,EACpG,MAAMC,EAAOH,EAAS,OAAS,MAAQA,EAAS,OAAS,OAAY,OAAS,OAC9ED,EAAI,OAAOC,EAAS,MAAM,EAAEG,CAAI,EAAEH,EAAS,IAAI,EAAE,IAAI,CACtD,CAGD,EACA,cAAe,CAACI,EAAQC,EAAMC,IAAO,CACpC,KAAKlB,GAAYgB,CAAM,IAAIC,EAAMC,CAAE,CACpC,EACA,qBAAuBA,GAAO,CAC7B,KAAKlB,GAAY,IAAI,MAAOmB,EAAKf,EAAKO,EAAKS,IAAUF,EAAGC,EAAKf,EAAKO,CAAG,CAAC,CACvE,EACA,wBAA0BO,GAAO,CAChC,KAAKlB,GAAY,IAAIkB,CAAE,CACxB,EACA,MAAO,MAAOG,GACb,IAAI,QAAQ,CAACC,EAA+BC,IAA+B,CAC1E,GAAI,CACH,MAAMrB,EAAM,KAAK,OAAO,OAAO,CAAE,KAAM,UAAW,KAAAmB,CAAK,EAAG,SAAYC,EAAQ,EAAI,CAAC,EACnF5B,EAAS,GAAG,QAASQ,EAAI,MAAO,CAAC,CAClC,OAASiB,EAAK,CACbI,EAAcJ,CAAG,CAClB,CACD,CAAC,CACH,CAAC,EACD,KAAKnB,GAAcE,EAEnBA,EAAI,QAAQ,cAAc,EACtBD,EAAO,SAAS,KAAKC,EAAI,IAAIT,EAAS,CAAE,OAAQU,EAAS,GAAI,CAAC,CAAC,EACnED,EAAI,IAAIb,EAAQ,KAAK,CAAC,EACtBa,EAAI,IAAIb,EAAQ,KAAK,CAAC,EACtBa,EAAI,IAAIf,EAAO,CAAC,EAChBe,EAAI,IACHV,EAAO,CACN,0BAA2B,CAAE,OAAQ,cAAe,EACpD,sBAAuB,EACxB,CAAC,CACF,EACAU,EAAI,IAAId,EAAK,KAAK,IAAI,CAAC,EACvBc,EAAI,IAAIb,EAAQ,WAAW,CAAE,SAAU,EAAM,CAAC,CAAC,EAC3CY,EAAO,YAAYC,EAAI,IAAIb,EAAQ,OAAOY,EAAO,UAAU,CAAC,EAChEC,EAAI,IACHZ,EAAW,CACV,OAAQ,CAAE,SAAUa,EAAS,SAAS,MAAM,sBAAwB,KAAO,IAAK,EAChF,aAAc,EACf,CAAC,CACF,EACIF,EAAO,SAAS,UAAU,SAC7BC,EAAI,IACHX,EAAU,CACT,SAAUU,EAAO,SAAS,UAAU,WACpC,MAAOA,EAAO,SAAS,UAAU,MACjC,QAAS,CAACuB,EAAoBb,IAC7BA,EAAI,OAAOd,EAAY,eAAe,EAAE,KAAK,CAAC,CAAE,QAAS,mBAAoB,CAAC,CAAC,CACjF,CAAC,CACF,CAMF,CACD","names":["http","cookie","cors","express","fileUpload","rateLimit","helmet","pinoHttp","Instance","getMediaDuration","Request","StatusCodes","Server","ExpressServer","#expressApp","config","app","instance","req","files","key","file","uploads","fileArray","f","res","response","value","opts","type","method","path","cb","err","_next","port","resolve","reject","_"]}
|
|
@@ -18,16 +18,6 @@ class ExpressServer extends Server {
|
|
|
18
18
|
const instance = Instance.get();
|
|
19
19
|
super(http.createServer(app), config, {
|
|
20
20
|
parseRequest: async (req) => {
|
|
21
|
-
const allHeaders = Object.fromEntries(Object.entries(req.headers).map(([key, val]) => [key, val ?? null]));
|
|
22
|
-
const headers = {
|
|
23
|
-
...allHeaders,
|
|
24
|
-
Authorization: req.get("authorization"),
|
|
25
|
-
RefreshToken: req.get("x-refresh-token"),
|
|
26
|
-
ApiKey: req.get("x-api-key"),
|
|
27
|
-
ContentType: req.get("content-type"),
|
|
28
|
-
Referer: req.get("referer"),
|
|
29
|
-
UserAgent: req.get("user-agent")
|
|
30
|
-
};
|
|
31
21
|
const files = Object.fromEntries(
|
|
32
22
|
await Promise.all(
|
|
33
23
|
Object.entries(req.files ?? {}).map(async ([key, file]) => {
|
|
@@ -54,9 +44,8 @@ class ExpressServer extends Server {
|
|
|
54
44
|
query: req.query ?? {},
|
|
55
45
|
method: req.method,
|
|
56
46
|
path: req.path,
|
|
57
|
-
headers,
|
|
58
|
-
files
|
|
59
|
-
context: {}
|
|
47
|
+
headers: req.headers,
|
|
48
|
+
files
|
|
60
49
|
});
|
|
61
50
|
},
|
|
62
51
|
handleResponse: async (res, response) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/server/impls/express.ts"],"sourcesContent":["import http from 'http'\n\nimport cookie from 'cookie-parser'\nimport cors from 'cors'\nimport express from 'express'\nimport fileUpload from 'express-fileupload'\nimport { rateLimit } from 'express-rate-limit'\n// import slowDown from 'express-slow-down'\nimport helmet from 'helmet'\nimport { pinoHttp } from 'pino-http'\n\nimport { Instance } from '../../instance'\nimport { getMediaDuration } from '../../utilities'\nimport type { ServerConfig } from '../pipes'\nimport { Request } from '../requests'\nimport { type IncomingFile, StatusCodes } from '../types'\nimport { Server } from './base'\n\nexport class ExpressServer extends Server<express.Request, express.Response> {\n\t#expressApp: express.Express\n\n\tconstructor(config: ServerConfig) {\n\t\tconst app = express()\n\t\tconst instance = Instance.get()\n\t\tsuper(http.createServer(app), config, {\n\t\t\tparseRequest: async (req) => {\n\t\t\t\tconst
|
|
1
|
+
{"version":3,"sources":["../../../../src/server/impls/express.ts"],"sourcesContent":["import http from 'http'\n\nimport cookie from 'cookie-parser'\nimport cors from 'cors'\nimport express from 'express'\nimport fileUpload from 'express-fileupload'\nimport { rateLimit } from 'express-rate-limit'\n// import slowDown from 'express-slow-down'\nimport helmet from 'helmet'\nimport { pinoHttp } from 'pino-http'\n\nimport { Instance } from '../../instance'\nimport { getMediaDuration } from '../../utilities'\nimport type { ServerConfig } from '../pipes'\nimport { Request } from '../requests'\nimport { type IncomingFile, StatusCodes } from '../types'\nimport { Server } from './base'\n\nexport class ExpressServer extends Server<express.Request, express.Response> {\n\t#expressApp: express.Express\n\n\tconstructor(config: ServerConfig) {\n\t\tconst app = express()\n\t\tconst instance = Instance.get()\n\t\tsuper(http.createServer(app), config, {\n\t\t\tparseRequest: async (req) => {\n\t\t\t\tconst files = Object.fromEntries(\n\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\tObject.entries(req.files ?? {}).map(async ([key, file]) => {\n\t\t\t\t\t\t\tconst uploads = Array.isArray(file) ? file : [file]\n\t\t\t\t\t\t\tconst fileArray: IncomingFile[] = await Promise.all(\n\t\t\t\t\t\t\t\tuploads.map(async (f) => ({\n\t\t\t\t\t\t\t\t\tname: f.name,\n\t\t\t\t\t\t\t\t\ttype: f.mimetype,\n\t\t\t\t\t\t\t\t\tsize: f.size,\n\t\t\t\t\t\t\t\t\tisTruncated: f.truncated,\n\t\t\t\t\t\t\t\t\tdata: f.data,\n\t\t\t\t\t\t\t\t\tduration: await getMediaDuration(f.data),\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn <const>[key, fileArray]\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\n\t\t\t\treturn new Request<any>({\n\t\t\t\t\tip: req.ip,\n\t\t\t\t\tbody: req.body ?? {},\n\t\t\t\t\tcookies: req.cookies ?? {},\n\t\t\t\t\tparams: req.params ?? {},\n\t\t\t\t\tquery: req.query ?? {},\n\t\t\t\t\tmethod: <any>req.method,\n\t\t\t\t\tpath: req.path,\n\t\t\t\t\theaders: req.headers,\n\t\t\t\t\tfiles,\n\t\t\t\t})\n\t\t\t},\n\t\t\thandleResponse: async (res, response) => {\n\t\t\t\tif (!response.piped) {\n\t\t\t\t\tObject.entries(response.headers).forEach(([key, value]) => res.header(key, value as string))\n\t\t\t\t\tObject.entries(response.cookies).forEach(([key, { value, ...opts }]) => res.cookie(key, value, opts))\n\t\t\t\t\tconst type = response.body === null || response.body === undefined ? 'json' : 'send'\n\t\t\t\t\tres.status(response.status)[type](response.body).end()\n\t\t\t\t} else {\n\t\t\t\t\tresponse.body.pipe(res)\n\t\t\t\t}\n\t\t\t},\n\t\t\tregisterRoute: (method, path, cb) => {\n\t\t\t\tthis.#expressApp[method]?.(path, cb)\n\t\t\t},\n\t\t\tregisterErrorHandler: (cb) => {\n\t\t\t\tthis.#expressApp.use(async (err, req, res, _next) => cb(err, req, res))\n\t\t\t},\n\t\t\tregisterNotFoundHandler: (cb) => {\n\t\t\t\tthis.#expressApp.use(cb)\n\t\t\t},\n\t\t\tstart: async (port) =>\n\t\t\t\tnew Promise((resolve: (s: boolean) => void, reject: (e: Error) => void) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst app = this.server.listen({ host: '0.0.0.0', port }, async () => resolve(true))\n\t\t\t\t\t\tInstance.on('close', app.close, 1)\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\treject(<Error>err)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t})\n\t\tthis.#expressApp = app\n\n\t\tapp.disable('x-powered-by')\n\t\tif (config.requests.log) app.use(pinoHttp({ logger: instance.log }))\n\t\tapp.use(express.json())\n\t\tapp.use(express.text())\n\t\tapp.use(cookie())\n\t\tapp.use(\n\t\t\thelmet({\n\t\t\t\tcrossOriginResourcePolicy: { policy: 'cross-origin' },\n\t\t\t\tcontentSecurityPolicy: false,\n\t\t\t}),\n\t\t)\n\t\tapp.use(cors(this.cors))\n\t\tapp.use(express.urlencoded({ extended: false }))\n\t\tif (config.publicPath) app.use(express.static(config.publicPath))\n\t\tapp.use(\n\t\t\tfileUpload({\n\t\t\t\tlimits: { fileSize: instance.settings.utils.maxFileUploadSizeInMb * 1024 * 1024 },\n\t\t\t\tuseTempFiles: false,\n\t\t\t}),\n\t\t)\n\t\tif (config.requests.rateLimit.enabled)\n\t\t\tapp.use(\n\t\t\t\trateLimit({\n\t\t\t\t\twindowMs: config.requests.rateLimit.periodInMs,\n\t\t\t\t\tlimit: config.requests.rateLimit.limit,\n\t\t\t\t\thandler: (_: express.Request, res: express.Response) =>\n\t\t\t\t\t\tres.status(StatusCodes.TooManyRequests).json([{ message: 'Too Many Requests' }]),\n\t\t\t\t}),\n\t\t\t)\n\t\t/* if (this.settings.slowdown.enabled) app.use(slowDown({\n\t\t\twindowMs: this.settings.slowdown.periodInMs,\n\t\t\tdelayAfter: this.settings.slowdown.delayAfter,\n\t\t\tdelayMs: this.settings.slowdown.delayInMs\n\t\t})) */\n\t}\n}\n"],"mappings":"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","names":["app"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import l from"@fastify/cookie";import u from"@fastify/cors";import y from"@fastify/formbody";import p from"@fastify/helmet";import c from"@fastify/multipart";import d from"@fastify/rate-limit";import g from"@fastify/static";import h from"fastify";import F from"qs";import{ValidationError as R}from "../../errors/index.min.mjs";import{Instance as m}from "../../instance/index.min.mjs";import{getMediaDuration as S}from "../../utilities/index.min.mjs";import{Request as b}from "../requests.min.mjs";import{StatusCodes as q}from "../types.min.mjs";import{Server as w}from "./base.min.mjs";class N extends w{constructor(i){const o=m.get(),r=h({disableRequestLogging:!i.requests.log,loggerInstance:i.requests.log?o.log:void 0,ajv:{customOptions:{coerceTypes:!1}},routerOptions:{ignoreTrailingSlash:!0,caseSensitive:!1},schemaErrorFormatter:(e,t)=>new R(e.map(s=>({messages:[s.message??""],field:`${t}${s.instancePath}`.replaceAll("/",".")})))});super(r.server,i,{parseRequest:async e=>{const{body:t,files:s}=C(e.body??{});return new b({ip:e.ip,body:t,cookies:e.cookies??{},params:e.params??{},query:e.query??{},method:e.method,path:e.url,headers:e.headers,files:s})},handleResponse:async(e,t)=>{for(const[s,{value:n,...f}]of Object.entries(t.cookies))e=e.setCookie(s,n,f);await e.status(t.status).headers(t.headers).send(t.body)},registerRoute:(e,t,s)=>{r.register(async n=>{n.route({url:t,method:e,handler:s})})},registerErrorHandler:e=>{r.setErrorHandler(e)},registerNotFoundHandler:e=>{r.setNotFoundHandler(e)},start:async e=>(await r.ready(),await r.listen({port:e,host:"0.0.0.0"}),m.on("close",r.close,1),!0)}),r.decorateRequest("savedReq",null),r.setValidatorCompiler(()=>()=>!0),r.setSerializerCompiler(()=>e=>JSON.stringify(e)),i.publicPath&&r.register(g,{root:i.publicPath}),r.register(l,{}),r.register(u,this.cors),r.register(y,{parser:e=>F.parse(e)}),r.register(p,{crossOriginResourcePolicy:{policy:"cross-origin"},contentSecurityPolicy:!1}),r.register(c,{attachFieldsToBody:"keyValues",throwFileSizeLimit:!1,limits:{fileSize:o.settings.utils.maxFileUploadSizeInMb*1024*1024},onFile:async e=>{const t=await e.toBuffer(),s={name:e.filename,type:e.mimetype,size:t.byteLength,isTruncated:e.file.truncated,data:t,duration:await S(t)};e.value=s}}),i.requests.rateLimit.enabled&&r.register(d,{max:i.requests.rateLimit.limit,timeWindow:i.requests.rateLimit.periodInMs,errorResponseBuilder:(e,t)=>({statusCode:q.TooManyRequests,message:JSON.stringify([{message:`Too Many Requests. Retry in ${t.after}`}])})})}}function C(a){if(typeof a!="object")return{body:a,files:{}};const i=Object.entries(a??{}),o=t=>Array.isArray(t)?o(t.at(0)):Buffer.isBuffer(t?.data),r=i.filter(([t,s])=>o(s)).map(([t,s])=>[t,Array.isArray(s)?s:[s]]),e=i.filter(([t,s])=>!o(s));return{body:Object.fromEntries(e),files:Object.fromEntries(r)}}export{N as FastifyServer};
|
|
2
2
|
//# sourceMappingURL=fastify.min.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/server/impls/fastify.ts"],"sourcesContent":["import fastifyCookie from '@fastify/cookie'\nimport fastifyCors from '@fastify/cors'\nimport fastifyFormBody from '@fastify/formbody'\nimport fastifyHelmet from '@fastify/helmet'\nimport fastifyMultipart from '@fastify/multipart'\nimport fastifyRateLimit from '@fastify/rate-limit'\nimport fastifyStatic from '@fastify/static'\nimport type { FastifyReply, FastifyRequest } from 'fastify'\nimport Fastify from 'fastify'\n// import fastifySlowDown from 'fastify-slow-down'\nimport qs from 'qs'\n\nimport { ValidationError } from '../../errors'\nimport { Instance } from '../../instance'\nimport { getMediaDuration } from '../../utilities'\nimport type { ServerConfig } from '../pipes'\nimport { Request } from '../requests'\nimport { type IncomingFile, StatusCodes } from '../types'\nimport { Server } from './base'\n\nexport class FastifyServer extends Server<FastifyRequest, FastifyReply> {\n\tconstructor(config: ServerConfig) {\n\t\tconst instance = Instance.get()\n\t\tconst app = Fastify({\n\t\t\tdisableRequestLogging: !config.requests.log,\n\t\t\tloggerInstance: config.requests.log ? instance.log : undefined,\n\t\t\tajv: { customOptions: { coerceTypes: false } },\n\t\t\trouterOptions: {\n\t\t\t\tignoreTrailingSlash: true,\n\t\t\t\tcaseSensitive: false,\n\t\t\t},\n\t\t\tschemaErrorFormatter: (errors, data) =>\n\t\t\t\tnew ValidationError(\n\t\t\t\t\terrors.map((error) => ({\n\t\t\t\t\t\tmessages: [error.message ?? ''],\n\t\t\t\t\t\tfield: `${data}${error.instancePath}`.replaceAll('/', '.'),\n\t\t\t\t\t})),\n\t\t\t\t),\n\t\t})\n\t\tsuper(app.server, config, {\n\t\t\tparseRequest: async (req) => {\n\t\t\t\tconst
|
|
1
|
+
{"version":3,"sources":["../../../../src/server/impls/fastify.ts"],"sourcesContent":["import fastifyCookie from '@fastify/cookie'\nimport fastifyCors from '@fastify/cors'\nimport fastifyFormBody from '@fastify/formbody'\nimport fastifyHelmet from '@fastify/helmet'\nimport fastifyMultipart from '@fastify/multipart'\nimport fastifyRateLimit from '@fastify/rate-limit'\nimport fastifyStatic from '@fastify/static'\nimport type { FastifyReply, FastifyRequest } from 'fastify'\nimport Fastify from 'fastify'\n// import fastifySlowDown from 'fastify-slow-down'\nimport qs from 'qs'\n\nimport { ValidationError } from '../../errors'\nimport { Instance } from '../../instance'\nimport { getMediaDuration } from '../../utilities'\nimport type { ServerConfig } from '../pipes'\nimport { Request } from '../requests'\nimport { type IncomingFile, StatusCodes } from '../types'\nimport { Server } from './base'\n\nexport class FastifyServer extends Server<FastifyRequest, FastifyReply> {\n\tconstructor(config: ServerConfig) {\n\t\tconst instance = Instance.get()\n\t\tconst app = Fastify({\n\t\t\tdisableRequestLogging: !config.requests.log,\n\t\t\tloggerInstance: config.requests.log ? instance.log : undefined,\n\t\t\tajv: { customOptions: { coerceTypes: false } },\n\t\t\trouterOptions: {\n\t\t\t\tignoreTrailingSlash: true,\n\t\t\t\tcaseSensitive: false,\n\t\t\t},\n\t\t\tschemaErrorFormatter: (errors, data) =>\n\t\t\t\tnew ValidationError(\n\t\t\t\t\terrors.map((error) => ({\n\t\t\t\t\t\tmessages: [error.message ?? ''],\n\t\t\t\t\t\tfield: `${data}${error.instancePath}`.replaceAll('/', '.'),\n\t\t\t\t\t})),\n\t\t\t\t),\n\t\t})\n\t\tsuper(app.server, config, {\n\t\t\tparseRequest: async (req) => {\n\t\t\t\tconst { body, files } = excludeBufferKeys(req.body ?? {})\n\n\t\t\t\treturn new Request({\n\t\t\t\t\tip: req.ip,\n\t\t\t\t\tbody,\n\t\t\t\t\tcookies: req.cookies ?? {},\n\t\t\t\t\tparams: req.params ?? <any>{},\n\t\t\t\t\tquery: req.query ?? {},\n\t\t\t\t\tmethod: <any>req.method,\n\t\t\t\t\tpath: req.url,\n\t\t\t\t\theaders: req.headers,\n\t\t\t\t\tfiles,\n\t\t\t\t})\n\t\t\t},\n\t\t\thandleResponse: async (res, response) => {\n\t\t\t\tfor (const [key, { value, ...opts }] of Object.entries(response.cookies)) res = res.setCookie(key, value, opts)\n\t\t\t\tawait res.status(response.status).headers(response.headers).send(response.body)\n\t\t\t},\n\t\t\tregisterRoute: (method, path, cb) => {\n\t\t\t\tapp.register(async (inst) => {\n\t\t\t\t\tinst.route({ url: path, method, handler: cb })\n\t\t\t\t})\n\t\t\t},\n\t\t\tregisterErrorHandler: (cb) => {\n\t\t\t\tapp.setErrorHandler(cb)\n\t\t\t},\n\t\t\tregisterNotFoundHandler: (cb) => {\n\t\t\t\tapp.setNotFoundHandler(cb)\n\t\t\t},\n\t\t\tstart: async (port) => {\n\t\t\t\tawait app.ready()\n\t\t\t\tawait app.listen({ port, host: '0.0.0.0' })\n\t\t\t\tInstance.on('close', app.close, 1)\n\t\t\t\treturn true\n\t\t\t},\n\t\t})\n\n\t\tapp.decorateRequest('savedReq', null)\n\t\tapp.setValidatorCompiler(() => () => true)\n\t\tapp.setSerializerCompiler(() => (data) => JSON.stringify(data))\n\t\tif (config.publicPath) app.register(fastifyStatic, { root: config.publicPath })\n\t\tapp.register(fastifyCookie, {})\n\t\tapp.register(fastifyCors, this.cors)\n\t\tapp.register(fastifyFormBody, { parser: (str) => qs.parse(str) })\n\t\tapp.register(fastifyHelmet, { crossOriginResourcePolicy: { policy: 'cross-origin' }, contentSecurityPolicy: false })\n\t\tapp.register(fastifyMultipart, {\n\t\t\tattachFieldsToBody: 'keyValues',\n\t\t\tthrowFileSizeLimit: false,\n\t\t\tlimits: { fileSize: instance.settings.utils.maxFileUploadSizeInMb * 1024 * 1024 },\n\t\t\tonFile: async (f) => {\n\t\t\t\tconst buffer = await f.toBuffer()\n\t\t\t\tconst parsed: IncomingFile = {\n\t\t\t\t\tname: f.filename,\n\t\t\t\t\ttype: f.mimetype,\n\t\t\t\t\tsize: buffer.byteLength,\n\t\t\t\t\tisTruncated: f.file.truncated,\n\t\t\t\t\tdata: buffer,\n\t\t\t\t\tduration: await getMediaDuration(buffer),\n\t\t\t\t}\n\t\t\t\t// @ts-ignore\n\t\t\t\tf.value = parsed\n\t\t\t},\n\t\t})\n\t\t/* if (this.settings.slowdown.enabled) app.register(fastifySlowDown, {\n\t\t\ttimeWindow: this.settings.slowdown.periodInMs,\n\t\t\tdelayAfter: this.settings.slowdown.delayAfter,\n\t\t\tdelay: this.settings.slowdown.delayInMs\n\t\t}) */\n\t\tif (config.requests.rateLimit.enabled)\n\t\t\tapp.register(fastifyRateLimit, {\n\t\t\t\tmax: config.requests.rateLimit.limit,\n\t\t\t\ttimeWindow: config.requests.rateLimit.periodInMs,\n\t\t\t\terrorResponseBuilder: (_, context) => ({\n\t\t\t\t\tstatusCode: StatusCodes.TooManyRequests,\n\t\t\t\t\tmessage: JSON.stringify([{ message: `Too Many Requests. Retry in ${context.after}` }]),\n\t\t\t\t}),\n\t\t\t})\n\t}\n}\n\nfunction excludeBufferKeys<T>(body: T) {\n\tif (typeof body !== 'object') return { body, files: {} }\n\tconst entries = Object.entries(body ?? {})\n\tconst isFile = (val: any) => (Array.isArray(val) ? isFile(val.at(0)) : Buffer.isBuffer(val?.data))\n\tconst fileEntries = entries.filter(([_, value]) => isFile(value)).map(([key, value]) => [key, Array.isArray(value) ? value : [value]])\n\tconst nonFileEntries = entries.filter(([_, value]) => !isFile(value))\n\treturn {\n\t\tbody: <T>Object.fromEntries(nonFileEntries),\n\t\tfiles: <Record<string, IncomingFile[]>>Object.fromEntries(fileEntries),\n\t}\n}\n"],"mappings":"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","names":["fastifyCookie","fastifyCors","fastifyFormBody","fastifyHelmet","fastifyMultipart","fastifyRateLimit","fastifyStatic","Fastify","qs","ValidationError","Instance","getMediaDuration","Request","StatusCodes","Server","FastifyServer","config","instance","app","errors","data","error","req","body","files","excludeBufferKeys","res","response","key","value","opts","method","path","cb","inst","port","str","f","buffer","parsed","_","context","entries","isFile","val","fileEntries","nonFileEntries"]}
|
|
@@ -33,16 +33,6 @@ class FastifyServer extends Server {
|
|
|
33
33
|
});
|
|
34
34
|
super(app.server, config, {
|
|
35
35
|
parseRequest: async (req) => {
|
|
36
|
-
const allHeaders = Object.fromEntries(Object.entries(req.headers).map(([key, val]) => [key, val ?? null]));
|
|
37
|
-
const headers = {
|
|
38
|
-
...allHeaders,
|
|
39
|
-
Authorization: req.headers["authorization"]?.toString(),
|
|
40
|
-
RefreshToken: req.headers["x-refresh-token"]?.toString(),
|
|
41
|
-
ApiKey: req.headers["x-api-key"]?.toString(),
|
|
42
|
-
ContentType: req.headers["content-type"]?.toString(),
|
|
43
|
-
Referer: req.headers["referer"]?.toString(),
|
|
44
|
-
UserAgent: req.headers["user-agent"]?.toString()
|
|
45
|
-
};
|
|
46
36
|
const { body, files } = excludeBufferKeys(req.body ?? {});
|
|
47
37
|
return new Request({
|
|
48
38
|
ip: req.ip,
|
|
@@ -52,9 +42,8 @@ class FastifyServer extends Server {
|
|
|
52
42
|
query: req.query ?? {},
|
|
53
43
|
method: req.method,
|
|
54
44
|
path: req.url,
|
|
55
|
-
headers,
|
|
56
|
-
files
|
|
57
|
-
context: {}
|
|
45
|
+
headers: req.headers,
|
|
46
|
+
files
|
|
58
47
|
});
|
|
59
48
|
},
|
|
60
49
|
handleResponse: async (res, response) => {
|