@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.
- package/AUTHENTICATION.md +281 -0
- package/BACKEND-API.md +1829 -0
- package/CHANGELOG.md +28 -0
- package/DEVELOPMENT.md +339 -0
- package/EXAMPLES.md +194 -0
- package/LICENSE +22 -0
- package/QUICKSTART.md +200 -0
- package/README.md +213 -0
- package/dist/DQMSidebar.d.ts +5 -0
- package/dist/DQMSidebar.d.ts.map +1 -0
- package/dist/ErrorBoundary.d.ts +34 -0
- package/dist/ErrorBoundary.d.ts.map +1 -0
- package/dist/auth-ui/assets/index-CehNKFGj.js +158 -0
- package/dist/auth-ui/index.html +30 -0
- package/dist/components/auth/DQMLogin.d.ts +16 -0
- package/dist/components/auth/DQMLogin.d.ts.map +1 -0
- package/dist/components/auth/OAuth2CallbackHandler.d.ts +15 -0
- package/dist/components/auth/OAuth2CallbackHandler.d.ts.map +1 -0
- package/dist/components/auth/index.d.ts +3 -0
- package/dist/components/auth/index.d.ts.map +1 -0
- package/dist/components/cards/CategoryCard.d.ts +2 -0
- package/dist/components/cards/CategoryCard.d.ts.map +1 -0
- package/dist/components/cards/FailedCheckpointsCard.d.ts +2 -0
- package/dist/components/cards/FailedCheckpointsCard.d.ts.map +1 -0
- package/dist/components/cards/QualityOverviewCard.d.ts +2 -0
- package/dist/components/cards/QualityOverviewCard.d.ts.map +1 -0
- package/dist/components/cards/index.d.ts +4 -0
- package/dist/components/cards/index.d.ts.map +1 -0
- package/dist/components/common/CircularProgressWithLabel.d.ts +5 -0
- package/dist/components/common/CircularProgressWithLabel.d.ts.map +1 -0
- package/dist/components/common/index.d.ts +2 -0
- package/dist/components/common/index.d.ts.map +1 -0
- package/dist/components/renderers/BrowserViewRenderer.d.ts +9 -0
- package/dist/components/renderers/BrowserViewRenderer.d.ts.map +1 -0
- package/dist/components/renderers/SafeParsedHtml.d.ts +4 -0
- package/dist/components/renderers/SafeParsedHtml.d.ts.map +1 -0
- package/dist/components/renderers/ShadowDOMRenderer.d.ts +11 -0
- package/dist/components/renderers/ShadowDOMRenderer.d.ts.map +1 -0
- package/dist/components/renderers/index.d.ts +4 -0
- package/dist/components/renderers/index.d.ts.map +1 -0
- package/dist/components/sidebar/SidebarContent.d.ts +2 -0
- package/dist/components/sidebar/SidebarContent.d.ts.map +1 -0
- package/dist/components/sidebar/SidebarFooter.d.ts +5 -0
- package/dist/components/sidebar/SidebarFooter.d.ts.map +1 -0
- package/dist/components/sidebar/SidebarHeader.d.ts +2 -0
- package/dist/components/sidebar/SidebarHeader.d.ts.map +1 -0
- package/dist/components/sidebar/SidebarSkeleton.d.ts +5 -0
- package/dist/components/sidebar/SidebarSkeleton.d.ts.map +1 -0
- package/dist/components/sidebar/StyledDrawer.d.ts +2 -0
- package/dist/components/sidebar/StyledDrawer.d.ts.map +1 -0
- package/dist/components/sidebar/StyledFab.d.ts +4 -0
- package/dist/components/sidebar/StyledFab.d.ts.map +1 -0
- package/dist/components/sidebar/index.d.ts +7 -0
- package/dist/components/sidebar/index.d.ts.map +1 -0
- package/dist/index.cjs +113 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13712 -0
- package/dist/index.js.map +1 -0
- package/dist/server/config.js +21 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/index.js +74 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/middleware/authenticate.js +31 -0
- package/dist/server/middleware/authenticate.js.map +1 -0
- package/dist/server/middleware/errorHandler.js +8 -0
- package/dist/server/middleware/errorHandler.js.map +1 -0
- package/dist/server/routes/auth.js +142 -0
- package/dist/server/routes/auth.js.map +1 -0
- package/dist/server/routes/dqm.js +138 -0
- package/dist/server/routes/dqm.js.map +1 -0
- package/dist/server/services/dqmClient.js +127 -0
- package/dist/server/services/dqmClient.js.map +1 -0
- package/dist/server/services/sessionStore.js +250 -0
- package/dist/server/services/sessionStore.js.map +1 -0
- package/dist/server/types.js +2 -0
- package/dist/server/types.js.map +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/colors/GenerateCategoryColors.d.ts +12 -0
- package/dist/utils/colors/GenerateCategoryColors.d.ts.map +1 -0
- package/dist/utils/localStorage.d.ts +4 -0
- package/dist/utils/localStorage.d.ts.map +1 -0
- package/dist/utils/storage.d.ts +28 -0
- package/dist/utils/storage.d.ts.map +1 -0
- 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 @@
|
|
|
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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"}
|