@crownpeak/dqm-react-component-dev-mcp 1.2.1 → 1.2.4

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/data/.glfrc.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "inputs": ["./package.json", "./mcp-server/package.json"],
2
+ "inputs": ["./package.json", "./mcp-server/package.json", "./website/package.json"],
3
3
  "output": "./THIRD_PARTY_LICENSES.txt",
4
4
  "lineEnding": "lf",
5
5
  "omitVersions": false,
package/data/CHANGELOG.md CHANGED
@@ -5,6 +5,39 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.4] - 2026-01-08
9
+
10
+ ### Added
11
+ - **Marketing Website**: New Next.js marketing/documentation website deployed to GitHub Pages
12
+ - Hero section with animated feature highlights
13
+ - Interactive demo section with live sidebar preview
14
+ - Integration section with code examples and copy functionality
15
+ - Multi-language support (English, German, Spanish) using react-i18next
16
+ - Framer Motion animations throughout
17
+ - Built with Tailwind CSS and shadcn/ui components
18
+ - WCAG AA accessibility compliant (proper aria-labels, 4.5:1+ contrast ratios)
19
+ - Static export for GitHub Pages hosting
20
+ - **AI Agent Documentation**: Added comprehensive Website section to `.github/copilot-instructions.md`
21
+
22
+ ## [1.2.2] - 2026-01-08
23
+
24
+ ### Fixed
25
+ - **AI Translation Reliability**: Resolved issue where AI translations were not triggered automatically
26
+ - Translation now starts automatically when AI summary completes
27
+ - Translation now starts automatically when AI engine becomes ready
28
+ - Fixed race condition where blocked translations would never retry
29
+
30
+ ### Added
31
+ - **300ms Debounce**: API calls are now debounced to prevent accidental spam when state changes rapidly
32
+ - **Reactive State Management**: `summaryGenerating` and `engineIsReady` are now proper effect dependencies
33
+ - **Automatic Retry Logic**: Translation automatically restarts when blocking conditions are resolved
34
+ - **Unit Tests**: 13 new tests for `useAITranslation` hook covering debounce, blocking, cache, and abort behavior
35
+ - **Integration Tests**: 6 new tests for Summary→Translation flow with API call counting
36
+
37
+ ### Changed
38
+ - AI Translation hook now uses reactive dependencies instead of refs for blocking conditions
39
+ - Improved cleanup on component unmount (cancels pending debounce timers and aborts requests)
40
+
8
41
  ## [1.2.0] - 2026-01-07
9
42
 
10
43
  ### Added
package/data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Crownpeak Technology GmbH
3
+ Copyright (c) 2025-2026 Crownpeak Technology GmbH
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crownpeak/dqm-react-component",
3
- "version": "1.2.1",
3
+ "version": "1.2.4",
4
4
  "private": false,
5
5
  "description": "A React component for Crownpeak Digital Quality Management (DQM) integration",
6
6
  "type": "module",
@@ -84,7 +84,7 @@
84
84
  "test:e2e:debug": "playwright test --debug",
85
85
  "wiki:build": "./scripts/wiki-build.sh",
86
86
  "wiki:deploy": "./scripts/wiki-deploy.sh",
87
- "setVersion": "npm version --workspaces --no-git-tag-version",
87
+ "setVersion": "node ./scripts/npm-set-version.mjs",
88
88
  "licenses:generate": "generate-license-file --config .glfrc.json",
89
89
  "licenses:check": "license-checker --onlyAllow 'MIT;ISC;Apache-2.0;BSD-2-Clause;BSD-3-Clause;0BSD;Unlicense;CC0-1.0;CC-BY-3.0;CC-BY-4.0;Python-2.0;BlueOak-1.0.0;Zlib;WTFPL' --production",
90
90
  "licenses:check:all": "npm run licenses:check && npm run licenses:check --prefix mcp-server",
@@ -92,7 +92,8 @@
92
92
  "prepare": "husky"
93
93
  },
94
94
  "workspaces": [
95
- "mcp-server"
95
+ "mcp-server",
96
+ "website"
96
97
  ],
