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.
Files changed (246) hide show
  1. package/bin/build/build.mjs +53 -0
  2. package/bin/build/build_bin.mjs +17 -0
  3. package/bin/build/cli/client.mjs +52 -0
  4. package/bin/build/cli/css.mjs +22 -0
  5. package/bin/build/cli/index.mjs +40 -0
  6. package/bin/build/cli/ssr.mjs +21 -0
  7. package/bin/build/server/aliases.mjs +112 -0
  8. package/bin/build/server/babel.config.js +24 -0
  9. package/bin/build/server/banner.mjs +20 -0
  10. package/bin/build/server/bundle.mjs +111 -0
  11. package/bin/build/server/fix.mjs +15 -0
  12. package/bin/build/server/index.mjs +69 -0
  13. package/bin/build/server/options.mjs +83 -0
  14. package/bin/create/auth.mjs +23 -0
  15. package/bin/create/copy.mjs +175 -0
  16. package/bin/create/docker.mjs +25 -0
  17. package/bin/create/index.mjs +137 -0
  18. package/bin/create/pkgjson.mjs +72 -0
  19. package/bin/create/prepare-template.mjs +158 -0
  20. package/bin/create/validation.mjs +27 -0
  21. package/bin/dev/dev.mjs +32 -23
  22. package/bin/dev/dev_start.mjs +6 -5
  23. package/bin/index.mjs +94 -52
  24. package/bin/prod-bin/create-bin.mjs +42 -27
  25. package/bin/prod-bin/run.mjs +13 -9
  26. package/bin/{prod-run → run}/pid.mjs +4 -4
  27. package/bin/run/restart.mjs +13 -0
  28. package/bin/run/start.mjs +18 -0
  29. package/bin/run/stop.mjs +20 -0
  30. package/bin/util.mjs +35 -11
  31. package/package.json +59 -39
  32. package/src/config/.env +34 -12
  33. package/src/config/defaults.mjs +253 -185
  34. package/src/config/env.mjs +40 -22
  35. package/src/config/index.mjs +19 -24
  36. package/src/config/util.mjs +25 -10
  37. package/src/db-conn.mjs +34 -0
  38. package/src/engines/cron/emails.mjs +10 -5
  39. package/src/engines/cron/index.mjs +45 -51
  40. package/src/engines/cron/init.mjs +16 -17
  41. package/src/engines/cron/ipsum.mjs +65 -60
  42. package/src/engines/cron/syscheck.mjs +30 -30
  43. package/src/engines/emailer/index.mjs +1 -2
  44. package/src/engines/emailer/queue.mjs +14 -20
  45. package/src/engines/emailer/transporter.mjs +86 -74
  46. package/src/engines/geoip/index.mjs +23 -28
  47. package/src/engines/http/index.mjs +26 -15
  48. package/src/engines/logger/buildErrorEmailBody.mjs +72 -0
  49. package/src/engines/logger/index.mjs +114 -122
  50. package/src/engines/logger/injectStackTrace.mjs +59 -0
  51. package/src/engines/logger/logger_mail.mjs +47 -61
  52. package/src/engines/logger/reopenTransportOnHupSignal.mjs +12 -13
  53. package/src/engines/parser/Parser.mjs +77 -60
  54. package/src/engines/parser/index.mjs +1 -1
  55. package/src/engines/schema/diffObjs.mjs +41 -0
  56. package/src/engines/schema/index.mjs +4 -0
  57. package/src/engines/schema/input.mjs +54 -0
  58. package/src/engines/schema/output.mjs +66 -0
  59. package/src/engines/socket/index.mjs +44 -46
  60. package/src/index.mjs +15 -10
  61. package/src/middleware/auth/basic.mjs +41 -40
  62. package/src/middleware/auth/custom.mjs +10 -13
  63. package/src/middleware/auth/guest.mjs +27 -27
  64. package/src/middleware/auth/passport/index.mjs +374 -0
  65. package/src/middleware/auth/passport/session/index.mjs +43 -0
  66. package/src/middleware/auth/{credentials → passport}/session/store.mjs +35 -15
  67. package/src/middleware/auth/passport/session/store_koa_redis.mjs +3 -0
  68. package/src/middleware/context/cache/index.mjs +78 -33
  69. package/src/middleware/context/cache/options.mjs +19 -21
  70. package/src/middleware/context/db.mjs +45 -20
  71. package/src/middleware/context/index.mjs +12 -12
  72. package/src/middleware/extra.mjs +4 -5
  73. package/src/middleware/http/body.mjs +25 -25
  74. package/src/middleware/http/catcher.mjs +81 -8
  75. package/src/middleware/http/custom_blacklist.mjs +19 -16
  76. package/src/middleware/http/headers.mjs +37 -34
  77. package/src/middleware/http/ratelimit.mjs +16 -23
  78. package/src/middleware/http/request.mjs +60 -65
  79. package/src/middleware/routes/catch_js_error.mjs +30 -23
  80. package/src/middleware/routes/robots.mjs +4 -7
  81. package/src/middleware/routes/router/crud/attachCrudRoutes.mjs +108 -90
  82. package/src/middleware/routes/router/crud/getCrudConfig.mjs +31 -55
  83. package/src/middleware/routes/router/defaults.mjs +6 -19
  84. package/src/middleware/routes/router/index.mjs +17 -21
  85. package/src/middleware/routes/router/queries/attachQueriesRoutes.mjs +227 -50
  86. package/src/middleware/routes/router/queries/getQueriesConfig.mjs +45 -55
  87. package/src/middleware/routes/router/utils.mjs +41 -26
  88. package/src/middleware/ssr/context.mjs +5 -7
  89. package/src/middleware/ssr/html.mjs +66 -43
  90. package/src/middleware/ssr/loader.mjs +11 -14
  91. package/src/middleware/ssr/ssr_render.mjs +39 -22
  92. package/src/middleware/static/index.mjs +33 -14
  93. package/src/middleware/vite/devserver.mjs +38 -22
  94. package/src/middleware/vite/watcher.mjs +12 -14
  95. package/src/server-cron.mjs +13 -8
  96. package/src/server-dev.mjs +13 -16
  97. package/src/server.mjs +49 -51
  98. package/template/.agent/skills/miolo-app-arch/SKILL.md +218 -0
  99. package/template/.agent/skills/miolo-auth/SKILL.md +450 -0
  100. package/template/.agent/skills/miolo-cli-router/SKILL.md +394 -0
  101. package/template/.agent/skills/miolo-database/SKILL.md +358 -0
  102. package/template/.agent/skills/miolo-react-patterns/SKILL.md +426 -0
  103. package/template/.agent/skills/miolo-routing/SKILL.md +326 -0
  104. package/template/.agent/skills/miolo-schemas/SKILL.md +329 -0
  105. package/template/.agent/skills/miolo-session-context/SKILL.md +397 -0
  106. package/template/.agent/skills/miolo-ssr/SKILL.md +433 -0
  107. package/template/.editorconfig +18 -0
  108. package/template/.env +120 -0
  109. package/template/biome.json +63 -0
  110. package/template/components.json +21 -0
  111. package/template/db/init.sh +89 -0
  112. package/template/db/sql/00_drop.sql +2 -0
  113. package/template/db/sql/01_users.sql +31 -0
  114. package/template/db/sql/02_todos.sql +20 -0
  115. package/template/docker/Dockerfile +13 -0
  116. package/template/docker/docker-compose.yaml +79 -0
  117. package/template/gitignore +42 -0
  118. package/template/jsconfig.json +18 -0
  119. package/template/package.json +88 -0
  120. package/template/postcss.config.js +9 -0
  121. package/template/src/cli/App.jsx +25 -0
  122. package/template/src/cli/components/JsonTreeViewer.jsx +128 -0
  123. package/template/src/cli/components/shadcn-io/spinner/index.jsx +232 -0
  124. package/template/src/cli/components/stepper.jsx +408 -0
  125. package/template/src/cli/components/ui/avatar.jsx +36 -0
  126. package/template/src/cli/components/ui/badge.jsx +31 -0
  127. package/template/src/cli/components/ui/breadcrumb.jsx +97 -0
  128. package/template/src/cli/components/ui/card.jsx +73 -0
  129. package/template/src/cli/components/ui/collapsible.jsx +16 -0
  130. package/template/src/cli/components/ui/dropdown-menu.jsx +179 -0
  131. package/template/src/cli/components/ui/field.jsx +217 -0
  132. package/template/src/cli/components/ui/input.jsx +19 -0
  133. package/template/src/cli/components/ui/label.jsx +17 -0
  134. package/template/src/cli/components/ui/pagination.jsx +99 -0
  135. package/template/src/cli/components/ui/patched/alert.jsx +56 -0
  136. package/template/src/cli/components/ui/patched/button.jsx +45 -0
  137. package/template/src/cli/components/ui/patched/dialog.jsx +114 -0
  138. package/template/src/cli/components/ui/patched/sidebar.jsx +660 -0
  139. package/template/src/cli/components/ui/select.jsx +141 -0
  140. package/template/src/cli/components/ui/separator.jsx +21 -0
  141. package/template/src/cli/components/ui/sheet.jsx +115 -0
  142. package/template/src/cli/components/ui/skeleton.jsx +13 -0
  143. package/template/src/cli/components/ui/sonner.jsx +22 -0
  144. package/template/src/cli/components/ui/switch.jsx +25 -0
  145. package/template/src/cli/components/ui/table.jsx +88 -0
  146. package/template/src/cli/components/ui/textarea.jsx +16 -0
  147. package/template/src/cli/components/ui/tooltip.jsx +45 -0
  148. package/template/src/cli/config/store_keys.mjs +2 -0
  149. package/template/src/cli/context/data/DataContext.jsx +5 -0
  150. package/template/src/cli/context/data/DataProvider.jsx +44 -0
  151. package/template/src/cli/context/data/useBreads.mjs +15 -0
  152. package/template/src/cli/context/data/useDataContext.mjs +4 -0
  153. package/template/src/cli/context/session/SessionContext.mjs +4 -0
  154. package/template/src/cli/context/session/SessionProvider.jsx +31 -0
  155. package/template/src/cli/context/session/makePermissioner.mjs +34 -0
  156. package/template/src/cli/context/session/useSessionContext.mjs +6 -0
  157. package/template/src/cli/context/theme/ThemeContext.mjs +4 -0
  158. package/template/src/cli/context/theme/ThemeProvider.jsx +49 -0
  159. package/template/src/cli/context/theme/useThemeContext.mjs +6 -0
  160. package/template/src/cli/context/ui/UIContext.jsx +5 -0
  161. package/template/src/cli/context/ui/UIProvider.jsx +16 -0
  162. package/template/src/cli/context/ui/useUIContext.mjs +4 -0
  163. package/template/src/cli/context/util.mjs +17 -0
  164. package/template/src/cli/entry-cli.jsx +33 -0
  165. package/template/src/cli/hooks/useIsMobile.mjs +19 -0
  166. package/template/src/cli/hooks/useStoragedState.mjs +63 -0
  167. package/template/src/cli/index.html +29 -0
  168. package/template/src/cli/layout/app-sidebar.jsx +25 -0
  169. package/template/src/cli/layout/main-layout.jsx +63 -0
  170. package/template/src/cli/layout/nav-last-todos.jsx +72 -0
  171. package/template/src/cli/layout/nav-main.jsx +39 -0
  172. package/template/src/cli/layout/nav-user.jsx +105 -0
  173. package/template/src/cli/layout/prop-switcher.jsx +93 -0
  174. package/template/src/cli/lib/utils.mjs +10 -0
  175. package/template/src/cli/pages/Index.jsx +13 -0
  176. package/template/src/cli/pages/IndexOffline.jsx +13 -0
  177. package/template/src/cli/pages/IndexOnline.jsx +18 -0
  178. package/template/src/cli/pages/dash/Dashboard.jsx +29 -0
  179. package/template/src/cli/pages/offline/Login.jsx +43 -0
  180. package/template/src/cli/pages/offline/LoginForm.jsx +115 -0
  181. package/template/src/cli/pages/security/Security.jsx +39 -0
  182. package/template/src/cli/pages/security/SecurityForm.jsx +106 -0
  183. package/template/src/cli/pages/todos/TodoActions.jsx +99 -0
  184. package/template/src/cli/pages/todos/TodoAdd.jsx +43 -0
  185. package/template/src/cli/pages/todos/TodoList.jsx +60 -0
  186. package/template/src/cli/pages/todos/Todos.jsx +23 -0
  187. package/template/src/cli/pages/todos/context/TodosContext.jsx +5 -0
  188. package/template/src/cli/pages/todos/context/TodosProvider.jsx +191 -0
  189. package/template/src/cli/pages/todos/context/useTodosContext.mjs +4 -0
  190. package/template/src/ns/models/Todo.mjs +29 -0
  191. package/template/src/ns/models/TodoList.mjs +8 -0
  192. package/template/src/ns/models/User.mjs +40 -0
  193. package/template/src/server/bot/check_today.mjs +10 -0
  194. package/template/src/server/io/cache/base.mjs +21 -0
  195. package/template/src/server/io/db/filter.mjs +92 -0
  196. package/template/src/server/io/db/todos/delete.mjs +29 -0
  197. package/template/src/server/io/db/todos/find.mjs +13 -0
  198. package/template/src/server/io/db/todos/read.mjs +83 -0
  199. package/template/src/server/io/db/todos/toggle.mjs +37 -0
  200. package/template/src/server/io/db/todos/upsave.mjs +32 -0
  201. package/template/src/server/io/db/triggers/user.mjs +13 -0
  202. package/template/src/server/io/db/users/auth.mjs +132 -0
  203. package/template/src/server/io/db/users/pwd.mjs +38 -0
  204. package/template/src/server/io/db/users/save.mjs +17 -0
  205. package/template/src/server/miolo/auth/basic.mjs +15 -0
  206. package/template/src/server/miolo/auth/guest.mjs +3 -0
  207. package/template/src/server/miolo/auth/passport.mjs +73 -0
  208. package/template/src/server/miolo/cache.mjs +11 -0
  209. package/template/src/server/miolo/cron/foo.mjs +7 -0
  210. package/template/src/server/miolo/cron/index.mjs +28 -0
  211. package/template/src/server/miolo/cron/invalidate.mjs +21 -0
  212. package/template/src/server/miolo/db.mjs +36 -0
  213. package/template/src/server/miolo/http.mjs +14 -0
  214. package/template/src/server/miolo/index.mjs +43 -0
  215. package/template/src/server/miolo/routes/crud.mjs +16 -0
  216. package/template/src/server/miolo/routes/index.mjs +8 -0
  217. package/template/src/server/miolo/ssr/entry-server.jsx +13 -0
  218. package/template/src/server/miolo/ssr/loader.mjs +18 -0
  219. package/template/src/server/routes/index.mjs +66 -0
  220. package/template/src/server/routes/todos/mod.mjs +52 -0
  221. package/template/src/server/routes/todos/read.mjs +45 -0
  222. package/template/src/server/routes/todos/special.mjs +47 -0
  223. package/template/src/server/routes/users/user.mjs +54 -0
  224. package/template/src/server/server.mjs +10 -0
  225. package/template/src/server/utils/crypt.mjs +38 -0
  226. package/template/src/server/utils/io.mjs +15 -0
  227. package/template/src/server/utils/pwdfor.mjs +25 -0
  228. package/template/src/server/utils/schema.mjs +22 -0
  229. package/template/src/static/img/default/profile.png +0 -0
  230. package/template/src/static/img/favicon.ico +0 -0
  231. package/template/src/static/img/miolo_logo.png +0 -0
  232. package/template/src/static/img/miolo_name.png +0 -0
  233. package/template/src/static/public/manifest.json +21 -0
  234. package/template/src/static/public/sw.js +79 -0
  235. package/template/src/static/style/globals.css +156 -0
  236. package/template/src/static/style/json-tree.css +54 -0
  237. package/template/src/static/style/skeleton.css +49 -0
  238. package/bin/prod-build/build-client.mjs +0 -67
  239. package/bin/prod-build/build-server.mjs +0 -58
  240. package/bin/prod-run/restart.mjs +0 -9
  241. package/bin/prod-run/start.mjs +0 -15
  242. package/bin/prod-run/stop.mjs +0 -20
  243. package/src/engines/logger/verify.mjs +0 -22
  244. package/src/middleware/auth/credentials/index.mjs +0 -151
  245. package/src/middleware/auth/credentials/session/index.mjs +0 -24
  246. package/src/middleware/auth/credentials/session/store_koa_redis.mjs +0 -3
