miolo 3.0.0-beta.13 → 3.0.0-beta.131

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.
Files changed (52) hide show
  1. package/bin/{dev.mjs → dev/dev.mjs} +19 -5
  2. package/bin/{dev_start.mjs → dev/dev_start.mjs} +3 -2
  3. package/bin/index.mjs +47 -33
  4. package/bin/prod-bin/create-bin.mjs +33 -0
  5. package/bin/prod-bin/run.mjs +35 -0
  6. package/bin/{build-client.mjs → prod-build/build-client.mjs} +17 -5
  7. package/bin/{build-server.mjs → prod-build/build-server.mjs} +12 -10
  8. package/bin/prod-run/pid.mjs +13 -0
  9. package/bin/{restart.mjs → prod-run/restart.mjs} +3 -4
  10. package/bin/prod-run/start.mjs +14 -0
  11. package/bin/{stop.mjs → prod-run/stop.mjs} +4 -3
  12. package/bin/util.mjs +2 -29
  13. package/package.json +25 -26
  14. package/{bin → src/config}/.env +17 -6
  15. package/src/config/defaults.mjs +443 -422
  16. package/src/config/env.mjs +52 -0
  17. package/src/config/index.mjs +17 -10
  18. package/src/config/util.mjs +41 -0
  19. package/src/engines/emailer/queue.mjs +3 -2
  20. package/src/engines/emailer/transporter.mjs +10 -9
  21. package/src/engines/http/index.mjs +1 -1
  22. package/src/engines/parser/Parser.mjs +25 -7
  23. package/src/engines/schema/index.mjs +40 -0
  24. package/src/index.mjs +3 -1
  25. package/src/middleware/auth/basic.mjs +5 -2
  26. package/src/middleware/auth/credentials/index.mjs +75 -43
  27. package/src/middleware/auth/credentials/session/index.mjs +7 -0
  28. package/src/middleware/auth/credentials/session/store.mjs +9 -0
  29. package/src/middleware/context/index.mjs +1 -1
  30. package/src/middleware/http/catcher.mjs +78 -2
  31. package/src/middleware/http/catcher.old.mjs +82 -0
  32. package/src/middleware/http/custom_blacklist.mjs +3 -1
  33. package/src/middleware/routes/catch_js_error.mjs +14 -2
  34. package/src/middleware/routes/router/crud/attachCrudRoutes.mjs +24 -12
  35. package/src/middleware/routes/router/crud/getCrudConfig.mjs +4 -6
  36. package/src/middleware/routes/router/defaults.mjs +1 -11
  37. package/src/middleware/routes/router/index.mjs +0 -1
  38. package/src/middleware/routes/router/queries/attachQueriesRoutes.mjs +70 -13
  39. package/src/middleware/routes/router/queries/getQueriesConfig.mjs +21 -21
  40. package/src/middleware/routes/router/utils.mjs +43 -25
  41. package/src/middleware/ssr/context.mjs +1 -1
  42. package/src/middleware/ssr/fallbackIndex.mjs +2 -8
  43. package/src/middleware/ssr/html.mjs +39 -31
  44. package/src/middleware/vite/devserver.mjs +22 -8
  45. package/src/server-cron.mjs +3 -4
  46. package/src/server-dev.mjs +3 -3
  47. package/src/server.mjs +3 -5
  48. package/bin/create-bin.mjs +0 -38
  49. package/bin/env.mjs +0 -39
  50. package/bin/prod_start.mjs +0 -9
  51. package/bin/start.mjs +0 -17
  52. package/src/engines/logger/verify.mjs +0 -22
@@ -3,17 +3,92 @@
3
3
  * @param ctx
4
4
  */
5
5
 
6
- import http from 'http'
6
+ // import http from 'http'
7
+ import statuses from 'statuses'
8
+ import util from 'node:util'
9
+
7
10
  const _ONLY_WARN= [401, 403]
8
11
 
