miolo 3.0.0-beta.21 → 3.0.0-beta.210
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/bin/build/build.mjs +53 -0
- package/bin/build/build_bin.mjs +17 -0
- package/bin/build/cli/client.mjs +52 -0
- package/bin/build/cli/css.mjs +22 -0
- package/bin/build/cli/index.mjs +40 -0
- package/bin/build/cli/ssr.mjs +21 -0
- package/bin/build/server/aliases.mjs +112 -0
- package/bin/build/server/babel.config.js +24 -0
- package/bin/build/server/banner.mjs +20 -0
- package/bin/build/server/bundle.mjs +111 -0
- package/bin/build/server/fix.mjs +15 -0
- package/bin/build/server/index.mjs +69 -0
- package/bin/build/server/options.mjs +83 -0
- package/bin/create/auth.mjs +23 -0
- package/bin/create/copy.mjs +175 -0
- package/bin/create/docker.mjs +25 -0
- package/bin/create/index.mjs +137 -0
- package/bin/create/pkgjson.mjs +72 -0
- package/bin/create/prepare-template.mjs +158 -0
- package/bin/create/validation.mjs +27 -0
- package/bin/dev/dev.mjs +32 -23
- package/bin/dev/dev_start.mjs +6 -5
- package/bin/index.mjs +94 -52
- package/bin/prod-bin/create-bin.mjs +42 -27
- package/bin/prod-bin/run.mjs +13 -9
- package/bin/{prod-run → run}/pid.mjs +4 -4
- package/bin/run/restart.mjs +13 -0
- package/bin/run/start.mjs +18 -0
- package/bin/run/stop.mjs +20 -0
- package/bin/util.mjs +35 -11
- package/package.json +59 -39
- package/src/config/.env +34 -12
- package/src/config/defaults.mjs +253 -185
- package/src/config/env.mjs +40 -22
- package/src/config/index.mjs +19 -24
- package/src/config/util.mjs +25 -10
- package/src/db-conn.mjs +34 -0
- package/src/engines/cron/emails.mjs +10 -5
- package/src/engines/cron/index.mjs +45 -51
- package/src/engines/cron/init.mjs +16 -17
- package/src/engines/cron/ipsum.mjs +65 -60
- package/src/engines/cron/syscheck.mjs +30 -30
- package/src/engines/emailer/index.mjs +1 -2
- package/src/engines/emailer/queue.mjs +14 -20
- package/src/engines/emailer/transporter.mjs +86 -74
- package/src/engines/geoip/index.mjs +23 -28
- package/src/engines/http/index.mjs +26 -15
- package/src/engines/logger/buildErrorEmailBody.mjs +72 -0
- package/src/engines/logger/index.mjs +114 -122
- package/src/engines/logger/injectStackTrace.mjs +59 -0
- package/src/engines/logger/logger_mail.mjs +47 -61
- package/src/engines/logger/reopenTransportOnHupSignal.mjs +12 -13
- package/src/engines/parser/Parser.mjs +77 -60
- package/src/engines/parser/index.mjs +1 -1
- package/src/engines/schema/diffObjs.mjs +41 -0
- package/src/engines/schema/index.mjs +4 -0
- package/src/engines/schema/input.mjs +54 -0
- package/src/engines/schema/output.mjs +66 -0
- package/src/engines/socket/index.mjs +44 -46
- package/src/index.mjs +15 -10
- package/src/middleware/auth/basic.mjs +41 -40
- package/src/middleware/auth/custom.mjs +10 -13
- package/src/middleware/auth/guest.mjs +27 -27
- package/src/middleware/auth/passport/index.mjs +374 -0
- package/src/middleware/auth/passport/session/index.mjs +43 -0
- package/src/middleware/auth/{credentials → passport}/session/store.mjs +35 -15
- package/src/middleware/auth/passport/session/store_koa_redis.mjs +3 -0
- package/src/middleware/context/cache/index.mjs +78 -33
- package/src/middleware/context/cache/options.mjs +19 -21
- package/src/middleware/context/db.mjs +45 -20
- package/src/middleware/context/index.mjs +12 -12
- package/src/middleware/extra.mjs +4 -5
- package/src/middleware/http/body.mjs +25 -25
- package/src/middleware/http/catcher.mjs +81 -8
- package/src/middleware/http/custom_blacklist.mjs +19 -16
- package/src/middleware/http/headers.mjs +37 -34
- package/src/middleware/http/ratelimit.mjs +16 -23
- package/src/middleware/http/request.mjs +60 -65
- package/src/middleware/routes/catch_js_error.mjs +30 -23
- package/src/middleware/routes/robots.mjs +4 -7
- package/src/middleware/routes/router/crud/attachCrudRoutes.mjs +108 -90
- package/src/middleware/routes/router/crud/getCrudConfig.mjs +31 -55
- package/src/middleware/routes/router/defaults.mjs +6 -19
- package/src/middleware/routes/router/index.mjs +17 -21
- package/src/middleware/routes/router/queries/attachQueriesRoutes.mjs +227 -50
- package/src/middleware/routes/router/queries/getQueriesConfig.mjs +45 -55
- package/src/middleware/routes/router/utils.mjs +41 -26
- package/src/middleware/ssr/context.mjs +5 -7
- package/src/middleware/ssr/html.mjs +66 -43
- package/src/middleware/ssr/loader.mjs +11 -14
- package/src/middleware/ssr/ssr_render.mjs +39 -22
- package/src/middleware/static/index.mjs +33 -14
- package/src/middleware/vite/devserver.mjs +38 -22
- package/src/middleware/vite/watcher.mjs +12 -14
- package/src/server-cron.mjs +13 -8
- package/src/server-dev.mjs +13 -16
- package/src/server.mjs +49 -51
- package/template/.agent/skills/miolo-app-arch/SKILL.md +218 -0
- package/template/.agent/skills/miolo-auth/SKILL.md +450 -0
- package/template/.agent/skills/miolo-cli-router/SKILL.md +394 -0
- package/template/.agent/skills/miolo-database/SKILL.md +358 -0
- package/template/.agent/skills/miolo-react-patterns/SKILL.md +426 -0
- package/template/.agent/skills/miolo-routing/SKILL.md +326 -0
- package/template/.agent/skills/miolo-schemas/SKILL.md +329 -0
- package/template/.agent/skills/miolo-session-context/SKILL.md +397 -0
- package/template/.agent/skills/miolo-ssr/SKILL.md +433 -0
- package/template/.editorconfig +18 -0
- package/template/.env +120 -0
- package/template/biome.json +63 -0
- package/template/components.json +21 -0
- package/template/db/init.sh +89 -0
- package/template/db/sql/00_drop.sql +2 -0
- package/template/db/sql/01_users.sql +31 -0
- package/template/db/sql/02_todos.sql +20 -0
- package/template/docker/Dockerfile +13 -0
- package/template/docker/docker-compose.yaml +79 -0
- package/template/gitignore +42 -0
- package/template/jsconfig.json +18 -0
- package/template/package.json +88 -0
- package/template/postcss.config.js +9 -0
- package/template/src/cli/App.jsx +25 -0
- package/template/src/cli/components/JsonTreeViewer.jsx +128 -0
- package/template/src/cli/components/shadcn-io/spinner/index.jsx +232 -0
- package/template/src/cli/components/stepper.jsx +408 -0
- package/template/src/cli/components/ui/avatar.jsx +36 -0
- package/template/src/cli/components/ui/badge.jsx +31 -0
- package/template/src/cli/components/ui/breadcrumb.jsx +97 -0
- package/template/src/cli/components/ui/card.jsx +73 -0
- package/template/src/cli/components/ui/collapsible.jsx +16 -0
- package/template/src/cli/components/ui/dropdown-menu.jsx +179 -0
- package/template/src/cli/components/ui/field.jsx +217 -0
- package/template/src/cli/components/ui/input.jsx +19 -0
- package/template/src/cli/components/ui/label.jsx +17 -0
- package/template/src/cli/components/ui/pagination.jsx +99 -0
- package/template/src/cli/components/ui/patched/alert.jsx +56 -0
- package/template/src/cli/components/ui/patched/button.jsx +45 -0
- package/template/src/cli/components/ui/patched/dialog.jsx +114 -0
- package/template/src/cli/components/ui/patched/sidebar.jsx +660 -0
- package/template/src/cli/components/ui/select.jsx +141 -0
- package/template/src/cli/components/ui/separator.jsx +21 -0
- package/template/src/cli/components/ui/sheet.jsx +115 -0
- package/template/src/cli/components/ui/skeleton.jsx +13 -0
- package/template/src/cli/components/ui/sonner.jsx +22 -0
- package/template/src/cli/components/ui/switch.jsx +25 -0
- package/template/src/cli/components/ui/table.jsx +88 -0
- package/template/src/cli/components/ui/textarea.jsx +16 -0
- package/template/src/cli/components/ui/tooltip.jsx +45 -0
- package/template/src/cli/config/store_keys.mjs +2 -0
- package/template/src/cli/context/data/DataContext.jsx +5 -0
- package/template/src/cli/context/data/DataProvider.jsx +44 -0
- package/template/src/cli/context/data/useBreads.mjs +15 -0
- package/template/src/cli/context/data/useDataContext.mjs +4 -0
- package/template/src/cli/context/session/SessionContext.mjs +4 -0
- package/template/src/cli/context/session/SessionProvider.jsx +31 -0
- package/template/src/cli/context/session/makePermissioner.mjs +34 -0
- package/template/src/cli/context/session/useSessionContext.mjs +6 -0
- package/template/src/cli/context/theme/ThemeContext.mjs +4 -0
- package/template/src/cli/context/theme/ThemeProvider.jsx +49 -0
- package/template/src/cli/context/theme/useThemeContext.mjs +6 -0
- package/template/src/cli/context/ui/UIContext.jsx +5 -0
- package/template/src/cli/context/ui/UIProvider.jsx +16 -0
- package/template/src/cli/context/ui/useUIContext.mjs +4 -0
- package/template/src/cli/context/util.mjs +17 -0
- package/template/src/cli/entry-cli.jsx +33 -0
- package/template/src/cli/hooks/useIsMobile.mjs +19 -0
- package/template/src/cli/hooks/useStoragedState.mjs +63 -0
- package/template/src/cli/index.html +29 -0
- package/template/src/cli/layout/app-sidebar.jsx +25 -0
- package/template/src/cli/layout/main-layout.jsx +63 -0
- package/template/src/cli/layout/nav-last-todos.jsx +72 -0
- package/template/src/cli/layout/nav-main.jsx +39 -0
- package/template/src/cli/layout/nav-user.jsx +105 -0
- package/template/src/cli/layout/prop-switcher.jsx +93 -0
- package/template/src/cli/lib/utils.mjs +10 -0
- package/template/src/cli/pages/Index.jsx +13 -0
- package/template/src/cli/pages/IndexOffline.jsx +13 -0
- package/template/src/cli/pages/IndexOnline.jsx +18 -0
- package/template/src/cli/pages/dash/Dashboard.jsx +29 -0
- package/template/src/cli/pages/offline/Login.jsx +43 -0
- package/template/src/cli/pages/offline/LoginForm.jsx +115 -0
- package/template/src/cli/pages/security/Security.jsx +39 -0
- package/template/src/cli/pages/security/SecurityForm.jsx +106 -0
- package/template/src/cli/pages/todos/TodoActions.jsx +99 -0
- package/template/src/cli/pages/todos/TodoAdd.jsx +43 -0
- package/template/src/cli/pages/todos/TodoList.jsx +60 -0
- package/template/src/cli/pages/todos/Todos.jsx +23 -0
- package/template/src/cli/pages/todos/context/TodosContext.jsx +5 -0
- package/template/src/cli/pages/todos/context/TodosProvider.jsx +191 -0
- package/template/src/cli/pages/todos/context/useTodosContext.mjs +4 -0
- package/template/src/ns/models/Todo.mjs +29 -0
- package/template/src/ns/models/TodoList.mjs +8 -0
- package/template/src/ns/models/User.mjs +40 -0
- package/template/src/server/bot/check_today.mjs +10 -0
- package/template/src/server/io/cache/base.mjs +21 -0
- package/template/src/server/io/db/filter.mjs +92 -0
- package/template/src/server/io/db/todos/delete.mjs +29 -0
- package/template/src/server/io/db/todos/find.mjs +13 -0
- package/template/src/server/io/db/todos/read.mjs +83 -0
- package/template/src/server/io/db/todos/toggle.mjs +37 -0
- package/template/src/server/io/db/todos/upsave.mjs +32 -0
- package/template/src/server/io/db/triggers/user.mjs +13 -0
- package/template/src/server/io/db/users/auth.mjs +132 -0
- package/template/src/server/io/db/users/pwd.mjs +38 -0
- package/template/src/server/io/db/users/save.mjs +17 -0
- package/template/src/server/miolo/auth/basic.mjs +15 -0
- package/template/src/server/miolo/auth/guest.mjs +3 -0
- package/template/src/server/miolo/auth/passport.mjs +73 -0
- package/template/src/server/miolo/cache.mjs +11 -0
- package/template/src/server/miolo/cron/foo.mjs +7 -0
- package/template/src/server/miolo/cron/index.mjs +28 -0
- package/template/src/server/miolo/cron/invalidate.mjs +21 -0
- package/template/src/server/miolo/db.mjs +36 -0
- package/template/src/server/miolo/http.mjs +14 -0
- package/template/src/server/miolo/index.mjs +43 -0
- package/template/src/server/miolo/routes/crud.mjs +16 -0
- package/template/src/server/miolo/routes/index.mjs +8 -0
- package/template/src/server/miolo/ssr/entry-server.jsx +13 -0
- package/template/src/server/miolo/ssr/loader.mjs +18 -0
- package/template/src/server/routes/index.mjs +66 -0
- package/template/src/server/routes/todos/mod.mjs +52 -0
- package/template/src/server/routes/todos/read.mjs +45 -0
- package/template/src/server/routes/todos/special.mjs +47 -0
- package/template/src/server/routes/users/user.mjs +54 -0
- package/template/src/server/server.mjs +10 -0
- package/template/src/server/utils/crypt.mjs +38 -0
- package/template/src/server/utils/io.mjs +15 -0
- package/template/src/server/utils/pwdfor.mjs +25 -0
- package/template/src/server/utils/schema.mjs +22 -0
- package/template/src/static/img/default/profile.png +0 -0
- package/template/src/static/img/favicon.ico +0 -0
- package/template/src/static/img/miolo_logo.png +0 -0
- package/template/src/static/img/miolo_name.png +0 -0
- package/template/src/static/public/manifest.json +21 -0
- package/template/src/static/public/sw.js +79 -0
- package/template/src/static/style/globals.css +156 -0
- package/template/src/static/style/json-tree.css +54 -0
- package/template/src/static/style/skeleton.css +49 -0
- package/bin/prod-build/build-client.mjs +0 -67
- package/bin/prod-build/build-server.mjs +0 -58
- package/bin/prod-run/restart.mjs +0 -9
- package/bin/prod-run/start.mjs +0 -15
- package/bin/prod-run/stop.mjs +0 -20
- package/src/engines/logger/verify.mjs +0 -22
- package/src/middleware/auth/credentials/index.mjs +0 -151
- package/src/middleware/auth/credentials/session/index.mjs +0 -24
- package/src/middleware/auth/credentials/session/store_koa_redis.mjs +0 -3
|
@@ -1,66 +1,61 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import {Reader} from
|
|
1
|
+
import fs from "node:fs"
|
|
2
|
+
import { Reader } from "@maxmind/geoip2-node"
|
|
3
3
|
|
|
4
|
-
let _geoip_reader
|
|
4
|
+
let _geoip_reader
|
|
5
5
|
|
|
6
|
-
const _geoip_def_local_ips= [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
const _geoip_def_local_ips = [
|
|
7
|
+
"127.0.0.1",
|
|
8
|
+
"::1:",
|
|
9
|
+
"172.19.0.1" // Docker inner - probably healthcheck
|
|
10
10
|
]
|
|
11
11
|
|
|
12
12
|
function _geoip_is_local(ip, local_ips = []) {
|
|
13
13
|
// if (process.env.NODE_ENV == 'development') {
|
|
14
14
|
// return true
|
|
15
15
|
// }
|
|
16
|
-
|
|
17
|
-
const all_local_ips = [
|
|
18
|
-
..._geoip_def_local_ips,
|
|
19
|
-
...local_ips || []
|
|
20
|
-
]
|
|
16
|
+
|
|
17
|
+
const all_local_ips = [..._geoip_def_local_ips, ...(local_ips || [])]
|
|
21
18
|
return all_local_ips.indexOf(ip) >= 0
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
function _geoip_init(db = '/var/lib/GeoIP/GeoLite2-City.mmdb', logger= console) {
|
|
21
|
+
function _geoip_init(db = "/var/lib/GeoIP/GeoLite2-City.mmdb", logger = console) {
|
|
27
22
|
try {
|
|
28
|
-
if (_geoip_reader
|
|
23
|
+
if (_geoip_reader !== undefined) {
|
|
29
24
|
return _geoip_reader
|
|
30
25
|
}
|
|
31
26
|
const dbBuffer = fs.readFileSync(db)
|
|
32
27
|
_geoip_reader = Reader.openBuffer(dbBuffer)
|
|
33
28
|
return _geoip_reader
|
|
34
|
-
} catch(error) {
|
|
29
|
+
} catch (error) {
|
|
35
30
|
logger.error(`[geoip] Error initing:`)
|
|
36
31
|
logger.error(error)
|
|
37
32
|
return undefined
|
|
38
33
|
}
|
|
39
34
|
}
|
|
40
35
|
|
|
41
|
-
export const geoip_localize_ip= (ip, config, logger= console) => {
|
|
36
|
+
export const geoip_localize_ip = (ip, config, logger = console) => {
|
|
42
37
|
if (_geoip_is_local(ip, config?.local_ips)) {
|
|
43
38
|
return {
|
|
44
39
|
local: true,
|
|
45
|
-
country:
|
|
46
|
-
city:
|
|
47
|
-
}
|
|
40
|
+
country: "",
|
|
41
|
+
city: ""
|
|
42
|
+
}
|
|
48
43
|
}
|
|
49
44
|
|
|
50
45
|
try {
|
|
51
46
|
const reader = _geoip_init(config?.db, logger)
|
|
52
|
-
const resp= reader.city(ip)
|
|
47
|
+
const resp = reader.city(ip)
|
|
53
48
|
return {
|
|
54
49
|
country: resp.country.isoCode,
|
|
55
|
-
city
|
|
50
|
+
city: resp.city?.names?.en
|
|
56
51
|
}
|
|
57
|
-
} catch(
|
|
52
|
+
} catch (_) {
|
|
58
53
|
logger.error(`[geoip] Error localizing IP ${ip} (not in the database)`)
|
|
59
|
-
//logger.error(
|
|
54
|
+
//logger.error(_)
|
|
60
55
|
}
|
|
61
56
|
|
|
62
57
|
return {
|
|
63
|
-
country:
|
|
64
|
-
city:
|
|
65
|
-
}
|
|
58
|
+
country: "",
|
|
59
|
+
city: ""
|
|
60
|
+
}
|
|
66
61
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import http
|
|
1
|
+
import http from "node:http"
|
|
2
|
+
import https from "node:https"
|
|
2
3
|
//import util from 'util'
|
|
3
|
-
import { createHttpTerminator }
|
|
4
|
-
|
|
4
|
+
import { createHttpTerminator } from "http-terminator"
|
|
5
5
|
|
|
6
6
|
// promisify the server.listen()
|
|
7
7
|
|
|
@@ -25,30 +25,41 @@ const _listenAsync = (server, port, hostname) => {
|
|
|
25
25
|
|
|
26
26
|
export function init_http_server(app, config) {
|
|
27
27
|
const miolo = app.context.miolo
|
|
28
|
-
const logger= miolo.logger
|
|
28
|
+
const logger = miolo.logger
|
|
29
29
|
|
|
30
30
|
const _http_start = async () => {
|
|
31
31
|
try {
|
|
32
32
|
// If previous server already created, lets avoid
|
|
33
|
-
if (app.http?.server
|
|
34
|
-
logger.warn(
|
|
33
|
+
if (app.http?.server !== undefined) {
|
|
34
|
+
logger.warn(
|
|
35
|
+
`[http][start] Server already running on ${app?.http?.hostname}:${app?.http?.port}`
|
|
36
|
+
)
|
|
35
37
|
return
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
// Init server
|
|
39
|
-
const server =
|
|
41
|
+
const server =
|
|
42
|
+
config?.ssl === undefined
|
|
43
|
+
? http.createServer(app.callback())
|
|
44
|
+
: https
|
|
45
|
+
.createServer(config.ssl, app.callback())
|
|
46
|
+
.listen(config.port, config.hostname, () => {
|
|
47
|
+
logger.info("[http][start] Server running at https://localhost:8010")
|
|
48
|
+
})
|
|
40
49
|
|
|
41
50
|
// Init terminator
|
|
42
51
|
const httpTerminator = createHttpTerminator({
|
|
43
|
-
server
|
|
52
|
+
server
|
|
44
53
|
})
|
|
45
54
|
|
|
46
55
|
const http_stop = async () => {
|
|
47
56
|
try {
|
|
48
57
|
await httpTerminator.terminate()
|
|
49
58
|
delete app.http.server
|
|
50
|
-
logger.info(
|
|
51
|
-
|
|
59
|
+
logger.info(
|
|
60
|
+
`[http][stop] miolo has been shutdowned from ${config.hostname}:${config.port}`
|
|
61
|
+
)
|
|
62
|
+
} catch (error) {
|
|
52
63
|
logger.error(`[http][stop] error: ${error}`)
|
|
53
64
|
}
|
|
54
65
|
}
|
|
@@ -59,21 +70,21 @@ export function init_http_server(app, config) {
|
|
|
59
70
|
// Finally start the server
|
|
60
71
|
await _listenAsync(server, config.port, config.hostname)
|
|
61
72
|
logger.info(`[http][start] miolo is listening on ${config.hostname}:${config.port}`)
|
|
62
|
-
} catch(error) {
|
|
73
|
+
} catch (error) {
|
|
63
74
|
logger.error(`[http][start] error: ${error}`)
|
|
64
75
|
}
|
|
65
|
-
}
|
|
76
|
+
}
|
|
66
77
|
|
|
67
78
|
// Attach objects to app
|
|
68
79
|
app.http = {
|
|
69
80
|
server: undefined,
|
|
70
81
|
start: _http_start,
|
|
71
82
|
stop: async () => {
|
|
72
|
-
logger.warn(`[http] stop()
|
|
83
|
+
logger.warn(`[http] stop() function still not attached. Is server running?`)
|
|
73
84
|
},
|
|
74
85
|
hostname: config.hostname,
|
|
75
86
|
port: config.port
|
|
76
|
-
}
|
|
87
|
+
}
|
|
77
88
|
|
|
78
89
|
return app
|
|
79
|
-
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import os from "node:os"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Genera un cuerpo de email HTML a partir del objeto info de Winston.
|
|
5
|
+
* @param {Object} info - El objeto info transformado por Winston.
|
|
6
|
+
* @returns {String} HTML string.
|
|
7
|
+
*/
|
|
8
|
+
export default function buildErrorEmailBody(info) {
|
|
9
|
+
// 1. Extraemos propiedades estándar y conocidas
|
|
10
|
+
const { timestamp, level, message, stack, ...metadata } = info
|
|
11
|
+
|
|
12
|
+
// 2. Preparamos el Stack Trace (si existe)
|
|
13
|
+
// Nota: Winston solo tiene 'stack' si usas format.errors({ stack: true })
|
|
14
|
+
const stackHtml = stack
|
|
15
|
+
? `<div style="margin-top: 20px;">
|
|
16
|
+
<h3 style="color: #d9534f;">Stack Trace</h3>
|
|
17
|
+
<pre style="background: #f4f4f4; padding: 10px; border: 1px solid #ddd; overflow-x: auto; font-size: 12px; font-family: monospace;">${stack}</pre>
|
|
18
|
+
</div>`
|
|
19
|
+
: "<p><em>No stack trace available (Log was likely a string or logical error).</em></p>"
|
|
20
|
+
|
|
21
|
+
// 3. Preparamos los Metadatos (el resto de propiedades en info)
|
|
22
|
+
// Esto es vital en Koa para ver requestId, url, method, etc.
|
|
23
|
+
const metaRows = Object.entries(metadata)
|
|
24
|
+
.map(([key, value]) => {
|
|
25
|
+
// Si el valor es un objeto complejo, lo pasamos a string
|
|
26
|
+
const displayValue =
|
|
27
|
+
typeof value === "object"
|
|
28
|
+
? `<pre style="margin: 0;">${JSON.stringify(value, null, 2)}</pre>`
|
|
29
|
+
: value
|
|
30
|
+
|
|
31
|
+
return `
|
|
32
|
+
<tr>
|
|
33
|
+
<td style="padding: 8px; border-bottom: 1px solid #ddd; font-weight: bold; width: 30%;">${key}</td>
|
|
34
|
+
<td style="padding: 8px; border-bottom: 1px solid #ddd;">${displayValue}</td>
|
|
35
|
+
</tr>
|
|
36
|
+
`
|
|
37
|
+
})
|
|
38
|
+
.join("")
|
|
39
|
+
|
|
40
|
+
const metadataHtml =
|
|
41
|
+
metaRows.length > 0
|
|
42
|
+
? `<div style="margin-top: 20px;">
|
|
43
|
+
<h3>Metadata / Context</h3>
|
|
44
|
+
<table style="width: 100%; border-collapse: collapse; font-family: sans-serif; font-size: 14px;">
|
|
45
|
+
${metaRows}
|
|
46
|
+
</table>
|
|
47
|
+
</div>`
|
|
48
|
+
: ""
|
|
49
|
+
|
|
50
|
+
// 4. Construcción final del HTML
|
|
51
|
+
return `
|
|
52
|
+
<div style="font-family: Arial, sans-serif; color: #333; line-height: 1.6;">
|
|
53
|
+
<h2 style="background-color: #ca7d7bff; color: white; padding: 10px;">🚨 Error at [${process.env.MIOLO_NAME || "miolo"}]</h2>
|
|
54
|
+
|
|
55
|
+
<div style="padding: 10px; border: 1px solid #ddd; background-color: #fff9f9;">
|
|
56
|
+
<strong>Message:</strong> <span style="font-size: 1.2em;">${message
|
|
57
|
+
.split("\n")
|
|
58
|
+
.map((l) => `<div>${l}</div>`)
|
|
59
|
+
.join("\n")}</span><br>
|
|
60
|
+
<strong>Time:</strong> ${timestamp || new Date().toISOString()}<br>
|
|
61
|
+
<strong>Server:</strong> ${os.hostname()}
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
${stackHtml}
|
|
65
|
+
${metadataHtml}
|
|
66
|
+
|
|
67
|
+
<div style="margin-top: 30px; font-size: 12px; color: #777; border-top: 1px solid #eee; padding-top: 10px;">
|
|
68
|
+
Sent automatically by <strong>miolo</strong> logger.
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
`
|
|
72
|
+
}
|
|
@@ -1,67 +1,66 @@
|
|
|
1
1
|
// import fs from 'fs'
|
|
2
2
|
// import path from 'path'
|
|
3
|
-
import {
|
|
3
|
+
import { blue, blue_light, cyan, magenta, red, yellow } from "tinguir"
|
|
4
|
+
import { createLogger, format, transports } from "winston"
|
|
5
|
+
import injectStackTrace from "./injectStackTrace.mjs"
|
|
4
6
|
/* https://github.com/winstonjs/winston/issues/925 */
|
|
5
7
|
/* https://github.com/winstonjs/winston/issues/287 */
|
|
6
|
-
import {init_logger_to_mail} from
|
|
7
|
-
import {
|
|
8
|
-
|
|
8
|
+
import { init_logger_to_mail } from "./logger_mail.mjs"
|
|
9
|
+
import { reopenTransportOnHupSignal } from "./reopenTransportOnHupSignal.mjs"
|
|
10
|
+
|
|
9
11
|
// import 'winston-daily-rotate-file'
|
|
10
12
|
// import { /*intre_to_str,*/ intre_now } from 'intre'
|
|
11
13
|
|
|
12
14
|
const { combine, timestamp, _label, printf, errors } = format
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
silly : gray,
|
|
19
|
-
debug : magenta,
|
|
16
|
+
const init_logger = (config, emailer, prefix = "miolo") => {
|
|
17
|
+
const LEVEL_COLORS = {
|
|
18
|
+
silly: blue_light,
|
|
19
|
+
debug: blue,
|
|
20
20
|
verbose: cyan,
|
|
21
|
-
info
|
|
22
|
-
warn
|
|
23
|
-
error
|
|
21
|
+
info: magenta,
|
|
22
|
+
warn: yellow,
|
|
23
|
+
error: red
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const LEVEL_ABBRV= {
|
|
27
|
-
silly
|
|
28
|
-
debug
|
|
29
|
-
verbose:
|
|
30
|
-
info
|
|
31
|
-
warn
|
|
32
|
-
error
|
|
26
|
+
const LEVEL_ABBRV = {
|
|
27
|
+
silly: "sly",
|
|
28
|
+
debug: "dbg",
|
|
29
|
+
verbose: "vbs",
|
|
30
|
+
info: "inf",
|
|
31
|
+
warn: "wrn",
|
|
32
|
+
error: "err"
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
const _INDENT_SIZE = 4
|
|
36
36
|
let _INDENT = 0
|
|
37
|
-
|
|
37
|
+
const _SECTIONS = {}
|
|
38
38
|
|
|
39
|
-
const myFormat = info => {
|
|
39
|
+
const myFormat = (info) => {
|
|
40
40
|
const lc = LEVEL_COLORS[info.level]
|
|
41
41
|
const tm = new Date(info.timestamp)
|
|
42
|
-
const ts= tm.toLocaleString(config?.format?.locale ||
|
|
43
|
-
|
|
42
|
+
const ts = tm.toLocaleString(config?.format?.locale || "en")
|
|
43
|
+
const sindent = "".padStart(_INDENT, " ")
|
|
44
44
|
//const ts= tm.toString().substr(4, 20)
|
|
45
|
-
const log= `[${prefix}] ${lc(ts)} ${lc(LEVEL_ABBRV[info.level])} ${sindent}${info.message}`
|
|
46
|
-
return info.stack
|
|
47
|
-
? `${log}\n${info.stack}`
|
|
48
|
-
: log
|
|
45
|
+
const log = `[${prefix}] ${lc(ts)} ${lc(LEVEL_ABBRV[info.level])} ${sindent}${info.message}`
|
|
46
|
+
return info.stack ? `${log}\n${info.stack}` : log
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
|
|
49
|
+
const _log_transports = []
|
|
52
50
|
//
|
|
53
51
|
// Console transport
|
|
54
52
|
// If we're not in production then log to the `console` with the format:
|
|
55
53
|
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
|
|
56
|
-
//
|
|
54
|
+
//
|
|
57
55
|
|
|
58
56
|
if (config?.console?.enabled === true) {
|
|
59
57
|
_log_transports.push(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
new transports.Console({
|
|
59
|
+
humanReadableUnhandledException: true,
|
|
60
|
+
level: config?.console?.level || config?.level || "silly",
|
|
61
|
+
handleExceptions: true
|
|
62
|
+
})
|
|
63
|
+
)
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
//
|
|
@@ -72,62 +71,60 @@ const init_logger = (config, emailer, prefix= 'miolo') => {
|
|
|
72
71
|
// https://gist.github.com/suprememoocow/5133080
|
|
73
72
|
//
|
|
74
73
|
if (config?.file?.enabled === true) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
:
|
|
80
|
-
level : config?.file?.level || config?.level || 'info' ,
|
|
74
|
+
const fileTransport = new transports.File({
|
|
75
|
+
filename: config?.file?.filename
|
|
76
|
+
? config.file.filename.replace("%MIOLO%", prefix)
|
|
77
|
+
: "/var/log/afialapis/miolo.log",
|
|
78
|
+
level: config?.file?.level || config?.level || "info",
|
|
81
79
|
humanReadableUnhandledException: true,
|
|
82
80
|
handleExceptions: true,
|
|
83
81
|
maxRetries: 10
|
|
84
82
|
})
|
|
85
|
-
|
|
83
|
+
|
|
86
84
|
if (config?.file?.hup_patch === true) {
|
|
87
85
|
reopenTransportOnHupSignal(fileTransport)
|
|
88
86
|
}
|
|
89
87
|
|
|
90
88
|
_log_transports.push(fileTransport)
|
|
91
89
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
//
|
|
90
|
+
// const _file_log = (s) => {
|
|
91
|
+
// const filename = path.join(fileTransport.dirname, fileTransport.filename)
|
|
92
|
+
//
|
|
93
|
+
// // console.log(fileTransport._stream )
|
|
94
|
+
// const msg = myFormat({
|
|
95
|
+
// level: 'info',
|
|
96
|
+
// message: `[logger][file-rotate] ${s}\n`,
|
|
97
|
+
// timestamp: intre_now()
|
|
98
|
+
// })
|
|
99
|
+
//
|
|
100
|
+
// try {
|
|
101
|
+
// fs.accessSync(filename, fs.constants.F_OK)
|
|
102
|
+
// fs.appendFileSync(filename, msg)
|
|
103
|
+
// } catch(_) {
|
|
104
|
+
// fs.writeFileSync(filename, msg, { encoding: 'utf-8' })
|
|
105
|
+
// }
|
|
106
|
+
// if (config?.console?.enabled === true) {
|
|
107
|
+
// if (fileTransport.levels[config?.console?.level || config?.level || 'error'] >= fileTransport.levels['info']) {
|
|
108
|
+
// console.log(msg)
|
|
109
|
+
// }
|
|
110
|
+
// }
|
|
111
|
+
// }
|
|
112
|
+
//
|
|
113
|
+
// fileTransport.on('finish', function(info) {
|
|
114
|
+
// // do something fun
|
|
115
|
+
// _file_log('Log done')
|
|
116
|
+
// })
|
|
117
|
+
// fileTransport.on('error', function(error) {
|
|
118
|
+
// // do something fun
|
|
119
|
+
// _file_log(red(`Error: ${error}`))
|
|
120
|
+
// })
|
|
121
|
+
//
|
|
125
122
|
}
|
|
126
123
|
|
|
127
124
|
// if (config?.file?.enabled === true) {
|
|
128
125
|
// const datePattern = config?.file?.datePattern || 'YYYY-MM-DD'
|
|
129
126
|
//
|
|
130
|
-
// const fileTransport = new transports.DailyRotateFile({
|
|
127
|
+
// const fileTransport = new transports.DailyRotateFile({
|
|
131
128
|
// level : config?.file?.level || config?.level || 'info' ,
|
|
132
129
|
//
|
|
133
130
|
// frequency: config?.file?.frequency,
|
|
@@ -135,21 +132,21 @@ const init_logger = (config, emailer, prefix= 'miolo') => {
|
|
|
135
132
|
// zippedArchive: config?.file?.zippedArchive == true,
|
|
136
133
|
// maxSize: config?.file?.maxSize || '20m',
|
|
137
134
|
// maxFiles: config?.file?.maxFiles || '10d',
|
|
138
|
-
//
|
|
139
|
-
// filename : config?.file?.filename
|
|
135
|
+
//
|
|
136
|
+
// filename : config?.file?.filename
|
|
140
137
|
// ? config.file.filename.replace('%MIOLO%', prefix)
|
|
141
|
-
// : '/var/log/afialapis/miolo.%DATE%.log',
|
|
142
|
-
//
|
|
138
|
+
// : '/var/log/afialapis/miolo.%DATE%.log',
|
|
139
|
+
//
|
|
143
140
|
// auditFile: config?.file?.auditFile
|
|
144
141
|
// ? config.file.auditFile.replace('%MIOLO%', prefix)
|
|
145
142
|
// : '/var/log/afialapis/miolo.audit.json',
|
|
146
|
-
//
|
|
143
|
+
//
|
|
147
144
|
// symlinkName: config?.file?.symlinkName
|
|
148
145
|
// ? config.file.symlinkName.replace('%MIOLO%', prefix)
|
|
149
146
|
// : 'miolo.log',
|
|
150
147
|
//
|
|
151
148
|
// createSymlink: config?.file?.createSymlink == true,
|
|
152
|
-
//
|
|
149
|
+
//
|
|
153
150
|
// watchLog: true,
|
|
154
151
|
//
|
|
155
152
|
// humanReadableUnhandledException: true,
|
|
@@ -159,7 +156,7 @@ const init_logger = (config, emailer, prefix= 'miolo') => {
|
|
|
159
156
|
// const _file_log = (s) => {
|
|
160
157
|
// const currentDate = intre_to_str(intre_now(), datePattern)
|
|
161
158
|
// const filename = path.join(fileTransport.dirname, fileTransport.filename.replace('%DATE%', currentDate))
|
|
162
|
-
//
|
|
159
|
+
//
|
|
163
160
|
// const msg = myFormat({
|
|
164
161
|
// level: 'info',
|
|
165
162
|
// message: `[logger][file-rotate] ${s}\n`,
|
|
@@ -205,19 +202,18 @@ const init_logger = (config, emailer, prefix= 'miolo') => {
|
|
|
205
202
|
// _log_transports.push(fileTransport)
|
|
206
203
|
// }
|
|
207
204
|
|
|
208
|
-
|
|
209
205
|
// if (config?.file?.enabled === true) {
|
|
210
|
-
// const fileTransport = new transports.File({
|
|
206
|
+
// const fileTransport = new transports.File({
|
|
211
207
|
// level : config?.file?.level || config?.level || 'info' ,
|
|
212
208
|
//
|
|
213
209
|
// zippedArchive: config?.file?.zippedArchive == true,
|
|
214
210
|
// maxsize: config?.file?.maxsize || (1024 * 1024 * 20),
|
|
215
211
|
// maxFiles: config?.file?.maxFiles || 20,
|
|
216
|
-
// //
|
|
217
|
-
// filename : config?.file?.filename
|
|
212
|
+
// //
|
|
213
|
+
// filename : config?.file?.filename
|
|
218
214
|
// ? config.file.filename.replace('%MIOLO%', prefix)
|
|
219
|
-
// : '/var/log/afialapis/miolo.log',
|
|
220
|
-
// //
|
|
215
|
+
// : '/var/log/afialapis/miolo.log',
|
|
216
|
+
// //
|
|
221
217
|
//
|
|
222
218
|
// humanReadableUnhandledException: true,
|
|
223
219
|
// handleExceptions: true,
|
|
@@ -225,22 +221,21 @@ const init_logger = (config, emailer, prefix= 'miolo') => {
|
|
|
225
221
|
// tailable: true,
|
|
226
222
|
//
|
|
227
223
|
// })
|
|
228
|
-
//
|
|
224
|
+
//
|
|
229
225
|
// _log_transports.push(fileTransport)
|
|
230
226
|
// }
|
|
231
227
|
|
|
232
|
-
|
|
233
228
|
//
|
|
234
229
|
// Mail transport
|
|
235
230
|
//
|
|
236
|
-
if (config?.mail?.enabled === true) {
|
|
237
|
-
const MailerLogger= init_logger_to_mail(config.mail, emailer)
|
|
231
|
+
if (emailer && config?.mail?.enabled === true) {
|
|
232
|
+
const MailerLogger = init_logger_to_mail(config.mail, emailer)
|
|
238
233
|
transports.MailerLogger = MailerLogger
|
|
239
234
|
|
|
240
235
|
_log_transports.push(
|
|
241
236
|
new transports.MailerLogger({
|
|
242
237
|
humanReadableUnhandledException: true,
|
|
243
|
-
handleExceptions: true
|
|
238
|
+
handleExceptions: true
|
|
244
239
|
})
|
|
245
240
|
)
|
|
246
241
|
}
|
|
@@ -249,12 +244,8 @@ const init_logger = (config, emailer, prefix= 'miolo') => {
|
|
|
249
244
|
// Logger
|
|
250
245
|
//
|
|
251
246
|
const logger = createLogger({
|
|
252
|
-
level: config?.level ||
|
|
253
|
-
format: combine(
|
|
254
|
-
errors({ stack: true }),
|
|
255
|
-
timestamp(),
|
|
256
|
-
printf(myFormat)
|
|
257
|
-
),
|
|
247
|
+
level: config?.level || "silly",
|
|
248
|
+
format: combine(errors({ stack: true }), injectStackTrace(), timestamp(), printf(myFormat)),
|
|
258
249
|
transports: _log_transports
|
|
259
250
|
})
|
|
260
251
|
|
|
@@ -262,52 +253,53 @@ const init_logger = (config, emailer, prefix= 'miolo') => {
|
|
|
262
253
|
const _indented_func = (text, opts) => {
|
|
263
254
|
try {
|
|
264
255
|
if (opts?.section) {
|
|
265
|
-
if (!
|
|
256
|
+
if (!(opts.section in _SECTIONS)) {
|
|
266
257
|
// Section starts
|
|
267
|
-
_SECTIONS[opts.section]= {
|
|
268
|
-
indentIncr: parseInt(opts?.indent || _INDENT_SIZE),
|
|
258
|
+
_SECTIONS[opts.section] = {
|
|
259
|
+
indentIncr: parseInt(opts?.indent || _INDENT_SIZE, 10),
|
|
269
260
|
timeStart: Date.now()
|
|
270
261
|
}
|
|
271
262
|
const nIndent = Math.max(_INDENT + _SECTIONS[opts.section].indentIncr, 0)
|
|
272
263
|
f(text, opts)
|
|
273
|
-
_INDENT= nIndent
|
|
274
|
-
|
|
264
|
+
_INDENT = nIndent
|
|
275
265
|
} else {
|
|
276
266
|
// Section ends
|
|
277
|
-
const elapsed = parseFloat(
|
|
267
|
+
const elapsed = parseFloat(
|
|
268
|
+
(Date.now() - _SECTIONS[opts.section].timeStart) / 1000.0
|
|
269
|
+
).toFixed(2)
|
|
278
270
|
text = `${text} (time: ${elapsed})`
|
|
279
|
-
_INDENT-= _SECTIONS[opts.section].indentIncr
|
|
271
|
+
_INDENT -= _SECTIONS[opts.section].indentIncr
|
|
280
272
|
f(text, opts)
|
|
281
|
-
delete _SECTIONS[opts.section]
|
|
273
|
+
delete _SECTIONS[opts.section]
|
|
282
274
|
}
|
|
283
275
|
} else {
|
|
284
276
|
f(text, opts)
|
|
285
277
|
}
|
|
286
|
-
} catch(error) {
|
|
278
|
+
} catch (error) {
|
|
287
279
|
// TODO - How to exxpose info from here
|
|
288
280
|
console.error(error)
|
|
289
|
-
|
|
290
281
|
}
|
|
291
282
|
}
|
|
292
|
-
Object.defineProperty(_indented_func, "name", { value: name })
|
|
283
|
+
Object.defineProperty(_indented_func, "name", { value: name })
|
|
293
284
|
return _indented_func
|
|
294
285
|
}
|
|
295
286
|
|
|
296
|
-
logger.error
|
|
297
|
-
logger.warn
|
|
298
|
-
logger.info
|
|
299
|
-
logger.http
|
|
300
|
-
logger.verbose = _make_indented_log(logger.verbose,
|
|
301
|
-
logger.debug
|
|
302
|
-
logger.silly
|
|
287
|
+
logger.error = _make_indented_log(logger.error, "error")
|
|
288
|
+
logger.warn = _make_indented_log(logger.warn, "warn")
|
|
289
|
+
logger.info = _make_indented_log(logger.info, "info")
|
|
290
|
+
logger.http = _make_indented_log(logger.http, "http")
|
|
291
|
+
logger.verbose = _make_indented_log(logger.verbose, "verbose")
|
|
292
|
+
logger.debug = _make_indented_log(logger.debug, "debug")
|
|
293
|
+
logger.silly = _make_indented_log(logger.silly, "silly")
|
|
303
294
|
|
|
304
295
|
//console.log(logger.transports[0])
|
|
305
296
|
try {
|
|
306
|
-
logger.debug(
|
|
307
|
-
|
|
297
|
+
logger.debug(
|
|
298
|
+
`[logger] Inited for ${logger.transports.map((t) => `${t.name} (${t.level})${t.silent ? red(" SILENT!") : ""}`).join(",")}`
|
|
299
|
+
)
|
|
300
|
+
} catch (_) {}
|
|
308
301
|
|
|
309
302
|
return logger
|
|
310
303
|
}
|
|
311
304
|
|
|
312
|
-
|
|
313
|
-
export {init_logger}
|
|
305
|
+
export { init_logger }
|