@@ -0,0 +1,374 @@
1
+ import Router from "@koa/router"
2
+ import passport from "koa-passport"
3
+ import { Strategy as GoogleStrategy } from "passport-google-oauth20"
4
+ import LocalStrategy from "passport-local"
5
+ import { init_session_middleware } from "./session/index.mjs"
6
+
7
+ // local: {
8
+ // get_user_id: (user, done) => done(null, user.id), // default
9
+ // find_user_by_id: (id, done) => done(null, {id: 1}), // ok=> done(null, user) err=> done(error, null)
10
+ // local_auth_user: (username, password, done) => done(null, {id: 1})
11
+ // // auth=> done(null, user) noauth=> done(null, false, {message: ''}) err=> done(error, null)
12
+ // local_url_login : '/login',
13
+ // local_url_logout: '/logout',
14
+ // local_url_login_redirect: undefined
15
+ // local_url_logout_redirect: '/'
16
+ // google_auth_user: (accessToken, refreshToken, profile, done, ctx) => done(null, {id: 1})
17
+ // // auth=> done(null, user) noauth=> done(null, false, {message: ''}) err=> done(error, null)
18
+ // google_client_id: 'your-google-client-id',
19
+ // google_client_secret: 'your-google-client-secret',
20
+ // google_url_login : '/auth/google',
21
+ // google_url_callback : '/auth/google/callback',
22
+ // google_url_logout: '/logout',
23
+ // google_url_login_redirect: undefined
24
+ // google_url_logout_redirect: '/'
25
+ // }
26
+
27
+ const def_get_user_id = async (user, _ctx) => user?.id
28
+
29
+ const def_find_user_by_id = async (_id, _ctx) => {
30
+ throw new Error("You need to define auth.passport.find_user_by_id")
31
+ }
32
+
33
+ const def_local_auth_user = async (_username, _password, _ctx) => {
34
+ throw new Error("You need to define auth.passport.local_auth_user")
35
+ }
36
+
37
+ const def_google_auth_user = async (_accessToken, _refreshToken, _profile, _ctx) => {
38
+ throw new Error("You need to define auth.passport.google_auth_user")
39
+ }
40
+
41
+ const init_passport_auth_middleware = (app, options, sessionConfig, cacheConfig) => {
42
+ const {
43
+ get_user_id,
44
+ find_user_by_id,
45
+ local_auth_user,
46
+ local_url_login,
47
+ local_url_logout,
48
+ local_url_login_redirect,
49
+ local_url_logout_redirect,
50
+ google_auth_user,
51
+ google_client_id,
52
+ google_client_secret,
53
+ google_url_login,
54
+ google_url_callback,
55
+ google_url_logout,
56
+ google_url_login_redirect,
57
+ google_url_logout_redirect
58
+ } = options
59
+
60
+ //const local_options = {}
61
+
62
+ // fallback funcs
63
+ const get_user_id_f = get_user_id || def_get_user_id
64
+ const find_user_by_id_f = find_user_by_id || def_find_user_by_id
65
+ const local_auth_user_f = local_auth_user || def_local_auth_user
66
+ const local_url_login_f = local_url_login || "/login"
67
+ const local_url_logout_f = local_url_logout || "/logout"
68
+ const google_auth_user_f = google_auth_user || def_google_auth_user
69
+
70
+ const google_url_login_f = google_url_login || "/auth/google"
71
+ const google_url_callback_f = google_url_callback || "/auth/google/callback"
72
+ const google_url_logout_f = google_url_logout || "/logout"
73
+
74
+ // init passport
75
+ const serialize_user = (ctx) => (user, done) => {
76
+ process.nextTick(() => {
77
+ try {
78
+ ctx.miolo.logger.debug(`[auth][passport] serializing user...`)
79
+ ctx.sessionId = ctx.session?.externalKey
80
+ ? ctx.getSessionStoreKey(ctx.session?.externalKey)
81
+ : undefined
82
+ get_user_id_f(user, ctx).then((uid) => {
83
+ return done(null, uid || false)
84
+ })
85
+ } catch (error) {
86
+ const msg = `Error serializing user: ${error}`
87
+ ctx.miolo.logger.error(`[auth][passport] ${msg}`)
88
+ return done(null, false, { message: msg })
89
+ }
90
+ })
91
+ }
92
+
93
+ const deserialize_user = (ctx) => (id, done) => {
94
+ process.nextTick(() => {
95
+ try {
96
+ ctx.miolo.logger.debug(`[auth][passport] deserializing user...`)
97
+ ctx.sessionId = ctx.session?.externalKey
98
+ ? ctx.getSessionStoreKey(ctx.session?.externalKey)
99
+ : undefined
100
+ find_user_by_id_f(id, ctx).then((user) => {
101
+ return done(null, user || false)
102
+ })
103
+ } catch (error) {
104
+ const msg = `Error deserializing user: ${error}`
105
+ ctx.miolo.logger.error(`[auth][passport] ${msg}`)
106
+ return done(null, false, { message: msg })
107
+ }
108
+ })
109
+ }
110
+
111
+ const local_strategy = (ctx) =>
112
+ new LocalStrategy.Strategy((username, password, done) => {
113
+ ctx.sessionId = ctx.session?.externalKey
114
+ ? ctx.getSessionStoreKey(ctx.session?.externalKey)
115
+ : undefined
116
+ try {
117
+ local_auth_user_f(username, password, ctx).then(([user, msg]) => {
118
+ ctx.body = {
119
+ authenticated: user || false,
120
+ message: msg,
121
+ user: user,
122
+ config: {
123
+ auth_method: "local"
124
+ }
125
+ }
126
+ return done(null, user || false, { message: msg || "" })
127
+ })
128
+ } catch (error) {
129
+ const msg = `Error local auth user: ${error}`
130
+ ctx.miolo.logger.error(`[auth][passport] ${msg}`)
131
+ return done(null, false, { message: msg })
132
+ }
133
+ })
134
+
135
+ let google_strategy
136
+
137
+ if (google_client_id) {
138
+ google_strategy = (ctx) =>
139
+ new GoogleStrategy(
140
+ {
141
+ clientID: google_client_id,
142
+ clientSecret: google_client_secret,
143
+ callbackURL: google_url_callback_f,
144
+ passReqToCallback: true,
145
+ proxy: process.env.NODE_ENV === "production"
146
+ },
147
+ (_req, accessToken, refreshToken, profile, done) => {
148
+ ctx.sessionId = ctx.session?.externalKey
149
+ ? ctx.getSessionStoreKey(ctx.session?.externalKey)
150
+ : undefined
151
+ try {
152
+ google_auth_user_f(accessToken, refreshToken, profile, ctx).then(([user, msg]) => {
153
+ ctx.body = {
154
+ authenticated: user || false,
155
+ message: msg,
156
+ user: user,
157
+ config: {
158
+ auth_method: "google"
159
+ }
160
+ }
161
+ return done(null, user || false, { message: msg || "" })
162
+ })
163
+ } catch (error) {
164
+ const msg = `Error google auth user: ${error}`
165
+ ctx.miolo.logger.error(`[auth][passport] ${msg}`)
166
+ return done(null, false, { message: msg })
167
+ }
168
+ }
169
+ )
170
+ }
171
+
172
+ app.use((ctx, next) => {
173
+ passport.serializeUser(serialize_user(ctx))
174
+ passport.deserializeUser(deserialize_user(ctx))
175
+ passport.use(local_strategy(ctx))
176
+ if (google_client_id) {
177
+ passport.use("google", google_strategy(ctx))
178
+ }
179
+ return next()
180
+ })
181
+
182
+ init_session_middleware(app, sessionConfig, cacheConfig)
183
+
184
+ app.use(passport.initialize())
185
+ app.use(passport.session())
186
+
187
+ async function _ensure_ctx_user(ctx, next) {
188
+ try {
189
+ if (ctx.session.authenticated) {
190
+ ctx.session.user = ctx.state.user
191
+ }
192
+ } catch (_) {}
193
+ await next()
194
+ }
195
+ app.use(_ensure_ctx_user)
196
+
197
+ // handle auth routes
198
+ const handleLocalLogIn = (ctx, _next) => {
199
+ ctx.miolo.logger.debug(`[auth][local] handleLocalLogIn() - authenticating...`)
200
+ return passport.authenticate("local", async (err, user, info, _status) => {
201
+ const noUser = user === false || user === undefined || user === null
202
+ const hasErr = err !== undefined && err !== null
203
+ if (noUser || hasErr) {
204
+ ctx.miolo.logger.debug(`[auth][local] handleLocalLogIn() - user not authenticated`)
205
+ ctx.session.user = undefined
206
+ ctx.session.authenticated = false
207
+ ctx.session.auth_method = undefined
208
+ ctx.sessionId = undefined
209
+
210
+ // This will show error logs on the catcher middleware
211
+ // ctx.throw(401)
212
+
213
+ ctx.status = 401
214
+
215
+ ctx.body = {
216
+ ok: false,
217
+ data: {
218
+ user: undefined,
219
+ authenticated: false,
220
+ info: info
221
+ },
222
+ error: err?.message || err?.stack || err
223
+ }
224
+ } else {
225
+ ctx.miolo.logger.debug(`[auth][local] handleLocalLogIn() - user authenticated`)
226
+ await ctx.login(user)
227
+ ctx.session.user = user // ctx.state.user
228
+ ctx.session.authenticated = true
229
+ ctx.session.auth_method = "local"
230
+
231
+ ctx.body = {
232
+ ok: true,
233
+ data: {
234
+ user: user,
235
+ authenticated: true,
236
+ config: {
237
+ auth_method: "local"
238
+ }
239
+ }
240
+ }
241
+
242
+ if (local_url_login_redirect !== undefined) {
243
+ ctx.redirect(local_url_login_redirect)
244
+ }
245
+ }
246
+ })(ctx)
247
+ }
248
+
249
+ // handle auth routes
250
+ const handleGoogleLogin = (ctx, next) => {
251
+ ctx.miolo.logger.debug(`[auth][google] handleGoogleLogin() - authenticating...`)
252
+
253
+ const redirectUrl = ctx.query.redirect || "/"
254
+
255
+ ctx.miolo.logger.info(
256
+ `[auth][google] handleGoogleLogin() - authenticating with redirectUrl: ${redirectUrl}`
257
+ )
258
+
259
+ const strategy = passport.authenticate("google", {
260
+ scope: ["profile", "email"],
261
+ state: redirectUrl
262
+ })
263
+
264
+ return strategy(ctx, next)
265
+ }
266
+
267
+ const handleGoogleCallback = (ctx, next) => {
268
+ ctx.miolo.logger.debug(`[auth][google] handleGoogleCallback() - authenticating...`)
269
+ return passport.authenticate("google", async (err, user, info, _status) => {
270
+ if (err || user === false) {
271
+ ctx.miolo.logger.debug(`[auth][google] handleGoogleCallback() - user not authenticated`)
272
+ ctx.session.user = undefined
273
+ ctx.session.authenticated = false
274
+ ctx.session.auth_method = undefined
275
+ ctx.sessionId = undefined
276
+
277
+ // This will show error logs on the catcher middleware
278
+ // ctx.throw(401)
279
+
280
+ ctx.status = 401
281
+
282
+ ctx.body = {
283
+ ok: err === undefined,
284
+ data: {
285
+ user: undefined,
286
+ authenticated: false,
287
+ info: info
288
+ },
289
+ error: err
290
+ }
291
+
292
+ ctx.redirect(google_url_logout_redirect || "/")
293
+ } else {
294
+ ctx.miolo.logger.debug(`[auth][google] handleGoogleCallback() - user authenticated`)
295
+ await ctx.login(user)
296
+ ctx.session.user = user // ctx.state.user
297
+ ctx.session.authenticated = true
298
+ ctx.session.auth_method = "google"
299
+
300
+ // ctx.body = {
301
+ // ok: true,
302
+ // data: {
303
+ // user: user,
304
+ // authenticated: true,
305
+ // config: {
306
+ // auth_method: "google"
307
+ // }
308
+ // }
309
+ // }
310
+
311
+ const redirectUrl = ctx.query.state || google_url_login_redirect || "/"
312
+
313
+ ctx.miolo.logger.info(
314
+ `[auth][google] handleGoogleCallback() - redirecting to: ${redirectUrl}. query.state: ${ctx.query.state}. google_url_login_redirect: ${google_url_login_redirect}`
315
+ )
316
+
317
+ ctx.redirect(redirectUrl)
318
+ }
319
+ })(ctx, next)
320
+ }
321
+
322
+ const handleLogOut = async (ctx, _next) => {
323
+ if (ctx.session.authenticated) {
324
+ ctx.miolo.logger.debug(`[auth][passport] handleLogOut() - logging out...`)
325
+
326
+ ctx.session.user = undefined
327
+ ctx.session.authenticated = false
328
+ ctx.session.auth_method = undefined
329
+ ctx.sessionId = undefined
330
+
331
+ ctx.body = {
332
+ ok: true,
333
+ data: {
334
+ user: undefined,
335
+ authenticated: false
336
+ }
337
+ }
338
+
339
+ if (local_url_logout_redirect !== undefined) {
340
+ ctx.redirect(local_url_logout_redirect)
341
+ } else {
342
+ await ctx.logout()
343
+ }
344
+ } else {
345
+ ctx.miolo.logger.debug(`[auth][passport] handleLogOut() - logging out (unauthed)...`)
346
+
347
+ // This will show error logs on the catcher middleware
348
+ // ctx.throw(401)
349
+
350
+ ctx.status = 401
351
+ ctx.body = {
352
+ ok: true,
353
+ data: {
354
+ user: undefined,
355
+ authenticated: false
356
+ }
357
+ }
358
+ }
359
+ }
360
+
361
+ // Init the router
362
+ const login_router = new Router()
363
+ login_router.post(local_url_login_f, handleLocalLogIn)
364
+ login_router.get(local_url_logout_f, handleLogOut)
365
+ login_router.post(local_url_logout_f, handleLogOut)
366
+ login_router.get(google_url_login_f, handleGoogleLogin)
367
+ login_router.get(google_url_callback_f, handleGoogleCallback)
368
+ login_router.get(google_url_logout_f, handleLogOut)
369
+ login_router.post(google_url_logout_f, handleLogOut)
370
+
371
+ app.use(login_router.routes())
372
+ }
373
+
374
+ export { init_passport_auth_middleware }
@@ -0,0 +1,43 @@
1
+ import { createSession } from "koa-session"
2
+ // import store_koa_redis from './store_koa_redis.mjs'
3
+ import { init_session_cache_store } from "./store.mjs"
4
+
5
+ /**
6
+ * Middleware for session
7
+ * @param ctx
8
+ * @param next
9
+ */
10
+ function init_session_middleware(app, sessionConfig, cacheConfig) {
11
+ const store = init_session_cache_store(cacheConfig, app.context.miolo.logger)
12
+
13
+ app.keys = [sessionConfig.secret || "*secret*"]
14
+
15
+ const options = {
16
+ // store: store_koa_redis,
17
+ store,
18
+ ...(sessionConfig.options || {})
19
+ }
20
+
21
+ app.context.miolo.session = {
22
+ store,
23
+ options
24
+ }
25
+
26
+ app.use(createSession(options, app))
27
+
28
+ app.use(async (ctx, next) => {
29
+ ctx.getSessionStoreKey = (externalKey) => {
30
+ return store.getInnerKey(externalKey)
31
+ }
32
+ await next()
33
+ })
34
+
35
+ app.initSessionStore = async () => {
36
+ await store.initCache()
37
+ }
38
+ app.closeSessionStore = async () => {
39
+ await store.closeCache()
40
+ }
41
+ }
42
+
43
+ export { init_session_middleware }
@@ -1,5 +1,5 @@
1
- import {cacheiro} from 'cacheiro'
2
- import { miolo_cacher_options_for_session } from '../../../context/cache/options.mjs'
1
+ import { cacheiro } from "cacheiro"
2
+ import { miolo_cacher_options_for_session } from "../../../context/cache/options.mjs"
3
3
 