97
98
  "peerDependencies": {
98
99
  "@mui/icons-material": ">=5.0.0",
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execSync } from 'child_process';
4
+ import { dirname, join } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const rootDir = join(__dirname, '..');
9
+
10
+ // Get version from command line argument
11
+ const newVersion = process.argv[2];
12
+
13
+ if (!newVersion) {
14
+ console.error('Usage: npm run setVersion <version>');
15
+ console.error('Example: npm run setVersion 1.2.3');
16
+ process.exit(1);
17
+ }
18
+
19
+ // Validate version format
20
+ const versionRegex = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
21
+ if (!versionRegex.test(newVersion)) {
22
+ console.error(`Invalid version format: ${newVersion}`);
23
+ console.error('Expected format: x.y.z or x.y.z-prerelease');
24
+ process.exit(1);
25
+ }
26
+
27
+ // Main execution
28
+ console.log(`Setting version to ${newVersion} in all packages...\n`);
29
+
30
+ try {
31
+ // Update root package.json
32
+ execSync(`npm version ${newVersion} --no-git-tag-version`, { cwd: rootDir, stdio: 'inherit' });
33
+
34
+ // Update all workspace packages
35
+ execSync(`npm version ${newVersion} --workspaces --no-git-tag-version`, { cwd: rootDir, stdio: 'inherit' });
36
+
37
+ console.log('\nVersion update complete!');
38
+ } catch (error) {
39
+ console.error(`Failed to update version: ${error.message}`);
40
+ process.exit(1);
41
+ }
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Crownpeak Technology GmbH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,95 @@
1
+ # Crownpeak DQM React Component - Demo Website
2
+
3
+ Eine interaktive Demo-Website für das [@crownpeak/dqm-react-component](https://www.npmjs.com/package/@crownpeak/dqm-react-component) Paket.
4
+
5
+ ## 🚀 Features
6
+
7
+ - **Interaktive Demo** - Erleben Sie das DQM React Component mit Mock-Daten
8
+ - **Mehrsprachig** - Verfügbar in Deutsch, Englisch und Spanisch
9
+ - **Statischer Export** - Läuft ohne Server, nur HTML/CSS/JS
10
+ - **GitHub Pages Ready** - Automatisches Deployment via GitHub Actions
11
+
12
+ ## 🛠️ Entwicklung
13
+
14
+ ### Voraussetzungen
15
+
16
+ - Node.js 20+
17
+ - Yarn 1.22+
18
+
19
+ ### Installation
20
+
21
+ ```bash
22
+ yarn install
23
+ ```
24
+
25
+ ### Entwicklungsserver starten
26
+
27
+ ```bash
28
+ yarn dev
29
+ ```
30
+
31
+ Die Website ist dann unter [http://localhost:3000](http://localhost:3000) erreichbar.
32
+
33
+ ### Produktions-Build
34
+
35
+ ```bash
36
+ yarn build
37
+ ```
38
+
39
+ Der statische Export wird im `out/`-Ordner erstellt.
40
+
41
+ ## 📦 Deployment
42
+
43
+ ### GitHub Pages (automatisch)
44
+
45
+ 1. Repository auf GitHub erstellen
46
+ 2. Code pushen
47
+ 3. In den Repository-Einstellungen:
48
+ - **Settings** → **Pages** → **Source**: "GitHub Actions"
49
+
50
+ Der Workflow in `.github/workflows/deploy.yml` übernimmt den Rest.
51
+
52
+ ### Manuelles Deployment
53
+
54
+ Der `out/`-Ordner kann auf jedem statischen Hosting-Service deployed werden:
55
+
56
+ - Netlify
57
+ - Vercel
58
+ - AWS S3
59
+ - Cloudflare Pages
60
+ - etc.
61
+
62
+ ## 🔧 Konfiguration
63
+
64
+ ### Base Path (für Subdirectory-Deployment)
65
+
66
+ Falls die Website nicht im Root einer Domain gehostet wird, setze die Umgebungsvariable:
67
+
68
+ ```bash
69
+ NEXT_PUBLIC_BASE_PATH=/mein-pfad yarn build
70
+ ```
71
+
72
+ ## 📁 Projektstruktur
73
+
74
+ ```
75
+ ├── src/
76
+ │ ├── app/ # Next.js App Router
77
+ │ ├── components/ # React Komponenten
78
+ │ ├── i18n/ # Internationalisierung
79
+ │ ├── lib/ # Utility-Funktionen
80
+ │ ├── locales/ # Übersetzungen (de, en, es)
81
+ │ ├── mocks/ # MSW Mock-Handler
82
+ │ └── store/ # Redux Store
83
+ ├── public/ # Statische Assets
84
+ └── out/ # Build-Output (nach `yarn build`)
85
+ ```
86
+
87
+ ## 📄 Lizenz
88
+
89
+ © 2024 Crownpeak Technology GmbH. Alle Rechte vorbehalten.
90
+
91
+ ## 🔗 Links
92
+
93
+ - [DQM React Component auf npm](https://www.npmjs.com/package/@crownpeak/dqm-react-component)
94
+ - [GitHub Repository](https://github.com/Crownpeak/dqm-react-component)
95
+ - [Crownpeak Website](https://www.crownpeak.com)
@@ -0,0 +1,42 @@
1
+ # Crownpeak DQM Website - Release Notes
2
+
3
+ ## v1.2.4 - 2026-01-08
4
+
5
+ ### 🚀 Initial Release
6
+
7
+ The Crownpeak DQM React Component now has an official marketing and documentation website, hosted on GitHub Pages.
8
+
9
+ #### ✨ Features
10
+
11
+ - **Hero Section**: Animated landing page with feature highlights and call-to-action
12
+ - **Features Section**: Grid layout showcasing component capabilities
13
+ - **Demo Section**: Interactive sidebar demonstration with live preview
14
+ - **Integration Section**: Code examples with syntax highlighting and one-click copy
15
+ - **Footer**: Links to documentation, GitHub repository, and NPM package
16
+
17
+ #### 🌍 Internationalization
18
+
19
+ - Multi-language support: English (default), German, Spanish
20
+ - Language switcher in navigation
21
+ - Browser language auto-detection
22
+ - URL parameter override (`?lang=de`)
23
+
24
+ #### ♿ Accessibility (WCAG AA)
25
+
26
+ - Proper `aria-label` attributes on all icon-only interactive elements
27
+ - Color contrast ratio of 6.5:1+ on dark backgrounds
28
+ - Semantic HTML structure
29
+ - Keyboard navigation support
30
+
31
+ #### 🛠 Tech Stack
32
+
33
+ - **Framework**: Next.js 14 with App Router
34
+ - **Styling**: Tailwind CSS
35
+ - **Components**: shadcn/ui
36
+ - **Animations**: Framer Motion
37
+ - **i18n**: react-i18next
38
+ - **Deployment**: Static export to GitHub Pages
39
+
40
+ #### 📦 Deployment
41
+
42
+ Automatic deployment via GitHub Actions on push to `main` branch. Manual trigger also available via workflow dispatch.
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "default",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "src/app/globals.css",
9
+ "baseColor": "slate",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "@/components",
15
+ "utils": "@/lib/utils",
16
+ "ui": "@/components/ui",
17
+ "hooks": "@/hooks",
18
+ "lib": "@/lib"
19
+ },
20
+ "iconLibrary": "lucide",
21
+ "registries": {
22
+ "@aceternity": "https://ui.aceternity.com/registry/{name}.json",
23
+ "@shadcnblocks": {
24
+ "url": "https://www.shadcnblocks.com/r/{name}",
25
+ "headers": {
26
+ "Authorization": "Bearer YOUR_API_KEY_HERE"
27
+ }
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,16 @@
1
+ import { defineConfig, globalIgnores } from "eslint/config";
2
+ import nextVitals from "eslint-config-next/core-web-vitals";
3
+ import nextTs from "eslint-config-next/typescript";
4
+
5
+ const eslintConfig = defineConfig([
6
+ ...nextVitals,
7
+ ...nextTs,
8
+ globalIgnores([
9
+ ".next/**",
10
+ "out/**",
11
+ "build/**",
12
+ "next-env.d.ts",
13
+ ]),
14
+ ]);
15
+
16
+ export default eslintConfig;
@@ -0,0 +1,25 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const isProd = process.env.NODE_ENV === 'production';
4
+
5
+ const nextConfig: NextConfig = {
6
+ // Static export for GitHub Pages
7
+ output: 'export',
8
+
9
+ // Base path for GitHub Pages (repository name)
10
+ // Wird automatisch von GitHub Actions gesetzt, oder manuell konfiguriert
11
+ basePath: isProd ? process.env.NEXT_PUBLIC_BASE_PATH || '' : '',
12
+
13
+ // Asset prefix for proper asset loading on GitHub Pages
14
+ assetPrefix: isProd ? process.env.NEXT_PUBLIC_BASE_PATH || '' : '',
15
+
16
+ // Disable image optimization for static export
17
+ images: {
18
+ unoptimized: true,
19
+ },
20
+
21
+ // Trailing slash for better compatibility with static hosting
22
+ trailingSlash: true,
23
+ };
24
+
25
+ export default nextConfig;
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@crownpeak/dqm-react-component-website",
3
+ "version": "1.2.4",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "eslint"
10
+ },
11
+ "dependencies": {
12
+ "@crownpeak/dqm-react-component": "^1.2.2",
13
+ "@emotion/react": "^11.14.0",
14
+ "@emotion/styled": "^11.14.1",
15
+ "@mui/icons-material": "^7.3.7",
16
+ "@mui/material": "^7.3.7",
17
+ "@radix-ui/react-accordion": "^1.2.12",
18
+ "@radix-ui/react-avatar": "^1.1.11",
19
+ "@radix-ui/react-progress": "^1.1.8",
20
+ "@radix-ui/react-scroll-area": "^1.2.10",
21
+ "@radix-ui/react-separator": "^1.1.8",
22
+ "@radix-ui/react-slot": "^1.2.4",
23
+ "@radix-ui/react-tabs": "^1.1.13",
24
+ "@radix-ui/react-tooltip": "^1.2.8",
25
+ "@reduxjs/toolkit": "^2.11.2",
26
+ "class-variance-authority": "^0.7.1",
27
+ "clsx": "^2.1.1",
28
+ "framer-motion": "^12.24.10",
29
+ "i18next": "^25.7.4",
30
+ "i18next-browser-languagedetector": "^8.2.0",
31
+ "lucide-react": "^0.562.0",
32
+ "next": "16.1.1",
33
+ "react": "19.2.3",
34
+ "react-dom": "19.2.3",
35
+ "react-i18next": "^16.5.1",
36
+ "react-redux": "^9.2.0",
37
+ "tailwind-merge": "^3.4.0",
38
+ "vanilla-cookieconsent": "^3.1.0"
39
+ },
40
+ "devDependencies": {
41
+ "@tailwindcss/postcss": "^4",
42
+ "@types/node": "^20",
43
+ "@types/react": "^19",
44
+ "@types/react-dom": "^19",
45
+ "eslint": "^9",
46
+ "eslint-config-next": "16.1.1",
47
+ "husky": "^9.1.7",
48
+ "msw": "^2.12.7",
49
+ "tailwindcss": "^4",
50
+ "typescript": "^5"
51
+ },
52
+ "packageManager": "yarn@1.22.22",
53
+ "msw": {
54
+ "workerDirectory": [
55
+ "public"
56
+ ]
57
+ }
58
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
File without changes
@@ -0,0 +1,349 @@
1
+ /* eslint-disable */
2
+ /* tslint:disable */
3
+
4
+ /**
5
+ * Mock Service Worker.
6
+ * @see https://github.com/mswjs/msw
7
+ * - Please do NOT modify this file.
8
+ */
9
+
10
+ const PACKAGE_VERSION = '2.12.7'
11
+ const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'
12
+ const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
13
+ const activeClientIds = new Set()
14
+
15
+ addEventListener('install', function () {
16
+ self.skipWaiting()
17
+ })
18
+
19
+ addEventListener('activate', function (event) {
20
+ event.waitUntil(self.clients.claim())
21
+ })
22
+
23
+ addEventListener('message', async function (event) {
24
+ const clientId = Reflect.get(event.source || {}, 'id')
25
+
26
+ if (!clientId || !self.clients) {
27
+ return
28
+ }
29
+
30
+ const client = await self.clients.get(clientId)
31
+
32
+ if (!client) {
33
+ return
34
+ }
35
+
36
+ const allClients = await self.clients.matchAll({
37
+ type: 'window',
38
+ })
39
+
40
+ switch (event.data) {
41
+ case 'KEEPALIVE_REQUEST': {
42
+ sendToClient(client, {
43
+ type: 'KEEPALIVE_RESPONSE',
44
+ })
45
+ break
46
+ }
47
+
48
+ case 'INTEGRITY_CHECK_REQUEST': {
49
+ sendToClient(client, {
50
+ type: 'INTEGRITY_CHECK_RESPONSE',
51
+ payload: {
52
+ packageVersion: PACKAGE_VERSION,
53
+ checksum: INTEGRITY_CHECKSUM,
54
+ },
55
+ })
56
+ break
57
+ }
58
+
59
+ case 'MOCK_ACTIVATE': {
60
+ activeClientIds.add(clientId)
61
+
62
+ sendToClient(client, {
63
+ type: 'MOCKING_ENABLED',
64
+ payload: {
65
+ client: {
66
+ id: client.id,
67
+ frameType: client.frameType,
68
+ },
69
+ },
70
+ })
71
+ break
72
+ }
73
+
74
+ case 'CLIENT_CLOSED': {
75
+ activeClientIds.delete(clientId)
76
+
77
+ const remainingClients = allClients.filter((client) => {
78
+ return client.id !== clientId
79
+ })
80
+
81
+ // Unregister itself when there are no more clients
82
+ if (remainingClients.length === 0) {
83
+ self.registration.unregister()
84
+ }
85
+
86
+ break
87
+ }
88
+ }
89
+ })
90
+
91
+ addEventListener('fetch', function (event) {
92
+ const requestInterceptedAt = Date.now()
93
+
94
+ // Bypass navigation requests.
95
+ if (event.request.mode === 'navigate') {
96
+ return
97
+ }
98
+
99
+ // Opening the DevTools triggers the "only-if-cached" request
100
+ // that cannot be handled by the worker. Bypass such requests.
101
+ if (
102
+ event.request.cache === 'only-if-cached' &&
103
+ event.request.mode !== 'same-origin'
104
+ ) {
105
+ return
106
+ }
107
+
108
+ // Bypass all requests when there are no active clients.
109
+ // Prevents the self-unregistered worked from handling requests
110
+ // after it's been terminated (still remains active until the next reload).
111
+ if (activeClientIds.size === 0) {
112
+ return
113
+ }
114
+
115
+ const requestId = crypto.randomUUID()
116
+ event.respondWith(handleRequest(event, requestId, requestInterceptedAt))
117
+ })
118
+
119
+ /**
120
+ * @param {FetchEvent} event
121
+ * @param {string} requestId
122
+ * @param {number} requestInterceptedAt
123
+ */
124
+ async function handleRequest(event, requestId, requestInterceptedAt) {
125
+ const client = await resolveMainClient(event)
126
+ const requestCloneForEvents = event.request.clone()
127
+ const response = await getResponse(
128
+ event,
129
+ client,
130
+ requestId,
131
+ requestInterceptedAt,
132
+ )
133
+
134
+ // Send back the response clone for the "response:*" life-cycle events.
135
+ // Ensure MSW is active and ready to handle the message, otherwise
136
+ // this message will pend indefinitely.
137
+ if (client && activeClientIds.has(client.id)) {
138
+ const serializedRequest = await serializeRequest(requestCloneForEvents)
139
+
140
+ // Clone the response so both the client and the library could consume it.
141
+ const responseClone = response.clone()
142
+
143
+ sendToClient(
144
+ client,
145
+ {
146
+ type: 'RESPONSE',
147
+ payload: {
148
+ isMockedResponse: IS_MOCKED_RESPONSE in response,
149
+ request: {
150
+ id: requestId,
151
+ ...serializedRequest,
152
+ },
153
+ response: {
154
+ type: responseClone.type,
155
+ status: responseClone.status,
156
+ statusText: responseClone.statusText,
157
+ headers: Object.fromEntries(responseClone.headers.entries()),
158
+ body: responseClone.body,
159
+ },
160
+ },
161
+ },
162
+ responseClone.body ? [serializedRequest.body, responseClone.body] : [],
163
+ )
164
+ }
165
+
166
+ return response
167
+ }
168
+
169
+ /**
170
+ * Resolve the main client for the given event.
171
+ * Client that issues a request doesn't necessarily equal the client
172
+ * that registered the worker. It's with the latter the worker should
173
+ * communicate with during the response resolving phase.
174
+ * @param {FetchEvent} event
175
+ * @returns {Promise<Client | undefined>}
176
+ */
177
+ async function resolveMainClient(event) {
178
+ const client = await self.clients.get(event.clientId)
179
+
180
+ if (activeClientIds.has(event.clientId)) {
181
+ return client
182
+ }
183
+
184
+ if (client?.frameType === 'top-level') {
185
+ return client
186
+ }
187
+
188
+ const allClients = await self.clients.matchAll({
189
+ type: 'window',
190
+ })
191
+
192
+ return allClients
193
+ .filter((client) => {
194
+ // Get only those clients that are currently visible.
195
+ return client.visibilityState === 'visible'
196
+ })
197
+ .find((client) => {
198
+ // Find the client ID that's recorded in the
199
+ // set of clients that have registered the worker.
200
+ return activeClientIds.has(client.id)
201
+ })
202
+ }
203
+
204
+ /**
205
+ * @param {FetchEvent} event
206
+ * @param {Client | undefined} client
207
+ * @param {string} requestId
208
+ * @param {number} requestInterceptedAt
209
+ * @returns {Promise<Response>}
210
+ */
211
+ async function getResponse(event, client, requestId, requestInterceptedAt) {
212
+ // Clone the request because it might've been already used
213
+ // (i.e. its body has been read and sent to the client).
214
+ const requestClone = event.request.clone()
215
+
216
+ function passthrough() {
217
+ // Cast the request headers to a new Headers instance
218
+ // so the headers can be manipulated with.
219
+ const headers = new Headers(requestClone.headers)
220
+
221
+ // Remove the "accept" header value that marked this request as passthrough.
222
+ // This prevents request alteration and also keeps it compliant with the
223
+ // user-defined CORS policies.
224
+ const acceptHeader = headers.get('accept')
225
+ if (acceptHeader) {
226
+ const values = acceptHeader.split(',').map((value) => value.trim())
227
+ const filteredValues = values.filter(
228
+ (value) => value !== 'msw/passthrough',
229
+ )
230
+
231
+ if (filteredValues.length > 0) {
232
+ headers.set('accept', filteredValues.join(', '))
233
+ } else {
234
+ headers.delete('accept')
235
+ }
236
+ }
237
+
238
+ return fetch(requestClone, { headers })
239
+ }
240
+
241
+ // Bypass mocking when the client is not active.
242
+ if (!client) {
243
+ return passthrough()
244
+ }
245
+
246
+ // Bypass initial page load requests (i.e. static assets).
247
+ // The absence of the immediate/parent client in the map of the active clients
248
+ // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
249
+ // and is not ready to handle requests.
250
+ if (!activeClientIds.has(client.id)) {
251
+ return passthrough()
252
+ }
253
+
254
+ // Notify the client that a request has been intercepted.
255
+ const serializedRequest = await serializeRequest(event.request)
256
+ const clientMessage = await sendToClient(
257
+ client,
258
+ {
259
+ type: 'REQUEST',
260
+ payload: {
261
+ id: requestId,
262
+ interceptedAt: requestInterceptedAt,
263
+ ...serializedRequest,
264
+ },
265
+ },
266
+ [serializedRequest.body],
267
+ )
268
+
269
+ switch (clientMessage.type) {
270
+ case 'MOCK_RESPONSE': {
271
+ return respondWithMock(clientMessage.data)
272
+ }
273
+
274
+ case 'PASSTHROUGH': {
275
+ return passthrough()
276
+ }
277
+ }
278
+
279
+ return passthrough()
280
+ }
281
+
282
+ /**
283
+ * @param {Client} client
284
+ * @param {any} message
285
+ * @param {Array<Transferable>} transferrables
286
+ * @returns {Promise<any>}
287
+ */
288
+ function sendToClient(client, message, transferrables = []) {
289
+ return new Promise((resolve, reject) => {
290
+ const channel = new MessageChannel()
291
+
292
+ channel.port1.onmessage = (event) => {
293
+ if (event.data && event.data.error) {
294
+ return reject(event.data.error)
295
+ }
296
+
297
+ resolve(event.data)
298
+ }
299
+
300
+ client.postMessage(message, [
301
+ channel.port2,
302
+ ...transferrables.filter(Boolean),
303
+ ])
304
+ })
305
+ }
306
+
307
+ /**
308
+ * @param {Response} response
309
+ * @returns {Response}
310
+ */
311
+ function respondWithMock(response) {
312
+ // Setting response status code to 0 is a no-op.
313
+ // However, when responding with a "Response.error()", the produced Response
314
+ // instance will have status code set to 0. Since it's not possible to create
315
+ // a Response instance with status code 0, handle that use-case separately.
316
+ if (response.status === 0) {
317
+ return Response.error()
318
+ }
319
+
320
+ const mockedResponse = new Response(response.body, response)
321
+
322
+ Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
323
+ value: true,
324
+ enumerable: true,
325
+ })
326
+
327
+ return mockedResponse
328
+ }
329
+
330
+ /**
331
+ * @param {Request} request
332
+ */
333
+ async function serializeRequest(request) {
334
+ return {
335
+ url: request.url,
336
+ mode: request.mode,
337
+ method: request.method,
338
+ headers: Object.fromEntries(request.headers.entries()),
339
+ cache: request.cache,
340
+ credentials: request.credentials,
341
+ destination: request.destination,
342
+ integrity: request.integrity,
343
+ redirect: request.redirect,
344
+ referrer: request.referrer,
345
+ referrerPolicy: request.referrerPolicy,
346
+ body: await request.arrayBuffer(),
347
+ keepalive: request.keepalive,
348
+ }
349
+ }
@@ -0,0 +1,349 @@
1
+ /* eslint-disable */
2
+ /* tslint:disable */
3
+
4
+ /**
5
+ * Mock Service Worker.
6
+ * @see https://github.com/mswjs/msw
7
+ * - Please do NOT modify this file.
8
+ */
9
+
10
+ const PACKAGE_VERSION = '2.12.7'
11
+ const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'
12
+ const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
13
+ const activeClientIds = new Set()
14
+
15
+ addEventListener('install', function () {
16
+ self.skipWaiting()
17
+ })
18
+
19
+ addEventListener('activate', function (event) {
20
+ event.waitUntil(self.clients.claim())
21
+ })
22
+
23
+ addEventListener('message', async function (event) {
24
+ const clientId = Reflect.get(event.source || {}, 'id')
25
+
26
+ if (!clientId || !self.clients) {
27
+ return
28
+ }
29
+
30
+ const client = await self.clients.get(clientId)
31
+
32
+ if (!client) {
33
+ return
34
+ }
35
+
36
+ const allClients = await self.clients.matchAll({
37
+ type: 'window',
38
+ })
39
+
40
+ switch (event.data) {
41
+ case 'KEEPALIVE_REQUEST': {
42
+ sendToClient(client, {
43
+ type: 'KEEPALIVE_RESPONSE',
44
+ })
45
+ break
46
+ }
47
+
48
+ case 'INTEGRITY_CHECK_REQUEST': {
49
+ sendToClient(client, {
50
+ type: 'INTEGRITY_CHECK_RESPONSE',
51
+ payload: {
52
+ packageVersion: PACKAGE_VERSION,
53
+ checksum: INTEGRITY_CHECKSUM,
54
+ },
55
+ })
56
+ break
57
+ }
58
+
59
+ case 'MOCK_ACTIVATE': {
60
+ activeClientIds.add(clientId)
61
+
62
+ sendToClient(client, {
63
+ type: 'MOCKING_ENABLED',
64
+ payload: {
65
+ client: {
66
+ id: client.id,
67
+ frameType: client.frameType,
68
+ },
69
+ },
70
+ })
71
+ break
72
+ }
73
+
74
+ case 'CLIENT_CLOSED': {
75
+ activeClientIds.delete(clientId)
76
+
77
+ const remainingClients = allClients.filter((client) => {
78
+ return client.id !== clientId
79
+ })
80
+
81
+ // Unregister itself when there are no more clients
82
+ if (remainingClients.length === 0) {
83
+ self.registration.unregister()
84
+ }
85
+
86
+ break
87
+ }
88
+ }
89
+ })
90
+
91
+ addEventListener('fetch', function (event) {
92
+ const requestInterceptedAt = Date.now()
93
+
94
+ // Bypass navigation requests.
95
+ if (event.request.mode === 'navigate') {
96
+ return
97
+ }
98
+
99
+ // Opening the DevTools triggers the "only-if-cached" request
100
+ // that cannot be handled by the worker. Bypass such requests.
101
+ if (
102
+ event.request.cache === 'only-if-cached' &&
103
+ event.request.mode !== 'same-origin'
104
+ ) {
105
+ return
106
+ }
107
+
108
+ // Bypass all requests when there are no active clients.
109
+ // Prevents the self-unregistered worked from handling requests
110
+ // after it's been terminated (still remains active until the next reload).
111
+ if (activeClientIds.size === 0) {
112
+ return
113
+ }
114
+
115
+ const requestId = crypto.randomUUID()
116
+ event.respondWith(handleRequest(event, requestId, requestInterceptedAt))
117
+ })
118
+
119
+ /**
120
+ * @param {FetchEvent} event
121
+ * @param {string} requestId
122
+ * @param {number} requestInterceptedAt
123
+ */
124
+ async function handleRequest(event, requestId, requestInterceptedAt) {
125
+ const client = await resolveMainClient(event)
126
+ const requestCloneForEvents = event.request.clone()
127
+ const response = await getResponse(
128
+ event,
129
+ client,
130
+ requestId,
131
+ requestInterceptedAt,
132
+ )
133
+
134
+ // Send back the response clone for the "response:*" life-cycle events.
135
+ // Ensure MSW is active and ready to handle the message, otherwise
136
+ // this message will pend indefinitely.
137
+ if (client && activeClientIds.has(client.id)) {
138
+ const serializedRequest = await serializeRequest(requestCloneForEvents)
139
+
140
+ // Clone the response so both the client and the library could consume it.
141
+ const responseClone = response.clone()
142
+
143
+ sendToClient(
144
+ client,
145
+ {
146
+ type: 'RESPONSE',
147
+ payload: {
148
+ isMockedResponse: IS_MOCKED_RESPONSE in response,
149
+ request: {
150
+ id: requestId,
151
+ ...serializedRequest,
152
+ },
153
+ response: {
154
+ type: responseClone.type,
155
+ status: responseClone.status,
156
+ statusText: responseClone.statusText,
157
+ headers: Object.fromEntries(responseClone.headers.entries()),
158
+ body: responseClone.body,
159
+ },
160
+ },
161
+ },
162
+ responseClone.body ? [serializedRequest.body, responseClone.body] : [],
163
+ )
164
+ }
165
+
166
+ return response
167
+ }
168
+
169
+ /**
170
+ * Resolve the main client for the given event.
171
+ * Client that issues a request doesn't necessarily equal the client
172
+ * that registered the worker. It's with the latter the worker should
173
+ * communicate with during the response resolving phase.
174
+ * @param {FetchEvent} event
175
+ * @returns {Promise<Client | undefined>}
176
+ */
177
+ async function resolveMainClient(event) {
178
+ const client = await self.clients.get(event.clientId)
179
+
180
+ if (activeClientIds.has(event.clientId)) {
181
+ return client
182
+ }
183
+
184
+ if (client?.frameType === 'top-level') {
185
+ return client
186
+ }
187
+
188
+ const allClients = await self.clients.matchAll({
189
+ type: 'window',
190
+ })
191
+
192
+ return allClients
193
+ .filter((client) => {
194
+ // Get only those clients that are currently visible.
195
+ return client.visibilityState === 'visible'
196
+ })
197
+ .find((client) => {
198
+ // Find the client ID that's recorded in the
199
+ // set of clients that have registered the worker.
200
+ return activeClientIds.has(client.id)
201
+ })
202
+ }
203
+
204
+ /**
205
+ * @param {FetchEvent} event
206
+ * @param {Client | undefined} client
207
+ * @param {string} requestId
208
+ * @param {number} requestInterceptedAt
209
+ * @returns {Promise<Response>}
210
+ */
211
+ async function getResponse(event, client, requestId, requestInterceptedAt) {
212
+ // Clone the request because it might've been already used
213
+ // (i.e. its body has been read and sent to the client).
214
+ const requestClone = event.request.clone()
215
+
216
+ function passthrough() {
217
+ // Cast the request headers to a new Headers instance
218
+ // so the headers can be manipulated with.
219
+ const headers = new Headers(requestClone.headers)
220
+
221
+ // Remove the "accept" header value that marked this request as passthrough.
222
+ // This prevents request alteration and also keeps it compliant with the
223
+ // user-defined CORS policies.
224
+ const acceptHeader = headers.get('accept')
225
+ if (acceptHeader) {
226
+ const values = acceptHeader.split(',').map((value) => value.trim())
227
+ const filteredValues = values.filter(
228
+ (value) => value !== 'msw/passthrough',
229
+ )
230
+
231
+ if (filteredValues.length > 0) {
232
+ headers.set('accept', filteredValues.join(', '))
233
+ } else {
234
+ headers.delete('accept')
235
+ }
236
+ }
237
+
238
+ return fetch(requestClone, { headers })
239
+ }
240
+
241
+ // Bypass mocking when the client is not active.
242
+ if (!client) {
243
+ return passthrough()
244
+ }
245
+
246
+ // Bypass initial page load requests (i.e. static assets).
247
+ // The absence of the immediate/parent client in the map of the active clients
248
+ // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
249
+ // and is not ready to handle requests.
250
+ if (!activeClientIds.has(client.id)) {
251
+ return passthrough()
252
+ }
253
+
254
+ // Notify the client that a request has been intercepted.
255
+ const serializedRequest = await serializeRequest(event.request)
256
+ const clientMessage = await sendToClient(
257
+ client,
258
+ {
259
+ type: 'REQUEST',
260
+ payload: {
261
+ id: requestId,
262
+ interceptedAt: requestInterceptedAt,
263
+ ...serializedRequest,
264
+ },
265
+ },
266
+ [serializedRequest.body],
267
+ )
268
+
269
+ switch (clientMessage.type) {
270
+ case 'MOCK_RESPONSE': {
271
+ return respondWithMock(clientMessage.data)
272
+ }
273
+
274
+ case 'PASSTHROUGH': {
275
+ return passthrough()
276
+ }
277
+ }
278
+
279
+ return passthrough()
280
+ }
281
+
282
+ /**
283
+ * @param {Client} client
284
+ * @param {any} message
285
+ * @param {Array<Transferable>} transferrables
286
+ * @returns {Promise<any>}
287
+ */
288
+ function sendToClient(client, message, transferrables = []) {
289
+ return new Promise((resolve, reject) => {
290
+ const channel = new MessageChannel()
291
+
292
+ channel.port1.onmessage = (event) => {
293
+ if (event.data && event.data.error) {
294
+ return reject(event.data.error)
295
+ }
296
+
297
+ resolve(event.data)
298
+ }
299
+
300
+ client.postMessage(message, [
301
+ channel.port2,
302
+ ...transferrables.filter(Boolean),
303
+ ])
304
+ })
305
+ }
306
+
307
+ /**
308
+ * @param {Response} response
309
+ * @returns {Response}
310
+ */
311
+ function respondWithMock(response) {
312
+ // Setting response status code to 0 is a no-op.
313
+ // However, when responding with a "Response.error()", the produced Response
314
+ // instance will have status code set to 0. Since it's not possible to create
315
+ // a Response instance with status code 0, handle that use-case separately.
316
+ if (response.status === 0) {
317
+ return Response.error()
318
+ }
319
+
320
+ const mockedResponse = new Response(response.body, response)
321
+
322
+ Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
323
+ value: true,
324
+ enumerable: true,
325
+ })
326
+
327
+ return mockedResponse
328
+ }
329
+
330
+ /**
331
+ * @param {Request} request
332
+ */
333
+ async function serializeRequest(request) {
334
+ return {
335
+ url: request.url,
336
+ mode: request.mode,
337
+ method: request.method,
338
+ headers: Object.fromEntries(request.headers.entries()),
339
+ cache: request.cache,
340
+ credentials: request.credentials,
341
+ destination: request.destination,
342
+ integrity: request.integrity,
343
+ redirect: request.redirect,
344
+ referrer: request.referrer,
345
+ referrerPolicy: request.referrerPolicy,
346
+ body: await request.arrayBuffer(),
347
+ keepalive: request.keepalive,
348
+ }
349
+ }
@@ -0,0 +1,7 @@
1
+ # Robots.txt for Crownpeak DQM React Component Website
2
+
3
+ User-agent: *
4
+ Allow: /
5
+
6
+ # Sitemap
7
+ Sitemap: https://crownpeak.github.io/dqm-react-component/sitemap.xml
@@ -0,0 +1 @@
1
+ {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
+ <url>
4
+ <loc>https://crownpeak.github.io/dqm-react-component/</loc>
5
+ <lastmod>2026-01-08</lastmod>
6
+ <changefreq>weekly</changefreq>
7
+ <priority>1.0</priority>
8
+ </url>
9
+ </urlset>
@@ -0,0 +1,41 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": [
5
+ "dom",
6
+ "dom.iterable",
7
+ "esnext"
8
+ ],
9
+ "allowJs": true,
10
+ "skipLibCheck": true,
11
+ "strict": true,
12
+ "noEmit": true,
13
+ "esModuleInterop": true,
14
+ "module": "esnext",
15
+ "moduleResolution": "bundler",
16
+ "resolveJsonModule": true,
17
+ "isolatedModules": true,
18
+ "jsx": "react-jsx",
19
+ "incremental": true,
20
+ "plugins": [
21
+ {
22
+ "name": "next"
23
+ }
24
+ ],
25
+ "paths": {
26
+ "@/*": [
27
+ "./src/*"
28
+ ]
29
+ }
30
+ },
31
+ "include": [
32
+ "next-env.d.ts",
33
+ "**/*.ts",
34
+ "**/*.tsx",
35
+ ".next/types/**/*.ts",
36
+ ".next/dev/types/**/*.ts"
37
+ ],
38
+ "exclude": [
39
+ "node_modules"
40
+ ]
41
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crownpeak/dqm-react-component-dev-mcp",
3
- "version": "1.2.1",
3
+ "version": "1.2.4",
4
4
  "description": "MCP Server for Crownpeak DQM React Component documentation - powered by Probe",
5
5
  "author": "Crownpeak Technology GmbH",
6
6
  "license": "MIT",
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@probelabs/probe": "^0.6.0-rc128",
25
- "@modelcontextprotocol/sdk": "^1.6.0",
25
+ "@modelcontextprotocol/sdk": "^1.25.2",
26
26
  "axios": "^1.6.0",
27
27
  "fs-extra": "^11.2.0",
28
28
  "glob": "^10.3.0",