@kosmojs/api 0.0.10 → 0.0.20

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@kosmojs/api",
4
- "version": "0.0.10",
4
+ "version": "0.0.20",
5
5
  "author": "Slee Woo",
6
6
  "license": "MIT",
7
7
  "publishConfig": {
@@ -23,16 +23,15 @@
23
23
  "types": "./pkg/src/queryparser/index.d.ts",
24
24
  "default": "./pkg/queryparser/index.js"
25
25
  },
26
- "./debug": {
27
- "types": "./pkg/src/debug.d.ts",
28
- "default": "./pkg/debug.js"
26
+ "./errors": {
27
+ "types": "./pkg/src/errors/index.d.ts",
28
+ "default": "./pkg/errors/index.js"
29
29
  }
30
30
  },
31
31
  "dependencies": {
32
32
  "@koa/router": "^15.0.0",
33
33
  "formidable": "^3.5.4",
34
34
  "koa": "^3.1.1",
35
- "picomatch": "^4.0.3",
36
35
  "qs": "^6.14.0",
37
36
  "raw-body": "^3.0.2",
38
37
  "string-width": "^8.1.0"
@@ -40,13 +39,13 @@
40
39
  "devDependencies": {
41
40
  "@types/formidable": "^3.4.6",
42
41
  "@types/koa": "^3.0.1",
42
+ "@types/koa-compose": "^3.2.9",
43
43
  "@types/picomatch": "^4.0.2",
44
44
  "@types/qs": "^6.14.0",
45
- "@kosmojs/config": "^0.0.10",
46
- "@kosmojs/devlib": "^0.0.10"
45
+ "koa-compose": "^4.1.0"
47
46
  },
48
47
  "scripts": {
49
- "build": "esbuilder src/index.ts src/bodyparser/index.ts src/queryparser/index.ts src/debug.ts",
48
+ "build": "esbuilder src/index.ts src/bodyparser/index.ts src/queryparser/index.ts src/errors/index.ts",
50
49
  "test": "vitest --root ../../.. --project core/api"
51
50
  }
52
51
  }
