waibu 1.0.0 → 1.0.2
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/README.md +5 -5
- package/bajo/.alias +1 -0
- package/bajo/.dependencies +1 -0
- package/bajo/config.json +4 -9
- package/bajo/hook/on-request.js +4 -1
- package/bajo/hook/on-response.js +1 -1
- package/bajo/hook/on-route.js +1 -1
- package/bajo/init.js +3 -0
- package/bajo/logo.png +0 -0
- package/bajo/method/escape-chars.js +6 -0
- package/bajo/method/escape.js +11 -0
- package/bajo/method/fetch.js +19 -0
- package/bajo/method/get-plugin-by-prefix.js +13 -0
- package/bajo/method/get-plugin-prefix.js +7 -0
- package/bajo/method/not-found.js +1 -1
- package/bajo/method/qs.js +17 -0
- package/bajo/method/route-dir.js +5 -3
- package/bajo/method/route-path.js +22 -17
- package/bajo/method/unescape.js +12 -0
- package/bajo/start.js +7 -3
- package/lib/app-hook.js +2 -4
- package/lib/app.js +12 -4
- package/lib/collect-route-path-handlers.js +15 -0
- package/lib/handle-forward.js +8 -5
- package/lib/handle-redirect.js +4 -3
- package/lib/home.js +2 -2
- package/lib/webapp-scope/attach-i18n.js +15 -8
- package/lib/webapp-scope/error-handler.js +4 -7
- package/lib/webapp-scope/is-route-disabled.js +1 -1
- package/{bajo/method → lib/webapp-scope}/merge-route-hooks.js +3 -3
- package/lib/webapp-scope/rerouted-path.js +1 -1
- package/lib/webapp-scope/route-hook.js +3 -3
- package/package.json +19 -17
- package/bajo/hook/bajoI18N@before-init.js +0 -6
- package/bajo/method/get-params.js +0 -18
- package/bajo/method/method-map.js +0 -9
- package/bajo/method/record/create.js +0 -13
- package/bajo/method/record/find-one.js +0 -19
- package/bajo/method/record/find.js +0 -20
- package/bajo/method/record/get.js +0 -14
- package/bajo/method/record/remove.js +0 -10
- package/bajo/method/record/update.js +0 -13
- package/bajo/method/stat/aggregate.js +0 -13
- package/bajo/method/stat/histogram.js +0 -13
- package/lib/prep-crud.js +0 -17
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# waibu
|
|
2
2
|
|
|
3
|
-
Plugin name: **
|
|
3
|
+
Plugin name: **waibu**, alias: **waibu**
|
|
4
4
|
|
|
5
|
-
 