9
12
  function init_catcher_middleware(app) {
10
13
  const logger= app.context.miolo.logger
11
14
 
12
15
  async function catcher_middleware(err) {
16
+ // don't do anything if there is no error.
17
+ // this allows you to pass `this.onerror`
18
+ // to node-style callbacks.
19
+ if (err == null) return
20
+
21
+ // Ignore this error
22
+ // Appearing since Koa 3.1 + koa-static 6.x + koa-send 7.x
23
+ if (err.code === 'ERR_STREAM_PREMATURE_CLOSE') return
24
+
25
+
26
+ // When dealing with cross-globals a normal `instanceof` check doesn't work properly.
27
+ // See https://github.com/koajs/koa/issues/1466
28
+ // We can probably remove it once jest fixes https://github.com/facebook/jest/issues/2549.
29
+ const isNativeError =
30
+ Object.prototype.toString.call(err) === '[object Error]' ||
31
+ err instanceof Error
32
+ if (!isNativeError) err = new Error(util.format('non-error thrown: %j', err))
33
+
34
+ let headerSent = false
35
+ if (this.headerSent || !this.writable) {
36
+ headerSent = err.headerSent = true
37
+ }
38
+
39
+ // delegate
40
+ this.app.emit('error', err, this)
41
+
42
+
43
+ let statusCode = err.status || err.statusCode
44
+ // default to 500
45
+ if (typeof statusCode !== 'number' || !statuses.message[statusCode]) statusCode = 500
46
+
47
+ // Log the error depending on the status
48
+ const ip = this.headers["x-real-ip"] || this.headers["x-orig-ip"] || this.ip || '127.0.0.1'
49
+ if ((_ONLY_WARN.indexOf(statusCode)>=0) || (err.message.indexOf('Premature close')>=0)) {
50
+ logger.warn(`[${ip}] ${this.method} ${this.url} - ${statusCode}: ${err.message}`)
51
+ } else {
52
+ logger.error(`[${ip}] ${this.method} ${this.url} - ${statusCode}: ${err.message}`)
53
+ }
54
+
55
+ // nothing we can do here other
56
+ // than delegate to the app-level
57
+ // handler and log.
58
+ if (headerSent) {
59
+ return
60
+ }
61
+
62
+ const { res } = this
63
+
64
+ // first unset all headers
65
+ /* istanbul ignore else */
66
+ if (typeof res.getHeaderNames === 'function') {
67
+ res.getHeaderNames().forEach(name => res.removeHeader(name))
68
+ } else {
69
+ res._headers = {} // Node < 7.7
70
+ }
71
+
72
+ // then set those specified
73
+ this.set(err.headers)
74
+
75
+ // force text/plain
76
+ this.type = 'text'
77
+
78
+
79
+ // respond
80
+ const code = statuses.message[statusCode]
81
+ const msg = err.expose ? err.message : code
82
+ this.status = err.status = statusCode
83
+ this.length = Buffer.byteLength(msg)
84
+ res.end(msg)
85
+
86
+ /*
13
87
  if (!err) return
14
88
 
15
89
  // wrap non-error object
16
- if (!(err instanceof Error)) {
90
+ const isNativeError = (Object.prototype.toString.call(err) === '[object Error]') || (err instanceof Error)
91
+ if (!isNativeError) {
17
92
  let errMsg = err;
18
93
  if (typeof err === 'object') {
19
94
  try {
@@ -73,6 +148,7 @@ function init_catcher_middleware(app) {
73
148
  this.body = JSON.stringify(this.body || '', null, 2)
74
149
  this.length = Buffer.byteLength(this.body)
75
150
  this.res.end(this.body)
151
+ */
76
152
  }
77
153
 
78
154
  app.context.onerror = catcher_middleware
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Middleware for catching errors thrown in routes
3
+ * @param ctx
4
+ */
5
+
6
+ import http from 'http'
7
+ const _ONLY_WARN= [401, 403]
8
+
9
+ function init_catcher_middleware(app) {
10
+ const logger= app.context.miolo.logger
11
+
12
+ async function catcher_middleware(err) {
13
+ if (!err) return
14
+
15
+ // wrap non-error object
16
+ const isNativeError = (Object.prototype.toString.call(err) === '[object Error]') || (err instanceof Error)
17
+ if (!isNativeError) {
18
+ let errMsg = err;
19
+ if (typeof err === 'object') {
20
+ try {
21
+ errMsg = JSON.stringify(err);
22
+ // eslint-disable-next-line no-empty
23
+ } catch (e) {}
24
+ }
25
+ const newError = new Error('non-error thrown: ' + errMsg);
26
+ // err maybe an object, try to copy the name, message and stack to the new error instance
27
+ if (err) {
28
+ if (err.name) newError.name = err.name;
29
+ if (err.message) newError.message = err.message;
30
+ if (err.stack) newError.stack = err.stack;
31
+ if (err.status) newError.status = err.status;
32
+ if (err.headers) newError.headers = err.headers;
33
+ }
34
+ err = newError;
35
+ }
36
+
37
+ const headerSent = this.headerSent || !this.writable;
38
+ if (headerSent) err.headerSent = true;
39
+
40
+ // delegate
41
+ this.app.emit('error', err, this);
42
+
43
+ // ENOENT support
44
+ if (err.code === 'ENOENT') err.status = 404;
45
+
46
+ // Get HTML status code
47
+ let status = err.status || 400
48
+ const type = this.accepts(['text', 'json', 'html'])
49
+ if (!type) {
50
+ status = 406
51
+ err.message = 'Unsupported type'
52
+ } else if (typeof err.status !== 'number' || !http.STATUS_CODES[err.status]) {
53
+ err.status = 500
54
+ }
55
+ this.status = status
56
+
57
+
58
+ // Log the error depending on the status
59
+ const ip = this.headers["x-real-ip"] || this.headers["x-orig-ip"] || this.ip || '127.0.0.1'
60
+ if (_ONLY_WARN.indexOf(status)>=0) {
61
+ logger.warn(`[${ip}] ${this.method} ${this.url} - ${status}: ${err.message}`)
62
+ } else {
63
+ logger.error(err)
64
+ }
65
+
66
+ // Nothing we can do here other than delegate to the app-level handler and log.
67
+ if (err.headerSent ) {
68
+ logger.warn('headers were already sent, returning early')
69
+ return
70
+ }
71
+
72
+ // Prepare response a bit
73
+ this.type = 'json'
74
+ this.body = JSON.stringify(this.body || '', null, 2)
75
+ this.length = Buffer.byteLength(this.body)
76
+ this.res.end(this.body)
77
+ }
78
+
79
+ app.context.onerror = catcher_middleware
80
+ }
81
+
82
+ export {init_catcher_middleware}
@@ -13,5 +13,7 @@ export const CUSTOM_BLACKLIST_IPS= [
13
13
  '198.12.222.107', // GoDaddy.com, LLC (GODAD)
14
14
  '212.128.118.10', // RIPE Network Coordination Centre (RIPE)
15
15
  '103.218.240.46', // Asia Pacific Network Information Centre (APNIC)
16
- '45.15.167.150' // ??
16
+ '45.15.167.150', // ??
17
+ '165.227.173.41', // Frankfurt am Main, DE
18
+ '147.135.220.53', //
17
19
  ]
@@ -1,12 +1,24 @@
1
1
  import { blue, red, yellow } from 'tinguir'
2
2
  import Router from '@koa/router'
3
3
 
4
+ const ERRORS_AS_WARNINGS = [
5
+ 'Minified React error'
6
+ ]
7
+
4
8
  function init_route_catch_js_error(app, route) {
5
9
 
6
10
  async function catch_js_error(ctx) {
7
- const { error, warning, path, agent } = ctx.request.body
11
+ let { error, warning, path, agent } = ctx.request.body
8
12
  const logger = ctx.miolo.logger
9
13
 
14
+ if (error) {
15
+ ERRORS_AS_WARNINGS.map(e => {
16
+ if (error.msg.indexOf(e) >= 0) {
17
+ warning = error
18
+ }
19
+ })
20
+ }
21
+
10
22
  if (warning) {
11
23
  const msg=
12
24
  `${yellow('[JS Warning]')} on ${blue(path)}: ${JSON.stringify(warning.msg)}\n` +
@@ -28,7 +40,7 @@ function init_route_catch_js_error(app, route) {
28
40
  logger.error(msg)
29
41
  }
30
42
 
31
- ctx.body = {result: 1}
43
+ ctx.body = {ok: true, data: 1}
32
44
  }
33
45
 
34
46
  const catch_js_error_router = new Router()
@@ -11,9 +11,10 @@ function attachCrudRoutes(router, crudConfigs, logger) {
11
11
 
12
12
  const _pack_body_field = (data) => {
13
13
  if (route.bodyField == undefined) {
14
- return data
14
+ return {data}
15
15
  }
16
16
  return {
17
+ bodyField: route.bodyField,
17
18
  [route.bodyField]: data
18
19
  }
19
20
  }
@@ -32,15 +33,22 @@ function attachCrudRoutes(router, crudConfigs, logger) {
32
33
  ctx.miolo.logger.error(`[router] Unauthorized access. Throwing error ${auth.error_code}`)
33
34
  ctx.throw(
34
35
  auth.error_code,
35
- 'Unauthorized',
36
+ new Error('Unauthorized'),
36
37
  {}
37
38
  )
38
39
  } else if (auth.action=='redirect') {
39
40
  ctx.miolo.logger.warn(`[router] Unauthorized access. Redirecting to ${auth.redirect_url}`)
41
+ ctx.body= {
42
+ ok: false,
43
+ error: 'Unathorized'
44
+ }
40
45
  ctx.redirect(auth.redirect_url)
41
46
  } else {
42
47
  ctx.miolo.logger.error(`[router] Crud path ${route.url} specified auth but no action`)
43
- ctx.body= {}
48
+ ctx.body= {
49
+ ok: false,
50
+ error: 'Unathorized'
51
+ }
44
52
  }
45
53
  }
46
54
  return authenticated
@@ -57,12 +65,15 @@ function attachCrudRoutes(router, crudConfigs, logger) {
57
65
  throw new Error(`[router] Could not get model for ${route.name}`)
58
66
  }
59
67
 
60
- let result = {}
68
+ let data = {}
61
69
  try {
62
70
  const authenticated = await _crud_auth_callback(ctx, op)
63
71
 
64
72
  if (! authenticated) {
65
- ctx.body= {}
73
+ ctx.body= {
74
+ ok: false,
75
+ error: 'Unathorized'
76
+ }
66
77
  return
67
78
  }
68
79
 
@@ -72,7 +83,10 @@ function attachCrudRoutes(router, crudConfigs, logger) {
72
83
  }
73
84
 
74
85
  if (! goon) {
75
- ctx.body= {}
86
+ ctx.body= {
87
+ ok: false,
88
+ error: 'Not allowd'
89
+ }
76
90
  return
77
91
  }
78
92
 
@@ -87,19 +101,17 @@ function attachCrudRoutes(router, crudConfigs, logger) {
87
101
  fieldNames,
88
102
  }
89
103
 
90
- result= await callback(model, uinfo)
104
+ data= await callback(model, uinfo)
91
105
 
92
106
  if (route?.after) {
93
- result= await route.after(ctx, result)
107
+ data= await route.after(ctx, data)
94
108
  }
95
109
  } catch(error) {
96
110
  ctx.miolo.logger.error(`[router] Unexpected error on CRUD ${route.name}-${op}`)
97
111
  ctx.miolo.logger.error(error)
98
112
  }
99
-
100
- result= _pack_body_field(result)
101
-
102
- ctx.body= result
113
+
114
+ ctx.body= {ok: true, ..._pack_body_field(data)}
103
115
  }
104
116
 
105
117
  const route_read = async (ctx) => {
@@ -3,8 +3,6 @@ import merge from 'deepmerge'
3
3
  import {
4
4
  DEFAULT_AUTH_USER,
5
5
  DEFAULT_USE_USER_FIELDS,
6
- DEFAULT_BEFORE_CALLBACK,
7
- DEFAULT_AFTER_CALLBACK
8
6
  } from "../defaults.mjs"
9
7
 
10
8
  /**
@@ -14,7 +12,7 @@ import {
14
12
  auth,
15
13
  bodyField,
16
14
  before: (ctx) => {return goon/!goon},
17
- after : (ctx, result) => {return result},
15
+ after : (ctx, data) => {return data},
18
16
 
19
17
  routes: an array of tables config, where each config can be:
20
18
  - a simple string with the table name
@@ -36,7 +34,7 @@ import {
36
34
  auth,
37
35
  bodyField,
38
36
  before: (ctx) => {return goon/!goon},
39
- after : (ctx, result) => {return result},
37
+ after : (ctx, data) => {return data},
40
38
 
41
39
  }
42
40
  }]
@@ -69,8 +67,8 @@ const getCrudConfig = (config) => {
69
67
  }
70
68
 
71
69
  const comm_bodyField = crud?.bodyField || config?.bodyField
72
- const comm_before = crud?.before || config?.before || DEFAULT_BEFORE_CALLBACK
73
- const comm_after = crud?.after || config?.after || DEFAULT_AFTER_CALLBACK
70
+ const comm_before = crud?.before || config?.before
71
+ const comm_after = crud?.after || config?.after
74
72
 
75
73
 
76
74
  const comm_auth= merge.all([
@@ -1,11 +1,3 @@
1
- const DEFAULT_BEFORE_CALLBACK = async (ctx) => {
2
- return true
3
- }
4
-
5
- const DEFAULT_AFTER_CALLBACK = async (ctx, result) => {
6
- return result
7
- }
8
-
9
1
  const DEFAULT_AUTH_USER = {
10
2
  require: false, // true / false / 'read-only'
11
3
  action: 'redirect', // 'error'
@@ -23,7 +15,5 @@ const DEFAULT_USE_USER_FIELDS = {
23
15
 
24
16
  export {
25
17
  DEFAULT_AUTH_USER,
26
- DEFAULT_USE_USER_FIELDS,
27
- DEFAULT_BEFORE_CALLBACK,
28
- DEFAULT_AFTER_CALLBACK
18
+ DEFAULT_USE_USER_FIELDS
29
19
  }
@@ -4,7 +4,6 @@ import attachCrudRoutes from './crud/attachCrudRoutes.mjs'
4
4
  import getQueriesConfig from './queries/getQueriesConfig.mjs'
5
5
  import attachQueriesRoutes from './queries/attachQueriesRoutes.mjs'
6
6
 
7
-
8
7
  function init_router(app, routes) {
9
8
  const logger = app.context.miolo.logger
10
9
 
@@ -1,4 +1,7 @@
1
- import {query_string_to_json} from '../utils.mjs'
1
+ import Joi from 'joi'
2
+ import {
3
+ query_string_to_json,
4
+ ensure_response_is_ok_data} from '../utils.mjs'
2
5
 
3
6
  function attachQueriesRoutes(router, queriesConfigs, logger) {
4
7
 
@@ -21,7 +24,6 @@ function attachQueriesRoutes(router, queriesConfigs, logger) {
21
24
  logger.debug(`[router] Routing ${route.callback?.name || 'callback'} to ${route.method} ${url}${checkAuth ? ' (auth)' : ''}`)
22
25
 
23
26
  const _route_auth_callback = async (ctx) => {
24
-
25
27
  if (checkAuth) {
26
28
  const authenticated= ctx?.session?.authenticated === true
27
29
  if (!authenticated) {
@@ -29,7 +31,7 @@ function attachQueriesRoutes(router, queriesConfigs, logger) {
29
31
  ctx.miolo.logger.error(`Unauthorized access. Throwing error ${routeAuth.error_code}`)
30
32
  ctx.throw(
31
33
  routeAuth.error_code,
32
- 'Unauthorized',
34
+ new Error('Unauthorized'),
33
35
  {}
34
36
  )
35
37
  } else if (routeAuth.action=='redirect') {
@@ -37,7 +39,6 @@ function attachQueriesRoutes(router, queriesConfigs, logger) {
37
39
  ctx.redirect(routeAuth.redirect_url)
38
40
  } else {
39
41
  ctx.miolo.logger.error(`Route path ${route.url} specified auth but no action`)
40
- ctx.body= {}
41
42
  }
42
43
  }
43
44
 
@@ -48,7 +49,6 @@ function attachQueriesRoutes(router, queriesConfigs, logger) {
48
49
  }
49
50
 
50
51
  const _route_callback = async (ctx) => {
51
- let result = {}
52
52
  try {
53
53
  try {
54
54
  if ((route.method == 'GET') && (!ctx.request?.body)) {
@@ -59,35 +59,92 @@ function attachQueriesRoutes(router, queriesConfigs, logger) {
59
59
  }
60
60
  }
61
61
  }
62
- } catch(e) {
63
- ctx.miolo.logger.error(`[router] Error while trying to qet query params for ${ctx.request.url}`)
62
+ } catch(error) {
63
+ ctx.miolo.logger.error(`[router] Error while trying to qet query params for ${ctx.request.url}: ${error?.message || '?'}`)
64
64
  }
65
65
 
66
66
  const authenticated = await _route_auth_callback(ctx)
67
67
  if (! authenticated) {
68
+ ctx.body= {
69
+ ok: false,
70
+ error: 'Not authorized'
71
+ }
68
72
  return
69
73
  }
70
74
 
71
75
  let goon= true
72
76
  if (route?.before) {
73
77
  goon= await route.before(ctx)
78
+
79
+ if (! goon) {
80
+ ctx.body= {
81
+ ok: false,
82
+ error: `Route was aborted by a <before> callback (${route.before?.name})`
83
+ }
84
+ return
85
+ }
74
86
  }
75
87
 
76
- if (! goon) {
77
- return
88
+ if (route?.schema) {
89
+ // Check schema is actually a schema
90
+ if (! Joi.isSchema(route.schema)) {
91
+ ctx.miolo.logger.error(`[router] Expecting schema at ${url} but something else was found (${typeof route.schema})`)
92
+ ctx.body = {
93
+ ok: false,
94
+ error: 'Invalid schema'
95
+ }
96
+ return
97
+ }
98
+
99
+ try {
100
+ const v = route.schema.validate(ctx.request.body)
101
+
102
+ if (v?.error) {
103
+ ctx.miolo.logger.warn(`[router] Schema invalidated data for ${url}: ${v.error}\n${v.error.annotate(true)}`)
104
+ ctx.body = {
105
+ ok: false,
106
+ error: v.error.toString()
107
+ }
108
+ return
109
+ } else if (v?.value) {
110
+ ctx.miolo.logger.silly(`[router] Schema validated data for ${url} successfully`)
111
+ ctx.request.body = v.value
112
+ } else {
113
+ ctx.miolo.logger.warn(`[router] Schema returned unknown result for ${url}: ${JSON.stringify(v)}. Let's ignore it.`)
114
+ }
115
+
116
+ } catch(error) {
117
+ ctx.miolo.logger.error(`[router] Error validating schema at ${url}: ${error?.message || error}`)
118
+ ctx.body = {
119
+ ok: false,
120
+ error: error?.message || error
121
+ }
122
+ return
123
+ }
78
124
  }
79
125
 
80
- result= await route.callback(ctx)
126
+ const result = await route.callback(ctx, ctx.request.body)
127
+
128
+ if (! route.keep_body) {
129
+ if (ctx.body!==undefined) {
130
+ ctx.body = ensure_response_is_ok_data(ctx, ctx.body)
131
+ } else {
132
+ ctx.body = ensure_response_is_ok_data(ctx, result)
133
+ }
134
+ }
81
135
 
82
136
  if (route?.after) {
83
- result= await route.after(ctx, result)
137
+ const result = await route.after(ctx, ctx.body)
138
+ ctx.body = ensure_response_is_ok_data(ctx, result)
84
139
  }
85
140
  } catch(error) {
86
141
  ctx.miolo.logger.error(`[router] Unexpected error on Query ${route.callback?.name} at ${url}`)
87
142
  ctx.miolo.logger.error(error)
143
+ ctx.body = {
144
+ ok: false,
145
+ error: error?.message || error
146
+ }
88
147
  }
89
-
90
- return result
91
148
  }
92
149
 
93
150
  const router_method = route.method.toLowerCase()
@@ -1,11 +1,7 @@
1
1
  import merge from 'deepmerge'
2
-
3
2
  import {
4
- DEFAULT_AUTH_USER,
5
- DEFAULT_BEFORE_CALLBACK,
6
- DEFAULT_AFTER_CALLBACK
3
+ DEFAULT_AUTH_USER
7
4
  } from "../defaults.mjs"
8
- import { make_endpoint_from_fn } from '../utils.mjs'
9
5
 
10
6
  /**
11
7
  {
@@ -13,7 +9,7 @@ import { make_endpoint_from_fn } from '../utils.mjs'
13
9
 
14
10
  auth,
15
11
  before: (ctx) => {return goon/!goon},
16
- after : (ctx, result) => {return result},
12
+ after : (ctx, data) => {return data},
17
13
 
18
14
 
19
15
  routes: [
@@ -21,13 +17,20 @@ import { make_endpoint_from_fn } from '../utils.mjs'
21
17
  {
22
18
  url: '/crud/todos/fake',
23
19
  method: 'GET', // 'POST'
24
- callback: async (ctx) => { ctx.body = result } ,
25
- // or
26
- callback_fn: async (miolo, params) => { return result } ,
27
-
20
+ callback: async (ctx, params) => {
21
+ return {ok: true/false, data|error}
22
+ // or:
23
+ // return <anything>
24
+ // and milo will wrap into {ok: true, data: <anything>}
25
+ // or by yourself:
26
+ // ctx.body = {ok: true/false, data|error}
27
+ // (you may want {keep_body: true})
28
+ } ,
28
29
  auth,
29
- before: (ctx) => {return goon/!goon},
30
- after : (ctx, result) => {return result},
30
+ before: async (ctx) => { return true/false },
31
+ after : async (ctx, data) => { return data },
32
+ schema: a Joi schema,
33
+ keep_body: false by default. If true, miolo wont wnsure ctx.body after callback.
31
34
  }
32
35
  ]
33
36
  }
@@ -61,8 +64,8 @@ const getQueriesConfig = (config) => {
61
64
  return
62
65
  }
63
66
 
64
- const comm_before = instance?.before || config?.before || DEFAULT_BEFORE_CALLBACK
65
- const comm_after = instance?.after || config?.after || DEFAULT_AFTER_CALLBACK
67
+ const comm_before = instance?.before || config?.before
68
+ const comm_after = instance?.after || config?.after
66
69
 
67
70
  const comm_auth= merge.all([
68
71
  DEFAULT_AUTH_USER,
@@ -77,12 +80,7 @@ const getQueriesConfig = (config) => {
77
80
  continue
78
81
  }
79
82
 
80
- let cb=undefined
81
- if ((! route.callback) && (! route.callback_fn)) {
82
- continue
83
- } else {
84
- cb = route.callback || make_endpoint_from_fn(route.callback_fn)
85
- }
83
+ let cb=route?.callback
86
84
 
87
85
  const parsed_route= {
88
86
  url: route.url,
@@ -95,7 +93,9 @@ const getQueriesConfig = (config) => {
95
93
  ]),
96
94
 
97
95
  before: route?.before || comm_before,
98
- after: route?.after || comm_after
96
+ after: route?.after || comm_after,
97
+ schema: route?.schema,
98
+ keep_body: route?.keep_body === true
99
99
  }
100
100
 
101
101
  parsed_routes.push(parsed_route)