miolo 3.0.0-beta.180 → 3.0.0-beta.182
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/package.json +7 -7
- package/src/config/defaults.mjs +7 -0
- package/src/middleware/auth/basic.mjs +1 -1
- package/src/middleware/static/index.mjs +18 -2
- package/template/biome.json +1 -1
- package/template/package.json +5 -5
- package/template/src/cli/entry-cli.jsx +16 -0
- package/template/src/cli/index.html +12 -3
- package/template/src/cli/pages/security/Security.jsx +4 -1
- package/template/src/cli/pages/todos/context/TodosProvider.jsx +48 -40
- package/template/src/server/miolo/auth/basic.mjs +3 -3
- package/template/src/server/routes/todos/read.mjs +1 -1
- package/template/src/static/public/manifest.json +21 -0
- package/template/src/static/public/sw.js +79 -0
- package/template/src/static/public/favicon.ico +0 -0
- package/template/src/static/public/robots.txt +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "miolo",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.182",
|
|
4
4
|
"description": "all-in-one koa-based server",
|
|
5
5
|
"author": "Donato Lorenzo <donato@afialapis.com>",
|
|
6
6
|
"contributors": [
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@babel/plugin-proposal-decorators": "^7.29.0",
|
|
48
|
-
"@babel/preset-env": "^7.29.
|
|
48
|
+
"@babel/preset-env": "^7.29.3",
|
|
49
49
|
"@babel/preset-react": "^7.28.5",
|
|
50
|
-
"@dotenvx/dotenvx": "^1.
|
|
50
|
+
"@dotenvx/dotenvx": "^1.64.0",
|
|
51
51
|
"@koa/bodyparser": "^6.1.0",
|
|
52
52
|
"@koa/cors": "^5.0.0",
|
|
53
|
-
"@koa/router": "^15.
|
|
53
|
+
"@koa/router": "^15.5.0",
|
|
54
54
|
"@maxmind/geoip2-node": "^6.3.4",
|
|
55
55
|
"@rollup/plugin-alias": "^6.0.0",
|
|
56
56
|
"@rollup/plugin-babel": "^7.0.0",
|
|
@@ -82,8 +82,8 @@
|
|
|
82
82
|
"koa-ratelimit": "^6.0.0",
|
|
83
83
|
"koa-session": "^7.0.2",
|
|
84
84
|
"koa-static": "^5.0.0",
|
|
85
|
-
"nanoid": "^5.1.
|
|
86
|
-
"nodemailer": "^8.0.
|
|
85
|
+
"nanoid": "^5.1.11",
|
|
86
|
+
"nodemailer": "^8.0.7",
|
|
87
87
|
"passport-google-oauth20": "^2.0.0",
|
|
88
88
|
"passport-local": "^1.0.0",
|
|
89
89
|
"rollup": "^4.60.2",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"statuses": "^2.0.2",
|
|
95
95
|
"tailwindcss": "^4.2.4",
|
|
96
96
|
"tinguir": "^0.0.7",
|
|
97
|
-
"vite": "^8.0.
|
|
97
|
+
"vite": "^8.0.10",
|
|
98
98
|
"winston": "^3.19.0",
|
|
99
99
|
"winston-daily-rotate-file": "^5.0.0",
|
|
100
100
|
"yargs-parser": "^22.0.0"
|
package/src/config/defaults.mjs
CHANGED
|
@@ -23,6 +23,13 @@ export default function make_config_defaults() {
|
|
|
23
23
|
|
|
24
24
|
static: {
|
|
25
25
|
favicon: root("src/static/img/favicon.ico"),
|
|
26
|
+
headers: {
|
|
27
|
+
"/sw.js": {
|
|
28
|
+
"Cache-Control": "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0"
|
|
29
|
+
}
|
|
30
|
+
//"/index.html": { "Cache-Control": "no-cache, max-age=0" },
|
|
31
|
+
//"/": { "Cache-Control": "no-cache, max-age=0" }
|
|
32
|
+
},
|
|
26
33
|
folders: {
|
|
27
34
|
"/build": root("build"),
|
|
28
35
|
"/static": root("src/static"),
|
|
@@ -66,7 +66,7 @@ const init_basic_auth_middleware = (app, options) => {
|
|
|
66
66
|
return unauth_err()
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
const user = await auth_user(aaccount.username, aaccount.password,
|
|
69
|
+
const user = await auth_user(aaccount.username, aaccount.password, ctx)
|
|
70
70
|
|
|
71
71
|
if (user === false || user === undefined || user === null) {
|
|
72
72
|
return unauth_err()
|
|
@@ -4,7 +4,7 @@ import koa_mount from "koa-mount"
|
|
|
4
4
|
import koa_serve from "koa-static"
|
|
5
5
|
|
|
6
6
|
const init_static_middleware = (app, config) => {
|
|
7
|
-
const { favicon, folders } = config
|
|
7
|
+
const { favicon, folders, headers } = config
|
|
8
8
|
|
|
9
9
|
if (favicon && existsSync(favicon)) {
|
|
10
10
|
app.context.miolo.logger.debug(`[static] Serving favicon from -${favicon}-`)
|
|
@@ -15,9 +15,25 @@ const init_static_middleware = (app, config) => {
|
|
|
15
15
|
)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
// Do not cache some specific files
|
|
19
|
+
app.use(async (ctx, next) => {
|
|
20
|
+
for (const [fpath, fheaders] of Object.entries(headers)) {
|
|
21
|
+
if (ctx.path === fpath) {
|
|
22
|
+
app.context.miolo.logger.info(
|
|
23
|
+
`[static] Setting headers for -${fpath}- ${Object.keys(fheaders).join(", ")}`
|
|
24
|
+
)
|
|
25
|
+
for (const [key, value] of Object.entries(fheaders)) {
|
|
26
|
+
ctx.set(key, value)
|
|
27
|
+
}
|
|
28
|
+
break
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
await next()
|
|
32
|
+
})
|
|
33
|
+
|
|
18
34
|
for (const [froute, fpath] of Object.entries(folders)) {
|
|
19
35
|
if (fpath && existsSync(fpath)) {
|
|
20
|
-
app.context.miolo.logger.
|
|
36
|
+
app.context.miolo.logger.info(`[static] Mounting static folder ${froute} => -${fpath}-`)
|
|
21
37
|
app.use(koa_mount(froute, koa_serve(fpath, { index: false })))
|
|
22
38
|
} else {
|
|
23
39
|
app.context.miolo.logger.warn(
|
package/template/biome.json
CHANGED
package/template/package.json
CHANGED
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"farrapa": "^3.0.0-beta.10",
|
|
44
44
|
"intre": "^3.0.0-beta.4",
|
|
45
45
|
"joi": "^18.1.2",
|
|
46
|
-
"lucide-react": "^1.
|
|
47
|
-
"miolo-cli": "^3.0.0-beta.
|
|
46
|
+
"lucide-react": "^1.14.0",
|
|
47
|
+
"miolo-cli": "^3.0.0-beta.182",
|
|
48
48
|
"miolo-model": "file:../miolo-model",
|
|
49
|
-
"miolo-react": "^3.0.0-beta.
|
|
49
|
+
"miolo-react": "^3.0.0-beta.182",
|
|
50
50
|
"next-themes": "^0.4.6",
|
|
51
51
|
"radix-ui": "^1.4.3",
|
|
52
52
|
"react": "^19.2.5",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"tw-animate-css": "^1.4.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@biomejs/biome": "2.4.
|
|
64
|
-
"miolo": "^3.0.0-beta.
|
|
63
|
+
"@biomejs/biome": "2.4.14",
|
|
64
|
+
"miolo": "^3.0.0-beta.182",
|
|
65
65
|
"sass-embedded": "^1.99.0"
|
|
66
66
|
},
|
|
67
67
|
"overrides": {
|
|
@@ -15,3 +15,19 @@ hydrateRoot(
|
|
|
15
15
|
</BrowserRouter>
|
|
16
16
|
</AppBrowser>
|
|
17
17
|
)
|
|
18
|
+
|
|
19
|
+
// Comprobamos si el navegador del usuario soporta Service Workers
|
|
20
|
+
if ("serviceWorker" in navigator) {
|
|
21
|
+
// Esperamos a que la página cargue completamente para no afectar el rendimiento inicial
|
|
22
|
+
window.addEventListener("load", () => {
|
|
23
|
+
// Apuntamos a la URL pública donde Miolo está sirviendo el archivo
|
|
24
|
+
navigator.serviceWorker
|
|
25
|
+
.register("/sw.js")
|
|
26
|
+
.then((registration) => {
|
|
27
|
+
console.log("Service Worker registrado con éxito. Scope:", registration.scope)
|
|
28
|
+
})
|
|
29
|
+
.catch((error) => {
|
|
30
|
+
console.error("Fallo al registrar el Service Worker:", error)
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
|
+
|
|
3
4
|
<head>
|
|
4
5
|
<meta charset="utf-8">
|
|
5
6
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
@@ -9,12 +10,20 @@
|
|
|
9
10
|
<meta name="keywords" content="miolo-sample" />
|
|
10
11
|
<meta name="author" content="devel@afialapis.com" />
|
|
11
12
|
|
|
12
|
-
<!-- Touch Icons - iOS and Android 2.1+ 180x180 pixels in size. -->
|
|
13
|
+
<!-- Touch Icons - iOS and Android 2.1+ 180x180 pixels in size. -->
|
|
13
14
|
<!--<link rel="apple-touch-icon-precomposed" href="/favicon.ico"/>-->
|
|
14
15
|
<!-- Firefox, Chrome, Safari, IE 11+ and Opera. 196x196 pixels in size. -->
|
|
15
|
-
<link rel="icon" href="/favicon.ico"/>
|
|
16
|
+
<link rel="icon" href="/favicon.ico" />
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
<!-- PWA -->
|
|
21
|
+
<link rel="manifest" href="/manifest.json">
|
|
22
|
+
<meta name="theme-color" content="#fb64b6">
|
|
23
|
+
|
|
16
24
|
</head>
|
|
17
25
|
|
|
18
26
|
<body>
|
|
19
27
|
</body>
|
|
20
|
-
|
|
28
|
+
|
|
29
|
+
</html>
|
|
@@ -15,8 +15,11 @@ export default function Security() {
|
|
|
15
15
|
const resp = await fetcher.post("/user/chpwd", params)
|
|
16
16
|
if (resp.ok === true) {
|
|
17
17
|
toast.success(resp.data.msg)
|
|
18
|
+
} else {
|
|
19
|
+
toast.error(resp.error)
|
|
18
20
|
}
|
|
19
|
-
|
|
21
|
+
|
|
22
|
+
return { ok: resp.ok, error: resp?.error }
|
|
20
23
|
} catch (e) {
|
|
21
24
|
return { ok: false, error: `Error al modificar la contraseña: ${e}` }
|
|
22
25
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { useCallback, useState } from "react"
|
|
2
2
|
import useSessionContext from "#cli/context/session/useSessionContext.mjs"
|
|
3
|
+
import useUIContext from "#cli/context/ui/useUIContext.mjs"
|
|
3
4
|
import TodoList from "#ns/models/TodoList.mjs"
|
|
4
5
|
import TodosContext from "./TodosContext.jsx"
|
|
5
6
|
|
|
6
7
|
const TodosProvider = ({ children }) => {
|
|
7
8
|
// const [status, setStatus] = useState("loaded")
|
|
8
9
|
const { useSsrData, fetcher, authenticated } = useSessionContext()
|
|
10
|
+
const { toast } = useUIContext()
|
|
9
11
|
const [useCrud, setUseCrud] = useState(true)
|
|
10
12
|
|
|
11
13
|
const {
|
|
@@ -17,17 +19,16 @@ const TodosProvider = ({ children }) => {
|
|
|
17
19
|
loader: useCallback(
|
|
18
20
|
async (_context, fetcher) => {
|
|
19
21
|
//setStatus("loading")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
} else {
|
|
25
|
-
data = await fetcher.get("/api/todo/list")
|
|
22
|
+
const res = useCrud ? await fetcher.read("/crud/todo") : await fetcher.get("/api/todo/list")
|
|
23
|
+
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
toast.error(`Error loading todos: ${res.error}`)
|
|
26
26
|
}
|
|
27
|
+
const data = res?.data || []
|
|
27
28
|
//setStatus("loaded")
|
|
28
29
|
return new TodoList(data.sort((a, b) => b.created_at - a.created_at))
|
|
29
30
|
},
|
|
30
|
-
[useCrud]
|
|
31
|
+
[useCrud, toast]
|
|
31
32
|
)
|
|
32
33
|
})
|
|
33
34
|
|
|
@@ -40,20 +41,22 @@ const TodosProvider = ({ children }) => {
|
|
|
40
41
|
done: false
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
const res = useCrud
|
|
45
|
+
? await fetcher.upsave("crud/todo", todoObject)
|
|
46
|
+
: await fetcher.post("/api/todo/upsave", todoObject)
|
|
47
|
+
|
|
48
|
+
if (!res.ok) {
|
|
49
|
+
toast.error(`Error adding todo: ${res.error}`)
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
todoObject.id = res?.data?.id
|
|
53
|
+
|
|
51
54
|
setTodoList([todoObject, ...todoList])
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
addIt()
|
|
55
58
|
},
|
|
56
|
-
[fetcher, todoList, setTodoList, useCrud]
|
|
59
|
+
[fetcher, todoList, setTodoList, useCrud, toast]
|
|
57
60
|
)
|
|
58
61
|
|
|
59
62
|
const toggleTodo = useCallback(
|
|
@@ -65,19 +68,21 @@ const TodosProvider = ({ children }) => {
|
|
|
65
68
|
|
|
66
69
|
setTodoList(nTodoList)
|
|
67
70
|
|
|
68
|
-
|
|
69
|
-
await fetcher.upsave("crud/todo", nTodoList[selectedTodoIndex])
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const res = useCrud
|
|
72
|
+
? await fetcher.upsave("crud/todo", nTodoList[selectedTodoIndex])
|
|
73
|
+
: await fetcher.post("/api/todo/toggle", {
|
|
74
|
+
id: todoId,
|
|
75
|
+
done: nTodoList[selectedTodoIndex].done
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
if (!res.ok) {
|
|
79
|
+
toast.error(`Error toggling todo: ${res.error}`)
|
|
75
80
|
}
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
toggleIt()
|
|
79
84
|
},
|
|
80
|
-
[fetcher, todoList, setTodoList, useCrud]
|
|
85
|
+
[fetcher, todoList, setTodoList, useCrud, toast]
|
|
81
86
|
)
|
|
82
87
|
|
|
83
88
|
const removeTodo = useCallback(
|
|
@@ -90,38 +95,41 @@ const TodosProvider = ({ children }) => {
|
|
|
90
95
|
|
|
91
96
|
setTodoList(nTodoList)
|
|
92
97
|
|
|
93
|
-
|
|
94
|
-
await fetcher.remove("crud/todo", todoId)
|
|
98
|
+
const res = useCrud
|
|
99
|
+
? await fetcher.remove("crud/todo", todoId)
|
|
100
|
+
: await fetcher.post("api/todo/delete", { id: todoId })
|
|
101
|
+
|
|
102
|
+
if (!res.ok) {
|
|
103
|
+
toast.error(`Error removing todo: ${res.error}`)
|
|
95
104
|
} else {
|
|
96
|
-
|
|
105
|
+
toast.info(`Todo removed successfully`)
|
|
97
106
|
}
|
|
98
107
|
},
|
|
99
|
-
[fetcher, todoList, setTodoList, useCrud]
|
|
108
|
+
[fetcher, todoList, setTodoList, useCrud, toast]
|
|
100
109
|
)
|
|
101
110
|
|
|
102
111
|
const checkLastHours = useCallback(
|
|
103
112
|
async ({ hours }) => {
|
|
104
|
-
const {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
const res = await fetcher.get("api/todo/last_hours", { hours })
|
|
114
|
+
if (res.ok === true) {
|
|
115
|
+
toast.info(`You have added ${res?.data?.count} todos in the last ${hours} hours`)
|
|
116
|
+
} else {
|
|
117
|
+
toast.error(`Error checking last hours: ${res.error}`)
|
|
118
|
+
}
|
|
108
119
|
},
|
|
109
|
-
[fetcher]
|
|
120
|
+
[fetcher, toast]
|
|
110
121
|
)
|
|
111
122
|
|
|
112
123
|
const insertFakeTodo = useCallback(async () => {
|
|
113
|
-
const {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
} = await fetcher.post("api/todo/fake", { done: true })
|
|
118
|
-
if (!ok) {
|
|
119
|
-
alert(`Error adding fake todo: ${error}`)
|
|
124
|
+
const res = await fetcher.post("api/todo/fake", { done: true })
|
|
125
|
+
|
|
126
|
+
if (!res.ok) {
|
|
127
|
+
toast.error(`Error adding fake todo: ${res.error}`)
|
|
120
128
|
} else {
|
|
121
|
-
|
|
129
|
+
toast.info(`Fake todo added with id ${res?.data?.id}`)
|
|
122
130
|
}
|
|
123
131
|
refreshTodoList()
|
|
124
|
-
}, [fetcher, refreshTodoList])
|
|
132
|
+
}, [fetcher, refreshTodoList, toast])
|
|
125
133
|
|
|
126
134
|
return (
|
|
127
135
|
<TodosContext.Provider
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { db_auth_user } from "#server/db/io/users/auth.mjs"
|
|
2
2
|
|
|
3
|
-
const local_auth_user = async (username, password,
|
|
4
|
-
const [user,
|
|
3
|
+
const local_auth_user = async (username, password, ctx) => {
|
|
4
|
+
const [user, msg] = await db_auth_user(ctx.miolo, username, password)
|
|
5
5
|
|
|
6
|
-
return user
|
|
6
|
+
return [user, msg]
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export default {
|
|
@@ -5,7 +5,7 @@ export async function r_todo_list(ctx, params) {
|
|
|
5
5
|
try {
|
|
6
6
|
ctx.miolo.logger.info(`[r_todo_list] Reading todo list`)
|
|
7
7
|
|
|
8
|
-
const res = await db_todo_read(ctx,
|
|
8
|
+
const res = await db_todo_read(ctx, { filter: {}, options: {} })
|
|
9
9
|
|
|
10
10
|
ctx.miolo.logger.info(`[r_todo_list] Read todo list (${res.length})`)
|
|
11
11
|
return { ok: true, data: res }
|
|
@@ -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
|
+
})
|
|
Binary file
|