|
|
6
6
|
|
|
7
7
|
> <br />**Attention**: I do NOT accept any pull request at the moment, thanks!<br /><br />
|
|
8
8
|
|
|
@@ -13,10 +13,10 @@ Plugin name: **wakatobi**, alias: **wktb**
|
|
|
13
13
|
Goto your ```<bajo-base-dir>``` and type:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
$ npm install
|
|
16
|
+
$ npm install waibu
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
Now open your ```<bajo-data-dir>/config/.plugins``` and put ```
|
|
19
|
+
Now open your ```<bajo-data-dir>/config/.plugins``` and put ```waibu``` in it
|
|
20
20
|
|
|
21
21
|
## License
|
|
22
22
|
|
package/bajo/.alias
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
w
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bajo-logger
|
package/bajo/config.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"alias": "wktb",
|
|
3
2
|
"server": {
|
|
4
3
|
"host": "localhost",
|
|
5
4
|
"port": 7777
|
|
6
5
|
},
|
|
7
6
|
"factory": {
|
|
8
|
-
"trustProxy": true
|
|
7
|
+
"trustProxy": true,
|
|
8
|
+
"bodyLimit": 10485760
|
|
9
9
|
},
|
|
10
|
+
"prefixVirtual": "~",
|
|
10
11
|
"qsKey": {
|
|
11
12
|
"bbox": "bbox",
|
|
12
13
|
"bboxLatField": "bboxLatField",
|
|
@@ -21,11 +22,6 @@
|
|
|
21
22
|
"lang": "lang"
|
|
22
23
|
},
|
|
23
24
|
"paramsCharMap": {},
|
|
24
|
-
"dbColl": {
|
|
25
|
-
"dataOnly": false,
|
|
26
|
-
"count": false,
|
|
27
|
-
"patchEnabled": false
|
|
28
|
-
},
|
|
29
25
|
"logRoutes": false,
|
|
30
26
|
"siteInfo": {
|
|
31
27
|
"title": "My Website",
|
|
@@ -42,6 +38,5 @@
|
|
|
42
38
|
"underPressure": false,
|
|
43
39
|
"forwardOpts": {
|
|
44
40
|
"disableRequestLogging": true
|
|
45
|
-
}
|
|
46
|
-
"dependencies": ["bajo-logger"]
|
|
41
|
+
}
|
|
47
42
|
}
|
package/bajo/hook/on-request.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
const onRequest = {
|
|
2
2
|
level: 5,
|
|
3
|
-
handler: async function onRequest (
|
|
3
|
+
handler: async function onRequest (req, reply) {
|
|
4
|
+
const { get } = this.app.bajo.lib._
|
|
5
|
+
|
|
4
6
|
req.site = this.config.siteInfo
|
|
7
|
+
req.ns = get(reply.request, 'routeOptions.config.ns')
|
|
5
8
|
let msg = '< %s:%s from IP %s'
|
|
6
9
|
if (req.headers['content-length']) msg += ', content length: %s'
|
|
7
10
|
this.log.info(msg, req.method, req.url, this.getIp(req), req.headers['content-length'])
|
package/bajo/hook/on-response.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const onResponse = {
|
|
2
2
|
level: 5,
|
|
3
|
-
handler: async function onResponse (
|
|
3
|
+
handler: async function onResponse (req, reply) {
|
|
4
4
|
let method = 'info'
|
|
5
5
|
if (reply.statusCode >= 300 && reply.statusCode < 400) method = 'warn'
|
|
6
6
|
else if (reply.statusCode >= 400) method = 'error'
|
package/bajo/hook/on-route.js
CHANGED
package/bajo/init.js
CHANGED
package/bajo/logo.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
async function fetch (url, opts = {}, extra = {}) {
|
|
2
|
+
const { getPlugin } = this.app.bajo
|
|
3
|
+
getPlugin('bajoExtra')
|
|
4
|
+
const { fetch } = this.app.bajoExtra
|
|
5
|
+
extra.rawResponse = true
|
|
6
|
+
|
|
7
|
+
url = this.routePath(url, { guessHost: true })
|
|
8
|
+
const resp = await fetch(url, opts, extra)
|
|
9
|
+
const result = await resp.json()
|
|
10
|
+
if (!resp.ok) {
|
|
11
|
+
throw this.error(result.message, {
|
|
12
|
+
statusCode: resp.status,
|
|
13
|
+
success: false
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
return result
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default fetch
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function getPluginByPrefix (prefix) {
|
|
2
|
+
const { get } = this.app.bajo.lib._
|
|
3
|
+
let plugin
|
|
4
|
+
for (const p of this.app.bajo.pluginNames) {
|
|
5
|
+
if (get(this, `app.${p}.config.waibu.prefix`) === prefix) {
|
|
6
|
+
plugin = this.app[p]
|
|
7
|
+
break
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return plugin
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default getPluginByPrefix
|
package/bajo/method/not-found.js
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import queryString from 'query-string'
|
|
2
|
+
|
|
3
|
+
function parse (item) {
|
|
4
|
+
return queryString.parse(item, {
|
|
5
|
+
parseBooleans: true,
|
|
6
|
+
parseNumbers: true
|
|
7
|
+
})
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const qs = {
|
|
11
|
+
parse,
|
|
12
|
+
parseUrl: queryString.parseUrl,
|
|
13
|
+
stringify: queryString.stringify,
|
|
14
|
+
stringifyUrl: queryString.stringifyUrl
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default qs
|
package/bajo/method/route-dir.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
function routeDir (ns, base) {
|
|
2
|
+
const { get } = this.app.bajo.lib._
|
|
2
3
|
if (!base) base = ns
|
|
3
4
|
const cfg = this.app[base].config
|
|
4
|
-
const
|
|
5
|
+
const prefix = get(cfg, 'waibu.prefix', this.app[base].alias)
|
|
6
|
+
const dir = prefix === '' ? '' : `/${prefix}`
|
|
5
7
|
if (!ns) return dir
|
|
6
|
-
if (ns === base || (ns === this.app.bajo.mainNs && cfg.
|
|
7
|
-
return dir + '
|
|
8
|
+
if (ns === base || (ns === this.app.bajo.mainNs && cfg.mountMainAsRoot)) return dir
|
|
9
|
+
return dir + `/${get(this.app[ns].config, 'waibu.prefix', this.app[ns].alias)}`
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
export default routeDir
|
|
@@ -1,24 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// TODO: what if wakatobiMpa isn't loaded?
|
|
5
|
-
const { defaultsDeep } = this.app.bajo
|
|
6
|
-
const { isEmpty, get } = this.app.bajo.lib._
|
|
1
|
+
function routePath (name = '', { query = {}, base = 'waibuMpa', params = {}, guessHost } = {}) {
|
|
2
|
+
const { defaultsDeep, getPlugin } = this.app.bajo
|
|
3
|
+
const { isEmpty, get, trimEnd, trimStart } = this.app.bajo.lib._
|
|
7
4
|
const { breakNsPath } = this.app.bajo
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
|
|
6
|
+
const plugin = getPlugin(base)
|
|
7
|
+
const cfg = plugin.config ?? {}
|
|
8
|
+
let info = {}
|
|
9
|
+
if (['.', '/', '?', '#'].includes(name[0]) || name.slice(1, 2) === ':') info.path = name
|
|
10
|
+
else if (['~'].includes(name[0])) info.path = name.slice(1)
|
|
11
|
+
else {
|
|
12
|
+
info = breakNsPath(name)
|
|
13
|
+
}
|
|
14
|
+
if (info.path.slice(0, 2) === './') info.path = info.path.slice(2)
|
|
15
|
+
if (this.routePathHandlers[info.subNs]) return this.routePathHandlers[info.subNs](name)
|
|
16
|
+
if (info.path.includes('//')) return info.path
|
|
17
|
+
|
|
18
|
+
info.path = info.path.split('/').map(p => {
|
|
15
19
|
return p[0] === ':' && params[p.slice(1)] ? params[p.slice(1)] : p
|
|
16
20
|
}).join('/')
|
|
17
|
-
let url = path
|
|
21
|
+
let url = info.path
|
|
18
22
|
const langDetector = get(cfg, 'i18n.detectors', [])
|
|
19
|
-
if (ns) url = langDetector.includes('path') ? `/${params.lang ?? ''}${this.routeDir(ns)}${path}` : `${this.routeDir(ns)}${path}
|
|
20
|
-
|
|
21
|
-
if (!isEmpty(
|
|
23
|
+
if (info.ns) url = trimEnd(langDetector.includes('path') ? `/${params.lang ?? ''}${this.routeDir(info.ns)}${info.path}` : `${this.routeDir(info.ns)}${info.path}`, '/')
|
|
24
|
+
info.qs = defaultsDeep({}, query, info.qs)
|
|
25
|
+
if (!isEmpty(info.qs)) url += '?' + this.qs.stringify(info.qs)
|
|
26
|
+
if (!url.startsWith('http') && guessHost) url = `http://${this.config.server.host}:${this.config.server.port}/${trimStart(url, '/')}`
|
|
22
27
|
return url
|
|
23
28
|
}
|
|
24
29
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import escapeChars from './escape-chars.js'
|
|
2
|
+
|
|
3
|
+
function unescape (text) {
|
|
4
|
+
const { forOwn, invert } = this.app.bajo.lib._
|
|
5
|
+
const mapping = invert(escapeChars)
|
|
6
|
+
forOwn(mapping, (v, k) => {
|
|
7
|
+
text = text.replaceAll(k, v)
|
|
8
|
+
})
|
|
9
|
+
return text
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default unescape
|
package/bajo/start.js
CHANGED
|
@@ -12,20 +12,24 @@ import handleRedirect from '../lib/handle-redirect.js'
|
|
|
12
12
|
async function start () {
|
|
13
13
|
const { generateId, runHook } = this.app.bajo
|
|
14
14
|
const cfg = this.getConfig()
|
|
15
|
-
cfg.factory.
|
|
15
|
+
cfg.factory.loggerInstance = this.app.bajoLogger.instance.child(
|
|
16
16
|
{},
|
|
17
|
-
{ msgPrefix: '[
|
|
17
|
+
{ msgPrefix: '[waibu] ' }
|
|
18
18
|
)
|
|
19
19
|
cfg.factory.genReqId = req => generateId()
|
|
20
20
|
cfg.factory.disableRequestLogging = true
|
|
21
|
+
cfg.factory.querystringParser = str => this.qs.parse(str)
|
|
21
22
|
|
|
22
23
|
const instance = fastify(cfg.factory)
|
|
23
24
|
instance.decorateRequest('lang', null)
|
|
25
|
+
instance.decorateRequest('i18n', null)
|
|
26
|
+
instance.decorateRequest('t', () => {})
|
|
24
27
|
instance.decorateRequest('langDetector', null)
|
|
25
28
|
instance.decorateRequest('site', null)
|
|
29
|
+
instance.decorateRequest('ns', null)
|
|
26
30
|
this.instance = instance
|
|
27
31
|
this.routes = this.routes || []
|
|
28
|
-
await runHook('
|
|
32
|
+
await runHook('waibu:afterCreateContext', instance)
|
|
29
33
|
await instance.register(sensible)
|
|
30
34
|
if (cfg.underPressure) await instance.register(underPressure)
|
|
31
35
|
if (cfg.noIcon) await instance.register(noIcon)
|
package/lib/app-hook.js
CHANGED
|
@@ -4,11 +4,9 @@ async function appHook () {
|
|
|
4
4
|
const me = this
|
|
5
5
|
for (const hook of hooks) {
|
|
6
6
|
me.instance.addHook(hook, async function (...args) {
|
|
7
|
+
args.push(this)
|
|
7
8
|
if (['onClose', 'onReady'].includes(hook)) await runHook(`${me.name}:${hook}`, ...args)
|
|
8
|
-
else {
|
|
9
|
-
const ctx = this // encapsulated fastify scope
|
|
10
|
-
await runHook(`${me.name}:${hook}`, ctx, ...args)
|
|
11
|
-
}
|
|
9
|
+
else await runHook(`${me.name}:${hook}`, ...args)
|
|
12
10
|
})
|
|
13
11
|
}
|
|
14
12
|
}
|
package/lib/app.js
CHANGED
|
@@ -2,15 +2,18 @@ import home from './home.js'
|
|
|
2
2
|
|
|
3
3
|
export async function collect (glob = 'boot.js', baseNs) {
|
|
4
4
|
const { eachPlugins, importModule } = this.app.bajo
|
|
5
|
-
const { orderBy } = this.app.bajo.lib._
|
|
5
|
+
const { orderBy, get } = this.app.bajo.lib._
|
|
6
6
|
if (!baseNs) baseNs = this.name
|
|
7
7
|
const mods = []
|
|
8
|
+
|
|
8
9
|
await eachPlugins(async function ({ config, file, ns, alias }) {
|
|
9
10
|
const mod = await importModule(file, { asHandler: true })
|
|
10
|
-
mod.prefix = config.prefix
|
|
11
|
+
mod.prefix = get(config, 'waibu.prefix', alias)
|
|
12
|
+
if (get(config, 'i18n.detectors', []).includes('path')) mod.prefix = `/:lang${mod.prefix}`
|
|
11
13
|
mod.ns = ns
|
|
14
|
+
mod.alias = alias
|
|
12
15
|
mods.push(mod)
|
|
13
|
-
}, { glob, baseNs })
|
|
16
|
+
}, { glob, prefix: baseNs })
|
|
14
17
|
const prefixes = {}
|
|
15
18
|
mods.forEach(m => {
|
|
16
19
|
if (!prefixes[m.prefix]) prefixes[m.prefix] = []
|
|
@@ -27,7 +30,12 @@ export async function boot () {
|
|
|
27
30
|
for (const m of mods) {
|
|
28
31
|
await runHook(`${this.name}.${m.ns}:beforeAppBoot`)
|
|
29
32
|
this.log.debug('Boot app: %s', m.ns)
|
|
30
|
-
await
|
|
33
|
+
await this.instance.register(async (ctx) => {
|
|
34
|
+
const plugin = this.app[m.ns]
|
|
35
|
+
plugin.instance = ctx
|
|
36
|
+
await runHook(`${plugin.name}:afterCreateContext`, ctx)
|
|
37
|
+
await m.handler.call(plugin, ctx, m.prefix)
|
|
38
|
+
}, { prefix: m.prefix })
|
|
31
39
|
await runHook(`${this.name}.${m.ns}:afterAppBoot`)
|
|
32
40
|
}
|
|
33
41
|
await runHook(`${this.name}:afterAppBoot`)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
async function collectRoutePathHandlers () {
|
|
2
|
+
const { eachPlugins } = this.app.bajo
|
|
3
|
+
const { isEmpty } = this.app.bajo.lib._
|
|
4
|
+
this.routePathHandlers = this.routePathHandlers ?? {}
|
|
5
|
+
const me = this
|
|
6
|
+
|
|
7
|
+
await eachPlugins(async function ({ alias }) {
|
|
8
|
+
if (isEmpty(this.routePathHandlers) || !this.routePath) return undefined
|
|
9
|
+
for (const key of this.routePathHandlers) {
|
|
10
|
+
me.routePathHandlers[key] = this.routePath
|
|
11
|
+
}
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default collectRoutePathHandlers
|
package/lib/handle-forward.js
CHANGED
|
@@ -15,11 +15,14 @@ async function handleForward (ctx) {
|
|
|
15
15
|
const options = defaultsDeep({ base }, this.config.forwardOpts)
|
|
16
16
|
await ctx.register(replyFrom, options)
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
if (url.startsWith('http'))
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
ctx.decorateReply('forwardTo', async function (url, options = {}) {
|
|
19
|
+
if (url.startsWith('http')) this.redirectTo(url)
|
|
20
|
+
else {
|
|
21
|
+
this.from(me.routePath(url, options), {
|
|
22
|
+
rewriteHeaders
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
return this
|
|
23
26
|
})
|
|
24
27
|
}
|
|
25
28
|
|
package/lib/handle-redirect.js
CHANGED
|
@@ -2,9 +2,10 @@ import path from 'path'
|
|
|
2
2
|
|
|
3
3
|
async function handleRedirect (ctx, options) {
|
|
4
4
|
const me = this
|
|
5
|
-
ctx.decorateReply('redirectTo',
|
|
6
|
-
if (url.startsWith('http') || path.isAbsolute(url))
|
|
7
|
-
|
|
5
|
+
ctx.decorateReply('redirectTo', function (url, options = {}) {
|
|
6
|
+
if (url.startsWith('http') || path.isAbsolute(url)) this.redirect(url)
|
|
7
|
+
else this.redirect(me.routePath(url, options))
|
|
8
|
+
return this
|
|
8
9
|
})
|
|
9
10
|
}
|
|
10
11
|
|
package/lib/home.js
CHANGED
|
@@ -5,9 +5,9 @@ async function home () {
|
|
|
5
5
|
if (config.home) {
|
|
6
6
|
if (isString(config.home)) config.home = { path: config.home }
|
|
7
7
|
await this.instance.get('/', async function (req, reply) {
|
|
8
|
-
if (!config.home.forward) return
|
|
8
|
+
if (!config.home.forward) return reply.redirectTo(config.home.path)
|
|
9
9
|
const opts = defaultsDeep(pick(req, ['params', 'query']), pick(config.home, ['params', 'query']))
|
|
10
|
-
return
|
|
10
|
+
return reply.forwardTo(config.home.path, opts)
|
|
11
11
|
})
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -14,13 +14,12 @@ function detect (detector = [], req, reply) {
|
|
|
14
14
|
const length = req.url.split('/').length
|
|
15
15
|
let url = req.url.replace(`/${lang}`, `/${defLang}`)
|
|
16
16
|
if (length > 2) url = req.url.replace(`/${lang}/`, `/${defLang}/`)
|
|
17
|
-
reply.redirectTo(url)
|
|
18
|
-
return
|
|
17
|
+
return reply.redirectTo(url)
|
|
19
18
|
}
|
|
20
19
|
// by query string
|
|
21
20
|
lang = null
|
|
22
21
|
if (detector.includes('qs')) {
|
|
23
|
-
lang = req.query[this.app.
|
|
22
|
+
lang = req.query[this.app.waibu.config.qsKey.lang]
|
|
24
23
|
if (lang && supported.includes(lang)) {
|
|
25
24
|
req.lang = lang
|
|
26
25
|
req.langDetector = 'qs'
|
|
@@ -51,13 +50,21 @@ function detect (detector = [], req, reply) {
|
|
|
51
50
|
|
|
52
51
|
async function attachI18N (detector = [], req, reply) {
|
|
53
52
|
if (!this.app.bajoI18N) return
|
|
53
|
+
const { importModule } = this.app.bajo
|
|
54
54
|
const { get } = this.app.bajo.lib._
|
|
55
|
+
const translate = await importModule('bajo:/boot/lib/translate.js')
|
|
55
56
|
detect.call(this, detector, req, reply)
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
req.
|
|
57
|
+
const defNs = get(req, 'routeOptions.config.ns', this.name)
|
|
58
|
+
const opts = { defaultNS: defNs }
|
|
59
|
+
if (req.lang) opts.lng = req.lang
|
|
60
|
+
req.i18n = this.app.bajoI18N.instance.cloneInstance(opts)
|
|
61
|
+
req.t = (...args) => {
|
|
62
|
+
// const defNs = get(req, 'routeOptions.config.ns', this.name)
|
|
63
|
+
return translate.call(this.app[defNs], req.i18n, ...args)
|
|
64
|
+
}
|
|
65
|
+
req.format = (value, type = 'auto', opts) => {
|
|
66
|
+
return this.app.bajoI18N.format(value, type, req.lang, opts)
|
|
67
|
+
}
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
export default attachI18N
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
async function errorHandler (ctx, extHandler) {
|
|
2
2
|
const me = this
|
|
3
3
|
ctx.setErrorHandler(async function (err, req, reply) {
|
|
4
|
-
if (err.redirect)
|
|
5
|
-
reply.redirect(err.redirect)
|
|
6
|
-
return
|
|
7
|
-
}
|
|
4
|
+
if (err.redirect) return reply.redirect(err.redirect)
|
|
8
5
|
if (err.print) {
|
|
9
6
|
reply.send(err.print)
|
|
10
7
|
return
|
|
11
8
|
}
|
|
12
|
-
if (me.app.bajo.config.log.level === 'trace' && !['
|
|
13
|
-
if (extHandler) return await extHandler.call(me,
|
|
14
|
-
if (err.message === '
|
|
9
|
+
if (me.app.bajo.config.log.level === 'trace' && !['notFound', 'redirect'].includes(err.message)) console.error(err)
|
|
10
|
+
if (extHandler) return await extHandler.call(me, err, req, reply, ctx)
|
|
11
|
+
if (err.message === 'notFound' || err.statusCode === 404) {
|
|
15
12
|
reply.code(err.statusCode)
|
|
16
13
|
return
|
|
17
14
|
}
|
|
@@ -9,7 +9,7 @@ async function isRouteDisabled (url, method, matchers = []) {
|
|
|
9
9
|
const { intersection, cloneDeep } = this.app.bajo.lib._
|
|
10
10
|
const items = []
|
|
11
11
|
for (const m of cloneDeep(matchers)) {
|
|
12
|
-
m.path = this.app.
|
|
12
|
+
m.path = this.app.waibu.routePath(m.path)
|
|
13
13
|
m.methods = santizeMethods(m.methods)
|
|
14
14
|
items.push(m)
|
|
15
15
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import hookTypes from './hook-types.js'
|
|
2
|
-
|
|
3
1
|
async function mergeRouteHooks (def, withHandler = true) {
|
|
4
2
|
const { last, isFunction } = this.app.bajo.lib._
|
|
3
|
+
const { hookTypes } = this.app.waibu
|
|
5
4
|
const hooks = [...hookTypes]
|
|
6
5
|
const me = this
|
|
7
6
|
if (withHandler) hooks.push('handler')
|
|
@@ -11,7 +10,8 @@ async function mergeRouteHooks (def, withHandler = true) {
|
|
|
11
10
|
def[h] = async function (...args) {
|
|
12
11
|
// TODO: hooks can be array of functions
|
|
13
12
|
if (isFunction(last(args))) args.pop()
|
|
14
|
-
|
|
13
|
+
args.push(this)
|
|
14
|
+
return await oldH.call(me, ...args)
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
async function routeHook (ns) {
|
|
2
2
|
const ctx = this.app[ns].instance
|
|
3
3
|
const { runHook } = this.app.bajo
|
|
4
|
-
const { hookTypes } = this.app.
|
|
4
|
+
const { hookTypes } = this.app.waibu
|
|
5
5
|
for (const hook of hookTypes) {
|
|
6
6
|
ctx.addHook(hook, async function (...args) {
|
|
7
|
-
|
|
8
|
-
await runHook(`${ns}:${hook}`,
|
|
7
|
+
args.push(this)
|
|
8
|
+
await runHook(`${ns}:${hook}`, ...args)
|
|
9
9
|
})
|
|
10
10
|
}
|
|
11
11
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "waibu",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Web Framework for Bajo",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"url": "git+https://github.com/ardhi/waibu.git"
|
|
13
13
|
},
|
|
14
14
|
"keywords": [
|
|
15
|
+
"waibu",
|
|
15
16
|
"web",
|
|
16
17
|
"webserver",
|
|
17
18
|
"bajo",
|
|
@@ -26,21 +27,22 @@
|
|
|
26
27
|
},
|
|
27
28
|
"homepage": "https://github.com/ardhi/waibu#readme",
|
|
28
29
|
"dependencies": {
|
|
29
|
-
"@fastify/accepts": "^
|
|
30
|
-
"@fastify/compress": "^
|
|
31
|
-
"@fastify/cookie": "^
|
|
32
|
-
"@fastify/cors": "^
|
|
33
|
-
"@fastify/flash": "^
|
|
34
|
-
"@fastify/formbody": "^
|
|
35
|
-
"@fastify/helmet": "^
|
|
36
|
-
"@fastify/multipart": "^
|
|
37
|
-
"@fastify/rate-limit": "^
|
|
38
|
-
"@fastify/reply-from": "^
|
|
39
|
-
"@fastify/sensible": "^
|
|
40
|
-
"@fastify/session": "^
|
|
41
|
-
"@fastify/static": "
|
|
42
|
-
"@fastify/under-pressure": "^
|
|
43
|
-
"fastify": "^
|
|
44
|
-
"fastify-no-icon": "^
|
|
30
|
+
"@fastify/accepts": "^5.0.2",
|
|
31
|
+
"@fastify/compress": "^8.0.1",
|
|
32
|
+
"@fastify/cookie": "^11.0.2",
|
|
33
|
+
"@fastify/cors": "^10.0.2",
|
|
34
|
+
"@fastify/flash": "^6.0.3",
|
|
35
|
+
"@fastify/formbody": "^8.0.2",
|
|
36
|
+
"@fastify/helmet": "^13.0.1",
|
|
37
|
+
"@fastify/multipart": "^9.0.2",
|
|
38
|
+
"@fastify/rate-limit": "^10.2.2",
|
|
39
|
+
"@fastify/reply-from": "^12.0.1",
|
|
40
|
+
"@fastify/sensible": "^6.0.2",
|
|
41
|
+
"@fastify/session": "^11.1.0",
|
|
42
|
+
"@fastify/static": "^8.0.4",
|
|
43
|
+
"@fastify/under-pressure": "^9.0.3",
|
|
44
|
+
"fastify": "^5.2.1",
|
|
45
|
+
"fastify-no-icon": "^7.0.0",
|
|
46
|
+
"query-string": "^9.1.1"
|
|
45
47
|
}
|
|
46
48
|
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
function getParams (req, ...items) {
|
|
2
|
-
const { map, trim, get } = this.app.bajo.lib._
|
|
3
|
-
let fields
|
|
4
|
-
req.query = req.query ?? {}
|
|
5
|
-
req.params = req.params ?? {}
|
|
6
|
-
if (req.query.fields) fields = map((req.query.fields ?? '').split(','), i => trim(i))
|
|
7
|
-
const params = {
|
|
8
|
-
fields,
|
|
9
|
-
count: get(this, 'config.dbColl.count', false),
|
|
10
|
-
body: req.body
|
|
11
|
-
}
|
|
12
|
-
items.forEach(i => {
|
|
13
|
-
params[i] = req.params[i]
|
|
14
|
-
})
|
|
15
|
-
return params
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export default getParams
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import prepCrud from '../../../lib/prep-crud.js'
|
|
2
|
-
|
|
3
|
-
async function create ({ coll, req, reply, body, options = {} }) {
|
|
4
|
-
this.app.bajo.getPlugin('dobo') // ensure dobo is loaded
|
|
5
|
-
const { recordCreate, attachmentFind } = this.app.dobo
|
|
6
|
-
const { name, input, opts } = prepCrud.call(this, { coll, req, body, options, args: ['coll'] })
|
|
7
|
-
const ret = await recordCreate(name, input, opts)
|
|
8
|
-
const { attachment, stats, mimeType } = req.query
|
|
9
|
-
if (attachment) ret.data._attachment = await attachmentFind(name, ret.data.id, { stats, mimeType })
|
|
10
|
-
return ret
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default create
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import prepCrud from '../../../lib/prep-crud.js'
|
|
2
|
-
|
|
3
|
-
async function find ({ coll, req, reply, options = {} }) {
|
|
4
|
-
this.app.bajo.getPlugin('dobo') // ensure dobo is loaded
|
|
5
|
-
const { recordFindOne, attachmentFind } = this.app.dobo
|
|
6
|
-
const { name, opts } = prepCrud.call(this, { coll, req, options, args: ['coll'] })
|
|
7
|
-
opts.bboxLatField = req.query[this.config.qsKey.bboxLatField]
|
|
8
|
-
opts.bboxLngField = req.query[this.config.qsKey.bboxLngField]
|
|
9
|
-
const filter = this.parseFilter(req)
|
|
10
|
-
const ret = await recordFindOne(name, filter, opts)
|
|
11
|
-
ret.filter = filter
|
|
12
|
-
const { attachment, stats, mimeType } = req.query
|
|
13
|
-
if (attachment) {
|
|
14
|
-
ret.data._attachment = await attachmentFind(name, ret.data.id, { stats, mimeType })
|
|
15
|
-
}
|
|
16
|
-
return ret
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export default find
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import prepCrud from '../../../lib/prep-crud.js'
|
|
2
|
-
|
|
3
|
-
async function find ({ coll, req, reply, options = {} }) {
|
|
4
|
-
this.app.bajo.getPlugin('dobo') // ensure dobo is loaded
|
|
5
|
-
const { recordFind, attachmentFind } = this.app.dobo
|
|
6
|
-
const { name, opts } = prepCrud.call(this, { coll, req, options, args: ['coll'] })
|
|
7
|
-
opts.bboxLatField = req.query[this.config.qsKey.bboxLatField]
|
|
8
|
-
opts.bboxLngField = req.query[this.config.qsKey.bboxLngField]
|
|
9
|
-
const filter = this.parseFilter(req)
|
|
10
|
-
const ret = await recordFind(name, filter, opts)
|
|
11
|
-
const { attachment, stats, mimeType } = req.query
|
|
12
|
-
if (attachment) {
|
|
13
|
-
for (const d of ret.data) {
|
|
14
|
-
d._attachment = await attachmentFind(name, d.id, { stats, mimeType })
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return ret
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export default find
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import prepCrud from '../../../lib/prep-crud.js'
|
|
2
|
-
|
|
3
|
-
async function get ({ coll, req, reply, id, options = {} }) {
|
|
4
|
-
this.app.bajo.getPlugin('dobo') // ensure dobo is loaded
|
|
5
|
-
const { recordGet, attachmentFind } = this.app.dobo
|
|
6
|
-
const { name, recId, opts } = prepCrud.call(this, { coll, req, id, options, args: ['coll', 'id'] })
|
|
7
|
-
opts.filter = this.parseFilter(req)
|
|
8
|
-
const ret = await recordGet(name, recId, opts)
|
|
9
|
-
const { attachment, stats, mimeType } = req.query
|
|
10
|
-
if (attachment) ret.data._attachment = await attachmentFind(name, id, { stats, mimeType })
|
|
11
|
-
return ret
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default get
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import prepCrud from '../../../lib/prep-crud.js'
|
|
2
|
-
|
|
3
|
-
async function remove ({ coll, req, reply, id, options = {} }) {
|
|
4
|
-
this.app.bajo.getPlugin('dobo') // ensure dobo is loaded
|
|
5
|
-
const { recordRemove } = this.app.dobo
|
|
6
|
-
const { name, recId, opts } = prepCrud.call(this, { coll, req, id, options, args: ['coll', 'id'] })
|
|
7
|
-
return await recordRemove(name, recId, opts)
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export default remove
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import prepCrud from '../../../lib/prep-crud.js'
|
|
2
|
-
|
|
3
|
-
async function update ({ coll, req, reply, id, body, options = {} }) {
|
|
4
|
-
this.app.bajo.getPlugin('dobo') // ensure dobo is loaded
|
|
5
|
-
const { recordUpdate, attachmentFind } = this.app.dobo
|
|
6
|
-
const { name, input, opts, recId } = prepCrud.call(this, { coll, req, body, id, options, args: ['coll', 'id'] })
|
|
7
|
-
const ret = await recordUpdate(name, recId, input, opts)
|
|
8
|
-
const { attachment, stats, mimeType } = req.query
|
|
9
|
-
if (attachment) ret.data._attachment = await attachmentFind(name, id, { stats, mimeType })
|
|
10
|
-
return ret
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default update
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import prepCrud from '../../../lib/prep-crud.js'
|
|
2
|
-
|
|
3
|
-
async function aggregate ({ coll, req, reply, options = {} }) {
|
|
4
|
-
this.app.bajo.getPlugin('dobo') // ensure dobo is loaded
|
|
5
|
-
const { statAggregate } = this.app.dobo
|
|
6
|
-
const { name, opts } = prepCrud.call(this, { coll, req, options, args: ['coll'] })
|
|
7
|
-
for (const item of ['group', 'aggregate']) {
|
|
8
|
-
opts[item] = options[item] ?? req.params[item] ?? req.query[item]
|
|
9
|
-
}
|
|
10
|
-
return await statAggregate(name, this.parseFilter(req), opts)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default aggregate
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import prepCrud from '../../../lib/prep-crud.js'
|
|
2
|
-
|
|
3
|
-
async function histogram ({ coll, req, reply, options = {} }) {
|
|
4
|
-
this.app.bajo.getPlugin('dobo') // ensure dobo is loaded
|
|
5
|
-
const { statHistogram } = this.app.dobo
|
|
6
|
-
const { name, opts } = prepCrud.call(this, { coll, req, options, args: ['coll'] })
|
|
7
|
-
for (const item of ['type', 'group', 'aggregate']) {
|
|
8
|
-
opts[item] = options[item] ?? req.params[item] ?? req.query[item]
|
|
9
|
-
}
|
|
10
|
-
return await statHistogram(name, this.parseFilter(req), opts)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default histogram
|
package/lib/prep-crud.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
function prepCrud ({ coll, body, id, req, options, args }) {
|
|
2
|
-
const { pascalCase } = this.app.bajo
|
|
3
|
-
const { cloneDeep, get } = this.app.bajo.lib._
|
|
4
|
-
const opts = cloneDeep(options)
|
|
5
|
-
const params = this.getParams(req, ...args)
|
|
6
|
-
for (const k of ['count', 'fields']) {
|
|
7
|
-
opts[k] = opts[k] ?? params[k]
|
|
8
|
-
}
|
|
9
|
-
opts.dataOnly = get(this, 'config.dbColl.dataOnly', false)
|
|
10
|
-
opts.req = req
|
|
11
|
-
const recId = id ?? params.id ?? req.query.id
|
|
12
|
-
const name = pascalCase(coll ?? params.coll)
|
|
13
|
-
const input = body ?? params.body
|
|
14
|
-
return { name, recId, input, opts }
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default prepCrud
|