miolo 3.0.0-beta.203 → 3.0.0-beta.204
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 +5 -5
- package/src/config/defaults.mjs +5 -2
- package/src/engines/socket/index.mjs +38 -38
- package/src/middleware/auth/passport/session/index.mjs +5 -0
- package/src/middleware/ssr/ssr_render.mjs +7 -6
- package/src/server.mjs +5 -2
- package/template/package.json +4 -4
- package/template/src/cli/pages/todos/TodoActions.jsx +19 -3
- package/template/src/cli/pages/todos/context/TodosProvider.jsx +33 -3
- package/template/src/server/miolo/index.mjs +20 -1
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.204",
|
|
4
4
|
"description": "all-in-one koa-based server",
|
|
5
5
|
"author": "Donato Lorenzo <donato@afialapis.com>",
|
|
6
6
|
"contributors": [
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"@babel/plugin-proposal-decorators": "^7.29.0",
|
|
48
48
|
"@babel/preset-env": "^7.29.5",
|
|
49
49
|
"@babel/preset-react": "^7.28.5",
|
|
50
|
-
"@dotenvx/dotenvx": "^1.
|
|
50
|
+
"@dotenvx/dotenvx": "^1.67.0",
|
|
51
51
|
"@koa/bodyparser": "^6.1.0",
|
|
52
52
|
"@koa/cors": "^5.0.0",
|
|
53
53
|
"@koa/router": "^15.5.0",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"is-plain-object": "^5.0.0",
|
|
73
73
|
"joi": "^18.2.1",
|
|
74
74
|
"jwt-simple": "^0.5.6",
|
|
75
|
-
"koa": "^3.2.
|
|
75
|
+
"koa": "^3.2.1",
|
|
76
76
|
"koa-compress": "^5.2.1",
|
|
77
77
|
"koa-connect": "^2.1.1",
|
|
78
78
|
"koa-favicon": "^2.1.0",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"koa-session": "^7.0.2",
|
|
84
84
|
"koa-static": "^5.0.0",
|
|
85
85
|
"nanoid": "^5.1.11",
|
|
86
|
-
"nodemailer": "^8.0.
|
|
86
|
+
"nodemailer": "^8.0.8",
|
|
87
87
|
"passport-google-oauth20": "^2.0.0",
|
|
88
88
|
"passport-local": "^1.0.0",
|
|
89
89
|
"rollup": "^4.60.4",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"statuses": "^2.0.2",
|
|
95
95
|
"tailwindcss": "^4.3.0",
|
|
96
96
|
"tinguir": "^0.0.7",
|
|
97
|
-
"vite": "^8.0.
|
|
97
|
+
"vite": "^8.0.14",
|
|
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
|
@@ -476,10 +476,13 @@ export default function make_config_defaults() {
|
|
|
476
476
|
|
|
477
477
|
socket: {
|
|
478
478
|
enabled: false,
|
|
479
|
+
// Auto create rooms based on sessions
|
|
480
|
+
// To be able to do like: app.context.miolo.io.to('user_<id>').emit('ns', newData);
|
|
481
|
+
userRooms: true,
|
|
479
482
|
cli: {
|
|
480
483
|
/**
|
|
481
|
-
|
|
482
|
-
|
|
484
|
+
url: '',
|
|
485
|
+
options: {}
|
|
483
486
|
*/
|
|
484
487
|
}
|
|
485
488
|
/*
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//import IO from 'koa-socket-2'
|
|
2
1
|
import { Server } from "socket.io"
|
|
3
2
|
|
|
4
3
|
function init_socket(app, config) {
|
|
@@ -12,8 +11,44 @@ function init_socket(app, config) {
|
|
|
12
11
|
|
|
13
12
|
const io = new Server(app.http.server)
|
|
14
13
|
|
|
14
|
+
if (config?.userRooms === true) {
|
|
15
|
+
io.use(async (socket, next) => {
|
|
16
|
+
try {
|
|
17
|
+
const { store, options } = app.context.miolo.session || {}
|
|
18
|
+
if (store && options) {
|
|
19
|
+
// Create a fake Koa context to easily parse the signed cookies
|
|
20
|
+
const ctx = app.createContext(
|
|
21
|
+
socket.request,
|
|
22
|
+
socket.request.res || { headersSent: false }
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
// Read the session cookie (Koa handles signature validation if options.signed is true)
|
|
26
|
+
const sessionCookieValue = ctx.cookies.get(options.key, options)
|
|
27
|
+
|
|
28
|
+
if (sessionCookieValue) {
|
|
29
|
+
// If the cookie is present, koa-session stores the external key directly
|
|
30
|
+
// or sometimes it's base64 encoded. koa-session's decode function:
|
|
31
|
+
const sessionId = sessionCookieValue
|
|
32
|
+
|
|
33
|
+
const session = await store.get(sessionId, undefined, {})
|
|
34
|
+
|
|
35
|
+
if (session?.user) {
|
|
36
|
+
const userId = session.user?.id
|
|
37
|
+
socket.join(`user_${userId}`)
|
|
38
|
+
socket.mioloUser = userId // Attach for convenience
|
|
39
|
+
logger.info(`[socket] Socket ${socket.id} joined room user_${userId}`)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} catch (err) {
|
|
44
|
+
logger.error(`[socket] Error parsing session: ${err.message}`)
|
|
45
|
+
}
|
|
46
|
+
next()
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
15
50
|
io.on("connection", (socket) => {
|
|
16
|
-
logger.
|
|
51
|
+
logger.info(`[socket] Connection from ... `) // ${i.ip} ${i.id}`)
|
|
17
52
|
|
|
18
53
|
if (config?.connection) {
|
|
19
54
|
config.connection(socket)
|
|
@@ -24,42 +59,7 @@ function init_socket(app, config) {
|
|
|
24
59
|
}
|
|
25
60
|
})
|
|
26
61
|
|
|
27
|
-
|
|
28
|
-
// let i= {id: '', ip: ''}
|
|
29
|
-
// try {
|
|
30
|
-
// i.id = ctx.socket.id
|
|
31
|
-
// } catch (e) {}
|
|
32
|
-
// try {
|
|
33
|
-
// i.ip = ctx.socket.handshake.address
|
|
34
|
-
// } catch (e) {}
|
|
35
|
-
// return i
|
|
36
|
-
// }
|
|
37
|
-
|
|
38
|
-
// const io = new IO({ origins: '*:*'})
|
|
39
|
-
|
|
40
|
-
// io.on('connection', function (ctx, data) {
|
|
41
|
-
// const logger = ctx.miolo.logger
|
|
42
|
-
// const i= getInfo(ctx)
|
|
43
|
-
// logger.warn(`[socket] Connection from ${i.ip} ${i.id}`)
|
|
44
|
-
// if (config?.connection) {
|
|
45
|
-
// config.connection(ctx, data)
|
|
46
|
-
// }
|
|
47
|
-
// })
|
|
48
|
-
|
|
49
|
-
// io.on('disconnect', function (ctx, data) {
|
|
50
|
-
// const logger = ctx.miolo.logger
|
|
51
|
-
// const i = getInfo(ctx)
|
|
52
|
-
// logger.warn(`[socket] Disconnected ${i.ip} ${i.id} => ${data}`)
|
|
53
|
-
// })
|
|
54
|
-
//
|
|
55
|
-
// io.on('error', function (ctx, data) {
|
|
56
|
-
// const logger = ctx.miolo.logger
|
|
57
|
-
// const i = getInfo(ctx)
|
|
58
|
-
// logger.error(`[socket] Error on ${i.ip} ${i.id} => ${data}`)
|
|
59
|
-
// })
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
// io.attach(app)
|
|
62
|
+
app.context.miolo.io = io
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
export { init_socket }
|
|
@@ -6,7 +6,7 @@ export async function init_ssr_render_middleware(app, config, devRender = undefi
|
|
|
6
6
|
const ssrConfig = config.build.ssr
|
|
7
7
|
const httpConfig = config.http
|
|
8
8
|
const authConfig = config?.auth || {}
|
|
9
|
-
|
|
9
|
+
const socketConfig = config?.socket || {}
|
|
10
10
|
|
|
11
11
|
const ssr_build_context = ssr_context_builder_make(app, ssrConfig)
|
|
12
12
|
const ssr_loader = ssr_loader_make(app, ssrConfig)
|
|
@@ -32,11 +32,12 @@ export async function init_ssr_render_middleware(app, config, devRender = undefi
|
|
|
32
32
|
logout_url:
|
|
33
33
|
ctx.session?.auth_method === "google"
|
|
34
34
|
? authConfig?.passport?.google_url_logout
|
|
35
|
-
: authConfig?.passport?.local_url_logout
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
: authConfig?.passport?.local_url_logout,
|
|
36
|
+
socket: {
|
|
37
|
+
enabled: socketConfig?.enabled === true,
|
|
38
|
+
url: socketConfig?.config?.cli?.url || null,
|
|
39
|
+
options: socketConfig?.config?.cli?.options || {}
|
|
40
|
+
}
|
|
40
41
|
}
|
|
41
42
|
ctx.miolo.logger.debug(
|
|
42
43
|
`[render-ssr] rendering an ${ctx?.session?.authenticated === true ? "authenticated" : "unauthenticated"} context...`
|
package/src/server.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import Koa from "koa"
|
|
2
2
|
import { init_config } from "./config/index.mjs"
|
|
3
|
-
//import {init_socket} from './engines/socket/index.mjs'
|
|
4
3
|
import { init_cron } from "./engines/cron/index.mjs"
|
|
5
4
|
import { init_http_server } from "./engines/http/index.mjs"
|
|
5
|
+
import { init_socket } from "./engines/socket/index.mjs"
|
|
6
6
|
import { init_basic_auth_middleware } from "./middleware/auth/basic.mjs"
|
|
7
7
|
import { init_guest_auth_middleware } from "./middleware/auth/guest.mjs"
|
|
8
8
|
import { init_passport_auth_middleware } from "./middleware/auth/passport/index.mjs"
|
|
@@ -102,6 +102,9 @@ async function miolo(makeConfig, devInit = undefined, devRender = undefined) {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
await app.http.start()
|
|
105
|
+
if (app.context.miolo?.io) {
|
|
106
|
+
app.context.miolo.io.attach(app.http.server)
|
|
107
|
+
}
|
|
105
108
|
await app.cron.start()
|
|
106
109
|
}
|
|
107
110
|
|
|
@@ -124,7 +127,7 @@ async function miolo(makeConfig, devInit = undefined, devRender = undefined) {
|
|
|
124
127
|
}
|
|
125
128
|
|
|
126
129
|
// Socket.io
|
|
127
|
-
|
|
130
|
+
init_socket(app, config?.socket)
|
|
128
131
|
|
|
129
132
|
return app
|
|
130
133
|
}
|
package/template/package.json
CHANGED
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"intre": "^3.0.0-beta.4",
|
|
46
46
|
"joi": "^18.2.1",
|
|
47
47
|
"lucide-react": "^1.16.0",
|
|
48
|
-
"miolo-cli": "^3.0.0-beta.
|
|
48
|
+
"miolo-cli": "^3.0.0-beta.204",
|
|
49
49
|
"miolo-model": "file:../miolo-model",
|
|
50
|
-
"miolo-react": "^3.0.0-beta.
|
|
50
|
+
"miolo-react": "^3.0.0-beta.204",
|
|
51
51
|
"next-themes": "^0.4.6",
|
|
52
52
|
"radix-ui": "^1.4.3",
|
|
53
53
|
"react": "^19.2.6",
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@biomejs/biome": "2.4.15",
|
|
65
|
-
"miolo": "^3.0.0-beta.
|
|
66
|
-
"sass-embedded": "^1.
|
|
65
|
+
"miolo": "^3.0.0-beta.204",
|
|
66
|
+
"sass-embedded": "^1.100.0"
|
|
67
67
|
},
|
|
68
68
|
"overrides": {
|
|
69
69
|
"@babel/runtime": "^7.28.6",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bomb, Bone, CircleQuestionMark, RefreshCw } from "lucide-react"
|
|
1
|
+
import { Bomb, Bone, CircleQuestionMark, Phone, RefreshCw } from "lucide-react"
|
|
2
2
|
import { useState } from "react"
|
|
3
3
|
import { Field, FieldContent, FieldLabel } from "#cli/components/ui/field.jsx"
|
|
4
4
|
import { Button } from "#cli/components/ui/patched/button.jsx"
|
|
@@ -12,8 +12,15 @@ const throwAnError = () => {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export default function TodoActions() {
|
|
15
|
-
const {
|
|
16
|
-
|
|
15
|
+
const {
|
|
16
|
+
refreshTodoList,
|
|
17
|
+
checkLastHours,
|
|
18
|
+
insertFakeTodo,
|
|
19
|
+
canEdit,
|
|
20
|
+
useCrud,
|
|
21
|
+
setUseCrud,
|
|
22
|
+
pingSocket
|
|
23
|
+
} = useTodosContext()
|
|
17
24
|
const [hours, _setHours] = useState(1)
|
|
18
25
|
|
|
19
26
|
return (
|
|
@@ -51,6 +58,15 @@ export default function TodoActions() {
|
|
|
51
58
|
<Bomb size={18} />
|
|
52
59
|
{`Throw an JS error`}
|
|
53
60
|
</Button>
|
|
61
|
+
|
|
62
|
+
<Button
|
|
63
|
+
onClick={() => pingSocket()}
|
|
64
|
+
disabled={!canEdit}
|
|
65
|
+
className={`px-4 py-6 text-white rounded-lg transition-colors flex items-center gap-2 cursor-pointer ${useCrud ? "bg-pink-500 hover:bg-pink-400" : "bg-blue-500 hover:bg-blue-400"}`}
|
|
66
|
+
>
|
|
67
|
+
<Phone size={18} />
|
|
68
|
+
Ping through socket
|
|
69
|
+
</Button>
|
|
54
70
|
</div>
|
|
55
71
|
|
|
56
72
|
<h1 className="text-3xl font-bold text-center mt-8 mb-8 text-gray-800 dark:text-white">
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useState } from "react"
|
|
1
|
+
import { useCallback, useEffect, useState } from "react"
|
|
2
2
|
import useSessionContext from "#cli/context/session/useSessionContext.mjs"
|
|
3
3
|
import useUIContext from "#cli/context/ui/useUIContext.mjs"
|
|
4
4
|
import TodoList from "#ns/models/TodoList.mjs"
|
|
@@ -6,9 +6,10 @@ import TodosContext from "./TodosContext.jsx"
|
|
|
6
6
|
|
|
7
7
|
const TodosProvider = ({ children }) => {
|
|
8
8
|
// const [status, setStatus] = useState("loaded")
|
|
9
|
-
const { useSsrData, fetcher, authenticated } = useSessionContext()
|
|
9
|
+
const { useSsrData, fetcher, socket, authenticated } = useSessionContext()
|
|
10
10
|
const { toast } = useUIContext()
|
|
11
11
|
const [useCrud, setUseCrud] = useState(true)
|
|
12
|
+
const [socketInited, setSocketInited] = useState(false)
|
|
12
13
|
|
|
13
14
|
const {
|
|
14
15
|
data: todoList,
|
|
@@ -132,6 +133,34 @@ const TodosProvider = ({ children }) => {
|
|
|
132
133
|
refreshTodoList()
|
|
133
134
|
}, [fetcher, refreshTodoList, toast])
|
|
134
135
|
|
|
136
|
+
const pingSocket = useCallback(() => {
|
|
137
|
+
if (!socket) {
|
|
138
|
+
toast.error("Socket not initialized")
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
socket.emit("ping", { timestamp: new Date().toISOString() })
|
|
142
|
+
}, [socket, toast])
|
|
143
|
+
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (socket === undefined) {
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (socketInited) {
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
setSocketInited(true)
|
|
153
|
+
|
|
154
|
+
socket.on("connect", () => {
|
|
155
|
+
console.log("Connected to server!")
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
socket.on("todos-update", (data) => {
|
|
159
|
+
console.log("TODOS UPDATED!!!")
|
|
160
|
+
console.log(data)
|
|
161
|
+
})
|
|
162
|
+
}, [socket, socketInited])
|
|
163
|
+
|
|
135
164
|
return (
|
|
136
165
|
<TodosContext.Provider
|
|
137
166
|
value={{
|
|
@@ -146,7 +175,8 @@ const TodosProvider = ({ children }) => {
|
|
|
146
175
|
insertFakeTodo,
|
|
147
176
|
canEdit: authenticated,
|
|
148
177
|
useCrud,
|
|
149
|
-
setUseCrud
|
|
178
|
+
setUseCrud,
|
|
179
|
+
pingSocket
|
|
150
180
|
}}
|
|
151
181
|
>
|
|
152
182
|
{children}
|
|
@@ -19,6 +19,25 @@ export default () => {
|
|
|
19
19
|
build: {
|
|
20
20
|
ssr: { loader }
|
|
21
21
|
},
|
|
22
|
-
cron: init_cron()
|
|
22
|
+
cron: init_cron(),
|
|
23
|
+
socket: {
|
|
24
|
+
enabled: true,
|
|
25
|
+
namespaces: [
|
|
26
|
+
{
|
|
27
|
+
name: "todos-update",
|
|
28
|
+
listener: (data) => {
|
|
29
|
+
console.log("TODOS UPDATED!!!")
|
|
30
|
+
console.log(data)
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "ping",
|
|
35
|
+
listener: (data) => {
|
|
36
|
+
console.log("PING!!!")
|
|
37
|
+
console.log(data)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
23
42
|
}
|
|
24
43
|
}
|