4
4
  class SessionStore {
5
5
  constructor(options, logger) {
@@ -8,52 +8,72 @@ class SessionStore {
8
8
  this._cache = undefined
9
9
  }
10
10
 
11
- async init_cache() {
12
- if (this._cache == undefined) {
11
+ async initCache() {
12
+ if (this._cache === undefined) {
13
13
  this.logger.silly(`[session-store] Initing store`)
14
14
  this._cache = await cacheiro(this.options)
15
15
  }
16
16
  return this._cache
17
17
  }
18
18
 
19
+ async closeCache() {
20
+ if (this._cache !== undefined) {
21
+ this.logger.silly(`[session-store] Closing store`)
22
+ try {
23
+ await this._cache.close()
24
+ } catch (error) {
25
+ this.logger.warn(error)
26
+ }
27
+ }
28
+ }
29
+
30
+ // biome-ignore lint/correctness/noUnusedFunctionParameters: keep definition for koa-session store
19
31
  async get(key, maxAge, { rolling, ctx }) {
20
-
21
- const cache = await this.init_cache()
32
+ const cache = await this.initCache()
22
33
  const jvalue = await cache.getItem(key)
23
34
  try {
24
35
  const value = JSON.parse(jvalue)
25
36
  this.logger.silly(`[session-store] Get session for ${key}: ${JSON.stringify(value)}`)
26
37
  //console.log(`[session-store] Get session for ${key}: ${JSON.stringify(value)}`)
27
38
  return value
28
- } catch(_) {
39
+ } catch (_) {
29
40
  this.logger.silly(`[session-store] No session for ${key}`)
30
41
  //console.log(`[session-store] No session for ${key}`)
31
42
  return undefined
32
43
  }
33
44
  }
34
45
 
46
+ // biome-ignore lint/correctness/noUnusedFunctionParameters: keep definition for koa-session store
35
47
  async set(key, sess, maxAge, { rolling, changed, ctx }) {
36
48
  this.logger.silly(`[session-store] Set session for ${key}`)
37
- const cache = await this.init_cache()
38
- let svalue = undefined
49
+ const cache = await this.initCache()
50
+ let svalue
39
51
  try {
40
52
  svalue = JSON.stringify(sess)
41
- } catch(_) {}
53
+ } catch (_) {}
42
54
 
43
55
  // Rely on miolo settings for ttl / maxAge
44
56
  await cache.setItem(key, svalue /*, maxAge*/)
45
57
  }
46
-
47
- async destroy(key, {ctx}) {
58
+
59
+ // biome-ignore lint/correctness/noUnusedFunctionParameters: keep definition for koa-session store
60
+ async destroy(key, { ctx }) {
48
61
  this.logger.silly(`[session-store] Destroy session for ${key}`)
49
- const cache = await this.init_cache()
62
+ const cache = await this.initCache()
50
63
  await cache.unsetItem(key)
51
64
  }
52
- }
53
65
 
66
+ getInnerKey(key) {
67
+ if (this._cache === undefined) {
68
+ this.logger.error("[session-store] Calling getInnerKey() before cache is inited")
69
+ return key
70
+ }
71
+ return this._cache.getInnerKey(key)
72
+ }
73
+ }
54
74
 
55
75
  export function init_session_cache_store(cacheConfig, logger) {
56
- const options = miolo_cacher_options_for_session({cache: cacheConfig}, logger)
76
+ const options = miolo_cacher_options_for_session({ cache: cacheConfig }, logger)
57
77
  const store = new SessionStore(options, logger)
58
78
  return store
59
79
  }
@@ -0,0 +1,3 @@
1
+ import RedisStore from "koa-redis"
2
+
3
+ export default new RedisStore()
@@ -1,61 +1,106 @@
1
- import { cacheiro } from 'cacheiro'
2
- import { miolo_cacher_options_for_custom } from './options.mjs'
1
+ import { cacheiro } from "cacheiro"
2
+ import { miolo_cacher_options_for_custom, miolo_cacher_options_for_fly } from "./options.mjs"
3
3
 
4
- let _glob_cache_stores = undefined
4
+ let _glob_cache_mother
5
+ const _local_cache_instances = new Map()
6
+
7
+ const _get_cache_mother = async (config, logger) => {
8
+ if (_glob_cache_mother === undefined) {
9
+ const default_options = miolo_cacher_options_for_fly(
10
+ config,
11
+ {
12
+ type: process.env.MIOLO_CACHE_TYPE || "combined",
13
+ namespace: "miolo-cache-mother"
14
+ },
15
+ logger
16
+ )
17
+
18
+ _glob_cache_mother = await cacheiro(default_options)
19
+ }
20
+ return _glob_cache_mother
21
+ }
5
22
 
6
23
  export function init_context_cache(config, logger) {
7
-
8
- const _init_cache_stores = async () => {
9
- if (_glob_cache_stores==undefined) {
10
- _glob_cache_stores = {}
11
- const custom_options = miolo_cacher_options_for_custom(config, logger)
12
-
13
- for(const [name, options] of Object.entries(custom_options)) {
14
- const cache_store = await cacheiro(options)
15
- _glob_cache_stores[name] = cache_store
16
- }
17
-
18
- }
19
- return _glob_cache_stores
24
+ const custom_options = miolo_cacher_options_for_custom(config, logger)
25
+
26
+ const _init_cache_instance = async (name) => {
27
+ const cache_mother = await _get_cache_mother(config, logger)
28
+
29
+ const cache_instance = await cacheiro(custom_options?.[name] || {})
30
+ await cache_mother.setItem(name, "1")
31
+ _local_cache_instances.set(name, cache_instance)
32
+ return cache_instance
20
33
  }
21
34
 
35
+ const init = async () => {
36
+ await _get_cache_mother(config, logger)
37
+ }
22
38
 
23
39
  const get_cache = async (name) => {
24
- const cache_stores = await _init_cache_stores()
25
- return cache_stores[name]
40
+ if (_local_cache_instances.has(name)) {
41
+ return _local_cache_instances.get(name)
42
+ }
43
+
44
+ const cache_mother = await _get_cache_mother(config, logger)
45
+
46
+ const exists_in_mother = await cache_mother.getItem(name)
47
+ if (exists_in_mother) {
48
+ const cache_instance = await cacheiro(custom_options?.[name] || {})
49
+ _local_cache_instances.set(name, cache_instance)
50
+ return cache_instance
51
+ }
52
+
53
+ return await _init_cache_instance(name)
26
54
  }
27
- const get_cache_names = async () => {
28
- const cache_stores = await _init_cache_stores()
29
- return Object.keys(cache_stores)
55
+
56
+ const get_cache_names = async (pattern = "*") => {
57
+ const cache_mother = await _get_cache_mother(config, logger)
58
+
59
+ return await cache_mother.getKeys(pattern)
30
60
  }
31
61
 
32
- const drop_cache = async (name, clean) => {
33
- const cache_stores = await _init_cache_stores()
62
+ const drop_cache = async (name, clean = true) => {
34
63
  if (clean) {
35
64
  const cache = await get_cache(name)
36
- cache.unsetAll()
65
+ if (cache) {
66
+ try {
67
+ await cache.close()
68
+ } catch (error) {
69
+ logger.warn(error)
70
+ }
71
+ }
37
72
  }
38
- delete cache_stores[name]
73
+ _local_cache_instances.delete(name)
74
+
75
+ const cache_mother = await _get_cache_mother(config, logger)
76
+ await cache_mother.unsetItem(name)
39
77
  }
40
78
 
41
- const drop_caches = async (clean) => {
79
+ const close = async (clean = true) => {
80
+ const cache_mother = await _get_cache_mother(config, logger)
81
+
42
82
  if (clean) {
43
- const cache_stores = await _init_cache_stores()
44
- for(const [_name, cache] of Object.entries(cache_stores)) {
45
- await cache.unsetAll()
83
+ for (const cache of _local_cache_instances.values()) {
84
+ try {
85
+ await cache.close()
86
+ } catch (error) {
87
+ logger.warn(error)
88
+ }
46
89
  }
47
90
  }
48
-
49
- _glob_cache_stores = {}
91
+ _local_cache_instances.clear()
92
+
93
+ await cache_mother.close()
94
+ _glob_cache_mother = undefined
50
95
  }
51
96
 
52
97
  const cache_ctx = {
98
+ init,
53
99
  get_cache,
54
100
  get_cache_names,
55
101
  drop_cache,
56
- drop_caches
102
+ close
57
103
  }
58
104
 
59
105
  return cache_ctx
60
-
61
106
  }