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,47 @@
1
+ import { intre_now } from "intre"
2
+
3
+ export async function r_todo_count_last_hours(ctx, params) {
4
+ ctx.miolo.logger.verbose(
5
+ `[r_todo_count_last_hours] Counting last ${params.hours} hours todos... `
6
+ )
7
+
8
+ const conn = await ctx.miolo.db.get_connection()
9
+ // TODO : handle transactions
10
+ const options = { transaction: undefined }
11
+
12
+ const one_hour_ago = intre_now() - 60 * 60 * parseInt(params.hours, 10)
13
+
14
+ const query = `
15
+ SELECT COUNT(1) as cnt
16
+ FROM todo
17
+ WHERE created_at >= $1`
18
+
19
+ const data = await conn.select(query, [one_hour_ago], options)
20
+ const res = data[0].cnt
21
+
22
+ ctx.miolo.logger.verbose(
23
+ `[r_todo_count_last_hours] Counted last ${params.hours} hours todos: ${res} `
24
+ )
25
+
26
+ return { ok: true, data: { count: res } }
27
+ }
28
+
29
+ export async function r_todo_insert_fake(ctx, params) {
30
+ ctx.miolo.logger.verbose(`[r_todo_insert_fake] Inserting fake todo... `)
31
+
32
+ const conn = await ctx.miolo.db.get_connection()
33
+ // TODO : handle transactions
34
+ const options = { transaction: undefined }
35
+
36
+ const Todos = await conn.get_model("todo")
37
+
38
+ const d = {
39
+ description: "Fake todo",
40
+ done: params?.done === true
41
+ }
42
+ const tid = await Todos.insert(d, options)
43
+
44
+ ctx.miolo.logger.verbose(`[r_todo_insert_fake] Inserted fake todo with id ${tid}`)
45
+
46
+ return { ok: true, data: { id: tid } }
47
+ }
@@ -0,0 +1,54 @@
1
+ import { db_password_change } from "#server/io/db/users/pwd.mjs"
2
+ import { db_user_save } from "#server/io/db/users/save.mjs"
3
+ import { generateRandomPassword } from "#server/utils/crypt.mjs"
4
+
5
+ export async function r_forgot(ctx, params) {
6
+ const logger = ctx.miolo.logger
7
+
8
+ const { email } = params
9
+
10
+ const new_pwd = generateRandomPassword()
11
+ const msg = await db_password_change(ctx.miolo, email, new_pwd)
12
+
13
+ if (msg === undefined) {
14
+ const emailer = ctx.miolo.emailer
15
+
16
+ const mail = {
17
+ to: email,
18
+ subject: "miolo-sample: Nueva contraseña",
19
+ text: `Tu nueva contraseña es: ${new_pwd}
20
+ Por favor, inicia sesión con ella y, desde "Mi Cuenta",
21
+ cámbiala por una que vayas a recordar mejor.`
22
+ }
23
+
24
+ const info = await emailer.send(mail)
25
+ if (info?.ok) {
26
+ logger.info(`Reseted password for ${email}`)
27
+ }
28
+ }
29
+
30
+ return {
31
+ success: msg === undefined,
32
+ info: msg
33
+ }
34
+ }
35
+
36
+ export async function r_change_password(ctx, params) {
37
+ const logger = ctx.miolo.logger
38
+ const { username, passwords } = params
39
+
40
+ const { ok, msg } = await db_password_change(ctx.miolo, username, passwords)
41
+
42
+ logger.info(`Changed password for ${username}`)
43
+
44
+ if (!ok) {
45
+ return { ok: false, error: msg }
46
+ }
47
+
48
+ return { ok: true, data: { msg } }
49
+ }
50
+
51
+ export async function r_user_save(ctx, params) {
52
+ const res = await db_user_save(ctx.miolo, params)
53
+ return res
54
+ }
@@ -0,0 +1,10 @@
1
+ import { miolo } from "miolo"
2
+ import makeConfig from "#server/miolo/index.mjs"
3
+
4
+ export default async function miolo_sample_server() {
5
+ console.log("[miolo-sample] Initing server...")
6
+
7
+ const server = await miolo(makeConfig)
8
+ const app = await server.start()
9
+ return app
10
+ }
@@ -0,0 +1,38 @@
1
+ import crypto from "node:crypto"
2
+
3
+ const PASSWORD_LENGTH = 18
4
+ const LOWERCASE_ALPHABET = "abcdefghijklmnopqrstuvwxyz" // 26 chars
5
+ const UPPERCASE_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 26 chars
6
+ const NUMBERS = "0123456789" // 10 chars
7
+ const SYMBOLS = ",./<>?;'\":[]\\|}{=-_+`~!@#$%^&*()" // 32 chars
8
+ const ALPHANUMERIC_CHARS = LOWERCASE_ALPHABET + UPPERCASE_ALPHABET + NUMBERS // 62 chars
9
+ const ALL_CHARS = ALPHANUMERIC_CHARS + SYMBOLS // 94 chars
10
+
11
+ /**
12
+ * Hash the password
13
+ * @private
14
+ * @param str {string}
15
+ * @param options {object}
16
+ * @returns {string}
17
+ */
18
+ function sha512(str, salt) {
19
+ return crypto.createHmac("sha512", salt).update(str).digest("hex")
20
+ }
21
+
22
+ function _generateRandomPassword(length, alphabet) {
23
+ const rb = crypto.randomBytes(length)
24
+ let rp = ""
25
+
26
+ for (let i = 0; i < length; i++) {
27
+ rb[i] = rb[i] % alphabet.length
28
+ rp += alphabet[rb[i]]
29
+ }
30
+
31
+ return rp
32
+ }
33
+
34
+ function generateRandomPassword() {
35
+ return _generateRandomPassword(PASSWORD_LENGTH, ALL_CHARS)
36
+ }
37
+
38
+ export { generateRandomPassword, sha512 }
@@ -0,0 +1,15 @@
1
+ import { readdir } from "node:fs"
2
+
3
+ function readDirAsync(path) {
4
+ return new Promise((resolve, reject) => {
5
+ readdir(path, (error, result) => {
6
+ if (error) {
7
+ reject(error)
8
+ } else {
9
+ resolve(result)
10
+ }
11
+ })
12
+ })
13
+ }
14
+
15
+ export { readDirAsync }
@@ -0,0 +1,25 @@
1
+ import fs from "node:fs"
2
+ import path from "node:path"
3
+ import { fileURLToPath } from "node:url"
4
+ import { sha512 } from "./crypt.mjs"
5
+
6
+ function _loadSalt() {
7
+ let dir = path.dirname(fileURLToPath(import.meta.url))
8
+ while (dir !== path.parse(dir).root && !fs.existsSync(path.join(dir, "package.json"))) {
9
+ dir = path.dirname(dir)
10
+ }
11
+ const env = fs.readFileSync(path.join(dir, ".env"), "utf8")
12
+ return env.match(/^MIOLO_SESSION_SALT=(.*)$/m)?.[1]?.trim()
13
+ }
14
+
15
+ async function _pwd_for() {
16
+ const args = process.argv.slice(2)
17
+ const pwd = args[0]
18
+
19
+ const salt = _loadSalt()
20
+
21
+ const cpwd = sha512(pwd, salt)
22
+ console.log([salt, cpwd])
23
+ }
24
+
25
+ _pwd_for()
@@ -0,0 +1,22 @@
1
+ import Joi from "joi"
2
+
3
+ export const req_int = Joi.number().integer().required()
4
+
5
+ export const opt_float = Joi.number().optional().empty(null)
6
+ export const opt_float_null = Joi.number().optional().allow(null)
7
+
8
+ export const opt_int = Joi.number().integer().optional().empty(null)
9
+ export const opt_int_null = Joi.number().integer().optional().allow(null)
10
+
11
+ export const opt_int_or_arr = Joi.alternatives()
12
+ .try(Joi.number().integer(), Joi.array().items(Joi.number().integer()))
13
+ .optional()
14
+ .empty(null)
15
+
16
+ export const req_str = Joi.string().required()
17
+ export const opt_str = Joi.string().optional().empty(null)
18
+ export const opt_str_null = Joi.string().optional().allow(null)
19
+
20
+ export const bool_false = Joi.boolean().optional().default(false)
21
+ export const bool_true = Joi.boolean().optional().default(true)
22
+ export const bool_null = Joi.boolean().optional().allow(null)
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "miolo-sample",
3
+ "short_name": "miolo-sample",
4
+ "start_url": "/",
5
+ "display": "standalone",
6
+ "background_color": "#ffffff",
7
+ "theme_color": "#fb64b6",
8
+ "description": "A simple PWA for miolo-sample",
9
+ "icons": [
10
+ {
11
+ "src": "/favicon.ico",
12
+ "sizes": "30x30",
13
+ "type": "image/x-icon"
14
+ },
15
+ {
16
+ "src": "/static/img/miolo_logo.png",
17
+ "sizes": "600x600",
18
+ "type": "image/png"
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1,79 @@
1
+ const CACHE_NAME = "miolo-sample-cache-v1"
2
+
3
+ // 1. EVENTO INSTALL: Ocurre la primera vez que el usuario entra.
4
+ // Aquí cacheamos el "App Shell" (lo básico para que la app abra sin red).
5
+ self.addEventListener("install", (_event) => {
6
+ /*console.log(`[miolo][sw] installing`)
7
+ event.waitUntil(
8
+ caches.open(CACHE_NAME).then((cache) => {
9
+ console.log(`[miolo][sw] installing - caching main`)
10
+ // Rutas estáticas clave (ajusta según cómo sirva Miolo tus archivos)
11
+ return cache.addAll([
12
+ "/"
13
+ // "/index.html",
14
+ // "/icon-192x192.png"
15
+ // Si sabes las URLs de tu JS/CSS, añádelas aquí.
16
+ ])
17
+ })
18
+ )
19
+ self.skipWaiting()*/
20
+ })
21
+
22
+ // 2. EVENTO ACTIVATE: Limpia cachés antiguas si cambias el CACHE_NAME
23
+ self.addEventListener("activate", (event) => {
24
+ console.log(`[miolo][sw] activating`)
25
+ event.waitUntil(
26
+ caches.keys().then((cacheNames) => {
27
+ const oldCaches = cacheNames.filter((name) => name !== CACHE_NAME)
28
+ console.log(`[miolo][sw] activating - cleaning old caches ${oldCaches}`)
29
+ return Promise.all(oldCaches.map((name) => caches.delete(name)))
30
+ })
31
+ )
32
+ self.clients.claim()
33
+ })
34
+
35
+ // 3. EVENTO FETCH: El núcleo de tu estrategia
36
+ self.addEventListener("fetch", (_event) => {
37
+ /*console.log(`[miolo][sw] fetching`)
38
+ // ESTRATEGIA PARA LLAMADAS POST
39
+ if (event.request.method === "POST" || event.request.method === "PUT") {
40
+ event.respondWith(
41
+ fetch(event.request).catch(() => {
42
+ console.log(`[miolo][sw] fetching - fetch failed, returning 503 error`)
43
+ // Si el fetch falla (porque no hay red), devolvemos un error controlado 503
44
+ return new Response(
45
+ JSON.stringify({ error: "Estás sin conexión. No se pueden guardar los cambios." }),
46
+ {
47
+ headers: { "Content-Type": "application/json" },
48
+ status: 503,
49
+ statusText: "Service Unavailable"
50
+ }
51
+ )
52
+ })
53
+ )
54
+ return // Cortamos aquí para los POST
55
+ }
56
+
57
+ // ESTRATEGIA PARA LLAMADAS GET (Network First, fallback to Cache)
58
+ // Intenta ir a internet siempre para tener los resultados frescos.
59
+ // Si falla, tira de lo que tenga guardado en caché.
60
+ event.respondWith(
61
+ fetch(event.request)
62
+ .then((networkResponse) => {
63
+ console.log(`[miolo][sw] fetching - fetch ok, caching it`)
64
+ // Guardamos una copia en la caché para la próxima vez que se quede offline
65
+ const responseClone = networkResponse.clone()
66
+ caches.open(CACHE_NAME).then((cache) => {
67
+ // No cacheamos extensiones raras del navegador
68
+ if (event.request.url.startsWith("http")) {
69
+ cache.put(event.request, responseClone)
70
+ }
71
+ })
72
+ return networkResponse
73
+ })
74
+ .catch(() => {
75
+ // Si no hay internet, devuelve la versión guardada en caché
76
+ return caches.match(event.request)
77
+ })
78
+ )*/
79
+ })
@@ -0,0 +1,156 @@
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+
4
+ @import "./json-tree.css";
5
+ @import "./skeleton.css";
6
+
7
+ /* biome-ignore lint/suspicious/noUnknownAtRules: biome-ignore */
8
+ @tailwind base;
9
+ /* biome-ignore lint/suspicious/noUnknownAtRules: biome-ignore */
10
+ @tailwind components;
11
+ /* biome-ignore lint/suspicious/noUnknownAtRules: biome-ignore */
12
+ @tailwind utilities;
13
+
14
+ @custom-variant dark (&:is(.dark *));
15
+
16
+ :root {
17
+ --background: oklch(1 0 0);
18
+ --foreground: oklch(0.145 0 0);
19
+ --card: oklch(1 0 0);
20
+ --card-foreground: oklch(0.145 0 0);
21
+ --popover: oklch(1 0 0);
22
+ --popover-foreground: oklch(0.145 0 0);
23
+ --primary: oklch(0.205 0 0);
24
+ --primary-foreground: oklch(0.985 0 0);
25
+ --secondary: oklch(0.97 0 0);
26
+ --secondary-foreground: oklch(0.205 0 0);
27
+ --muted: oklch(0.97 0 0);
28
+ --muted-foreground: oklch(0.556 0 0);
29
+ --accent: oklch(0.97 0 0);
30
+ --accent-foreground: oklch(0.205 0 0);
31
+ --destructive: oklch(0.577 0.245 27.325);
32
+ --destructive-foreground: oklch(0.577 0.245 27.325);
33
+ --border: oklch(0.922 0 0);
34
+ --input: oklch(0.922 0 0);
35
+ --ring: oklch(0.708 0 0);
36
+ --chart-1: oklch(0.646 0.222 41.116);
37
+ --chart-2: oklch(0.6 0.118 184.704);
38
+ --chart-3: oklch(0.398 0.07 227.392);
39
+ --chart-4: oklch(0.828 0.189 84.429);
40
+ --chart-5: oklch(0.769 0.188 70.08);
41
+ --radius: 0.625rem;
42
+ --sidebar: oklch(0.985 0 0);
43
+ --sidebar-foreground: oklch(0.145 0 0);
44
+ --sidebar-primary: oklch(0.205 0 0);
45
+ --sidebar-primary-foreground: oklch(0.985 0 0);
46
+ --sidebar-accent: oklch(0.97 0 0);
47
+ --sidebar-accent-foreground: oklch(0.205 0 0);
48
+ --sidebar-border: oklch(0.922 0 0);
49
+ --sidebar-ring: oklch(0.708 0 0);
50
+ }
51
+
52
+ .dark {
53
+ --background: oklch(0.145 0 0);
54
+ --foreground: oklch(0.985 0 0);
55
+ --card: oklch(0.145 0 0);
56
+ --card-foreground: oklch(0.985 0 0);
57
+ --popover: oklch(0.145 0 0);
58
+ --popover-foreground: oklch(0.985 0 0);
59
+ --primary: oklch(0.985 0 0);
60
+ --primary-foreground: oklch(0.205 0 0);
61
+ --secondary: oklch(0.269 0 0);
62
+ --secondary-foreground: oklch(0.985 0 0);
63
+ --muted: oklch(0.269 0 0);
64
+ --muted-foreground: oklch(0.708 0 0);
65
+ --accent: oklch(0.269 0 0);
66
+ --accent-foreground: oklch(0.985 0 0);
67
+ --destructive: oklch(0.396 0.141 25.723);
68
+ --destructive-foreground: oklch(0.637 0.237 25.331);
69
+ --border: oklch(0.269 0 0);
70
+ --input: oklch(0.269 0 0);
71
+ --ring: oklch(0.439 0 0);
72
+ --chart-1: oklch(0.488 0.243 264.376);
73
+ --chart-2: oklch(0.696 0.17 162.48);
74
+ --chart-3: oklch(0.769 0.188 70.08);
75
+ --chart-4: oklch(0.627 0.265 303.9);
76
+ --chart-5: oklch(0.645 0.246 16.439);
77
+ --sidebar: oklch(0.205 0 0);
78
+ --sidebar-foreground: oklch(0.985 0 0);
79
+ --sidebar-primary: oklch(0.488 0.243 264.376);
80
+ --sidebar-primary-foreground: oklch(0.985 0 0);
81
+ --sidebar-accent: oklch(0.269 0 0);
82
+ --sidebar-accent-foreground: oklch(0.985 0 0);
83
+ --sidebar-border: oklch(0.269 0 0);
84
+ --sidebar-ring: oklch(0.439 0 0);
85
+ }
86
+
87
+ @theme inline {
88
+ --color-background: var(--background);
89
+ --color-foreground: var(--foreground);
90
+ --color-card: var(--card);
91
+ --color-card-foreground: var(--card-foreground);
92
+ --color-popover: var(--popover);
93
+ --color-popover-foreground: var(--popover-foreground);
94
+ --color-primary: var(--primary);
95
+ --color-primary-foreground: var(--primary-foreground);
96
+ --color-secondary: var(--secondary);
97
+ --color-secondary-foreground: var(--secondary-foreground);
98
+ --color-muted: var(--muted);
99
+ --color-muted-foreground: var(--muted-foreground);
100
+ --color-accent: var(--accent);
101
+ --color-accent-foreground: var(--accent-foreground);
102
+ --color-destructive: var(--destructive);
103
+ --color-destructive-foreground: var(--destructive-foreground);
104
+ --color-border: var(--border);
105
+ --color-input: var(--input);
106
+ --color-ring: var(--ring);
107
+ --color-chart-1: var(--chart-1);
108
+ --color-chart-2: var(--chart-2);
109
+ --color-chart-3: var(--chart-3);
110
+ --color-chart-4: var(--chart-4);
111
+ --color-chart-5: var(--chart-5);
112
+ --radius-sm: calc(var(--radius) - 4px);
113
+ --radius-md: calc(var(--radius) - 2px);
114
+ --radius-lg: var(--radius);
115
+ --radius-xl: calc(var(--radius) + 4px);
116
+ --color-sidebar: var(--sidebar);
117
+ --color-sidebar-foreground: var(--sidebar-foreground);
118
+ --color-sidebar-primary: var(--sidebar-primary);
119
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
120
+ --color-sidebar-accent: var(--sidebar-accent);
121
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
122
+ --color-sidebar-border: var(--sidebar-border);
123
+ --color-sidebar-ring: var(--sidebar-ring);
124
+ }
125
+
126
+ @layer base {
127
+ * {
128
+ @apply border-border outline-ring/50;
129
+ }
130
+ body {
131
+ @apply bg-background text-foreground;
132
+ }
133
+
134
+ /* Sidebar */
135
+ :root {
136
+ --sidebar: oklch(0.985 0 0);
137
+ --sidebar-foreground: oklch(0.145 0 0);
138
+ --sidebar-primary: oklch(0.205 0 0);
139
+ --sidebar-primary-foreground: oklch(0.985 0 0);
140
+ --sidebar-accent: oklch(0.97 0 0);
141
+ --sidebar-accent-foreground: oklch(0.205 0 0);
142
+ --sidebar-border: oklch(0.922 0 0);
143
+ --sidebar-ring: oklch(0.708 0 0);
144
+ }
145
+
146
+ .dark {
147
+ --sidebar: oklch(0.205 0 0);
148
+ --sidebar-foreground: oklch(0.985 0 0);
149
+ --sidebar-primary: oklch(0.488 0.243 264.376);
150
+ --sidebar-primary-foreground: oklch(0.985 0 0);
151
+ --sidebar-accent: oklch(0.269 0 0);
152
+ --sidebar-accent-foreground: oklch(0.985 0 0);
153
+ --sidebar-border: oklch(1 0 0 / 10%);
154
+ --sidebar-ring: oklch(0.439 0 0);
155
+ }
156
+ }
@@ -0,0 +1,54 @@
1
+ .json-tree-viewer {
2
+ font-family: monospace;
3
+ font-size: 14px;
4
+ line-height: 1.5;
5
+ background-color: #272822; /* Fondo oscuro */
6
+ color: #f8f8f2; /* Color de texto claro */
7
+ padding: 10px;
8
+ border-radius: 4px;
9
+ overflow: auto;
10
+ max-height: 500px;
11
+ }
12
+
13
+ .json-node {
14
+ margin-left: 20px; /* Indentación para nodos anidados */
15
+ white-space: nowrap; /* Evita que los valores se rompan en múltiples líneas */
16
+ }
17
+
18
+ .json-key {
19
+ color: #a6e22e; /* Color para las claves (verde) */
20
+ font-weight: bold;
21
+ }
22
+
23
+ .json-value-string {
24
+ color: #e6db74; /* Color para strings (amarillo) */
25
+ }
26
+
27
+ .json-value-number {
28
+ color: #ae81ff; /* Color para números (morado) */
29
+ }
30
+
31
+ .json-value-boolean {
32
+ color: #fd971f; /* Color para booleanos (naranja) */
33
+ }
34
+
35
+ .json-value-null {
36
+ color: #66d9ef; /* Color para null (azul claro) */
37
+ }
38
+
39
+ .json-object,
40
+ .json-array {
41
+ display: inline-flex; /* Permite que el icono y el contenido estén en la misma línea */
42
+ align-items: center;
43
+ }
44
+
45
+ .toggle-icon {
46
+ cursor: pointer;
47
+ margin-right: 5px;
48
+ color: #66d9ef; /* Color para los iconos de expandir/contraer */
49
+ font-size: 0.8em; /* Un poco más pequeño */
50
+ }
51
+
52
+ .indent {
53
+ margin-left: 20px; /* Indentación para el contenido expandido */
54
+ }
@@ -0,0 +1,49 @@
1
+ @keyframes pulse {
2
+ 50% {
3
+ opacity: 0.5;
4
+ }
5
+ }
6
+ /*
7
+ .skeleton-loading h1,
8
+ .skeleton-loading h2,
9
+ .skeleton-loading h3,
10
+ .skeleton-loading p,
11
+ .skeleton-loading span,
12
+ .skeleton-loading div:not(:empty) {
13
+ @apply
14
+ bg-gray-200
15
+ dark:bg-gray-700
16
+ rounded-md
17
+ text-transparent
18
+ relative
19
+ overflow-hidden;
20
+ animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
21
+
22
+ / * Esto asegura que los elementos vacíos tengan un tamaño * /
23
+ min-height: 1rem;
24
+ }
25
+ */
26
+
27
+ .skeleton-loading input,
28
+ .skeleton-loading button,
29
+ .skeleton-loading a,
30
+ .skeleton-loading .skeleton-apply {
31
+ @apply bg-gray-200 dark:bg-gray-700 rounded-md text-transparent relative overflow-hidden;
32
+ animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
33
+ pointer-events: none; /* Para deshabilitar la interacción */
34
+ }
35
+
36
+ /* Manejo de imágenes y elementos con aspecto */
37
+ .skeleton-loading img,
38
+ .skeleton-loading [data-aspect] {
39
+ @apply bg-gray-200 dark:bg-gray-700;
40
+ animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
41
+ }
42
+
43
+ /*
44
+ .skeleton-loading h1,
45
+ .skeleton-loading h2,
46
+ .skeleton-loading h3 {
47
+ height: 1.5em; / * Define una altura para los títulos * /
48
+ }
49
+ */
@@ -1,67 +0,0 @@
1
-
2
- import path from 'node:path'
3
- import {xeiraBundle} from 'xeira'
4
- import { cleanFolder, copyFileSync, isFileExistingSync } from '../util.mjs'
5
-
6
- function _addCssLinkToHead(appName, htmlString, dest) {
7
-
8
- const webDest = dest.startsWith('./')
9
- ? dest.replace('./', '/')
10
- : dest.startsWith('/')
11
- ? dest
12
- : `/${dest}`
13
-
14
- const linkTag = ` <link href="${webDest}/${appName}.${process.env.MIOLO_BUILD_CLIENT_SUFFIX}.css" rel="stylesheet" media="all">`
15
-
16
- // Expresión regular para encontrar la etiqueta </head> de cierre.
17
- // Usamos un grupo de captura para mantener el contenido antes de </head>.
18
- const headCloseTagRegex = /(<\/head>)/i;
19
-
20
- // Busca la etiqueta </head> en el HTML.
21
- const match = htmlString.match(headCloseTagRegex);
22
-
23
- if (match) {
24
- console.log(`[${appName}][prod] adding css link ${linkTag} to <head>`)
25
-
26
- // Si se encuentra </head>, inserta la etiqueta <link> justo antes de ella.
27
- return htmlString.replace(headCloseTagRegex, `${linkTag}\n$&`);
28
- } else {
29
- // Si no se encuentra </head>, devuelve el HTML original sin modificar.
30
- console.warn(`[${appName}][prod] No se encontró la etiqueta <head> en el HTML proporcionado.`);
31
- return htmlString;
32
- }
33
- }
34
-
35
-
36
- export default async function(appName, entry, htmlFile, dest) {
37
- console.log(`[${appName}][prod] Building client from entry ${entry}`)
38
-
39
- // Clean dest folder
40
- cleanFolder(dest)
41
-
42
- // Build client
43
- await xeiraBundle({
44
- source_index: entry,
45
- target: 'browser',
46
- bundle_folder: dest,
47
- bundle_name: appName,
48
- bundle_extension: process.env.MIOLO_BUILD_CLIENT_SUFFIX,
49
- bundler: 'rollup',
50
- bundle_node_polyfill: true
51
- })
52
-
53
- // Fix css file
54
- const destCssFile = `${dest}/${appName}.${process.env.MIOLO_BUILD_CLIENT_SUFFIX}.css`
55
- const destCssFileExists = isFileExistingSync(destCssFile)
56
-
57
- console.log(`[${appName}][prod] destCssFile ${destCssFile} exists?: ${destCssFileExists}`)
58
-
59
- console.log(`[${appName}][prod] Copying HTML file ${htmlFile} to ${dest}/index.html`)
60
- copyFileSync(path.join(process.cwd(), htmlFile), path.join(process.cwd(), `${dest}/index.html`), (content) => {
61
- if (destCssFileExists) {
62
- content = _addCssLinkToHead(appName, content, dest)
63
- }
64
- return content
65
- })
66
-
67
- }