added Swagger documentation

This commit is contained in:
Dmitri 2026-07-02 13:03:05 +02:00
parent a3dfdccd0d
commit 6085443549
27 changed files with 2133 additions and 338 deletions

View File

@ -35,7 +35,6 @@
"pino": "^9.0.0", "pino": "^9.0.0",
"pino-pretty": "^11.0.0", "pino-pretty": "^11.0.0",
"sequelize": "^6.37.0", "sequelize": "^6.37.0",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.0", "swagger-ui-express": "^5.0.0",
"uuid": "^14.0.1", "uuid": "^14.0.1",
"validator": "^13.15.35" "validator": "^13.15.35"
@ -58,7 +57,6 @@
"@types/passport-google-oauth2": "^0.1.10", "@types/passport-google-oauth2": "^0.1.10",
"@types/passport-jwt": "^4.0.1", "@types/passport-jwt": "^4.0.1",
"@types/passport-microsoft": "^2.1.1", "@types/passport-microsoft": "^2.1.1",
"@types/swagger-jsdoc": "^6.0.4",
"@types/swagger-ui-express": "^4.1.8", "@types/swagger-ui-express": "^4.1.8",
"@types/validator": "^13.15.10", "@types/validator": "^13.15.10",
"@typescript-eslint/eslint-plugin": "^8.62.1", "@typescript-eslint/eslint-plugin": "^8.62.1",
@ -76,50 +74,6 @@
"node": ">=24 <25" "node": ">=24 <25"
} }
}, },
"node_modules/@apidevtools/json-schema-ref-parser": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
"integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==",
"license": "MIT",
"dependencies": {
"@jsdevtools/ono": "^7.1.3",
"@types/json-schema": "^7.0.6",
"call-me-maybe": "^1.0.1",
"js-yaml": "^4.1.0"
}
},
"node_modules/@apidevtools/openapi-schemas": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz",
"integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==",
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/@apidevtools/swagger-methods": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
"integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==",
"license": "MIT"
},
"node_modules/@apidevtools/swagger-parser": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz",
"integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==",
"license": "MIT",
"dependencies": {
"@apidevtools/json-schema-ref-parser": "^9.0.6",
"@apidevtools/openapi-schemas": "^2.0.4",
"@apidevtools/swagger-methods": "^3.0.2",
"@jsdevtools/ono": "^7.1.3",
"call-me-maybe": "^1.0.1",
"z-schema": "^5.0.1"
},
"peerDependencies": {
"openapi-types": ">=7"
}
},
"node_modules/@aws-crypto/crc32": { "node_modules/@aws-crypto/crc32": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz",
@ -1255,12 +1209,6 @@
"dev": true, "dev": true,
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/@jsdevtools/ono": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
"license": "MIT"
},
"node_modules/@napi-rs/wasm-runtime": { "node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.6", "version": "1.1.6",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
@ -2369,12 +2317,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"license": "MIT"
},
"node_modules/@types/json2csv": { "node_modules/@types/json2csv": {
"version": "5.0.7", "version": "5.0.7",
"resolved": "https://registry.npmjs.org/@types/json2csv/-/json2csv-5.0.7.tgz", "resolved": "https://registry.npmjs.org/@types/json2csv/-/json2csv-5.0.7.tgz",
@ -2566,13 +2508,6 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/swagger-jsdoc": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.4.tgz",
"integrity": "sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/swagger-ui-express": { "node_modules/@types/swagger-ui-express": {
"version": "4.1.8", "version": "4.1.8",
"resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.8.tgz", "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.8.tgz",
@ -3321,6 +3256,7 @@
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0" "license": "Python-2.0"
}, },
"node_modules/array-buffer-byte-length": { "node_modules/array-buffer-byte-length": {
@ -3640,6 +3576,7 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/base64-js": { "node_modules/base64-js": {
@ -3806,6 +3743,7 @@
"version": "1.1.15", "version": "1.1.15",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz",
"integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
@ -3930,12 +3868,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/call-me-maybe": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
"integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
"license": "MIT"
},
"node_modules/callsites": { "node_modules/callsites": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@ -4039,6 +3971,7 @@
"version": "10.0.1", "version": "10.0.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"engines": { "engines": {
@ -4049,6 +3982,7 @@
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/concat-stream": { "node_modules/concat-stream": {
@ -4353,6 +4287,7 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
"dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"esutils": "^2.0.2" "esutils": "^2.0.2"
@ -5254,6 +5189,7 @@
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@ -5664,6 +5600,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/fsevents": { "node_modules/fsevents": {
@ -5895,26 +5832,6 @@
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
} }
}, },
"node_modules/glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/glob-parent": { "node_modules/glob-parent": {
"version": "6.0.2", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@ -6292,6 +6209,7 @@
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"once": "^1.3.0", "once": "^1.3.0",
@ -6784,6 +6702,7 @@
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz",
"integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",
"dev": true,
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@ -6992,6 +6911,7 @@
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/lodash.isinteger": { "node_modules/lodash.isinteger": {
@ -7025,12 +6945,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/lodash.mergewith": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
"integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==",
"license": "MIT"
},
"node_modules/lodash.once": { "node_modules/lodash.once": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
@ -7123,6 +7037,7 @@
"version": "3.1.5", "version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
@ -7632,13 +7547,6 @@
"wrappy": "1" "wrappy": "1"
} }
}, },
"node_modules/openapi-types": {
"version": "12.1.3",
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
"license": "MIT",
"peer": true
},
"node_modules/optionator": { "node_modules/optionator": {
"version": "0.9.4", "version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@ -7838,6 +7746,7 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@ -9251,47 +9160,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/swagger-jsdoc": {
"version": "6.2.8",
"resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz",
"integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==",
"license": "MIT",
"dependencies": {
"commander": "6.2.0",
"doctrine": "3.0.0",
"glob": "7.1.6",
"lodash.mergewith": "^4.6.2",
"swagger-parser": "^10.0.3",
"yaml": "2.0.0-1"
},
"bin": {
"swagger-jsdoc": "bin/swagger-jsdoc.js"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/swagger-jsdoc/node_modules/commander": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz",
"integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==",
"license": "MIT",
"engines": {
"node": ">= 6"
}
},
"node_modules/swagger-parser": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz",
"integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==",
"license": "MIT",
"dependencies": {
"@apidevtools/swagger-parser": "10.0.3"
},
"engines": {
"node": ">=10"
}
},
"node_modules/swagger-ui-dist": { "node_modules/swagger-ui-dist": {
"version": "5.17.14", "version": "5.17.14",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.14.tgz", "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.14.tgz",
@ -10199,15 +10067,6 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/yaml": {
"version": "2.0.0-1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz",
"integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==",
"license": "ISC",
"engines": {
"node": ">= 6"
}
},
"node_modules/yocto-queue": { "node_modules/yocto-queue": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@ -10224,6 +10083,7 @@
"version": "5.0.6", "version": "5.0.6",
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.6.tgz", "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.6.tgz",
"integrity": "sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg==", "integrity": "sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",

View File

@ -55,7 +55,6 @@
"pino": "^9.0.0", "pino": "^9.0.0",
"pino-pretty": "^11.0.0", "pino-pretty": "^11.0.0",
"sequelize": "^6.37.0", "sequelize": "^6.37.0",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.0", "swagger-ui-express": "^5.0.0",
"uuid": "^14.0.1", "uuid": "^14.0.1",
"validator": "^13.15.35" "validator": "^13.15.35"
@ -93,7 +92,6 @@
"@types/passport-google-oauth2": "^0.1.10", "@types/passport-google-oauth2": "^0.1.10",
"@types/passport-jwt": "^4.0.1", "@types/passport-jwt": "^4.0.1",
"@types/passport-microsoft": "^2.1.1", "@types/passport-microsoft": "^2.1.1",
"@types/swagger-jsdoc": "^6.0.4",
"@types/swagger-ui-express": "^4.1.8", "@types/swagger-ui-express": "^4.1.8",
"@types/validator": "^13.15.10", "@types/validator": "^13.15.10",
"@typescript-eslint/eslint-plugin": "^8.62.1", "@typescript-eslint/eslint-plugin": "^8.62.1",

View File

@ -4,7 +4,6 @@ import express from 'express';
import fs from 'node:fs'; import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import helmet from 'helmet'; import helmet from 'helmet';
import swaggerJsDoc from 'swagger-jsdoc';
import * as swaggerUI from 'swagger-ui-express'; import * as swaggerUI from 'swagger-ui-express';
import './auth/auth.ts'; import './auth/auth.ts';
@ -23,6 +22,7 @@ import {
downloadLimiter, downloadLimiter,
searchLimiter, searchLimiter,
} from './middlewares/rateLimiter.ts'; } from './middlewares/rateLimiter.ts';
import { createOpenApiDocument } from './openapi/document.ts';
import accessLogsRoutesModule from './routes/access_logs.ts'; import accessLogsRoutesModule from './routes/access_logs.ts';
import assetVariantsRoutesModule from './routes/asset_variants.ts'; import assetVariantsRoutesModule from './routes/asset_variants.ts';
import assetsRoutesModule from './routes/assets.ts'; import assetsRoutesModule from './routes/assets.ts';
@ -55,9 +55,6 @@ import type {
HealthResponse, HealthResponse,
MountRuntimeEntityRoute, MountRuntimeEntityRoute,
RuntimeReadOrAuthMiddleware, RuntimeReadOrAuthMiddleware,
SwaggerDocumentOptions,
SwaggerHostMiddleware,
SwaggerUiModuleWithHost,
} from './types/index.ts'; } from './types/index.ts';
import { import {
exitAfterLogging, exitAfterLogging,
@ -73,7 +70,6 @@ import {
} from './utils/request-context.ts'; } from './utils/request-context.ts';
const app = express(); const app = express();
const swaggerUiWithHost: SwaggerUiModuleWithHost = swaggerUI;
registerProcessErrorHandlers(); registerProcessErrorHandlers();
initializePermissionsMiddleware(); initializePermissionsMiddleware();
@ -154,54 +150,12 @@ const getBaseUrl = (url: string | undefined): string => {
return url.endsWith('/api') ? url.slice(0, -4) : url; return url.endsWith('/api') ? url.slice(0, -4) : url;
}; };
const options: SwaggerDocumentOptions = { const specs = createOpenApiDocument({
definition: { serverUrl: getBaseUrl(process.env.NEXT_PUBLIC_BACK_API) || config.swaggerUrl,
openapi: '3.0.0', });
info: {
version: '1.0.0',
title: 'Tour Builder Platform',
description:
'Tour Builder Platform Online REST API for Testing and Prototyping application. You can perform all major operations with your entities - create, delete and etc.',
},
servers: [
{
url: getBaseUrl(process.env.NEXT_PUBLIC_BACK_API) || config.swaggerUrl,
description: 'Development server',
},
],
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
},
},
responses: {
UnauthorizedError: {
description: 'Access token is missing or invalid',
},
},
},
security: [
{
bearerAuth: [],
},
],
},
apis: ['./src/routes/*.{js,ts}'],
};
const specs = swaggerJsDoc(options);
const swaggerHostMiddleware: SwaggerHostMiddleware = (req, _res, next) => {
swaggerUiWithHost.host =
getBaseUrl(process.env.NEXT_PUBLIC_BACK_API) || req.get('host') || '';
next();
};
app.use( app.use(
'/api-docs', '/api-docs',
swaggerHostMiddleware,
swaggerUI.serve, swaggerUI.serve,
swaggerUI.setup(specs), swaggerUI.setup(specs),
); );

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,7 @@
import type { ErrorRequestHandler, NextFunction, Request, RequestHandler, Response, Router } from 'express'; import type { ErrorRequestHandler, RequestHandler, Router } from 'express';
import type swaggerJSDoc from 'swagger-jsdoc';
import type * as swaggerUiExpress from 'swagger-ui-express';
import type { CurrentUser } from './auth.ts'; import type { CurrentUser } from './auth.ts';
export type SwaggerDocumentOptions = swaggerJSDoc.Options;
export type SwaggerUiModuleWithHost = typeof swaggerUiExpress & {
host?: string;
};
export type ExpressRouter = Router; export type ExpressRouter = Router;
export interface HealthResponse { export interface HealthResponse {
@ -33,10 +25,6 @@ export interface MountRuntimeEntityRoute {
export type AppErrorHandler = ErrorRequestHandler; export type AppErrorHandler = ErrorRequestHandler;
export interface SwaggerHostMiddleware {
(req: Request, res: Response, next: NextFunction): void;
}
export interface PublicAccessHardeningSummary { export interface PublicAccessHardeningSummary {
publicRolePermissions: number; publicRolePermissions: number;
publicUsersWithCustomPermissions: number; publicUsersWithCustomPermissions: number;

View File

@ -131,9 +131,6 @@ export type {
PublicAccessHardeningSummary, PublicAccessHardeningSummary,
RuntimeJwtVerifyHandler, RuntimeJwtVerifyHandler,
RuntimeReadOrAuthMiddleware, RuntimeReadOrAuthMiddleware,
SwaggerDocumentOptions,
SwaggerHostMiddleware,
SwaggerUiModuleWithHost,
} from './app.ts'; } from './app.ts';
export type { export type {
EmailSendResult, EmailSendResult,

View File

@ -0,0 +1,114 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import type { NextFunction } from 'express';
import { createRequest, createResponse } from 'node-mocks-http';
import * as swaggerUI from 'swagger-ui-express';
import { createOpenApiDocument } from '../src/openapi/document.ts';
import type { OpenApiDocument } from '../src/openapi/document.ts';
function createTestDocument(): OpenApiDocument {
return createOpenApiDocument({
serverUrl: 'http://localhost:3000',
});
}
function collectRefs(value: unknown): Set<string> {
const refs = new Set<string>();
const serialized = JSON.stringify(value);
const refPattern = /"\$ref"\s*:\s*"([^"]+)"/g;
for (const match of serialized.matchAll(refPattern)) {
const ref = match[1];
if (ref) {
refs.add(ref);
}
}
return refs;
}
function hasComponentRef(document: OpenApiDocument, ref: string): boolean {
const match = /^#\/components\/(schemas|responses|parameters|securitySchemes)\/(.+)$/.exec(ref);
if (!match) return false;
const section = match[1];
const name = match[2];
if (!section || !name) return false;
switch (section) {
case 'schemas':
return name in document.components.schemas;
case 'responses':
return name in document.components.responses;
case 'parameters':
return name in document.components.parameters;
case 'securitySchemes':
return name in document.components.securitySchemes;
default:
return false;
}
}
void test('OpenAPI document exposes comprehensive route coverage', () => {
const document = createTestDocument();
const requiredPaths = [
'/api/health',
'/api/auth/signin/local',
'/api/users',
'/api/users/count',
'/api/users/autocomplete',
'/api/projects/{id}/clone',
'/api/file/presign',
'/api/file/upload-sessions/{sessionId}/chunks/{chunkIndex}',
'/api/runtime-access/me',
'/api/project-ui-control-settings/project/{projectId}/env/{environment}',
'/api/tour_pages/reverse-video-status',
];
assert.equal(document.openapi, '3.0.0');
for (const path of requiredPaths) {
assert.ok(document.paths[path], `Missing OpenAPI path: ${path}`);
}
});
void test('OpenAPI document resolves all internal refs', () => {
const document = createTestDocument();
const refs = collectRefs(document);
const missingRefs = [...refs].filter((ref) => !hasComponentRef(document, ref));
assert.equal(missingRefs.length, 0, `Missing refs: ${missingRefs.join(', ')}`);
});
void test('OpenAPI factory CRUD paths are generated consistently', () => {
const document = createTestDocument();
const resourcePath = '/api/assets';
assert.ok(document.paths[resourcePath]?.post);
assert.ok(document.paths[resourcePath]?.get);
assert.ok(document.paths[`${resourcePath}/bulk-import`]?.post);
assert.ok(document.paths[`${resourcePath}/deleteByIds`]?.post);
assert.ok(document.paths[`${resourcePath}/count`]?.get);
assert.ok(document.paths[`${resourcePath}/autocomplete`]?.get);
assert.ok(document.paths[`${resourcePath}/{id}`]?.get);
assert.ok(document.paths[`${resourcePath}/{id}`]?.put);
assert.ok(document.paths[`${resourcePath}/{id}`]?.delete);
});
void test('Swagger UI setup serves documentation HTML without throwing', () => {
const document = createTestDocument();
const req = createRequest({ url: '/api-docs/' });
const res = createResponse();
const handler = swaggerUI.setup(document);
let nextError: unknown = null;
const next: NextFunction = (error?: unknown) => {
nextError = error;
};
handler(req, res, next);
assert.equal(nextError, null);
assert.equal(res.statusCode, 200);
assert.match(String(res._getData()), /swagger-ui/);
});

View File

@ -434,9 +434,7 @@ const ConstructorToolbar = forwardRef<HTMLDivElement, ConstructorToolbarProps>(
className='h-10 w-[86px]' className='h-10 w-[86px]'
label={isSaving ? 'Saving...' : 'Save'} label={isSaving ? 'Saving...' : 'Save'}
subtitle={ subtitle={
lastSavedAt lastSavedAt ? dataFormatter.relativeTimestamp(lastSavedAt) : ' '
? dataFormatter.relativeTimestamp(lastSavedAt)
: ' '
} }
onClick={onSave} onClick={onSave}
disabled={isSaving} disabled={isSaving}

View File

@ -642,8 +642,7 @@ export function ElementEditorPanel({
<NavigationSettingsSectionCompact <NavigationSettingsSectionCompact
type={ type={
selectedElement.type as selectedElement.type as
| 'navigation_next' 'navigation_next' | 'navigation_prev'
| 'navigation_prev'
} }
navType={selectedElement.navType} navType={selectedElement.navType}
navLabel={selectedElement.navLabel || ''} navLabel={selectedElement.navLabel || ''}
@ -1310,10 +1309,7 @@ export function ElementEditorPanel({
} }
onChange={(e) => { onChange={(e) => {
const val = e.target.value as const val = e.target.value as
| 'left' 'left' | 'center' | 'right' | '';
| 'center'
| 'right'
| '';
updateSelectedElement({ updateSelectedElement({
infoPanelTitleTextAlign: val || undefined, infoPanelTitleTextAlign: val || undefined,
}); });
@ -1465,10 +1461,7 @@ export function ElementEditorPanel({
} }
onChange={(e) => { onChange={(e) => {
const val = e.target.value as const val = e.target.value as
| 'left' 'left' | 'center' | 'right' | '';
| 'center'
| 'right'
| '';
updateSelectedElement({ updateSelectedElement({
infoPanelTextTextAlign: val || undefined, infoPanelTextTextAlign: val || undefined,
}); });
@ -1639,10 +1632,7 @@ export function ElementEditorPanel({
} }
onChange={(e) => { onChange={(e) => {
const val = e.target.value as const val = e.target.value as
| 'left' 'left' | 'center' | 'right' | '';
| 'center'
| 'right'
| '';
updateSelectedElement({ updateSelectedElement({
infoPanelSpanTextAlign: val || undefined, infoPanelSpanTextAlign: val || undefined,
}); });
@ -2093,10 +2083,7 @@ export function ElementEditorPanel({
// Handle slide transition properties with proper prefixes // Handle slide transition properties with proper prefixes
if (prop === 'slideTransitionType') { if (prop === 'slideTransitionType') {
const typedValue = (value || undefined) as const typedValue = (value || undefined) as
| 'fade' 'fade' | 'none' | '' | undefined;
| 'none'
| ''
| undefined;
if (selectedElement.type === 'gallery') { if (selectedElement.type === 'gallery') {
updateSelectedElement({ updateSelectedElement({
gallerySlideTransitionType: typedValue, gallerySlideTransitionType: typedValue,

View File

@ -148,7 +148,10 @@ const StyleSettingsSection: React.FC<StyleSettingsSectionProps> = ({
max='100' max='100'
value={opacityToPercentInput(values.opacity)} value={opacityToPercentInput(values.opacity)}
onChange={(event) => onChange={(event) =>
onChange('opacity', percentInputToOpacityValue(event.target.value)) onChange(
'opacity',
percentInputToOpacityValue(event.target.value),
)
} }
placeholder='50' placeholder='50'
/> />

View File

@ -8,6 +8,8 @@ export const portApi =
: ''; : '';
export const baseURLApi = `${hostApi}${portApi ? `:${portApi}` : ``}/api`; export const baseURLApi = `${hostApi}${portApi ? `:${portApi}` : ``}/api`;
export const swaggerDocsUrl = baseURLApi.replace(/\/api\/?$/, '/api-docs');
export const localStorageDarkModeKey = 'darkMode'; export const localStorageDarkModeKey = 'darkMode';
export const localStorageStyleKey = 'style'; export const localStorageStyleKey = 'style';

View File

@ -36,8 +36,7 @@ const PageNavigationContext =
// Provider // Provider
// ============================================================================ // ============================================================================
export interface PageNavigationProviderProps export interface PageNavigationProviderProps extends UsePageNavigationStateOptions {
extends UsePageNavigationStateOptions {
children: ReactNode; children: ReactNode;
} }

View File

@ -48,10 +48,7 @@ interface PreloadQueueItem {
} }
export type PreloadPhase = export type PreloadPhase =
| 'idle' 'idle' | 'phase1_current_page' | 'phase2_transitions' | 'complete';
| 'phase1_current_page'
| 'phase2_transitions'
| 'complete';
interface UsePreloadOrchestratorResult { interface UsePreloadOrchestratorResult {
isPreloading: boolean; isPreloading: boolean;

View File

@ -47,8 +47,7 @@ export interface UseTransitionCreationOptions {
} }
export interface UseTransitionCreationResult export interface UseTransitionCreationResult
extends TransitionCreationState, extends TransitionCreationState, TransitionCreationActions {}
TransitionCreationActions {}
/** /**
* Hook to manage transition creation form state. * Hook to manage transition creation form state.

View File

@ -60,11 +60,7 @@ export interface UseTransitionPlaybackOptions {
} }
export type PlaybackPhase = export type PlaybackPhase =
| 'idle' 'idle' | 'preparing' | 'playing' | 'finishing' | 'completed';
| 'preparing'
| 'playing'
| 'finishing'
| 'completed';
export interface UseTransitionPlaybackResult { export interface UseTransitionPlaybackResult {
phase: PlaybackPhase; phase: PlaybackPhase;

View File

@ -404,11 +404,7 @@ export function toPreloadAssetInfo(asset: AssetToCache): PreloadAssetInfo {
url: asset.originalUrl, url: asset.originalUrl,
pageId: asset.pageId, pageId: asset.pageId,
assetType: assetType as assetType: assetType as
| 'image' 'image' | 'video' | 'audio' | 'transition' | 'other',
| 'video'
| 'audio'
| 'transition'
| 'other',
priority: asset.priority, priority: asset.priority,
}; };
} }

View File

@ -131,12 +131,7 @@ export function remToDesignPx(value: number): number {
export function normalizeToCanvasUnits( export function normalizeToCanvasUnits(
value: string | number | undefined, value: string | number | undefined,
property: property:
| 'width' 'width' | 'height' | 'fontSize' | 'padding' | 'borderRadius' | 'gap',
| 'height'
| 'fontSize'
| 'padding'
| 'borderRadius'
| 'gap',
designWidth: number = CANVAS_CONFIG.defaults.width, designWidth: number = CANVAS_CONFIG.defaults.width,
designHeight: number = CANVAS_CONFIG.defaults.height, designHeight: number = CANVAS_CONFIG.defaults.height,
): string { ): string {

View File

@ -266,10 +266,10 @@ export function hasHoverEffects(
): boolean { ): boolean {
return Boolean( return Boolean(
effects.hoverScale || effects.hoverScale ||
effects.hoverOpacity || effects.hoverOpacity ||
effects.hoverBackgroundColor || effects.hoverBackgroundColor ||
effects.hoverColor || effects.hoverColor ||
effects.hoverBoxShadow, effects.hoverBoxShadow,
); );
} }
@ -281,9 +281,9 @@ export function hasFocusEffects(
): boolean { ): boolean {
return Boolean( return Boolean(
effects.focusScale || effects.focusScale ||
effects.focusOpacity || effects.focusOpacity ||
effects.focusOutline || effects.focusOutline ||
effects.focusBoxShadow, effects.focusBoxShadow,
); );
} }
@ -295,8 +295,8 @@ export function hasActiveEffects(
): boolean { ): boolean {
return Boolean( return Boolean(
effects.activeScale || effects.activeScale ||
effects.activeOpacity || effects.activeOpacity ||
effects.activeBackgroundColor, effects.activeBackgroundColor,
); );
} }

View File

@ -18,11 +18,7 @@ import { toCU } from './canvasScale';
* Gallery section names for styling * Gallery section names for styling
*/ */
export type GallerySectionName = export type GallerySectionName =
| 'header' 'header' | 'title' | 'span' | 'card' | 'wrapper';
| 'title'
| 'span'
| 'card'
| 'wrapper';
/** /**
* Default values for gallery sections using canvas units. * Default values for gallery sections using canvas units.

View File

@ -1,4 +1,5 @@
import * as icon from '@mdi/js'; import * as icon from '@mdi/js';
import { swaggerDocsUrl } from './config';
import { MenuAsideItem } from './types/menu'; import { MenuAsideItem } from './types/menu';
const menuAside: MenuAsideItem[] = [ const menuAside: MenuAsideItem[] = [
@ -31,7 +32,7 @@ const menuAside: MenuAsideItem[] = [
icon: icon.mdiAccountCircle, icon: icon.mdiAccountCircle,
}, },
{ {
href: '/api-docs', href: swaggerDocsUrl,
target: '_blank', target: '_blank',
label: 'Swagger', label: 'Swagger',
icon: icon.mdiFileCode, icon: icon.mdiFileCode,

View File

@ -23,9 +23,7 @@ const ProjectsListPage = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const projectsRaw = useAppSelector((state) => state.projects.data) as const projectsRaw = useAppSelector((state) => state.projects.data) as
| Project[] Project[] | Project | undefined;
| Project
| undefined;
// Handle both array (from list fetch) and single object (after edit fetch) // Handle both array (from list fetch) and single object (after edit fetch)
const projects: Project[] = Array.isArray(projectsRaw) const projects: Project[] = Array.isArray(projectsRaw)
? projectsRaw ? projectsRaw

View File

@ -114,10 +114,7 @@ export interface CarouselSlide {
export type InfoPanelItemType = 'image' | 'video' | '360'; export type InfoPanelItemType = 'image' | 'video' | '360';
export type InfoPanelMediaOpenMode = 'panel' | 'fullscreen'; export type InfoPanelMediaOpenMode = 'panel' | 'fullscreen';
export type InfoPanelImageClickAction = export type InfoPanelImageClickAction =
| 'panel' 'panel' | 'fullscreen' | 'target_page' | 'external_url';
| 'fullscreen'
| 'target_page'
| 'external_url';
export type InfoPanelLinkClickAction = 'target_page' | 'external_url'; export type InfoPanelLinkClickAction = 'target_page' | 'external_url';
/** /**
@ -165,12 +162,7 @@ export interface InfoPanelInfoSpan {
* - 'images': Media viewer with preview + thumbnail strip * - 'images': Media viewer with preview + thumbnail strip
*/ */
export type InfoPanelSectionType = export type InfoPanelSectionType =
| 'header' 'header' | 'title' | 'text' | 'spans' | 'cards' | 'images';
| 'title'
| 'text'
| 'spans'
| 'cards'
| 'images';
/** /**
* Section instance with unique ID, settings, AND data. * Section instance with unique ID, settings, AND data.
@ -269,8 +261,7 @@ export function generateItemId(): string {
* Extends ElementStyleProperties for CSS styling and ElementEffectProperties for effects. * Extends ElementStyleProperties for CSS styling and ElementEffectProperties for effects.
*/ */
export interface BaseCanvasElement export interface BaseCanvasElement
extends ElementStyleProperties, extends ElementStyleProperties, ElementEffectProperties {
ElementEffectProperties {
id: string; id: string;
type: CanvasElementType | string; type: CanvasElementType | string;
label?: string; label?: string;

View File

@ -50,13 +50,7 @@ export interface TableColumnConfig {
valueOptions?: string[]; valueOptions?: string[];
// Custom render function name // Custom render function name
renderType?: renderType?:
| 'link' 'link' | 'boolean' | 'date' | 'datetime' | 'image' | 'actions' | 'relation';
| 'boolean'
| 'date'
| 'datetime'
| 'image'
| 'actions'
| 'relation';
// For relation columns // For relation columns
relationField?: string; relationField?: string;
} }

View File

@ -6,22 +6,13 @@
// Asset variant types matching backend model // Asset variant types matching backend model
export type AssetVariantType = export type AssetVariantType =
| 'thumbnail' 'thumbnail' | 'preview' | 'webp' | 'mp4_low' | 'mp4_high' | 'original';
| 'preview'
| 'webp'
| 'mp4_low'
| 'mp4_high'
| 'original';
export type AssetType = 'image' | 'video' | 'audio' | 'transition' | 'other'; export type AssetType = 'image' | 'video' | 'audio' | 'transition' | 'other';
// Preload job status // Preload job status
export type PreloadJobStatus = export type PreloadJobStatus =
| 'queued' 'queued' | 'downloading' | 'completed' | 'error' | 'paused';
| 'downloading'
| 'completed'
| 'error'
| 'paused';
// Download job for tracking individual asset downloads // Download job for tracking individual asset downloads
export interface PreloadJob { export interface PreloadJob {
@ -44,11 +35,7 @@ export interface PreloadJob {
// Project offline status // Project offline status
export type ProjectOfflineStatus = export type ProjectOfflineStatus =
| 'not_downloaded' 'not_downloaded' | 'downloading' | 'downloaded' | 'outdated' | 'error';
| 'downloading'
| 'downloaded'
| 'outdated'
| 'error';
// Offline project metadata // Offline project metadata
export interface OfflineProject { export interface OfflineProject {

View File

@ -92,11 +92,7 @@ export interface NavigableElement {
* Transition phase from useTransitionPlayback * Transition phase from useTransitionPlayback
*/ */
export type TransitionPhase = export type TransitionPhase =
| 'idle' 'idle' | 'preparing' | 'playing' | 'finishing' | 'completed';
| 'preparing'
| 'playing'
| 'finishing'
| 'completed';
/** /**
* Background transition options * Background transition options

View File

@ -8,13 +8,7 @@
* Color keys for general UI elements * Color keys for general UI elements
*/ */
export type ColorKey = export type ColorKey =
| 'white' 'white' | 'light' | 'contrast' | 'success' | 'danger' | 'warning' | 'info';
| 'light'
| 'contrast'
| 'success'
| 'danger'
| 'warning'
| 'info';
/** /**
* Color keys for buttons * Color keys for buttons

View File

@ -2,11 +2,7 @@ import type { BaseEntity } from './entities';
export type SystemUiControlType = 'fullscreen' | 'sound' | 'offline'; export type SystemUiControlType = 'fullscreen' | 'sound' | 'offline';
export type SystemUiControlAnchor = export type SystemUiControlAnchor =
| 'center' 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
| 'top-left'
| 'top-right'
| 'bottom-left'
| 'bottom-right';
export interface SystemUiControlSettings { export interface SystemUiControlSettings {
enabled?: boolean; enabled?: boolean;