@@ -24,7 +24,7 @@ var config_default = {
24
24
  var bodyparser_default = { json: json2, form: form2, raw: raw2 };
25
25
  function json2(opts = {}) {
26
26
  return [
27
- async (ctx, next) => {
27
+ async function useJSONBodyparser(ctx, next) {
28
28
  const form3 = IncomingForm({
29
29
  maxFieldsSize: opts.limit || config_default.json.limit,
30
30
  ...opts
@@ -44,7 +44,7 @@ function json2(opts = {}) {
44
44
  }
45
45
  function form2(opts = {}) {
46
46
  return [
47
- async (ctx, next) => {
47
+ async function useFormBodyparser(ctx, next) {
48
48
  const form3 = IncomingForm({
49
49
  maxFieldsSize: opts.limit || config_default.form.limit,
50
50
  maxFileSize: opts.limit || config_default.form.limit,
@@ -71,7 +71,7 @@ function form2(opts = {}) {
71
71
  }
72
72
  function raw2(opts = {}) {
73
73
  return [
74
- async (ctx, next) => {
74
+ async function useRawBodyparser(ctx, next) {
75
75
  const { chunkSize, ...rawParserOptions } = { ...config_default.raw, ...opts };
76
76
  const stream = ctx.request.req.pipe(zlib.createUnzip({ chunkSize }));
77
77
  ctx.request.body = await rawParser(stream, rawParserOptions);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/bodyparser/index.ts", "../../src/bodyparser/config.ts"],
4
- "sourcesContent": ["import zlib from \"node:zlib\";\n\nimport IncomingForm from \"formidable\";\nimport rawParser from \"raw-body\";\n\nimport type { Middleware } from \"@kosmojs/api\";\n\nimport config from \"./config\";\nimport type {\n FormOptions,\n JsonOptions,\n RawOptions,\n Trimmer,\n TrimOption,\n} from \"./types\";\n\nexport * from \"./types\";\nexport { config };\nexport default { json, form, raw };\n\nexport function json(opts: JsonOptions = {}): Array<Middleware> {\n return [\n async (ctx, next) => {\n const form = IncomingForm({\n maxFieldsSize: opts.limit || config.json.limit,\n ...opts,\n });\n\n const trimmer = trimmerFactory(opts.trim);\n\n ctx.request.body = await new Promise((resolve, reject) => {\n form.parse(ctx.request.req, (err, fields) => {\n if (err) {\n return reject(err);\n }\n\n resolve(trimmer ? trimmer(fields) : fields);\n });\n });\n\n return next();\n },\n ];\n}\n\nexport function form(opts: FormOptions = {}): Array<Middleware> {\n return [\n async (ctx, next) => {\n const form = IncomingForm({\n maxFieldsSize: opts.limit || config.form.limit,\n maxFileSize: opts.limit || config.form.limit,\n ...opts,\n });\n\n let trimmer = trimmerFactory(opts.trim);\n\n if (opts.multipart || opts.urlencoded) {\n trimmer = undefined;\n }\n\n ctx.request.body = await new Promise((resolve, reject) => {\n form.parse(ctx.request.req, (err, fields, files) => {\n if (err) {\n return reject(err);\n }\n\n resolve({\n fields: trimmer ? trimmer(fields) : fields,\n files,\n });\n });\n });\n\n return next();\n },\n ];\n}\n\nexport function raw(opts: RawOptions = {}): Array<Middleware> {\n return [\n async (ctx, next) => {\n const { chunkSize, ...rawParserOptions } = { ...config.raw, ...opts };\n\n const stream = ctx.request.req.pipe(zlib.createUnzip({ chunkSize }));\n ctx.request.body = await rawParser(stream, rawParserOptions);\n\n return next();\n },\n ];\n}\n\nfunction trimmerFactory(\n trimOption: TrimOption | undefined,\n): Trimmer | undefined {\n if (!Array.isArray(trimOption) || !trimOption.length) {\n return;\n }\n\n const trimableKeys: {\n [key: string]: boolean;\n } = trimOption.reduce((m: Record<string, boolean>, k) => {\n m[k] = true;\n return m;\n }, {});\n\n const trim = (key: string, val: unknown) => {\n return typeof val === \"string\"\n ? trimableKeys[key] || trimableKeys[\"*\"]\n ? val.trim()\n : val\n : val;\n };\n\n const reducer = (\n memo: Record<string, unknown>,\n [key, val]: [string, unknown],\n ) => {\n memo[key] = trim(key, val);\n return memo;\n };\n\n return (payload) =>\n Object.entries(payload).reduce(\n reducer,\n // accumulator is set to payload intentionally, to avoid duplication of big strings.\n // if using a new object for accumulator then trimmed strings will be duplicated?\n payload,\n );\n}\n", "import type { FormOptions, JsonOptions, RawOptions } from \"./types\";\n\nexport const json: JsonOptions = {\n limit: 1024 ** 2,\n trim: [\"*\"],\n};\n\nexport const form: FormOptions = {\n limit: 1024 ** 2,\n};\n\nexport const raw: RawOptions = {\n limit: 1024 ** 2,\n};\n\nexport default {\n json,\n form,\n raw,\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import zlib from \"node:zlib\";\n\nimport IncomingForm from \"formidable\";\nimport rawParser from \"raw-body\";\n\nimport type { ParameterizedMiddleware } from \"@kosmojs/api\";\n\nimport config from \"./config\";\nimport type {\n FormOptions,\n JsonOptions,\n RawOptions,\n Trimmer,\n TrimOption,\n} from \"./types\";\n\nexport * from \"./types\";\nexport { config };\nexport default { json, form, raw };\n\nexport function json(opts: JsonOptions = {}): Array<ParameterizedMiddleware> {\n return [\n async function useJSONBodyparser(ctx, next) {\n const form = IncomingForm({\n maxFieldsSize: opts.limit || config.json.limit,\n ...opts,\n });\n\n const trimmer = trimmerFactory(opts.trim);\n\n ctx.request.body = await new Promise((resolve, reject) => {\n form.parse(ctx.request.req, (err, fields) => {\n if (err) {\n return reject(err);\n }\n\n resolve(trimmer ? trimmer(fields) : fields);\n });\n });\n\n return next();\n },\n ];\n}\n\nexport function form(opts: FormOptions = {}): Array<ParameterizedMiddleware> {\n return [\n async function useFormBodyparser(ctx, next) {\n const form = IncomingForm({\n maxFieldsSize: opts.limit || config.form.limit,\n maxFileSize: opts.limit || config.form.limit,\n ...opts,\n });\n\n let trimmer = trimmerFactory(opts.trim);\n\n if (opts.multipart || opts.urlencoded) {\n trimmer = undefined;\n }\n\n ctx.request.body = await new Promise((resolve, reject) => {\n form.parse(ctx.request.req, (err, fields, files) => {\n if (err) {\n return reject(err);\n }\n\n resolve({\n fields: trimmer ? trimmer(fields) : fields,\n files,\n });\n });\n });\n\n return next();\n },\n ];\n}\n\nexport function raw(opts: RawOptions = {}): Array<ParameterizedMiddleware> {\n return [\n async function useRawBodyparser(ctx, next) {\n const { chunkSize, ...rawParserOptions } = { ...config.raw, ...opts };\n\n const stream = ctx.request.req.pipe(zlib.createUnzip({ chunkSize }));\n ctx.request.body = await rawParser(stream, rawParserOptions);\n\n return next();\n },\n ];\n}\n\nfunction trimmerFactory(\n trimOption: TrimOption | undefined,\n): Trimmer | undefined {\n if (!Array.isArray(trimOption) || !trimOption.length) {\n return;\n }\n\n const trimableKeys: {\n [key: string]: boolean;\n } = trimOption.reduce((m: Record<string, boolean>, k) => {\n m[k] = true;\n return m;\n }, {});\n\n const trim = (key: string, val: unknown) => {\n return typeof val === \"string\"\n ? trimableKeys[key] || trimableKeys[\"*\"]\n ? val.trim()\n : val\n : val;\n };\n\n const reducer = (\n memo: Record<string, unknown>,\n [key, val]: [string, unknown],\n ) => {\n memo[key] = trim(key, val);\n return memo;\n };\n\n return (payload) =>\n Object.entries(payload).reduce(\n reducer,\n // accumulator is set to payload intentionally, to avoid duplication of big strings.\n // if using a new object for accumulator then trimmed strings will be duplicated?\n payload,\n );\n}\n", "import type { FormOptions, JsonOptions, RawOptions } from \"./types\";\n\nexport const json: JsonOptions = {\n limit: 1024 ** 2,\n trim: [\"*\"],\n};\n\nexport const form: FormOptions = {\n limit: 1024 ** 2,\n};\n\nexport const raw: RawOptions = {\n limit: 1024 ** 2,\n};\n\nexport default {\n json,\n form,\n raw,\n};\n"],
5
+ "mappings": "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",
6
6
  "names": ["json", "form", "raw"]
7
7
  }
@@ -0,0 +1,19 @@
1
+ // src/errors/index.ts
2
+ var ValidationError = class extends Error {
3
+ scope;
4
+ errors = [];
5
+ errorMessage;
6
+ errorSummary;
7
+ constructor([scope, { errors, errorMessage, errorSummary }]) {
8
+ super(JSON.stringify(errors, null, 2));
9
+ this.name = `${scope}ValidationError`;
10
+ this.scope = scope;
11
+ this.errors = errors;
12
+ this.errorMessage = errorMessage;
13
+ this.errorSummary = errorSummary;
14
+ }
15
+ };
16
+ export {
17
+ ValidationError
18
+ };
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/errors/index.ts"],
4
+ "sourcesContent": ["import type {\n ValidationErrorData,\n ValidationErrorEntry,\n ValidationErrorScope,\n} from \"@/types\";\n\n/**\n * Standardized error wrapper used by validation generators.\n *\n * Instances of this class are thrown whenever validation fails,\n * carrying both the error scope (e.g. `\"params\"`, `\"payload\"`)\n * and the list of validation error details.\n * */\nexport class ValidationError extends Error {\n public scope: ValidationErrorScope;\n public errors: Array<ValidationErrorEntry> = [];\n public errorMessage: string;\n public errorSummary: string;\n\n constructor([scope, { errors, errorMessage, errorSummary }]: [\n ValidationErrorScope,\n ValidationErrorData,\n ]) {\n super(JSON.stringify(errors, null, 2));\n this.name = `${scope}ValidationError`;\n this.scope = scope;\n this.errors = errors;\n this.errorMessage = errorMessage;\n this.errorSummary = errorSummary;\n }\n}\n"],
5
+ "mappings": ";AAaO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EAClC;AAAA,EACA,SAAsC,CAAC;AAAA,EACvC;AAAA,EACA;AAAA,EAEP,YAAY,CAAC,OAAO,EAAE,QAAQ,cAAc,aAAa,CAAC,GAGvD;AACD,UAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AACrC,SAAK,OAAO,GAAG,KAAK;AACpB,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,eAAe;AACpB,SAAK,eAAe;AAAA,EACtB;AACF;",
6
+ "names": []
7
+ }
package/pkg/index.js CHANGED
@@ -1,11 +1,46 @@
1
1
  // src/app.ts
2
2
  import Koa from "koa";
3
- import withQueryparser from "@kosmojs/api/queryparser";
3
+
4
+ // src/queryparser/index.ts
5
+ import { parse, stringify } from "qs";
6
+ var queryparser_default = (app, _parseOptions = {}, _stringifyOptions = {}) => {
7
+ const parseOptions = {
8
+ ignoreQueryPrefix: true,
9
+ parseArrays: true,
10
+ arrayLimit: 100,
11
+ parameterLimit: 100,
12
+ depth: 5,
13
+ ..._parseOptions
14
+ };
15
+ const stringifyOptions = {
16
+ encodeValuesOnly: true,
17
+ arrayFormat: "brackets",
18
+ ..._stringifyOptions
19
+ };
20
+ const obj = {
21
+ get query() {
22
+ return parse(this.querystring || "", parseOptions);
23
+ },
24
+ set query(obj2) {
25
+ this.querystring = stringify(obj2, stringifyOptions);
26
+ }
27
+ };
28
+ const entries = Object.getOwnPropertyNames(obj).map((name) => [
29
+ name,
30
+ Object.getOwnPropertyDescriptor(obj, name)
31
+ ]);
32
+ for (const [name, desc] of entries) {
33
+ Object.defineProperty(app.request, name, desc);
34
+ }
35
+ return app;
36
+ };
37
+
38
+ // src/app.ts
4
39
  var createApp = (options) => {
5
- return withQueryparser(new Koa(options));
40
+ return queryparser_default(new Koa(options));
6
41
  };
7
42
 
8
- // src/errors.ts
43
+ // src/errors/index.ts
9
44
  var ValidationError = class extends Error {
10
45
  scope;
11
46
  errors = [];
@@ -24,17 +59,79 @@ var ValidationError = class extends Error {
24
59
  // src/router.ts
25
60
  import Router from "@koa/router";
26
61
 
27
- // src/types.ts
28
- var HTTPMethods = /* @__PURE__ */ ((HTTPMethods2) => {
29
- HTTPMethods2["HEAD"] = "HEAD";
30
- HTTPMethods2["OPTIONS"] = "OPTIONS";
31
- HTTPMethods2["GET"] = "GET";
32
- HTTPMethods2["PUT"] = "PUT";
33
- HTTPMethods2["PATCH"] = "PATCH";
34
- HTTPMethods2["POST"] = "POST";
35
- HTTPMethods2["DELETE"] = "DELETE";
36
- return HTTPMethods2;
37
- })(HTTPMethods || {});
62
+ // src/debug.ts
63
+ import { styleText } from "node:util";
64
+ import stringWidth from "string-width";
65
+ var colorizeMethod = (method) => {
66
+ const color = {
67
+ HEAD: "gray",
68
+ GET: "green",
69
+ POST: "blue",
70
+ PATCH: "blue",
71
+ PUT: "blue",
72
+ DELETE: "red"
73
+ }[method];
74
+ return color ? styleText(color, method) : method;
75
+ };
76
+ var debug_default = (entry) => {
77
+ const { path, file } = entry;
78
+ const methodLines = entry.methods.flatMap((method) => {
79
+ const coloredMethod = colorizeMethod(method);
80
+ return method === "GET" ? [coloredMethod + styleText("gray", "|HEAD")] : [coloredMethod];
81
+ });
82
+ const middlewareLines = entry.middleware.map(({ options, middleware: middleware2 }) => {
83
+ const lines = [];
84
+ if (options?.slot) {
85
+ lines.push(
86
+ `${styleText("dim", "slot:")} ${styleText("blue", options.slot)};`
87
+ );
88
+ }
89
+ const funcNames = middleware2.map((fn) => {
90
+ return styleText("magenta", funcName(fn));
91
+ });
92
+ lines.push(`${styleText("dim", "exec:")} ${funcNames.join("; ")}`);
93
+ return lines.join(" ");
94
+ }).join(`
95
+ ${Array(12).fill(" ").join("")}`);
96
+ const handlerLines = entry.handler.middleware.map((fn) => {
97
+ return styleText("yellow", funcName(fn));
98
+ });
99
+ const headline = `${styleText("bgBlue", styleText("black", ` ${path} `))} ${styleText("gray", `[ ${file} ]`)}`;
100
+ const methods = `${styleText("dim", " methods:")} ${methodLines.join(" ")}`;
101
+ const middleware = `${styleText("dim", "middleware:")} ${middlewareLines}`;
102
+ const handler = `${styleText("dim", " handler:")} ${handlerLines.join(Array(7).fill(" ").join(""))}`;
103
+ const maxColumns = process.stdout.isTTY ? Number(process.stdout.columns || 80) : 80;
104
+ const debugEntries = [
105
+ ["headline", headline],
106
+ ["methods", methods],
107
+ ["middleware", middleware],
108
+ ["handler", handler]
109
+ ];
110
+ const lineMapper = (line) => {
111
+ const freeColumns = maxColumns - stringWidth(line);
112
+ return freeColumns > 0 ? [
113
+ line,
114
+ styleText(
115
+ "dim",
116
+ styleText("gray", Array(freeColumns).fill("\xB7").join(""))
117
+ )
118
+ ].join("") : line;
119
+ };
120
+ const debug = debugEntries.reduce(
121
+ (map, [key, line]) => {
122
+ map[key] = line.split("\n").map(lineMapper).join("\n");
123
+ return map;
124
+ },
125
+ {}
126
+ );
127
+ return {
128
+ ...debug,
129
+ full: Object.values(debug).join("\n")
130
+ };
131
+ };
132
+ var funcName = (fn) => {
133
+ return fn.name || fn.toString().split("\n")[0].slice(0, 30);
134
+ };
38
135
 
39
136
  // src/use.ts
40
137
  var use = (middleware, options) => {
@@ -46,9 +143,6 @@ var use = (middleware, options) => {
46
143
  };
47
144
 
48
145
  // src/router.ts
49
- var createRouter = (options) => {
50
- return new Router(options);
51
- };
52
146
  var defineRoute = (factory) => {
53
147
  return factory({
54
148
  use(middleware, options) {
@@ -109,33 +203,34 @@ var defineRoute = (factory) => {
109
203
  }
110
204
  });
111
205
  };
112
- var routerRoutesFactory = (routeSources, {
206
+ var createRouter = (options) => {
207
+ return new Router(options);
208
+ };
209
+ var createRouterRoutes = (routeSources, {
113
210
  // Global middleware applied to every route (e.g., logging)
114
211
  coreMiddleware
115
212
  }) => {
116
213
  const prioritizedSlots = [
214
+ "errorHandler",
117
215
  "params",
118
- // Path params processing
119
216
  "validateParams",
120
- // Path params validation
121
217
  "bodyparser",
122
- // Raw request body parsing
123
218
  "payload",
124
- // Set ctx.payload
125
219
  "validatePayload",
126
- // Payload validation
127
220
  "validateResponse"
128
- // Response validation
129
221
  ];
130
222
  const stack = [];
131
223
  for (const { name, path, file, ...rest } of routeSources) {
132
- const definitionItems = [...rest.useWrappers, ...rest.definitionItems];
224
+ const definitionItems = [
225
+ ...rest.useWrappers,
226
+ ...rest.definitionItems
227
+ ].flat();
133
228
  const routeMiddleware = definitionItems.filter(
134
229
  (e) => e.kind === "middleware"
135
230
  );
136
231
  const middlewareStack = [
137
- ...paramsMiddlewareFactory(rest.params, rest.numericParams),
138
- ...validationMiddlewareFactory(rest.validationSchemas),
232
+ ...createParamsMiddleware(rest.params, rest.numericParams),
233
+ ...createValidationMiddleware(rest.validationSchemas),
139
234
  // core middleware overrides builtin middleware (of same slot)
140
235
  ...coreMiddleware,
141
236
  // route middleware overrides core middleware (of same slot)
@@ -178,34 +273,39 @@ var routerRoutesFactory = (routeSources, {
178
273
  })
179
274
  ];
180
275
  for (const entry of routeStack) {
181
- if (entry.kind === "middleware") {
182
- stack.push({
183
- name,
184
- path,
185
- file,
186
- methods: entry.options?.on || Object.keys(HTTPMethods),
187
- middleware: entry.middleware,
188
- kind: entry.kind,
189
- slot: entry.options?.slot,
190
- debug: entry.options?.debug
276
+ if (entry.kind === "handler") {
277
+ const middleware = routeStack.flatMap((e) => {
278
+ if (e.kind === "middleware") {
279
+ return !e.options?.on || e.options.on.includes(entry.method) ? [e] : [];
280
+ }
281
+ return [];
191
282
  });
192
- } else if (entry.kind === "handler") {
193
283
  stack.push({
194
284
  name,
195
285
  path,
196
286
  file,
197
287
  methods: [entry.method],
198
- middleware: entry.middleware,
199
- kind: entry.kind
288
+ middleware: [
289
+ ...middleware.flatMap((e) => e.middleware),
290
+ ...entry.middleware
291
+ ],
292
+ debug: debug_default({
293
+ name,
294
+ path,
295
+ file,
296
+ methods: [entry.method],
297
+ middleware,
298
+ handler: entry
299
+ })
200
300
  });
201
301
  }
202
302
  }
203
303
  }
204
304
  return stack;
205
305
  };
206
- var paramsMiddlewareFactory = (params, numericParams) => [
306
+ var createParamsMiddleware = (params, numericParams) => [
207
307
  use(
208
- (ctx, next) => {
308
+ function useParams(ctx, next) {
209
309
  ctx.typedParams = params.reduce(
210
310
  (map, [name, isRest]) => {
211
311
  const value = ctx.params[name];
@@ -227,16 +327,16 @@ var paramsMiddlewareFactory = (params, numericParams) => [
227
327
  { slot: "params" }
228
328
  )
229
329
  ];
230
- var validationMiddlewareFactory = (validationSchemas) => [
330
+ var createValidationMiddleware = (validationSchemas) => [
231
331
  use(
232
- (ctx, next) => {
332
+ function useValidateParams(ctx, next) {
233
333
  validationSchemas.params?.validate(ctx.typedParams);
234
334
  return next();
235
335
  },
236
336
  { slot: "validateParams" }
237
337
  ),
238
338
  use(
239
- (ctx, next) => {
339
+ function useValidatePayload(ctx, next) {
240
340
  validationSchemas.payload?.[ctx.method]?.validate(ctx.payload);
241
341
  return next();
242
342
  },
@@ -246,7 +346,7 @@ var validationMiddlewareFactory = (validationSchemas) => [
246
346
  }
247
347
  ),
248
348
  use(
249
- async (ctx, next) => {
349
+ async function useValidateResponse(ctx, next) {
250
350
  if (validationSchemas.response?.[ctx.method]) {
251
351
  await next();
252
352
  validationSchemas.response?.[ctx.method]?.validate(ctx.body);
@@ -260,13 +360,25 @@ var validationMiddlewareFactory = (validationSchemas) => [
260
360
  }
261
361
  )
262
362
  ];
363
+
364
+ // src/types.ts
365
+ var HTTPMethods = /* @__PURE__ */ ((HTTPMethods2) => {
366
+ HTTPMethods2["HEAD"] = "HEAD";
367
+ HTTPMethods2["OPTIONS"] = "OPTIONS";
368
+ HTTPMethods2["GET"] = "GET";
369
+ HTTPMethods2["PUT"] = "PUT";
370
+ HTTPMethods2["PATCH"] = "PATCH";
371
+ HTTPMethods2["POST"] = "POST";
372
+ HTTPMethods2["DELETE"] = "DELETE";
373
+ return HTTPMethods2;
374
+ })(HTTPMethods || {});
263
375
  export {
264
376
  HTTPMethods,
265
377
  ValidationError,
266
378
  createApp,
267
379
  createRouter,
380
+ createRouterRoutes,
268
381
  defineRoute,
269
- routerRoutesFactory,
270
382
  use
271
383
  };
272
384
  //# sourceMappingURL=index.js.map
package/pkg/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/app.ts", "../src/errors.ts", "../src/router.ts", "../src/types.ts", "../src/use.ts"],
4
- "sourcesContent": ["import Koa from \"koa\";\n\nimport withQueryparser from \"@kosmojs/api/queryparser\";\n\nimport type { CreateApp } from \"./types\";\n\nexport const createApp: CreateApp = (options) => {\n return withQueryparser(new Koa(options));\n};\n", "import type {\n ValidationErrorData,\n ValidationErrorEntry,\n ValidationErrorScope,\n} from \"./types\";\n\n/**\n * Standardized error wrapper used by validation generators.\n *\n * Instances of this class are thrown whenever validation fails,\n * carrying both the error scope (e.g. `\"params\"`, `\"payload\"`)\n * and the list of validation error details.\n */\nexport class ValidationError extends Error {\n public scope: ValidationErrorScope;\n public errors: Array<ValidationErrorEntry> = [];\n public errorMessage: string;\n public errorSummary: string;\n\n constructor([scope, { errors, errorMessage, errorSummary }]: [\n ValidationErrorScope,\n ValidationErrorData,\n ]) {\n super(JSON.stringify(errors, null, 2));\n this.name = `${scope}ValidationError`;\n this.scope = scope;\n this.errors = errors;\n this.errorMessage = errorMessage;\n this.errorSummary = errorSummary;\n }\n}\n", "import Router from \"@koa/router\";\n\nimport {\n type CreateRouter,\n type DefineRoute,\n type HandlerDefinition,\n HTTPMethods,\n type MiddlewareDefinition,\n type RouterRoute,\n type RouterRouteSource,\n type UseSlots,\n type ValidationSchemas,\n} from \"./types\";\nimport { use } from \"./use\";\n\nexport const createRouter: CreateRouter = (options) => {\n return new Router(options);\n};\n\nexport const defineRoute: DefineRoute = (factory) => {\n return factory({\n use(middleware, options) {\n return {\n kind: \"middleware\",\n middleware: [middleware as never].flat(),\n options,\n };\n },\n HEAD(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"HEAD\",\n };\n },\n OPTIONS(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"OPTIONS\",\n };\n },\n GET(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"GET\",\n };\n },\n POST(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"POST\",\n };\n },\n PUT(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"PUT\",\n };\n },\n PATCH(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"PATCH\",\n };\n },\n DELETE(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"DELETE\",\n };\n },\n });\n};\n\nexport const routerRoutesFactory = (\n routeSources: Array<RouterRouteSource>,\n {\n // Global middleware applied to every route (e.g., logging)\n coreMiddleware,\n }: {\n coreMiddleware: Array<MiddlewareDefinition>;\n },\n) => {\n // WARN:: prioritized middleware must run in this exact order!\n const prioritizedSlots: Array<keyof UseSlots> = [\n \"params\", // Path params processing\n \"validateParams\", // Path params validation\n \"bodyparser\", // Raw request body parsing\n \"payload\", // Set ctx.payload\n \"validatePayload\", // Payload validation\n \"validateResponse\", // Response validation\n ];\n\n const stack: Array<RouterRoute> = [];\n\n // Iterate over each route definition\n for (const { name, path, file, ...rest } of routeSources) {\n // Include both middleware and HTTP method handlers\n const definitionItems = [...rest.useWrappers, ...rest.definitionItems];\n\n const routeMiddleware: Array<MiddlewareDefinition> = definitionItems.filter(\n (e) => e.kind === \"middleware\",\n );\n\n // WARN: the order is critical!\n // the last defined middleware will take precedence.\n const middlewareStack: Array<MiddlewareDefinition> = [\n ...paramsMiddlewareFactory(rest.params, rest.numericParams),\n ...validationMiddlewareFactory(rest.validationSchemas),\n // core middleware overrides builtin middleware (of same slot)\n ...coreMiddleware,\n // route middleware overrides core middleware (of same slot)\n ...routeMiddleware,\n ];\n\n const routeStack: Array<MiddlewareDefinition | HandlerDefinition> = [\n ...prioritizedSlots.flatMap((slot) => {\n const middleware = middlewareStack.findLast(\n // Using findLast to pick the latest entry,\n // ensuring later entries override earlier ones.\n (e) => e.options?.slot === slot,\n );\n return middleware //\n ? [middleware]\n : [];\n }),\n\n ...coreMiddleware.flatMap((entry) => {\n if (!entry.options?.slot) {\n // no slot, including regardless\n return [entry];\n }\n if (prioritizedSlots.includes(entry.options?.slot)) {\n // already picked when inserted prioritized middleware, excluding\n return [];\n }\n const override = routeMiddleware.findLast(\n // Using findLast to pick the latest entry,\n // ensuring later entries override earlier ones.\n (e) => e.options?.slot === entry.options?.slot,\n );\n return [override || entry];\n }),\n\n ...definitionItems.flatMap((entry) => {\n const slot =\n entry.kind === \"middleware\" //\n ? entry.options?.slot\n : undefined;\n\n if (slot) {\n if (prioritizedSlots.includes(slot)) {\n // already picked when inserted prioritized middleware, excluding\n return [];\n }\n if (coreMiddleware.some((e) => e.options?.slot === slot)) {\n // already picked when inserted core middleware, excluding\n return [];\n }\n }\n\n return [entry];\n }),\n ];\n\n for (const entry of routeStack) {\n if (entry.kind === \"middleware\") {\n stack.push({\n name,\n path,\n file,\n methods: entry.options?.on || Object.keys(HTTPMethods),\n middleware: entry.middleware,\n kind: entry.kind,\n slot: entry.options?.slot,\n debug: entry.options?.debug,\n });\n } else if (entry.kind === \"handler\") {\n stack.push({\n name,\n path,\n file,\n methods: [entry.method],\n middleware: entry.middleware,\n kind: entry.kind,\n });\n }\n }\n }\n\n return stack;\n};\n\nconst paramsMiddlewareFactory = (\n params: RouterRouteSource[\"params\"],\n numericParams: RouterRouteSource[\"numericParams\"],\n) => [\n use(\n (ctx, next) => {\n ctx.typedParams = params.reduce(\n (map: Record<string, unknown>, [name, isRest]) => {\n const value = ctx.params[name];\n if (value) {\n if (isRest) {\n map[name] = numericParams.includes(name)\n ? value.split(\"/\").map(Number)\n : value.split(\"/\");\n } else {\n map[name] = numericParams.includes(name) ? Number(value) : value;\n }\n } else {\n map[name] = value;\n }\n return map;\n },\n {},\n ) as never;\n return next();\n },\n { slot: \"params\" },\n ),\n];\n\nconst validationMiddlewareFactory = (validationSchemas: ValidationSchemas) => [\n use(\n (ctx, next) => {\n validationSchemas.params?.validate(ctx.typedParams);\n return next();\n },\n { slot: \"validateParams\" },\n ),\n\n use(\n (ctx, next) => {\n validationSchemas.payload?.[ctx.method]?.validate(ctx.payload);\n return next();\n },\n {\n slot: \"validatePayload\",\n on: Object.keys(validationSchemas.payload || {}) as never,\n },\n ),\n\n use(\n async (ctx, next) => {\n if (validationSchemas.response?.[ctx.method]) {\n await next();\n validationSchemas.response?.[ctx.method]?.validate(ctx.body);\n } else {\n return next();\n }\n },\n {\n slot: \"validateResponse\",\n on: Object.keys(validationSchemas.response || {}) as never,\n },\n ),\n];\n", "import type {\n RouterContext,\n RouterMiddleware,\n RouterOptions,\n} from \"@koa/router\";\nimport type { Next } from \"koa\";\n\ndeclare module \"koa\" {\n interface Request {\n body?: unknown;\n rawBody: string;\n }\n}\n\nexport interface DefaultState {}\nexport interface DefaultContext {}\n\nexport enum HTTPMethods {\n HEAD = \"HEAD\",\n OPTIONS = \"OPTIONS\",\n GET = \"GET\",\n PUT = \"PUT\",\n PATCH = \"PATCH\",\n POST = \"POST\",\n DELETE = \"DELETE\",\n}\n\nexport type { RouterMiddleware as Middleware };\n\nexport type HTTPMethod = keyof typeof HTTPMethods;\n\nexport type ParameterizedContext<\n ParamsT,\n StateT,\n ContextT,\n PayloadT = unknown,\n ResponseT = unknown,\n> = RouterContext<\n DefaultState & StateT,\n DefaultContext &\n ContextT & {\n typedParams: ParamsT;\n payload: PayloadT;\n },\n ResponseT\n>;\n\ntype RouteMiddleware<ParamsT, StateT, ContextT> = (\n ctx: ParameterizedContext<ParamsT, StateT, ContextT>,\n next: Next,\n) => Promise<void> | void;\n\nexport type RouteHandler<\n ParamsT,\n StateT,\n ContextT,\n PayloadT = unknown,\n ResponseT = unknown,\n> = (\n ctx: ParameterizedContext<ParamsT, StateT, ContextT, PayloadT, ResponseT>,\n next: Next,\n) => Promise<void> | void;\n\nexport type MiddlewareDefinition = {\n kind: \"middleware\";\n middleware: Array<RouterMiddleware>;\n options?: UseOptions | undefined;\n};\n\nexport type HandlerDefinition = {\n kind: \"handler\";\n middleware: Array<RouterMiddleware>;\n method: HTTPMethod;\n};\n\nexport type RouteDefinitionItem = MiddlewareDefinition | HandlerDefinition;\n\nexport type DefineRouteHelpers<\n ParamsT,\n StateT,\n ContextT,\n OptionalHandlers = undefined,\n> = {\n // INFO: The `use` helper intentionally does not accept type parameters.\n // PayloadT and ResponseT are only relevant to route handlers,\n // as different request methods receive different payloads and return different responses.\n // Allowing these type parameters on `use` would be misleading,\n // since middleware operates across multiple request methods with varying types.\n use: (\n middleware:\n | RouteMiddleware<ParamsT, StateT, ContextT>\n | Array<RouteMiddleware<ParamsT, StateT, ContextT>>,\n options?: UseOptions,\n ) => RouteDefinitionItem;\n} & {\n [M in HTTPMethod]: M extends OptionalHandlers\n ? <PayloadT = unknown, ResponseT = unknown>(\n handler?:\n | RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT>\n | Array<RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT>>,\n ) => RouteDefinitionItem\n : <PayloadT = unknown, ResponseT = unknown>(\n handler:\n | RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT>\n | Array<RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT>>,\n ) => RouteDefinitionItem;\n};\n\nexport type DefineRoute = <\n ParamsT = Record<string, string>,\n StateT = object,\n ContextT = object,\n>(\n factory: (\n helpers: DefineRouteHelpers<ParamsT, StateT, ContextT>,\n ) => Array<RouteDefinitionItem>,\n) => Array<RouteDefinitionItem>;\n\nexport interface UseSlots {\n params: string;\n validateParams: string;\n bodyparser: string;\n payload: string;\n validatePayload: string;\n validateResponse: string;\n}\n\nexport type UseOptions = {\n on?: Array<HTTPMethod>;\n slot?: keyof UseSlots;\n debug?: string | undefined;\n};\n\nexport type Use = <StateT = DefaultState, ContextT = DefaultContext>(\n middleware:\n | RouteMiddleware<Record<string, string>, StateT, ContextT>\n | Array<RouteMiddleware<Record<string, string>, StateT, ContextT>>,\n options?: UseOptions,\n) => MiddlewareDefinition;\n\nexport type RouterRouteSource = {\n name: string;\n path: string;\n file: string;\n // useWrappers is same as defining middleware inside route definition,\n // just automatically imported from use.ts files\n useWrappers: Array<MiddlewareDefinition>;\n definitionItems: Array<RouteDefinitionItem>;\n params: Array<[name: string, isRest?: boolean]>;\n numericParams: Array<string>;\n validationSchemas: ValidationSchemas;\n meta?: Record<string, unknown>;\n};\n\nexport type RouterRoute = {\n name: string;\n path: string;\n file: string;\n methods: Array<string>;\n middleware: Array<RouterMiddleware>;\n kind: \"middleware\" | \"handler\";\n slot?: keyof UseSlots | undefined;\n debug?: string | undefined;\n};\n\nimport type Koa from \"koa\";\nexport type App = Koa<DefaultState, DefaultContext>;\nexport type AppOptions = ConstructorParameters<typeof import(\"koa\")>[0];\nexport type CreateApp = (options?: AppOptions) => App;\n\nimport type KoaRouter from \"@koa/router\";\nexport type Router = KoaRouter<DefaultState, DefaultContext>;\nexport type { RouterOptions };\nexport type CreateRouter = (options?: RouterOptions) => Router;\n\nexport type DevMiddlewareFactory = (\n app: App,\n) => (\n req: import(\"node:http\").IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n next: () => Promise<void>,\n) => Promise<void>;\nexport type TeardownHandler = (app: App) => void | Promise<void>;\n\nexport type ValidationSchema = {\n check: (data: unknown) => boolean;\n errors: (data: unknown) => Array<ValidationErrorEntry>;\n errorMessage: (data: unknown) => string;\n errorSummary: (data: unknown) => string;\n validate: (data: unknown) => void;\n};\n\nexport type ValidationSchemas<Extend = object> = {\n params?: ValidationSchema & Extend;\n payload?: Record<string, ValidationSchema & Extend>;\n response?: Record<string, ValidationSchema & Extend>;\n};\n\nexport type ValidationErrorScope = \"params\" | \"payload\" | \"response\";\n\n/**\n * Shape of individual validation errors emitted by generators.\n */\nexport type ValidationErrorEntry = {\n /** JSON Schema keyword that triggered the error (e.g. `format`, `maxItems`, `maxLength`). */\n keyword: string;\n /** JSON Pointer\u2013style path to the invalid field (matches JSON Schema `instancePath`). */\n path: string;\n /** Human-readable error message. */\n message: string;\n /** Constraint parameters (e.g. `{ limit: 5 }`, `{ format: \"email\" }`). */\n params?: Record<string, unknown>;\n /** Optional error code for i18n/l10n or custom handling. */\n code?: string;\n};\n\nexport type ValidationErrorData = {\n errors: Array<ValidationErrorEntry>;\n /**\n * Formats errors into a single human-readable message.\n * @example: Validation failed: user: missing required properties: \"email\", \"name\"; password: must be at least 8 characters long\n */\n errorMessage: string;\n /**\n * Gets a simple error summary for quick feedback.\n * @example: 2 validation errors found across 2 fields\n */\n errorSummary: string;\n};\n", "import type { Use } from \"./types\";\n\nexport const use: Use = (middleware, options) => {\n return {\n kind: \"middleware\",\n middleware: [middleware].flat() as never,\n options,\n };\n};\n"],
5
- "mappings": "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",
6
- "names": ["HTTPMethods"]
3
+ "sources": ["../src/app.ts", "../src/queryparser/index.ts", "../src/errors/index.ts", "../src/router.ts", "../src/debug.ts", "../src/use.ts", "../src/types.ts"],
4
+ "sourcesContent": ["import Koa from \"koa\";\n\nimport withQueryparser from \"@/queryparser\";\n\nimport type { AppOptions } from \"./types\";\n\nexport const createApp = (options?: AppOptions) => {\n return withQueryparser(new Koa(options));\n};\n", "import type Koa from \"koa\";\nimport type { IParseOptions, IStringifyOptions } from \"qs\";\nimport { parse, stringify } from \"qs\";\n\nimport type { DefaultContext, DefaultState } from \"@/types\";\n\nexport default <\n T extends InstanceType<typeof Koa<DefaultState, DefaultContext>> = never,\n>(\n app: T,\n _parseOptions: IParseOptions = {},\n _stringifyOptions: IStringifyOptions = {},\n) => {\n const parseOptions = {\n ignoreQueryPrefix: true,\n parseArrays: true,\n arrayLimit: 100,\n parameterLimit: 100,\n depth: 5,\n ..._parseOptions,\n };\n\n const stringifyOptions = {\n encodeValuesOnly: true,\n arrayFormat: \"brackets\",\n ..._stringifyOptions,\n } as const;\n\n const obj = {\n get query() {\n return parse((this as Koa.Request).querystring || \"\", parseOptions);\n },\n\n set query(obj: object) {\n (this as Koa.Request).querystring = stringify(obj, stringifyOptions);\n },\n };\n\n const entries = Object.getOwnPropertyNames(obj).map((name) => [\n name,\n Object.getOwnPropertyDescriptor(obj, name),\n ]) as [name: string, desc: PropertyDescriptor][];\n\n for (const [name, desc] of entries) {\n Object.defineProperty(app.request, name, desc);\n }\n\n return app;\n};\n", "import type {\n ValidationErrorData,\n ValidationErrorEntry,\n ValidationErrorScope,\n} from \"@/types\";\n\n/**\n * Standardized error wrapper used by validation generators.\n *\n * Instances of this class are thrown whenever validation fails,\n * carrying both the error scope (e.g. `\"params\"`, `\"payload\"`)\n * and the list of validation error details.\n * */\nexport class ValidationError extends Error {\n public scope: ValidationErrorScope;\n public errors: Array<ValidationErrorEntry> = [];\n public errorMessage: string;\n public errorSummary: string;\n\n constructor([scope, { errors, errorMessage, errorSummary }]: [\n ValidationErrorScope,\n ValidationErrorData,\n ]) {\n super(JSON.stringify(errors, null, 2));\n this.name = `${scope}ValidationError`;\n this.scope = scope;\n this.errors = errors;\n this.errorMessage = errorMessage;\n this.errorSummary = errorSummary;\n }\n}\n", "import Router, { type RouterMiddleware } from \"@koa/router\";\n\nimport debugRouteEntry from \"./debug\";\nimport type {\n DefineRoute,\n HandlerDefinition,\n MiddlewareDefinition,\n RouterOptions,\n RouterRoute,\n RouterRouteSource,\n UseSlots,\n ValidationSchemas,\n} from \"./types\";\nimport { use } from \"./use\";\n\nexport const defineRoute: DefineRoute = (factory) => {\n return factory({\n use(middleware, options) {\n return {\n kind: \"middleware\",\n middleware: [middleware as never].flat(),\n options,\n };\n },\n HEAD(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"HEAD\",\n };\n },\n OPTIONS(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"OPTIONS\",\n };\n },\n GET(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"GET\",\n };\n },\n POST(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"POST\",\n };\n },\n PUT(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"PUT\",\n };\n },\n PATCH(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"PATCH\",\n };\n },\n DELETE(middleware) {\n return {\n kind: \"handler\",\n middleware: [middleware as never].flat(),\n method: \"DELETE\",\n };\n },\n });\n};\n\nexport const createRouter = (options?: RouterOptions) => {\n return new Router(options);\n};\n\nexport const createRouterRoutes = (\n routeSources: Array<RouterRouteSource>,\n {\n // Global middleware applied to every route (e.g., logging)\n coreMiddleware,\n }: {\n coreMiddleware: Array<MiddlewareDefinition>;\n },\n): Array<RouterRoute> => {\n // NOTE:: prioritized middleware must run in this exact order!\n const prioritizedSlots: Array<keyof UseSlots> = [\n \"errorHandler\",\n \"params\",\n \"validateParams\",\n \"bodyparser\",\n \"payload\",\n \"validatePayload\",\n \"validateResponse\",\n ];\n\n const stack: Array<RouterRoute> = [];\n\n // Iterate over each route definition\n for (const { name, path, file, ...rest } of routeSources) {\n // Include both middleware and HTTP method handlers\n const definitionItems = [\n ...rest.useWrappers,\n ...rest.definitionItems,\n ].flat();\n\n const routeMiddleware: Array<MiddlewareDefinition> = definitionItems.filter(\n (e) => e.kind === \"middleware\",\n );\n\n const middlewareStack: Array<MiddlewareDefinition> = [\n ...createParamsMiddleware(rest.params, rest.numericParams),\n ...createValidationMiddleware(rest.validationSchemas),\n // core middleware overrides builtin middleware (of same slot)\n ...coreMiddleware,\n // route middleware overrides core middleware (of same slot)\n ...routeMiddleware,\n ];\n\n // NOTE: later defined middleware should override previous middleware of same slot\n const routeStack: Array<MiddlewareDefinition | HandlerDefinition> = [\n ...prioritizedSlots.flatMap((slot) => {\n const middleware = middlewareStack.findLast(\n // Using findLast to pick the latest entry,\n // ensuring later entries override earlier ones.\n (e) => e.options?.slot === slot,\n );\n return middleware //\n ? [middleware]\n : [];\n }),\n\n ...coreMiddleware.flatMap((entry) => {\n if (!entry.options?.slot) {\n // no slot, including regardless\n return [entry];\n }\n if (prioritizedSlots.includes(entry.options?.slot)) {\n // already picked when inserted prioritized middleware, excluding\n return [];\n }\n const override = routeMiddleware.findLast(\n // Using findLast to pick the latest entry,\n // ensuring later entries override earlier ones.\n (e) => e.options?.slot === entry.options?.slot,\n );\n return [override || entry];\n }),\n\n ...definitionItems.flatMap((entry) => {\n const slot =\n entry.kind === \"middleware\" //\n ? entry.options?.slot\n : undefined;\n\n if (slot) {\n if (prioritizedSlots.includes(slot)) {\n // already picked when inserted prioritized middleware, excluding\n return [];\n }\n if (coreMiddleware.some((e) => e.options?.slot === slot)) {\n // already picked when inserted core middleware, excluding\n return [];\n }\n }\n\n return [entry];\n }),\n ];\n\n for (const entry of routeStack) {\n if (entry.kind === \"handler\") {\n const middleware = routeStack.flatMap((e) => {\n if (e.kind === \"middleware\") {\n return !e.options?.on || e.options.on.includes(entry.method)\n ? [e]\n : [];\n }\n return [];\n });\n stack.push({\n name,\n path,\n file,\n methods: [entry.method],\n middleware: [\n ...middleware.flatMap((e) => e.middleware),\n ...entry.middleware,\n ] as unknown as Array<RouterMiddleware>,\n debug: debugRouteEntry({\n name,\n path,\n file,\n methods: [entry.method],\n middleware,\n handler: entry,\n }),\n });\n }\n }\n }\n\n return stack;\n};\n\nconst createParamsMiddleware = (\n params: RouterRouteSource[\"params\"],\n numericParams: RouterRouteSource[\"numericParams\"],\n) => [\n use(\n function useParams(ctx, next) {\n ctx.typedParams = params.reduce(\n (map: Record<string, unknown>, [name, isRest]) => {\n const value = ctx.params[name];\n if (value) {\n if (isRest) {\n map[name] = numericParams.includes(name)\n ? value.split(\"/\").map(Number)\n : value.split(\"/\");\n } else {\n map[name] = numericParams.includes(name) ? Number(value) : value;\n }\n } else {\n map[name] = value;\n }\n return map;\n },\n {},\n ) as never;\n return next();\n },\n { slot: \"params\" },\n ),\n];\n\nconst createValidationMiddleware = (validationSchemas: ValidationSchemas) => [\n use(\n function useValidateParams(ctx, next) {\n validationSchemas.params?.validate(ctx.typedParams);\n return next();\n },\n { slot: \"validateParams\" },\n ),\n\n use(\n function useValidatePayload(ctx, next) {\n validationSchemas.payload?.[ctx.method]?.validate(ctx.payload);\n return next();\n },\n {\n slot: \"validatePayload\",\n on: Object.keys(validationSchemas.payload || {}) as never,\n },\n ),\n\n use(\n async function useValidateResponse(ctx, next) {\n if (validationSchemas.response?.[ctx.method]) {\n await next();\n validationSchemas.response?.[ctx.method]?.validate(ctx.body);\n } else {\n return next();\n }\n },\n {\n slot: \"validateResponse\",\n on: Object.keys(validationSchemas.response || {}) as never,\n },\n ),\n];\n", "import { styleText } from \"node:util\";\n\nimport stringWidth from \"string-width\";\n\nimport type {\n HandlerDefinition,\n MiddlewareDefinition,\n RouterRoute,\n} from \"./types\";\n\nconst colorizeMethod = (method: string): string => {\n const color = (\n {\n HEAD: \"gray\",\n GET: \"green\",\n POST: \"blue\",\n PATCH: \"blue\",\n PUT: \"blue\",\n DELETE: \"red\",\n } as const\n )[method];\n return color ? styleText(color, method) : method;\n};\n\nexport default (entry: {\n name: string;\n path: string;\n file: string;\n methods: Array<string>;\n middleware: Array<MiddlewareDefinition>;\n handler: HandlerDefinition;\n}): RouterRoute[\"debug\"] => {\n const { path, file } = entry;\n\n const methodLines = entry.methods.flatMap((method) => {\n const coloredMethod = colorizeMethod(method);\n return method === \"GET\"\n ? [coloredMethod + styleText(\"gray\", \"|HEAD\")]\n : [coloredMethod];\n });\n\n const middlewareLines = entry.middleware\n .map(({ options, middleware }) => {\n const lines: Array<string> = [];\n\n if (options?.slot) {\n lines.push(\n `${styleText(\"dim\", \"slot:\")} ${styleText(\"blue\", options.slot)};`,\n );\n }\n\n const funcNames = middleware.map((fn) => {\n return styleText(\"magenta\", funcName(fn));\n });\n\n lines.push(`${styleText(\"dim\", \"exec:\")} ${funcNames.join(\"; \")}`);\n\n return lines.join(\" \");\n })\n .join(`\\n${Array(12).fill(\" \").join(\"\")}`);\n\n const handlerLines = entry.handler.middleware.map((fn) => {\n return styleText(\"yellow\", funcName(fn));\n });\n\n const headline = `${styleText(\"bgBlue\", styleText(\"black\", ` ${path} `))} ${styleText(\"gray\", `[ ${file} ]`)}`;\n const methods = `${styleText(\"dim\", \" methods:\")} ${methodLines.join(\" \")}`;\n const middleware = `${styleText(\"dim\", \"middleware:\")} ${middlewareLines}`;\n const handler = `${styleText(\"dim\", \" handler:\")} ${handlerLines.join(Array(7).fill(\" \").join(\"\"))}`;\n\n const maxColumns = process.stdout.isTTY\n ? Number(process.stdout.columns || 80)\n : 80;\n\n const debugEntries = [\n [\"headline\", headline],\n [\"methods\", methods],\n [\"middleware\", middleware],\n [\"handler\", handler],\n ] as const;\n\n const lineMapper = (line: string) => {\n const freeColumns = maxColumns - stringWidth(line);\n return freeColumns > 0\n ? [\n line,\n styleText(\n \"dim\",\n styleText(\"gray\", Array(freeColumns).fill(\"\u00B7\").join(\"\")),\n ),\n ].join(\"\")\n : line;\n };\n\n const debug = debugEntries.reduce(\n (map, [key, line]) => {\n map[key] = line.split(\"\\n\").map(lineMapper).join(\"\\n\");\n return map;\n },\n {} as RouterRoute[\"debug\"],\n );\n\n return {\n ...debug,\n full: Object.values(debug).join(\"\\n\"),\n };\n};\n\nconst funcName = (fn: Function) => {\n return fn.name || fn.toString().split(\"\\n\")[0].slice(0, 30);\n};\n", "import type { Use } from \"./types\";\n\nexport const use: Use = (middleware, options) => {\n return {\n kind: \"middleware\",\n middleware: [middleware].flat() as never,\n options,\n };\n};\n", "import type { RouterContext, RouterMiddleware } from \"@koa/router\";\nimport type { Next } from \"koa\";\n\ndeclare module \"koa\" {\n interface Request {\n body?: unknown;\n rawBody: string;\n }\n}\n\nexport interface DefaultState {}\nexport interface DefaultContext {}\n\nexport enum HTTPMethods {\n HEAD = \"HEAD\",\n OPTIONS = \"OPTIONS\",\n GET = \"GET\",\n PUT = \"PUT\",\n PATCH = \"PATCH\",\n POST = \"POST\",\n DELETE = \"DELETE\",\n}\n\nexport type HTTPMethod = keyof typeof HTTPMethods;\n\nexport type ParameterizedContext<\n ParamsT,\n StateT,\n ContextT,\n PayloadT = unknown,\n ResponseT = unknown,\n> = RouterContext<\n DefaultState & StateT,\n DefaultContext &\n ContextT & {\n typedParams: ParamsT;\n payload: PayloadT;\n },\n ResponseT\n>;\n\nexport type ParameterizedMiddleware<\n ParamsT = {},\n StateT = {},\n ContextT = {},\n> = (\n ctx: ParameterizedContext<ParamsT, StateT, ContextT>,\n next: Next,\n) => Promise<void> | void;\n\nexport type RouteHandler<\n ParamsT,\n StateT,\n ContextT,\n PayloadT = unknown,\n ResponseT = unknown,\n> = (\n ctx: ParameterizedContext<ParamsT, StateT, ContextT, PayloadT, ResponseT>,\n next: Next,\n) => Promise<void> | void;\n\nexport type MiddlewareDefinition = {\n kind: \"middleware\";\n middleware: Array<ParameterizedMiddleware>;\n options?: UseOptions | undefined;\n};\n\nexport type HandlerDefinition = {\n kind: \"handler\";\n middleware: Array<ParameterizedMiddleware>;\n method: HTTPMethod;\n};\n\nexport type RouteDefinitionItem = MiddlewareDefinition | HandlerDefinition;\n\nexport type DefineRouteHelpers<\n ParamsT,\n StateT,\n ContextT,\n OptionalHandlers = undefined,\n> = {\n // INFO: The `use` helper intentionally does not accept type parameters.\n // PayloadT and ResponseT are only relevant to route handlers,\n // as different request methods receive different payloads and return different responses.\n // Allowing these type parameters on `use` would be misleading,\n // since middleware operates across multiple request methods with varying types.\n use: (\n middleware:\n | ParameterizedMiddleware<ParamsT, StateT, ContextT>\n | Array<ParameterizedMiddleware<ParamsT, StateT, ContextT>>,\n options?: UseOptions,\n ) => RouteDefinitionItem;\n} & {\n [M in HTTPMethod]: M extends OptionalHandlers\n ? <PayloadT = unknown, ResponseT = unknown>(\n handler?:\n | RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT>\n | Array<RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT>>,\n ) => RouteDefinitionItem\n : <PayloadT = unknown, ResponseT = unknown>(\n handler:\n | RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT>\n | Array<RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT>>,\n ) => RouteDefinitionItem;\n};\n\nexport type DefineRoute = <\n ParamsT = Record<string, string>,\n StateT = object,\n ContextT = object,\n>(\n factory: (\n helpers: DefineRouteHelpers<ParamsT, StateT, ContextT>,\n ) => Array<RouteDefinitionItem>,\n) => Array<RouteDefinitionItem>;\n\nexport interface UseSlots {\n errorHandler: string;\n params: string;\n validateParams: string;\n bodyparser: string;\n payload: string;\n validatePayload: string;\n validateResponse: string;\n}\n\nexport type UseOptions = {\n on?: Array<HTTPMethod>;\n slot?: keyof UseSlots;\n debug?: string | undefined;\n};\n\nexport type Use = <StateT = DefaultState, ContextT = DefaultContext>(\n middleware:\n | ParameterizedMiddleware<Record<string, string>, StateT, ContextT>\n | Array<ParameterizedMiddleware<Record<string, string>, StateT, ContextT>>,\n options?: UseOptions,\n) => MiddlewareDefinition;\n\nexport type RouterRouteSource = {\n name: string;\n path: string;\n file: string;\n // useWrappers is same as defining middleware inside route definition,\n // just automatically imported from use.ts files\n useWrappers: [...a: Array<MiddlewareDefinition>];\n definitionItems: Array<RouteDefinitionItem>;\n params: Array<[name: string, isRest?: boolean]>;\n numericParams: Array<string>;\n validationSchemas: ValidationSchemas;\n meta?: Record<string, unknown>;\n};\n\nexport type RouterRoute = {\n name: string;\n path: string;\n file: string;\n methods: Array<string>;\n middleware: Array<RouterMiddleware>;\n debug: {\n headline: string;\n methods: string;\n middleware: string;\n handler: string;\n full: string;\n };\n};\n\nimport type Koa from \"koa\";\nexport type App = Koa<DefaultState, DefaultContext>;\nexport type AppOptions = ConstructorParameters<typeof import(\"koa\")>[0];\n\nexport type Router = import(\"@koa/router\").Router<DefaultState, DefaultContext>;\nexport type RouterOptions = import(\"@koa/router\").RouterOptions;\n\nexport type DevMiddlewareFactory = (\n app: App,\n) => (\n req: import(\"node:http\").IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n next: () => Promise<void>,\n) => Promise<void>;\nexport type TeardownHandler = (app: App) => void | Promise<void>;\n\nexport type ValidationSchema = {\n check: (data: unknown) => boolean;\n errors: (data: unknown) => Array<ValidationErrorEntry>;\n errorMessage: (data: unknown) => string;\n errorSummary: (data: unknown) => string;\n validate: (data: unknown) => void;\n};\n\nexport type ValidationSchemas<Extend = object> = {\n params?: ValidationSchema & Extend;\n payload?: Record<string, ValidationSchema & Extend>;\n response?: Record<string, ValidationSchema & Extend>;\n};\n\nexport type ValidationErrorScope = \"params\" | \"payload\" | \"response\";\n\n/**\n * Shape of individual validation errors emitted by generators.\n */\nexport type ValidationErrorEntry = {\n /** JSON Schema keyword that triggered the error (e.g. `format`, `maxItems`, `maxLength`). */\n keyword: string;\n /** JSON Pointer\u2013style path to the invalid field (matches JSON Schema `instancePath`). */\n path: string;\n /** Human-readable error message. */\n message: string;\n /** Constraint parameters (e.g. `{ limit: 5 }`, `{ format: \"email\" }`). */\n params?: Record<string, unknown>;\n /** Optional error code for i18n/l10n or custom handling. */\n code?: string;\n};\n\nexport type ValidationErrorData = {\n errors: Array<ValidationErrorEntry>;\n /**\n * Formats errors into a single human-readable message.\n * @example: Validation failed: user: missing required properties: \"email\", \"name\"; password: must be at least 8 characters long\n */\n errorMessage: string;\n /**\n * Gets a simple error summary for quick feedback.\n * @example: 2 validation errors found across 2 fields\n */\n errorSummary: string;\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["obj", "middleware", "HTTPMethods"]
7
7
  }
package/pkg/src/app.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- import type { CreateApp } from "./types";
2
- export declare const createApp: CreateApp;
1
+ import Koa from "koa";
2
+ import type { AppOptions } from "./types";
3
+ export declare const createApp: (options?: AppOptions) => Koa<Koa.DefaultState, Koa.DefaultContext>;
@@ -1,4 +1,4 @@
1
- import type { Middleware } from "@kosmojs/api";
1
+ import type { ParameterizedMiddleware } from "@kosmojs/api";
2
2
  import config from "./config";
3
3
  import type { FormOptions, JsonOptions, RawOptions } from "./types";
4
4
  export * from "./types";
@@ -9,6 +9,6 @@ declare const _default: {
9
9
  raw: typeof raw;
10
10
  };
11
11
  export default _default;
12
- export declare function json(opts?: JsonOptions): Array<Middleware>;
13
- export declare function form(opts?: FormOptions): Array<Middleware>;
14
- export declare function raw(opts?: RawOptions): Array<Middleware>;
12
+ export declare function json(opts?: JsonOptions): Array<ParameterizedMiddleware>;
13
+ export declare function form(opts?: FormOptions): Array<ParameterizedMiddleware>;
14
+ export declare function raw(opts?: RawOptions): Array<ParameterizedMiddleware>;
@@ -1,4 +1,10 @@
1
- import type { RouterRoute } from "./types";
2
- type Printer = (line: string) => void;
3
- declare const _default: (routes: Array<RouterRoute>, printer: Printer, patterns?: Array<string> | undefined) => void;
1
+ import type { HandlerDefinition, MiddlewareDefinition, RouterRoute } from "./types";
2
+ declare const _default: (entry: {
3
+ name: string;
4
+ path: string;
5
+ file: string;
6
+ methods: Array<string>;
7
+ middleware: Array<MiddlewareDefinition>;
8
+ handler: HandlerDefinition;
9
+ }) => RouterRoute["debug"];
4
10
  export default _default;
@@ -1,11 +1,11 @@
1
- import type { ValidationErrorData, ValidationErrorEntry, ValidationErrorScope } from "./types";
1
+ import type { ValidationErrorData, ValidationErrorEntry, ValidationErrorScope } from "../types";
2
2
  /**
3
3
  * Standardized error wrapper used by validation generators.
4
4
  *
5
5
  * Instances of this class are thrown whenever validation fails,
6
6
  * carrying both the error scope (e.g. `"params"`, `"payload"`)
7
7
  * and the list of validation error details.
8
- */
8
+ * */
9
9
  export declare class ValidationError extends Error {
10
10
  scope: ValidationErrorScope;
11
11
  errors: Array<ValidationErrorEntry>;
@@ -1,6 +1,7 @@
1
- import { type CreateRouter, type DefineRoute, type MiddlewareDefinition, type RouterRoute, type RouterRouteSource } from "./types";
2
- export declare const createRouter: CreateRouter;
1
+ import Router from "@koa/router";
2
+ import type { DefineRoute, MiddlewareDefinition, RouterOptions, RouterRoute, RouterRouteSource } from "./types";
3
3
  export declare const defineRoute: DefineRoute;
4
- export declare const routerRoutesFactory: (routeSources: Array<RouterRouteSource>, { coreMiddleware, }: {
4
+ export declare const createRouter: (options?: RouterOptions) => Router<import("koa").DefaultState, import("koa").DefaultContext>;
5
+ export declare const createRouterRoutes: (routeSources: Array<RouterRouteSource>, { coreMiddleware, }: {
5
6
  coreMiddleware: Array<MiddlewareDefinition>;
6
- }) => RouterRoute[];
7
+ }) => Array<RouterRoute>;
@@ -1,4 +1,4 @@
1
- import type { RouterContext, RouterMiddleware, RouterOptions } from "@koa/router";
1
+ import type { RouterContext, RouterMiddleware } from "@koa/router";
2
2
  import type { Next } from "koa";
3
3
  declare module "koa" {
4
4
  interface Request {
@@ -19,32 +19,32 @@ export declare enum HTTPMethods {
19
19
  POST = "POST",
20
20
  DELETE = "DELETE"
21
21
  }
22
- export type { RouterMiddleware as Middleware };
23
22
  export type HTTPMethod = keyof typeof HTTPMethods;
24
23
  export type ParameterizedContext<ParamsT, StateT, ContextT, PayloadT = unknown, ResponseT = unknown> = RouterContext<DefaultState & StateT, DefaultContext & ContextT & {
25
24
  typedParams: ParamsT;
26
25
  payload: PayloadT;
27
26
  }, ResponseT>;
28
- type RouteMiddleware<ParamsT, StateT, ContextT> = (ctx: ParameterizedContext<ParamsT, StateT, ContextT>, next: Next) => Promise<void> | void;
27
+ export type ParameterizedMiddleware<ParamsT = {}, StateT = {}, ContextT = {}> = (ctx: ParameterizedContext<ParamsT, StateT, ContextT>, next: Next) => Promise<void> | void;
29
28
  export type RouteHandler<ParamsT, StateT, ContextT, PayloadT = unknown, ResponseT = unknown> = (ctx: ParameterizedContext<ParamsT, StateT, ContextT, PayloadT, ResponseT>, next: Next) => Promise<void> | void;
30
29
  export type MiddlewareDefinition = {
31
30
  kind: "middleware";
32
- middleware: Array<RouterMiddleware>;
31
+ middleware: Array<ParameterizedMiddleware>;
33
32
  options?: UseOptions | undefined;
34
33
  };
35
34
  export type HandlerDefinition = {
36
35
  kind: "handler";
37
- middleware: Array<RouterMiddleware>;
36
+ middleware: Array<ParameterizedMiddleware>;
38
37
  method: HTTPMethod;
39
38
  };
40
39
  export type RouteDefinitionItem = MiddlewareDefinition | HandlerDefinition;
41
40
  export type DefineRouteHelpers<ParamsT, StateT, ContextT, OptionalHandlers = undefined> = {
42
- use: (middleware: RouteMiddleware<ParamsT, StateT, ContextT> | Array<RouteMiddleware<ParamsT, StateT, ContextT>>, options?: UseOptions) => RouteDefinitionItem;
41
+ use: (middleware: ParameterizedMiddleware<ParamsT, StateT, ContextT> | Array<ParameterizedMiddleware<ParamsT, StateT, ContextT>>, options?: UseOptions) => RouteDefinitionItem;
43
42
  } & {
44
43
  [M in HTTPMethod]: M extends OptionalHandlers ? <PayloadT = unknown, ResponseT = unknown>(handler?: RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT> | Array<RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT>>) => RouteDefinitionItem : <PayloadT = unknown, ResponseT = unknown>(handler: RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT> | Array<RouteHandler<ParamsT, StateT, ContextT, PayloadT, ResponseT>>) => RouteDefinitionItem;
45
44
  };
46
45
  export type DefineRoute = <ParamsT = Record<string, string>, StateT = object, ContextT = object>(factory: (helpers: DefineRouteHelpers<ParamsT, StateT, ContextT>) => Array<RouteDefinitionItem>) => Array<RouteDefinitionItem>;
47
46
  export interface UseSlots {
47
+ errorHandler: string;
48
48
  params: string;
49
49
  validateParams: string;
50
50
  bodyparser: string;
@@ -57,12 +57,12 @@ export type UseOptions = {
57
57
  slot?: keyof UseSlots;
58
58
  debug?: string | undefined;
59
59
  };
60
- export type Use = <StateT = DefaultState, ContextT = DefaultContext>(middleware: RouteMiddleware<Record<string, string>, StateT, ContextT> | Array<RouteMiddleware<Record<string, string>, StateT, ContextT>>, options?: UseOptions) => MiddlewareDefinition;
60
+ export type Use = <StateT = DefaultState, ContextT = DefaultContext>(middleware: ParameterizedMiddleware<Record<string, string>, StateT, ContextT> | Array<ParameterizedMiddleware<Record<string, string>, StateT, ContextT>>, options?: UseOptions) => MiddlewareDefinition;
61
61
  export type RouterRouteSource = {
62
62
  name: string;
63
63
  path: string;
64
64
  file: string;
65
- useWrappers: Array<MiddlewareDefinition>;
65
+ useWrappers: [...a: Array<MiddlewareDefinition>];
66
66
  definitionItems: Array<RouteDefinitionItem>;
67
67
  params: Array<[name: string, isRest?: boolean]>;
68
68
  numericParams: Array<string>;
@@ -75,18 +75,19 @@ export type RouterRoute = {
75
75
  file: string;
76
76
  methods: Array<string>;
77
77
  middleware: Array<RouterMiddleware>;
78
- kind: "middleware" | "handler";
79
- slot?: keyof UseSlots | undefined;
80
- debug?: string | undefined;
78
+ debug: {
79
+ headline: string;
80
+ methods: string;
81
+ middleware: string;
82
+ handler: string;
83
+ full: string;
84
+ };
81
85
  };
82
86
  import type Koa from "koa";
83
87
  export type App = Koa<DefaultState, DefaultContext>;
84
88
  export type AppOptions = ConstructorParameters<typeof import("koa")>[0];
85
- export type CreateApp = (options?: AppOptions) => App;
86
- import type KoaRouter from "@koa/router";
87
- export type Router = KoaRouter<DefaultState, DefaultContext>;
88
- export type { RouterOptions };
89
- export type CreateRouter = (options?: RouterOptions) => Router;
89
+ export type Router = import("@koa/router").Router<DefaultState, DefaultContext>;
90
+ export type RouterOptions = import("@koa/router").RouterOptions;
90
91
  export type DevMiddlewareFactory = (app: App) => (req: import("node:http").IncomingMessage, res: import("node:http").ServerResponse, next: () => Promise<void>) => Promise<void>;
91
92
  export type TeardownHandler = (app: App) => void | Promise<void>;
92
93
  export type ValidationSchema = {
@@ -1,5 +1,7 @@
1
+ import Koa, { type Context, type Next } from "koa";
1
2
  import { type MiddlewareDefinition, type RouterRouteSource } from "../src/types";
2
3
  export declare const defaultMethods: string[];
3
4
  export declare const middlewareStackBuilder: (a: Array<Partial<RouterRouteSource>>, b: {
4
5
  coreMiddleware?: Array<MiddlewareDefinition>;
5
6
  }) => import("../src/types").RouterRoute[];
7
+ export declare const runMiddleware: <T = any>(middleware: Array<(ctx: T, next: Next) => void | Promise<void>>, ctxOverrides?: Partial<Context>) => Promise<Koa.ParameterizedContext<Koa.DefaultState, Koa.DefaultContext, unknown>>;
package/pkg/debug.js DELETED
@@ -1,62 +0,0 @@
1
- // src/debug.ts
2
- import { styleText } from "node:util";
3
- import picomatch from "picomatch";
4
- import stringWidth from "string-width";
5
- var dot = "\xB7";
6
- var colorizeMethod = (method) => {
7
- const color = {
8
- HEAD: "grey",
9
- GET: "green",
10
- POST: "blue",
11
- PATCH: "blue",
12
- PUT: "blue",
13
- DELETE: "red"
14
- }[method];
15
- return color ? styleText(color, method) : method;
16
- };
17
- var debug_default = (routes, printer, patterns) => {
18
- const patternMatchers = patterns?.flatMap((pattern) => {
19
- return pattern?.trim?.() ? [picomatch(pattern)] : [];
20
- });
21
- for (const { path, file, methods, slot, debug, kind } of routes.filter(
22
- ({ name, path: path2 }) => {
23
- return patternMatchers?.length ? patternMatchers.some((isMatch) => isMatch(name) || isMatch(path2)) : true;
24
- }
25
- )) {
26
- const lines = [];
27
- lines.push(
28
- `[ ${styleText("bgBlue", styleText("black", ` ${path} `))} ] ${styleText("gray", file)}`
29
- );
30
- const methodsLine = methods.map((method) => {
31
- const coloredMethod = colorizeMethod(method);
32
- if (method === "GET" && kind === "handler") {
33
- return coloredMethod + styleText("gray", "|HEAD");
34
- }
35
- return coloredMethod;
36
- }).join(" ");
37
- lines.push(`${styleText("dim", " methods:")} ${methodsLine}`);
38
- if (slot) {
39
- lines.push(
40
- `${styleText("dim", " slot: ")} ${styleText("cyan", slot)}`
41
- );
42
- }
43
- if (debug) {
44
- lines.push(` ${styleText("cyan", debug)}`);
45
- }
46
- const maxColumns = process.stdout.isTTY ? Number(process.stdout.columns || 80) : 80;
47
- for (const line of lines.map((e) => `${e} `)) {
48
- const freeColumns = maxColumns - stringWidth(line);
49
- printer(
50
- freeColumns > 0 ? line + styleText(
51
- "dim",
52
- styleText("gray", Array(freeColumns).fill(dot).join(""))
53
- ) : line
54
- );
55
- }
56
- printer("\n");
57
- }
58
- };
59
- export {
60
- debug_default as default
61
- };
62
- //# sourceMappingURL=debug.js.map
package/pkg/debug.js.map DELETED
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/debug.ts"],
4
- "sourcesContent": ["import { styleText } from \"node:util\";\n\nimport picomatch from \"picomatch\";\nimport stringWidth from \"string-width\";\n\nimport type { RouterRoute } from \"./types\";\n\ntype Printer = (line: string) => void;\n\nconst dot = \"\u00B7\";\n\nconst colorizeMethod = (method: string): string => {\n const color = (\n {\n HEAD: \"grey\",\n GET: \"green\",\n POST: \"blue\",\n PATCH: \"blue\",\n PUT: \"blue\",\n DELETE: \"red\",\n } as const\n )[method];\n return color ? styleText(color, method) : method;\n};\n\nexport default (\n routes: Array<RouterRoute>,\n printer: Printer,\n patterns?: Array<string> | undefined, // picomatch patterns\n) => {\n const patternMatchers = patterns?.flatMap((pattern) => {\n return pattern?.trim?.() ? [picomatch(pattern)] : [];\n });\n\n for (const { path, file, methods, slot, debug, kind } of routes.filter(\n ({ name, path }) => {\n return patternMatchers?.length\n ? patternMatchers.some((isMatch) => isMatch(name) || isMatch(path))\n : true;\n },\n )) {\n const lines: Array<string> = [];\n\n lines.push(\n `[ ${styleText(\"bgBlue\", styleText(\"black\", ` ${path} `))} ] ${styleText(\"gray\", file)}`,\n );\n\n const methodsLine = methods\n .map((method) => {\n const coloredMethod = colorizeMethod(method);\n if (method === \"GET\" && kind === \"handler\") {\n return coloredMethod + styleText(\"gray\", \"|HEAD\");\n }\n return coloredMethod;\n })\n .join(\" \");\n\n lines.push(`${styleText(\"dim\", \" methods:\")} ${methodsLine}`);\n\n if (slot) {\n lines.push(\n `${styleText(\"dim\", \" slot: \")} ${styleText(\"cyan\", slot)}`,\n );\n }\n\n if (debug) {\n lines.push(` ${styleText(\"cyan\", debug)}`);\n }\n\n const maxColumns = process.stdout.isTTY\n ? Number(process.stdout.columns || 80)\n : 80;\n\n for (const line of lines.map((e) => `${e} `)) {\n const freeColumns = maxColumns - stringWidth(line);\n printer(\n freeColumns > 0 //\n ? line +\n styleText(\n \"dim\",\n styleText(\"gray\", Array(freeColumns).fill(dot).join(\"\")),\n )\n : line,\n );\n }\n\n printer(\"\\n\");\n }\n};\n"],
5
- "mappings": ";AAAA,SAAS,iBAAiB;AAE1B,OAAO,eAAe;AACtB,OAAO,iBAAiB;AAMxB,IAAM,MAAM;AAEZ,IAAM,iBAAiB,CAAC,WAA2B;AACjD,QAAM,QACJ;AAAA,IACE,MAAM;AAAA,IACN,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,IACL,QAAQ;AAAA,EACV,EACA,MAAM;AACR,SAAO,QAAQ,UAAU,OAAO,MAAM,IAAI;AAC5C;AAEA,IAAO,gBAAQ,CACb,QACA,SACA,aACG;AACH,QAAM,kBAAkB,UAAU,QAAQ,CAAC,YAAY;AACrD,WAAO,SAAS,OAAO,IAAI,CAAC,UAAU,OAAO,CAAC,IAAI,CAAC;AAAA,EACrD,CAAC;AAED,aAAW,EAAE,MAAM,MAAM,SAAS,MAAM,OAAO,KAAK,KAAK,OAAO;AAAA,IAC9D,CAAC,EAAE,MAAM,MAAAA,MAAK,MAAM;AAClB,aAAO,iBAAiB,SACpB,gBAAgB,KAAK,CAAC,YAAY,QAAQ,IAAI,KAAK,QAAQA,KAAI,CAAC,IAChE;AAAA,IACN;AAAA,EACF,GAAG;AACD,UAAM,QAAuB,CAAC;AAE9B,UAAM;AAAA,MACJ,KAAK,UAAU,UAAU,UAAU,SAAS,IAAI,IAAI,GAAG,CAAC,CAAC,MAAM,UAAU,QAAQ,IAAI,CAAC;AAAA,IACxF;AAEA,UAAM,cAAc,QACjB,IAAI,CAAC,WAAW;AACf,YAAM,gBAAgB,eAAe,MAAM;AAC3C,UAAI,WAAW,SAAS,SAAS,WAAW;AAC1C,eAAO,gBAAgB,UAAU,QAAQ,OAAO;AAAA,MAClD;AACA,aAAO;AAAA,IACT,CAAC,EACA,KAAK,GAAG;AAEX,UAAM,KAAK,GAAG,UAAU,OAAO,YAAY,CAAC,IAAI,WAAW,EAAE;AAE7D,QAAI,MAAM;AACR,YAAM;AAAA,QACJ,GAAG,UAAU,OAAO,YAAY,CAAC,IAAI,UAAU,QAAQ,IAAI,CAAC;AAAA,MAC9D;AAAA,IACF;AAEA,QAAI,OAAO;AACT,YAAM,KAAK,KAAK,UAAU,QAAQ,KAAK,CAAC,EAAE;AAAA,IAC5C;AAEA,UAAM,aAAa,QAAQ,OAAO,QAC9B,OAAO,QAAQ,OAAO,WAAW,EAAE,IACnC;AAEJ,eAAW,QAAQ,MAAM,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,GAAG;AAC5C,YAAM,cAAc,aAAa,YAAY,IAAI;AACjD;AAAA,QACE,cAAc,IACV,OACE;AAAA,UACE;AAAA,UACA,UAAU,QAAQ,MAAM,WAAW,EAAE,KAAK,GAAG,EAAE,KAAK,EAAE,CAAC;AAAA,QACzD,IACF;AAAA,MACN;AAAA,IACF;AAEA,YAAQ,IAAI;AAAA,EACd;AACF;",
6
- "names": ["path"]
7
- }
@@ -1 +0,0 @@
1
- export {};