waibu 2.13.0 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,70 @@
1
+ export const methodColor = {
2
+ GET: 'blue',
3
+ POST: 'green',
4
+ UPDATE: 'yellow',
5
+ PATCH: 'yellow',
6
+ DELETE: 'red'
7
+ }
8
+
9
+ async function hook () {
10
+ return [{
11
+ name: 'waibu:onClose',
12
+ handler: async function () {
13
+ this.log.info('serverIs%s', this.t('closedL'))
14
+ }
15
+ }, {
16
+ name: 'waibu:onReady',
17
+ handler: async function () {
18
+ this.log.info('serverIs%s', this.t('readyL'))
19
+ }
20
+ }, {
21
+ level: 5,
22
+ name: 'waibu:onRequest',
23
+ handler: async function onRequest (req, reply) {
24
+ const { importPkg } = this.app.bajo
25
+ const { get } = this.app.lib._
26
+ const chalk = await importPkg('bajo:chalk')
27
+ const { plain } = this.app.bajo.config.log
28
+
29
+ req.site = this.config.siteInfo
30
+ req.ns = get(reply.request, 'routeOptions.config.ns') ?? this.ns
31
+ const ns = get(reply.request, 'routeOptions.config.webApp') ?? this.ns
32
+ const arrow = plain ? '<' : chalk.bold('🡨')
33
+ const c = methodColor[req.method] ?? 'gray'
34
+ const method = plain ? req.method : chalk[c](req.method)
35
+ const url = plain ? (':' + req.url) : chalk.gray(':' + req.url)
36
+ const ip = plain ? this.getIp(req) : chalk.magenta(this.getIp(req))
37
+ let msg = this.app[ns].t('httpReq%s%s%s%s', arrow, method, url.replaceAll('%', '%%'), ip)
38
+ if (req.headers['content-length']) msg += this.app[ns].t('httpReqExt%s', req.headers['content-length'])
39
+ if (this.config.log.defer) {
40
+ this.reqLog = this.reqLog ?? {}
41
+ this.reqLog[req.id] = msg
42
+ } else if (!this.config.log.noReq) this.app[ns].log.info(msg)
43
+ if (Object.keys(this.config.paramsCharMap).length === 0) return
44
+ for (const key in req.params) {
45
+ let val = req.params[key]
46
+ if (typeof val !== 'string') continue
47
+ for (const char in this.config.paramsCharMap) {
48
+ val = val.replaceAll(char, this.config.paramsCharMap[char])
49
+ }
50
+ req.params[key] = val
51
+ }
52
+ }
53
+ }, {
54
+ level: 5,
55
+ name: 'waibu:onRoute',
56
+ handler: async function (opts) {
57
+ this.routes.push(opts)
58
+ }
59
+ }, {
60
+ level: 9,
61
+ name: 'waibu:preParsing',
62
+ handler: async function (req, reply) {
63
+ const { importModule } = this.app.bajo
64
+ const attachIntl = await importModule('waibu:/lib/webapp-scope/attach-intl.js')
65
+ await attachIntl.call(this, this.config.intl.detectors, req, reply)
66
+ }
67
+ }]
68
+ }
69
+
70
+ export default hook
@@ -1,5 +1,3 @@
1
- const errs = {}
2
-
3
1
  async function buildHomesMenu (req) {
4
2
  const { callHandler } = this.app.bajo
5
3
  const { get, find, orderBy } = this.app.lib._
@@ -52,50 +50,48 @@ async function buildPagesMenu (req) {
52
50
  return orderBy(all, ['level', 'title'])
53
51
  }
54
52
 
53
+ const omitted = ['createdAt', 'updatedAt', '_immutable']
54
+
55
55
  async function buildLocals ({ tpl, params = {}, opts = {} } = {}) {
56
56
  const { runHook } = this.app.bajo
57
- const { set, merge, pick, get, isEmpty, find, pullAt } = this.app.lib._
57
+ const { set, merge, pick, get, isEmpty, find, cloneDeep, omit } = this.app.lib._
58
58
  const { req, reply } = opts
59
- params.page = merge(params.page ?? {}, { ns: req.ns, features: [] })
60
- params.sidebar = params.sidebar ?? []
61
59
 
62
- const { site, user, lang, darkMode } = req
63
- const theme = pick(find(this.themes, { name: opts.theme ?? req.theme }) ?? {}, ['name', 'framework'])
64
- const iconset = pick(find(this.iconsets, { name: opts.iconset ?? req.iconset }) ?? {}, ['name'])
65
- const routeOpts = get(req, 'routeOptions.config', {})
66
- const _meta = { theme, iconset, site, user, lang, darkMode, routeOpts }
67
- _meta.site = _meta.site ?? {}
68
- merge(_meta, pick(req, ['url', 'params', 'query']))
69
- _meta.env = this.app.bajo.config.env
70
- _meta.url = _meta.url.split('?')[0].split('#')[0]
71
- if (req.session) _meta.prevUrl = req.session.prevUrl
72
- _meta.route = get(req, 'routeOptions.url')
73
- _meta.template = tpl
74
- _meta.hostHeader = req.headers.host
75
- _meta.statusCode = 200
76
- const pulled = []
77
- for (const k in errs) {
78
- if (Date.now() - errs[k] > 5000) pulled.push(k)
79
- }
80
- pullAt(errs, pulled)
60
+ const _meta = { template: tpl }
81
61
  if (params.error) {
82
62
  if (params.error.statusCode) _meta.statusCode = params.error.statusCode
83
63
  _meta.errorMessage = params.error.message
84
64
  if (params.error.ns) params.page.ns = params.error.ns
85
- if (!errs[req.id]) {
86
- this.log.error('error%s', params.error.message)
87
- if (this.app.bajo.config.env === 'dev') console.log(params.error)
88
- }
89
- errs[req.id] = Date.now()
65
+ this.log.error('error%s', params.error.message)
66
+ if (this.app.bajo.config.env === 'dev') console.log(params.error)
90
67
  }
91
- _meta.flash = reply && req.session && req.flash && !opts.partial && !opts.noFlash ? reply.flash() : {}
92
68
  if (!opts.partial) {
69
+ params.page = merge(params.page ?? {}, { ns: req.ns, features: [] })
70
+ params.sidebar = params.sidebar ?? []
71
+ merge(_meta, pick(req, ['site', 'user', 'lang', 'darkMode', 'url']))
72
+ _meta.params = cloneDeep(req.params)
73
+ _meta.query = cloneDeep(req.query)
74
+ _meta.site = omit(req.site, omitted)
75
+ _meta.user = omit(req.user, [...omitted, 'apiKey', 'salt', 'token'])
76
+ _meta.theme = pick(find(this.themes, { name: opts.theme ?? req.theme }) ?? {}, ['name', 'framework'])
77
+ _meta.iconset = pick(find(this.iconsets, { name: opts.iconset ?? req.iconset }) ?? {}, ['name'])
78
+ _meta.routeOpts = get(req, 'routeOptions.config', {})
93
79
  set(params, 'menu.homes', await buildHomesMenu.call(this, req))
94
80
  set(params, 'menu.pages', await buildPagesMenu.call(this, req))
81
+ _meta.env = this.app.bajo.config.env
82
+ _meta.url = _meta.url.split('?')[0].split('#')[0]
83
+ if (req.session) _meta.prevUrl = req.session.prevUrl
84
+ _meta.route = get(req, 'routeOptions.url')
85
+ _meta.hostHeader = req.headers.host
86
+ _meta.statusCode = 200
87
+ _meta.reqId = req.id
88
+ _meta.flash = reply && req.session && req.flash && !opts.noFlash ? reply.flash() : {}
95
89
  }
96
90
  const merged = merge({}, params, { _meta })
97
- await runHook(`${this.ns}:afterBuildLocals`, merged, req, opts)
98
- if (!isEmpty(routeOpts.ns)) await runHook(`${this.ns}.${routeOpts.ns}:afterBuildLocals`, merged, req, opts)
91
+ if (!opts.partial) {
92
+ await runHook(`${this.ns}:afterBuildLocals`, merged, req, opts)
93
+ if (!isEmpty(merged._meta.routeOpts.ns)) await runHook(`${this.ns}.${merged._meta.routeOpts.ns}:afterBuildLocals`, merged, req, opts)
94
+ }
99
95
  return merged
100
96
  }
101
97
 
@@ -2,9 +2,9 @@ import { redirect } from './handle-redirect.js'
2
2
  import { notFound, writeHtml, interceptor } from './handle-not-found.js'
3
3
 
4
4
  async function error (err, req, reply) {
5
+ this.log.error(err)
5
6
  const resp = await interceptor.call(this, 'errorHandler', err, req, reply)
6
7
  if (resp) return resp
7
- this.log.error(err)
8
8
  const payload = {
9
9
  text: this.app.log.getErrorMessage(err),
10
10
  title: req.t('internalServerError')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waibu",
3
- "version": "2.13.0",
3
+ "version": "2.15.0",
4
4
  "description": "Web Framework for Bajo",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/wiki/CHANGES.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-05-28
4
+
5
+ - [2.15.0] Change hooks to be written in one ```hook.js``` file
6
+ - [2.15.0] Change model schemas to be written in one ```model.js``` file
7
+
8
+ ## 2026-05-24
9
+
10
+ - [2.14.0] Add auto detection of theme & iconset for all widgets incl the dynamic one
11
+ - [2.14.0] Bug fix in ```handle-error.js```
12
+
3
13
  ## 2026-05-22
4
14
 
5
15
  - [2.13.0] Add ```config.log.noReq``` & ```config.log.noReply```
@@ -1,5 +0,0 @@
1
- async function onClose () {
2
- this.log.info('serverIs%s', this.t('closedL'))
3
- }
4
-
5
- export default onClose
@@ -1,5 +0,0 @@
1
- async function onReady () {
2
- this.log.info('serverIs%s', this.t('readyL'))
3
- }
4
-
5
- export default onReady
@@ -1,37 +0,0 @@
1
- import { methodColor } from './waibu@on-response.js'
2
-
3
- const onRequest = {
4
- level: 5,
5
- handler: async function onRequest (req, reply) {
6
- const { importPkg } = this.app.bajo
7
- const { get } = this.app.lib._
8
- const chalk = await importPkg('bajo:chalk')
9
- const { plain } = this.app.bajo.config.log
10
-
11
- req.site = this.config.siteInfo
12
- req.ns = get(reply.request, 'routeOptions.config.ns') ?? this.ns
13
- const ns = get(reply.request, 'routeOptions.config.webApp') ?? this.ns
14
- const arrow = plain ? '<' : chalk.bold('🡨')
15
- const c = methodColor[req.method] ?? 'gray'
16
- const method = plain ? req.method : chalk[c](req.method)
17
- const url = plain ? (':' + req.url) : chalk.gray(':' + req.url)
18
- const ip = plain ? this.getIp(req) : chalk.magenta(this.getIp(req))
19
- let msg = this.app[ns].t('httpReq%s%s%s%s', arrow, method, url.replaceAll('%', '%%'), ip)
20
- if (req.headers['content-length']) msg += this.app[ns].t('httpReqExt%s', req.headers['content-length'])
21
- if (this.config.log.defer) {
22
- this.reqLog = this.reqLog ?? {}
23
- this.reqLog[req.id] = msg
24
- } else if (!this.config.log.noReq) this.app[ns].log.info(msg)
25
- if (Object.keys(this.config.paramsCharMap).length === 0) return
26
- for (const key in req.params) {
27
- let val = req.params[key]
28
- if (typeof val !== 'string') continue
29
- for (const char in this.config.paramsCharMap) {
30
- val = val.replaceAll(char, this.config.paramsCharMap[char])
31
- }
32
- req.params[key] = val
33
- }
34
- }
35
- }
36
-
37
- export default onRequest
@@ -1,48 +0,0 @@
1
- export const methodColor = {
2
- GET: 'blue',
3
- POST: 'green',
4
- UPDATE: 'yellow',
5
- PATCH: 'yellow',
6
- DELETE: 'red'
7
- }
8
-
9
- const stateColor = {
10
- 2: 'green',
11
- 3: 'yellow',
12
- 4: 'red',
13
- 5: 'red'
14
- }
15
-
16
- const onResponse = {
17
- level: 5,
18
- handler: async function onResponse (req, reply) {
19
- const { importPkg } = this.app.bajo
20
- const { get } = this.app.lib._
21
- const { plain } = this.app.bajo.config.log
22
- const chalk = await importPkg('bajo:chalk')
23
- let level = 'info'
24
- if (reply.statusCode >= 300 && reply.statusCode < 400) level = 'warn'
25
- else if (reply.statusCode >= 400) level = 'error'
26
- const ns = get(reply.request, 'routeOptions.config.webApp') ?? this.ns
27
- const arrow = plain ? '>' : chalk.bold('🡪')
28
- const mc = methodColor[req.method] ?? 'gray'
29
- const method = plain ? req.method : chalk[mc](req.method)
30
- const url = plain ? (':' + req.url) : chalk.gray(':' + req.url)
31
- let state = plain ? reply.statusCode : chalk.gray(reply.statusCode)
32
- const sc = stateColor[Math.floor(reply.statusCode / 100)]
33
- if (!plain && sc) state = chalk[sc](reply.statusCode)
34
- const elapsed = reply.elapsedTime ?? 0
35
- let tc = 'red'
36
- if (elapsed < 1000) tc = 'yellow'
37
- if (elapsed < 500) tc = 'green'
38
- const time = plain ? elapsed.toFixed(2) : chalk[tc](elapsed.toFixed(2))
39
- if (this.config.log.defer) {
40
- this.reqLog = this.reqLog ?? {}
41
- if (this.reqLog[req.id] && !this.config.log.noReq) this.app[ns].log.info(this.reqLog[req.id])
42
- delete this.reqLog[req.id]
43
- }
44
- if (!this.config.log.noReply) this.app[ns].log[level]('httpResp%s%s%s%s%s', arrow, method, url, state, time)
45
- }
46
- }
47
-
48
- export default onResponse
@@ -1,8 +0,0 @@
1
- const onRoute = {
2
- level: 5,
3
- handler: async function (opts) {
4
- this.routes.push(opts)
5
- }
6
- }
7
-
8
- export default onRoute
@@ -1,10 +0,0 @@
1
- const waibuPreParsing = {
2
- level: 9,
3
- handler: async function (req, reply) {
4
- const { importModule } = this.app.bajo
5
- const attachIntl = await importModule('waibu:/lib/webapp-scope/attach-intl.js')
6
- await attachIntl.call(this, this.config.intl.detectors, req, reply)
7
- }
8
- }
9
-
10
- export default waibuPreParsing