@crownpeak/dqm-react-component 1.0.0

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 (87) hide show
  1. package/AUTHENTICATION.md +281 -0
  2. package/BACKEND-API.md +1829 -0
  3. package/CHANGELOG.md +28 -0
  4. package/DEVELOPMENT.md +339 -0
  5. package/EXAMPLES.md +194 -0
  6. package/LICENSE +22 -0
  7. package/QUICKSTART.md +200 -0
  8. package/README.md +213 -0
  9. package/dist/DQMSidebar.d.ts +5 -0
  10. package/dist/DQMSidebar.d.ts.map +1 -0
  11. package/dist/ErrorBoundary.d.ts +34 -0
  12. package/dist/ErrorBoundary.d.ts.map +1 -0
  13. package/dist/auth-ui/assets/index-CehNKFGj.js +158 -0
  14. package/dist/auth-ui/index.html +30 -0
  15. package/dist/components/auth/DQMLogin.d.ts +16 -0
  16. package/dist/components/auth/DQMLogin.d.ts.map +1 -0
  17. package/dist/components/auth/OAuth2CallbackHandler.d.ts +15 -0
  18. package/dist/components/auth/OAuth2CallbackHandler.d.ts.map +1 -0
  19. package/dist/components/auth/index.d.ts +3 -0
  20. package/dist/components/auth/index.d.ts.map +1 -0
  21. package/dist/components/cards/CategoryCard.d.ts +2 -0
  22. package/dist/components/cards/CategoryCard.d.ts.map +1 -0
  23. package/dist/components/cards/FailedCheckpointsCard.d.ts +2 -0
  24. package/dist/components/cards/FailedCheckpointsCard.d.ts.map +1 -0
  25. package/dist/components/cards/QualityOverviewCard.d.ts +2 -0
  26. package/dist/components/cards/QualityOverviewCard.d.ts.map +1 -0
  27. package/dist/components/cards/index.d.ts +4 -0
  28. package/dist/components/cards/index.d.ts.map +1 -0
  29. package/dist/components/common/CircularProgressWithLabel.d.ts +5 -0
  30. package/dist/components/common/CircularProgressWithLabel.d.ts.map +1 -0
  31. package/dist/components/common/index.d.ts +2 -0
  32. package/dist/components/common/index.d.ts.map +1 -0
  33. package/dist/components/renderers/BrowserViewRenderer.d.ts +9 -0
  34. package/dist/components/renderers/BrowserViewRenderer.d.ts.map +1 -0
  35. package/dist/components/renderers/SafeParsedHtml.d.ts +4 -0
  36. package/dist/components/renderers/SafeParsedHtml.d.ts.map +1 -0
  37. package/dist/components/renderers/ShadowDOMRenderer.d.ts +11 -0
  38. package/dist/components/renderers/ShadowDOMRenderer.d.ts.map +1 -0
  39. package/dist/components/renderers/index.d.ts +4 -0
  40. package/dist/components/renderers/index.d.ts.map +1 -0
  41. package/dist/components/sidebar/SidebarContent.d.ts +2 -0
  42. package/dist/components/sidebar/SidebarContent.d.ts.map +1 -0
  43. package/dist/components/sidebar/SidebarFooter.d.ts +5 -0
  44. package/dist/components/sidebar/SidebarFooter.d.ts.map +1 -0
  45. package/dist/components/sidebar/SidebarHeader.d.ts +2 -0
  46. package/dist/components/sidebar/SidebarHeader.d.ts.map +1 -0
  47. package/dist/components/sidebar/SidebarSkeleton.d.ts +5 -0
  48. package/dist/components/sidebar/SidebarSkeleton.d.ts.map +1 -0
  49. package/dist/components/sidebar/StyledDrawer.d.ts +2 -0
  50. package/dist/components/sidebar/StyledDrawer.d.ts.map +1 -0
  51. package/dist/components/sidebar/StyledFab.d.ts +4 -0
  52. package/dist/components/sidebar/StyledFab.d.ts.map +1 -0
  53. package/dist/components/sidebar/index.d.ts +7 -0
  54. package/dist/components/sidebar/index.d.ts.map +1 -0
  55. package/dist/index.cjs +113 -0
  56. package/dist/index.cjs.map +1 -0
  57. package/dist/index.d.ts +4 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +13712 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/server/config.js +21 -0
  62. package/dist/server/config.js.map +1 -0
  63. package/dist/server/index.js +74 -0
  64. package/dist/server/index.js.map +1 -0
  65. package/dist/server/middleware/authenticate.js +31 -0
  66. package/dist/server/middleware/authenticate.js.map +1 -0
  67. package/dist/server/middleware/errorHandler.js +8 -0
  68. package/dist/server/middleware/errorHandler.js.map +1 -0
  69. package/dist/server/routes/auth.js +142 -0
  70. package/dist/server/routes/auth.js.map +1 -0
  71. package/dist/server/routes/dqm.js +138 -0
  72. package/dist/server/routes/dqm.js.map +1 -0
  73. package/dist/server/services/dqmClient.js +127 -0
  74. package/dist/server/services/dqmClient.js.map +1 -0
  75. package/dist/server/services/sessionStore.js +250 -0
  76. package/dist/server/services/sessionStore.js.map +1 -0
  77. package/dist/server/types.js +2 -0
  78. package/dist/server/types.js.map +1 -0
  79. package/dist/types.d.ts +76 -0
  80. package/dist/types.d.ts.map +1 -0
  81. package/dist/utils/colors/GenerateCategoryColors.d.ts +12 -0
  82. package/dist/utils/colors/GenerateCategoryColors.d.ts.map +1 -0
  83. package/dist/utils/localStorage.d.ts +4 -0
  84. package/dist/utils/localStorage.d.ts.map +1 -0
  85. package/dist/utils/storage.d.ts +28 -0
  86. package/dist/utils/storage.d.ts.map +1 -0
  87. package/package.json +124 -0
