@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.
Files changed (136) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/bin/cli.js +1 -1
  3. package/dev/README.md +4 -0
  4. package/dist/cli.js +135 -124
  5. package/dist/cli.js.map +4 -4
  6. package/dist/index.js +9 -8
  7. package/dist/index.js.map +4 -4
  8. package/package.json +9 -5
  9. package/services/backend/delay-api-debugger.sh +0 -0
  10. package/services/backend/package.json +1 -0
  11. package/services/backend/src/app.ts +4 -0
  12. package/services/backend/src/core/config/configService.ts +10 -1
  13. package/services/backend/src/core/events/eventEmitter.ts +32 -7
  14. package/services/backend/src/core/http/request-params.plugin.ts +2 -2
  15. package/services/backend/src/core/pluginSystem/pluginFastifyInstance.ts +4 -1
  16. package/services/backend/src/core/pluginSystem/pluginTypes.ts +3 -1
  17. package/services/backend/src/core/sockets/createSystemEventHandlers.ts +7 -0
  18. package/services/backend/src/core/sockets/index.ts +61 -13
  19. package/services/backend/src/core/sockets/socketManager.ts +452 -105
  20. package/services/backend/src/core/sockets/socketTypes.ts +13 -1
  21. package/services/backend/src/core/sockets/workSessionJoinPayload.ts +106 -0
  22. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.get.ts +3 -1
  23. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.getAll.ts +3 -1
  24. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.hardDelete.ts +16 -19
  25. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.patch.ts +3 -1
  26. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.post.ts +3 -1
  27. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/account/routes/route.account.remove.ts +3 -1
  28. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/composition.service.ts +86 -3
  29. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/index.ts +2 -0
  30. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.get.ts +3 -1
  31. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.getAll.ts +3 -1
  32. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.hardDelete.ts +16 -19
  33. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.patch.ts +3 -1
  34. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.post.bulk.ts +60 -0
  35. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.post.ts +3 -1
  36. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.remove.ts +3 -1
  37. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/composition/routes/route.composition.restore.ts +12 -15
  38. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/interactionLink.service.ts +96 -12
  39. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/index.ts +2 -0
  40. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.get.ts +3 -1
  41. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.getAll.ts +4 -2
  42. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.hardDelete.ts +12 -17
  43. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.patch.ts +3 -1
  44. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.post.bulk.ts +62 -0
  45. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.post.ts +3 -1
  46. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.remove.ts +3 -1
  47. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/route.interactionLink.restore.ts +12 -15
  48. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/project.service.ts +1 -0
  49. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.get.ts +3 -1
  50. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.getAll.ts +4 -2
  51. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.hardDelete.ts +3 -1
  52. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.patch.ts +3 -1
  53. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.post.ts +4 -2
  54. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/project/routes/route.project.remove.ts +3 -1
  55. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/index.ts +2 -0
  56. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.get.ts +1 -0
  57. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.getAll.ts +1 -0
  58. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.hardDelete.ts +10 -15
  59. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.patch.ts +3 -1
  60. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.post.bulk.ts +60 -0
  61. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.post.ts +3 -1
  62. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.remove.ts +3 -1
  63. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/routes/route.tag.restore.ts +12 -15
  64. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/tag/tag.service.ts +73 -3
  65. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.get.ts +1 -0
  66. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.getAll.ts +1 -0
  67. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.hardDelete.ts +10 -15
  68. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.patch.ts +4 -6
  69. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.patchLastProject.ts +4 -2
  70. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.post.ts +3 -1
  71. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.remove.ts +3 -4
  72. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.restore.ts +12 -15
  73. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/events/index.ts +45 -0
  74. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/helpers/crud.ts +12 -0
  75. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/helpers/payload.ts +21 -0
  76. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/index.ts +55 -0
  77. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/index.ts +19 -0
  78. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.get.ts +53 -0
  79. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.getAll.ts +39 -0
  80. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.hardDelete.ts +53 -0
  81. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.patch.ts +58 -0
  82. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.post.ts +53 -0
  83. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/routes/route.workSession.remove.ts +52 -0
  84. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/workSession.model.ts +65 -0
  85. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/workSession.schema.ts +125 -0
  86. package/services/backend/src/corePlugins/raclette__core/backend/datatypes/workSession/workSession.service.ts +351 -0
  87. package/services/backend/src/corePlugins/raclette__core/backend/index.ts +2 -0
  88. package/services/backend/src/corePlugins/raclette__core/frontend/generated-config.ts +159 -24
  89. package/services/backend/src/modules/authentication/index.ts +255 -4
  90. package/services/backend/src/modules/hooks/rate-limiter.ts +21 -0
  91. package/services/backend/src/types/custom-fastify.d.ts +17 -0
  92. package/services/backend/src/utils/request.utils.ts +4 -1
  93. package/services/backend/types/index.d.ts +15 -1
  94. package/services/backend/yarn.lock +13 -4
  95. package/services/frontend/index.html +1 -1
  96. package/services/frontend/provision/entrypoint.sh +0 -0
  97. package/services/frontend/src/core/lib/configService.ts +1 -1
  98. package/services/frontend/src/core/lib/data/dataApi.ts +10 -1
  99. package/services/frontend/src/core/lib/dataHelper.ts +1 -1
  100. package/services/frontend/src/core/lib/eggs/snow.ts +66 -48
  101. package/services/frontend/src/core/lib/helpers/index.ts +1 -0
  102. package/services/frontend/src/core/lib/helpers/removeEmpty.ts +69 -0
  103. package/services/frontend/src/core/lib/httpClient.ts +19 -0
  104. package/services/frontend/src/core/main.ts +20 -10
  105. package/services/frontend/src/core/setup/socket.ts +4 -3
  106. package/services/frontend/src/core/setup/socketClient.ts +31 -3
  107. package/services/frontend/src/core/setup/socketEvents.ts +92 -8
  108. package/services/frontend/src/core/store/index.ts +5 -1
  109. package/services/frontend/src/core/store/reducers/compositions/index.ts +2 -2
  110. package/services/frontend/src/core/store/reducers/interactionLinks/index.ts +1 -1
  111. package/services/frontend/src/core/store/reducers/widgets/reducers.ts +1 -2
  112. package/services/frontend/src/core/store/types/index.ts +0 -1
  113. package/services/frontend/src/core/types/PluginRegistrar.ts +8 -6
  114. package/services/frontend/src/core/types/Store.ts +1 -0
  115. package/services/frontend/src/orchestrator/components/composition/WidgetsLayoutLoader.vue +68 -8
  116. package/services/frontend/src/orchestrator/components/menu/UserMenu.vue +17 -5
  117. package/services/frontend/src/orchestrator/components/welcomeScreen/AdminWelcomeScreen.vue +1 -1
  118. package/services/frontend/src/orchestrator/composables/index.ts +1 -0
  119. package/services/frontend/src/orchestrator/composables/usePluginApi.ts +0 -3
  120. package/services/frontend/src/orchestrator/composables/useRouteState.ts +23 -4
  121. package/services/frontend/src/orchestrator/composables/useWidgetLifecycle.ts +166 -0
  122. package/services/frontend/src/orchestrator/helpers/index.ts +1 -0
  123. package/services/frontend/src/orchestrator/i18n/de-DE.json +15 -1
  124. package/services/frontend/src/orchestrator/i18n/en-EU.json +15 -1
  125. package/services/frontend/src/orchestrator/i18n/sk.json +15 -1
  126. package/services/frontend/src/orchestrator/index.ts +34 -4
  127. package/services/frontend/src/orchestrator/router/routeParserHelper.ts +106 -1
  128. package/services/frontend/src/orchestrator/types/Widgets.ts +2 -0
  129. package/services/frontend/types.ts +1 -0
  130. package/src/README.md +404 -0
  131. package/src/types.ts +19 -5
  132. package/templates/README.md +0 -0
  133. package/types/index.ts +18 -4
  134. package/services/backend/.gitignore +0 -17
  135. package/services/frontend/.gitignore +0 -35
  136. package/yarn.lock +0 -2937
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raclettejs/core",
3
- "version": "0.1.18",
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.18",
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
- "packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
92
- }
95
+ }
96
+ }
File without changes
@@ -28,6 +28,7 @@
28
28
  "@fastify/jwt": "10.0.0",
29
29
  "@fastify/schedule": "6.0.0",
30
30
  "@fastify/sensible": "6.0.3",
31
+ "@fastify/rate-limit": "10.3.0",
31
32
  "@sinclair/typebox": "0.34.41",
32
33
  "@types/vary": "1.1.3",
33
34
  "axios": "1.13.2",
@@ -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 Raclette configuration")
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
- if (typeof this.events[event] === "object") {
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
- return true
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 false
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. This is only done for core events, not for plugins.
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-prefixed events
118
- if (event.includes("__") && event.includes("--")) {
119
- // assume plugin
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.info(
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.info(
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
- // Instead of socketio-jwt, use this custom middleware
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
- if (!token) {
41
- fastify.log.warn(`Socket connection without token: ${socket.id}`)
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
- return next(new Error("Authentication failed: No token provided"))
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
- // Log successful authentication
49
- fastify.log.debug(`Socket authenticated: ${socket.id}`)
64
+ // Check for workSession authentication (same validation as socketManager.validateWorkSession)
65
+ const sessionId = socket.handshake.auth?.sessionId
50
66
 
51
- // Store decoded token on socket
52
- socket.decoded_token = decoded
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
- next()
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(`Socket authentication error: ${error.message}`)
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
  })