@raclettejs/core 0.1.31 → 0.1.32-nightly-1
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 +31 -4
- package/dist/cli.js +94 -94
- package/dist/cli.js.map +3 -3
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/services/backend/.yarn/install-state.gz +0 -0
- package/services/backend/dist/core/eventBus/index.js +7 -0
- package/services/backend/dist/core/pluginSystem/configGenerator/index.js +346 -0
- package/services/backend/dist/core/sockets/index.js +95 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/account/events/index.js +31 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/account/index.js +48 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/account/routes/index.js +15 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/composition/events/index.js +22 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/composition/index.js +51 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/composition/routes/index.js +19 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/interactionLink/events/index.js +22 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/interactionLink/index.js +48 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/interactionLink/routes/index.js +19 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/project/events/index.js +31 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/project/index.js +49 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/project/routes/index.js +16 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/tag/events/index.js +39 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/tag/index.js +50 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/tag/routes/index.js +19 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/user/events/index.js +31 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/user/index.js +51 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/user/routes/index.js +21 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/workSession/events/index.js +31 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/workSession/index.js +48 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/workSession/routes/index.js +15 -0
- package/services/backend/dist/corePlugins/raclette__core/backend/index.js +34 -0
- package/services/backend/dist/domains/index.js +11 -0
- package/services/backend/dist/domains/system/index.js +11 -0
- package/services/backend/dist/domains/system/routes/index.js +17 -0
- package/services/backend/dist/helpers/index.js +14 -0
- package/services/backend/dist/index.js +3 -0
- package/services/backend/dist/modules/authentication/index.js +253 -0
- package/services/backend/dist/shared/types/core/index.js +8 -0
- package/services/backend/dist/shared/types/dataTypes/index.js +6 -0
- package/services/backend/dist/shared/types/index.js +8 -0
- package/services/backend/dist/shared/types/plugins/index.js +8 -0
- package/services/backend/dist/types/index.js +12 -0
- package/services/backend/dist/utils/index.js +2 -0
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/routes/route.user.patchOwn.ts +1 -1
- package/services/backend/src/corePlugins/raclette__core/backend/datatypes/user/user.service.ts +22 -1
- package/services/backend/yarn.lock +1 -1
- package/services/frontend/.yarn/install-state.gz +0 -0
- package/services/frontend/package.json +2 -2
- package/services/frontend/src/core/lib/data/dataApi.ts +1 -2
- package/services/frontend/src/orchestrator/ProductOrchestrator.vue +8 -1
- package/services/frontend/src/orchestrator/assets/styles/layers.css +1 -4
- package/services/frontend/src/orchestrator/assets/styles/tailwindStyles.css +3 -3
- package/services/frontend/src/orchestrator/assets/styles/vuetifyStyles.scss +4 -1
- package/services/frontend/src/orchestrator/components/dataExport/DataExporter.vue +303 -0
- package/services/frontend/src/orchestrator/components/dataImport/ImportSelectionDialog.vue +169 -0
- package/services/frontend/src/orchestrator/components/dataImport/ImportSummaryDialog.vue +211 -0
- package/services/frontend/src/orchestrator/components/dataTable/BaseDataTable.vue +473 -0
- package/services/frontend/src/orchestrator/components/index.ts +8 -0
- package/services/frontend/src/orchestrator/components/input/FileUpload.vue +83 -0
- package/services/frontend/src/orchestrator/composables/index.ts +1 -0
- package/services/frontend/src/orchestrator/composables/useExport/formats/builtins.ts +124 -0
- package/services/frontend/src/orchestrator/composables/useExport/index.ts +176 -0
- package/services/frontend/src/orchestrator/composables/useExport/types.ts +141 -0
- package/services/frontend/src/orchestrator/i18n/de-DE.json +26 -1
- package/services/frontend/src/orchestrator/i18n/en-EU.json +26 -1
- package/services/frontend/src/orchestrator/i18n/sk.json +26 -1
- package/services/frontend/src/orchestrator/i18n/tl-TL.json +14 -0
- package/services/frontend/src/orchestrator/setup/vuetify.ts +0 -1
- package/services/frontend/yarn.lock +4854 -0
- package/types/index.ts +1 -1
- package/package/LICENSE.md +0 -699
- package/package/README.md +0 -49
- package/package/dev/README.md +0 -4
- package/package/index.js +0 -11
- package/package/raclette.default.config.yaml +0 -60
- package/package/services/backend/README.md +0 -172
- package/package/services/backend/yarn.lock +0 -5320
- package/package/services/frontend/README.md +0 -511
- package/package/services/frontend/src/core/lib/eggs/readme.md +0 -75
- package/package/services/frontend/yarn.lock +0 -0
- package/package/src/README.md +0 -404
- package/package/templates/README.md +0 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import eventMap from "@c/eventBus/eventBusEventMap";
|
|
4
|
+
// ========================================
|
|
5
|
+
// Registry Class (State Management)
|
|
6
|
+
// ========================================
|
|
7
|
+
class FrontendConfigRegistry {
|
|
8
|
+
static instance;
|
|
9
|
+
registrations = new Map();
|
|
10
|
+
trackedRoutes = [];
|
|
11
|
+
isGenerationPending = false;
|
|
12
|
+
fastifyInstance = null;
|
|
13
|
+
isTrackingSetup = false;
|
|
14
|
+
static getInstance = () => {
|
|
15
|
+
if (!FrontendConfigRegistry.instance) {
|
|
16
|
+
FrontendConfigRegistry.instance = new FrontendConfigRegistry();
|
|
17
|
+
}
|
|
18
|
+
return FrontendConfigRegistry.instance;
|
|
19
|
+
};
|
|
20
|
+
registerPlugin = (pluginData, options) => {
|
|
21
|
+
const registration = {
|
|
22
|
+
pluginName: pluginData.pluginName,
|
|
23
|
+
author: pluginData.author,
|
|
24
|
+
pluginKey: pluginData.key,
|
|
25
|
+
pluginPath: pluginData.absolutePath,
|
|
26
|
+
frontendPath: pluginData.frontendAbsolutePath,
|
|
27
|
+
routePrefix: pluginData.routePrefix,
|
|
28
|
+
entityMapping: options?.entityMapping || {},
|
|
29
|
+
customConfig: options?.customConfig,
|
|
30
|
+
registeredAt: Date.now(),
|
|
31
|
+
};
|
|
32
|
+
this.registrations.set(registration.pluginKey, registration);
|
|
33
|
+
this.isGenerationPending = true;
|
|
34
|
+
};
|
|
35
|
+
setFastifyInstance = (fastify) => {
|
|
36
|
+
this.fastifyInstance = fastify;
|
|
37
|
+
if (!this.isTrackingSetup) {
|
|
38
|
+
this.setupRouteTracking(fastify);
|
|
39
|
+
this.isTrackingSetup = true;
|
|
40
|
+
}
|
|
41
|
+
if (fastify.log) {
|
|
42
|
+
fastify.log.info("Fastify instance registered for frontend generation with route tracking");
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
setupRouteTracking = (fastify) => {
|
|
46
|
+
if (fastify.log) {
|
|
47
|
+
fastify.log.info("Setting up route tracking for frontend generation");
|
|
48
|
+
}
|
|
49
|
+
fastify.addHook("onRoute", (routeOptions) => {
|
|
50
|
+
if (routeOptions.url &&
|
|
51
|
+
routeOptions.url !== "" &&
|
|
52
|
+
routeOptions.url !== "/*" &&
|
|
53
|
+
!Array.isArray(routeOptions.method) &&
|
|
54
|
+
routeOptions.method.toUpperCase() !== "HEAD") {
|
|
55
|
+
const trackedRoute = {
|
|
56
|
+
method: Array.isArray(routeOptions.method)
|
|
57
|
+
? routeOptions.method[0]
|
|
58
|
+
: routeOptions.method,
|
|
59
|
+
url: routeOptions.url,
|
|
60
|
+
routePath: routeOptions.url,
|
|
61
|
+
config: routeOptions.config,
|
|
62
|
+
schema: routeOptions.schema,
|
|
63
|
+
handler: routeOptions.handler,
|
|
64
|
+
routePrefix: routeOptions.prefix,
|
|
65
|
+
};
|
|
66
|
+
this.trackedRoutes.push(trackedRoute);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
fastify.addHook("onReady", async () => {
|
|
70
|
+
if (fastify.log) {
|
|
71
|
+
fastify.log.debug(`Route tracking complete. Tracked ${this.trackedRoutes.length} routes`);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
// Getters
|
|
76
|
+
isReadyForGeneration = () => this.fastifyInstance !== null &&
|
|
77
|
+
this.isGenerationPending &&
|
|
78
|
+
this.registrations.size > 0;
|
|
79
|
+
getRegistrations = () => Array.from(this.registrations.values());
|
|
80
|
+
getTrackedRoutes = () => this.trackedRoutes;
|
|
81
|
+
getFastifyInstance = () => this.fastifyInstance;
|
|
82
|
+
// State management
|
|
83
|
+
markGenerationCompleted = () => {
|
|
84
|
+
this.isGenerationPending = false;
|
|
85
|
+
};
|
|
86
|
+
reset = () => {
|
|
87
|
+
this.registrations.clear();
|
|
88
|
+
this.trackedRoutes = [];
|
|
89
|
+
this.fastifyInstance = null;
|
|
90
|
+
this.isGenerationPending = false;
|
|
91
|
+
this.isTrackingSetup = false;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// ========================================
|
|
95
|
+
// Plugin Registration Functions (Called by Plugins)
|
|
96
|
+
// ========================================
|
|
97
|
+
export const registerPluginForFrontendGeneration = (pluginOptions, options) => {
|
|
98
|
+
const registry = FrontendConfigRegistry.getInstance();
|
|
99
|
+
registry.registerPlugin(pluginOptions, options);
|
|
100
|
+
};
|
|
101
|
+
export const setFastifyInstanceForGeneration = (fastify) => {
|
|
102
|
+
const registry = FrontendConfigRegistry.getInstance();
|
|
103
|
+
registry.setFastifyInstance(fastify);
|
|
104
|
+
};
|
|
105
|
+
// ========================================
|
|
106
|
+
// Generation Functions (Called by Core)
|
|
107
|
+
// ========================================
|
|
108
|
+
export const generateAllFrontendConfigs = async () => {
|
|
109
|
+
const registry = FrontendConfigRegistry.getInstance();
|
|
110
|
+
if (!registry.isReadyForGeneration()) {
|
|
111
|
+
const fastify = registry.getFastifyInstance();
|
|
112
|
+
if (fastify?.log) {
|
|
113
|
+
fastify.log.warn("Frontend generation not ready - missing Fastify instance or no plugins registered");
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const fastify = registry.getFastifyInstance();
|
|
118
|
+
const registrations = registry.getRegistrations();
|
|
119
|
+
if (fastify.log) {
|
|
120
|
+
fastify.log.info(`Generating frontend configurations for ${registrations.length} registered plugins`);
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
for (const registration of registrations) {
|
|
124
|
+
await generatePluginFrontendConfig(fastify, registration);
|
|
125
|
+
}
|
|
126
|
+
registry.markGenerationCompleted();
|
|
127
|
+
if (fastify.log) {
|
|
128
|
+
fastify.log.info(`Frontend configurations generated successfully for ${registrations.length} plugins`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
if (fastify.log) {
|
|
133
|
+
fastify.log.error("Error generating frontend configurations:", error);
|
|
134
|
+
}
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
export const triggerGenerationIfReady = async () => {
|
|
139
|
+
const registry = FrontendConfigRegistry.getInstance();
|
|
140
|
+
if (registry.isReadyForGeneration()) {
|
|
141
|
+
await generateAllFrontendConfigs();
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
// ========================================
|
|
145
|
+
// Internal Generation Logic
|
|
146
|
+
// ========================================
|
|
147
|
+
const generatePluginFrontendConfig = async (fastify, registration) => {
|
|
148
|
+
const registry = FrontendConfigRegistry.getInstance();
|
|
149
|
+
const allRoutes = registry.getTrackedRoutes();
|
|
150
|
+
const pluginRoutes = allRoutes.filter((route) => {
|
|
151
|
+
const routePrefix = registration.routePrefix || registration.pluginKey;
|
|
152
|
+
return (route.url.startsWith(`${routePrefix}`) || route.url === `${routePrefix}`);
|
|
153
|
+
});
|
|
154
|
+
if (pluginRoutes.length === 0) {
|
|
155
|
+
if (fastify.log) {
|
|
156
|
+
fastify.log.warn(`No routes found for plugin ${registration.pluginKey}`);
|
|
157
|
+
}
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (fastify.log) {
|
|
161
|
+
fastify.log.info(`Processing ${pluginRoutes.length} routes for plugin ${registration.pluginKey}`);
|
|
162
|
+
}
|
|
163
|
+
const dataTypes = new Map();
|
|
164
|
+
for (const route of pluginRoutes) {
|
|
165
|
+
const routeInfo = parseRouteInfo(route, registration);
|
|
166
|
+
if (!routeInfo)
|
|
167
|
+
continue;
|
|
168
|
+
const { entityName, operationName } = routeInfo;
|
|
169
|
+
if (!dataTypes.has(entityName)) {
|
|
170
|
+
dataTypes.set(entityName, {
|
|
171
|
+
type: entityName,
|
|
172
|
+
operations: {},
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
const dataType = dataTypes.get(entityName);
|
|
176
|
+
const operationConfig = generateOperationConfig(routeInfo);
|
|
177
|
+
if (operationConfig) {
|
|
178
|
+
dataType.operations[operationName] = operationConfig;
|
|
179
|
+
if (fastify.log) {
|
|
180
|
+
fastify.log.debug(`Generated operation config: ${entityName}.${operationName} -> ${routeInfo.method} ${routeInfo.url}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
await writePluginConfigFile(dataTypes, registration, fastify);
|
|
185
|
+
};
|
|
186
|
+
// ========================================
|
|
187
|
+
// Route Parsing Utilities
|
|
188
|
+
// ========================================
|
|
189
|
+
const parseRouteInfo = (route, registration) => {
|
|
190
|
+
const method = route.method || "GET";
|
|
191
|
+
const url = route.url || route.routePath || "";
|
|
192
|
+
const routePrefix = registration.routePrefix || registration.pluginKey;
|
|
193
|
+
const prefixPattern = new RegExp(`^/?${routePrefix}/?`);
|
|
194
|
+
const routeAfterPrefix = url.replace(prefixPattern, "");
|
|
195
|
+
if (!routeAfterPrefix)
|
|
196
|
+
return null;
|
|
197
|
+
const segments = routeAfterPrefix
|
|
198
|
+
.split("/")
|
|
199
|
+
.filter((segment) => segment !== "");
|
|
200
|
+
if (segments.length === 0)
|
|
201
|
+
return null;
|
|
202
|
+
const routeKey = segments[0];
|
|
203
|
+
const entityName = registration.entityMapping?.[routeKey] || routeKey;
|
|
204
|
+
const operationSegments = segments.slice(1);
|
|
205
|
+
const pathParams = segments
|
|
206
|
+
.filter((segment) => segment.startsWith(":"))
|
|
207
|
+
.map((param) => param.substring(1));
|
|
208
|
+
const operationName = getOperationName(method, operationSegments);
|
|
209
|
+
return {
|
|
210
|
+
method,
|
|
211
|
+
url,
|
|
212
|
+
entityName,
|
|
213
|
+
operationName,
|
|
214
|
+
pathParams,
|
|
215
|
+
registration,
|
|
216
|
+
config: route.config || {},
|
|
217
|
+
schema: route.schema || {},
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
const getOperationName = (method, urlSegments) => {
|
|
221
|
+
const httpMethod = method.toLowerCase();
|
|
222
|
+
const baseMethod = getMethodMapping(httpMethod);
|
|
223
|
+
const nonParamSegments = urlSegments.filter((segment) => !segment.startsWith(":"));
|
|
224
|
+
if (nonParamSegments.length === 0) {
|
|
225
|
+
return baseMethod;
|
|
226
|
+
}
|
|
227
|
+
const operationParts = nonParamSegments
|
|
228
|
+
.map((segment) => segment
|
|
229
|
+
.split("-")
|
|
230
|
+
.map((word, index) => index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1))
|
|
231
|
+
.join(""))
|
|
232
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
233
|
+
.join("");
|
|
234
|
+
return baseMethod + operationParts;
|
|
235
|
+
};
|
|
236
|
+
const getMethodMapping = (httpMethod) => {
|
|
237
|
+
const methodMapping = {
|
|
238
|
+
get: "get",
|
|
239
|
+
post: "create",
|
|
240
|
+
patch: "update",
|
|
241
|
+
put: "update",
|
|
242
|
+
delete: "delete",
|
|
243
|
+
};
|
|
244
|
+
return methodMapping[httpMethod] || httpMethod;
|
|
245
|
+
};
|
|
246
|
+
// ========================================
|
|
247
|
+
// Operation Configuration Generation
|
|
248
|
+
// ========================================
|
|
249
|
+
const generateOperationConfig = (routeInfo) => {
|
|
250
|
+
const { method, url, pathParams, registration, config: routeConfig, } = routeInfo;
|
|
251
|
+
if (!registration)
|
|
252
|
+
return null;
|
|
253
|
+
const config = {
|
|
254
|
+
target: generateTargetFunction(url, pathParams),
|
|
255
|
+
method: method.toLowerCase(),
|
|
256
|
+
};
|
|
257
|
+
if (routeConfig?.type) {
|
|
258
|
+
config.storeActionType = routeConfig.type;
|
|
259
|
+
}
|
|
260
|
+
if (routeInfo.config.broadcastChannels?.length) {
|
|
261
|
+
config.channels = routeInfo.config.broadcastChannels.map((channelName) => {
|
|
262
|
+
const coreChannel = getCoreChannel(channelName);
|
|
263
|
+
const channel = coreChannel || registration.pluginKey + "--" + channelName;
|
|
264
|
+
return {
|
|
265
|
+
channel,
|
|
266
|
+
channelKey: channelName,
|
|
267
|
+
prefix: coreChannel ? "" : registration.pluginKey,
|
|
268
|
+
};
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
return config;
|
|
272
|
+
};
|
|
273
|
+
const getCoreChannel = (channelName) => {
|
|
274
|
+
if (Object.keys(eventMap).includes(channelName)) {
|
|
275
|
+
if (channelName.startsWith("broadcast")) {
|
|
276
|
+
const result = channelName.replace("broadcast", "");
|
|
277
|
+
return result.charAt(0).toLowerCase() + result.slice(1);
|
|
278
|
+
}
|
|
279
|
+
return channelName;
|
|
280
|
+
}
|
|
281
|
+
return undefined;
|
|
282
|
+
};
|
|
283
|
+
const generateTargetFunction = (url, pathParams) => {
|
|
284
|
+
if (pathParams.length > 0) {
|
|
285
|
+
let targetFunction = `(payload) => \`${url}\``;
|
|
286
|
+
for (const param of pathParams) {
|
|
287
|
+
const paramPattern = new RegExp(`:${param}`, "g");
|
|
288
|
+
targetFunction = targetFunction.replace(paramPattern, `\${payload.${param}}`);
|
|
289
|
+
}
|
|
290
|
+
return targetFunction;
|
|
291
|
+
}
|
|
292
|
+
return url;
|
|
293
|
+
};
|
|
294
|
+
// ========================================
|
|
295
|
+
// File Generation Utilities
|
|
296
|
+
// ========================================
|
|
297
|
+
const writePluginConfigFile = async (dataTypes, registration, fastify) => {
|
|
298
|
+
if (dataTypes.size === 0) {
|
|
299
|
+
if (fastify.log) {
|
|
300
|
+
fastify.log.warn(`No data types generated for plugin ${registration.pluginKey}`);
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const configContent = generatePluginConfigFile(dataTypes, registration);
|
|
305
|
+
const outputPath = path.join(registration.frontendPath, "generated-config.ts");
|
|
306
|
+
try {
|
|
307
|
+
await fs.ensureDir(path.dirname(outputPath));
|
|
308
|
+
await fs.writeFile(outputPath, configContent);
|
|
309
|
+
if (fastify.log) {
|
|
310
|
+
fastify.log.info(`Generated config for plugin ${registration.pluginKey}: ${outputPath}`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
if (fastify.log) {
|
|
315
|
+
fastify.log.error(`Error writing config for plugin ${registration.pluginKey}:`, error);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
const generatePluginConfigFile = (dataTypes, registration) => {
|
|
320
|
+
const dataObject = {};
|
|
321
|
+
for (const [entityName, dataType] of dataTypes.entries()) {
|
|
322
|
+
const routeKey = Object.keys(registration.entityMapping || {}).find((key) => registration.entityMapping[key] === entityName) || entityName;
|
|
323
|
+
dataObject[routeKey] = {
|
|
324
|
+
type: dataType.type,
|
|
325
|
+
operations: dataType.operations,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
return `// Auto-generated frontend configuration for plugin: ${registration.pluginKey}
|
|
329
|
+
// This file is generated from backend routes - do not edit manually
|
|
330
|
+
// Entity mapping: ${JSON.stringify(registration.entityMapping || {})}
|
|
331
|
+
|
|
332
|
+
export default {
|
|
333
|
+
pluginName: "${registration.pluginName}",
|
|
334
|
+
author: "${registration.author}",
|
|
335
|
+
pluginKey: "${registration.pluginKey}",
|
|
336
|
+
routePrefix: "${registration.routePrefix}",
|
|
337
|
+
pluginPath: "${registration.pluginPath}",
|
|
338
|
+
data: ${JSON.stringify(dataObject, null, 2)
|
|
339
|
+
.replace(/"(\([^)]+\) => [^"]+)"/g, "$1")
|
|
340
|
+
.replace(/"([a-zA-Z_$][a-zA-Z0-9_$]*)"\s*:/g, "$1:")
|
|
341
|
+
.split("\n")
|
|
342
|
+
.map((line, index) => (index === 0 ? line : " " + line))
|
|
343
|
+
.join("\n")}
|
|
344
|
+
}
|
|
345
|
+
`;
|
|
346
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import fastifyPlugin from "fastify-plugin";
|
|
2
|
+
import { Server } from "socket.io";
|
|
3
|
+
import configService from "@c/config/configService";
|
|
4
|
+
import { getAllowedOrigins } from "@/helpers";
|
|
5
|
+
import { validate } from "uuid";
|
|
6
|
+
import { validateWorkSession } from "./socketManager";
|
|
7
|
+
export default fastifyPlugin((fastify, opts, done) => {
|
|
8
|
+
// Get socket configuration using the wrfastifyer
|
|
9
|
+
const { options: socketOptions, security } = configService.getSocketConfig();
|
|
10
|
+
// Configure default options with overrides from config
|
|
11
|
+
const defaults = {
|
|
12
|
+
cors: { origin: getAllowedOrigins(), credentials: true },
|
|
13
|
+
connectionTimeout: socketOptions?.connectionTimeout || 3000,
|
|
14
|
+
pingInterval: socketOptions?.pingInterval || 1500,
|
|
15
|
+
pingTimeout: socketOptions?.pingTimeout || 1000,
|
|
16
|
+
};
|
|
17
|
+
/*
|
|
18
|
+
* create and configure the websocket server
|
|
19
|
+
*/
|
|
20
|
+
const socketServer = new Server(fastify.server, { ...defaults, ...opts });
|
|
21
|
+
// Configure authentication based on security settings
|
|
22
|
+
if (configService.isAuthRequired() ?? true) {
|
|
23
|
+
// Default to JWT authentication
|
|
24
|
+
if (security?.tokenValidation === "jwt") {
|
|
25
|
+
if (!process.env.SERVER_TOKEN_SECRET) {
|
|
26
|
+
fastify.log.warn("SERVER_TOKEN_SECRET not set, socket authentication may fail");
|
|
27
|
+
}
|
|
28
|
+
// Dual authentication middleware: JWT or workSession
|
|
29
|
+
socketServer.use(async (socket, next) => {
|
|
30
|
+
fastify.log.debug(`[Socket Auth] Starting authentication for socket: ${socket.id}`);
|
|
31
|
+
try {
|
|
32
|
+
const token = socket.handshake.auth?.token ??
|
|
33
|
+
socket.handshake.headers.authorization?.split(" ")[1];
|
|
34
|
+
// Try JWT authentication first
|
|
35
|
+
if (token) {
|
|
36
|
+
try {
|
|
37
|
+
// Verify token using fastify-jwt
|
|
38
|
+
const decoded = fastify.jwt.verify(token);
|
|
39
|
+
// Store decoded token on socket
|
|
40
|
+
socket.decoded_token = decoded;
|
|
41
|
+
socket.isWorkSession = false;
|
|
42
|
+
return next();
|
|
43
|
+
}
|
|
44
|
+
catch (jwtError) {
|
|
45
|
+
// JWT verification failed, continue to workSession check
|
|
46
|
+
fastify.log.debug(`[Socket Auth] JWT verification failed for ${socket.id}: ${jwtError.message}, checking workSession`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Check for workSession authentication (same validation as socketManager.validateWorkSession)
|
|
50
|
+
const sessionId = socket.handshake.auth?.sessionId;
|
|
51
|
+
if (sessionId) {
|
|
52
|
+
fastify.log.info(`[Socket Auth] Attempting workSession authentication for socket: ${socket.id}, sessionId: ${sessionId}`);
|
|
53
|
+
if (!validate(sessionId)) {
|
|
54
|
+
fastify.log.warn(`[Socket Auth] Invalid sessionId format for socket: ${socket.id}`);
|
|
55
|
+
return next(new Error("Authentication failed: Invalid session ID format"));
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const workSession = await validateWorkSession(fastify, sessionId);
|
|
59
|
+
socket.workSession = workSession;
|
|
60
|
+
socket.isWorkSession = true;
|
|
61
|
+
return next();
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
fastify.log.warn(`[Socket Auth] WorkSession validation failed for socket: ${socket.id}, error: ${err.message}`);
|
|
65
|
+
return next(new Error("Invalid or expired session"));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// No valid authentication method found
|
|
69
|
+
fastify.log.warn(`[Socket Auth] Socket connection without valid authentication: ${socket.id}, hasToken: ${!!token}, hasSessionId: ${!!sessionId}`);
|
|
70
|
+
return next(new Error("Authentication failed: No valid token or session provided"));
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
fastify.log.error(`[Socket Auth] Socket authentication error for ${socket.id}: ${error.message}, stack: ${error.stack}`);
|
|
74
|
+
next(new Error("Authentication failed: Invalid token"));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else if (security?.customValidator) {
|
|
79
|
+
// Custom validator would be implemented here
|
|
80
|
+
fastify.log.warn("Custom socket validator specified but not implemented - yet ;)");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
fastify.log.warn("Socket authentication is disabled - this is not recommended for production");
|
|
85
|
+
}
|
|
86
|
+
// make the websocket server available in the whole fastify
|
|
87
|
+
fastify.decorate("wss", socketServer);
|
|
88
|
+
// close the websocket server when the http server is closing
|
|
89
|
+
fastify.addHook("onClose", (fastify, done) => {
|
|
90
|
+
fastify.log.warn("App is closing, socket connection is also closed");
|
|
91
|
+
fastify.wss.close();
|
|
92
|
+
done();
|
|
93
|
+
});
|
|
94
|
+
done();
|
|
95
|
+
});
|
package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/account/events/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const registerEvents = (fastify) => {
|
|
2
|
+
/**
|
|
3
|
+
* Account created
|
|
4
|
+
*/
|
|
5
|
+
const created = (payload) => {
|
|
6
|
+
fastify.eventbus.emit("broadcastDataUpdated", payload);
|
|
7
|
+
fastify.eventbus.emit("broadcastAccountCreated", payload);
|
|
8
|
+
fastify.log.info(`[eventbus] account broadcast created ${payload.appSessionId}`);
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Account updated
|
|
12
|
+
*/
|
|
13
|
+
const updated = (payload) => {
|
|
14
|
+
fastify.eventbus.emit("broadcastDataUpdated", payload);
|
|
15
|
+
fastify.log.info(`[eventbus] account broadcast updated ${payload.appSessionId}`);
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Account deleted
|
|
19
|
+
*/
|
|
20
|
+
const deleted = (payload) => {
|
|
21
|
+
fastify.eventbus.emit("broadcastAccountDeleted", payload);
|
|
22
|
+
fastify.log.info(`[eventbus] account broadcast deleted ${payload.appSessionId}`);
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Register event handlers
|
|
26
|
+
*/
|
|
27
|
+
fastify.eventbus.on("coreAccountCreated", created);
|
|
28
|
+
fastify.eventbus.on("coreAccountUpdated", updated);
|
|
29
|
+
fastify.eventbus.on("coreAccountDeleted", deleted);
|
|
30
|
+
};
|
|
31
|
+
export default registerEvents;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import registerRoutes from "./routes";
|
|
2
|
+
import { createModels } from "./account.model";
|
|
3
|
+
import { createAccountService } from "./account.service";
|
|
4
|
+
import { registerPayload } from "./helpers/payload";
|
|
5
|
+
import { registerCrud } from "./helpers/crud";
|
|
6
|
+
import { registerSchemas } from "./account.schema";
|
|
7
|
+
const registerAccount = async (fastify) => {
|
|
8
|
+
/*
|
|
9
|
+
* ---------------------------------------------------------------------
|
|
10
|
+
* CREATE AND REGISTER ALL YOUR MODELS
|
|
11
|
+
* ---------------------------------------------------------------------
|
|
12
|
+
*/
|
|
13
|
+
const accountModel = createModels(fastify);
|
|
14
|
+
// create and pass in the model to your service
|
|
15
|
+
const accountService = createAccountService(accountModel);
|
|
16
|
+
// decorate the service to the instance, so we can easily call it everywhere
|
|
17
|
+
fastify.custom.accountService = accountService;
|
|
18
|
+
/*
|
|
19
|
+
* ---------------------------------------------------------------------
|
|
20
|
+
* REGISTER ALL YOUR ROUTES
|
|
21
|
+
* ---------------------------------------------------------------------
|
|
22
|
+
*/
|
|
23
|
+
try {
|
|
24
|
+
await fastify.register((instance) => registerRoutes(instance));
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
fastify.log.error(`Failed to register routes.`, error);
|
|
28
|
+
throw error; // Let the application handle the error
|
|
29
|
+
}
|
|
30
|
+
registerPayload(fastify);
|
|
31
|
+
registerCrud(fastify);
|
|
32
|
+
registerSchemas(fastify);
|
|
33
|
+
return {
|
|
34
|
+
account: {
|
|
35
|
+
operations: {
|
|
36
|
+
readAll: accountService._readAccounts.bind(accountService),
|
|
37
|
+
read: accountService._readAccount.bind(accountService),
|
|
38
|
+
create: accountService._createAccount.bind(accountService),
|
|
39
|
+
update: accountService._updateAccount.bind(accountService),
|
|
40
|
+
},
|
|
41
|
+
keywords: ["account"],
|
|
42
|
+
metadata: {
|
|
43
|
+
description: "An account handles users and projects",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export default registerAccount;
|
package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/account/routes/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import get from "./route.account.get";
|
|
2
|
+
import getAll from "./route.account.getAll";
|
|
3
|
+
import hardDelete from "./route.account.hardDelete";
|
|
4
|
+
import patch from "./route.account.patch";
|
|
5
|
+
import post from "./route.account.post";
|
|
6
|
+
import remove from "./route.account.remove";
|
|
7
|
+
const registerRoutes = async (fastify) => {
|
|
8
|
+
await fastify.get("/account/all", getAll(fastify));
|
|
9
|
+
await fastify.get("/account/:_id", get(fastify));
|
|
10
|
+
await fastify.patch("/account/:_id", patch(fastify));
|
|
11
|
+
await fastify.post("/account", post(fastify));
|
|
12
|
+
await fastify.delete("/account/:_id", remove(fastify));
|
|
13
|
+
await fastify.delete("/account/:_id/hard", hardDelete(fastify));
|
|
14
|
+
};
|
|
15
|
+
export default registerRoutes;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const registerEvents = (fastify) => {
|
|
2
|
+
/*
|
|
3
|
+
* composition created and created
|
|
4
|
+
*/
|
|
5
|
+
const created = async (payload) => {
|
|
6
|
+
fastify.eventbus.emit("broadcastCompositionCreated", payload);
|
|
7
|
+
fastify.log.info(`[eventbus] composition broadcast created ${payload.body.items}`);
|
|
8
|
+
};
|
|
9
|
+
/*
|
|
10
|
+
* composition deleted
|
|
11
|
+
*/
|
|
12
|
+
const deleted = async (payload) => {
|
|
13
|
+
fastify.eventbus.emit("broadcastCompositionDeleted", payload);
|
|
14
|
+
fastify.log.info(`[eventbus] composition broadcast deleted ${payload.body.items}`);
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Register those functions for eventbus events
|
|
18
|
+
*/
|
|
19
|
+
fastify.eventbus.on("coreCompositionCreated", created);
|
|
20
|
+
fastify.eventbus.on("coreCompositionDeleted", deleted);
|
|
21
|
+
};
|
|
22
|
+
export default registerEvents;
|
package/services/backend/dist/corePlugins/raclette__core/backend/datatypes/composition/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import registerRoutes from "./routes";
|
|
2
|
+
import { createModels } from "./composition.model";
|
|
3
|
+
import { createCompositionService } from "./composition.service";
|
|
4
|
+
import { registerPayload } from "./helpers/payload";
|
|
5
|
+
import { registerCrud } from "./helpers/crud";
|
|
6
|
+
import { compositionSchema, registerSchemas } from "./composition.schema";
|
|
7
|
+
const registerComposition = async (fastify) => {
|
|
8
|
+
/*
|
|
9
|
+
* ---------------------------------------------------------------------
|
|
10
|
+
* CREATE AND REGISTER ALL YOUR MODELS
|
|
11
|
+
* ---------------------------------------------------------------------
|
|
12
|
+
*/
|
|
13
|
+
const compositionModel = createModels(fastify);
|
|
14
|
+
// create and pass in the model to your service
|
|
15
|
+
const compositionService = await createCompositionService(compositionModel);
|
|
16
|
+
// decorate the service to the instance, so we can easily call it everywhere
|
|
17
|
+
fastify.custom.compositionService = compositionService;
|
|
18
|
+
/*
|
|
19
|
+
* ---------------------------------------------------------------------
|
|
20
|
+
* REGISTER ALL YOUR ROUTES
|
|
21
|
+
* ---------------------------------------------------------------------
|
|
22
|
+
*/
|
|
23
|
+
try {
|
|
24
|
+
await fastify.register((instance) => registerRoutes(instance));
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
fastify.log.error(`Failed to register routes.`, error);
|
|
28
|
+
throw error; // Let the application handle the error
|
|
29
|
+
}
|
|
30
|
+
registerSchemas(fastify);
|
|
31
|
+
registerPayload(fastify);
|
|
32
|
+
registerCrud(fastify);
|
|
33
|
+
return {
|
|
34
|
+
composition: {
|
|
35
|
+
schema: compositionSchema,
|
|
36
|
+
operations: {
|
|
37
|
+
readAll: compositionService._readAllCompositions.bind(compositionService),
|
|
38
|
+
read: compositionService._readComposition.bind(compositionService),
|
|
39
|
+
create: compositionService._createComposition.bind(compositionService),
|
|
40
|
+
update: compositionService._updateComposition.bind(compositionService),
|
|
41
|
+
delete: compositionService._removeComposition.bind(compositionService),
|
|
42
|
+
},
|
|
43
|
+
keywords: ["composition", "content", "layout", "structure"],
|
|
44
|
+
metadata: {
|
|
45
|
+
description: "Core composition management",
|
|
46
|
+
version: "1.0.0",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
export default registerComposition;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import get from "./route.composition.get";
|
|
2
|
+
import getAll from "./route.composition.getAll";
|
|
3
|
+
import hardDelete from "./route.composition.hardDelete";
|
|
4
|
+
import patch from "./route.composition.patch";
|
|
5
|
+
import post from "./route.composition.post";
|
|
6
|
+
import postBulk from "./route.composition.post.bulk";
|
|
7
|
+
import remove from "./route.composition.remove";
|
|
8
|
+
import restore from "./route.composition.restore";
|
|
9
|
+
const registerRoutes = async (fastify) => {
|
|
10
|
+
await fastify.get("/composition/all", getAll(fastify));
|
|
11
|
+
await fastify.get("/composition/:_id", get(fastify));
|
|
12
|
+
await fastify.patch("/composition/:_id", patch(fastify));
|
|
13
|
+
await fastify.patch("/composition/:_id/restore", restore(fastify));
|
|
14
|
+
await fastify.post("/composition", post(fastify));
|
|
15
|
+
await fastify.post("/composition/bulk", postBulk(fastify));
|
|
16
|
+
await fastify.delete("/composition/:_id", remove(fastify));
|
|
17
|
+
await fastify.delete("/composition/:_id/hard", hardDelete(fastify));
|
|
18
|
+
};
|
|
19
|
+
export default registerRoutes;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const registerEvents = (fastify) => {
|
|
2
|
+
/*
|
|
3
|
+
* interactionLink created and created
|
|
4
|
+
*/
|
|
5
|
+
const created = async (payload) => {
|
|
6
|
+
fastify.eventbus.emit("broadcastInteractionLinkCreated", payload);
|
|
7
|
+
fastify.log.info(`[eventbus] interactionLink broadcast created ${payload.body.items}`);
|
|
8
|
+
};
|
|
9
|
+
/*
|
|
10
|
+
* interactionLink deleted
|
|
11
|
+
*/
|
|
12
|
+
const deleted = async (payload) => {
|
|
13
|
+
fastify.eventbus.emit("broadcastInteractionLinkDeleted", payload);
|
|
14
|
+
fastify.log.info(`[eventbus] interactionLink broadcast deleted ${payload.body.items}`);
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Register those functions for eventbus events
|
|
18
|
+
*/
|
|
19
|
+
fastify.eventbus.on("coreInteractionLinkCreated", created);
|
|
20
|
+
fastify.eventbus.on("coreInteractionLinkDeleted", deleted);
|
|
21
|
+
};
|
|
22
|
+
export default registerEvents;
|