diff --git a/angular.json b/angular.json
index 9746bdb..616a8d7 100644
--- a/angular.json
+++ b/angular.json
@@ -53,7 +53,8 @@
"node_modules/datatables.net-buttons/js/buttons.html5.js",
"node_modules/datatables.net-buttons/js/buttons.print.min.js",
"node_modules/datatables.net-select/js/dataTables.select.min.js",
- "node_modules/datatables.net-fixedheader/js/dataTables.fixedHeader.js"
+ "node_modules/datatables.net-fixedheader/js/dataTables.fixedHeader.js",
+ "node_modules/mermaid/dist/mermaid.min.js"
],
"allowedCommonJsDependencies": [
"jsvectormap/dist/maps/world-merc.js",
diff --git a/package-lock.json b/package-lock.json
index 38b45b5..458daa3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -53,6 +53,7 @@
"keycloak-js": "^26.2.1",
"leaflet": "^1.9.4",
"lodash-es": "^4.17.21",
+ "mermaid": "^11.12.2",
"ng-otp-input": "^2.0.9",
"ng2-charts": "^8.0.0",
"ngx-countup": "^13.2.0",
@@ -1246,6 +1247,19 @@
"rxjs": "^6.5.3 || ^7.4.0"
}
},
+ "node_modules/@antfu/install-pkg": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz",
+ "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==",
+ "license": "MIT",
+ "dependencies": {
+ "package-manager-detector": "^1.3.0",
+ "tinyexec": "^1.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
"node_modules/@babel/code-frame": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
@@ -1534,6 +1548,51 @@
"leaflet": "1"
}
},
+ "node_modules/@braintree/sanitize-url": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.1.tgz",
+ "integrity": "sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==",
+ "license": "MIT"
+ },
+ "node_modules/@chevrotain/cst-dts-gen": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz",
+ "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@chevrotain/gast": "11.0.3",
+ "@chevrotain/types": "11.0.3",
+ "lodash-es": "4.17.21"
+ }
+ },
+ "node_modules/@chevrotain/gast": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz",
+ "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@chevrotain/types": "11.0.3",
+ "lodash-es": "4.17.21"
+ }
+ },
+ "node_modules/@chevrotain/regexp-to-ast": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz",
+ "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@chevrotain/types": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz",
+ "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@chevrotain/utils": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz",
+ "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==",
+ "license": "Apache-2.0"
+ },
"node_modules/@colors/colors": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
@@ -2022,6 +2081,23 @@
"@fullcalendar/core": "~6.1.19"
}
},
+ "node_modules/@iconify/types": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
+ "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
+ "license": "MIT"
+ },
+ "node_modules/@iconify/utils": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz",
+ "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==",
+ "license": "MIT",
+ "dependencies": {
+ "@antfu/install-pkg": "^1.1.0",
+ "@iconify/types": "^2.0.0",
+ "mlly": "^1.8.0"
+ }
+ },
"node_modules/@inquirer/ansi": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz",
@@ -2635,6 +2711,15 @@
"win32"
]
},
+ "node_modules/@mermaid-js/parser": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.6.3.tgz",
+ "integrity": "sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==",
+ "license": "MIT",
+ "dependencies": {
+ "langium": "3.3.1"
+ }
+ },
"node_modules/@modelcontextprotocol/sdk": {
"version": "1.17.3",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.3.tgz",
@@ -4301,6 +4386,259 @@
"@types/node": "*"
}
},
+ "node_modules/@types/d3": {
+ "version": "7.4.3",
+ "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz",
+ "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-array": "*",
+ "@types/d3-axis": "*",
+ "@types/d3-brush": "*",
+ "@types/d3-chord": "*",
+ "@types/d3-color": "*",
+ "@types/d3-contour": "*",
+ "@types/d3-delaunay": "*",
+ "@types/d3-dispatch": "*",
+ "@types/d3-drag": "*",
+ "@types/d3-dsv": "*",
+ "@types/d3-ease": "*",
+ "@types/d3-fetch": "*",
+ "@types/d3-force": "*",
+ "@types/d3-format": "*",
+ "@types/d3-geo": "*",
+ "@types/d3-hierarchy": "*",
+ "@types/d3-interpolate": "*",
+ "@types/d3-path": "*",
+ "@types/d3-polygon": "*",
+ "@types/d3-quadtree": "*",
+ "@types/d3-random": "*",
+ "@types/d3-scale": "*",
+ "@types/d3-scale-chromatic": "*",
+ "@types/d3-selection": "*",
+ "@types/d3-shape": "*",
+ "@types/d3-time": "*",
+ "@types/d3-time-format": "*",
+ "@types/d3-timer": "*",
+ "@types/d3-transition": "*",
+ "@types/d3-zoom": "*"
+ }
+ },
+ "node_modules/@types/d3-array": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
+ "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-axis": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz",
+ "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/d3-brush": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz",
+ "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/d3-chord": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz",
+ "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-color": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
+ "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-contour": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz",
+ "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-array": "*",
+ "@types/geojson": "*"
+ }
+ },
+ "node_modules/@types/d3-delaunay": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
+ "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-dispatch": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz",
+ "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-drag": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz",
+ "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/d3-dsv": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz",
+ "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-ease": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
+ "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-fetch": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz",
+ "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-dsv": "*"
+ }
+ },
+ "node_modules/@types/d3-force": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz",
+ "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-format": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz",
+ "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-geo": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz",
+ "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/geojson": "*"
+ }
+ },
+ "node_modules/@types/d3-hierarchy": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz",
+ "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-interpolate": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
+ "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-color": "*"
+ }
+ },
+ "node_modules/@types/d3-path": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
+ "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-polygon": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz",
+ "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-quadtree": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz",
+ "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-random": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz",
+ "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-scale": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
+ "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-time": "*"
+ }
+ },
+ "node_modules/@types/d3-scale-chromatic": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
+ "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-selection": {
+ "version": "3.0.11",
+ "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz",
+ "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-shape": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz",
+ "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-path": "*"
+ }
+ },
+ "node_modules/@types/d3-time": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
+ "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-time-format": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz",
+ "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-timer": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
+ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-transition": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz",
+ "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/d3-zoom": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz",
+ "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-interpolate": "*",
+ "@types/d3-selection": "*"
+ }
+ },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -4312,7 +4650,6 @@
"version": "7946.0.16",
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
"integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
- "dev": true,
"license": "MIT"
},
"node_modules/@types/jasmine": {
@@ -4376,6 +4713,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/@types/validator": {
"version": "13.15.4",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.4.tgz",
@@ -4426,6 +4770,18 @@
"node": ">= 0.6"
}
},
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/agent-base": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
@@ -4988,6 +5344,32 @@
"pnpm": ">=8"
}
},
+ "node_modules/chevrotain": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz",
+ "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@chevrotain/cst-dts-gen": "11.0.3",
+ "@chevrotain/gast": "11.0.3",
+ "@chevrotain/regexp-to-ast": "11.0.3",
+ "@chevrotain/types": "11.0.3",
+ "@chevrotain/utils": "11.0.3",
+ "lodash-es": "4.17.21"
+ }
+ },
+ "node_modules/chevrotain-allstar": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz",
+ "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==",
+ "license": "MIT",
+ "dependencies": {
+ "lodash-es": "^4.17.21"
+ },
+ "peerDependencies": {
+ "chevrotain": "^11.0.0"
+ }
+ },
"node_modules/choices.js": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/choices.js/-/choices.js-11.1.0.tgz",
@@ -5148,6 +5530,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/commander": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -5155,6 +5546,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/confbox": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
+ "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
+ "license": "MIT"
+ },
"node_modules/connect": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
@@ -5310,6 +5707,15 @@
"node": ">= 0.10"
}
},
+ "node_modules/cose-base": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz",
+ "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==",
+ "license": "MIT",
+ "dependencies": {
+ "layout-base": "^1.0.0"
+ }
+ },
"node_modules/countup.js": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.9.0.tgz",
@@ -5368,6 +5774,517 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/cytoscape": {
+ "version": "3.33.1",
+ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz",
+ "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/cytoscape-cose-bilkent": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz",
+ "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cose-base": "^1.0.0"
+ },
+ "peerDependencies": {
+ "cytoscape": "^3.2.0"
+ }
+ },
+ "node_modules/cytoscape-fcose": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz",
+ "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cose-base": "^2.2.0"
+ },
+ "peerDependencies": {
+ "cytoscape": "^3.2.0"
+ }
+ },
+ "node_modules/cytoscape-fcose/node_modules/cose-base": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz",
+ "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==",
+ "license": "MIT",
+ "dependencies": {
+ "layout-base": "^2.0.0"
+ }
+ },
+ "node_modules/cytoscape-fcose/node_modules/layout-base": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz",
+ "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==",
+ "license": "MIT"
+ },
+ "node_modules/d3": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz",
+ "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "3",
+ "d3-axis": "3",
+ "d3-brush": "3",
+ "d3-chord": "3",
+ "d3-color": "3",
+ "d3-contour": "4",
+ "d3-delaunay": "6",
+ "d3-dispatch": "3",
+ "d3-drag": "3",
+ "d3-dsv": "3",
+ "d3-ease": "3",
+ "d3-fetch": "3",
+ "d3-force": "3",
+ "d3-format": "3",
+ "d3-geo": "3",
+ "d3-hierarchy": "3",
+ "d3-interpolate": "3",
+ "d3-path": "3",
+ "d3-polygon": "3",
+ "d3-quadtree": "3",
+ "d3-random": "3",
+ "d3-scale": "4",
+ "d3-scale-chromatic": "3",
+ "d3-selection": "3",
+ "d3-shape": "3",
+ "d3-time": "3",
+ "d3-time-format": "4",
+ "d3-timer": "3",
+ "d3-transition": "3",
+ "d3-zoom": "3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-array": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
+ "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
+ "license": "ISC",
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-axis": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
+ "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-brush": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
+ "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-drag": "2 - 3",
+ "d3-interpolate": "1 - 3",
+ "d3-selection": "3",
+ "d3-transition": "3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-chord": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
+ "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-path": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-color": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-contour": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz",
+ "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "^3.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-delaunay": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
+ "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
+ "license": "ISC",
+ "dependencies": {
+ "delaunator": "5"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-dispatch": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
+ "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-drag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
+ "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-selection": "3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-dsv": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
+ "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
+ "license": "ISC",
+ "dependencies": {
+ "commander": "7",
+ "iconv-lite": "0.6",
+ "rw": "1"
+ },
+ "bin": {
+ "csv2json": "bin/dsv2json.js",
+ "csv2tsv": "bin/dsv2dsv.js",
+ "dsv2dsv": "bin/dsv2dsv.js",
+ "dsv2json": "bin/dsv2json.js",
+ "json2csv": "bin/json2dsv.js",
+ "json2dsv": "bin/json2dsv.js",
+ "json2tsv": "bin/json2dsv.js",
+ "tsv2csv": "bin/dsv2dsv.js",
+ "tsv2json": "bin/dsv2json.js"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-dsv/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/d3-ease": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
+ "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-fetch": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
+ "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dsv": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-force": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
+ "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-quadtree": "1 - 3",
+ "d3-timer": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-format": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
+ "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-geo": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz",
+ "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2.5.0 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-hierarchy": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
+ "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-interpolate": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-path": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
+ "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-polygon": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
+ "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-quadtree": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
+ "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-random": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
+ "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-sankey": {
+ "version": "0.12.3",
+ "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz",
+ "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "d3-array": "1 - 2",
+ "d3-shape": "^1.2.0"
+ }
+ },
+ "node_modules/d3-sankey/node_modules/d3-array": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
+ "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "internmap": "^1.0.0"
+ }
+ },
+ "node_modules/d3-sankey/node_modules/d3-path": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
+ "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/d3-sankey/node_modules/d3-shape": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
+ "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "d3-path": "1"
+ }
+ },
+ "node_modules/d3-sankey/node_modules/internmap": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
+ "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==",
+ "license": "ISC"
+ },
+ "node_modules/d3-scale": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2.10.0 - 3",
+ "d3-format": "1 - 3",
+ "d3-interpolate": "1.2.0 - 3",
+ "d3-time": "2.1.1 - 3",
+ "d3-time-format": "2 - 4"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-scale-chromatic": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
+ "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3",
+ "d3-interpolate": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-selection": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
+ "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-shape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
+ "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-path": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time-format": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-time": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-timer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-transition": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
+ "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3",
+ "d3-dispatch": "1 - 3",
+ "d3-ease": "1 - 3",
+ "d3-interpolate": "1 - 3",
+ "d3-timer": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "d3-selection": "2 - 3"
+ }
+ },
+ "node_modules/d3-zoom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
+ "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-drag": "2 - 3",
+ "d3-interpolate": "1 - 3",
+ "d3-selection": "2 - 3",
+ "d3-transition": "2 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/dagre-d3-es": {
+ "version": "7.0.13",
+ "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz",
+ "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "d3": "^7.9.0",
+ "lodash-es": "^4.17.21"
+ }
+ },
"node_modules/datatables": {
"version": "1.10.18",
"resolved": "https://registry.npmjs.org/datatables/-/datatables-1.10.18.tgz",
@@ -5511,6 +6428,12 @@
"node": ">=4.0"
}
},
+ "node_modules/dayjs": {
+ "version": "1.11.19",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
+ "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
+ "license": "MIT"
+ },
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@@ -5528,6 +6451,15 @@
}
}
},
+ "node_modules/delaunator": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
+ "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
+ "license": "ISC",
+ "dependencies": {
+ "robust-predicates": "^3.0.2"
+ }
+ },
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -5624,6 +6556,15 @@
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
+ "node_modules/dompurify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz",
+ "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==",
+ "license": "(MPL-2.0 OR Apache-2.0)",
+ "optionalDependencies": {
+ "@types/trusted-types": "^2.0.7"
+ }
+ },
"node_modules/domutils": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
@@ -6435,6 +7376,12 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/hachure-fill": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz",
+ "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==",
+ "license": "MIT"
+ },
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -6724,6 +7671,15 @@
"node": "^18.17.0 || >=20.5.0"
}
},
+ "node_modules/internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/ip-address": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz",
@@ -7575,6 +8531,31 @@
"node": ">=10"
}
},
+ "node_modules/katex": {
+ "version": "0.16.27",
+ "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.27.tgz",
+ "integrity": "sha512-aeQoDkuRWSqQN6nSvVCEFvfXdqo1OQiCmmW1kc9xSdjutPv7BGO7pqY9sQRJpMOGrEdfDgF2TfRXe5eUAD2Waw==",
+ "funding": [
+ "https://opencollective.com/katex",
+ "https://github.com/sponsors/katex"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^8.3.0"
+ },
+ "bin": {
+ "katex": "cli.js"
+ }
+ },
+ "node_modules/katex/node_modules/commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/keycloak-angular": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/keycloak-angular/-/keycloak-angular-20.0.0.tgz",
@@ -7600,6 +8581,33 @@
"test"
]
},
+ "node_modules/khroma": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz",
+ "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="
+ },
+ "node_modules/langium": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz",
+ "integrity": "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==",
+ "license": "MIT",
+ "dependencies": {
+ "chevrotain": "~11.0.3",
+ "chevrotain-allstar": "~0.3.0",
+ "vscode-languageserver": "~9.0.1",
+ "vscode-languageserver-textdocument": "~1.0.11",
+ "vscode-uri": "~3.0.8"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/layout-base": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz",
+ "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==",
+ "license": "MIT"
+ },
"node_modules/leaflet": {
"version": "1.9.4",
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
@@ -7893,6 +8901,18 @@
"node": "^18.17.0 || >=20.5.0"
}
},
+ "node_modules/marked": {
+ "version": "16.4.2",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz",
+ "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==",
+ "license": "MIT",
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -7926,6 +8946,34 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/mermaid": {
+ "version": "11.12.2",
+ "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.2.tgz",
+ "integrity": "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==",
+ "license": "MIT",
+ "dependencies": {
+ "@braintree/sanitize-url": "^7.1.1",
+ "@iconify/utils": "^3.0.1",
+ "@mermaid-js/parser": "^0.6.3",
+ "@types/d3": "^7.4.3",
+ "cytoscape": "^3.29.3",
+ "cytoscape-cose-bilkent": "^4.1.0",
+ "cytoscape-fcose": "^2.2.0",
+ "d3": "^7.9.0",
+ "d3-sankey": "^0.12.3",
+ "dagre-d3-es": "7.0.13",
+ "dayjs": "^1.11.18",
+ "dompurify": "^3.2.5",
+ "katex": "^0.16.22",
+ "khroma": "^2.1.0",
+ "lodash-es": "^4.17.21",
+ "marked": "^16.2.1",
+ "roughjs": "^4.6.6",
+ "stylis": "^4.3.6",
+ "ts-dedent": "^2.2.0",
+ "uuid": "^11.1.0"
+ }
+ },
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
@@ -8193,6 +9241,18 @@
"mkdirp": "bin/cmd.js"
}
},
+ "node_modules/mlly": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz",
+ "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==",
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.15.0",
+ "pathe": "^2.0.3",
+ "pkg-types": "^1.3.1",
+ "ufo": "^1.6.1"
+ }
+ },
"node_modules/mrmime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
@@ -8817,6 +9877,12 @@
"dev": true,
"license": "BlueOak-1.0.0"
},
+ "node_modules/package-manager-detector": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz",
+ "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==",
+ "license": "MIT"
+ },
"node_modules/pacote": {
"version": "21.0.0",
"resolved": "https://registry.npmjs.org/pacote/-/pacote-21.0.0.tgz",
@@ -8974,6 +10040,12 @@
"node": ">= 0.8"
}
},
+ "node_modules/path-data-parser": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz",
+ "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==",
+ "license": "MIT"
+ },
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -9036,6 +10108,12 @@
"url": "https://opencollective.com/express"
}
},
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "license": "MIT"
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -9077,6 +10155,33 @@
"node": ">=16.20.0"
}
},
+ "node_modules/pkg-types": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz",
+ "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
+ "license": "MIT",
+ "dependencies": {
+ "confbox": "^0.1.8",
+ "mlly": "^1.7.4",
+ "pathe": "^2.0.1"
+ }
+ },
+ "node_modules/points-on-curve": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz",
+ "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==",
+ "license": "MIT"
+ },
+ "node_modules/points-on-path": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz",
+ "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==",
+ "license": "MIT",
+ "dependencies": {
+ "path-data-parser": "0.1.0",
+ "points-on-curve": "0.2.0"
+ }
+ },
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
@@ -9417,6 +10522,12 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/robust-predicates": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
+ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==",
+ "license": "Unlicense"
+ },
"node_modules/rollup": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.3.tgz",
@@ -9459,6 +10570,18 @@
"fsevents": "~2.3.2"
}
},
+ "node_modules/roughjs": {
+ "version": "4.6.6",
+ "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz",
+ "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "hachure-fill": "^0.5.2",
+ "path-data-parser": "^0.1.0",
+ "points-on-curve": "^0.2.0",
+ "points-on-path": "^0.2.1"
+ }
+ },
"node_modules/router": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
@@ -9476,6 +10599,12 @@
"node": ">= 18"
}
},
+ "node_modules/rw": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+ "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
@@ -9528,7 +10657,6 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true,
"license": "MIT"
},
"node_modules/sass": {
@@ -10229,6 +11357,12 @@
"node": ">=8"
}
},
+ "node_modules/stylis": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz",
+ "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==",
+ "license": "MIT"
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -10356,6 +11490,15 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/tinyexec": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz",
+ "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/tinyglobby": {
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
@@ -10405,6 +11548,15 @@
"node": ">=0.6"
}
},
+ "node_modules/ts-dedent": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz",
+ "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.10"
+ }
+ },
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
@@ -10482,6 +11634,12 @@
"node": "*"
}
},
+ "node_modules/ufo": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz",
+ "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==",
+ "license": "MIT"
+ },
"node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
@@ -10601,6 +11759,19 @@
"node": ">= 0.4.0"
}
},
+ "node_modules/uuid": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
+ "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/esm/bin/uuid"
+ }
+ },
"node_modules/validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@@ -10743,6 +11914,55 @@
"node": ">=0.10.0"
}
},
+ "node_modules/vscode-jsonrpc": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
+ "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/vscode-languageserver": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz",
+ "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==",
+ "license": "MIT",
+ "dependencies": {
+ "vscode-languageserver-protocol": "3.17.5"
+ },
+ "bin": {
+ "installServerIntoExtension": "bin/installServerIntoExtension"
+ }
+ },
+ "node_modules/vscode-languageserver-protocol": {
+ "version": "3.17.5",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
+ "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
+ "license": "MIT",
+ "dependencies": {
+ "vscode-jsonrpc": "8.2.0",
+ "vscode-languageserver-types": "3.17.5"
+ }
+ },
+ "node_modules/vscode-languageserver-textdocument": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz",
+ "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==",
+ "license": "MIT"
+ },
+ "node_modules/vscode-languageserver-types": {
+ "version": "3.17.5",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
+ "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==",
+ "license": "MIT"
+ },
+ "node_modules/vscode-uri": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz",
+ "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==",
+ "license": "MIT"
+ },
"node_modules/watchpack": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
diff --git a/package.json b/package.json
index e2aad41..948bf66 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,7 @@
"keycloak-js": "^26.2.1",
"leaflet": "^1.9.4",
"lodash-es": "^4.17.21",
+ "mermaid": "^11.12.2",
"ng-otp-input": "^2.0.9",
"ng2-charts": "^8.0.0",
"ngx-countup": "^13.2.0",
diff --git a/src/app/modules/documentation/documentation.html b/src/app/modules/documentation/documentation.html
index 3fd0888..91dce45 100644
--- a/src/app/modules/documentation/documentation.html
+++ b/src/app/modules/documentation/documentation.html
@@ -1 +1,785 @@
-
Documentation
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @if (activeSection() === 'overview') {
+
+
+
+ @for (feature of features; track feature.title) {
+
+
+
+
+
{{ feature.title }}
+
{{ feature.desc }}
+
+ }
+
+
+
+
+
+
+ Configuration Requise
+
+
+
+
Headers Obligatoires
+
+
+
X-Merchant-ID: votre-merchant-id
+X-API-Key: votre-api-key
+X-COUNTRY: CI (Côte d'Ivoire), SN (Sénégal), etc.
+X-OPERATOR: ORANGE, MTN, AIRTEL
+
+
+
+
Environnements
+
+
+
+
+
Sandbox
+
https://sandbox.dcb-hub.pixpay.sn/api/v1
+
+
+
+
+
+
Production
+
https://api.dcb-hub.pixpay.sn/api/v1
+
+
+
+
+
+
+
+ }
+
+
+ @if (activeSection() === 'flow') {
+
+
+
+
+
+
+
+
Phase 1-2
+
Authentification
+
OTP Challenge & Validation
+
+
+
Phase 3-4
+
Souscription
+
Création abonnement & Webhook
+
+
+
Phase 5-6
+
Facturation
+
Charge & SMS confirmation
+
+
+
+ }
+
+
+ @if (activeSection() === 'steps') {
+
+ @for (step of steps; track step.id) {
+
+
+
+ @if (step.isOpen) {
+
+ @if (step.endpoint) {
+
+
+ {{ step.endpoint.method }}
+
+ {{ step.endpoint.path }}
+
+ }
+
+ @if (step.headers) {
+
+ }
+
+ @if (step.requestBody) {
+
+
+
{{ step.requestBody }}
+
+ }
+
+ @if (step.responseBody) {
+
+
+
{{ step.responseBody }}
+
+ }
+
+ @if (step.note) {
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+ @if (activeSection() === 'api') {
+
+
+
+ @for (tab of apiTabs; track tab.id) {
+
+ }
+
+
+
+ @if (activeApiTab() === 'otp') {
+
+
+
+
+ OTP Challenge Endpoints
+
+
+
+
+
+ POST
+ /api/v1/otp-challenge/initiate
+
+
Initie un challenge OTP pour authentifier l'utilisateur
+
+
+
Paramètres
+
+
+ | msisdn | string, required |
+ | channel | SMS | USSD | IVR |
+ | serviceId | string |
+
+
+
+
+
Headers
+
+
+ | X-Merchant-ID | required |
+ | X-API-Key | required |
+
+
+
+
+
+
+
+
+ POST
+ /api/v1/otp-challenge/{challengeId}/verify
+
+
Vérifie le code OTP entré par l'utilisateur
+
+
+
Path Parameters
+
+
+ | challengeId | string, required |
+
+
+
+
+
Responses
+
+
+ 200
+ Code validé
+
+
+ 400
+ Code invalide
+
+
+ 404
+ Challenge non trouvé
+
+
+
+
+
+
+
+
+ }
+
+
+ @if (activeApiTab() === 'subscriptions') {
+
+
+
+
+ Subscriptions Endpoints
+
+
+
+
+
+ POST
+ /api/v1/subscriptions
+
+
Créer une nouvelle souscription
+
+
+
+
+ GET
+ /api/v1/subscriptions
+
+
Liste des souscriptions avec pagination et filtres
+
+ page
+ limit
+ status
+ periodicity
+ serviceId
+ merchantPartnerId
+
+
+
+
+
+ GET
+ /api/v1/subscriptions/{id}
+
+
Détails d'une souscription
+
+
+
+
+ DELETE
+ /api/v1/subscriptions/{id}
+
+
Annuler une souscription
+
+
+
+
+
Statuts possibles
+
+ @for (status of subscriptionStatuses; track status) {
+ {{ status }}
+ }
+
+
+
+
+ }
+
+
+ @if (activeApiTab() === 'payments') {
+
+
+
+
+ Payments Endpoints
+
+
+
+
+
+ POST
+ /api/v1/payments/charge
+
+
Créer une nouvelle charge
+
+
+
+
interface ChargeDto {
+ userToken: string; // ISE2 token from OTP validation
+ amount: number; // Amount to charge
+ currency: string; // XOF, XAF, USD, EUR
+ description: string; // Payment description
+ reference?: string; // Unique payment reference
+ subscriptionId?: number;
+ callbackUrl?: string;
+ metadata?: Record<string, any>;
+}
+
+
+
+
+
+ GET
+ /api/v1/payments
+
+
Liste des paiements avec filtres avancés
+
+
+
Pagination
+
+ - page (default: 1)
+ - limit (max: 100)
+ - sortBy, sortOrder
+
+
+
+
Filtres
+
+ - type: MM, BANK, CHEQUE
+ - status: SUCCESS, FAILED, PENDING
+ - currency, amountMin, amountMax
+
+
+
+
Dates
+
+ - createdFrom, createdTo
+ - completedFrom, completedTo
+
+
+
+
+
+
+
+ GET
+ /api/v1/payments/{paymentId}
+
+
Détails d'un paiement par ID
+
+
+
+
+ POST
+ /api/v1/payments/{paymentId}/refund
+
+
Rembourser un paiement (total ou partiel)
+
+
+
+
+ POST
+ /api/v1/payments/{paymentId}/retry
+
+
Réessayer un paiement échoué
+
+
+
+
+ }
+
+
+ @if (activeApiTab() === 'operators') {
+
+
+
+
+ Operators Endpoints
+
+
+
+
+
+ GET
+ /api/v1/operators
+
+
Liste des opérateurs disponibles
+
+ operatorCode
+ period
+ startDate
+ endDate
+ active
+ country
+
+
+
+
+
+ GET
+ /api/v1/operators/{operatorCode}/health
+
+
Métriques de santé d'un opérateur
+
+
+
+
+ GET
+ /api/v1/operators/detect/{msisdn}
+
+
Détection automatique de l'opérateur à partir du MSISDN
+
+
+
+
+
+
interface OperatorResponseDto {
+ id: string;
+ code: string; // ORANGE, MTN, AIRTEL, etc.
+ name: string; // Nom complet
+ country: string; // CI, SN, CM, CD, etc.
+ active: boolean;
+ features: {
+ otp: boolean;
+ subscription: boolean;
+ oneTimePayment: boolean;
+ refund: boolean;
+ };
+}
+
+
+
+ }
+
+
+ @if (activeApiTab() === 'swagger') {
+
+
+
+
+
+
+
+
+
+
+ @if (selectedSwaggerEndpoint(); as endpoint) {
+
+
+
+
{{ endpoint.summary }}
+ @if (endpoint.description) {
+
{{ endpoint.description }}
+ }
+
+
+ @if (endpoint.parameters && endpoint.parameters.length > 0) {
+
+
Paramètres
+
+ @if (getParametersByLocation(endpoint.parameters, 'path').length > 0) {
+
+
Path Parameters
+
+ @for (param of getParametersByLocation(endpoint.parameters, 'path'); track param.name) {
+
+
+ {{ param.name }}
+ @if (param.required) {
+ required
+ }
+
+
{{ param.schema?.type || 'string' }}
+ @if (param.description) {
+
{{ param.description }}
+ }
+
+ }
+
+
+ }
+
+ @if (getParametersByLocation(endpoint.parameters, 'query').length > 0) {
+
+
Query Parameters
+
+ @for (param of getParametersByLocation(endpoint.parameters, 'query'); track param.name) {
+
+
+ {{ param.name }}
+ @if (param.required) {
+ required
+ }
+
+
+ {{ param.schema?.type || 'string' }}
+ @if (param.schema?.enum) {
+ enum: {{ param.schema.enum.join(', ') }}
+ }
+
+ @if (param.description) {
+
{{ param.description }}
+ }
+
+ }
+
+
+ }
+
+ @if (getParametersByLocation(endpoint.parameters, 'header').length > 0) {
+
+
Header Parameters
+
+ @for (param of getParametersByLocation(endpoint.parameters, 'header'); track param.name) {
+
+
+ {{ param.name }}
+ @if (param.required) {
+ required
+ }
+
+
{{ param.schema?.type || 'string' }}
+ @if (param.description) {
+
{{ param.description }}
+ }
+
+ }
+
+
+ }
+
+ }
+
+
+ @if (endpoint.requestBody) {
+
+
Request Body
+
+
+
{{ formatJson(endpoint.requestBody) }}
+
+
+ }
+
+
+ @if (endpoint.responses) {
+
+
Responses
+
+ @for (response of endpoint.responses | keyvalue; track response.key) {
+
+ {{ response.key }}
+ {{ $any(response.value).description }}
+
+
+
+ }
+
+
+ }
+
+
+ @if (endpoint.security && endpoint.security.length > 0) {
+
+
+
+ Authentification requise
+
+
+
+ Bearer Token (JWT)
+
+
+ }
+
+ } @else {
+
+
+
Sélectionnez un endpoint pour voir les détails
+
+ }
+
+
+
+ }
+
+ }
+
+
+
+
+
+
diff --git a/src/app/modules/documentation/documentation.scss b/src/app/modules/documentation/documentation.scss
new file mode 100644
index 0000000..adf76af
--- /dev/null
+++ b/src/app/modules/documentation/documentation.scss
@@ -0,0 +1,1504 @@
+// Variables - Light Theme
+$bg-primary: #ffffff;
+$bg-secondary: #f8fafc;
+$bg-card: #ffffff;
+$bg-hover: #f1f5f9;
+$border-color: #e2e8f0;
+$text-primary: #1e293b;
+$text-secondary: #475569;
+$text-muted: #94a3b8;
+
+$indigo: #6366f1;
+$green: #22c55e;
+$blue: #3b82f6;
+$purple: #a855f7;
+$orange: #f97316;
+$pink: #ec4899;
+$amber: #f59e0b;
+$red: #ef4444;
+
+// Animations
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.animate-fadeIn {
+ animation: fadeIn 0.3s ease-out;
+}
+
+// Container
+.documentation-container {
+ min-height: 100vh;
+ background: linear-gradient(135deg, $bg-secondary 0%, $bg-primary 50%, $bg-secondary 100%);
+ color: $text-primary;
+ position: relative;
+ overflow: hidden;
+}
+
+// Background Effects
+.bg-effects {
+ position: fixed;
+ inset: 0;
+ overflow: hidden;
+ pointer-events: none;
+ z-index: 0;
+}
+
+.bg-blob {
+ position: absolute;
+ border-radius: 50%;
+ filter: blur(100px);
+ opacity: 0.5;
+
+ &.bg-blob-1 {
+ top: -10%;
+ left: 20%;
+ width: 30rem;
+ height: 30rem;
+ background: rgba($indigo, 0.08);
+ }
+
+ &.bg-blob-2 {
+ bottom: -10%;
+ right: 20%;
+ width: 30rem;
+ height: 30rem;
+ background: rgba($purple, 0.08);
+ }
+}
+
+.content-wrapper {
+ position: relative;
+ z-index: 10;
+ max-width: 80rem;
+ margin: 0 auto;
+ padding: 2rem 1.5rem;
+}
+
+// Header
+.doc-header {
+ text-align: center;
+ margin-bottom: 3rem;
+}
+
+.version-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 1rem;
+ border-radius: 9999px;
+ background: rgba($indigo, 0.1);
+ border: 1px solid rgba($indigo, 0.2);
+ margin-bottom: 1.5rem;
+
+ ng-icon {
+ color: $indigo;
+ }
+
+ span {
+ font-size: 0.875rem;
+ font-weight: 500;
+ color: $indigo;
+ }
+}
+
+.doc-title {
+ font-size: 2.5rem;
+ font-weight: 700;
+ margin-bottom: 1rem;
+ background: linear-gradient(135deg, $text-primary, $indigo);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+
+ @media (min-width: 768px) {
+ font-size: 3rem;
+ }
+}
+
+.doc-subtitle {
+ font-size: 1.125rem;
+ color: $text-secondary;
+ max-width: 42rem;
+ margin: 0 auto;
+}
+
+// Navigation
+.doc-nav {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 0.5rem;
+ margin-bottom: 3rem;
+}
+
+.nav-btn {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.75rem 1.25rem;
+ border-radius: 0.75rem;
+ font-size: 0.875rem;
+ font-weight: 500;
+ border: 1px solid $border-color;
+ background: $bg-card;
+ color: $text-secondary;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+
+ &:hover {
+ color: $text-primary;
+ background: $bg-hover;
+ border-color: darken($border-color, 5%);
+ }
+
+ &.active {
+ background: linear-gradient(135deg, $indigo, $purple);
+ color: white;
+ border-color: transparent;
+ box-shadow: 0 4px 15px rgba($indigo, 0.3);
+ }
+}
+
+// Sections Container
+.sections-container {
+ margin-bottom: 2rem;
+}
+
+// Feature Grid
+.feature-grid {
+ display: grid;
+ grid-template-columns: repeat(1, 1fr);
+ gap: 1rem;
+ margin-bottom: 2rem;
+
+ @media (min-width: 768px) {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ @media (min-width: 1024px) {
+ grid-template-columns: repeat(4, 1fr);
+ }
+}
+
+.feature-card {
+ padding: 1.5rem;
+ border-radius: 1rem;
+ background: $bg-card;
+ border: 1px solid $border-color;
+ transition: all 0.3s ease;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+
+ &:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
+
+ .feature-icon {
+ transform: scale(1.1);
+ }
+ }
+
+ &.feature-indigo:hover {
+ border-color: rgba($indigo, 0.3);
+ }
+
+ &.feature-green:hover {
+ border-color: rgba($green, 0.3);
+ }
+
+ &.feature-blue:hover {
+ border-color: rgba($blue, 0.3);
+ }
+
+ &.feature-purple:hover {
+ border-color: rgba($purple, 0.3);
+ }
+}
+
+.feature-icon {
+ width: 3rem;
+ height: 3rem;
+ border-radius: 0.75rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 1rem;
+ transition: transform 0.3s ease;
+
+ &.icon-indigo {
+ background: rgba($indigo, 0.1);
+ color: $indigo;
+ }
+
+ &.icon-green {
+ background: rgba($green, 0.1);
+ color: $green;
+ }
+
+ &.icon-blue {
+ background: rgba($blue, 0.1);
+ color: $blue;
+ }
+
+ &.icon-purple {
+ background: rgba($purple, 0.1);
+ color: $purple;
+ }
+}
+
+.feature-title {
+ font-size: 1.125rem;
+ font-weight: 600;
+ color: $text-primary;
+ margin-bottom: 0.5rem;
+}
+
+.feature-desc {
+ font-size: 0.875rem;
+ color: $text-secondary;
+ margin: 0;
+}
+
+// Config Section
+.config-section {
+ padding: 2rem;
+ border-radius: 1rem;
+ background: $bg-card;
+ border: 1px solid $border-color;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+}
+
+.config-title {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ font-size: 1.5rem;
+ font-weight: 700;
+ margin-bottom: 1.5rem;
+ color: $text-primary;
+
+ ng-icon {
+ color: $indigo;
+ }
+}
+
+.config-grid {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 1.5rem;
+
+ @media (min-width: 768px) {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+.config-block-title {
+ font-size: 1.125rem;
+ font-weight: 600;
+ color: $text-primary;
+ margin-bottom: 0.75rem;
+}
+
+// Code Block
+.code-block {
+ border-radius: 0.75rem;
+ overflow: hidden;
+ border: 1px solid $border-color;
+ background: #1e293b;
+}
+
+.code-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0.5rem 1rem;
+ background: #334155;
+ border-bottom: 1px solid #475569;
+}
+
+.code-label {
+ font-size: 0.75rem;
+ font-family: 'JetBrains Mono', monospace;
+ color: #94a3b8;
+}
+
+.code-lang {
+ font-size: 0.75rem;
+ padding: 0.125rem 0.5rem;
+ border-radius: 0.25rem;
+ background: rgba($indigo, 0.3);
+ color: #a5b4fc;
+ font-family: 'JetBrains Mono', monospace;
+}
+
+.code-actions {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.copy-btn {
+ padding: 0.375rem;
+ border-radius: 0.5rem;
+ background: transparent;
+ border: none;
+ color: #94a3b8;
+ cursor: pointer;
+ transition: all 0.2s ease;
+
+ &:hover {
+ background: rgba(255, 255, 255, 0.1);
+ color: white;
+ }
+}
+
+.code-content {
+ padding: 1rem;
+ margin: 0;
+ overflow-x: auto;
+ font-size: 0.875rem;
+ background: #1e293b;
+
+ code {
+ font-family: 'JetBrains Mono', monospace;
+ color: #e2e8f0;
+ }
+}
+
+// Environment List
+.env-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.env-item {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ padding: 0.75rem;
+ border-radius: 0.75rem;
+ background: $bg-secondary;
+ border: 1px solid $border-color;
+}
+
+.env-indicator {
+ width: 0.75rem;
+ height: 0.75rem;
+ border-radius: 50%;
+
+ &.env-sandbox {
+ background: $amber;
+ animation: pulse 2s infinite;
+ }
+
+ &.env-prod {
+ background: $green;
+ }
+}
+
+@keyframes pulse {
+ 0%, 100% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.5;
+ }
+}
+
+.env-info {
+ flex: 1;
+}
+
+.env-name {
+ font-size: 0.875rem;
+ font-weight: 500;
+ color: $text-primary;
+ margin: 0;
+}
+
+.env-url {
+ font-size: 0.75rem;
+ font-family: 'JetBrains Mono', monospace;
+ color: $text-secondary;
+ margin: 0;
+}
+
+// Flow Section
+.flow-header {
+ padding: 1.5rem;
+ border-radius: 1rem;
+ background: linear-gradient(135deg, rgba($indigo, 0.05), rgba($purple, 0.05));
+ border: 1px solid rgba($indigo, 0.15);
+ margin-bottom: 1.5rem;
+}
+
+.flow-title {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ font-size: 1.25rem;
+ font-weight: 700;
+ margin-bottom: 0.5rem;
+ color: $text-primary;
+
+ ng-icon {
+ color: $indigo;
+ }
+}
+
+.flow-desc {
+ color: $text-secondary;
+ margin: 0;
+}
+
+// Mermaid Container
+.mermaid-container {
+ padding: 1.5rem;
+ border-radius: 1rem;
+ background: $bg-card;
+ border: 1px solid $border-color;
+ overflow-x: auto;
+ margin-bottom: 2rem;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+
+ .mermaid {
+ background: transparent !important;
+
+ svg {
+ max-width: 100%;
+ height: auto;
+ }
+ }
+}
+
+// Phases Grid
+.phases-grid {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 1rem;
+
+ @media (min-width: 768px) {
+ grid-template-columns: repeat(3, 1fr);
+ }
+}
+
+.phase-card {
+ padding: 1.25rem;
+ border-radius: 0.75rem;
+ background: $bg-card;
+ border: 1px solid $border-color;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+}
+
+.phase-badge {
+ display: inline-block;
+ padding: 0.25rem 0.5rem;
+ border-radius: 0.25rem;
+ font-size: 0.75rem;
+ font-weight: 700;
+ color: white;
+ margin-bottom: 0.75rem;
+
+ &.phase-indigo {
+ background: $indigo;
+ }
+
+ &.phase-blue {
+ background: $blue;
+ }
+
+ &.phase-orange {
+ background: $orange;
+ }
+}
+
+.phase-title {
+ font-size: 1.125rem;
+ font-weight: 600;
+ color: $text-primary;
+ margin-bottom: 0.25rem;
+}
+
+.phase-desc {
+ font-size: 0.875rem;
+ color: $text-secondary;
+ margin: 0;
+}
+
+// Steps Section
+.steps-section {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.step-card {
+ border-radius: 1rem;
+ overflow: hidden;
+}
+
+.step-header {
+ width: 100%;
+ display: flex;
+ align-items: flex-start;
+ gap: 1rem;
+ padding: 1.25rem;
+ background: $bg-card;
+ border: 1px solid $border-color;
+ border-radius: 1rem;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-align: left;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+
+ &:hover {
+ background: $bg-hover;
+ border-color: darken($border-color, 5%);
+ }
+}
+
+.step-icon {
+ flex-shrink: 0;
+ width: 3rem;
+ height: 3rem;
+ border-radius: 0.75rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: white;
+
+ &.step-indigo {
+ background: linear-gradient(135deg, $indigo, darken($indigo, 10%));
+ box-shadow: 0 4px 15px rgba($indigo, 0.3);
+ }
+
+ &.step-green {
+ background: linear-gradient(135deg, $green, darken($green, 10%));
+ box-shadow: 0 4px 15px rgba($green, 0.3);
+ }
+
+ &.step-blue {
+ background: linear-gradient(135deg, $blue, darken($blue, 10%));
+ box-shadow: 0 4px 15px rgba($blue, 0.3);
+ }
+
+ &.step-purple {
+ background: linear-gradient(135deg, $purple, darken($purple, 10%));
+ box-shadow: 0 4px 15px rgba($purple, 0.3);
+ }
+
+ &.step-orange {
+ background: linear-gradient(135deg, $orange, darken($orange, 10%));
+ box-shadow: 0 4px 15px rgba($orange, 0.3);
+ }
+
+ &.step-pink {
+ background: linear-gradient(135deg, $pink, darken($pink, 10%));
+ box-shadow: 0 4px 15px rgba($pink, 0.3);
+ }
+}
+
+.step-info {
+ flex: 1;
+}
+
+.step-label {
+ font-size: 0.75rem;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ color: $text-muted;
+}
+
+.step-title {
+ font-size: 1.125rem;
+ font-weight: 600;
+ color: $text-primary;
+ margin: 0.25rem 0;
+}
+
+.step-desc {
+ font-size: 0.875rem;
+ color: $text-secondary;
+ margin: 0;
+}
+
+.step-chevron {
+ flex-shrink: 0;
+ margin-top: 0.5rem;
+ color: $text-muted;
+ transition: transform 0.3s ease;
+
+ &.open {
+ transform: rotate(90deg);
+ }
+}
+
+.step-content {
+ margin-left: 4rem;
+ padding: 1rem 0 1rem 1rem;
+ border-left: 2px solid $border-color;
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+// Endpoint Badge
+.endpoint-badge {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 0.875rem;
+
+ &.large {
+ font-size: 1rem;
+
+ .method {
+ padding: 0.375rem 0.75rem;
+ }
+ }
+}
+
+.method {
+ padding: 0.25rem 0.5rem;
+ border-radius: 0.5rem;
+ font-weight: 700;
+ border: 1px solid;
+
+ &.method-get {
+ background: rgba($green, 0.1);
+ color: darken($green, 10%);
+ border-color: rgba($green, 0.3);
+ }
+
+ &.method-post {
+ background: rgba($blue, 0.1);
+ color: darken($blue, 10%);
+ border-color: rgba($blue, 0.3);
+ }
+
+ &.method-put {
+ background: rgba($amber, 0.1);
+ color: darken($amber, 10%);
+ border-color: rgba($amber, 0.3);
+ }
+
+ &.method-delete {
+ background: rgba($red, 0.1);
+ color: darken($red, 10%);
+ border-color: rgba($red, 0.3);
+ }
+
+ &.method-patch {
+ background: rgba($purple, 0.1);
+ color: darken($purple, 10%);
+ border-color: rgba($purple, 0.3);
+ }
+}
+
+.path {
+ color: $text-secondary;
+}
+
+// Note Box
+.note-box {
+ padding: 1rem;
+ border-radius: 0.75rem;
+
+ p {
+ font-size: 0.875rem;
+ margin: 0;
+ }
+
+ &.note-warning {
+ background: rgba($amber, 0.1);
+ border: 1px solid rgba($amber, 0.2);
+
+ p {
+ color: darken($amber, 15%);
+ }
+ }
+
+ &.note-success {
+ background: rgba($green, 0.1);
+ border: 1px solid rgba($green, 0.2);
+
+ p {
+ color: darken($green, 15%);
+ }
+ }
+
+ &.note-info {
+ background: rgba($blue, 0.1);
+ border: 1px solid rgba($blue, 0.2);
+
+ p {
+ color: darken($blue, 15%);
+ }
+ }
+
+ &.note-purple {
+ background: rgba($purple, 0.1);
+ border: 1px solid rgba($purple, 0.2);
+
+ p {
+ color: darken($purple, 15%);
+ }
+ }
+}
+
+// API Section
+.api-tabs {
+ display: flex;
+ gap: 0.25rem;
+ padding: 0.25rem;
+ background: $bg-secondary;
+ border-radius: 0.75rem;
+ border: 1px solid $border-color;
+ margin-bottom: 1.5rem;
+ overflow-x: auto;
+}
+
+.api-tab {
+ flex: 1;
+ min-width: max-content;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ padding: 0.625rem 1rem;
+ border-radius: 0.5rem;
+ font-size: 0.875rem;
+ font-weight: 500;
+ background: transparent;
+ border: none;
+ color: $text-secondary;
+ cursor: pointer;
+ transition: all 0.2s ease;
+
+ &:hover {
+ color: $text-primary;
+ background: $bg-hover;
+ }
+
+ &.active {
+ background: $indigo;
+ color: white;
+ box-shadow: 0 4px 15px rgba($indigo, 0.3);
+ }
+}
+
+.api-content {
+ // Placeholder
+}
+
+.api-section {
+ padding: 1.5rem;
+ border-radius: 1rem;
+ background: $bg-card;
+ border: 1px solid $border-color;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+}
+
+.api-section-title {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ font-size: 1.25rem;
+ font-weight: 700;
+ margin-bottom: 1rem;
+ color: $text-primary;
+
+ ng-icon {
+ color: $indigo;
+ }
+}
+
+.api-endpoints {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.api-endpoint {
+ padding: 1rem;
+ border-radius: 0.75rem;
+ background: $bg-secondary;
+ border: 1px solid $border-color;
+}
+
+.endpoint-desc {
+ font-size: 0.875rem;
+ color: $text-secondary;
+ margin: 0.5rem 0;
+}
+
+.endpoint-details {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 1rem;
+ margin-top: 1rem;
+
+ @media (min-width: 768px) {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ &.three-cols {
+ @media (min-width: 768px) {
+ grid-template-columns: repeat(3, 1fr);
+ }
+ }
+}
+
+.detail-title {
+ font-size: 0.75rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ color: $text-muted;
+ margin-bottom: 0.5rem;
+}
+
+.params-table {
+ width: 100%;
+ font-size: 0.875rem;
+
+ tbody {
+ tr {
+ border-bottom: 1px solid $border-color;
+
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+
+ td {
+ padding: 0.5rem 0;
+
+ &:first-child {
+ color: $text-primary;
+ font-weight: 500;
+ }
+
+ &:last-child {
+ color: $text-secondary;
+ }
+ }
+ }
+}
+
+.detail-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+
+ li {
+ font-size: 0.875rem;
+ color: $text-secondary;
+ padding: 0.25rem 0;
+ }
+}
+
+.responses-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
+}
+
+.response-item {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 0.875rem;
+ color: $text-secondary;
+}
+
+.response-code {
+ padding: 0.125rem 0.5rem;
+ border-radius: 0.25rem;
+ font-size: 0.75rem;
+ font-weight: 500;
+
+ &.response-success {
+ background: rgba($green, 0.15);
+ color: darken($green, 10%);
+ }
+
+ &.response-warning {
+ background: rgba($amber, 0.15);
+ color: darken($amber, 10%);
+ }
+
+ &.response-error {
+ background: rgba($red, 0.15);
+ color: darken($red, 10%);
+ }
+}
+
+.param-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ margin-top: 0.5rem;
+}
+
+.param-tag {
+ padding: 0.25rem 0.5rem;
+ border-radius: 0.25rem;
+ background: $bg-hover;
+ border: 1px solid $border-color;
+ font-size: 0.75rem;
+ font-family: 'JetBrains Mono', monospace;
+ color: $text-secondary;
+}
+
+.status-box {
+ margin-top: 1.5rem;
+ padding: 1rem;
+ border-radius: 0.75rem;
+ background: rgba($green, 0.05);
+ border: 1px solid rgba($green, 0.2);
+}
+
+.status-title {
+ font-size: 0.875rem;
+ font-weight: 600;
+ color: darken($green, 10%);
+ margin-bottom: 0.5rem;
+}
+
+.status-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+}
+
+.status-tag {
+ padding: 0.25rem 0.75rem;
+ border-radius: 9999px;
+ background: rgba($green, 0.1);
+ font-size: 0.75rem;
+ font-weight: 500;
+ color: darken($green, 10%);
+}
+
+// Swagger Section
+.swagger-header {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ margin-bottom: 1.5rem;
+ padding: 1.5rem;
+ background: linear-gradient(135deg, rgba($indigo, 0.05), rgba($blue, 0.05));
+ border: 1px solid rgba($indigo, 0.15);
+ border-radius: 1rem;
+
+ @media (min-width: 768px) {
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ }
+}
+
+.swagger-info {
+ flex: 1;
+}
+
+.swagger-title {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ font-size: 1.25rem;
+ font-weight: 700;
+ color: $text-primary;
+ margin-bottom: 0.5rem;
+
+ ng-icon {
+ color: $indigo;
+ }
+}
+
+.swagger-desc {
+ font-size: 0.875rem;
+ color: $text-secondary;
+ margin: 0 0 0.5rem;
+}
+
+.swagger-version {
+ font-size: 0.75rem;
+ padding: 0.25rem 0.75rem;
+ background: rgba($indigo, 0.1);
+ color: $indigo;
+ border-radius: 9999px;
+ font-weight: 500;
+}
+
+.swagger-search {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.625rem 1rem;
+ background: $bg-card;
+ border: 1px solid $border-color;
+ border-radius: 0.5rem;
+ min-width: 280px;
+
+ ng-icon {
+ color: $text-muted;
+ }
+
+ input {
+ flex: 1;
+ border: none;
+ background: transparent;
+ font-size: 0.875rem;
+ color: $text-primary;
+ outline: none;
+
+ &::placeholder {
+ color: $text-muted;
+ }
+ }
+}
+
+.swagger-layout {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 1.5rem;
+
+ @media (min-width: 1024px) {
+ grid-template-columns: 350px 1fr;
+ }
+}
+
+.swagger-sidebar {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ max-height: 600px;
+ overflow-y: auto;
+ padding-right: 0.5rem;
+
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: $bg-secondary;
+ border-radius: 3px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: $border-color;
+ border-radius: 3px;
+
+ &:hover {
+ background: darken($border-color, 10%);
+ }
+ }
+}
+
+.swagger-tag-group {
+ background: $bg-card;
+ border: 1px solid $border-color;
+ border-radius: 0.75rem;
+ overflow: hidden;
+}
+
+.swagger-tag-header {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ width: 100%;
+ padding: 0.875rem 1rem;
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ transition: background 0.2s ease;
+
+ &:hover {
+ background: $bg-hover;
+ }
+
+ .tag-name {
+ flex: 1;
+ text-align: left;
+ font-weight: 600;
+ color: $text-primary;
+ text-transform: capitalize;
+ }
+
+ .tag-count {
+ font-size: 0.75rem;
+ padding: 0.125rem 0.5rem;
+ background: rgba($indigo, 0.1);
+ color: $indigo;
+ border-radius: 9999px;
+ font-weight: 500;
+ }
+
+ ng-icon {
+ color: $text-muted;
+ }
+}
+
+.swagger-tag-endpoints {
+ border-top: 1px solid $border-color;
+ padding: 0.5rem;
+}
+
+.swagger-endpoint-item {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ width: 100%;
+ padding: 0.625rem 0.75rem;
+ background: transparent;
+ border: none;
+ border-radius: 0.5rem;
+ cursor: pointer;
+ transition: background 0.2s ease;
+ text-align: left;
+
+ &:hover {
+ background: $bg-hover;
+ }
+
+ &.selected {
+ background: rgba($indigo, 0.1);
+
+ .endpoint-path {
+ color: $indigo;
+ }
+ }
+
+ .endpoint-method {
+ font-size: 0.625rem;
+ padding: 0.125rem 0.375rem;
+ border-radius: 0.25rem;
+ font-weight: 700;
+ font-family: 'JetBrains Mono', monospace;
+ }
+
+ .endpoint-path {
+ flex: 1;
+ font-size: 0.75rem;
+ font-family: 'JetBrains Mono', monospace;
+ color: $text-secondary;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+}
+
+.swagger-detail {
+ min-height: 400px;
+}
+
+.swagger-placeholder {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ min-height: 400px;
+ background: $bg-card;
+ border: 1px dashed $border-color;
+ border-radius: 1rem;
+ color: $text-muted;
+
+ ng-icon {
+ margin-bottom: 1rem;
+ opacity: 0.5;
+ }
+
+ p {
+ font-size: 0.875rem;
+ }
+}
+
+.endpoint-detail-card {
+ background: $bg-card;
+ border: 1px solid $border-color;
+ border-radius: 1rem;
+ overflow: hidden;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+}
+
+.endpoint-detail-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 1rem 1.25rem;
+ background: $bg-secondary;
+ border-bottom: 1px solid $border-color;
+
+ .close-btn {
+ width: 2rem;
+ height: 2rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: transparent;
+ border: 1px solid $border-color;
+ border-radius: 0.5rem;
+ font-size: 1.25rem;
+ color: $text-muted;
+ cursor: pointer;
+ transition: all 0.2s ease;
+
+ &:hover {
+ background: $bg-hover;
+ color: $text-primary;
+ }
+ }
+}
+
+.endpoint-summary {
+ font-size: 1.125rem;
+ font-weight: 600;
+ color: $text-primary;
+ margin: 1rem 1.25rem 0.5rem;
+}
+
+.endpoint-description {
+ font-size: 0.875rem;
+ color: $text-secondary;
+ margin: 0 1.25rem 1rem;
+}
+
+.endpoint-section {
+ padding: 1rem 1.25rem;
+ border-top: 1px solid $border-color;
+
+ .section-title {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 0.875rem;
+ font-weight: 600;
+ color: $text-primary;
+ margin-bottom: 0.75rem;
+ text-transform: uppercase;
+ letter-spacing: 0.025em;
+
+ ng-icon {
+ color: $indigo;
+ }
+ }
+}
+
+.params-group {
+ margin-bottom: 1rem;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+}
+
+.params-group-title {
+ font-size: 0.75rem;
+ font-weight: 600;
+ color: $text-muted;
+ margin-bottom: 0.5rem;
+ text-transform: uppercase;
+}
+
+.params-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+}
+
+.param-item {
+ padding: 0.75rem;
+ background: $bg-secondary;
+ border-radius: 0.5rem;
+ border: 1px solid $border-color;
+
+ .param-name {
+ font-weight: 600;
+ color: $text-primary;
+ font-size: 0.875rem;
+ margin-bottom: 0.25rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ }
+
+ .required-badge {
+ font-size: 0.625rem;
+ padding: 0.125rem 0.375rem;
+ background: rgba($red, 0.1);
+ color: $red;
+ border-radius: 0.25rem;
+ font-weight: 500;
+ text-transform: uppercase;
+ }
+
+ .param-type {
+ font-size: 0.75rem;
+ font-family: 'JetBrains Mono', monospace;
+ color: $indigo;
+ margin-bottom: 0.25rem;
+ }
+
+ .param-enum {
+ display: block;
+ font-size: 0.7rem;
+ color: $text-muted;
+ margin-top: 0.25rem;
+ }
+
+ .param-desc {
+ font-size: 0.75rem;
+ color: $text-secondary;
+ }
+}
+
+.responses-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+}
+
+.response-card {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 0.75rem;
+ border-radius: 0.5rem;
+ border: 1px solid;
+
+ &.response-2 {
+ background: rgba($green, 0.05);
+ border-color: rgba($green, 0.2);
+
+ .response-status {
+ color: $green;
+ }
+ }
+
+ &.response-4 {
+ background: rgba($amber, 0.05);
+ border-color: rgba($amber, 0.2);
+
+ .response-status {
+ color: $amber;
+ }
+ }
+
+ &.response-5 {
+ background: rgba($red, 0.05);
+ border-color: rgba($red, 0.2);
+
+ .response-status {
+ color: $red;
+ }
+ }
+
+ .response-status {
+ font-weight: 700;
+ font-family: 'JetBrains Mono', monospace;
+ }
+
+ .response-desc {
+ font-size: 0.875rem;
+ color: $text-secondary;
+ }
+}
+
+.security-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 0.75rem;
+ background: rgba($green, 0.1);
+ border: 1px solid rgba($green, 0.2);
+ border-radius: 0.5rem;
+ font-size: 0.875rem;
+ font-weight: 500;
+ color: darken($green, 10%);
+
+ ng-icon {
+ color: $green;
+ }
+}
+
+// Footer
+.doc-footer {
+ margin-top: 4rem;
+ padding-top: 2rem;
+ border-top: 1px solid $border-color;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+
+ @media (min-width: 768px) {
+ flex-direction: row;
+ justify-content: space-between;
+ }
+}
+
+.footer-brand {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ color: $text-secondary;
+
+ ng-icon {
+ color: $indigo;
+ }
+}
+
+.footer-name {
+ font-weight: 600;
+ color: $text-primary;
+}
+
+.footer-divider {
+ color: $border-color;
+}
+
+.footer-version {
+ font-size: 0.875rem;
+}
+
+.footer-links {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+}
+
+.footer-link {
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ font-size: 0.875rem;
+ color: $text-secondary;
+ text-decoration: none;
+ transition: color 0.2s ease;
+
+ &:hover {
+ color: $indigo;
+ }
+}
+
+// Utility Classes
+.mt-3 {
+ margin-top: 0.75rem;
+}
+
+.mt-4 {
+ margin-top: 1rem;
+}
diff --git a/src/app/modules/documentation/documentation.ts b/src/app/modules/documentation/documentation.ts
index e388056..4c5f907 100644
--- a/src/app/modules/documentation/documentation.ts
+++ b/src/app/modules/documentation/documentation.ts
@@ -1,7 +1,784 @@
-import { Component } from '@angular/core';
+import { Component, OnInit, AfterViewInit, signal } from '@angular/core';
+import { CommonModule, KeyValuePipe } from '@angular/common';
+import { NgIcon, provideIcons } from '@ng-icons/core';
+import {
+ lucideZap,
+ lucideShield,
+ lucideUsers,
+ lucideCreditCard,
+ lucideBell,
+ lucideSettings,
+ lucideBookOpen,
+ lucideCode,
+ lucideArrowRight,
+ lucideExternalLink,
+ lucideChevronRight,
+ lucideChevronDown,
+ lucidePlay,
+ lucideCopy,
+ lucideCheck,
+ lucideMessageSquare,
+ lucideHome,
+ lucideFileJson,
+ lucideSearch,
+ lucideFilter,
+} from '@ng-icons/lucide';
+
+declare var mermaid: any;
+
+interface Step {
+ id: number;
+ title: string;
+ description: string;
+ icon: string;
+ color: string;
+ isOpen: boolean;
+ endpoint?: {
+ method: string;
+ path: string;
+ };
+ requestBody?: string;
+ responseBody?: string;
+ note?: {
+ type: 'warning' | 'success' | 'info' | 'purple';
+ text: string;
+ };
+ headers?: string;
+}
+
+interface SwaggerEndpoint {
+ method: string;
+ path: string;
+ summary: string;
+ description?: string;
+ operationId: string;
+ tags: string[];
+ parameters?: any[];
+ requestBody?: any;
+ responses?: any;
+ security?: any[];
+}
+
+interface SwaggerTag {
+ name: string;
+ endpoints: SwaggerEndpoint[];
+ isOpen: boolean;
+}
@Component({
selector: 'app-documentation',
+ standalone: true,
+ imports: [CommonModule, NgIcon, KeyValuePipe],
+ viewProviders: [
+ provideIcons({
+ lucideZap,
+ lucideShield,
+ lucideUsers,
+ lucideCreditCard,
+ lucideBell,
+ lucideSettings,
+ lucideBookOpen,
+ lucideCode,
+ lucideArrowRight,
+ lucideExternalLink,
+ lucideChevronRight,
+ lucideChevronDown,
+ lucidePlay,
+ lucideCopy,
+ lucideCheck,
+ lucideMessageSquare,
+ lucideHome,
+ lucideFileJson,
+ lucideSearch,
+ lucideFilter,
+ }),
+ ],
templateUrl: './documentation.html',
+ styleUrl: './documentation.scss',
})
-export class Documentation {}
\ No newline at end of file
+export class Documentation implements OnInit, AfterViewInit {
+ activeSection = signal('overview');
+ activeApiTab = signal('otp');
+ copiedCode = signal(null);
+ swaggerSearch = signal('');
+ selectedSwaggerEndpoint = signal(null);
+
+ sections = [
+ { id: 'overview', label: "Vue d'ensemble", icon: 'lucideBookOpen' },
+ { id: 'flow', label: 'Call Flow', icon: 'lucidePlay' },
+ { id: 'steps', label: "Étapes d'intégration", icon: 'lucideArrowRight' },
+ { id: 'api', label: 'API Reference', icon: 'lucideCode' },
+ ];
+
+ apiTabs = [
+ { id: 'otp', label: 'OTP Challenge' },
+ { id: 'subscriptions', label: 'Subscriptions' },
+ { id: 'payments', label: 'Payments' },
+ { id: 'operators', label: 'Operators' },
+ { id: 'swagger', label: 'Swagger API' },
+ ];
+
+ features = [
+ {
+ icon: 'lucideShield',
+ title: 'OTP Challenge',
+ desc: 'Authentification sécurisée par SMS',
+ color: 'indigo',
+ },
+ {
+ icon: 'lucideUsers',
+ title: 'Subscriptions',
+ desc: 'Gestion des abonnements récurrents',
+ color: 'green',
+ },
+ {
+ icon: 'lucideCreditCard',
+ title: 'Payments',
+ desc: 'Facturation et charges',
+ color: 'blue',
+ },
+ {
+ icon: 'lucideBell',
+ title: 'Webhooks',
+ desc: 'Notifications en temps réel',
+ color: 'purple',
+ },
+ ];
+
+ steps: Step[] = [
+ {
+ id: 1,
+ title: 'Initier le Challenge OTP',
+ description: "Envoi d'un code OTP au numéro de téléphone de l'utilisateur",
+ icon: 'lucideShield',
+ color: 'indigo',
+ isOpen: true,
+ endpoint: { method: 'POST', path: '/api/v1/otp-challenge/initiate' },
+ requestBody: `{
+ "msisdn": "225XXXXXXXXX",
+ "channel": "SMS",
+ "serviceId": "your-service-id",
+ "merchantId": "your-merchant-id"
+}`,
+ responseBody: `{
+ "challengeId": "chg_abc123xyz",
+ "status": "PENDING",
+ "expiresAt": "2024-01-15T10:30:00Z",
+ "channel": "SMS"
+}`,
+ note: {
+ type: 'warning',
+ text: "⚠️ Note: Le code OTP expire après 15 minutes. Maximum 3 tentatives de validation.",
+ },
+ },
+ {
+ id: 2,
+ title: 'Valider le Code OTP',
+ description: "Vérification du code saisi par l'utilisateur et récupération du token ISE2",
+ icon: 'lucideCheck',
+ color: 'green',
+ isOpen: false,
+ endpoint: { method: 'POST', path: '/api/v1/otp-challenge/{challengeId}/verify' },
+ requestBody: `{
+ "otp": "123456"
+}`,
+ responseBody: `{
+ "challengeId": "chg_abc123xyz",
+ "status": "VALIDATED",
+ "ise2Token": "eyJhbGciOiJSUzI1NiIs...",
+ "validatedAt": "2024-01-15T10:28:45Z"
+}`,
+ note: {
+ type: 'success',
+ text: "✅ Important: Conservez le ise2Token - il sera nécessaire pour la souscription et les charges.",
+ },
+ },
+ {
+ id: 3,
+ title: 'Créer une Souscription',
+ description: "Enregistrement de l'abonnement utilisateur au service",
+ icon: 'lucideUsers',
+ color: 'blue',
+ isOpen: false,
+ endpoint: { method: 'POST', path: '/api/v1/subscriptions' },
+ requestBody: `{
+ "userToken": "ise2_token_from_otp_validation",
+ "userAlias": "225XXXXXXXXX",
+ "planId": 1,
+ "callbackUrl": "https://your-domain.com/webhooks/subscription",
+ "metadata": {
+ "customerId": "cust_123",
+ "source": "mobile_app"
+ }
+}`,
+ responseBody: `{
+ "id": 456,
+ "status": "ACTIVE",
+ "planId": 1,
+ "startDate": "2024-01-15",
+ "nextPaymentDate": "2024-02-15",
+ "createdAt": "2024-01-15T10:29:00Z"
+}`,
+ },
+ {
+ id: 4,
+ title: 'Recevoir les Webhooks',
+ description: 'Notifications automatiques des événements (souscription, paiement, etc.)',
+ icon: 'lucideBell',
+ color: 'purple',
+ isOpen: false,
+ responseBody: `{
+ "event": "subscription.created",
+ "timestamp": "2024-01-15T10:29:05Z",
+ "data": {
+ "subscriptionId": 456,
+ "ise2": "ise2_token",
+ "productId": "prod_abc",
+ "serviceId": "svc_xyz",
+ "status": "ACTIVE",
+ "msisdn": "225XXXXXXXXX"
+ },
+ "signature": "sha256=..."
+}`,
+ note: {
+ type: 'purple',
+ text: "🔔 Types d'événements: subscription.created, subscription.cancelled, payment.success, payment.failed",
+ },
+ },
+ {
+ id: 5,
+ title: 'Effectuer une Charge',
+ description: "Facturation du montant sur le compte mobile de l'utilisateur",
+ icon: 'lucideCreditCard',
+ color: 'orange',
+ isOpen: false,
+ endpoint: { method: 'POST', path: '/api/v1/payments/charge' },
+ headers: `X-Merchant-ID: your-merchant-id
+X-COUNTRY: CI
+X-OPERATOR: ORANGE`,
+ requestBody: `{
+ "userToken": "ise2_token",
+ "amount": 500,
+ "currency": "XOF",
+ "description": "Abonnement Premium - Janvier 2024",
+ "reference": "PAY-2024-001-ABC",
+ "subscriptionId": 456,
+ "callbackUrl": "https://your-domain.com/webhooks/payment",
+ "metadata": {
+ "orderId": "ord_789"
+ }
+}`,
+ responseBody: `{
+ "id": "pay_xyz789",
+ "status": "SUCCESS",
+ "amount": 500,
+ "currency": "XOF",
+ "reference": "PAY-2024-001-ABC",
+ "operatorReference": "OPR-123456",
+ "completedAt": "2024-01-15T10:30:15Z"
+}`,
+ },
+ {
+ id: 6,
+ title: 'Envoyer un SMS de Confirmation',
+ description: "Notification SMS à l'utilisateur confirmant l'activation du service",
+ icon: 'lucideMessageSquare',
+ color: 'pink',
+ isOpen: false,
+ endpoint: { method: 'POST', path: '/smsmessaging/service/mea/v1/outbound/{senderMsisdn}/requests' },
+ requestBody: `{
+ "outboundSMSMessageRequest": {
+ "address": ["tel:+225XXXXXXXXX"],
+ "senderAddress": "tel:+225YYYYYYYYYY",
+ "outboundSMSTextMessage": {
+ "message": "Félicitations! Votre abonnement Premium est maintenant actif."
+ }
+ }
+}`,
+ },
+ ];
+
+ subscriptionStatuses = ['ACTIVE', 'TRIAL', 'PENDING', 'SUSPENDED', 'EXPIRED', 'CANCELLED'];
+
+ // Swagger data parsed from the JSON
+ swaggerTags: SwaggerTag[] = [];
+ swaggerInfo = {
+ title: 'Payment Hub API',
+ description: 'Unified DCB Payment Aggregation Platform',
+ version: '1.0.0'
+ };
+
+ mermaidDiagram = `sequenceDiagram
+ participant USER as 👤 Utilisateur
+ participant Partner as 🏪 Partner
+ participant HUB as ⚡ HUB DCB
+ participant DigiPay as 📱 DigiPay
+
+ rect rgb(99, 102, 241, 0.1)
+ Note over Partner,DigiPay: 🔐 Phase 1: OTP Challenge
+ Partner->>HUB: POST /api/v1/otp-challenge/initiate
+ HUB->>DigiPay: POST /challenge/v1/challenges
+ DigiPay-->>HUB: challengeId + status
+ HUB-->>Partner: challengeId + status
+ end
+
+ DigiPay->>USER: 📨 SMS avec code OTP
+ USER->>Partner: Saisie du code OTP
+
+ rect rgb(34, 197, 94, 0.1)
+ Note over Partner,DigiPay: ✅ Phase 2: Validation OTP
+ Partner->>HUB: POST /api/v1/otp-challenge/{id}/verify
+ HUB->>DigiPay: POST /challenge/v1/challenges/{id}
+ DigiPay-->>HUB: ise2 token
+ HUB-->>Partner: ise2 token
+ end
+
+ rect rgb(59, 130, 246, 0.1)
+ Note over Partner,DigiPay: 📋 Phase 3: Souscription
+ Partner->>HUB: POST /api/v1/subscriptions
+ HUB->>DigiPay: POST /digipay_sub/productOrder/
+ DigiPay-->>HUB: subscription response
+ HUB-->>Partner: subscription details
+ end
+
+ rect rgb(168, 85, 247, 0.1)
+ Note over Partner,DigiPay: 🔔 Notification Webhook
+ DigiPay->>HUB: Subscription notification
+ HUB->>Partner: Webhook callback
+ end
+
+ rect rgb(249, 115, 22, 0.1)
+ Note over Partner,DigiPay: 💳 Phase 4: Facturation
+ Partner->>HUB: POST /api/v1/payments/charge
+ HUB->>DigiPay: POST /payment/mea/v1/.../transactions/amount
+ DigiPay-->>HUB: payment response
+ HUB-->>Partner: payment confirmation
+ end
+
+ rect rgb(236, 72, 153, 0.1)
+ Note over Partner,DigiPay: 📱 Phase 5: SMS Confirmation
+ Partner->>HUB: POST /smsmessaging/.../requests
+ HUB->>DigiPay: Send SMS
+ DigiPay->>USER: 📨 SMS de confirmation
+ end
+
+ HUB->>USER: 🎉 Service activé`;
+
+ ngOnInit(): void {
+ this.parseSwaggerSpec();
+ }
+
+ ngAfterViewInit(): void {
+ this.initMermaid();
+ }
+
+ private parseSwaggerSpec(): void {
+ // Parse the Swagger JSON spec
+ const swaggerSpec = {
+ "openapi": "3.0.0",
+ "paths": {
+ "/api/v1/operators": {
+ "get": {
+ "operationId": "OperatorsController_getOperatorStatistics",
+ "parameters": [
+ {"name": "operatorCode", "required": true, "in": "path", "schema": {"type": "string"}},
+ {"name": "period", "required": false, "in": "query", "schema": {"enum": ["daily", "weekly", "monthly", "yearly"], "type": "string"}},
+ {"name": "startDate", "required": false, "in": "query", "schema": {"format": "date-time", "type": "string"}},
+ {"name": "endDate", "required": false, "in": "query", "schema": {"format": "date-time", "type": "string"}},
+ {"name": "active", "required": false, "in": "query", "schema": {"type": "boolean"}},
+ {"name": "country", "required": false, "in": "query", "schema": {}}
+ ],
+ "responses": {"200": {"description": "List of operators"}},
+ "security": [{"bearer": []}],
+ "summary": "List all available operators",
+ "tags": ["operators"]
+ }
+ },
+ "/api/v1/operators/{operatorCode}/health": {
+ "get": {
+ "operationId": "OperatorsController_getOperatorHealth",
+ "parameters": [{"name": "operatorCode", "required": true, "in": "path", "schema": {"type": "string"}}],
+ "responses": {"200": {"description": "Operator health metrics"}},
+ "security": [{"bearer": []}],
+ "summary": "Get operator health metrics",
+ "tags": ["operators"]
+ }
+ },
+ "/api/v1/operators/detect/{msisdn}": {
+ "get": {
+ "operationId": "OperatorsController_detectOperator",
+ "parameters": [{"name": "msisdn", "required": true, "in": "path", "schema": {"type": "string"}}],
+ "responses": {"200": {"description": "Detected operator information"}},
+ "security": [{"bearer": []}],
+ "summary": "Detect operator from MSISDN",
+ "tags": ["operators"]
+ }
+ },
+ "/api/v1/payments/charge": {
+ "post": {
+ "operationId": "PaymentsController_createCharge",
+ "parameters": [
+ {"name": "X-Merchant-ID", "required": true, "in": "header", "schema": {"type": "string"}},
+ {"name": "X-COUNTRY", "required": true, "in": "header", "schema": {"type": "string"}},
+ {"name": "X-OPERATOR", "required": true, "in": "header", "schema": {"type": "string"}}
+ ],
+ "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ChargeDto"}}}},
+ "responses": {
+ "201": {"description": "Payment created successfully"},
+ "400": {"description": "Bad request"},
+ "401": {"description": "Unauthorized"}
+ },
+ "security": [{"bearer": []}],
+ "summary": "Create a new charge",
+ "tags": ["payments"]
+ }
+ },
+ "/api/v1/payments/{paymentId}/refund": {
+ "post": {
+ "operationId": "PaymentsController_refundPayment",
+ "parameters": [{"name": "paymentId", "required": true, "in": "path", "schema": {"type": "string"}}],
+ "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RefundDto"}}}},
+ "responses": {
+ "200": {"description": "Refund processed successfully"},
+ "404": {"description": "Payment not found"}
+ },
+ "security": [{"bearer": []}],
+ "summary": "Refund a payment",
+ "tags": ["payments"]
+ }
+ },
+ "/api/v1/payments/{paymentId}": {
+ "get": {
+ "operationId": "PaymentsController_getPayment",
+ "parameters": [{"name": "paymentId", "required": true, "in": "path", "schema": {"type": "number"}}],
+ "responses": {
+ "200": {"description": "Payment details retrieved"},
+ "404": {"description": "Payment not found"}
+ },
+ "security": [{"bearer": []}],
+ "summary": "Get payment details",
+ "tags": ["payments"]
+ }
+ },
+ "/api/v1/payments/reference/{reference}": {
+ "get": {
+ "operationId": "PaymentsController_getPaymentByReference",
+ "parameters": [{"name": "reference", "required": true, "in": "path", "schema": {"type": "string"}}],
+ "responses": {"200": {"description": "Payment details retrieved"}},
+ "security": [{"bearer": []}],
+ "summary": "Get payment by reference",
+ "tags": ["payments"]
+ }
+ },
+ "/api/v1/payments": {
+ "get": {
+ "description": "Retrieve payments with optional filters on status, type, dates, amounts, etc.",
+ "operationId": "PaymentsController_getAll",
+ "parameters": [
+ {"name": "page", "required": false, "in": "query", "description": "Page number", "schema": {"minimum": 1, "default": 1, "type": "number"}},
+ {"name": "limit", "required": false, "in": "query", "description": "Number of items per page", "schema": {"minimum": 1, "maximum": 100, "default": 10, "type": "number"}},
+ {"name": "type", "required": false, "in": "query", "description": "Filter by payment type", "schema": {"type": "string", "enum": ["MM", "BANK", "CHEQUE"]}},
+ {"name": "status", "required": false, "in": "query", "description": "Filter by transaction status", "schema": {"type": "string", "enum": ["SUCCESS", "FAILED", "PENDING"]}},
+ {"name": "merchantPartnerId", "required": false, "in": "query", "description": "Filter by merchant partner ID", "schema": {"type": "number"}},
+ {"name": "currency", "required": false, "in": "query", "description": "Filter by currency code", "schema": {"example": "XOF", "type": "string"}},
+ {"name": "amountMin", "required": false, "in": "query", "description": "Filter payments with amount >= this value", "schema": {"type": "number"}},
+ {"name": "amountMax", "required": false, "in": "query", "description": "Filter payments with amount <= this value", "schema": {"type": "number"}},
+ {"name": "createdFrom", "required": false, "in": "query", "description": "Filter payments created from this date", "schema": {"type": "string"}},
+ {"name": "createdTo", "required": false, "in": "query", "description": "Filter payments created until this date", "schema": {"type": "string"}},
+ {"name": "sortBy", "required": false, "in": "query", "description": "Sort field", "schema": {"default": "createdAt", "type": "string", "enum": ["createdAt", "completedAt", "amount"]}},
+ {"name": "sortOrder", "required": false, "in": "query", "description": "Sort order", "schema": {"default": "desc", "type": "string", "enum": ["asc", "desc"]}}
+ ],
+ "responses": {"200": {"description": "Paginated list of payments"}},
+ "summary": "Get payment list with pagination and filters",
+ "tags": ["payments"]
+ }
+ },
+ "/api/v1/payments/{paymentId}/retry": {
+ "post": {
+ "operationId": "PaymentsController_retryPayment",
+ "parameters": [{"name": "paymentId", "required": true, "in": "path", "schema": {"type": "string"}}],
+ "responses": {
+ "200": {"description": "Payment retry initiated"},
+ "400": {"description": "Payment cannot be retried"}
+ },
+ "security": [{"bearer": []}],
+ "summary": "Retry a failed payment",
+ "tags": ["payments"]
+ }
+ },
+ "/api/v1/subscriptions": {
+ "post": {
+ "operationId": "SubscriptionsController_create",
+ "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateSubscriptionDto"}}}},
+ "responses": {"201": {"description": "Subscription created successfully"}},
+ "summary": "Create subscription",
+ "tags": ["subscriptions"]
+ },
+ "get": {
+ "operationId": "SubscriptionsController_getAll",
+ "parameters": [
+ {"name": "page", "required": false, "in": "query", "description": "Page number", "schema": {"minimum": 1, "default": 1, "type": "number"}},
+ {"name": "limit", "required": false, "in": "query", "description": "Number of items per page", "schema": {"minimum": 1, "maximum": 100, "default": 10, "type": "number"}},
+ {"name": "status", "required": false, "in": "query", "description": "Filter by subscription status", "schema": {"type": "string", "enum": ["ACTIVE", "TRIAL", "PENDING", "SUSPENDED", "EXPIRED", "CANCELLED"]}},
+ {"name": "periodicity", "required": false, "in": "query", "description": "Filter by periodicity", "schema": {"type": "string", "enum": ["Daily", "Weekly", "Monthly", "OneTime"]}},
+ {"name": "serviceId", "required": false, "in": "query", "description": "Filter by service ID", "schema": {"type": "number"}}
+ ],
+ "responses": {"200": {"description": "Paginated list of subscriptions"}},
+ "summary": "Get subscription list with pagination",
+ "tags": ["subscriptions"]
+ }
+ },
+ "/api/v1/subscriptions/{id}": {
+ "get": {
+ "operationId": "SubscriptionsController_get",
+ "parameters": [{"name": "id", "required": true, "in": "path", "schema": {"type": "number"}}],
+ "responses": {"200": {"description": "Subscription details"}},
+ "summary": "Get subscription details",
+ "tags": ["subscriptions"]
+ },
+ "delete": {
+ "operationId": "SubscriptionsController_cancel",
+ "parameters": [{"name": "id", "required": true, "in": "path", "schema": {"type": "number"}}],
+ "responses": {"200": {"description": "Subscription cancelled"}},
+ "summary": "Cancel subscription",
+ "tags": ["subscriptions"]
+ }
+ },
+ "/api/v1/otp-challenge/initiate": {
+ "post": {
+ "description": "Envoie un code OTP au numéro de téléphone spécifié via SMS, USSD ou IVR",
+ "operationId": "OtpChallengeController_initiateChallenge",
+ "parameters": [
+ {"name": "X-Merchant-ID", "required": true, "in": "header", "description": "Identifiant du merchant", "schema": {"type": "string"}},
+ {"name": "X-API-Key", "required": true, "in": "header", "description": "Clé API du merchant", "schema": {"type": "string"}}
+ ],
+ "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OtpChallengeRequestDto"}}}},
+ "responses": {
+ "201": {"description": "Challenge OTP initié avec succès"},
+ "400": {"description": "Requête invalide"},
+ "500": {"description": "Erreur serveur"}
+ },
+ "summary": "Initier un challenge OTP",
+ "tags": ["OTP Challenge"]
+ }
+ },
+ "/api/v1/otp-challenge/{challengeId}/verify": {
+ "post": {
+ "description": "Vérifie le code OTP entré par l'utilisateur",
+ "operationId": "OtpChallengeController_verifyOtp",
+ "parameters": [
+ {"name": "challengeId", "required": true, "in": "path", "description": "Identifiant du challenge", "schema": {"type": "string"}},
+ {"name": "X-Merchant-ID", "required": true, "in": "header", "description": "Identifiant du merchant", "schema": {"type": "string"}},
+ {"name": "X-API-Key", "required": true, "in": "header", "description": "Clé API du merchant", "schema": {"type": "string"}}
+ ],
+ "responses": {
+ "200": {"description": "Code OTP vérifié avec succès"},
+ "400": {"description": "Code OTP invalide"},
+ "404": {"description": "Challenge non trouvé"}
+ },
+ "summary": "Vérifier un code OTP",
+ "tags": ["OTP Challenge"]
+ }
+ }
+ },
+ "info": {
+ "title": "Payment Hub API",
+ "description": "Unified DCB Payment Aggregation Platform",
+ "version": "1.0.0"
+ },
+ "components": {
+ "schemas": {
+ "ChargeDto": {
+ "type": "object",
+ "properties": {
+ "userToken": {"type": "string", "description": "User token from authentication"},
+ "amount": {"type": "number", "description": "Amount to charge"},
+ "currency": {"type": "string", "description": "Currency code (XOF, XAF, USD, etc.)"},
+ "description": {"type": "string", "description": "Payment description"},
+ "reference": {"type": "string", "description": "Unique payment reference"},
+ "subscriptionId": {"type": "number", "description": "Subscription ID if recurring"},
+ "callbackUrl": {"type": "string", "description": "Callback URL for notifications"},
+ "metadata": {"type": "object", "description": "Additional metadata"}
+ },
+ "required": ["userToken", "amount", "currency", "description"]
+ },
+ "RefundDto": {
+ "type": "object",
+ "properties": {
+ "amount": {"type": "number", "description": "Amount to refund (partial refund)"},
+ "reason": {"type": "string", "description": "Reason for refund"},
+ "metadata": {"type": "object", "description": "Additional metadata"}
+ },
+ "required": ["reason"]
+ },
+ "CreateSubscriptionDto": {
+ "type": "object",
+ "properties": {
+ "userToken": {"type": "string"},
+ "userAlias": {"type": "string"},
+ "planId": {"type": "number"},
+ "callbackUrl": {"type": "string"},
+ "metadata": {"type": "object"}
+ },
+ "required": ["userToken", "userAlias", "planId"]
+ },
+ "OtpChallengeRequestDto": {
+ "type": "object",
+ "properties": {
+ "msisdn": {"type": "string", "description": "Phone number"},
+ "channel": {"type": "string", "enum": ["SMS", "USSD", "IVR"]},
+ "serviceId": {"type": "string"}
+ }
+ }
+ }
+ }
+ };
+
+ // Group endpoints by tags
+ const tagGroups: Record = {};
+
+ Object.entries(swaggerSpec.paths).forEach(([path, methods]) => {
+ Object.entries(methods as Record).forEach(([method, details]) => {
+ const endpoint: SwaggerEndpoint = {
+ method: method.toUpperCase(),
+ path: path,
+ summary: details.summary || '',
+ description: details.description || '',
+ operationId: details.operationId || '',
+ tags: details.tags || ['default'],
+ parameters: details.parameters || [],
+ requestBody: details.requestBody,
+ responses: details.responses,
+ security: details.security
+ };
+
+ const tag = endpoint.tags[0] || 'default';
+ if (!tagGroups[tag]) {
+ tagGroups[tag] = [];
+ }
+ tagGroups[tag].push(endpoint);
+ });
+ });
+
+ this.swaggerTags = Object.entries(tagGroups).map(([name, endpoints]) => ({
+ name,
+ endpoints,
+ isOpen: name === 'payments'
+ }));
+ }
+
+ private initMermaid(): void {
+ if (typeof mermaid !== 'undefined') {
+ mermaid.initialize({
+ startOnLoad: false,
+ theme: 'default',
+ themeVariables: {
+ primaryColor: '#6366f1',
+ primaryTextColor: '#1e293b',
+ primaryBorderColor: '#818cf8',
+ lineColor: '#64748b',
+ secondaryColor: '#f1f5f9',
+ tertiaryColor: '#ffffff',
+ background: '#ffffff',
+ mainBkg: '#f8fafc',
+ textColor: '#1e293b',
+ },
+ });
+ }
+ }
+
+ renderMermaid(): void {
+ setTimeout(() => {
+ if (typeof mermaid !== 'undefined') {
+ const element = document.querySelector('.mermaid');
+ if (element) {
+ element.innerHTML = this.mermaidDiagram;
+ mermaid.run({ nodes: [element] });
+ }
+ }
+ }, 100);
+ }
+
+ setActiveSection(sectionId: string): void {
+ this.activeSection.set(sectionId);
+ if (sectionId === 'flow') {
+ this.renderMermaid();
+ }
+ }
+
+ setActiveApiTab(tabId: string): void {
+ this.activeApiTab.set(tabId);
+ }
+
+ toggleStep(step: Step): void {
+ step.isOpen = !step.isOpen;
+ }
+
+ toggleSwaggerTag(tag: SwaggerTag): void {
+ tag.isOpen = !tag.isOpen;
+ }
+
+ selectSwaggerEndpoint(endpoint: SwaggerEndpoint): void {
+ this.selectedSwaggerEndpoint.set(endpoint);
+ }
+
+ closeSwaggerDetail(): void {
+ this.selectedSwaggerEndpoint.set(null);
+ }
+
+ async copyCode(code: string, codeId: string): Promise {
+ try {
+ await navigator.clipboard.writeText(code);
+ this.copiedCode.set(codeId);
+ setTimeout(() => this.copiedCode.set(null), 2000);
+ } catch (err) {
+ console.error('Failed to copy:', err);
+ }
+ }
+
+ getMethodClass(method: string): string {
+ const classes: Record = {
+ GET: 'method-get',
+ POST: 'method-post',
+ PUT: 'method-put',
+ DELETE: 'method-delete',
+ PATCH: 'method-patch',
+ };
+ return classes[method] || 'method-get';
+ }
+
+ getStepColorClass(color: string): string {
+ return `step-${color}`;
+ }
+
+ getNoteClass(type: string): string {
+ return `note-${type}`;
+ }
+
+ getFilteredSwaggerTags(): SwaggerTag[] {
+ const search = this.swaggerSearch().toLowerCase();
+ if (!search) return this.swaggerTags;
+
+ return this.swaggerTags.map(tag => ({
+ ...tag,
+ endpoints: tag.endpoints.filter(
+ e => e.path.toLowerCase().includes(search) ||
+ e.summary.toLowerCase().includes(search) ||
+ e.method.toLowerCase().includes(search)
+ )
+ })).filter(tag => tag.endpoints.length > 0);
+ }
+
+ onSwaggerSearch(event: Event): void {
+ const value = (event.target as HTMLInputElement).value;
+ this.swaggerSearch.set(value);
+ }
+
+ formatJson(obj: any): string {
+ return JSON.stringify(obj, null, 2);
+ }
+
+ getParametersByLocation(params: any[], location: string): any[] {
+ return params?.filter(p => p.in === location) || [];
+ }
+}
diff --git a/src/environments/environment.ts b/src/environments/environment.ts
index 80c1eef..927a057 100644
--- a/src/environments/environment.ts
+++ b/src/environments/environment.ts
@@ -1,8 +1,8 @@
export const environment = {
production: false,
- localServiceTestApiUrl: "http://localhost:4200/api/v1",
- iamApiUrl: "http://localhost:3000/api/v1",
+ localServiceTestApiUrl: "https://backoffice.dcb.pixpay.sn/api/v1",
+ iamApiUrl: "https://api-user-service.dcb.pixpay.sn/api/v1",
configApiUrl: 'https://api-merchant-config-service.dcb.pixpay.sn/api/v1',
- apiCoreUrl: 'https://api-core-service.dcb.pixpay.sn/api/v1',
- reportingApiUrl: 'https://api-reporting-service.dcb.pixpay.sn/api/v1',
-}
\ No newline at end of file
+ apiCoreUrl: 'https://api-core-service.dcb.pixpay.sn/api/v1',
+ reportingApiUrl: 'https://api-reporting-service.dcb.pixpay.sn/api/v1/',
+}
diff --git a/src/types/mermaid.d.ts b/src/types/mermaid.d.ts
new file mode 100644
index 0000000..f47792e
--- /dev/null
+++ b/src/types/mermaid.d.ts
@@ -0,0 +1,27 @@
+// src/types/mermaid.d.ts
+
+declare module 'mermaid' {
+ interface MermaidConfig {
+ startOnLoad?: boolean;
+ theme?: string;
+ themeVariables?: Record;
+ securityLevel?: string;
+ flowchart?: Record;
+ sequence?: Record;
+ }
+
+ interface MermaidAPI {
+ initialize(config: MermaidConfig): void;
+ run(config?: { nodes?: Element[] }): Promise;
+ render(id: string, text: string): Promise<{ svg: string }>;
+ }
+
+ const mermaid: MermaidAPI;
+ export default mermaid;
+}
+
+declare var mermaid: {
+ initialize(config: any): void;
+ run(config?: { nodes?: Element[] }): Promise;
+ render(id: string, text: string): Promise<{ svg: string }>;
+};