@raclettejs/core 0.1.18 → 0.1.20
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/CHANGELOG.md +23 -0
- package/bin/cli.js +1 -1
- package/dev/README.md +4 -0
- package/dist/cli.js +135 -124
- package/dist/cli.js.map +4 -4
- package/dist/index.js +9 -8
- package/dist/index.js.map +4 -4
- package/package.json +9 -5
- package/services/backend/delay-api-debugger.sh +0 -0
- package/services/backend/package.json +1 -0
- package/services/backend/src/app.ts +4 -0
- package/services/backend/src/core/config/configService.ts +10 -1
- package/services/backend/src/core/events/eventEmitter.ts +32 -7
- package/services/backend/src/core/http/request-params.plugin.ts +2 -2
- package/services/backend/src/core/pluginSystem/pluginFastifyInstance.ts +4 -1
- package/services/backend/src/core/pluginSystem/pluginTypes.ts +3 -1
- package/services/backend/src/core/sockets/createSystemEventHandlers.ts +7 -0
- package/services/backend/src/core/sockets/index.ts +61 -13
- package/services/backend/src/core/sockets/socketManager.ts +452 -105
- package/services/backend/src/core/sockets/socketTypes.ts +13 -1
- package/services/backend/src/core/sockets/workSessionJoinPayload.ts +106 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.get.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.getAll.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.hardDelete.ts +16 -19
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.patch.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.post.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.remove.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/composition.service.ts +86 -3
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/index.ts +2 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.get.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.getAll.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.hardDelete.ts +16 -19
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.patch.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.post.bulk.ts +60 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.post.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.remove.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.restore.ts +12 -15
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/interactionLink.service.ts +96 -12
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/index.ts +2 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.get.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.getAll.ts +4 -2
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.hardDelete.ts +12 -17
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.patch.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.post.bulk.ts +62 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.post.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.remove.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.restore.ts +12 -15
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/project.service.ts +1 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.get.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.getAll.ts +4 -2
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.hardDelete.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.patch.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.post.ts +4 -2
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.remove.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/index.ts +2 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.get.ts +1 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.getAll.ts +1 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.hardDelete.ts +10 -15
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.patch.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.post.bulk.ts +60 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.post.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.remove.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.restore.ts +12 -15
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/tag.service.ts +73 -3
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.get.ts +1 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.getAll.ts +1 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.hardDelete.ts +10 -15
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.patch.ts +4 -6
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.patchLastProject.ts +4 -2
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.post.ts +3 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.remove.ts +3 -4
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.restore.ts +12 -15
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/events/index.ts +45 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/helpers/crud.ts +12 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/helpers/payload.ts +21 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/index.ts +55 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/index.ts +19 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.get.ts +53 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.getAll.ts +39 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.hardDelete.ts +53 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.patch.ts +58 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.post.ts +53 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.remove.ts +52 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/workSession.model.ts +65 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/workSession.schema.ts +125 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/workSession.service.ts +351 -0
- package/services/backend/src/corePlugins/raclette__core/backend/index.ts +2 -0
- package/services/backend/src/corePlugins/raclette__core/frontend/generated-config.ts +159 -24
- package/services/backend/src/modules/authentication/index.ts +255 -4
- package/services/backend/src/modules/hooks/rate-limiter.ts +21 -0
- package/services/backend/src/types/custom-fastify.d.ts +17 -0
- package/services/backend/src/utils/request.utils.ts +4 -1
- package/services/backend/types/index.d.ts +15 -1
- package/services/backend/yarn.lock +13 -4
- package/services/frontend/index.html +1 -1
- package/services/frontend/provision/entrypoint.sh +0 -0
- package/services/frontend/src/core/lib/configService.ts +1 -1
- package/services/frontend/src/core/lib/data/dataApi.ts +10 -1
- package/services/frontend/src/core/lib/dataHelper.ts +1 -1
- package/services/frontend/src/core/lib/eggs/snow.ts +66 -48
- package/services/frontend/src/core/lib/helpers/index.ts +1 -0
- package/services/frontend/src/core/lib/helpers/removeEmpty.ts +69 -0
- package/services/frontend/src/core/lib/httpClient.ts +19 -0
- package/services/frontend/src/core/main.ts +20 -10
- package/services/frontend/src/core/setup/socket.ts +4 -3
- package/services/frontend/src/core/setup/socketClient.ts +31 -3
- package/services/frontend/src/core/setup/socketEvents.ts +92 -8
- package/services/frontend/src/core/store/index.ts +5 -1
- package/services/frontend/src/core/store/reducers/compositions/index.ts +2 -2
- package/services/frontend/src/core/store/reducers/interactionLinks/index.ts +1 -1
- package/services/frontend/src/core/store/reducers/widgets/reducers.ts +1 -2
- package/services/frontend/src/core/store/types/index.ts +0 -1
- package/services/frontend/src/core/types/PluginRegistrar.ts +8 -6
- package/services/frontend/src/core/types/Store.ts +1 -0
- package/services/frontend/src/orchestrator/components/composition/WidgetsLayoutLoader.vue +68 -8
- package/services/frontend/src/orchestrator/components/menu/UserMenu.vue +17 -5
- package/services/frontend/src/orchestrator/components/welcomeScreen/AdminWelcomeScreen.vue +1 -1
- package/services/frontend/src/orchestrator/composables/index.ts +1 -0
- package/services/frontend/src/orchestrator/composables/usePluginApi.ts +0 -3
- package/services/frontend/src/orchestrator/composables/useRouteState.ts +23 -4
- package/services/frontend/src/orchestrator/composables/useWidgetLifecycle.ts +166 -0
- package/services/frontend/src/orchestrator/helpers/index.ts +1 -0
- package/services/frontend/src/orchestrator/i18n/de-DE.json +15 -1
- package/services/frontend/src/orchestrator/i18n/en-EU.json +15 -1
- package/services/frontend/src/orchestrator/i18n/sk.json +15 -1
- package/services/frontend/src/orchestrator/index.ts +34 -4
- package/services/frontend/src/orchestrator/router/routeParserHelper.ts +106 -1
- package/services/frontend/src/orchestrator/types/Widgets.ts +2 -0
- package/services/frontend/types.ts +1 -0
- package/src/README.md +404 -0
- package/src/types.ts +19 -5
- package/templates/README.md +0 -0
- package/types/index.ts +18 -4
- package/services/backend/.gitignore +0 -17
- package/services/frontend/.gitignore +0 -35
- package/yarn.lock +0 -2937
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raclettejs/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"description": "racletteJS core package",
|
|
5
5
|
"repository": "https://gitlab.com/raclettejs/core",
|
|
6
6
|
"author": "Pacifico Digital Explorations GmbH <info@raclettejs.com>",
|
|
@@ -55,21 +55,26 @@
|
|
|
55
55
|
"import": "./services/frontend/src/orchestrator/index.ts"
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
|
+
"config": {},
|
|
58
59
|
"dependencies": {
|
|
60
|
+
"@inquirer/prompts": "8.2.0",
|
|
61
|
+
"@types/mustache": "4.2.6",
|
|
59
62
|
"chalk": "5.6.2",
|
|
60
63
|
"chokidar": "3.6.0",
|
|
64
|
+
"cli-highlight": "2.1.11",
|
|
61
65
|
"commander": "14.0.1",
|
|
62
66
|
"dotenv": "17.2.2",
|
|
63
67
|
"esbuild": "0.25.9",
|
|
64
68
|
"fs-extra": "11.3.2",
|
|
65
69
|
"globby": "14.1.0",
|
|
66
70
|
"js-yaml": "4.1.0",
|
|
71
|
+
"mustache": "4.2.0",
|
|
67
72
|
"ramda": "0.31.3",
|
|
68
73
|
"tsc-alias": "1.8.16"
|
|
69
74
|
},
|
|
70
75
|
"devDependencies": {
|
|
71
76
|
"@eslint/js": "9.35.0",
|
|
72
|
-
"@raclettejs/types": "^0.1.
|
|
77
|
+
"@raclettejs/types": "^0.1.20",
|
|
73
78
|
"@types/fs-extra": "11.0.4",
|
|
74
79
|
"@types/js-yaml": "4.0.9",
|
|
75
80
|
"@types/node": "24.5.1",
|
|
@@ -87,6 +92,5 @@
|
|
|
87
92
|
"typescript": "5.9.2",
|
|
88
93
|
"typescript-eslint": "8.44.0",
|
|
89
94
|
"vue-eslint-parser": "10.2.0"
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
File without changes
|
|
@@ -17,6 +17,7 @@ import registerCore from "./domains"
|
|
|
17
17
|
import { registerPlugins } from "./core/pluginSystem/pluginLoader"
|
|
18
18
|
import initializeSocketSystem from "./core/sockets/socketManager"
|
|
19
19
|
import jwt from "./modules/authentication"
|
|
20
|
+
import rateLimiter from "./modules/hooks/rate-limiter"
|
|
20
21
|
import eventbus from "./core/eventBus"
|
|
21
22
|
import headersPlugin from "./core/http/headers"
|
|
22
23
|
import httpClient from "./core/http/httpService"
|
|
@@ -137,6 +138,8 @@ export default async (): Promise<FastifyInstance> => {
|
|
|
137
138
|
await fastify.register(mongodb, { uri: process.env.MONGO_HOST ?? "" })
|
|
138
139
|
fastify.register(headersPlugin)
|
|
139
140
|
fastify.register(jwt, { secret: process.env.SERVER_TOKEN_SECRET })
|
|
141
|
+
fastify.register(rateLimiter)
|
|
142
|
+
|
|
140
143
|
fastify.register(valkeyPlugin, {
|
|
141
144
|
url: process.env.CACHE_URL,
|
|
142
145
|
options: {
|
|
@@ -202,6 +205,7 @@ export default async (): Promise<FastifyInstance> => {
|
|
|
202
205
|
"app-request-code",
|
|
203
206
|
"app-broadcast-channels",
|
|
204
207
|
"http-client-used",
|
|
208
|
+
"x-work-session-id", // For work session authentication
|
|
205
209
|
"Cache-Control", // For streaming
|
|
206
210
|
"Connection", // For streaming
|
|
207
211
|
],
|
|
@@ -6,6 +6,10 @@ type RacletteBackendConfig = {
|
|
|
6
6
|
sockets?: {
|
|
7
7
|
autoSend?: any
|
|
8
8
|
}
|
|
9
|
+
accessRateLimit?: {
|
|
10
|
+
max: number
|
|
11
|
+
timeWindow: string
|
|
12
|
+
}
|
|
9
13
|
cache?: {
|
|
10
14
|
persistence?: string
|
|
11
15
|
}
|
|
@@ -66,7 +70,7 @@ export class ConfigService {
|
|
|
66
70
|
public getConfig(): RacletteBackendConfig | null {
|
|
67
71
|
if (!this.config) {
|
|
68
72
|
if (!cachedConfig) {
|
|
69
|
-
console.error("Failed to load
|
|
73
|
+
console.error("Failed to load racletteJS configuration")
|
|
70
74
|
}
|
|
71
75
|
this.config = cachedConfig
|
|
72
76
|
}
|
|
@@ -118,7 +122,12 @@ export class ConfigService {
|
|
|
118
122
|
|
|
119
123
|
return socketConfig.options || {}
|
|
120
124
|
}
|
|
125
|
+
// get fastify rate limiter config
|
|
126
|
+
public getFastifyRateLimits() {
|
|
127
|
+
const config = this.getConfig()
|
|
121
128
|
|
|
129
|
+
return config?.accessRateLimit ?? { max: 1000, timeWindow: "1 minute" }
|
|
130
|
+
}
|
|
122
131
|
// Helper to check if a specific auto-send feature is enabled
|
|
123
132
|
// Default to true unless explicitly set to false
|
|
124
133
|
public isAutoSendEnabled(feature: socketDefaultAutoSend): boolean {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
type Listener = (...args: any[]) => void
|
|
12
|
+
type BroadcastHook = (eventName: string, data: unknown) => void
|
|
12
13
|
|
|
13
14
|
class EventEmitter {
|
|
14
15
|
/*
|
|
@@ -22,6 +23,11 @@ class EventEmitter {
|
|
|
22
23
|
*/
|
|
23
24
|
private eventMap?: Record<string, any>
|
|
24
25
|
|
|
26
|
+
/*
|
|
27
|
+
* @type {function} broadcastHook - optional hook for broadcasting plugin events
|
|
28
|
+
*/
|
|
29
|
+
private broadcastHook?: BroadcastHook
|
|
30
|
+
|
|
25
31
|
/*
|
|
26
32
|
* @param {array} eventMap
|
|
27
33
|
*/
|
|
@@ -36,6 +42,18 @@ class EventEmitter {
|
|
|
36
42
|
this.eventMap = eventMap
|
|
37
43
|
}
|
|
38
44
|
|
|
45
|
+
/*
|
|
46
|
+
* setBroadcastHook
|
|
47
|
+
*
|
|
48
|
+
* Registers a hook function that will be called for plugin events (events containing "--")
|
|
49
|
+
* This allows the EventEmitter to broadcast plugin events to sockets without direct dependencies
|
|
50
|
+
*
|
|
51
|
+
* @param {function} hook - callback function that receives (eventName, data)
|
|
52
|
+
*/
|
|
53
|
+
setBroadcastHook(hook: BroadcastHook): void {
|
|
54
|
+
this.broadcastHook = hook
|
|
55
|
+
}
|
|
56
|
+
|
|
39
57
|
/*
|
|
40
58
|
* on
|
|
41
59
|
*
|
|
@@ -81,13 +99,20 @@ class EventEmitter {
|
|
|
81
99
|
if (!this.isValid(event)) {
|
|
82
100
|
return false
|
|
83
101
|
}
|
|
84
|
-
|
|
102
|
+
|
|
103
|
+
const hasListeners = typeof this.events[event] === "object"
|
|
104
|
+
if (hasListeners) {
|
|
85
105
|
this.events[event].forEach((listener) => listener.apply(this, args))
|
|
106
|
+
}
|
|
86
107
|
|
|
87
|
-
|
|
108
|
+
// Broadcast plugin events (those containing "--") to sockets if hook is registered
|
|
109
|
+
// Plugin events have format: "pluginKey--eventName" (e.g., "pacifico__cheesy-slides--marpUpdated")
|
|
110
|
+
// We broadcast regardless of whether there are listeners, as this is for socket communication
|
|
111
|
+
if (this.broadcastHook && event.includes("--") && args.length > 0) {
|
|
112
|
+
this.broadcastHook(event, args[0])
|
|
88
113
|
}
|
|
89
114
|
|
|
90
|
-
return
|
|
115
|
+
return hasListeners
|
|
91
116
|
}
|
|
92
117
|
|
|
93
118
|
/*
|
|
@@ -110,13 +135,13 @@ class EventEmitter {
|
|
|
110
135
|
* isValid
|
|
111
136
|
*
|
|
112
137
|
* If an eventMap is present this method checks if the given event exists as
|
|
113
|
-
* key in the map.
|
|
138
|
+
* key in the map. Plugin events (containing "--") skip eventMap validation.
|
|
114
139
|
* @param {string} event - event name
|
|
115
140
|
*/
|
|
116
141
|
private isValid(event: string): boolean {
|
|
117
|
-
// Skip validation for plugin
|
|
118
|
-
|
|
119
|
-
|
|
142
|
+
// Skip eventMap validation for plugin events (containing "--")
|
|
143
|
+
// Plugin events have format: "pluginKey--eventName"
|
|
144
|
+
if (event.includes("--")) {
|
|
120
145
|
return true
|
|
121
146
|
}
|
|
122
147
|
|
|
@@ -27,7 +27,7 @@ export default fastifyPlugin(async (fastify) => {
|
|
|
27
27
|
fastify.addHook("onRequest", (request, reply, done) => {
|
|
28
28
|
const url = request.raw.url || ""
|
|
29
29
|
if (!isExcluded(url)) {
|
|
30
|
-
request.log.
|
|
30
|
+
request.log.debug(
|
|
31
31
|
{ url: request.raw.url, id: request.id },
|
|
32
32
|
"Received request",
|
|
33
33
|
)
|
|
@@ -39,7 +39,7 @@ export default fastifyPlugin(async (fastify) => {
|
|
|
39
39
|
fastify.addHook("onResponse", (request, reply, done) => {
|
|
40
40
|
const url = request.raw.url || ""
|
|
41
41
|
if (!isExcluded(url)) {
|
|
42
|
-
request.log.
|
|
42
|
+
request.log.debug(
|
|
43
43
|
{
|
|
44
44
|
url: request.raw.url,
|
|
45
45
|
statusCode: reply.statusCode,
|
|
@@ -56,6 +56,10 @@ export const createPluginFastifyInstance = (
|
|
|
56
56
|
patch: fastify.patch,
|
|
57
57
|
delete: fastify.delete,
|
|
58
58
|
authenticate: fastify.authenticate,
|
|
59
|
+
authenticatedOrWorksession: () =>
|
|
60
|
+
fastify.authenticatedOrWorksession(pluginOptions.key),
|
|
61
|
+
checkPermissions: (permissionsArr) =>
|
|
62
|
+
fastify.checkPermissions(permissionsArr),
|
|
59
63
|
|
|
60
64
|
// Plugin-scoped logger with plugin-specific prefix
|
|
61
65
|
log: pluginLogger,
|
|
@@ -110,7 +114,6 @@ export const createPluginFastifyInstance = (
|
|
|
110
114
|
|
|
111
115
|
fastify.log.info("[Eventbus] Emit Event " + prefixedEventName)
|
|
112
116
|
fastify.eventbus.emit(prefixedEventName, data)
|
|
113
|
-
fastify.wss.emit(prefixedEventName, data)
|
|
114
117
|
}
|
|
115
118
|
},
|
|
116
119
|
|
|
@@ -46,7 +46,9 @@ export type PluginFastifyInstance = {
|
|
|
46
46
|
patch: FastifyInstance["patch"]
|
|
47
47
|
delete: FastifyInstance["delete"]
|
|
48
48
|
authenticate: preHandlerHookHandler
|
|
49
|
-
|
|
49
|
+
/** Allow JWT or work session (X-Work-Session-Id). Plugin handles permission checks. */
|
|
50
|
+
authenticatedOrWorksession: () => preHandlerHookHandler
|
|
51
|
+
checkPermissions: () => preHandlerHookHandler
|
|
50
52
|
/* LOG */
|
|
51
53
|
log: ReturnType<FastifyInstance["log"]["child"]>
|
|
52
54
|
/* DB */
|
|
@@ -7,11 +7,18 @@ export const createSystemEventHandlers = (fastify: FastifyInstance) => {
|
|
|
7
7
|
|
|
8
8
|
const sendToChannel = (payload: FrontendPayload<unknown>, key: string) => {
|
|
9
9
|
// TODO rework this to handle spaces instead of project and in the future document rooms -> y.js?
|
|
10
|
+
// Is this even used? SocketManager also has wss.emit
|
|
11
|
+
fastify.log.debug(
|
|
12
|
+
`[Socket] sendToChannel ${key} to room ${payload.project} and ${payload.workSessionId}`,
|
|
13
|
+
)
|
|
10
14
|
if (payload.project) {
|
|
11
15
|
wss.in(payload.project).emit(key, payload)
|
|
12
16
|
} else {
|
|
13
17
|
wss.emit(key, payload)
|
|
14
18
|
}
|
|
19
|
+
if (payload.workSessionId) {
|
|
20
|
+
wss.in(payload.workSessionId).emit(key, payload)
|
|
21
|
+
}
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
return {
|
|
@@ -2,6 +2,8 @@ import fastifyPlugin from "fastify-plugin"
|
|
|
2
2
|
import { Server } from "socket.io"
|
|
3
3
|
import configService from "@c/config/configService"
|
|
4
4
|
import { getAllowedOrigins } from "@/helpers"
|
|
5
|
+
import { validate } from "uuid"
|
|
6
|
+
import { validateWorkSession } from "./socketManager"
|
|
5
7
|
|
|
6
8
|
export default fastifyPlugin((fastify, opts, done) => {
|
|
7
9
|
// Get socket configuration using the wrfastifyer
|
|
@@ -30,30 +32,76 @@ export default fastifyPlugin((fastify, opts, done) => {
|
|
|
30
32
|
)
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
//
|
|
34
|
-
socketServer.use((socket, next) => {
|
|
35
|
+
// Dual authentication middleware: JWT or workSession
|
|
36
|
+
socketServer.use(async (socket, next) => {
|
|
37
|
+
fastify.log.debug(
|
|
38
|
+
`[Socket Auth] Starting authentication for socket: ${socket.id}`,
|
|
39
|
+
)
|
|
35
40
|
try {
|
|
36
41
|
const token =
|
|
37
42
|
socket.handshake.auth?.token ??
|
|
38
43
|
socket.handshake.headers.authorization?.split(" ")[1]
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
// Try JWT authentication first
|
|
46
|
+
if (token) {
|
|
47
|
+
try {
|
|
48
|
+
// Verify token using fastify-jwt
|
|
49
|
+
const decoded = fastify.jwt.verify(token)
|
|
50
|
+
|
|
51
|
+
// Store decoded token on socket
|
|
52
|
+
socket.decoded_token = decoded
|
|
53
|
+
socket.isWorkSession = false
|
|
42
54
|
|
|
43
|
-
|
|
55
|
+
return next()
|
|
56
|
+
} catch (jwtError: any) {
|
|
57
|
+
// JWT verification failed, continue to workSession check
|
|
58
|
+
fastify.log.debug(
|
|
59
|
+
`[Socket Auth] JWT verification failed for ${socket.id}: ${jwtError.message}, checking workSession`,
|
|
60
|
+
)
|
|
61
|
+
}
|
|
44
62
|
}
|
|
45
|
-
// Verify token using fastify-jwt
|
|
46
|
-
const decoded = fastify.jwt.verify(token)
|
|
47
63
|
|
|
48
|
-
//
|
|
49
|
-
|
|
64
|
+
// Check for workSession authentication (same validation as socketManager.validateWorkSession)
|
|
65
|
+
const sessionId = socket.handshake.auth?.sessionId
|
|
50
66
|
|
|
51
|
-
|
|
52
|
-
|
|
67
|
+
if (sessionId) {
|
|
68
|
+
fastify.log.info(
|
|
69
|
+
`[Socket Auth] Attempting workSession authentication for socket: ${socket.id}, sessionId: ${sessionId}`,
|
|
70
|
+
)
|
|
71
|
+
if (!validate(sessionId)) {
|
|
72
|
+
fastify.log.warn(
|
|
73
|
+
`[Socket Auth] Invalid sessionId format for socket: ${socket.id}`,
|
|
74
|
+
)
|
|
75
|
+
return next(
|
|
76
|
+
new Error("Authentication failed: Invalid session ID format"),
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const workSession = await validateWorkSession(fastify, sessionId)
|
|
81
|
+
socket.workSession = workSession as any
|
|
82
|
+
socket.isWorkSession = true
|
|
83
|
+
return next()
|
|
84
|
+
} catch (err: any) {
|
|
85
|
+
fastify.log.warn(
|
|
86
|
+
`[Socket Auth] WorkSession validation failed for socket: ${socket.id}, error: ${err.message}`,
|
|
87
|
+
)
|
|
88
|
+
return next(new Error("Invalid or expired session"))
|
|
89
|
+
}
|
|
90
|
+
}
|
|
53
91
|
|
|
54
|
-
|
|
92
|
+
// No valid authentication method found
|
|
93
|
+
fastify.log.warn(
|
|
94
|
+
`[Socket Auth] Socket connection without valid authentication: ${socket.id}, hasToken: ${!!token}, hasSessionId: ${!!sessionId}`,
|
|
95
|
+
)
|
|
96
|
+
return next(
|
|
97
|
+
new Error(
|
|
98
|
+
"Authentication failed: No valid token or session provided",
|
|
99
|
+
),
|
|
100
|
+
)
|
|
55
101
|
} catch (error: any) {
|
|
56
|
-
fastify.log.error(
|
|
102
|
+
fastify.log.error(
|
|
103
|
+
`[Socket Auth] Socket authentication error for ${socket.id}: ${error.message}, stack: ${error.stack}`,
|
|
104
|
+
)
|
|
57
105
|
next(new Error("Authentication failed: Invalid token"))
|
|
58
106
|
}
|
|
59
107
|
})
|