equipped 5.0.26 → 5.0.27
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 +8 -0
- package/dist/cjs/dbs/pipes.cjs +17 -17
- package/dist/cjs/dbs/pipes.cjs.map +1 -1
- package/dist/cjs/dbs/pipes.min.cjs +1 -1
- package/dist/cjs/dbs/pipes.min.cjs.map +1 -1
- package/dist/cjs/server/impls/base.cjs +13 -11
- 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/esm/dbs/pipes.min.mjs +1 -1
- package/dist/esm/dbs/pipes.min.mjs.map +1 -1
- package/dist/esm/dbs/pipes.mjs +17 -17
- package/dist/esm/dbs/pipes.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 +13 -11
- package/dist/esm/server/impls/base.mjs.map +1 -1
- package/dist/types/{core-VE67ynvC.d.ts → core-BuPovjLX.d.ts} +16 -30
- package/dist/types/{db-CmGSoEjh.d.ts → db-Gck93XBL.d.ts} +1 -1
- package/dist/types/dbs/index.d.ts +3 -3
- package/dist/types/dbs/pipes.js +17 -17
- package/dist/types/{fastify-aW8KHCpj.d.ts → fastify-B7DQ55s8.d.ts} +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/instance/index.d.ts +3 -3
- package/dist/types/server/impls/base.js +13 -11
- package/dist/types/server/index.d.ts +2 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [5.0.27](https://github.com/kevinand11/equipped/compare/v5.0.26...v5.0.27) (2025-08-13)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* compile request and response pipes before server starts ([79fbe2d](https://github.com/kevinand11/equipped/commit/79fbe2d8c6f0a1eb2bb07d4ce5447be02d8f90fc))
|
|
11
|
+
* recursive fn not defined when validating queryParams ([d7b4650](https://github.com/kevinand11/equipped/commit/d7b4650b7604f0097bf8d481febc6646aec697fc))
|
|
12
|
+
|
|
5
13
|
### [5.0.26](https://github.com/kevinand11/equipped/compare/v5.0.25...v5.0.26) (2025-08-11)
|
|
6
14
|
|
|
7
15
|
|
package/dist/cjs/dbs/pipes.cjs
CHANGED
|
@@ -17,24 +17,24 @@ var Conditions = /* @__PURE__ */ ((Conditions2) => {
|
|
|
17
17
|
Conditions2["exists"] = "exists";
|
|
18
18
|
return Conditions2;
|
|
19
19
|
})(Conditions || {});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
value: _valleyed.v.array(queryWhereBlock)
|
|
32
|
-
}),
|
|
33
|
-
regular: queryWhere
|
|
20
|
+
const queryKeys = _valleyed.v.catch(_valleyed.v.defaults(_valleyed.v.in(["and" /* and */, "or" /* or */]), "and" /* and */), "and" /* and */);
|
|
21
|
+
const queryWhere = _valleyed.v.object({
|
|
22
|
+
field: _valleyed.v.string(),
|
|
23
|
+
value: _valleyed.v.any(),
|
|
24
|
+
condition: _valleyed.v.catch(_valleyed.v.defaults(_valleyed.v.in(Object.values(Conditions)), "eq" /* eq */), "eq" /* eq */)
|
|
25
|
+
});
|
|
26
|
+
const queryWhereBlock = _valleyed.v.recursive(
|
|
27
|
+
() => _valleyed.v.discriminate((d) => Object.values(QueryKeys).includes(d.condition) ? "block" : "regular", {
|
|
28
|
+
block: _valleyed.v.object({
|
|
29
|
+
condition: queryKeys,
|
|
30
|
+
value: _valleyed.v.array(queryWhereBlock)
|
|
34
31
|
}),
|
|
35
|
-
|
|
36
|
-
)
|
|
37
|
-
|
|
32
|
+
regular: queryWhere
|
|
33
|
+
}),
|
|
34
|
+
"QueryWhereBlock"
|
|
35
|
+
);
|
|
36
|
+
const queryWhereClause = _valleyed.v.defaults(_valleyed.v.array(queryWhereBlock), []);
|
|
37
|
+
function queryParamsPipe() {
|
|
38
38
|
return _valleyed.v.meta(
|
|
39
39
|
_valleyed.v.object({
|
|
40
40
|
all: _valleyed.v.defaults(_valleyed.v.boolean(), false),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/dbs/pipes.ts","/home/runner/work/equipped/equipped/dist/cjs/dbs/pipes.cjs"],"names":["QueryKeys","Conditions"],"mappings":"AAAA,6GAAsE;AAEtE,iDAAyB;AAElB,IAAK,UAAA,kBAAL,CAAA,CAAKA,UAAAA,EAAAA,GAAL;AACN,EAAAA,UAAAA,CAAA,KAAA,EAAA,EAAM,KAAA;AACN,EAAAA,UAAAA,CAAA,IAAA,EAAA,EAAK,IAAA;AAFM,EAAA,OAAAA,UAAAA;AAAA,CAAA,CAAA,CAAA,UAAA,GAAA,CAAA,CAAA,CAAA;AAKL,IAAK,WAAA,kBAAL,CAAA,CAAKC,WAAAA,EAAAA,GAAL;AACN,EAAAA,WAAAA,CAAA,IAAA,EAAA,EAAK,IAAA;AACL,EAAAA,WAAAA,CAAA,KAAA,EAAA,EAAM,KAAA;AACN,EAAAA,WAAAA,CAAA,IAAA,EAAA,EAAK,IAAA;AACL,EAAAA,WAAAA,CAAA,KAAA,EAAA,EAAM,KAAA;AACN,EAAAA,WAAAA,CAAA,IAAA,EAAA,EAAK,IAAA;AACL,EAAAA,WAAAA,CAAA,IAAA,EAAA,EAAK,IAAA;AACL,EAAAA,WAAAA,CAAA,IAAA,EAAA,EAAK,IAAA;AACL,EAAAA,WAAAA,CAAA,KAAA,EAAA,EAAM,KAAA;AACN,EAAAA,WAAAA,CAAA,QAAA,EAAA,EAAS,QAAA;AATE,EAAA,OAAAA,WAAAA;AAAA,CAAA,CAAA,CAAA,WAAA,GAAA,CAAA,CAAA,CAAA;
|
|
1
|
+
{"version":3,"sources":["../../../src/dbs/pipes.ts","/home/runner/work/equipped/equipped/dist/cjs/dbs/pipes.cjs"],"names":["QueryKeys","Conditions"],"mappings":"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","file":"/home/runner/work/equipped/equipped/dist/cjs/dbs/pipes.cjs","sourcesContent":["import { ConditionalObjectKeys, Pipe, PipeInput, PipeOutput, v } from 'valleyed'\n\nimport { Instance } from '../instance'\n\nexport enum QueryKeys {\n\tand = 'and',\n\tor = 'or',\n}\n\nexport enum Conditions {\n\tlt = 'lt',\n\tlte = 'lte',\n\tgt = 'gt',\n\tgte = 'gte',\n\teq = 'eq',\n\tne = 'ne',\n\tin = 'in',\n\tnin = 'nin',\n\texists = 'exists',\n}\n\nconst queryKeys = v.catch(v.defaults(v.in([QueryKeys.and, QueryKeys.or]), QueryKeys.and), QueryKeys.and)\nconst queryWhere = v.object({\n\tfield: v.string(),\n\tvalue: v.any(),\n\tcondition: v.catch(v.defaults(v.in(Object.values(Conditions)), Conditions.eq), Conditions.eq),\n})\nconst queryWhereBlock = v.recursive(\n\t() =>\n\t\tv.discriminate((d) => (Object.values(QueryKeys).includes(d.condition as any) ? 'block' : 'regular'), {\n\t\t\tblock: v.object({\n\t\t\t\tcondition: queryKeys,\n\t\t\t\tvalue: v.array(queryWhereBlock),\n\t\t\t}),\n\t\t\tregular: queryWhere,\n\t\t}),\n\t'QueryWhereBlock',\n) as Pipe<\n\t| {\n\t\t\tcondition: PipeInput<typeof queryKeys>\n\t\t\tvalue: PipeInput<typeof queryWhere>[]\n\t }\n\t| PipeInput<typeof queryWhere>,\n\t| {\n\t\t\tcondition: PipeOutput<typeof queryKeys>\n\t\t\tvalue: PipeOutput<typeof queryWhere>[]\n\t }\n\t| PipeOutput<typeof queryWhere>\n>\n\nconst queryWhereClause = v.defaults(v.array(queryWhereBlock), [])\n\nexport function queryParamsPipe() {\n\treturn v.meta(\n\t\tv\n\t\t\t.object({\n\t\t\t\tall: v.defaults(v.boolean(), false),\n\t\t\t\tlimit: v.lazy(() => {\n\t\t\t\t\tconst pagLimit = Instance.get().settings.utils.paginationDefaultLimit\n\t\t\t\t\treturn v.catch(v.defaults(v.number().pipe(v.lte(pagLimit)), pagLimit), pagLimit)\n\t\t\t\t}),\n\t\t\t\tpage: v.catch(v.defaults(v.number().pipe(v.gte(1)), 1), 1),\n\t\t\t\tsearch: v.defaults(\n\t\t\t\t\tv.nullish(\n\t\t\t\t\t\tv.object({\n\t\t\t\t\t\t\tvalue: v.string(),\n\t\t\t\t\t\t\tfields: v.array(v.string()),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tnull,\n\t\t\t\t),\n\t\t\t\tsort: v.defaults(\n\t\t\t\t\tv.array(\n\t\t\t\t\t\tv.object({\n\t\t\t\t\t\t\tfield: v.string(),\n\t\t\t\t\t\t\tdesc: v.defaults(v.boolean(), false),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\t[],\n\t\t\t\t),\n\t\t\t\twhereType: queryKeys,\n\t\t\t\twhere: queryWhereClause,\n\t\t\t})\n\t\t\t.pipe((p) => ({ ...p, auth: <(typeof p)['where']>[], authType: QueryKeys.and })),\n\t\t{ title: 'Query Params', $refId: 'QueryParams' },\n\t)\n}\n\nexport function queryResultsPipe<T>(model: Pipe<any, T>) {\n\treturn v.object({\n\t\tpages: v.object({\n\t\t\tcurrent: v.number(),\n\t\t\tstart: v.number(),\n\t\t\tlast: v.number(),\n\t\t\tprevious: v.nullable(v.number()),\n\t\t\tnext: v.nullable(v.number()),\n\t\t}),\n\t\tdocs: v.object({\n\t\t\tlimit: v.number(),\n\t\t\ttotal: v.number(),\n\t\t\tcount: v.number(),\n\t\t}),\n\t\tresults: v.array(model),\n\t})\n}\n\nexport function wrapQueryParams(params: QueryParamsInput): QueryParams {\n\treturn v.assert(queryParamsPipe(), params)\n}\n\nexport type QueryParams = PipeOutput<ReturnType<typeof queryParamsPipe>>\nexport type QueryParamsInput = ConditionalObjectKeys<PipeInput<ReturnType<typeof queryParamsPipe>>>\nexport type QueryWhereClause = QueryParams['where'][number]\nexport type QueryWhere = Extract<QueryWhereClause, { field: string }>\nexport type QueryWhereBlock = Exclude<QueryWhereClause, { field: string }>\nexport type QueryResults<T> = PipeOutput<ReturnType<typeof queryResultsPipe<T>>>\n\nexport const mongoDbConfigPipe = () =>\n\tv.meta(\n\t\tv.object({\n\t\t\turi: v.string(),\n\t\t}),\n\t\t{ title: 'Mongodb Config', $refId: 'MongodbConfig' },\n\t)\n\nexport type MongoDbConfig = PipeOutput<ReturnType<typeof mongoDbConfigPipe>>\n",null]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var _valleyed = require('valleyed');var _indexmincjs = require('../instance/index.min.cjs');var
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var _valleyed = require('valleyed');var _indexmincjs = require('../instance/index.min.cjs');var a=(u=>(u.and="and",u.or="or",u))(a||{}),n= exports.Conditions =(r=>(r.lt="lt",r.lte="lte",r.gt="gt",r.gte="gte",r.eq="eq",r.ne="ne",r.in="in",r.nin="nin",r.exists="exists",r))(n||{});const p=_valleyed.v.catch(_valleyed.v.defaults(_valleyed.v.in(["and","or"]),"and"),"and"),s=_valleyed.v.object({field:_valleyed.v.string(),value:_valleyed.v.any(),condition:_valleyed.v.catch(_valleyed.v.defaults(_valleyed.v.in(Object.values(n)),"eq"),"eq")}),o=_valleyed.v.recursive(()=>_valleyed.v.discriminate(t=>Object.values(a).includes(t.condition)?"block":"regular",{block:_valleyed.v.object({condition:p,value:_valleyed.v.array(o)}),regular:s}),"QueryWhereBlock"),y=_valleyed.v.defaults(_valleyed.v.array(o),[]);function l(){return _valleyed.v.meta(_valleyed.v.object({all:_valleyed.v.defaults(_valleyed.v.boolean(),!1),limit:_valleyed.v.lazy(()=>{const t=_indexmincjs.Instance.get().settings.utils.paginationDefaultLimit;return _valleyed.v.catch(_valleyed.v.defaults(_valleyed.v.number().pipe(_valleyed.v.lte(t)),t),t)}),page:_valleyed.v.catch(_valleyed.v.defaults(_valleyed.v.number().pipe(_valleyed.v.gte(1)),1),1),search:_valleyed.v.defaults(_valleyed.v.nullish(_valleyed.v.object({value:_valleyed.v.string(),fields:_valleyed.v.array(_valleyed.v.string())})),null),sort:_valleyed.v.defaults(_valleyed.v.array(_valleyed.v.object({field:_valleyed.v.string(),desc:_valleyed.v.defaults(_valleyed.v.boolean(),!1)})),[]),whereType:p,where:y}).pipe(t=>({...t,auth:[],authType:"and"})),{title:"Query Params",$refId:"QueryParams"})}function d(t){return _valleyed.v.object({pages:_valleyed.v.object({current:_valleyed.v.number(),start:_valleyed.v.number(),last:_valleyed.v.number(),previous:_valleyed.v.nullable(_valleyed.v.number()),next:_valleyed.v.nullable(_valleyed.v.number())}),docs:_valleyed.v.object({limit:_valleyed.v.number(),total:_valleyed.v.number(),count:_valleyed.v.number()}),results:_valleyed.v.array(t)})}function h(t){return _valleyed.v.assert(l(),t)}const q=()=>_valleyed.v.meta(_valleyed.v.object({uri:_valleyed.v.string()}),{title:"Mongodb Config",$refId:"MongodbConfig"});exports.Conditions = n; exports.QueryKeys = a; exports.mongoDbConfigPipe = q; exports.queryParamsPipe = l; exports.queryResultsPipe = d; exports.wrapQueryParams = h;
|
|
2
2
|
//# sourceMappingURL=pipes.min.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/dbs/pipes.ts"],"names":["QueryKeys","Conditions","
|
|
1
|
+
{"version":3,"sources":["../../../src/dbs/pipes.ts"],"names":["QueryKeys","Conditions","queryKeys","v","queryWhere","queryWhereBlock","d","queryParamsPipe","Instance","pagLimit","p","model","wrapQueryParams","params","mongoDbConfigPipe"],"mappings":"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","file":"/home/runner/work/equipped/equipped/dist/cjs/dbs/pipes.min.cjs","sourcesContent":["import { ConditionalObjectKeys, Pipe, PipeInput, PipeOutput, v } from 'valleyed'\n\nimport { Instance } from '../instance'\n\nexport enum QueryKeys {\n\tand = 'and',\n\tor = 'or',\n}\n\nexport enum Conditions {\n\tlt = 'lt',\n\tlte = 'lte',\n\tgt = 'gt',\n\tgte = 'gte',\n\teq = 'eq',\n\tne = 'ne',\n\tin = 'in',\n\tnin = 'nin',\n\texists = 'exists',\n}\n\nconst queryKeys = v.catch(v.defaults(v.in([QueryKeys.and, QueryKeys.or]), QueryKeys.and), QueryKeys.and)\nconst queryWhere = v.object({\n\tfield: v.string(),\n\tvalue: v.any(),\n\tcondition: v.catch(v.defaults(v.in(Object.values(Conditions)), Conditions.eq), Conditions.eq),\n})\nconst queryWhereBlock = v.recursive(\n\t() =>\n\t\tv.discriminate((d) => (Object.values(QueryKeys).includes(d.condition as any) ? 'block' : 'regular'), {\n\t\t\tblock: v.object({\n\t\t\t\tcondition: queryKeys,\n\t\t\t\tvalue: v.array(queryWhereBlock),\n\t\t\t}),\n\t\t\tregular: queryWhere,\n\t\t}),\n\t'QueryWhereBlock',\n) as Pipe<\n\t| {\n\t\t\tcondition: PipeInput<typeof queryKeys>\n\t\t\tvalue: PipeInput<typeof queryWhere>[]\n\t }\n\t| PipeInput<typeof queryWhere>,\n\t| {\n\t\t\tcondition: PipeOutput<typeof queryKeys>\n\t\t\tvalue: PipeOutput<typeof queryWhere>[]\n\t }\n\t| PipeOutput<typeof queryWhere>\n>\n\nconst queryWhereClause = v.defaults(v.array(queryWhereBlock), [])\n\nexport function queryParamsPipe() {\n\treturn v.meta(\n\t\tv\n\t\t\t.object({\n\t\t\t\tall: v.defaults(v.boolean(), false),\n\t\t\t\tlimit: v.lazy(() => {\n\t\t\t\t\tconst pagLimit = Instance.get().settings.utils.paginationDefaultLimit\n\t\t\t\t\treturn v.catch(v.defaults(v.number().pipe(v.lte(pagLimit)), pagLimit), pagLimit)\n\t\t\t\t}),\n\t\t\t\tpage: v.catch(v.defaults(v.number().pipe(v.gte(1)), 1), 1),\n\t\t\t\tsearch: v.defaults(\n\t\t\t\t\tv.nullish(\n\t\t\t\t\t\tv.object({\n\t\t\t\t\t\t\tvalue: v.string(),\n\t\t\t\t\t\t\tfields: v.array(v.string()),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tnull,\n\t\t\t\t),\n\t\t\t\tsort: v.defaults(\n\t\t\t\t\tv.array(\n\t\t\t\t\t\tv.object({\n\t\t\t\t\t\t\tfield: v.string(),\n\t\t\t\t\t\t\tdesc: v.defaults(v.boolean(), false),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\t[],\n\t\t\t\t),\n\t\t\t\twhereType: queryKeys,\n\t\t\t\twhere: queryWhereClause,\n\t\t\t})\n\t\t\t.pipe((p) => ({ ...p, auth: <(typeof p)['where']>[], authType: QueryKeys.and })),\n\t\t{ title: 'Query Params', $refId: 'QueryParams' },\n\t)\n}\n\nexport function queryResultsPipe<T>(model: Pipe<any, T>) {\n\treturn v.object({\n\t\tpages: v.object({\n\t\t\tcurrent: v.number(),\n\t\t\tstart: v.number(),\n\t\t\tlast: v.number(),\n\t\t\tprevious: v.nullable(v.number()),\n\t\t\tnext: v.nullable(v.number()),\n\t\t}),\n\t\tdocs: v.object({\n\t\t\tlimit: v.number(),\n\t\t\ttotal: v.number(),\n\t\t\tcount: v.number(),\n\t\t}),\n\t\tresults: v.array(model),\n\t})\n}\n\nexport function wrapQueryParams(params: QueryParamsInput): QueryParams {\n\treturn v.assert(queryParamsPipe(), params)\n}\n\nexport type QueryParams = PipeOutput<ReturnType<typeof queryParamsPipe>>\nexport type QueryParamsInput = ConditionalObjectKeys<PipeInput<ReturnType<typeof queryParamsPipe>>>\nexport type QueryWhereClause = QueryParams['where'][number]\nexport type QueryWhere = Extract<QueryWhereClause, { field: string }>\nexport type QueryWhereBlock = Exclude<QueryWhereClause, { field: string }>\nexport type QueryResults<T> = PipeOutput<ReturnType<typeof queryResultsPipe<T>>>\n\nexport const mongoDbConfigPipe = () =>\n\tv.meta(\n\t\tv.object({\n\t\t\turi: v.string(),\n\t\t}),\n\t\t{ title: 'Mongodb Config', $refId: 'MongodbConfig' },\n\t)\n\nexport type MongoDbConfig = PipeOutput<ReturnType<typeof mongoDbConfigPipe>>\n"]}
|
|
@@ -78,8 +78,8 @@ class Server {
|
|
|
78
78
|
let status = defaultStatusCode;
|
|
79
79
|
let contentType = defaultContentType;
|
|
80
80
|
const jsonSchema = { response: {}, request: {} };
|
|
81
|
-
const
|
|
82
|
-
const
|
|
81
|
+
const requestPipeDefs = {};
|
|
82
|
+
const responsePipeDefs = {};
|
|
83
83
|
const defs = [
|
|
84
84
|
{ key: "params", type: "request" },
|
|
85
85
|
{ key: "headers", type: "request" },
|
|
@@ -90,15 +90,14 @@ class Server {
|
|
|
90
90
|
];
|
|
91
91
|
defs.forEach((def) => {
|
|
92
92
|
const pipe = _nullishCoalesce(schema[def.key], () => ( _valleyed.v.any()));
|
|
93
|
-
_valleyed.v.compile(pipe, { allErrors: true });
|
|
94
93
|
if (def.skip) return;
|
|
95
94
|
if (def.type === "request") {
|
|
96
|
-
|
|
95
|
+
requestPipeDefs[def.key] = pipe;
|
|
97
96
|
jsonSchema.request[def.key] = _valleyed.v.schema(pipe);
|
|
98
97
|
}
|
|
99
98
|
if (def.type === "response") {
|
|
100
99
|
const pipeRecords = errorsSchemas.concat({ status: defaultStatusCode, contentType, pipe });
|
|
101
|
-
|
|
100
|
+
responsePipeDefs[def.key] = _valleyed.v.any().pipe((input) => {
|
|
102
101
|
const p = _optionalChain([pipeRecords, 'access', _9 => _9.find, 'call', _10 => _10((r) => r.status === status), 'optionalAccess', _11 => _11.pipe]);
|
|
103
102
|
if (!p) throw _valleyed.PipeError.root(`schema not defined for status code: ${status}`, input);
|
|
104
103
|
return _valleyed.v.assert(p, input);
|
|
@@ -110,13 +109,17 @@ class Server {
|
|
|
110
109
|
}));
|
|
111
110
|
}
|
|
112
111
|
});
|
|
112
|
+
const requestPipe = _valleyed.v.object(requestPipeDefs);
|
|
113
|
+
_valleyed.v.compile(requestPipe, { allErrors: true });
|
|
114
|
+
const responsePipe = _valleyed.v.object(responsePipeDefs);
|
|
115
|
+
_valleyed.v.compile(responsePipe, { allErrors: true });
|
|
113
116
|
const validateRequest = async (request) => {
|
|
114
|
-
if (!Object.keys(
|
|
117
|
+
if (!Object.keys(requestPipeDefs)) return request;
|
|
115
118
|
const context = schema.context ? await schema.context(request) : {};
|
|
116
119
|
request.context = context;
|
|
117
120
|
const validity = _valleyedcjs.requestLocalStorage.run(
|
|
118
121
|
request,
|
|
119
|
-
() => _valleyed.v.validate(
|
|
122
|
+
() => _valleyed.v.validate(requestPipe, {
|
|
120
123
|
params: request.params,
|
|
121
124
|
headers: request.headers,
|
|
122
125
|
query: request.query,
|
|
@@ -131,13 +134,12 @@ class Server {
|
|
|
131
134
|
return request;
|
|
132
135
|
};
|
|
133
136
|
const validateResponse = async (response) => {
|
|
134
|
-
if (!Object.keys(
|
|
137
|
+
if (!Object.keys(responsePipeDefs)) return response;
|
|
135
138
|
status = response.status;
|
|
136
139
|
contentType = response.contentType;
|
|
137
|
-
contentType;
|
|
138
140
|
const validity = _valleyedcjs.responseLocalStorage.run(
|
|
139
141
|
response,
|
|
140
|
-
() => _valleyed.v.validate(
|
|
142
|
+
() => _valleyed.v.validate(responsePipe, {
|
|
141
143
|
responseHeaders: response.headers,
|
|
142
144
|
response: response.body
|
|
143
145
|
})
|
|
@@ -174,7 +176,7 @@ class Server {
|
|
|
174
176
|
throw new (0, _indexcjs.NotFoundError)(`Route ${request.path} not found`);
|
|
175
177
|
});
|
|
176
178
|
this.implementations.registerErrorHandler(async (error, _, res) => {
|
|
177
|
-
_indexcjs3.Instance.get().log.error(error);
|
|
179
|
+
_indexcjs3.Instance.get().log.error({ error }, "Uncaught error in route handler");
|
|
178
180
|
const response = error instanceof _indexcjs.RequestError ? new (0, _requestscjs.Response)({
|
|
179
181
|
body: error.serializedErrors,
|
|
180
182
|
status: error.statusCode
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/server/impls/base.ts","/home/runner/work/equipped/equipped/dist/cjs/server/impls/base.cjs"],"names":[],"mappings":"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","file":"/home/runner/work/equipped/equipped/dist/cjs/server/impls/base.cjs","sourcesContent":["import type http from 'http'\n\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { 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, OpenApiSchemaDef } from '../openapi'\nimport { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, MethodsEnum, 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 requestPipe: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params'> = {}\n\t\tconst responsePipe: Pick<RouteDef, 'response' | 'responseHeaders'> = {}\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: '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]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tv.compile(pipe, { allErrors: true })\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipe[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\tresponsePipe[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 validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipe)) 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(v.object(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}),\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\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipe)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\t\t\tcontentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(v.object(responsePipe), {\n\t\t\t\t\tresponseHeaders: response.headers,\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\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)\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",null]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/server/impls/base.ts","/home/runner/work/equipped/equipped/dist/cjs/server/impls/base.cjs"],"names":[],"mappings":"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","file":"/home/runner/work/equipped/equipped/dist/cjs/server/impls/base.cjs","sourcesContent":["import type http from 'http'\n\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { 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, OpenApiSchemaDef } from '../openapi'\nimport { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, MethodsEnum, 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'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders'> = {}\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: '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]\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}),\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\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\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\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",null]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _socketio = require('socket.io');var _supertest = require('supertest'); var _supertest2 = _interopRequireDefault(_supertest);var _valleyed = require('valleyed');var _indexmincjs = require('../../errors/index.min.cjs');var _indexmincjs3 = require('../../instance/index.min.cjs');var _indexmincjs5 = require('../../validations/index.min.cjs');var _valleyedmincjs = require('../../validations/valleyed.min.cjs');var _parseAuthUsermincjs = require('../middlewares/parseAuthUser.min.cjs');var _openapimincjs = require('../openapi.min.cjs');var _requestsmincjs = require('../requests.min.cjs');var _socketsmincjs = require('../sockets.min.cjs');var _typesmincjs = require('../types.min.cjs');const
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _socketio = require('socket.io');var _supertest = require('supertest'); var _supertest2 = _interopRequireDefault(_supertest);var _valleyed = require('valleyed');var _indexmincjs = require('../../errors/index.min.cjs');var _indexmincjs3 = require('../../instance/index.min.cjs');var _indexmincjs5 = require('../../validations/index.min.cjs');var _valleyedmincjs = require('../../validations/valleyed.min.cjs');var _parseAuthUsermincjs = require('../middlewares/parseAuthUser.min.cjs');var _openapimincjs = require('../openapi.min.cjs');var _requestsmincjs = require('../requests.min.cjs');var _socketsmincjs = require('../sockets.min.cjs');var _typesmincjs = require('../types.min.cjs');const U=Object.entries(_typesmincjs.StatusCodes).filter(([,f])=>f>399).map(([f,s])=>({status:s,contentType:"application/json",pipe:_valleyed.v.meta(_valleyed.v.array(_valleyed.v.object({message:_valleyed.v.string(),field:_valleyed.v.optional(_valleyed.v.string())})),{$refId:`Errors.${f}Response`,description:`${f} Response`})}));class ae{constructor(s,t,i){;ae.prototype.__init.call(this);this.config=t;this.implementations=i;this.server=s,this.#e=new (0, _openapimincjs.OpenApi)(t);const c=new (0, _socketio.Server)(s,{cors:this.cors});this.socket=new (0, _socketsmincjs.SocketEmitter)(c,t),this.addRouter(this.#e.router())}#t=[];#s=new Map;#e;__init() {this.cors={origin:"*",methods:Object.values(_typesmincjs.Methods).filter(s=>s!==_typesmincjs.Methods.options).map(s=>s.toUpperCase())}}addRouter(...s){s.map(t=>t.routes).forEach(t=>this.addRoute(...t))}addRoute(...s){s.forEach(t=>{this.#t.push(async()=>{const{method:i,path:c,schema:o={},onError:d,middlewares:u=[]}=t,p=`(${i.toUpperCase()}) ${this.#e.cleanPath(c)}`;if(this.#s.get(p))throw new (0, _indexmincjs.EquippedError)(`Route key ${p} already registered. All route keys must be unique`,{route:t,key:p});u.unshift(_parseAuthUsermincjs.parseAuthUser),u.forEach(m=>_optionalChain([m, 'access', _ => _.onSetup, 'optionalCall', _2 => _2(t)])),_optionalChain([d, 'optionalAccess', _3 => _3.onSetup, 'optionalCall', _4 => _4(t)]);const{validateRequest:R,validateResponse:q,jsonSchema:g}=this.#o(i,o);this.#s.set(p,!0),await this.#e.register(t,g),this.implementations.registerRoute(i,this.#e.cleanPath(c),async(m,k)=>{const w=await R(await this.implementations.parseRequest(m));try{for(const n of u)await n.cb(w,this.config);const e=await t.handler(w,this.config),a=e instanceof _requestsmincjs.Response?e:new (0, _requestsmincjs.Response)({body:e,status:_typesmincjs.StatusCodes.Ok,headers:{},piped:!1});return await this.implementations.handleResponse(k,await q(a))}catch(e){if(_optionalChain([d, 'optionalAccess', _5 => _5.cb])){const a=await d.cb(w,this.config,e),n=a instanceof _requestsmincjs.Response?a:new (0, _requestsmincjs.Response)({body:a,status:_typesmincjs.StatusCodes.BadRequest,headers:{}});return await this.implementations.handleResponse(k,await q(n))}throw e}})})})}#o(s,t){const i=_nullishCoalesce(_optionalChain([t, 'optionalAccess', _6 => _6.defaultStatusCode]), () => (_typesmincjs.StatusCodes.Ok)),c=_nullishCoalesce(_optionalChain([t, 'optionalAccess', _7 => _7.defaultContentType]), () => ("application/json"));let o=i,d=c;const u={response:{},request:{}},p={},R={};[{key:"params",type:"request"},{key:"headers",type:"request"},{key:"query",type:"request"},{key:"body",type:"request",skip:![_typesmincjs.Methods.post,_typesmincjs.Methods.put,_typesmincjs.Methods.patch].includes(s)},{key:"response",type:"response"},{key:"responseHeaders",type:"response"}].forEach(e=>{const a=_nullishCoalesce(t[e.key], () => (_valleyed.v.any()));if(!e.skip&&(e.type==="request"&&(p[e.key]=a,u.request[e.key]=_valleyed.v.schema(a)),e.type==="response")){const n=U.concat({status:i,contentType:d,pipe:a});R[e.key]=_valleyed.v.any().pipe(h=>{const E=_optionalChain([n, 'access', _8 => _8.find, 'call', _9 => _9(P=>P.status===o), 'optionalAccess', _10 => _10.pipe]);if(!E)throw _valleyed.PipeError.root(`schema not defined for status code: ${o}`,h);return _valleyed.v.assert(E,h)}),u.response[e.key]=n.map(h=>({status:h.status,contentType:h.contentType,schema:_valleyed.v.schema(h.pipe)}))}});const g=_valleyed.v.object(p);_valleyed.v.compile(g,{allErrors:!0});const m=_valleyed.v.object(R);return _valleyed.v.compile(m,{allErrors:!0}),{jsonSchema:u,validateRequest:async e=>{if(!Object.keys(p))return e;const a=t.context?await t.context(e):{};e.context=a;const n=_valleyedmincjs.requestLocalStorage.run(e,()=>_valleyed.v.validate(g,{params:e.params,headers:e.headers,query:e.query,body:e.body}));if(!n.valid)throw _indexmincjs5.pipeErrorToValidationError.call(void 0, n.error);return e.params=n.value.params,e.headers=n.value.headers,e.query=n.value.query,e.body=n.value.body,e},validateResponse:async e=>{if(!Object.keys(R))return e;o=e.status,d=e.contentType;const a=_valleyedmincjs.responseLocalStorage.run(e,()=>_valleyed.v.validate(m,{responseHeaders:e.headers,response:e.body}));if(!a.valid)throw _indexmincjs5.pipeErrorToValidationError.call(void 0, a.error);return e.body=a.value.response,e.headers=a.value.responseHeaders,e}}}test(){return _supertest2.default.call(void 0, this.server)}async start(){const s=this.config.port,t=_indexmincjs3.Instance.get(),{app:i}=t.settings;this.config.healthPath&&this.addRoute({method:_typesmincjs.Methods.get,path:this.config.healthPath,handler:async o=>o.res({body:`${t.id}(${i.name}) service running`,contentType:"text/plain"})}),this.implementations.registerNotFoundHandler(async o=>{const d=await this.implementations.parseRequest(o);throw new (0, _indexmincjs.NotFoundError)(`Route ${d.path} not found`)}),this.implementations.registerErrorHandler(async(o,d,u)=>{_indexmincjs3.Instance.get().log.error({error:o},"Uncaught error in route handler");const p=o instanceof _indexmincjs.RequestError?new (0, _requestsmincjs.Response)({body:o.serializedErrors,status:o.statusCode}):new (0, _requestsmincjs.Response)({body:[{message:"Something went wrong",data:o.message}],status:_typesmincjs.StatusCodes.BadRequest});return await this.implementations.handleResponse(u,p)}),await Promise.all(this.#t.map(o=>o()));const c=await this.implementations.start(s);return c&&_indexmincjs3.Instance.get().log.info(`${t.id}(${i.name}) service listening on port ${s}`),c}}exports.Server = ae;
|
|
2
2
|
//# sourceMappingURL=base.min.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/server/impls/base.ts"],"names":["StatusCodes","v","key","server","config","implementations"],"mappings":"AAEA,szBAAuC,4FACjB,oCACa,yDAG1B,4DACA,+DACqB,oEACA,2EAGS,mDAET,qDACWA,mDAMvB,+CAGH,MACb,CAAA,CAAA,MAAQ,CAAA,OAAO,CAAA,wBAAMC,CAAAA,CAAE,MAAA,CAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAASA,CAAAA,GAAE,CAAA,CAAA,GAAO,CAAA,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOA,EAAE,CAAA,CAAA,MAAA,CAASA,CAAAA,CAAE,WAAY,CAAA,kBAC5E,CAAUC,IAAG,CAAA,WAAA,CAAA,IAAA,CACrB,WAAA,CAAA,KAAA,CAAA,WAAA,CAAA,MAAmB,CAAA,CAAA,OAAA,CAAA,WACpB,CAAC,MAGI,CAAA,CAAA,CAAA,KAaN,CAAA,WAAA,CAAA,QAAA,CACCC,WAAAA,CACQC,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,MACA,CAAA,CAAA,OAAA,EAAA,CAAA,CAAA,QAAAC,CASR,CAAA,WAAcF,CAAAA,CACd,EAAA","file":"/home/runner/work/equipped/equipped/dist/cjs/server/impls/base.min.cjs","sourcesContent":["import type http from 'http'\n\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { 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, OpenApiSchemaDef } from '../openapi'\nimport { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, MethodsEnum, 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 requestPipe: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params'> = {}\n\t\tconst responsePipe: Pick<RouteDef, 'response' | 'responseHeaders'> = {}\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: '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]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tv.compile(pipe, { allErrors: true })\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipe[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\tresponsePipe[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 validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipe)) 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(v.object(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}),\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\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipe)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\t\t\tcontentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(v.object(responsePipe), {\n\t\t\t\t\tresponseHeaders: response.headers,\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\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)\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"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/server/impls/base.ts"],"names":["StatusCodes","v","key","server","config","implementations"],"mappings":"AAEA,szBAAuC,4FACjB,oCACa,yDAG1B,4DACA,+DACqB,oEACA,2EAGS,mDAET,qDACWA,mDAMvB,+CAGH,MACb,CAAA,CAAA,MAAQ,CAAA,OAAO,CAAA,wBAAMC,CAAAA,CAAE,MAAA,CAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAASA,CAAAA,GAAE,CAAA,CAAA,GAAO,CAAA,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOA,EAAE,CAAA,CAAA,MAAA,CAASA,CAAAA,CAAE,WAAY,CAAA,kBAC5E,CAAUC,IAAG,CAAA,WAAA,CAAA,IAAA,CACrB,WAAA,CAAA,KAAA,CAAA,WAAA,CAAA,MAAmB,CAAA,CAAA,OAAA,CAAA,WACpB,CAAC,MAGI,CAAA,CAAA,CAAA,KAaN,CAAA,WAAA,CAAA,QAAA,CACCC,WAAAA,CACQC,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,MACA,CAAA,CAAA,OAAA,EAAA,CAAA,CAAA,QAAAC,CASR,CAAA,WAAcF,CAAAA,CACd,EAAA","file":"/home/runner/work/equipped/equipped/dist/cjs/server/impls/base.min.cjs","sourcesContent":["import type http from 'http'\n\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { 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, OpenApiSchemaDef } from '../openapi'\nimport { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, MethodsEnum, 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'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders'> = {}\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: '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]\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}),\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\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\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\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"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{v as e}from"valleyed";import{Instance as
|
|
1
|
+
import{v as e}from"valleyed";import{Instance as i}from "../instance/index.min.mjs";var a=(u=>(u.and="and",u.or="or",u))(a||{}),n=(r=>(r.lt="lt",r.lte="lte",r.gt="gt",r.gte="gte",r.eq="eq",r.ne="ne",r.in="in",r.nin="nin",r.exists="exists",r))(n||{});const p=e.catch(e.defaults(e.in(["and","or"]),"and"),"and"),s=e.object({field:e.string(),value:e.any(),condition:e.catch(e.defaults(e.in(Object.values(n)),"eq"),"eq")}),o=e.recursive(()=>e.discriminate(t=>Object.values(a).includes(t.condition)?"block":"regular",{block:e.object({condition:p,value:e.array(o)}),regular:s}),"QueryWhereBlock"),y=e.defaults(e.array(o),[]);function l(){return e.meta(e.object({all:e.defaults(e.boolean(),!1),limit:e.lazy(()=>{const t=i.get().settings.utils.paginationDefaultLimit;return e.catch(e.defaults(e.number().pipe(e.lte(t)),t),t)}),page:e.catch(e.defaults(e.number().pipe(e.gte(1)),1),1),search:e.defaults(e.nullish(e.object({value:e.string(),fields:e.array(e.string())})),null),sort:e.defaults(e.array(e.object({field:e.string(),desc:e.defaults(e.boolean(),!1)})),[]),whereType:p,where:y}).pipe(t=>({...t,auth:[],authType:"and"})),{title:"Query Params",$refId:"QueryParams"})}function d(t){return e.object({pages:e.object({current:e.number(),start:e.number(),last:e.number(),previous:e.nullable(e.number()),next:e.nullable(e.number())}),docs:e.object({limit:e.number(),total:e.number(),count:e.number()}),results:e.array(t)})}function h(t){return e.assert(l(),t)}const q=()=>e.meta(e.object({uri:e.string()}),{title:"Mongodb Config",$refId:"MongodbConfig"});export{n as Conditions,a as QueryKeys,q as mongoDbConfigPipe,l as queryParamsPipe,d as queryResultsPipe,h as wrapQueryParams};
|
|
2
2
|
//# sourceMappingURL=pipes.min.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/dbs/pipes.ts"],"sourcesContent":["import { ConditionalObjectKeys, Pipe, PipeInput, PipeOutput, v } from 'valleyed'\n\nimport { Instance } from '../instance'\n\nexport enum QueryKeys {\n\tand = 'and',\n\tor = 'or',\n}\n\nexport enum Conditions {\n\tlt = 'lt',\n\tlte = 'lte',\n\tgt = 'gt',\n\tgte = 'gte',\n\teq = 'eq',\n\tne = 'ne',\n\tin = 'in',\n\tnin = 'nin',\n\texists = 'exists',\n}\n\
|
|
1
|
+
{"version":3,"sources":["../../../src/dbs/pipes.ts"],"sourcesContent":["import { ConditionalObjectKeys, Pipe, PipeInput, PipeOutput, v } from 'valleyed'\n\nimport { Instance } from '../instance'\n\nexport enum QueryKeys {\n\tand = 'and',\n\tor = 'or',\n}\n\nexport enum Conditions {\n\tlt = 'lt',\n\tlte = 'lte',\n\tgt = 'gt',\n\tgte = 'gte',\n\teq = 'eq',\n\tne = 'ne',\n\tin = 'in',\n\tnin = 'nin',\n\texists = 'exists',\n}\n\nconst queryKeys = v.catch(v.defaults(v.in([QueryKeys.and, QueryKeys.or]), QueryKeys.and), QueryKeys.and)\nconst queryWhere = v.object({\n\tfield: v.string(),\n\tvalue: v.any(),\n\tcondition: v.catch(v.defaults(v.in(Object.values(Conditions)), Conditions.eq), Conditions.eq),\n})\nconst queryWhereBlock = v.recursive(\n\t() =>\n\t\tv.discriminate((d) => (Object.values(QueryKeys).includes(d.condition as any) ? 'block' : 'regular'), {\n\t\t\tblock: v.object({\n\t\t\t\tcondition: queryKeys,\n\t\t\t\tvalue: v.array(queryWhereBlock),\n\t\t\t}),\n\t\t\tregular: queryWhere,\n\t\t}),\n\t'QueryWhereBlock',\n) as Pipe<\n\t| {\n\t\t\tcondition: PipeInput<typeof queryKeys>\n\t\t\tvalue: PipeInput<typeof queryWhere>[]\n\t }\n\t| PipeInput<typeof queryWhere>,\n\t| {\n\t\t\tcondition: PipeOutput<typeof queryKeys>\n\t\t\tvalue: PipeOutput<typeof queryWhere>[]\n\t }\n\t| PipeOutput<typeof queryWhere>\n>\n\nconst queryWhereClause = v.defaults(v.array(queryWhereBlock), [])\n\nexport function queryParamsPipe() {\n\treturn v.meta(\n\t\tv\n\t\t\t.object({\n\t\t\t\tall: v.defaults(v.boolean(), false),\n\t\t\t\tlimit: v.lazy(() => {\n\t\t\t\t\tconst pagLimit = Instance.get().settings.utils.paginationDefaultLimit\n\t\t\t\t\treturn v.catch(v.defaults(v.number().pipe(v.lte(pagLimit)), pagLimit), pagLimit)\n\t\t\t\t}),\n\t\t\t\tpage: v.catch(v.defaults(v.number().pipe(v.gte(1)), 1), 1),\n\t\t\t\tsearch: v.defaults(\n\t\t\t\t\tv.nullish(\n\t\t\t\t\t\tv.object({\n\t\t\t\t\t\t\tvalue: v.string(),\n\t\t\t\t\t\t\tfields: v.array(v.string()),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tnull,\n\t\t\t\t),\n\t\t\t\tsort: v.defaults(\n\t\t\t\t\tv.array(\n\t\t\t\t\t\tv.object({\n\t\t\t\t\t\t\tfield: v.string(),\n\t\t\t\t\t\t\tdesc: v.defaults(v.boolean(), false),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\t[],\n\t\t\t\t),\n\t\t\t\twhereType: queryKeys,\n\t\t\t\twhere: queryWhereClause,\n\t\t\t})\n\t\t\t.pipe((p) => ({ ...p, auth: <(typeof p)['where']>[], authType: QueryKeys.and })),\n\t\t{ title: 'Query Params', $refId: 'QueryParams' },\n\t)\n}\n\nexport function queryResultsPipe<T>(model: Pipe<any, T>) {\n\treturn v.object({\n\t\tpages: v.object({\n\t\t\tcurrent: v.number(),\n\t\t\tstart: v.number(),\n\t\t\tlast: v.number(),\n\t\t\tprevious: v.nullable(v.number()),\n\t\t\tnext: v.nullable(v.number()),\n\t\t}),\n\t\tdocs: v.object({\n\t\t\tlimit: v.number(),\n\t\t\ttotal: v.number(),\n\t\t\tcount: v.number(),\n\t\t}),\n\t\tresults: v.array(model),\n\t})\n}\n\nexport function wrapQueryParams(params: QueryParamsInput): QueryParams {\n\treturn v.assert(queryParamsPipe(), params)\n}\n\nexport type QueryParams = PipeOutput<ReturnType<typeof queryParamsPipe>>\nexport type QueryParamsInput = ConditionalObjectKeys<PipeInput<ReturnType<typeof queryParamsPipe>>>\nexport type QueryWhereClause = QueryParams['where'][number]\nexport type QueryWhere = Extract<QueryWhereClause, { field: string }>\nexport type QueryWhereBlock = Exclude<QueryWhereClause, { field: string }>\nexport type QueryResults<T> = PipeOutput<ReturnType<typeof queryResultsPipe<T>>>\n\nexport const mongoDbConfigPipe = () =>\n\tv.meta(\n\t\tv.object({\n\t\t\turi: v.string(),\n\t\t}),\n\t\t{ title: 'Mongodb Config', $refId: 'MongodbConfig' },\n\t)\n\nexport type MongoDbConfig = PipeOutput<ReturnType<typeof mongoDbConfigPipe>>\n"],"mappings":"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","names":["v","Instance","QueryKeys","Conditions","queryKeys","queryWhere","queryWhereBlock","d","queryWhereClause","queryParamsPipe","pagLimit","p","queryResultsPipe","model","wrapQueryParams","params","mongoDbConfigPipe"]}
|
package/dist/esm/dbs/pipes.mjs
CHANGED
|
@@ -17,24 +17,24 @@ var Conditions = /* @__PURE__ */ ((Conditions2) => {
|
|
|
17
17
|
Conditions2["exists"] = "exists";
|
|
18
18
|
return Conditions2;
|
|
19
19
|
})(Conditions || {});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
value: v.array(queryWhereBlock)
|
|
32
|
-
}),
|
|
33
|
-
regular: queryWhere
|
|
20
|
+
const queryKeys = v.catch(v.defaults(v.in(["and" /* and */, "or" /* or */]), "and" /* and */), "and" /* and */);
|
|
21
|
+
const queryWhere = v.object({
|
|
22
|
+
field: v.string(),
|
|
23
|
+
value: v.any(),
|
|
24
|
+
condition: v.catch(v.defaults(v.in(Object.values(Conditions)), "eq" /* eq */), "eq" /* eq */)
|
|
25
|
+
});
|
|
26
|
+
const queryWhereBlock = v.recursive(
|
|
27
|
+
() => v.discriminate((d) => Object.values(QueryKeys).includes(d.condition) ? "block" : "regular", {
|
|
28
|
+
block: v.object({
|
|
29
|
+
condition: queryKeys,
|
|
30
|
+
value: v.array(queryWhereBlock)
|
|
34
31
|
}),
|
|
35
|
-
|
|
36
|
-
)
|
|
37
|
-
|
|
32
|
+
regular: queryWhere
|
|
33
|
+
}),
|
|
34
|
+
"QueryWhereBlock"
|
|
35
|
+
);
|
|
36
|
+
const queryWhereClause = v.defaults(v.array(queryWhereBlock), []);
|
|
37
|
+
function queryParamsPipe() {
|
|
38
38
|
return v.meta(
|
|
39
39
|
v.object({
|
|
40
40
|
all: v.defaults(v.boolean(), false),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/dbs/pipes.ts"],"sourcesContent":["import { ConditionalObjectKeys, Pipe, PipeInput, PipeOutput, v } from 'valleyed'\n\nimport { Instance } from '../instance'\n\nexport enum QueryKeys {\n\tand = 'and',\n\tor = 'or',\n}\n\nexport enum Conditions {\n\tlt = 'lt',\n\tlte = 'lte',\n\tgt = 'gt',\n\tgte = 'gte',\n\teq = 'eq',\n\tne = 'ne',\n\tin = 'in',\n\tnin = 'nin',\n\texists = 'exists',\n}\n\
|
|
1
|
+
{"version":3,"sources":["../../../src/dbs/pipes.ts"],"sourcesContent":["import { ConditionalObjectKeys, Pipe, PipeInput, PipeOutput, v } from 'valleyed'\n\nimport { Instance } from '../instance'\n\nexport enum QueryKeys {\n\tand = 'and',\n\tor = 'or',\n}\n\nexport enum Conditions {\n\tlt = 'lt',\n\tlte = 'lte',\n\tgt = 'gt',\n\tgte = 'gte',\n\teq = 'eq',\n\tne = 'ne',\n\tin = 'in',\n\tnin = 'nin',\n\texists = 'exists',\n}\n\nconst queryKeys = v.catch(v.defaults(v.in([QueryKeys.and, QueryKeys.or]), QueryKeys.and), QueryKeys.and)\nconst queryWhere = v.object({\n\tfield: v.string(),\n\tvalue: v.any(),\n\tcondition: v.catch(v.defaults(v.in(Object.values(Conditions)), Conditions.eq), Conditions.eq),\n})\nconst queryWhereBlock = v.recursive(\n\t() =>\n\t\tv.discriminate((d) => (Object.values(QueryKeys).includes(d.condition as any) ? 'block' : 'regular'), {\n\t\t\tblock: v.object({\n\t\t\t\tcondition: queryKeys,\n\t\t\t\tvalue: v.array(queryWhereBlock),\n\t\t\t}),\n\t\t\tregular: queryWhere,\n\t\t}),\n\t'QueryWhereBlock',\n) as Pipe<\n\t| {\n\t\t\tcondition: PipeInput<typeof queryKeys>\n\t\t\tvalue: PipeInput<typeof queryWhere>[]\n\t }\n\t| PipeInput<typeof queryWhere>,\n\t| {\n\t\t\tcondition: PipeOutput<typeof queryKeys>\n\t\t\tvalue: PipeOutput<typeof queryWhere>[]\n\t }\n\t| PipeOutput<typeof queryWhere>\n>\n\nconst queryWhereClause = v.defaults(v.array(queryWhereBlock), [])\n\nexport function queryParamsPipe() {\n\treturn v.meta(\n\t\tv\n\t\t\t.object({\n\t\t\t\tall: v.defaults(v.boolean(), false),\n\t\t\t\tlimit: v.lazy(() => {\n\t\t\t\t\tconst pagLimit = Instance.get().settings.utils.paginationDefaultLimit\n\t\t\t\t\treturn v.catch(v.defaults(v.number().pipe(v.lte(pagLimit)), pagLimit), pagLimit)\n\t\t\t\t}),\n\t\t\t\tpage: v.catch(v.defaults(v.number().pipe(v.gte(1)), 1), 1),\n\t\t\t\tsearch: v.defaults(\n\t\t\t\t\tv.nullish(\n\t\t\t\t\t\tv.object({\n\t\t\t\t\t\t\tvalue: v.string(),\n\t\t\t\t\t\t\tfields: v.array(v.string()),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tnull,\n\t\t\t\t),\n\t\t\t\tsort: v.defaults(\n\t\t\t\t\tv.array(\n\t\t\t\t\t\tv.object({\n\t\t\t\t\t\t\tfield: v.string(),\n\t\t\t\t\t\t\tdesc: v.defaults(v.boolean(), false),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\t[],\n\t\t\t\t),\n\t\t\t\twhereType: queryKeys,\n\t\t\t\twhere: queryWhereClause,\n\t\t\t})\n\t\t\t.pipe((p) => ({ ...p, auth: <(typeof p)['where']>[], authType: QueryKeys.and })),\n\t\t{ title: 'Query Params', $refId: 'QueryParams' },\n\t)\n}\n\nexport function queryResultsPipe<T>(model: Pipe<any, T>) {\n\treturn v.object({\n\t\tpages: v.object({\n\t\t\tcurrent: v.number(),\n\t\t\tstart: v.number(),\n\t\t\tlast: v.number(),\n\t\t\tprevious: v.nullable(v.number()),\n\t\t\tnext: v.nullable(v.number()),\n\t\t}),\n\t\tdocs: v.object({\n\t\t\tlimit: v.number(),\n\t\t\ttotal: v.number(),\n\t\t\tcount: v.number(),\n\t\t}),\n\t\tresults: v.array(model),\n\t})\n}\n\nexport function wrapQueryParams(params: QueryParamsInput): QueryParams {\n\treturn v.assert(queryParamsPipe(), params)\n}\n\nexport type QueryParams = PipeOutput<ReturnType<typeof queryParamsPipe>>\nexport type QueryParamsInput = ConditionalObjectKeys<PipeInput<ReturnType<typeof queryParamsPipe>>>\nexport type QueryWhereClause = QueryParams['where'][number]\nexport type QueryWhere = Extract<QueryWhereClause, { field: string }>\nexport type QueryWhereBlock = Exclude<QueryWhereClause, { field: string }>\nexport type QueryResults<T> = PipeOutput<ReturnType<typeof queryResultsPipe<T>>>\n\nexport const mongoDbConfigPipe = () =>\n\tv.meta(\n\t\tv.object({\n\t\t\turi: v.string(),\n\t\t}),\n\t\t{ title: 'Mongodb Config', $refId: 'MongodbConfig' },\n\t)\n\nexport type MongoDbConfig = PipeOutput<ReturnType<typeof mongoDbConfigPipe>>\n"],"mappings":"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","names":["QueryKeys","Conditions"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Server as
|
|
1
|
+
import{Server as $}from"socket.io";import j from"supertest";import{PipeError as D,v as r}from"valleyed";import{EquippedError as O,NotFoundError as T,RequestError as C}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 x,responseLocalStorage as H}from "../../validations/valleyed.min.mjs";import{parseAuthUser as A}from "../middlewares/parseAuthUser.min.mjs";import{OpenApi as M}from "../openapi.min.mjs";import{Response as y}from "../requests.min.mjs";import{SocketEmitter as V}from "../sockets.min.mjs";import{Methods as l,StatusCodes as v}from "../types.min.mjs";const U=Object.entries(v).filter(([,f])=>f>399).map(([f,s])=>({status:s,contentType:"application/json",pipe:r.meta(r.array(r.object({message:r.string(),field:r.optional(r.string())})),{$refId:`Errors.${f}Response`,description:`${f} Response`})}));class ae{constructor(s,t,i){this.config=t;this.implementations=i;this.server=s,this.#e=new M(t);const c=new $(s,{cors:this.cors});this.socket=new V(c,t),this.addRouter(this.#e.router())}#t=[];#s=new Map;#e;socket;server;cors={origin:"*",methods:Object.values(l).filter(s=>s!==l.options).map(s=>s.toUpperCase())};addRouter(...s){s.map(t=>t.routes).forEach(t=>this.addRoute(...t))}addRoute(...s){s.forEach(t=>{this.#t.push(async()=>{const{method:i,path:c,schema:o={},onError:d,middlewares:u=[]}=t,p=`(${i.toUpperCase()}) ${this.#e.cleanPath(c)}`;if(this.#s.get(p))throw new O(`Route key ${p} already registered. All route keys must be unique`,{route:t,key:p});u.unshift(A),u.forEach(m=>m.onSetup?.(t)),d?.onSetup?.(t);const{validateRequest:R,validateResponse:q,jsonSchema:g}=this.#o(i,o);this.#s.set(p,!0),await this.#e.register(t,g),this.implementations.registerRoute(i,this.#e.cleanPath(c),async(m,k)=>{const w=await R(await this.implementations.parseRequest(m));try{for(const n of u)await n.cb(w,this.config);const e=await t.handler(w,this.config),a=e instanceof y?e:new y({body:e,status:v.Ok,headers:{},piped:!1});return await this.implementations.handleResponse(k,await q(a))}catch(e){if(d?.cb){const a=await d.cb(w,this.config,e),n=a instanceof y?a:new y({body:a,status:v.BadRequest,headers:{}});return await this.implementations.handleResponse(k,await q(n))}throw e}})})})}#o(s,t){const i=t?.defaultStatusCode??v.Ok,c=t?.defaultContentType??"application/json";let o=i,d=c;const u={response:{},request:{}},p={},R={};[{key:"params",type:"request"},{key:"headers",type:"request"},{key:"query",type:"request"},{key:"body",type:"request",skip:![l.post,l.put,l.patch].includes(s)},{key:"response",type:"response"},{key:"responseHeaders",type:"response"}].forEach(e=>{const a=t[e.key]??r.any();if(!e.skip&&(e.type==="request"&&(p[e.key]=a,u.request[e.key]=r.schema(a)),e.type==="response")){const n=U.concat({status:i,contentType:d,pipe:a});R[e.key]=r.any().pipe(h=>{const E=n.find(P=>P.status===o)?.pipe;if(!E)throw D.root(`schema not defined for status code: ${o}`,h);return r.assert(E,h)}),u.response[e.key]=n.map(h=>({status:h.status,contentType:h.contentType,schema:r.schema(h.pipe)}))}});const g=r.object(p);r.compile(g,{allErrors:!0});const m=r.object(R);return r.compile(m,{allErrors:!0}),{jsonSchema:u,validateRequest:async e=>{if(!Object.keys(p))return e;const a=t.context?await t.context(e):{};e.context=a;const n=x.run(e,()=>r.validate(g,{params:e.params,headers:e.headers,query:e.query,body:e.body}));if(!n.valid)throw S(n.error);return e.params=n.value.params,e.headers=n.value.headers,e.query=n.value.query,e.body=n.value.body,e},validateResponse:async e=>{if(!Object.keys(R))return e;o=e.status,d=e.contentType;const a=H.run(e,()=>r.validate(m,{responseHeaders:e.headers,response:e.body}));if(!a.valid)throw S(a.error);return e.body=a.value.response,e.headers=a.value.responseHeaders,e}}}test(){return j(this.server)}async start(){const s=this.config.port,t=b.get(),{app:i}=t.settings;this.config.healthPath&&this.addRoute({method:l.get,path:this.config.healthPath,handler:async o=>o.res({body:`${t.id}(${i.name}) service running`,contentType:"text/plain"})}),this.implementations.registerNotFoundHandler(async o=>{const d=await this.implementations.parseRequest(o);throw new T(`Route ${d.path} not found`)}),this.implementations.registerErrorHandler(async(o,d,u)=>{b.get().log.error({error:o},"Uncaught error in route handler");const p=o instanceof C?new y({body:o.serializedErrors,status:o.statusCode}):new y({body:[{message:"Something went wrong",data:o.message}],status:v.BadRequest});return await this.implementations.handleResponse(u,p)}),await Promise.all(this.#t.map(o=>o()));const c=await this.implementations.start(s);return c&&b.get().log.info(`${t.id}(${i.name}) service listening on port ${s}`),c}}export{ae 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 { 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, OpenApiSchemaDef } from '../openapi'\nimport { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, MethodsEnum, 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 requestPipe: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params'> = {}\n\t\tconst responsePipe: Pick<RouteDef, 'response' | 'responseHeaders'> = {}\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: '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]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tv.compile(pipe, { allErrors: true })\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipe[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\tresponsePipe[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 validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipe)) 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(v.object(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}),\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\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipe)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\t\t\tcontentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(v.object(responsePipe), {\n\t\t\t\t\tresponseHeaders: response.headers,\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\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)\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","requestPipe","responsePipe","def","pipe","pipeRecords","input","p","r","record","context","validity","port","instance","app","_","cb","started"]}
|
|
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 { 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, OpenApiSchemaDef } from '../openapi'\nimport { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, MethodsEnum, 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'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders'> = {}\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: '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]\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}),\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\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\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\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"]}
|
|
@@ -78,8 +78,8 @@ class Server {
|
|
|
78
78
|
let status = defaultStatusCode;
|
|
79
79
|
let contentType = defaultContentType;
|
|
80
80
|
const jsonSchema = { response: {}, request: {} };
|
|
81
|
-
const
|
|
82
|
-
const
|
|
81
|
+
const requestPipeDefs = {};
|
|
82
|
+
const responsePipeDefs = {};
|
|
83
83
|
const defs = [
|
|
84
84
|
{ key: "params", type: "request" },
|
|
85
85
|
{ key: "headers", type: "request" },
|
|
@@ -90,15 +90,14 @@ class Server {
|
|
|
90
90
|
];
|
|
91
91
|
defs.forEach((def) => {
|
|
92
92
|
const pipe = schema[def.key] ?? v.any();
|
|
93
|
-
v.compile(pipe, { allErrors: true });
|
|
94
93
|
if (def.skip) return;
|
|
95
94
|
if (def.type === "request") {
|
|
96
|
-
|
|
95
|
+
requestPipeDefs[def.key] = pipe;
|
|
97
96
|
jsonSchema.request[def.key] = v.schema(pipe);
|
|
98
97
|
}
|
|
99
98
|
if (def.type === "response") {
|
|
100
99
|
const pipeRecords = errorsSchemas.concat({ status: defaultStatusCode, contentType, pipe });
|
|
101
|
-
|
|
100
|
+
responsePipeDefs[def.key] = v.any().pipe((input) => {
|
|
102
101
|
const p = pipeRecords.find((r) => r.status === status)?.pipe;
|
|
103
102
|
if (!p) throw PipeError.root(`schema not defined for status code: ${status}`, input);
|
|
104
103
|
return v.assert(p, input);
|
|
@@ -110,13 +109,17 @@ class Server {
|
|
|
110
109
|
}));
|
|
111
110
|
}
|
|
112
111
|
});
|
|
112
|
+
const requestPipe = v.object(requestPipeDefs);
|
|
113
|
+
v.compile(requestPipe, { allErrors: true });
|
|
114
|
+
const responsePipe = v.object(responsePipeDefs);
|
|
115
|
+
v.compile(responsePipe, { allErrors: true });
|
|
113
116
|
const validateRequest = async (request) => {
|
|
114
|
-
if (!Object.keys(
|
|
117
|
+
if (!Object.keys(requestPipeDefs)) return request;
|
|
115
118
|
const context = schema.context ? await schema.context(request) : {};
|
|
116
119
|
request.context = context;
|
|
117
120
|
const validity = requestLocalStorage.run(
|
|
118
121
|
request,
|
|
119
|
-
() => v.validate(
|
|
122
|
+
() => v.validate(requestPipe, {
|
|
120
123
|
params: request.params,
|
|
121
124
|
headers: request.headers,
|
|
122
125
|
query: request.query,
|
|
@@ -131,13 +134,12 @@ class Server {
|
|
|
131
134
|
return request;
|
|
132
135
|
};
|
|
133
136
|
const validateResponse = async (response) => {
|
|
134
|
-
if (!Object.keys(
|
|
137
|
+
if (!Object.keys(responsePipeDefs)) return response;
|
|
135
138
|
status = response.status;
|
|
136
139
|
contentType = response.contentType;
|
|
137
|
-
contentType;
|
|
138
140
|
const validity = responseLocalStorage.run(
|
|
139
141
|
response,
|
|
140
|
-
() => v.validate(
|
|
142
|
+
() => v.validate(responsePipe, {
|
|
141
143
|
responseHeaders: response.headers,
|
|
142
144
|
response: response.body
|
|
143
145
|
})
|
|
@@ -174,7 +176,7 @@ class Server {
|
|
|
174
176
|
throw new NotFoundError(`Route ${request.path} not found`);
|
|
175
177
|
});
|
|
176
178
|
this.implementations.registerErrorHandler(async (error, _, res) => {
|
|
177
|
-
Instance.get().log.error(error);
|
|
179
|
+
Instance.get().log.error({ error }, "Uncaught error in route handler");
|
|
178
180
|
const response = error instanceof RequestError ? new Response({
|
|
179
181
|
body: error.serializedErrors,
|
|
180
182
|
status: error.statusCode
|
|
@@ -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 { 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, OpenApiSchemaDef } from '../openapi'\nimport { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, MethodsEnum, 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 requestPipe: Pick<RouteDef, 'body' | 'headers' | 'query' | 'params'> = {}\n\t\tconst responsePipe: Pick<RouteDef, 'response' | 'responseHeaders'> = {}\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: '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]\n\t\tdefs.forEach((def) => {\n\t\t\tconst pipe = schema[def.key] ?? v.any()\n\t\t\tv.compile(pipe, { allErrors: true })\n\t\t\tif (def.skip) return\n\n\t\t\tif (def.type === 'request') {\n\t\t\t\trequestPipe[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\tresponsePipe[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 validateRequest: RequestValidator = async (request) => {\n\t\t\tif (!Object.keys(requestPipe)) 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(v.object(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}),\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\treturn request\n\t\t}\n\t\tconst validateResponse: ResponseValidator = async (response) => {\n\t\t\tif (!Object.keys(responsePipe)) return response\n\t\t\tstatus = response.status\n\t\t\tcontentType = response.contentType\n\t\t\tcontentType\n\n\t\t\tconst validity = responseLocalStorage.run(response, () =>\n\t\t\t\tv.validate(v.object(responsePipe), {\n\t\t\t\t\tresponseHeaders: response.headers,\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\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)\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 'http'\n\nimport { Server as SocketServer } from 'socket.io'\nimport supertest from 'supertest'\nimport { 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, OpenApiSchemaDef } from '../openapi'\nimport { ServerConfig } from '../pipes'\nimport { type Request, Response } from '../requests'\nimport { Router } from '../routes'\nimport { SocketEmitter } from '../sockets'\nimport { Methods, MethodsEnum, 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'> = {}\n\t\tconst responsePipeDefs: Pick<RouteDef, 'response' | 'responseHeaders'> = {}\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: '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]\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}),\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\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\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\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":[]}
|
|
@@ -17,6 +17,16 @@ declare enum Conditions {
|
|
|
17
17
|
nin = "nin",
|
|
18
18
|
exists = "exists"
|
|
19
19
|
}
|
|
20
|
+
declare const queryKeys: Pipe<QueryKeys | undefined, QueryKeys>;
|
|
21
|
+
declare const queryWhere: Pipe<{
|
|
22
|
+
field: string;
|
|
23
|
+
value: any;
|
|
24
|
+
condition: Conditions | undefined;
|
|
25
|
+
}, {
|
|
26
|
+
field: string;
|
|
27
|
+
value: any;
|
|
28
|
+
condition: Conditions;
|
|
29
|
+
}>;
|
|
20
30
|
declare function queryParamsPipe(): Pipe<{
|
|
21
31
|
all: boolean | undefined;
|
|
22
32
|
limit: number | undefined;
|
|
@@ -35,16 +45,8 @@ declare function queryParamsPipe(): Pipe<{
|
|
|
35
45
|
value: any;
|
|
36
46
|
condition: Conditions | undefined;
|
|
37
47
|
} | {
|
|
38
|
-
condition: PipeInput<
|
|
39
|
-
value: PipeInput<
|
|
40
|
-
field: string;
|
|
41
|
-
value: any;
|
|
42
|
-
condition: Conditions | undefined;
|
|
43
|
-
}, {
|
|
44
|
-
field: string;
|
|
45
|
-
value: any;
|
|
46
|
-
condition: Conditions;
|
|
47
|
-
}>>[];
|
|
48
|
+
condition: PipeInput<typeof queryKeys>;
|
|
49
|
+
value: PipeInput<typeof queryWhere>[];
|
|
48
50
|
})[] | undefined;
|
|
49
51
|
}, {
|
|
50
52
|
auth: ({
|
|
@@ -52,16 +54,8 @@ declare function queryParamsPipe(): Pipe<{
|
|
|
52
54
|
value: any;
|
|
53
55
|
condition: Conditions;
|
|
54
56
|
} | {
|
|
55
|
-
condition: PipeOutput<
|
|
56
|
-
value: PipeOutput<
|
|
57
|
-
field: string;
|
|
58
|
-
value: any;
|
|
59
|
-
condition: Conditions | undefined;
|
|
60
|
-
}, {
|
|
61
|
-
field: string;
|
|
62
|
-
value: any;
|
|
63
|
-
condition: Conditions;
|
|
64
|
-
}>>[];
|
|
57
|
+
condition: PipeOutput<typeof queryKeys>;
|
|
58
|
+
value: PipeOutput<typeof queryWhere>[];
|
|
65
59
|
})[];
|
|
66
60
|
authType: QueryKeys;
|
|
67
61
|
all: boolean;
|
|
@@ -81,16 +75,8 @@ declare function queryParamsPipe(): Pipe<{
|
|
|
81
75
|
value: any;
|
|
82
76
|
condition: Conditions;
|
|
83
77
|
} | {
|
|
84
|
-
condition: PipeOutput<
|
|
85
|
-
value: PipeOutput<
|
|
86
|
-
field: string;
|
|
87
|
-
value: any;
|
|
88
|
-
condition: Conditions | undefined;
|
|
89
|
-
}, {
|
|
90
|
-
field: string;
|
|
91
|
-
value: any;
|
|
92
|
-
condition: Conditions;
|
|
93
|
-
}>>[];
|
|
78
|
+
condition: PipeOutput<typeof queryKeys>;
|
|
79
|
+
value: PipeOutput<typeof queryWhere>[];
|
|
94
80
|
})[];
|
|
95
81
|
}>;
|
|
96
82
|
declare function queryResultsPipe<T>(model: Pipe<any, T>): Pipe<{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MongoClient, ObjectId, Collection } from 'mongodb';
|
|
2
|
-
import { I as IdType$1, f as DbConfig, M as Model, E as Entity, e as Config, T as Table, a as MongoDbConfig } from './core-
|
|
2
|
+
import { I as IdType$1, f as DbConfig, M as Model, E as Entity, e as Config, T as Table, a as MongoDbConfig } from './core-BuPovjLX.js';
|
|
3
3
|
|
|
4
4
|
type TableOptions = {
|
|
5
5
|
skipAudit?: boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { M as Model, E as Entity, D as DbChange, a as MongoDbConfig, b as DbChangeConfig, c as DbChangeCallbacks } from '../core-
|
|
2
|
-
export { B as BulkWriteOperation, g as Conditions, e as Config, C as CreateInput, f as DbConfig, d as EntityInput, I as IdType, Q as QueryKeys, i as QueryParams, j as QueryParamsInput, n as QueryResults, l as QueryWhere, m as QueryWhereBlock, k as QueryWhereClause, T as Table, U as UpdateInput, o as mongoDbConfigPipe, q as queryParamsPipe, h as queryResultsPipe, w as wrapQueryParams } from '../core-
|
|
3
|
-
export { D as Db, M as MongoDb, T as TableOptions } from '../db-
|
|
1
|
+
import { M as Model, E as Entity, D as DbChange, a as MongoDbConfig, b as DbChangeConfig, c as DbChangeCallbacks } from '../core-BuPovjLX.js';
|
|
2
|
+
export { B as BulkWriteOperation, g as Conditions, e as Config, C as CreateInput, f as DbConfig, d as EntityInput, I as IdType, Q as QueryKeys, i as QueryParams, j as QueryParamsInput, n as QueryResults, l as QueryWhere, m as QueryWhereBlock, k as QueryWhereClause, T as Table, U as UpdateInput, o as mongoDbConfigPipe, q as queryParamsPipe, h as queryResultsPipe, w as wrapQueryParams } from '../core-BuPovjLX.js';
|
|
3
|
+
export { D as Db, M as MongoDb, T as TableOptions } from '../db-Gck93XBL.js';
|
|
4
4
|
import { Collection } from 'mongodb';
|
|
5
5
|
export { Filter } from 'mongodb';
|
|
6
6
|
import 'valleyed';
|
package/dist/types/dbs/pipes.js
CHANGED
|
@@ -17,24 +17,24 @@ var Conditions = /* @__PURE__ */ ((Conditions2) => {
|
|
|
17
17
|
Conditions2["exists"] = "exists";
|
|
18
18
|
return Conditions2;
|
|
19
19
|
})(Conditions || {});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
value: v.array(queryWhereBlock)
|
|
32
|
-
}),
|
|
33
|
-
regular: queryWhere
|
|
20
|
+
const queryKeys = v.catch(v.defaults(v.in(["and" /* and */, "or" /* or */]), "and" /* and */), "and" /* and */);
|
|
21
|
+
const queryWhere = v.object({
|
|
22
|
+
field: v.string(),
|
|
23
|
+
value: v.any(),
|
|
24
|
+
condition: v.catch(v.defaults(v.in(Object.values(Conditions)), "eq" /* eq */), "eq" /* eq */)
|
|
25
|
+
});
|
|
26
|
+
const queryWhereBlock = v.recursive(
|
|
27
|
+
() => v.discriminate((d) => Object.values(QueryKeys).includes(d.condition) ? "block" : "regular", {
|
|
28
|
+
block: v.object({
|
|
29
|
+
condition: queryKeys,
|
|
30
|
+
value: v.array(queryWhereBlock)
|
|
34
31
|
}),
|
|
35
|
-
|
|
36
|
-
)
|
|
37
|
-
|
|
32
|
+
regular: queryWhere
|
|
33
|
+
}),
|
|
34
|
+
"QueryWhereBlock"
|
|
35
|
+
);
|
|
36
|
+
const queryWhereClause = v.defaults(v.array(queryWhereBlock), []);
|
|
37
|
+
function queryParamsPipe() {
|
|
38
38
|
return v.meta(
|
|
39
39
|
v.object({
|
|
40
40
|
all: v.defaults(v.boolean(), false),
|
|
@@ -5,7 +5,7 @@ import * as supertest_lib_agent from 'supertest/lib/agent';
|
|
|
5
5
|
import http from 'http';
|
|
6
6
|
import supertest from 'supertest';
|
|
7
7
|
import { Server as Server$1 } from 'socket.io';
|
|
8
|
-
import { E as Entity } from './core-
|
|
8
|
+
import { E as Entity } from './core-BuPovjLX.js';
|
|
9
9
|
import { A as AuthUser } from './overrides-6Hxg764S.js';
|
|
10
10
|
|
|
11
11
|
declare class Router<T extends RouteDef> {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -9,16 +9,16 @@ import './requests-DblEBsI-.js';
|
|
|
9
9
|
import 'stream';
|
|
10
10
|
import './types/index.js';
|
|
11
11
|
import './base-8yVXb67P.js';
|
|
12
|
-
import './fastify-
|
|
12
|
+
import './fastify-B7DQ55s8.js';
|
|
13
13
|
import 'express';
|
|
14
14
|
import 'fastify';
|
|
15
15
|
import 'supertest/lib/agent';
|
|
16
16
|
import 'http';
|
|
17
17
|
import 'supertest';
|
|
18
18
|
import 'socket.io';
|
|
19
|
-
import './core-
|
|
19
|
+
import './core-BuPovjLX.js';
|
|
20
20
|
import 'mongodb';
|
|
21
21
|
import './cache/index.js';
|
|
22
22
|
import 'ioredis';
|
|
23
|
-
import './db-
|
|
23
|
+
import './db-Gck93XBL.js';
|
|
24
24
|
import './jobs/index.js';
|
|
@@ -5,9 +5,9 @@ import { E as EventBus } from '../base-CfeyC14V.js';
|
|
|
5
5
|
import { K as KafkaEventBus } from '../kafka-zsC3c8ar.js';
|
|
6
6
|
import { RabbitMQEventBus } from '../events/index.js';
|
|
7
7
|
import { e as BaseTokensUtility, B as BaseApiKeysUtility, E as EquippedError } from '../requests-DblEBsI-.js';
|
|
8
|
-
import { E as ExpressServer, F as FastifyServer } from '../fastify-
|
|
8
|
+
import { E as ExpressServer, F as FastifyServer } from '../fastify-B7DQ55s8.js';
|
|
9
9
|
import { InMemoryCache, RedisCache } from '../cache/index.js';
|
|
10
|
-
import { M as MongoDb } from '../db-
|
|
10
|
+
import { M as MongoDb } from '../db-Gck93XBL.js';
|
|
11
11
|
import { RedisJob } from '../jobs/index.js';
|
|
12
12
|
import '../overrides-6Hxg764S.js';
|
|
13
13
|
import 'stream';
|
|
@@ -19,7 +19,7 @@ import 'supertest/lib/agent';
|
|
|
19
19
|
import 'http';
|
|
20
20
|
import 'supertest';
|
|
21
21
|
import 'socket.io';
|
|
22
|
-
import '../core-
|
|
22
|
+
import '../core-BuPovjLX.js';
|
|
23
23
|
import 'mongodb';
|
|
24
24
|
import 'ioredis';
|
|
25
25
|
|
|
@@ -78,8 +78,8 @@ class Server {
|
|
|
78
78
|
let status = defaultStatusCode;
|
|
79
79
|
let contentType = defaultContentType;
|
|
80
80
|
const jsonSchema = { response: {}, request: {} };
|
|
81
|
-
const
|
|
82
|
-
const
|
|
81
|
+
const requestPipeDefs = {};
|
|
82
|
+
const responsePipeDefs = {};
|
|
83
83
|
const defs = [
|
|
84
84
|
{ key: "params", type: "request" },
|
|
85
85
|
{ key: "headers", type: "request" },
|
|
@@ -90,15 +90,14 @@ class Server {
|
|
|
90
90
|
];
|
|
91
91
|
defs.forEach((def) => {
|
|
92
92
|
const pipe = schema[def.key] ?? v.any();
|
|
93
|
-
v.compile(pipe, { allErrors: true });
|
|
94
93
|
if (def.skip) return;
|
|
95
94
|
if (def.type === "request") {
|
|
96
|
-
|
|
95
|
+
requestPipeDefs[def.key] = pipe;
|
|
97
96
|
jsonSchema.request[def.key] = v.schema(pipe);
|
|
98
97
|
}
|
|
99
98
|
if (def.type === "response") {
|
|
100
99
|
const pipeRecords = errorsSchemas.concat({ status: defaultStatusCode, contentType, pipe });
|
|
101
|
-
|
|
100
|
+
responsePipeDefs[def.key] = v.any().pipe((input) => {
|
|
102
101
|
const p = pipeRecords.find((r) => r.status === status)?.pipe;
|
|
103
102
|
if (!p) throw PipeError.root(`schema not defined for status code: ${status}`, input);
|
|
104
103
|
return v.assert(p, input);
|
|
@@ -110,13 +109,17 @@ class Server {
|
|
|
110
109
|
}));
|
|
111
110
|
}
|
|
112
111
|
});
|
|
112
|
+
const requestPipe = v.object(requestPipeDefs);
|
|
113
|
+
v.compile(requestPipe, { allErrors: true });
|
|
114
|
+
const responsePipe = v.object(responsePipeDefs);
|
|
115
|
+
v.compile(responsePipe, { allErrors: true });
|
|
113
116
|
const validateRequest = async (request) => {
|
|
114
|
-
if (!Object.keys(
|
|
117
|
+
if (!Object.keys(requestPipeDefs)) return request;
|
|
115
118
|
const context = schema.context ? await schema.context(request) : {};
|
|
116
119
|
request.context = context;
|
|
117
120
|
const validity = requestLocalStorage.run(
|
|
118
121
|
request,
|
|
119
|
-
() => v.validate(
|
|
122
|
+
() => v.validate(requestPipe, {
|
|
120
123
|
params: request.params,
|
|
121
124
|
headers: request.headers,
|
|
122
125
|
query: request.query,
|
|
@@ -131,13 +134,12 @@ class Server {
|
|
|
131
134
|
return request;
|
|
132
135
|
};
|
|
133
136
|
const validateResponse = async (response) => {
|
|
134
|
-
if (!Object.keys(
|
|
137
|
+
if (!Object.keys(responsePipeDefs)) return response;
|
|
135
138
|
status = response.status;
|
|
136
139
|
contentType = response.contentType;
|
|
137
|
-
contentType;
|
|
138
140
|
const validity = responseLocalStorage.run(
|
|
139
141
|
response,
|
|
140
|
-
() => v.validate(
|
|
142
|
+
() => v.validate(responsePipe, {
|
|
141
143
|
responseHeaders: response.headers,
|
|
142
144
|
response: response.body
|
|
143
145
|
})
|
|
@@ -174,7 +176,7 @@ class Server {
|
|
|
174
176
|
throw new NotFoundError(`Route ${request.path} not found`);
|
|
175
177
|
});
|
|
176
178
|
this.implementations.registerErrorHandler(async (error, _, res) => {
|
|
177
|
-
Instance.get().log.error(error);
|
|
179
|
+
Instance.get().log.error({ error }, "Uncaught error in route handler");
|
|
178
180
|
const response = error instanceof RequestError ? new Response({
|
|
179
181
|
body: error.serializedErrors,
|
|
180
182
|
status: error.statusCode
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { E as ExpressServer, F as FastifyServer, O as OnJoinFn, R as Router, S as Server, a as SocketCallbacks, b as SocketEmitter } from '../fastify-
|
|
1
|
+
export { E as ExpressServer, F as FastifyServer, O as OnJoinFn, R as Router, S as Server, a as SocketCallbacks, b as SocketEmitter } from '../fastify-B7DQ55s8.js';
|
|
2
2
|
import { R as Request, a as RouteDefToReqRes, b as RouteDef, S as ServerConfig, c as Route } from '../requests-DblEBsI-.js';
|
|
3
3
|
export { B as BaseApiKeysUtility, e as BaseTokensUtility, C as CacheTokensUtility, D as DefaultHeaders, I as IncomingFile, k as MergeRouteDefs, M as Methods, g as MethodsEnum, d as Response, i as RouteConfig, l as RouteDefHandler, j as RouterConfig, f as StatusCodes, h as StatusCodesEnum, n as makeErrorMiddleware, m as makeMiddleware, s as serverConfigPipe } from '../requests-DblEBsI-.js';
|
|
4
4
|
import 'express';
|
|
@@ -7,7 +7,7 @@ import 'supertest/lib/agent';
|
|
|
7
7
|
import 'http';
|
|
8
8
|
import 'supertest';
|
|
9
9
|
import 'socket.io';
|
|
10
|
-
import '../core-
|
|
10
|
+
import '../core-BuPovjLX.js';
|
|
11
11
|
import 'mongodb';
|
|
12
12
|
import 'valleyed';
|
|
13
13
|
import '../kafka-zsC3c8ar.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "equipped",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.27",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "",
|
|
6
6
|
"type": "module",
|
|
@@ -185,7 +185,7 @@
|
|
|
185
185
|
"redis": "5.8.0",
|
|
186
186
|
"socket.io": "4.8.1",
|
|
187
187
|
"supertest": "7.1.4",
|
|
188
|
-
"valleyed": "^4.5.
|
|
188
|
+
"valleyed": "^4.5.17"
|
|
189
189
|
},
|
|
190
190
|
"repository": {
|
|
191
191
|
"url": "git://github.com/kevinand11/equipped.git"
|