@@ -0,0 +1,21 @@
1
+ import { config as dotenvConfig } from 'dotenv';
2
+ dotenvConfig();
3
+ // Server Configuration
4
+ export const config = {
5
+ port: parseInt(process.env.PORT || '3001', 10),
6
+ corsOrigins: process.env.CORS_ORIGINS?.split(',') || ['http://localhost:5173', 'http://localhost:3000'],
7
+ // Session configuration
8
+ session: {
9
+ ttl: 24 * 60 * 60 * 1000, // 24 hours in milliseconds
10
+ },
11
+ // Crownpeak DQM API
12
+ dqm: {
13
+ apiBaseUrl: process.env.DQM_API_BASE_URL || 'https://api.crownpeak.net/dqm-cms/v1',
14
+ },
15
+ // JWT (optional, for session tokens)
16
+ jwt: {
17
+ secret: process.env.JWT_SECRET || 'your-secret-key-change-in-production',
18
+ expiresIn: '24h',
19
+ },
20
+ };
21
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../server/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,IAAI,YAAY,EAAC,MAAM,QAAQ,CAAC;AAC9C,YAAY,EAAE,CAAC;AAEf,uBAAuB;AACvB,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC;IAC9C,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,uBAAuB,CAAC;IAEvG,wBAAwB;IACxB,OAAO,EAAE;QACP,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,2BAA2B;KACtD;IAED,oBAAoB;IACpB,GAAG,EAAE;QACH,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,sCAAsC;KACnF;IAED,qCAAqC;IACrC,GAAG,EAAE;QACH,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,sCAAsC;QACxE,SAAS,EAAE,KAAK;KACjB;CACF,CAAC"}
@@ -0,0 +1,74 @@
1
+ // Express Backend Server for DQM React Component
2
+ import express from 'express';
3
+ import cors from 'cors';
4
+ import helmet from 'helmet';
5
+ import path from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import { authRouter } from './routes/auth.js';
8
+ import { dqmRouter } from './routes/dqm.js';
9
+ import { errorHandler } from './middleware/errorHandler.js';
10
+ import { config } from './config.js';
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+ const app = express();
14
+ // Security middleware - Allow auth UI to load
15
+ app.use(helmet({
16
+ contentSecurityPolicy: {
17
+ directives: {
18
+ defaultSrc: ["'self'"],
19
+ styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
20
+ fontSrc: ["'self'", "https://fonts.gstatic.com"],
21
+ imgSrc: ["'self'", "data:", "https:"],
22
+ scriptSrc: ["'self'"],
23
+ connectSrc: ["'self'"],
24
+ },
25
+ },
26
+ }));
27
+ console.log('[Server] CORS allowed origins:', config.corsOrigins);
28
+ // CORS configuration
29
+ app.use(cors({
30
+ origin: config.corsOrigins,
31
+ credentials: true,
32
+ }));
33
+ // Body parsing middleware
34
+ app.use(express.json({ limit: '10mb' }));
35
+ app.use(express.urlencoded({ extended: true, limit: '10mb' }));
36
+ // Request logging
37
+ app.use((req, res, next) => {
38
+ console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
39
+ next();
40
+ });
41
+ // Health check
42
+ app.get('/health', (req, res) => {
43
+ res.json({ status: 'ok', timestamp: new Date().toISOString() });
44
+ });
45
+ // Serve Auth UI static files
46
+ // Detect if running from source (dev) or compiled (prod)
47
+ const isDev = __dirname.includes('/server') && !__dirname.includes('/dist/');
48
+ const authUiPath = isDev
49
+ ? path.join(__dirname, '..', 'dist', 'auth-ui') // Dev: server/ -> dist/auth-ui
50
+ : path.join(__dirname, '..', 'auth-ui'); // Prod: dist/server/ -> dist/auth-ui
51
+ console.log('[Server] Running in:', isDev ? 'DEVELOPMENT' : 'PRODUCTION');
52
+ console.log('[Server] Auth UI path:', authUiPath);
53
+ app.use('/auth', express.static(authUiPath));
54
+ app.use('/assets', express.static(path.join(authUiPath, 'assets')));
55
+ // Serve index.html for auth routes (SPA routing)
56
+ app.get('/auth/login', (req, res) => {
57
+ res.sendFile(path.join(authUiPath, 'index.html'));
58
+ });
59
+ app.get('/auth/callback', (req, res) => {
60
+ res.sendFile(path.join(authUiPath, 'index.html'));
61
+ });
62
+ // API routes
63
+ app.use('/auth', authRouter);
64
+ app.use('/dqm', dqmRouter);
65
+ // Error handling middleware (must be last)
66
+ app.use(errorHandler);
67
+ // Start server
68
+ const PORT = config.port;
69
+ app.listen(PORT, () => {
70
+ console.log(`🚀 DQM Backend API running on http://localhost:${PORT}`);
71
+ console.log(`📝 Health check: http://localhost:${PORT}/health`);
72
+ });
73
+ export default app;
74
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { sessionStore } from '../services/sessionStore.js';
2
+ /**
3
+ * Middleware to verify session token and attach session data to request
4
+ */
5
+ export async function authenticate(req, res, next) {
6
+ const authHeader = req.headers.authorization;
7
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
8
+ console.error('[Auth] Missing or invalid authorization header');
9
+ return res.status(401).json({
10
+ error: true,
11
+ message: 'Missing or invalid authorization header',
12
+ });
13
+ }
14
+ const token = authHeader.replace('Bearer ', '');
15
+ const session = await sessionStore.get(token);
16
+ if (!session) {
17
+ console.error(`[Auth] Invalid or expired session token: ${token.substring(0, 16)}...`);
18
+ const count = await sessionStore.count();
19
+ return res.status(401).json({
20
+ error: true,
21
+ message: 'Invalid or expired session token. Please log in again.',
22
+ });
23
+ }
24
+ // Attach session data to request
25
+ req.session = session;
26
+ req.sessionToken = token;
27
+ // Extend session expiration on each request
28
+ await sessionStore.extend(token);
29
+ next();
30
+ }
31
+ //# sourceMappingURL=authenticate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../../../server/middleware/authenticate.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAyB,EAAE,GAAa,EAAE,IAAkB;IAC7F,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;IAE7C,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAChE,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,IAAI;YACX,OAAO,EAAE,yCAAyC;SACnD,CAAC,CAAC;IACL,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAEhD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAE9C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,4CAA4C,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;QACvF,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,CAAC;QACzC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,IAAI;YACX,OAAO,EAAE,wDAAwD;SAClE,CAAC,CAAC;IACL,CAAC;IAED,iCAAiC;IACjC,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IACtB,GAAG,CAAC,YAAY,GAAG,KAAK,CAAC;IAEzB,4CAA4C;IAC5C,MAAM,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEjC,IAAI,EAAE,CAAC;AACT,CAAC"}
@@ -0,0 +1,8 @@
1
+ export function errorHandler(err, req, res, next) {
2
+ console.error('[Error]', err.stack);
3
+ res.status(500).json({
4
+ error: true,
5
+ message: err.message || 'Internal server error',
6
+ });
7
+ }
8
+ //# sourceMappingURL=errorHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../../../server/middleware/errorHandler.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,YAAY,CAC1B,GAAU,EACV,GAAY,EACZ,GAAa,EACb,IAAkB;IAElB,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IAEpC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,uBAAuB;KAChD,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,142 @@
1
+ // Authentication Routes
2
+ import { Router } from 'express';
3
+ import { sessionStore } from '../services/sessionStore.js';
4
+ import { DQMClient } from '../services/dqmClient.js';
5
+ import { authenticate } from '../middleware/authenticate.js';
6
+ export const authRouter = Router();
7
+ /**
8
+ * POST /auth/login
9
+ * Direct credentials login - validate with DQM API and issue session token
10
+ */
11
+ authRouter.post('/login', async (req, res) => {
12
+ try {
13
+ const { apiKey, websiteId } = req.body;
14
+ if (!apiKey || !websiteId) {
15
+ return res.status(400).json({
16
+ error: true,
17
+ message: 'Missing required fields: apiKey, websiteId',
18
+ });
19
+ }
20
+ // Validate API key encoding (must be ASCII)
21
+ if (!/^[\x00-\x7F]*$/.test(apiKey)) {
22
+ return res.status(400).json({
23
+ error: true,
24
+ message: 'API key contains non-ASCII characters',
25
+ });
26
+ }
27
+ // Validate credentials with Crownpeak DQM API (optional validation)
28
+ // If validation fails, we still create a session and let the actual API call fail later
29
+ // This allows users to login even if the validation endpoint doesn't work
30
+ const dqmClient = new DQMClient(apiKey, websiteId);
31
+ const isValid = await dqmClient.validateCredentials();
32
+ if (!isValid) {
33
+ console.warn('[Auth] Could not validate credentials during login, will validate on first API call');
34
+ }
35
+ // Create session regardless of validation result
36
+ const sessionToken = await sessionStore.create(apiKey, websiteId);
37
+ console.log(`[Auth] User logged in (websiteId: ${websiteId})`);
38
+ res.json({
39
+ sessionToken,
40
+ websiteId,
41
+ });
42
+ }
43
+ catch (error) {
44
+ console.error('[Auth] Login error:', error.message);
45
+ res.status(401).json({
46
+ error: true,
47
+ message: error.message || 'Authentication failed',
48
+ });
49
+ }
50
+ });
51
+ /**
52
+ * POST /auth/token
53
+ * DISABLED - Use /auth/login instead for direct credential authentication
54
+ */
55
+ authRouter.post('/token', async (req, res) => {
56
+ return res.status(501).json({
57
+ error: true,
58
+ message: 'Session-based authentication not available. Please use /auth/login with API key and website ID.',
59
+ });
60
+ });
61
+ /**
62
+ * POST /auth/oauth2/callback
63
+ * DISABLED - Use /auth/login instead for direct credential authentication
64
+ */
65
+ authRouter.post('/oauth2/callback', async (req, res) => {
66
+ return res.status(501).json({
67
+ error: true,
68
+ message: 'OAuth2 authentication not available. Please use /auth/login with API key and website ID.',
69
+ });
70
+ });
71
+ /**
72
+ * POST /auth/token/validate
73
+ * Validate if a session token is still valid
74
+ */
75
+ authRouter.post('/token/validate', async (req, res) => {
76
+ try {
77
+ const { sessionToken } = req.body;
78
+ if (!sessionToken) {
79
+ return res.status(400).json({
80
+ valid: false,
81
+ message: 'Missing sessionToken',
82
+ });
83
+ }
84
+ // Get session from store
85
+ const session = await sessionStore.get(sessionToken);
86
+ if (!session) {
87
+ return res.status(200).json({
88
+ valid: false,
89
+ message: 'Session not found or expired',
90
+ });
91
+ }
92
+ // Check if session is expired
93
+ if (session.expiresAt && new Date(session.expiresAt) < new Date()) {
94
+ // Clean up expired session
95
+ await sessionStore.delete(sessionToken);
96
+ return res.status(200).json({
97
+ valid: false,
98
+ message: 'Session expired',
99
+ });
100
+ }
101
+ // Session is valid
102
+ res.json({
103
+ valid: true,
104
+ websiteId: session.websiteId,
105
+ expiresAt: session.expiresAt,
106
+ });
107
+ }
108
+ catch (error) {
109
+ console.error('[Auth] Token validation error:', error.message);
110
+ res.status(500).json({
111
+ valid: false,
112
+ message: 'Token validation failed',
113
+ });
114
+ }
115
+ });
116
+ /**
117
+ * POST /auth/logout
118
+ * Logout - invalidate session token
119
+ */
120
+ authRouter.post('/logout', authenticate, async (req, res) => {
121
+ if (req.sessionToken) {
122
+ await sessionStore.delete(req.sessionToken);
123
+ }
124
+ res.json({
125
+ success: true,
126
+ message: 'Logged out successfully',
127
+ });
128
+ });
129
+ /**
130
+ * GET /auth/session
131
+ * Get current session info (for debugging)
132
+ */
133
+ authRouter.get('/session', authenticate, (req, res) => {
134
+ res.json({
135
+ session: {
136
+ websiteId: req.session?.websiteId,
137
+ createdAt: req.session?.createdAt,
138
+ expiresAt: req.session?.expiresAt,
139
+ },
140
+ });
141
+ });
142
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../server/routes/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,138 @@
1
+ // DQM API Proxy Routes
2
+ import { Router } from 'express';
3
+ import { authenticate } from '../middleware/authenticate.js';
4
+ import { DQMClient } from '../services/dqmClient.js';
5
+ export const dqmRouter = Router();
6
+ // All DQM routes require authentication
7
+ dqmRouter.use(authenticate);
8
+ /**
9
+ * POST /dqm/assets
10
+ * Proxy: Create new DQM analysis asset
11
+ */
12
+ dqmRouter.post('/assets', async (req, res) => {
13
+ try {
14
+ if (!req.session) {
15
+ return res.status(401).json({ error: true, message: 'No session' });
16
+ }
17
+ const { html, url, websiteId } = req.body;
18
+ if (!html) {
19
+ return res.status(400).json({
20
+ error: true,
21
+ message: 'Missing required field: html',
22
+ });
23
+ }
24
+ // Create DQM client with session credentials
25
+ const dqmClient = new DQMClient(req.session.apiKey, req.session.websiteId);
26
+ // Create asset
27
+ const result = await dqmClient.createAsset({
28
+ html,
29
+ url,
30
+ websiteId: websiteId || req.session.websiteId,
31
+ });
32
+ res.json(result);
33
+ }
34
+ catch (error) {
35
+ console.error('[DQM] Create asset error:', error.message);
36
+ res.status(500).json({
37
+ error: true,
38
+ message: error.message || 'Failed to create asset',
39
+ });
40
+ }
41
+ });
42
+ /**
43
+ * GET /dqm/assets/:assetId/status
44
+ * Proxy: Get DQM analysis results
45
+ */
46
+ dqmRouter.get('/assets/:assetId/status', async (req, res) => {
47
+ try {
48
+ if (!req.session) {
49
+ return res.status(401).json({ error: true, message: 'No session' });
50
+ }
51
+ const { assetId } = req.params;
52
+ if (!assetId) {
53
+ return res.status(400).json({
54
+ error: true,
55
+ message: 'Missing required parameter: assetId',
56
+ });
57
+ }
58
+ // Create DQM client with session credentials
59
+ const dqmClient = new DQMClient(req.session.apiKey, req.session.websiteId);
60
+ // Get asset
61
+ const result = await dqmClient.getAssetStatus(assetId);
62
+ res.json(result);
63
+ }
64
+ catch (error) {
65
+ console.error('[DQM] Get asset error:', error.message);
66
+ res.status(500).json({
67
+ error: true,
68
+ message: error.message || 'Failed to get asset',
69
+ });
70
+ }
71
+ });
72
+ /**
73
+ * GET /dqm/assets/:assetId/pagehighlight/all
74
+ * Proxy: Get highlighted HTML for all errors
75
+ */
76
+ dqmRouter.get('/assets/:assetId/pagehighlight/all', async (req, res) => {
77
+ try {
78
+ if (!req.session) {
79
+ return res.status(401).json({ error: true, message: 'No session' });
80
+ }
81
+ const { assetId } = req.params;
82
+ if (!assetId) {
83
+ return res.status(400).json({
84
+ error: true,
85
+ message: 'Missing required parameter: assetId',
86
+ });
87
+ }
88
+ // Create DQM client with session credentials
89
+ const dqmClient = new DQMClient(req.session.apiKey, req.session.websiteId);
90
+ // Get highlighted HTML
91
+ const html = await dqmClient.getPageHighlightAll(assetId);
92
+ // Return as HTML
93
+ res.setHeader('Content-Type', 'text/html');
94
+ res.send(html);
95
+ }
96
+ catch (error) {
97
+ console.error('[DQM] Get page highlight error:', error.message);
98
+ res.status(500).json({
99
+ error: true,
100
+ message: error.message || 'Failed to get page highlight',
101
+ });
102
+ }
103
+ });
104
+ /**
105
+ * GET /dqm/assets/:assetId/pagehighlight/:checkpointId
106
+ * Proxy: Get highlighted HTML for specific checkpoint
107
+ * Query params: highlightSource=true/false (default: false for browser view)
108
+ */
109
+ dqmRouter.get('/assets/:assetId/pagehighlight/:checkpointId', async (req, res) => {
110
+ try {
111
+ if (!req.session) {
112
+ return res.status(401).json({ error: true, message: 'No session' });
113
+ }
114
+ const { assetId, checkpointId } = req.params;
115
+ const { highlightSource } = req.query;
116
+ if (!assetId || !checkpointId) {
117
+ return res.status(400).json({
118
+ error: true,
119
+ message: 'Missing required parameters: assetId, checkpointId',
120
+ });
121
+ }
122
+ // Create DQM client with session credentials
123
+ const dqmClient = new DQMClient(req.session.apiKey, req.session.websiteId);
124
+ // Get highlighted HTML (with optional highlightSource parameter)
125
+ const html = await dqmClient.getPageHighlightCheckpoint(assetId, checkpointId, highlightSource === 'true');
126
+ // Return as HTML
127
+ res.setHeader('Content-Type', 'text/html');
128
+ res.send(html);
129
+ }
130
+ catch (error) {
131
+ console.error('[DQM] Get checkpoint highlight error:', error.message);
132
+ res.status(500).json({
133
+ error: true,
134
+ message: error.message || 'Failed to get checkpoint highlight',
135
+ });
136
+ }
137
+ });
138
+ //# sourceMappingURL=dqm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dqm.js","sourceRoot":"","sources":["../../../server/routes/dqm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ // Crownpeak DQM API Client
2
+ import axios from 'axios';
3
+ import { config } from '../config.js';
4
+ export class DQMClient {
5
+ apiKey;
6
+ websiteId;
7
+ client;
8
+ constructor(apiKey, websiteId) {
9
+ this.apiKey = apiKey;
10
+ this.websiteId = websiteId;
11
+ this.client = axios.create({
12
+ baseURL: config.dqm.apiBaseUrl,
13
+ headers: {
14
+ 'x-api-key': apiKey,
15
+ 'Content-Type': 'application/x-www-form-urlencoded',
16
+ },
17
+ timeout: 30000, // 30 seconds
18
+ });
19
+ }
20
+ /**
21
+ * Start HTML analysis
22
+ */
23
+ async createAsset(data) {
24
+ try {
25
+ const encodedApiKey = encodeURIComponent(this.apiKey);
26
+ const targetWebsiteId = data.websiteId || this.websiteId;
27
+ // Convert to URLSearchParams for proper application/x-www-form-urlencoded encoding
28
+ const formData = new URLSearchParams();
29
+ formData.append('websiteId', targetWebsiteId);
30
+ formData.append('content', data.html);
31
+ formData.append('contentType', 'text/html; charset=UTF-8');
32
+ formData.append('title', data.url || 'DQM Analysis');
33
+ formData.append('timestamp', new Date().toISOString());
34
+ const response = await this.client.post(`/assets?apiKey=${encodedApiKey}`, formData, {
35
+ headers: {
36
+ 'x-api-key': this.apiKey,
37
+ 'Content-Type': 'application/x-www-form-urlencoded',
38
+ }
39
+ });
40
+ return response.data;
41
+ }
42
+ catch (error) {
43
+ console.error('[DQMClient] Create asset error:', error.response?.data || error.message);
44
+ throw new Error(`Failed to create DQM asset: ${error.response?.data?.message || error.response?.statusText || error.message}`);
45
+ }
46
+ }
47
+ /**
48
+ * Get analysis status and results
49
+ */
50
+ async getAssetStatus(assetId) {
51
+ try {
52
+ const encodedApiKey = encodeURIComponent(this.apiKey);
53
+ const response = await this.client.get(`/assets/${assetId}/status?apiKey=${encodedApiKey}`, {
54
+ headers: {
55
+ 'x-api-key': this.apiKey,
56
+ }
57
+ });
58
+ return response.data;
59
+ }
60
+ catch (error) {
61
+ console.error('[DQMClient] Get asset error:', error.response?.data || error.message);
62
+ throw new Error(`Failed to get DQM asset: ${error.response?.data?.message || error.message}`);
63
+ }
64
+ }
65
+ /**
66
+ * Get highlighted HTML for all errors
67
+ */
68
+ async getPageHighlightAll(assetId) {
69
+ try {
70
+ const encodedApiKey = encodeURIComponent(this.apiKey);
71
+ const response = await this.client.get(`/assets/${assetId}/pagehighlight/all?apiKey=${encodedApiKey}`, {
72
+ responseType: 'text',
73
+ headers: {
74
+ 'x-api-key': this.apiKey,
75
+ }
76
+ });
77
+ return response.data;
78
+ }
79
+ catch (error) {
80
+ console.error('[DQMClient] Get page highlight error:', error.response?.data || error.message);
81
+ throw new Error(`Failed to get page highlight: ${error.response?.data?.message || error.message}`);
82
+ }
83
+ }
84
+ /**
85
+ * Get highlighted HTML for specific checkpoint
86
+ * @param assetId - The asset ID
87
+ * @param checkpointId - The checkpoint ID
88
+ * @param highlightSource - If true, returns source view with highlighted code snippet. If false, returns browser view with full page.
89
+ */
90
+ async getPageHighlightCheckpoint(assetId, checkpointId, highlightSource = false) {
91
+ try {
92
+ const encodedApiKey = encodeURIComponent(this.apiKey);
93
+ const response = await this.client.get(`/assets/${assetId}/errors/${checkpointId}?apiKey=${encodedApiKey}&highlightSource=${highlightSource}`, {
94
+ responseType: 'text',
95
+ headers: {
96
+ 'x-api-key': this.apiKey,
97
+ }
98
+ });
99
+ return response.data;
100
+ }
101
+ catch (error) {
102
+ console.error('[DQMClient] Get checkpoint highlight error:', error.response?.data || error.message);
103
+ throw new Error(`Failed to get checkpoint highlight: ${error.response?.data?.message || error.message}`);
104
+ }
105
+ }
106
+ /**
107
+ * Validate credentials by making a test request
108
+ * We'll use the /assets endpoint with minimal data as a test
109
+ */
110
+ async validateCredentials() {
111
+ try {
112
+ const encodedApiKey = encodeURIComponent(this.apiKey);
113
+ // Simple test: Try to get assets list (should return empty or existing assets)
114
+ await this.client.get(`/assets?apiKey=${encodedApiKey}`, {
115
+ headers: {
116
+ 'x-api-key': this.apiKey,
117
+ },
118
+ });
119
+ return true;
120
+ }
121
+ catch (error) {
122
+ console.error('[DQMClient] Credential validation failed:', error.response?.status || error.message);
123
+ return false;
124
+ }
125
+ }
126
+ }
127
+ //# sourceMappingURL=dqmClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dqmClient.js","sourceRoot":"","sources":["../../../server/services/dqmClient.ts"],"names":[],"mappings":"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"}