diff --git a/package-lock.json b/package-lock.json index 75c0567..090127c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,12 +11,12 @@ "dependencies": { "@fontsource/vollkorn": "5.0.18", "@payloadcms/bundler-webpack": "1.0.6", - "@payloadcms/db-mongodb": "1.4.0", - "@payloadcms/richtext-lexical": "0.5.2", + "@payloadcms/db-mongodb": "1.4.3", + "@payloadcms/richtext-lexical": "0.7.0", "cross-env": "7.0.3", "language-tags": "1.0.9", "luxon": "3.4.4", - "payload": "2.9.0", + "payload": "2.11.2", "sharp": "0.33.2", "styled-components": "6.1.8" }, @@ -25,14 +25,14 @@ "@types/express": "4.17.21", "@types/language-tags": "1.0.4", "@types/luxon": "3.4.2", - "@types/qs": "6.9.11", + "@types/qs": "6.9.12", "@types/react-router-dom": "5.3.3", "@types/styled-components": "5.1.34", "copyfiles": "2.4.1", - "nodemon": "3.0.3", - "npm-check-updates": "16.14.14", - "prettier": "3.2.4", - "ts-node": "10.9.1", + "nodemon": "3.1.0", + "npm-check-updates": "16.14.15", + "prettier": "3.2.5", + "ts-node": "10.9.2", "ts-unused-exports": "10.0.1", "typescript": "5.3.3" } @@ -2582,183 +2582,183 @@ "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" }, "node_modules/@lexical/clipboard": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.12.6.tgz", - "integrity": "sha512-rJFp7tXzawCrMWWRsjCR80dZoIkLJ/EPgPmTk3xqpc+9ntlwbkm3LUOdFmgN+pshnhiZTQBwbFqg/QbsA1Pw9g==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.13.1.tgz", + "integrity": "sha512-gMSbVeqb7S+XAi/EMMlwl+FCurLPugN2jAXcp5k5ZaUd7be8B+iupbYdoKkjt4qBhxmvmfe9k46GoC0QOPl/nw==", "dependencies": { - "@lexical/html": "0.12.6", - "@lexical/list": "0.12.6", - "@lexical/selection": "0.12.6", - "@lexical/utils": "0.12.6" + "@lexical/html": "0.13.1", + "@lexical/list": "0.13.1", + "@lexical/selection": "0.13.1", + "@lexical/utils": "0.13.1" }, "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/code": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.12.6.tgz", - "integrity": "sha512-D0IBKLzDFfVqk+3KPlJd2gWIq+h5QOsVn5Atz/Eh2eLRpOakSsZiRjmddsijoLsZbvgo1HObRPQAoeATRPWIzg==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.13.1.tgz", + "integrity": "sha512-QK77r3QgEtJy96ahYXNgpve8EY64BQgBSnPDOuqVrLdl92nPzjqzlsko2OZldlrt7gjXcfl9nqfhZ/CAhStfOg==", "dependencies": { - "@lexical/utils": "0.12.6", + "@lexical/utils": "0.13.1", "prismjs": "^1.27.0" }, "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/dragon": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.12.6.tgz", - "integrity": "sha512-VKbXzdtF6qizwESx7Zag/VGiYKMAc+xpJF7tcwv5SH8I4bnseoozafzxRG6AE7J9nzGwO74ypKqPmmpP9e20BA==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.13.1.tgz", + "integrity": "sha512-aNlqfif4//jW7gOxbBgdrbDovU6m3EwQrUw+Y/vqRkY+sWmloyAUeNwCPH1QP3Q5cvfolzOeN5igfBljsFr+1g==", "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/hashtag": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.12.6.tgz", - "integrity": "sha512-SiEId/IBIqUKJJKGg8HSumalfKGxtZQJRkF7Q50FqFSU906V1lcM1jkU7aVw0hiuEHg3H+vFBmNTRdXKyoibsw==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.13.1.tgz", + "integrity": "sha512-Dl0dUG4ZXNjYYuAUR0GMGpLGsA+cps2/ln3xEmy28bZR0sKkjXugsu2QOIxZjYIPBewDrXzPcvK8md45cMYoSg==", "dependencies": { - "@lexical/utils": "0.12.6" + "@lexical/utils": "0.13.1" }, "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/headless": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/headless/-/headless-0.12.6.tgz", - "integrity": "sha512-FDyN9FRvWqWUrMp3vzQAH+KngYLxwAfSjinhf40D+r4Y5OxgU7rpYBBBeQ5n6H+Zr1YvkIRFnTmOdqlKUcm3/g==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/headless/-/headless-0.13.1.tgz", + "integrity": "sha512-W2mLUuWPrsyf2n73NWM8nKiBI11lEpVVzKE0OzMsjTskv5+AAMaeu1wQ7M1508vKdCcUZwA6AOh3To/hstLEpw==", "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/history": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.12.6.tgz", - "integrity": "sha512-3vvbUF6XHuk/9985IQIXP15g+nr7SlwsPrd2IteOg6aNF+HeE2ttJS5dOiSJLnVZm+AX0OMgejMC1uU2uiZOtA==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.13.1.tgz", + "integrity": "sha512-cZXt30MalEEiRaflE9tHeGYnwT1xSDjXLsf9M409DSU9POJyZ1fsULJrG1tWv2uFQOhwal33rve9+MatUlITrg==", "dependencies": { - "@lexical/utils": "0.12.6" + "@lexical/utils": "0.13.1" }, "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/html": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.12.6.tgz", - "integrity": "sha512-HVlJLCkazLbLpxdw0mwMkteQuv6OMkJTlAi6qGJimtuqJLm45BpaQ16PTpUmFWpWeIHL2XpvcDX/lj5fm68XPA==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.13.1.tgz", + "integrity": "sha512-XkZrnCSHIUavtpMol6aG8YsJ5KqC9hMxEhAENf3HTGi3ocysCByyXOyt1EhEYpjJvgDG4wRqt25xGDbLjj1/sA==", "dependencies": { - "@lexical/selection": "0.12.6", - "@lexical/utils": "0.12.6" + "@lexical/selection": "0.13.1", + "@lexical/utils": "0.13.1" }, "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/link": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.12.6.tgz", - "integrity": "sha512-mrFFWR0EZ9liRUzHZqb2ijUDZqkCM+bNsyYqLh4I1CrJpzQtakyIEJt/GzYz4IHmmsRqwcc2zXUP/4kENjjPlQ==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.13.1.tgz", + "integrity": "sha512-7E3B2juL2UoMj2n+CiyFZ7tlpsdViAoIE7MpegXwfe/VQ66wFwk/VxGTa/69ng2EoF7E0kh+SldvGQDrWAWb1g==", "dependencies": { - "@lexical/utils": "0.12.6" + "@lexical/utils": "0.13.1" }, "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/list": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.12.6.tgz", - "integrity": "sha512-9DFe8vpSxZ8NQZ/67ZFNiRptB3XPa7mUl0Rmd5WpbJHJHmiORyngYkYgKOW56T/TCtYcLfkTbctMhsIt8OeIqQ==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.13.1.tgz", + "integrity": "sha512-6U1pmNZcKLuOWiWRML8Raf9zSEuUCMlsOye82niyF6I0rpPgYo5UFghAAbGISDsyqzM1B2L4BgJ6XrCk/dJptg==", "dependencies": { - "@lexical/utils": "0.12.6" + "@lexical/utils": "0.13.1" }, "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/mark": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.12.6.tgz", - "integrity": "sha512-utk6kgTSTuzmM0+B4imGTGwC4gQRCQ4hHEZTVbkIDbONvjbo9g6xfbTO9g6Qxs2h7Zt0Q2eDA7RG4nwC3vN1KQ==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.13.1.tgz", + "integrity": "sha512-dW27PW8wWDOKFqXTBUuUfV+umU0KfwvXGkPUAxRJrvwUWk5RKaS48LhgbNlQ5BfT84Q8dSiQzvbaa6T40t9a3A==", "dependencies": { - "@lexical/utils": "0.12.6" + "@lexical/utils": "0.13.1" }, "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/markdown": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.12.6.tgz", - "integrity": "sha512-q1cQ4w6KYxUF1N6nGwJTZwn8szLo0kbr8DzI62samZTxeztA0ByMSZLzvO5LSGhgeDremuWx5oa97s2qJMQZFw==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.13.1.tgz", + "integrity": "sha512-6tbdme2h5Zy/M88loVQVH5G0Nt7VMR9UUkyiSaicyBRDOU2OHacaXEp+KSS/XuF+d7TA+v/SzyDq8HS77cO1wA==", "dependencies": { - "@lexical/code": "0.12.6", - "@lexical/link": "0.12.6", - "@lexical/list": "0.12.6", - "@lexical/rich-text": "0.12.6", - "@lexical/text": "0.12.6", - "@lexical/utils": "0.12.6" + "@lexical/code": "0.13.1", + "@lexical/link": "0.13.1", + "@lexical/list": "0.13.1", + "@lexical/rich-text": "0.13.1", + "@lexical/text": "0.13.1", + "@lexical/utils": "0.13.1" }, "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/offset": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.12.6.tgz", - "integrity": "sha512-5NgIaWCvMuOQNf3SZSNn459QfsN7SmLl+Tu4ISqxyZRoMV5Sfojzion9MjCVmt1YSsIS4B29NYQvGQ/li1saOw==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.13.1.tgz", + "integrity": "sha512-j/RZcztJ7dyTrfA2+C3yXDzWDXV+XmMpD5BYeQCEApaHvlo20PHt1BISk7RcrnQW8PdzGvpKblRWf//c08LS9w==", "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/overflow": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.12.6.tgz", - "integrity": "sha512-4TZJhTGkn7xvR+rumSYW9U/OIsbith0kVGOvZZf+DM/t9fb0IVQWWSWmMlXJ5XNt/qXLFof3HFyJhK84dsN3NA==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.13.1.tgz", + "integrity": "sha512-Uw34j+qG2UJRCIR+bykfFMduFk7Pc4r/kNt8N1rjxGuGXAsreTVch1iOhu7Ev6tJgkURsduKuaJCAi7iHnKl7g==", "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/plain-text": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.12.6.tgz", - "integrity": "sha512-YF+EaWGQIxR1SHgeSuPrrqqSK8RYDxGv9RYyuIPvWXpt3M9NWw7hyAn7zxmXGgv2BhIicyHGPy5CyQgt3Mkb/w==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.13.1.tgz", + "integrity": "sha512-4j5KAsMKUvJ8LhVDSS4zczbYXzdfmgYSAVhmqpSnJtud425Nk0TAfpUBLFoivxZB7KMoT1LGWQZvd47IvJPvtA==", "peerDependencies": { - "@lexical/clipboard": "0.12.6", - "@lexical/selection": "0.12.6", - "@lexical/utils": "0.12.6", - "lexical": "0.12.6" + "@lexical/clipboard": "0.13.1", + "@lexical/selection": "0.13.1", + "@lexical/utils": "0.13.1", + "lexical": "0.13.1" } }, "node_modules/@lexical/react": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.12.6.tgz", - "integrity": "sha512-Pto4wsVwrnY94tzcCXP2kWukQejSRPDfwOPd+EFh8dUzj+L7fa9Pze2wVgCRZpEohwfbcgAdEsvmSbhz+yGkog==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.13.1.tgz", + "integrity": "sha512-Sy6EL230KAb0RZsZf1dZrRrc3+rvCDQWltcd8C/cqBUYlxsLYCW9s4f3RB2werngD/PtLYbBB48SYXNkIALITA==", "dependencies": { - "@lexical/clipboard": "0.12.6", - "@lexical/code": "0.12.6", - "@lexical/dragon": "0.12.6", - "@lexical/hashtag": "0.12.6", - "@lexical/history": "0.12.6", - "@lexical/link": "0.12.6", - "@lexical/list": "0.12.6", - "@lexical/mark": "0.12.6", - "@lexical/markdown": "0.12.6", - "@lexical/overflow": "0.12.6", - "@lexical/plain-text": "0.12.6", - "@lexical/rich-text": "0.12.6", - "@lexical/selection": "0.12.6", - "@lexical/table": "0.12.6", - "@lexical/text": "0.12.6", - "@lexical/utils": "0.12.6", - "@lexical/yjs": "0.12.6", + "@lexical/clipboard": "0.13.1", + "@lexical/code": "0.13.1", + "@lexical/dragon": "0.13.1", + "@lexical/hashtag": "0.13.1", + "@lexical/history": "0.13.1", + "@lexical/link": "0.13.1", + "@lexical/list": "0.13.1", + "@lexical/mark": "0.13.1", + "@lexical/markdown": "0.13.1", + "@lexical/overflow": "0.13.1", + "@lexical/plain-text": "0.13.1", + "@lexical/rich-text": "0.13.1", + "@lexical/selection": "0.13.1", + "@lexical/table": "0.13.1", + "@lexical/text": "0.13.1", + "@lexical/utils": "0.13.1", + "@lexical/yjs": "0.13.1", "react-error-boundary": "^3.1.4" }, "peerDependencies": { - "lexical": "0.12.6", + "lexical": "0.13.1", "react": ">=17.x", "react-dom": ">=17.x" } @@ -2779,65 +2779,65 @@ } }, "node_modules/@lexical/rich-text": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.12.6.tgz", - "integrity": "sha512-fRZHy2ug6Pq+pJK7trr9phTGaD2ba3If8o36dphOsl27MtUllpz68lcXL6mUonzJhAu4um1e9u7GFR3dLp+cVA==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.13.1.tgz", + "integrity": "sha512-HliB9Ync06mv9DBg/5j0lIsTJp+exLHlaLJe+n8Zq1QNTzZzu2LsIT/Crquk50In7K/cjtlaQ/d5RB0LkjMHYg==", "peerDependencies": { - "@lexical/clipboard": "0.12.6", - "@lexical/selection": "0.12.6", - "@lexical/utils": "0.12.6", - "lexical": "0.12.6" + "@lexical/clipboard": "0.13.1", + "@lexical/selection": "0.13.1", + "@lexical/utils": "0.13.1", + "lexical": "0.13.1" } }, "node_modules/@lexical/selection": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.12.6.tgz", - "integrity": "sha512-HJBEazVwOe6duyHV6+vB/MS4kUBlCV05Cfcigdx8HlLLFQRWPqHrTpaxKz4jfb9ar0SlI2W1BUNbySAxMkC/HQ==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.13.1.tgz", + "integrity": "sha512-Kt9eSwjxPznj7yzIYipu9yYEgmRJhHiq3DNxHRxInYcZJWWNNHum2xKyxwwcN8QYBBzgfPegfM/geqQEJSV1lQ==", "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/table": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.12.6.tgz", - "integrity": "sha512-rUh9/fN831T6UpNiPuzx0x6HNi/eQ7W5AQrVBwwzEwkbwAqnE0n28DP924AUbX72UsQNHtywgmDApMoEV7W2iQ==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.13.1.tgz", + "integrity": "sha512-VQzgkfkEmnvn6C64O/kvl0HI3bFoBh3WA/U67ALw+DS11Mb5CKjbt0Gzm/258/reIxNMpshjjicpWMv9Miwauw==", "dependencies": { - "@lexical/utils": "0.12.6" + "@lexical/utils": "0.13.1" }, "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/text": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.12.6.tgz", - "integrity": "sha512-WfqfH9gvPAx9Hi9wrJDWECdvt6turPQXImCRI657LVfsP2hHh4eHpcSnd3YYH313pv98HPWmeMstBbEieYwTpQ==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.13.1.tgz", + "integrity": "sha512-NYy3TZKt3qzReDwN2Rr5RxyFlg84JjXP2JQGMrXSSN7wYe73ysQIU6PqdVrz4iZkP+w34F3pl55dJ24ei3An9w==", "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/utils": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.12.6.tgz", - "integrity": "sha512-hK5r/TD2nH5TfWSiCxy7/lh0s11qJcI1wo++PBQOR9o937pQ+/Zr/1tMOc8MnrTpl89mtmYtPfWW3f++HH1Yog==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.13.1.tgz", + "integrity": "sha512-AtQQKzYymkbOaQxaBXjRBS8IPxF9zWQnqwHTUTrJqJ4hX71aIQd/thqZbfQETAFJfC8pNBZw5zpxN6yPHk23dQ==", "dependencies": { - "@lexical/list": "0.12.6", - "@lexical/selection": "0.12.6", - "@lexical/table": "0.12.6" + "@lexical/list": "0.13.1", + "@lexical/selection": "0.13.1", + "@lexical/table": "0.13.1" }, "peerDependencies": { - "lexical": "0.12.6" + "lexical": "0.13.1" } }, "node_modules/@lexical/yjs": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.12.6.tgz", - "integrity": "sha512-I/Yf/Qm8/ydU983kWpFBlDFNFQXLYur5uaAimTSBcJuqHmy3cv1xM7Xrq4BtM+0orKgWJt8vR8cLVIU9sAmzfw==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.13.1.tgz", + "integrity": "sha512-4GbqQM+PwNTV59AZoNrfTe/0rLjs+cX6Y6yAdZSRPBwr5L3JzYeU1TTcFCVQTtsE7KF8ddVP8sD7w9pi8rOWLA==", "dependencies": { - "@lexical/offset": "0.12.6" + "@lexical/offset": "0.13.1" }, "peerDependencies": { - "lexical": "0.12.6", + "lexical": "0.13.1", "yjs": ">=13.5.22" } }, @@ -3083,9 +3083,9 @@ } }, "node_modules/@payloadcms/db-mongodb": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@payloadcms/db-mongodb/-/db-mongodb-1.4.0.tgz", - "integrity": "sha512-9DVazhkV5+T2+NpIvIDMZ3AmJScjkj7r8OPwrz3BBvXXKid2NUDewTKFQSVtqWK6Ed5ArlvCAlk9J6zO3Q0+cA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@payloadcms/db-mongodb/-/db-mongodb-1.4.3.tgz", + "integrity": "sha512-EOqxE8XOuICkxBqCwPkAj/NiIT5GxbYG7uocUGNvw5icZkZSAT88YD4dipZISP4Ft8QQ7EUJsjqeRali8oLtCw==", "dependencies": { "bson-objectid": "2.0.4", "deepmerge": "4.3.1", @@ -3110,29 +3110,30 @@ } }, "node_modules/@payloadcms/richtext-lexical": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@payloadcms/richtext-lexical/-/richtext-lexical-0.5.2.tgz", - "integrity": "sha512-7FU/zDL+KRLdqE/zDsEDuRQx27ZYe7RPadVCW5hRy7aqke5+68rN/kACrLW0NiW2v90XXTHiDkUYmYAb+DRh5Q==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@payloadcms/richtext-lexical/-/richtext-lexical-0.7.0.tgz", + "integrity": "sha512-3ZrX+vsNdPYi6QYDMlssfR+ikmwdXSVXdcfC+iiEd8kg3++NErLeOFwaJY8i9YSuxES/WnDuLU934sUZfcniyQ==", "dependencies": { "@faceless-ui/modal": "2.0.1", - "@lexical/headless": "0.12.6", - "@lexical/link": "0.12.6", - "@lexical/list": "0.12.6", - "@lexical/mark": "0.12.6", - "@lexical/markdown": "0.12.6", - "@lexical/react": "0.12.6", - "@lexical/rich-text": "0.12.6", - "@lexical/selection": "0.12.6", - "@lexical/utils": "0.12.6", + "@lexical/headless": "0.13.1", + "@lexical/link": "0.13.1", + "@lexical/list": "0.13.1", + "@lexical/mark": "0.13.1", + "@lexical/markdown": "0.13.1", + "@lexical/react": "0.13.1", + "@lexical/rich-text": "0.13.1", + "@lexical/selection": "0.13.1", + "@lexical/utils": "0.13.1", "bson-objectid": "2.0.4", "classnames": "^2.3.2", "deep-equal": "2.2.3", "i18next": "22.5.1", - "lexical": "0.12.6", + "json-schema": "^0.4.0", + "lexical": "0.13.1", "lodash": "4.17.21", "react": "18.2.0", "react-dom": "18.2.0", - "react-error-boundary": "^4.0.11", + "react-error-boundary": "4.0.12", "react-i18next": "11.18.6", "ts-essentials": "7.0.3" }, @@ -3882,11 +3883,14 @@ } }, "node_modules/@swc/core": { - "version": "1.3.78", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.78.tgz", - "integrity": "sha512-y6DQP571v7fbUUY7nz5G4lNIRGofuO48K5pGhD9VnuOCTuptfooCdi8wnigIrIhM/M4zQ53m/YCMDCbOtDgEww==", + "version": "1.3.107", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.107.tgz", + "integrity": "sha512-zKhqDyFcTsyLIYK1iEmavljZnf4CCor5pF52UzLAz4B6Nu/4GLU+2LQVAf+oRHjusG39PTPjd2AlRT3f3QWfsQ==", "hasInstallScript": true, - "peer": true, + "dependencies": { + "@swc/counter": "^0.1.1", + "@swc/types": "^0.1.5" + }, "engines": { "node": ">=10" }, @@ -3895,16 +3899,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.78", - "@swc/core-darwin-x64": "1.3.78", - "@swc/core-linux-arm-gnueabihf": "1.3.78", - "@swc/core-linux-arm64-gnu": "1.3.78", - "@swc/core-linux-arm64-musl": "1.3.78", - "@swc/core-linux-x64-gnu": "1.3.78", - "@swc/core-linux-x64-musl": "1.3.78", - "@swc/core-win32-arm64-msvc": "1.3.78", - "@swc/core-win32-ia32-msvc": "1.3.78", - "@swc/core-win32-x64-msvc": "1.3.78" + "@swc/core-darwin-arm64": "1.3.107", + "@swc/core-darwin-x64": "1.3.107", + "@swc/core-linux-arm-gnueabihf": "1.3.107", + "@swc/core-linux-arm64-gnu": "1.3.107", + "@swc/core-linux-arm64-musl": "1.3.107", + "@swc/core-linux-x64-gnu": "1.3.107", + "@swc/core-linux-x64-musl": "1.3.107", + "@swc/core-win32-arm64-msvc": "1.3.107", + "@swc/core-win32-ia32-msvc": "1.3.107", + "@swc/core-win32-x64-msvc": "1.3.107" }, "peerDependencies": { "@swc/helpers": "^0.5.0" @@ -3916,9 +3920,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.76", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.76.tgz", - "integrity": "sha512-ovviEhZ/1E81Z9OGrO0ivLWk4VCa3I3ZzM+cd3gugglRRwVwtlIaoIYqY5S3KiCAupDd1+UCl5X7Vbio7a/V8g==", + "version": "1.3.107", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.107.tgz", + "integrity": "sha512-47tD/5vSXWxPd0j/ZllyQUg4bqalbQTsmqSw0J4dDdS82MWqCAwUErUrAZPRjBkjNQ6Kmrf5rpCWaGTtPw+ngw==", "cpu": [ "arm64" ], @@ -3931,9 +3935,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.3.76", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.76.tgz", - "integrity": "sha512-tcySTDqs0SHCebtW35sCdcLWsmTEo7bEwx0gNL/spetqVT9fpFi6qU8qcnt7i2KaZHbeNl9g1aadu+Yrni+GzA==", + "version": "1.3.107", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.107.tgz", + "integrity": "sha512-hwiLJ2ulNkBGAh1m1eTfeY1417OAYbRGcb/iGsJ+LuVLvKAhU/itzsl535CvcwAlt2LayeCFfcI8gdeOLeZa9A==", "cpu": [ "x64" ], @@ -3946,9 +3950,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.76", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.76.tgz", - "integrity": "sha512-apgzpGWy1AwoMF4urAAASsAjE7rEzZFIF+p6utuxhS7cNHzE0AyEVDYJbo+pzBdlZ8orBdzzsHtFwoEgKOjebA==", + "version": "1.3.107", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.107.tgz", + "integrity": "sha512-I2wzcC0KXqh0OwymCmYwNRgZ9nxX7DWnOOStJXV3pS0uB83TXAkmqd7wvMBuIl9qu4Hfomi9aDM7IlEEn9tumQ==", "cpu": [ "arm" ], @@ -3961,9 +3965,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.76", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.76.tgz", - "integrity": "sha512-c3c0zz6S0eludqidDpuqbadE0WT3OZczyQxe9Vw8lFFXES85mvNGtwYzyGK2o7TICpsuHrndwDIoYpmpWk879g==", + "version": "1.3.107", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.107.tgz", + "integrity": "sha512-HWgnn7JORYlOYnGsdunpSF8A+BCZKPLzLtEUA27/M/ZuANcMZabKL9Zurt7XQXq888uJFAt98Gy+59PU90aHKg==", "cpu": [ "arm64" ], @@ -3976,9 +3980,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.76", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.76.tgz", - "integrity": "sha512-Is3bpq7F2qtlnkzEeOD6HIZJPpOmu3q6c82lKww90Q0NnrlSluVMozTHJgwVoFZyizH7uLnk0LuNcEAWLnmJIw==", + "version": "1.3.107", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.107.tgz", + "integrity": "sha512-vfPF74cWfAm8hyhS8yvYI94ucMHIo8xIYU+oFOW9uvDlGQRgnUf/6DEVbLyt/3yfX5723Ln57U8uiMALbX5Pyw==", "cpu": [ "arm64" ], @@ -3991,9 +3995,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.78", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.78.tgz", - "integrity": "sha512-iDxa+RknnTQlyy+WfPor1FM6y44ERNI2E0xiUV6gV6uPwegCngi8LFC+E7IvP6+p+yXtAkesunAaiZ8nn0s+rw==", + "version": "1.3.107", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.107.tgz", + "integrity": "sha512-uBVNhIg0ip8rH9OnOsCARUFZ3Mq3tbPHxtmWk9uAa5u8jQwGWeBx5+nTHpDOVd3YxKb6+5xDEI/edeeLpha/9g==", "cpu": [ "x64" ], @@ -4001,15 +4005,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=10" } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.78", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.78.tgz", - "integrity": "sha512-dWtIYUFL5sMTE2UKshkXTusHcK8+zAhhGzvqWq1wJS45pqTlrAbzpyqB780fle880x3A6DMitWmsAFARdNzpuQ==", + "version": "1.3.107", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.107.tgz", + "integrity": "sha512-mvACkUvzSIB12q1H5JtabWATbk3AG+pQgXEN95AmEX2ZA5gbP9+B+mijsg7Sd/3tboHr7ZHLz/q3SHTvdFJrEw==", "cpu": [ "x64" ], @@ -4017,15 +4020,14 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=10" } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.76", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.76.tgz", - "integrity": "sha512-+swEFtjdMezS0vKUhJC3psdSDtOJGY5pEOt4e8XOPvn7aQpKQ9LfF49XVtIwDSk5SGuWtVoLFzkSY3reWUJCyg==", + "version": "1.3.107", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.107.tgz", + "integrity": "sha512-J3P14Ngy/1qtapzbguEH41kY109t6DFxfbK4Ntz9dOWNuVY3o9/RTB841ctnJk0ZHEG+BjfCJjsD2n8H5HcaOA==", "cpu": [ "arm64" ], @@ -4038,9 +4040,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.76", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.76.tgz", - "integrity": "sha512-5CqwAykpGBJ3PqGLOlWGLGIPpBAG1IwWVDUfro3hhjQ7XJxV5Z1aQf5V5OJ90HJVtrEAVx2xx59UV/Dh081LOg==", + "version": "1.3.107", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.107.tgz", + "integrity": "sha512-ZBUtgyjTHlz8TPJh7kfwwwFma+ktr6OccB1oXC8fMSopD0AxVnQasgun3l3099wIsAB9eEsJDQ/3lDkOLs1gBA==", "cpu": [ "ia32" ], @@ -4053,9 +4055,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.76", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.76.tgz", - "integrity": "sha512-CiMpWLLlR3Cew9067E7XxaLBwYYJ90r9EhGSO6V1pvYSWj7ET/Ppmtj1ZhzPJMqRXAP6xflfl5R5o4ee1m4WLA==", + "version": "1.3.107", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.107.tgz", + "integrity": "sha512-Eyzo2XRqWOxqhE1gk9h7LWmUf4Bp4Xn2Ttb0ayAXFp6YSTxQIThXcT9kipXZqcpxcmDwoq8iWbbf2P8XL743EA==", "cpu": [ "x64" ], @@ -4067,133 +4069,10 @@ "node": ">=10" } }, - "node_modules/@swc/core/node_modules/@swc/core-darwin-arm64": { - "version": "1.3.78", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.78.tgz", - "integrity": "sha512-596KRua/d5Gx1buHKKchSyHuwoIL4S1BRD/wCvYNLNZ3xOzcuBBmXOjrDVigKi1ztNDeS07p30RO5UyYur0XAA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core/node_modules/@swc/core-darwin-x64": { - "version": "1.3.78", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.78.tgz", - "integrity": "sha512-w0RsD1onQAj0vuLAoOVi48HgnW6D6oBEIZP17l0HYejCDBZ+FRZLjml7wgNAWMqHcd2qNRqgtZ+v7aLza2JtBQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core/node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.78", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.78.tgz", - "integrity": "sha512-v1CpRn+H6fha1WIqmdRvJM40pFdjUHrGfhf4Ygci72nlAU41l5XimN8Iwkm8FgIwf2wnv0lLzedSM4IHvpq/yA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core/node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.78", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.78.tgz", - "integrity": "sha512-Sis17dz9joJRFVvR/gteOZSUNrrrioo81RQzani0Zr5ZZOfWLMTB9DA+0MVlfnVa2taYcsJHJZFoAv9JkLwbzg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core/node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.78", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.78.tgz", - "integrity": "sha512-E5F8/qp+QupnfBnsP4vN1PKyCmAHYHDG1GMyPE/zLFOUYLgw+jK4C9rfyLBR0o2bWo1ay2WCIjusBZD9XHGOSA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core/node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.78", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.78.tgz", - "integrity": "sha512-CXFaGEc2M9Su3UoUMC8AnzKb9g+GwPxXfakLWZsjwS448h6jcreExq3nwtBNdVGzQ26xqeVLMFfb1l/oK99Hwg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core/node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.78", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.78.tgz", - "integrity": "sha512-FaH1jwWnJpWkdImpMoiZpMg9oy9UUyZwltzN7hFwjR48e3Li82cRFb+9PifIBHCUSBM+CrrsJXbHP213IMVAyw==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core/node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.78", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.78.tgz", - "integrity": "sha512-oYxa+tPdhlx1aH14AIoF6kvVjo49tEOW0drNqoEaVHufvgH0y43QU2Jum3b2+xXztmMRtzK2CSN3GPOAXDKKKg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=10" - } + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" }, "node_modules/@swc/register": { "version": "0.1.10", @@ -4211,6 +4090,11 @@ "@swc/core": "^1.0.46" } }, + "node_modules/@swc/types": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", + "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==" + }, "node_modules/@szmarczak/http-timer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", @@ -4514,9 +4398,9 @@ "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/qs": { - "version": "6.9.11", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", - "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", + "version": "6.9.12", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.12.tgz", + "integrity": "sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==", "dev": true }, "node_modules/@types/range-parser": { @@ -9452,6 +9336,11 @@ "jju": "^1.1.0" } }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, "node_modules/json-schema-to-typescript": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-11.0.3.tgz", @@ -9657,14 +9546,14 @@ } }, "node_modules/lexical": { - "version": "0.12.6", - "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.12.6.tgz", - "integrity": "sha512-Nlfjc+k9cIWpOMv7XufF0Mv09TAXSemNAuAqFLaOwTcN+RvhvYTDtVLSp9D9r+5I097fYs1Vf/UYwH2xEpkFfQ==" + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.13.1.tgz", + "integrity": "sha512-jaqRYzVEfBKbX4FwYpd/g+MyOjRaraAel0iQsTrwvx3hyN0bswUZuzb6H6nGlFSjcdrc77wKpyKwoWj4aUd+Bw==" }, "node_modules/lib0": { - "version": "0.2.88", - "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.88.tgz", - "integrity": "sha512-KyroiEvCeZcZEMx5Ys+b4u4eEBbA1ch7XUaBhYpwa/nPMrzTjUhI4RfcytmQfYoTBPcdyx+FX6WFNIoNuJzJfQ==", + "version": "0.2.89", + "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.89.tgz", + "integrity": "sha512-5j19vcCjsQhvLG6mcDD+nprtJUCbmqLz5Hzt5xgi9SV6RIW/Dty7ZkVZHGBuPOADMKjQuKDvuQTH495wsmw8DQ==", "peer": true, "dependencies": { "isomorphic.js": "^0.2.4" @@ -9964,11 +9853,6 @@ "node": ">= 0.6" } }, - "node_modules/micro-memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/micro-memoize/-/micro-memoize-4.1.2.tgz", - "integrity": "sha512-+HzcV2H+rbSJzApgkj0NdTakkC+bnyeiUxgT6/m7mjcz1CmM22KYFKp+EVj1sWe4UYcnriJr5uqHQD/gMHLD+g==" - }, "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -10594,9 +10478,9 @@ } }, "node_modules/nodemon": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz", - "integrity": "sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", + "integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -10746,9 +10630,9 @@ } }, "node_modules/npm-check-updates": { - "version": "16.14.14", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.14.tgz", - "integrity": "sha512-Y3ajS/Ep40jM489rLBdz9jehn/BMil5s9fA4PSr2ZJxxSmtLWCSmRqsI2IEZ9Nb3MTMu8a3s7kBs0l+JbjdkTA==", + "version": "16.14.15", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.15.tgz", + "integrity": "sha512-WH0wJ9j6CP7Azl+LLCxWAYqroT2IX02kRIzgK/fg0rPpMbETgHITWBdOPtrv521xmA3JMgeNsQ62zvVtS/nCmQ==", "dev": true, "dependencies": { "chalk": "^5.3.0", @@ -11512,9 +11396,9 @@ "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, "node_modules/payload": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/payload/-/payload-2.9.0.tgz", - "integrity": "sha512-C8QekOUOh1689qWWrCLNXhgC5K1LnKYFmFEru/GxhQBEO6SFEULdQHMnmjP1yrHARu1eVU24UdFVniKY+9oR7A==", + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/payload/-/payload-2.11.2.tgz", + "integrity": "sha512-UaruSsw7nFOzLurBjPWIHiDzGuTIGEK5UrEEfHagJnYe6xUP3/cg44qD+RQNb5D1FkV7x/B+ha8Ci7YVdz9eAA==", "dependencies": { "@date-io/date-fns": "2.16.0", "@dnd-kit/core": "6.0.8", @@ -11523,7 +11407,7 @@ "@faceless-ui/scroll-info": "1.3.0", "@faceless-ui/window-info": "2.1.1", "@monaco-editor/react": "4.5.1", - "@swc/core": "1.3.76", + "@swc/core": "1.3.107", "@swc/register": "0.1.10", "body-parser": "1.20.2", "body-scroll-lock": "4.0.0-beta.0", @@ -11565,7 +11449,6 @@ "jwt-decode": "3.1.2", "md5": "2.3.0", "method-override": "3.0.0", - "micro-memoize": "4.1.2", "minimist": "1.2.8", "mkdirp": "1.0.4", "monaco-editor": "0.38.0", @@ -11613,69 +11496,6 @@ "node": ">=14" } }, - "node_modules/payload/node_modules/@swc/core": { - "version": "1.3.76", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.76.tgz", - "integrity": "sha512-aYYTA2aVYkwJAZepQXtPnkUthhOfn8qd6rsh+lrJxonFrjmpI7RHt2tMDVTXP6XDX7fvnvrVtT1bwZfmBFPh0Q==", - "hasInstallScript": true, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.76", - "@swc/core-darwin-x64": "1.3.76", - "@swc/core-linux-arm-gnueabihf": "1.3.76", - "@swc/core-linux-arm64-gnu": "1.3.76", - "@swc/core-linux-arm64-musl": "1.3.76", - "@swc/core-linux-x64-gnu": "1.3.76", - "@swc/core-linux-x64-musl": "1.3.76", - "@swc/core-win32-arm64-msvc": "1.3.76", - "@swc/core-win32-ia32-msvc": "1.3.76", - "@swc/core-win32-x64-msvc": "1.3.76" - }, - "peerDependencies": { - "@swc/helpers": "^0.5.0" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } - } - }, - "node_modules/payload/node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.76", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.76.tgz", - "integrity": "sha512-iwCeRzd9oSvUzqt7nU6p/ztceAWfnO9XVxBn502R5gs6QCBbE1HCKrWHDO77aKPK7ss+0NcIGHvXTd9L8/wRzw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/payload/node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.76", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.76.tgz", - "integrity": "sha512-a671g4tW8kyFeuICsgq4uB9ukQfiIyXJT4V6YSnmqhCTz5mazWuDxZ5wKnx/1g5nXTl+U5cWH2TZaCJatp4GKA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, "node_modules/payload/node_modules/body-scroll-lock": { "version": "4.0.0-beta.0", "resolved": "https://registry.npmjs.org/body-scroll-lock/-/body-scroll-lock-4.0.0-beta.0.tgz", @@ -13208,9 +13028,9 @@ } }, "node_modules/prettier": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz", - "integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -13654,9 +13474,9 @@ } }, "node_modules/react-error-boundary": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.11.tgz", - "integrity": "sha512-U13ul67aP5DOSPNSCWQ/eO0AQEYzEFkVljULQIjMV0KlffTAhxuDoBKdO0pb/JZ8mDhMKFZ9NZi0BmLGUiNphw==", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.12.tgz", + "integrity": "sha512-kJdxdEYlb7CPC1A0SeUY38cHpjuu6UkvzKiAmqmOFL21VRfMhOcWxTCBgLVCO0VEMh9JhFNcVaXlV4/BTpiwOA==", "dependencies": { "@babel/runtime": "^7.12.5" }, @@ -15694,9 +15514,9 @@ } }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -16771,9 +16591,9 @@ } }, "node_modules/yjs": { - "version": "13.6.10", - "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.10.tgz", - "integrity": "sha512-1JcyQek1vaMyrDm7Fqfa+pvHg/DURSbVo4VmeN7wjnTKB/lZrfIPhdCj7d8sboK6zLfRBJXegTjc9JlaDd8/Zw==", + "version": "13.6.12", + "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.12.tgz", + "integrity": "sha512-KOT8ILoyVH2f/PxPadeu5kVVS055D1r3x1iFfJVJzFdnN98pVGM8H07NcKsO+fG3F7/0tf30Vnokf5YIqhU/iw==", "peer": true, "dependencies": { "lib0": "^0.2.86" diff --git a/package.json b/package.json index f28cc9f..8a0d125 100644 --- a/package.json +++ b/package.json @@ -24,12 +24,12 @@ "dependencies": { "@fontsource/vollkorn": "5.0.18", "@payloadcms/bundler-webpack": "1.0.6", - "@payloadcms/db-mongodb": "1.4.0", - "@payloadcms/richtext-lexical": "0.5.2", + "@payloadcms/db-mongodb": "1.4.3", + "@payloadcms/richtext-lexical": "0.7.0", "cross-env": "7.0.3", "language-tags": "1.0.9", "luxon": "3.4.4", - "payload": "2.9.0", + "payload": "2.11.2", "sharp": "0.33.2", "styled-components": "6.1.8" }, @@ -38,14 +38,14 @@ "@types/express": "4.17.21", "@types/language-tags": "1.0.4", "@types/luxon": "3.4.2", - "@types/qs": "6.9.11", + "@types/qs": "6.9.12", "@types/react-router-dom": "5.3.3", "@types/styled-components": "5.1.34", "copyfiles": "2.4.1", - "nodemon": "3.0.3", - "npm-check-updates": "16.14.14", - "prettier": "3.2.4", - "ts-node": "10.9.1", + "nodemon": "3.1.0", + "npm-check-updates": "16.14.15", + "prettier": "3.2.5", + "ts-node": "10.9.2", "ts-unused-exports": "10.0.1", "typescript": "5.3.3" } diff --git a/src/blocks/lineBlock.ts b/src/blocks/lineBlock.ts index e5e36f0..74a86dd 100644 --- a/src/blocks/lineBlock.ts +++ b/src/blocks/lineBlock.ts @@ -1,5 +1,6 @@ import { Block } from "payload/types"; import { createEditor } from "../utils/editor"; +import { cueBlock } from "./cueBlock"; export const lineBlock: Block = { slug: "lineBlock", @@ -14,7 +15,7 @@ export const lineBlock: Block = { admin: { className: "reduced-margins", }, - editor: createEditor({ inlines: true, lists: true, links: true }), + editor: createEditor({ inlines: true, lists: true, links: true, blocks: [cueBlock] }), }, ], }; diff --git a/src/collections/ChronologyEras/endpoints/getAllEndpoint.ts b/src/collections/ChronologyEras/endpoints/getAllEndpoint.ts index 438adad..da8cf5d 100644 --- a/src/collections/ChronologyEras/endpoints/getAllEndpoint.ts +++ b/src/collections/ChronologyEras/endpoints/getAllEndpoint.ts @@ -28,7 +28,7 @@ export const getAllEndpoint: CollectionEndpoint = { const eras: ChronologyEra[] = ( await payload.find({ collection: Collections.ChronologyEras, - limit: 100, + pagination: false, }) ).docs; diff --git a/src/collections/Contents/Contents.ts b/src/collections/Contents/Contents.ts index 3398425..5a68f43 100644 --- a/src/collections/Contents/Contents.ts +++ b/src/collections/Contents/Contents.ts @@ -1,12 +1,13 @@ +import { Where } from "payload/types"; import { sectionBlock } from "../../blocks/sectionBlock"; import { transcriptBlock } from "../../blocks/transcriptBlock"; -import { CollectionGroups, Collections, FileTypes, KeysTypes } from "../../constants"; +import { CollectionGroups, Collections, FileTypes } from "../../constants"; import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; import { fileField } from "../../fields/fileField/fileField"; import { imageField } from "../../fields/imageField/imageField"; -import { keysField } from "../../fields/keysField/keysField"; import { rowField } from "../../fields/rowField/rowField"; import { slugField } from "../../fields/slugField/slugField"; +import { tagsField } from "../../fields/tagsField/tagsField"; import { translatedFields } from "../../fields/translatedFields/translatedFields"; import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping"; @@ -14,14 +15,13 @@ import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish"; import { isDefined } from "../../utils/asserts"; import { createEditor } from "../../utils/editor"; import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig"; +import { getBySlugEndpoint } from "./endpoints/getBySlugEndpoint"; import { importFromStrapi } from "./endpoints/importFromStrapi"; import { importRelationsFromStrapi } from "./endpoints/importRelationsFromStrapi"; const fields = { slug: "slug", thumbnail: "thumbnail", - categories: "categories", - type: "type", translations: "translations", pretitle: "pretitle", title: "title", @@ -42,6 +42,7 @@ const fields = { nextContents: "nextContents", folders: "folders", libraryItems: "libraryItems", + tags: "tags", } as const satisfies Record; export const Contents = buildVersionedCollectionConfig({ @@ -55,14 +56,7 @@ export const Contents = buildVersionedCollectionConfig({ useAsTitle: fields.slug, description: "All the contents (textual, audio, and video) from the Library or other online sources.", - defaultColumns: [ - fields.thumbnail, - fields.slug, - fields.categories, - fields.type, - fields.translations, - fields.status, - ], + defaultColumns: [fields.thumbnail, fields.slug, fields.translations, fields.status], group: CollectionGroups.Collections, hooks: { beforeDuplicate: beforeDuplicatePiping([ @@ -71,7 +65,7 @@ export const Contents = buildVersionedCollectionConfig({ ]), }, }, - endpoints: [importFromStrapi, importRelationsFromStrapi], + endpoints: [importFromStrapi, importRelationsFromStrapi, getBySlugEndpoint], fields: [ rowField([ slugField({ name: fields.slug }), @@ -80,23 +74,7 @@ export const Contents = buildVersionedCollectionConfig({ relationTo: Collections.ContentsThumbnails, }), ]), - rowField([ - keysField({ - name: fields.categories, - relationTo: KeysTypes.Categories, - hasMany: true, - }), - keysField({ - name: fields.type, - relationTo: KeysTypes.Contents, - }), - backPropagationField({ - name: fields.libraryItems, - hasMany: true, - relationTo: Collections.LibraryItems, - where: ({ id }) => ({ "contents.content": { equals: id } }), - }), - ]), + tagsField({ name: fields.tags }), translatedFields({ name: fields.translations, admin: { useAsTitle: fields.title, hasSourceLanguage: true }, @@ -217,19 +195,30 @@ export const Contents = buildVersionedCollectionConfig({ rowField([ backPropagationField({ name: fields.folders, + relationTo: Collections.Folders, hasMany: true, - relationTo: Collections.ContentsFolders, - where: ({ id }) => ({ contents: { equals: id } }), - admin: { - description: `You can set the folder(s) from the "Contents Folders" collection`, - }, + where: ({ id }) => ({ + and: [ + { "files.value": { equals: id } }, + { "files.relationTo": { equals: Collections.Contents } }, + ] as Where[], + }), }), + backPropagationField({ + name: fields.libraryItems, + hasMany: true, + relationTo: Collections.LibraryItems, + where: ({ id }) => ({ "contents.content": { equals: id } }), + }), + ]), + rowField([ backPropagationField({ name: fields.previousContents, relationTo: Collections.Contents, hasMany: true, where: ({ id }) => ({ [fields.nextContents]: { equals: id } }), }), + { name: fields.nextContents, type: "relationship", diff --git a/src/collections/Contents/endpoints/getBySlugEndpoint.ts b/src/collections/Contents/endpoints/getBySlugEndpoint.ts new file mode 100644 index 0000000..3cb8428 --- /dev/null +++ b/src/collections/Contents/endpoints/getBySlugEndpoint.ts @@ -0,0 +1,50 @@ +import { Collections } from "../../../constants"; +import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; +import { EndpointContent } from "../../../sdk"; +import { Content } from "../../../types/collections"; +import { isPayloadArrayType, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; +import { convertTagsToGroups } from "../../../utils/tags"; + +export const getBySlugEndpoint = createGetByEndpoint( + Collections.Contents, + "slug", + ({ thumbnail, slug, translations, tags }: Content): EndpointContent => ({ + slug, + ...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}), + tagGroups: convertTagsToGroups(tags), + translations: translations.map((translation) => { + const { language, sourceLanguage, title, subtitle, pretitle, summary } = translation; + const text = handleTextContent(translation); + + return { + language: isPayloadType(language) ? language.id : language, + sourceLanguage: isPayloadType(sourceLanguage) ? sourceLanguage.id : sourceLanguage, + ...(pretitle ? { pretitle } : {}), + title, + ...(subtitle ? { subtitle } : {}), + ...(summary ? { summary } : {}), + format: { ...(text ? { text } : {}) }, + }; + }), + }) +); + + +const handleTextContent = ({ + textContent, + textNotes, + textProofreaders, + textTranscribers, + textTranslators, +}: Content["translations"][number]): EndpointContent["translations"][number]["format"]["text"] => { + if (!textContent) return undefined; + + return { + content: textContent, + toc: [], + translators: isPayloadArrayType(textTranslators) ? textTranslators.map(({ id }) => id) : [], + transcribers: isPayloadArrayType(textTranscribers) ? textTranscribers.map(({ id }) => id) : [], + proofreaders: isPayloadArrayType(textProofreaders) ? textProofreaders.map(({ id }) => id) : [], + ...(textNotes ? { notes: textNotes } : {}), + }; +}; diff --git a/src/collections/ContentsFolders/ContentsFolders.ts b/src/collections/ContentsFolders/ContentsFolders.ts deleted file mode 100644 index 895fb70..0000000 --- a/src/collections/ContentsFolders/ContentsFolders.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { CollectionGroups, Collections } from "../../constants"; -import { rowField } from "../../fields/rowField/rowField"; -import { slugField } from "../../fields/slugField/slugField"; -import { translatedFields } from "../../fields/translatedFields/translatedFields"; -import { buildCollectionConfig } from "../../utils/collectionConfig"; -import { importFromStrapi } from "./endpoints/importFromStrapi"; - -const fields = { - slug: "slug", - translations: "translations", - name: "name", - subfolders: "subfolders", - contents: "contents", -} as const satisfies Record; - -export const ContentsFolders = buildCollectionConfig({ - slug: Collections.ContentsFolders, - labels: { - singular: "Contents Folder", - plural: "Contents Folders", - }, - defaultSort: fields.slug, - admin: { - useAsTitle: fields.slug, - defaultColumns: [fields.slug, fields.translations], - disableDuplicate: true, - group: CollectionGroups.Collections, - }, - endpoints: [importFromStrapi], - timestamps: false, - versions: false, - fields: [ - slugField({ name: fields.slug }), - translatedFields({ - name: fields.translations, - admin: { - useAsTitle: fields.name, - }, - fields: [{ name: fields.name, type: "text", required: true }], - }), - rowField([ - { - type: "relationship", - name: fields.subfolders, - relationTo: Collections.ContentsFolders, - hasMany: true, - }, - { - type: "relationship", - name: fields.contents, - relationTo: Collections.Contents, - hasMany: true, - }, - ]), - ], -}); diff --git a/src/collections/ContentsFolders/endpoints/importFromStrapi.ts b/src/collections/ContentsFolders/endpoints/importFromStrapi.ts deleted file mode 100644 index 0240982..0000000 --- a/src/collections/ContentsFolders/endpoints/importFromStrapi.ts +++ /dev/null @@ -1,125 +0,0 @@ -import payload from "payload"; -import QueryString from "qs"; -import { Collections } from "../../../constants"; -import { CollectionEndpoint } from "../../../types/payload"; -import { StrapiLanguage } from "../../../types/strapi"; -import { isUndefined } from "../../../utils/asserts"; -import { findContent } from "../../../utils/localApi"; - -type StrapiContentsFolder = { - id: string; - attributes: { - slug: string; - titles?: { title: string; language: StrapiLanguage }[]; - subfolders: { data: StrapiContentsFolder[] }; - contents: { data: { attributes: { slug: string } }[] }; - }; -}; - -const getStrapiContentFolder = async (id: number): Promise => { - const paramsWithPagination = QueryString.stringify({ - populate: [ - "contents", - "subfolders", - "subfolders.contents", - "subfolders.titles", - "subfolders.titles.language", - "subfolders.subfolders", - "subfolders.subfolders.contents", - "subfolders.subfolders.titles", - "subfolders.subfolders.titles.language", - "subfolders.subfolders.subfolders", - "subfolders.subfolders.subfolders.contents", - "subfolders.subfolders.subfolders.titles", - "subfolders.subfolders.subfolders.titles.language", - "subfolders.subfolders.subfolders.subfolders", - "subfolders.subfolders.subfolders.subfolders.contents", - "subfolders.subfolders.subfolders.subfolders.titles", - "subfolders.subfolders.subfolders.subfolders.titles.language", - "subfolders.subfolders.subfolders.subfolders.subfolders", - "subfolders.subfolders.subfolders.subfolders.subfolders.contents", - "subfolders.subfolders.subfolders.subfolders.subfolders.titles", - "subfolders.subfolders.subfolders.subfolders.subfolders.titles.language", - "subfolders.subfolders.subfolders.subfolders.subfolders.subfolders", - "subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.contents", - "subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.titles", - "subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.titles.language", - "subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.subfolders", - "subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.contents", - "subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.titles", - "subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.subfolders.titles.language", - ], - }); - const uri = `${process.env.STRAPI_URI}/api/contents-folders/${id}?${paramsWithPagination}`; - const fetchResult = await fetch(uri, { - method: "get", - headers: { authorization: `Bearer ${process.env.STRAPI_TOKEN}` }, - }); - const { data } = await fetchResult.json(); - return data; -}; - -export const importFromStrapi: CollectionEndpoint = { - method: "post", - path: "/strapi", - handler: async (req, res) => { - if (!req.user) { - return res.status(403).send({ - errors: [ - { - message: "You are not allowed to perform this action.", - }, - ], - }); - } - - let foldersCreated = 0; - const errors: string[] = []; - - const createContentFolder = async (data: StrapiContentsFolder): Promise => { - const { slug, titles } = data.attributes; - - const subfolders = await Promise.all( - data.attributes.subfolders.data.map(createContentFolder) - ); - - const contents: string[] = []; - for (const content of data.attributes.contents.data) { - try { - const result = await findContent(content.attributes.slug); - contents.push(result); - } catch (e) { - errors.push(`Couldn't add ${content.attributes.slug} to folder ${slug}`); - } - } - - const result = await payload.create({ - collection: Collections.ContentsFolders, - data: { - slug, - subfolders, - contents, - translations: titles?.map(({ title, language }) => { - if (isUndefined(language.data)) - throw new Error("A language is required for a content folder translation"); - return { language: language.data.attributes.code, name: title }; - }), - }, - user: req.user, - }); - foldersCreated++; - return result.id; - }; - - const rootFolder = await getStrapiContentFolder(72); - try { - await createContentFolder(rootFolder); - } catch (e) { - res.status(500).json({ message: "Something went wrong", error: e }); - } - - res - .status(200) - .json({ message: `${foldersCreated} entries have been added successfully.`, errors }); - }, -}; diff --git a/src/collections/Currencies/endpoints/getAllEndpoint.ts b/src/collections/Currencies/endpoints/getAllEndpoint.ts index d1981e0..28811cd 100644 --- a/src/collections/Currencies/endpoints/getAllEndpoint.ts +++ b/src/collections/Currencies/endpoints/getAllEndpoint.ts @@ -20,11 +20,11 @@ export const getAllEndpoint: CollectionEndpoint = { const currencies: Currency[] = ( await payload.find({ collection: Collections.Currencies, - limit: 100, - sort: "id" + sort: "id", + pagination: false, }) ).docs; - res.status(200).header("Cache-Control", "max-age=60").json(currencies); + res.status(200).json(currencies); }, }; diff --git a/src/collections/Folders/Folders.ts b/src/collections/Folders/Folders.ts index d1999c5..032ca15 100644 --- a/src/collections/Folders/Folders.ts +++ b/src/collections/Folders/Folders.ts @@ -83,7 +83,7 @@ export const Folders = buildCollectionConfig({ { type: "relationship", name: fields.files, - relationTo: [Collections.LibraryItems, Collections.Contents], + relationTo: [Collections.LibraryItems, Collections.Contents, Collections.Pages], hasMany: true, }, ], diff --git a/src/collections/Folders/endpoints/getBySlugEndpoint.ts b/src/collections/Folders/endpoints/getBySlugEndpoint.ts index 8cb686a..4186815 100644 --- a/src/collections/Folders/endpoints/getBySlugEndpoint.ts +++ b/src/collections/Folders/endpoints/getBySlugEndpoint.ts @@ -1,8 +1,8 @@ import { Collections } from "../../../constants"; import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; -import { EndpointFolder, EndpointFolderPreview, PayloadImage } from "../../../sdk"; -import { Folder, FoldersThumbnail, Language } from "../../../types/collections"; -import { isDefined, isUndefined, isValidPayloadImage } from "../../../utils/asserts"; +import { EndpointFolder, EndpointFolderPreview } from "../../../sdk"; +import { Folder, Language } from "../../../types/collections"; +import { isDefined, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; export const getBySlugEndpoint = createGetByEndpoint( Collections.Folders, @@ -15,7 +15,7 @@ export const getBySlugEndpoint = createGetByEndpoint( ? { type: "single", subfolders: - folder.sections[0]?.subfolders?.filter(isValidFolder).map(convertFolderToPreview) ?? + folder.sections[0]?.subfolders?.filter(isPayloadType).map(convertFolderToPreview) ?? [], } : { @@ -29,6 +29,20 @@ export const getBySlugEndpoint = createGetByEndpoint( subfolders: subfolders.map(convertFolderToPreview), })) ?? [], }, + files: + folder.files?.flatMap(({ relationTo, value }) => { + if (!isPayloadType(value)) { + return []; + } + switch (relationTo) { + case "contents": + return [{ relationTo, value }]; + case "library-items": + return [{ relationTo, value }]; + case "pages": + return [{ relationTo, value }]; + } + }) ?? [], }; } ); @@ -47,10 +61,10 @@ export const convertFolderToPreview = ({ translations?.map(({ language, name, description }) => ({ language: getLanguageId(language), name, - description: JSON.stringify(description), + ...(description ? { description } : {}), })) ?? [], - darkThumbnail: getThumbnail(darkThumbnail), - lightThumbnail: getThumbnail(lightThumbnail), + darkThumbnail: isValidPayloadImage(darkThumbnail) ? darkThumbnail : undefined, + lightThumbnail: isValidPayloadImage(lightThumbnail) ? lightThumbnail : undefined, }; }; @@ -77,19 +91,7 @@ const isValidSection = (section: { if (!section.subfolders) { return false; } - return section.subfolders.every(isValidFolder); -}; - -export const isValidFolder = (folder: string | Folder): folder is Folder => - typeof folder !== "string"; - -const getThumbnail = ( - thumbnail: string | FoldersThumbnail | null | undefined -): PayloadImage | undefined => { - if (isUndefined(thumbnail)) return undefined; - if (typeof thumbnail === "string") return undefined; - if (!isValidPayloadImage(thumbnail)) return undefined; - return thumbnail; + return section.subfolders.every(isPayloadType); }; const getLanguageId = (language: string | Language) => diff --git a/src/collections/Folders/endpoints/rootEndpoint.ts b/src/collections/Folders/endpoints/rootEndpoint.ts index 158fd4b..3ffd030 100644 --- a/src/collections/Folders/endpoints/rootEndpoint.ts +++ b/src/collections/Folders/endpoints/rootEndpoint.ts @@ -2,7 +2,8 @@ import payload from "payload"; import { Collections } from "../../../constants"; import { EndpointFolderPreview } from "../../../sdk"; import { CollectionEndpoint } from "../../../types/payload"; -import { convertFolderToPreview, isValidFolder } from "./getBySlugEndpoint"; +import { isPayloadType } from "../../../utils/asserts"; +import { convertFolderToPreview } from "./getBySlugEndpoint"; export const getRootFoldersEndpoint: CollectionEndpoint = { @@ -39,7 +40,7 @@ export const getRootFoldersEndpoint: CollectionEndpoint = { return; } - const result = folders.filter(isValidFolder).map(convertFolderToPreview); + const result = folders.filter(isPayloadType).map(convertFolderToPreview); res.status(200).json(result); }, diff --git a/src/collections/FoldersThumbnails/FoldersThumbnails.ts b/src/collections/FoldersThumbnails/FoldersThumbnails.ts index 3eab1db..5cafae8 100644 --- a/src/collections/FoldersThumbnails/FoldersThumbnails.ts +++ b/src/collections/FoldersThumbnails/FoldersThumbnails.ts @@ -16,18 +16,7 @@ export const FoldersThumbnails = buildImageCollectionConfig({ }, admin: { defaultColumns: [fields.filename, fields.updatedAt] }, upload: { - imageSizes: [ - { - name: "medium", - height: 400, - width: 200, - fit: "contain", - formatOptions: { - format: "webp", - options: { effort: 6, quality: 80, alphaQuality: 80 }, - }, - }, - ], + imageSizes: [], }, fields: [], }); diff --git a/src/collections/Images/Images.ts b/src/collections/Images/Images.ts new file mode 100644 index 0000000..be9b3d7 --- /dev/null +++ b/src/collections/Images/Images.ts @@ -0,0 +1,33 @@ +import { Collections } from "../../constants"; +import { buildImageCollectionConfig } from "../../utils/imageCollectionConfig"; + +const fields = { + filename: "filename", + mimeType: "mimeType", + filesize: "filesize", + posts: "posts", + updatedAt: "updatedAt", +} as const satisfies Record; + +export const Images = buildImageCollectionConfig({ + slug: Collections.Images, + labels: { + singular: "Image", + plural: "Images", + }, + admin: { defaultColumns: [fields.filename, fields.posts, fields.updatedAt] }, + upload: { + imageSizes: [ + { + name: "og", + height: 750, + width: 1125, + formatOptions: { + format: "jpg", + options: { progressive: true, mozjpeg: true, compressionLevel: 9, quality: 60 }, + }, + }, + ], + }, + fields: [], +}); diff --git a/src/collections/Keys/Keys.ts b/src/collections/Keys/Keys.ts index d77a375..1b9ae63 100644 --- a/src/collections/Keys/Keys.ts +++ b/src/collections/Keys/Keys.ts @@ -8,6 +8,7 @@ import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; import { Key } from "../../types/collections"; import { isDefined, isUndefined } from "../../utils/asserts"; import { buildCollectionConfig } from "../../utils/collectionConfig"; +import { getAllEndpoint } from "./endpoints/getAllEndpoint"; import { importFromStrapi } from "./endpoints/importFromStrapi"; const fields = { @@ -74,7 +75,7 @@ export const Keys = buildCollectionConfig({ }, ], }, - endpoints: [importFromStrapi], + endpoints: [importFromStrapi, getAllEndpoint], timestamps: false, versions: false, fields: [ diff --git a/src/collections/Keys/endpoints/getAllEndpoint.ts b/src/collections/Keys/endpoints/getAllEndpoint.ts new file mode 100644 index 0000000..39bd7e4 --- /dev/null +++ b/src/collections/Keys/endpoints/getAllEndpoint.ts @@ -0,0 +1,42 @@ +import payload from "payload"; +import { Collections } from "../../../constants"; +import { EndpointKey } from "../../../sdk"; +import { Key } from "../../../types/collections"; +import { CollectionEndpoint } from "../../../types/payload"; +import { isPayloadType } from "../../../utils/asserts"; + +export const getAllEndpoint: CollectionEndpoint = { + method: "get", + path: "/all", + handler: async (req, res) => { + if (!req.user) { + return res.status(403).send({ + errors: [ + { + message: "You are not allowed to perform this action.", + }, + ], + }); + } + + const keys: Key[] = ( + await payload.find({ + collection: Collections.Keys, + sort: "id", + pagination: false, + }) + ).docs; + + const result: EndpointKey[] = keys.map(({ translations, ...others }) => ({ + ...others, + translations: + translations?.map(({ language, name, short }) => ({ + language: isPayloadType(language) ? language.id : language, + name, + short: short ?? name, + })) ?? [], + })); + + res.status(200).json(result); + }, +}; diff --git a/src/collections/Languages/endpoints/getAllEndpoint.ts b/src/collections/Languages/endpoints/getAllEndpoint.ts index 015177a..8c95684 100644 --- a/src/collections/Languages/endpoints/getAllEndpoint.ts +++ b/src/collections/Languages/endpoints/getAllEndpoint.ts @@ -20,8 +20,8 @@ export const getAllEndpoint: CollectionEndpoint = { const languages: Language[] = ( await payload.find({ collection: Collections.Languages, - limit: 100, - sort: "name" + sort: "name", + pagination: false, }) ).docs; diff --git a/src/collections/Pages/Pages.ts b/src/collections/Pages/Pages.ts new file mode 100644 index 0000000..fd8dd64 --- /dev/null +++ b/src/collections/Pages/Pages.ts @@ -0,0 +1,215 @@ +import { Where } from "payload/types"; +import { sectionBlock } from "../../blocks/sectionBlock"; +import { QuickFilters, publishStatusFilters } from "../../components/QuickFilters"; +import { CollectionGroups, Collections, PageType } from "../../constants"; +import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; +import { imageField } from "../../fields/imageField/imageField"; +import { rowField } from "../../fields/rowField/rowField"; +import { slugField } from "../../fields/slugField/slugField"; +import { tagsField } from "../../fields/tagsField/tagsField"; +import { translatedFields } from "../../fields/translatedFields/translatedFields"; +import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; +import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping"; +import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish"; +import { isDefined, isUndefined } from "../../utils/asserts"; +import { createEditor } from "../../utils/editor"; +import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig"; +import { getBySlugEndpoint } from "./endpoints/getBySlugEndpoint"; + +const fields = { + slug: "slug", + type: "type", + authors: "authors", + thumbnail: "thumbnail", + translations: "translations", + tags: "tags", + sourceLanguage: "sourceLanguage", + pretitle: "pretitle", + title: "title", + subtitle: "subtitle", + summary: "summary", + content: "content", + transcribers: "transcribers", + translators: "translators", + proofreaders: "proofreaders", + collectibles: "collectibles", + folders: "folders", +} as const satisfies Record; + +const pageTypesWithAuthor = [PageType.Article]; +const pageTypesWithCollectibles = [PageType.Content]; +const pageTypesWithTranscribers = [PageType.Content]; + +export const Pages = buildVersionedCollectionConfig({ + slug: Collections.Pages, + labels: { + singular: "Page", + plural: "Pages", + }, + defaultSort: fields.slug, + admin: { + useAsTitle: fields.slug, + defaultColumns: [fields.thumbnail, fields.slug], + group: CollectionGroups.Collections, + components: { + BeforeListTable: [ + () => + QuickFilters({ + slug: Collections.Posts, + filterGroups: [publishStatusFilters], + }), + ], + }, + hooks: { + beforeDuplicate: beforeDuplicatePiping([ + beforeDuplicateUnpublish, + beforeDuplicateAddCopyTo(fields.slug), + ]), + }, + }, + endpoints: [getBySlugEndpoint], + fields: [ + { + name: fields.type, + type: "radio", + required: true, + defaultValue: PageType.Generic, + options: Object.entries(PageType).map(([value, label]) => ({ label, value })), + }, + rowField([ + slugField({ name: fields.slug }), + imageField({ + name: fields.thumbnail, + relationTo: Collections.Images, + }), + ]), + rowField([ + tagsField({ name: fields.tags }), + { + name: fields.authors, + type: "relationship", + admin: { + condition: (_, siblingData) => pageTypesWithAuthor.includes(siblingData[fields.type]), + }, + relationTo: Collections.Recorders, + required: true, + minRows: 1, + hasMany: true, + }, + ]), + translatedFields({ + name: fields.translations, + admin: { useAsTitle: fields.title, hasSourceLanguage: true }, + required: true, + minRows: 1, + fields: [ + rowField([ + { name: fields.pretitle, type: "text" }, + { name: fields.title, type: "text", required: true }, + { name: fields.subtitle, type: "text" }, + ]), + { + name: fields.summary, + type: "richText", + editor: createEditor({ inlines: true, lists: true, links: true }), + }, + { + name: fields.content, + type: "richText", + required: true, + editor: createEditor({ + images: true, + inlines: true, + alignment: true, + blocks: [sectionBlock], + links: true, + lists: true, + }), + }, + rowField([ + { + name: fields.transcribers, + type: "relationship", + relationTo: Collections.Recorders, + hasMany: true, + admin: { + condition: (data, siblingData) => { + if (!pageTypesWithTranscribers.includes(data[fields.type])) { + return false; + } + if (isUndefined(siblingData.language) || isUndefined(siblingData.sourceLanguage)) { + return false; + } + return siblingData.language === siblingData.sourceLanguage; + }, + }, + }, + { + name: fields.translators, + type: "relationship", + relationTo: Collections.Recorders, + hasMany: true, + hooks: { + beforeChange: [ + ({ siblingData }) => { + if (siblingData.language === siblingData.sourceLanguage) { + delete siblingData.translators; + } + }, + ], + }, + admin: { + condition: (_, siblingData) => { + if (isUndefined(siblingData.language) || isUndefined(siblingData.sourceLanguage)) { + return false; + } + return siblingData.language !== siblingData.sourceLanguage; + }, + }, + validate: (translators, { siblingData }) => { + if (isUndefined(siblingData.language) || isUndefined(siblingData.sourceLanguage)) { + return true; + } + if (siblingData.language === siblingData.sourceLanguage) { + return true; + } + if (isDefined(translators) && translators.length > 0) { + return true; + } + return "This field is required when the language is different from the source language."; + }, + }, + { + name: fields.proofreaders, + type: "relationship", + relationTo: Collections.Recorders, + hasMany: true, + }, + ]), + ], + }), + rowField([ + backPropagationField({ + name: fields.folders, + relationTo: Collections.Folders, + hasMany: true, + where: ({ id }) => ({ + and: [ + { "files.value": { equals: id } }, + { "files.relationTo": { equals: Collections.Pages } }, + ] as Where[], + }), + }), + backPropagationField({ + name: fields.collectibles, + hasMany: true, + relationTo: Collections.LibraryItems, + admin: { + condition: (_, siblingData) => + pageTypesWithCollectibles.includes(siblingData[fields.type]), + }, + where: ({ id }) => ({ "contents.content": { equals: id } }), + }), + ]), + ], +}); diff --git a/src/collections/Pages/endpoints/getBySlugEndpoint.ts b/src/collections/Pages/endpoints/getBySlugEndpoint.ts new file mode 100644 index 0000000..32d1c88 --- /dev/null +++ b/src/collections/Pages/endpoints/getBySlugEndpoint.ts @@ -0,0 +1,134 @@ +import { + Collections, + PageType, + RichTextContent, + isBlockNodeSectionBlock, + isNodeBlockNode, +} from "../../../constants"; +import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; +import { EndpointPage, ParentPage, TableOfContentEntry } from "../../../sdk"; +import { Page } from "../../../types/collections"; +import { isPayloadArrayType, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; +import { convertTagsToGroups } from "../../../utils/tags"; + +export const getBySlugEndpoint = createGetByEndpoint( + Collections.Pages, + "slug", + ({ + authors, + slug, + translations, + tags, + thumbnail, + _status, + collectibles, + folders, + type, + }: Page): EndpointPage => ({ + slug, + type: type as PageType, + ...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}), + tagGroups: convertTagsToGroups(tags), + translations: translations.map( + ({ + content, + language, + sourceLanguage, + title, + pretitle, + subtitle, + proofreaders, + summary, + transcribers, + translators, + }) => ({ + language: isPayloadType(language) ? language.id : language, + sourceLanguage: isPayloadType(sourceLanguage) ? sourceLanguage.id : sourceLanguage, + ...(pretitle ? { pretitle } : {}), + title, + ...(subtitle ? { subtitle } : {}), + ...(summary ? { summary } : {}), + content: handleContent(content), + toc: handleToc(content), + translators: isPayloadArrayType(translators) ? translators.map(({ id }) => id) : [], + transcribers: isPayloadArrayType(transcribers) ? transcribers.map(({ id }) => id) : [], + proofreaders: isPayloadArrayType(proofreaders) ? proofreaders.map(({ id }) => id) : [], + }) + ), + authors: isPayloadArrayType(authors) ? authors.map(({ id }) => id) : [], + status: _status === "published" ? "published" : "draft", + parentPages: handleParentPages({ collectibles, folders }), + }) +); + +const handleContent = ( + { root: { children, ...others } }: RichTextContent, + parentPrefix = "" +): RichTextContent => { + let sectionCount = 0; + return { + root: { + ...others, + children: children.map((node) => { + if (isNodeBlockNode(node) && isBlockNodeSectionBlock(node)) { + sectionCount++; + const anchorHash = `${parentPrefix}${sectionCount}.`; + return { + ...node, + fields: { + ...node.fields, + anchorHash, + lines: handleContent(node.fields.lines, anchorHash), + }, + }; + } + return node; + }), + }, + }; +}; + +const handleToc = (content: RichTextContent, parentPrefix = ""): TableOfContentEntry[] => + content.root.children + .filter(isNodeBlockNode) + .filter(isBlockNodeSectionBlock) + .map(({ fields }, index) => ({ + prefix: `${parentPrefix}${index + 1}.`, + title: fields.blockName, + children: handleToc(fields.lines, `${index + 1}.`), + })); + +const handleParentPages = ({ + collectibles, + folders, +}: Pick): ParentPage[] => { + const result: ParentPage[] = []; + + if (collectibles && isPayloadArrayType(collectibles)) { + collectibles.forEach(({ slug, title }) => { + result.push({ + collection: Collections.LibraryItems, + slug, + translations: [{ language: "en", name: title }], + tag: "collectible", + }); + }); + } + + if (folders && isPayloadArrayType(folders)) { + folders.forEach(({ slug, translations }) => { + result.push({ + collection: Collections.Folders, + slug, + translations: + translations?.map(({ language, name }) => ({ + language: isPayloadType(language) ? language.id : language, + name, + })) ?? [], + tag: "folders", + }); + }); + } + + return result; +}; diff --git a/src/collections/Recorders/Recorders.ts b/src/collections/Recorders/Recorders.ts index 308aae1..37f66ec 100644 --- a/src/collections/Recorders/Recorders.ts +++ b/src/collections/Recorders/Recorders.ts @@ -8,6 +8,7 @@ import { rowField } from "../../fields/rowField/rowField"; import { translatedFields } from "../../fields/translatedFields/translatedFields"; import { buildCollectionConfig } from "../../utils/collectionConfig"; import { createEditor } from "../../utils/editor"; +import { getAllEndpoint } from "./endpoints/getAllEndpoint"; import { importFromStrapi } from "./endpoints/importFromStrapi"; import { beforeLoginMustHaveAtLeastOneRole } from "./hooks/beforeLoginMustHaveAtLeastOneRole"; @@ -75,7 +76,7 @@ export const Recorders = buildCollectionConfig({ hooks: { beforeLogin: [beforeLoginMustHaveAtLeastOneRole], }, - endpoints: [importFromStrapi], + endpoints: [importFromStrapi, getAllEndpoint], timestamps: false, fields: [ rowField([ diff --git a/src/collections/Recorders/endpoints/getAllEndpoint.ts b/src/collections/Recorders/endpoints/getAllEndpoint.ts new file mode 100644 index 0000000..f13a852 --- /dev/null +++ b/src/collections/Recorders/endpoints/getAllEndpoint.ts @@ -0,0 +1,45 @@ +import payload from "payload"; +import { Collections } from "../../../constants"; +import { EndpointRecorder } from "../../../sdk"; +import { CollectionEndpoint } from "../../../types/payload"; +import { isPayloadArrayType, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; + +export const getAllEndpoint: CollectionEndpoint = { + method: "get", + path: "/all", + handler: async (req, res) => { + if (!req.user) { + return res.status(403).send({ + errors: [ + { + message: "You are not allowed to perform this action.", + }, + ], + }); + } + + const recorders = ( + await payload.find({ + collection: Collections.Recorders, + sort: "id", + pagination: false, + }) + ).docs; + + const result: EndpointRecorder[] = recorders.map( + ({ anonymize, id, username, avatar, biographies, languages }) => ({ + id, + username: anonymize ? `Recorder#${id.substring(0, 5)}` : username, + ...(isValidPayloadImage(avatar) ? { avatar } : {}), + languages: isPayloadArrayType(languages) ? languages.map(({ id }) => id) : [], + biographies: + biographies?.map(({ biography, language }) => ({ + language: isPayloadType(language) ? language.id : language, + biography, + })) ?? [], + }) + ); + + res.status(200).json(result); + }, +}; diff --git a/src/collections/Tags/Tags.ts b/src/collections/Tags/Tags.ts new file mode 100644 index 0000000..aaa52e7 --- /dev/null +++ b/src/collections/Tags/Tags.ts @@ -0,0 +1,56 @@ +import payload from "payload"; +import { CollectionBeforeChangeHook, CollectionConfig } from "payload/types"; +import { CollectionGroups, Collections } from "../../constants"; +import { slugField } from "../../fields/slugField/slugField"; +import { translatedFields } from "../../fields/translatedFields/translatedFields"; +import { buildCollectionConfig } from "../../utils/collectionConfig"; +import { getAllEndpoint } from "./endpoints/getAllEndpoint"; + +const beforeChangeUpdateName: CollectionBeforeChangeHook = async ({ data }) => { + let name = data.slug; + + const parentId = data[fields.group]; + + if (parentId) { + const parent = await payload.findByID({ + collection: Collections.TagsGroups, + id: data[fields.group], + }); + name = `${parent.slug} / ${data.slug}`; + } + + return { + ...data, + [fields.name]: name, + }; +}; + +const fields = { + slug: "slug", + name: "name", + translations: "translations", + translationsName: "name", + group: "group", +}; + +export const Tags: CollectionConfig = buildCollectionConfig({ + slug: Collections.Tags, + labels: { singular: "Tag", plural: "Tags" }, + admin: { + group: CollectionGroups.Meta, + useAsTitle: fields.name, + defaultColumns: [fields.slug, fields.group, fields.translations], + }, + endpoints: [getAllEndpoint], + hooks: { beforeChange: [beforeChangeUpdateName] }, + fields: [ + { name: fields.name, type: "text", admin: { readOnly: true, hidden: true } }, + slugField({ name: fields.slug }), + translatedFields({ + name: fields.translations, + admin: { useAsTitle: fields.translationsName }, + fields: [{ name: fields.translationsName, type: "text", required: true }], + }), + { name: fields.group, type: "relationship", required: true, relationTo: Collections.TagsGroups }, + ], +}); diff --git a/src/collections/Tags/endpoints/getAllEndpoint.ts b/src/collections/Tags/endpoints/getAllEndpoint.ts new file mode 100644 index 0000000..6083afc --- /dev/null +++ b/src/collections/Tags/endpoints/getAllEndpoint.ts @@ -0,0 +1,41 @@ +import payload from "payload"; +import { Collections } from "../../../constants"; +import { EndpointTag } from "../../../sdk"; +import { CollectionEndpoint } from "../../../types/payload"; +import { isPayloadType } from "../../../utils/asserts"; + +export const getAllEndpoint: CollectionEndpoint = { + method: "get", + path: "/all", + handler: async (req, res) => { + if (!req.user) { + return res.status(403).send({ + errors: [ + { + message: "You are not allowed to perform this action.", + }, + ], + }); + } + + const tags = ( + await payload.find({ + collection: Collections.Tags, + sort: "id", + pagination: false, + }) + ).docs; + + const result = tags.map(({ slug, translations, group }) => ({ + slug, + translations: + translations?.map(({ language, name }) => ({ + language: isPayloadType(language) ? language.id : language, + name, + })) ?? [], + group: isPayloadType(group) ? group.slug : group, + })); + + res.status(200).json(result); + }, +}; diff --git a/src/collections/TagsGroups/TagsGroups.ts b/src/collections/TagsGroups/TagsGroups.ts new file mode 100644 index 0000000..ca0fc85 --- /dev/null +++ b/src/collections/TagsGroups/TagsGroups.ts @@ -0,0 +1,34 @@ +import { CollectionConfig } from "payload/types"; +import { CollectionGroups, Collections } from "../../constants"; +import { iconField } from "../../fields/iconField/iconField"; +import { slugField } from "../../fields/slugField/slugField"; +import { translatedFields } from "../../fields/translatedFields/translatedFields"; +import { buildCollectionConfig } from "../../utils/collectionConfig"; +import { getAllEndpoint } from "./endpoints/getAllEndpoint"; + +const fields = { + slug: "slug", + translations: "translations", + translationsName: "name", + icon: "icon", +}; + +export const TagsGroups: CollectionConfig = buildCollectionConfig({ + slug: Collections.TagsGroups, + labels: { singular: "Tags Group", plural: "Tags Groups" }, + admin: { + group: CollectionGroups.Meta, + useAsTitle: fields.slug, + defaultColumns: [fields.slug, fields.translations], + }, + endpoints: [getAllEndpoint], + fields: [ + slugField({ name: fields.slug }), + iconField({ name: fields.icon }), + translatedFields({ + name: fields.translations, + admin: { useAsTitle: fields.translationsName }, + fields: [{ name: fields.translationsName, type: "text", required: true }], + }), + ], +}); diff --git a/src/collections/TagsGroups/endpoints/getAllEndpoint.ts b/src/collections/TagsGroups/endpoints/getAllEndpoint.ts new file mode 100644 index 0000000..7fa9b89 --- /dev/null +++ b/src/collections/TagsGroups/endpoints/getAllEndpoint.ts @@ -0,0 +1,42 @@ +import payload from "payload"; +import { Collections } from "../../../constants"; +import { EndpointTagsGroup } from "../../../sdk"; +import { CollectionEndpoint } from "../../../types/payload"; +import { isPayloadType } from "../../../utils/asserts"; + +export const getAllEndpoint: CollectionEndpoint = { + method: "get", + path: "/all", + handler: async (req, res) => { + if (!req.user) { + return res.status(403).send({ + errors: [ + { + message: "You are not allowed to perform this action.", + }, + ], + }); + } + + const tags = ( + await payload.find({ + collection: Collections.TagsGroups, + sort: "id", + pagination: false, + }) + ).docs; + + const result = tags.map(({ slug, translations, icon }) => ({ + slug, + ...(icon ? { icon } : {}), + translations: + translations?.map(({ language, name }) => ({ + language: isPayloadType(language) ? language.id : language, + name, + })) ?? [], + tags: [] // TODO: Add tags, + })); + + res.status(200).json(result); + }, +}; diff --git a/src/constants.ts b/src/constants.ts index 928b9a5..5736418 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,7 +1,10 @@ +import { CueBlock, LineBlock, SectionBlock, TranscriptBlock } from "./types/collections"; + +// END MOCKING SECTION + export enum Collections { ChronologyEras = "chronology-eras", ChronologyItems = "chronology-items", - ContentsFolders = "contents-folders", Contents = "contents", ContentsThumbnails = "contents-thumbnails", Currencies = "currencies", @@ -12,8 +15,10 @@ export enum Collections { LibraryItemsThumbnails = "library-items-thumbnails", LibraryItemsScans = "library-items-scans", LibraryItemsGallery = "library-items-gallery", - Notes = "Notes", + Notes = "notes", Posts = "posts", + Pages = "pages", + PagesThumbnails = "pages-thumbnails", PostsThumbnails = "posts-thumbnails", Recorders = "recorders", RecordersThumbnails = "recorders-thumbnails", @@ -23,7 +28,10 @@ export enum Collections { WeaponsGroups = "weapons-groups", WeaponsThumbnails = "weapons-thumbnails", Folders = "folders", - FoldersThumbnails = "FoldersThumbnails", + FoldersThumbnails = "folders-thumbnails", + Tags = "tags", + TagsGroups = "tags-groups", + Images = "images", } export enum CollectionGroups { @@ -95,3 +103,153 @@ export enum VideoSources { NicoNico = "NicoNico", Tumblr = "Tumblr", } + +export enum PageType { + Content = "Content", + Article = "Article", + Generic = "Generic", +} + +/* RICH TEXT */ + +export type RichTextContent = { + root: { + children: RichTextNode[]; + direction: ("ltr" | "rtl") | null; + format: "left" | "start" | "center" | "right" | "end" | "justify" | ""; + indent: number; + type: string; + version: number; + }; + [k: string]: unknown; +}; + +export type RichTextNode = { + type: string; + version: number; + [k: string]: unknown; +}; + +export interface RichTextNodeWithChildren extends RichTextNode { + children: RichTextNode[]; +} + +export interface RichTextParagraphNode extends RichTextNodeWithChildren { + type: "paragraph"; +} + +export interface RichTextListNode extends RichTextNode { + type: "list"; + children: RichTextNodeWithChildren[]; + listType: string; +} + +export interface RichTextListNumberNode extends RichTextListNode { + listType: "number"; +} + +export interface RichTextListBulletNode extends RichTextListNode { + listType: "bullet"; +} + +export interface RichTextListCheckNode extends RichTextListNode { + listType: "check"; +} + +export interface RichTextTextNode extends RichTextNode { + type: "text"; + format: number; + text: string; +} + +export interface RichTextLinkNode extends RichTextNodeWithChildren { + type: "link"; + fields: { + linkType: "internal" | "custom"; + }; +} + +export interface RichTextLinkInternalNode extends RichTextLinkNode { + fields: { + linkType: "internal"; + newTab: boolean; + doc: { + relationTo: string; + value: any; + }; + }; +} + +export interface RichTextLinkCustomNode extends RichTextLinkNode { + fields: { + linkType: "custom"; + newTab: boolean; + url: string; + }; +} + +export interface RichTextBlockNode extends RichTextNode { + type: "block"; + fields: { + blockType: string; + }; +} + +export interface RichTextSectionBlock extends RichTextBlockNode { + fields: SectionBlock & { anchorHash: string }; +} + +export interface RichTextTranscriptBlock extends RichTextBlockNode { + fields: TranscriptBlock; +} + +export const isNodeParagraphNode = (node: RichTextNode): node is RichTextParagraphNode => + node.type === "paragraph"; + +export const isNodeListNode = (node: RichTextNode): node is RichTextListNode => + node.type === "list"; + +export const isListNodeNumberListNode = (node: RichTextListNode): node is RichTextListNumberNode => + node.listType === "number"; + +export const isListNodeBulletListNode = (node: RichTextListNode): node is RichTextListBulletNode => + node.listType === "bullet"; + +export const isListNodeCheckListNode = (node: RichTextListNode): node is RichTextListCheckNode => + node.listType === "check"; + +export const isNodeTextNode = (node: RichTextNode): node is RichTextTextNode => + node.type === "text"; + +export const isNodeLinkNode = (node: RichTextNode): node is RichTextLinkNode => + node.type === "link"; + +export const isLinkNodeInternalLinkNode = ( + node: RichTextLinkNode +): node is RichTextLinkInternalNode => node.fields.linkType === "internal"; + +export const isLinkNodeCustomLinkNode = (node: RichTextLinkNode): node is RichTextLinkCustomNode => + node.fields.linkType === "custom"; + +export const isNodeBlockNode = (node: RichTextNode): node is RichTextBlockNode => + node.type === "block"; + +export const isBlockNodeSectionBlock = (node: RichTextBlockNode): node is RichTextSectionBlock => + node.fields.blockType === "sectionBlock"; + +export const isBlockNodeTranscriptBlock = ( + node: RichTextBlockNode +): node is RichTextTranscriptBlock => node.fields.blockType === "transcriptBlock"; + +/* BLOCKS */ + +export interface GenericBlock { + content: unknown; + blockType: string; +} + +export const isBlockCueBlock = (block: GenericBlock): block is CueBlock => + block.blockType === "cueBlock"; + +export const isBlockLineBlock = (block: GenericBlock): block is LineBlock => + block.blockType === "lineBlock"; diff --git a/src/fields/iconField/iconField.ts b/src/fields/iconField/iconField.ts index 851e0c8..dfce027 100644 --- a/src/fields/iconField/iconField.ts +++ b/src/fields/iconField/iconField.ts @@ -5,4 +5,8 @@ type Props = Omit; export const iconField = (props: Props): TextField => ({ ...props, type: "text", + admin: { + description: + "Select an icon from here: https://icones.js.org/collection/material-symbols. Only outline and regular variants are usable on the website.", + }, }); diff --git a/src/fields/keysField/keysField.ts b/src/fields/keysField/keysField.ts index fe2d2a1..5c780ad 100644 --- a/src/fields/keysField/keysField.ts +++ b/src/fields/keysField/keysField.ts @@ -1,10 +1,10 @@ -import { FieldBase, RelationshipField } from "payload/dist/fields/config/types"; +import { FieldBase, SingleRelationshipField } from "payload/dist/fields/config/types"; import { Collections, KeysTypes } from "../../constants"; type KeysField = FieldBase & { relationTo: KeysTypes; hasMany?: boolean; - admin?: RelationshipField["admin"]; + admin?: SingleRelationshipField["admin"]; }; export const keysField = ({ @@ -12,7 +12,7 @@ export const keysField = ({ hasMany = false, admin, ...props -}: KeysField): RelationshipField => ({ +}: KeysField): SingleRelationshipField => ({ ...props, admin: { allowCreate: false, diff --git a/src/fields/tagsField/tagsField.ts b/src/fields/tagsField/tagsField.ts new file mode 100644 index 0000000..2fe52f6 --- /dev/null +++ b/src/fields/tagsField/tagsField.ts @@ -0,0 +1,17 @@ +import { FieldBase, SingleRelationshipField } from "payload/dist/fields/config/types"; +import { Collections } from "../../constants"; + +type KeysField = FieldBase & { + admin?: SingleRelationshipField["admin"]; +}; + +export const tagsField = ({ admin, ...props }: KeysField): SingleRelationshipField => ({ + ...props, + admin: { + allowCreate: false, + ...admin, + }, + type: "relationship", + hasMany: true, + relationTo: Collections.Tags, +}); diff --git a/src/payload.config.ts b/src/payload.config.ts index 7ee17c9..72be5a2 100644 --- a/src/payload.config.ts +++ b/src/payload.config.ts @@ -5,12 +5,12 @@ import { buildConfig } from "payload/config"; import { ChronologyEras } from "./collections/ChronologyEras/ChronologyEras"; import { ChronologyItems } from "./collections/ChronologyItems/ChronologyItems"; import { Contents } from "./collections/Contents/Contents"; -import { ContentsFolders } from "./collections/ContentsFolders/ContentsFolders"; import { ContentsThumbnails } from "./collections/ContentsThumbnails/ContentsThumbnails"; import { Currencies } from "./collections/Currencies/Currencies"; import { Files } from "./collections/Files/Files"; import { Folders } from "./collections/Folders/Folders"; import { FoldersThumbnails } from "./collections/FoldersThumbnails/FoldersThumbnails"; +import { Images } from "./collections/Images/Images"; import { Keys } from "./collections/Keys/Keys"; import { Languages } from "./collections/Languages/Languages"; import { LibraryItems } from "./collections/LibraryItems/LibraryItems"; @@ -18,10 +18,13 @@ import { LibraryItemsGallery } from "./collections/LibraryItemsGallery/LibraryIt import { LibraryItemsScans } from "./collections/LibraryItemsScans/LibraryItemsScans"; import { LibraryItemsThumbnails } from "./collections/LibraryItemsThumbnails/LibraryItemsThumbnails"; import { Notes } from "./collections/Notes/Notes"; +import { Pages } from "./collections/Pages/Pages"; import { Posts } from "./collections/Posts/Posts"; import { PostsThumbnails } from "./collections/PostsThumbnails/PostsThumbnails"; import { Recorders } from "./collections/Recorders/Recorders"; import { RecordersThumbnails } from "./collections/RecordersThumbnails/RecordersThumbnails"; +import { Tags } from "./collections/Tags/Tags"; +import { TagsGroups } from "./collections/TagsGroups/TagsGroups"; import { Videos } from "./collections/Videos/Videos"; import { VideosChannels } from "./collections/VideosChannels/VideosChannels"; import { Weapons } from "./collections/Weapons/Weapons"; @@ -51,8 +54,8 @@ export default buildConfig({ FoldersThumbnails, LibraryItems, Contents, - ContentsFolders, Posts, + Pages, ChronologyItems, ChronologyEras, Weapons, @@ -72,6 +75,9 @@ export default buildConfig({ Currencies, Recorders, Keys, + Tags, + TagsGroups, + Images ], db: mongooseAdapter({ url: process.env.MONGODB_URI ?? "mongodb://mongo:27017/payload", diff --git a/src/sdk.ts b/src/sdk.ts index ead0f69..aa8ad87 100644 --- a/src/sdk.ts +++ b/src/sdk.ts @@ -1,5 +1,5 @@ -import { Collections } from "./constants"; -import { Currency, Language } from "./types/collections"; +import { Collections, PageType, RichTextContent } from "./constants"; +import { Content, Currency, Key, Language, LibraryItem, Page } from "./types/collections"; class NodeCache { constructor(_params: any) {} @@ -34,8 +34,8 @@ const refreshToken = async () => { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ - email: process.env.PAYLOAD_USER, - password: process.env.PAYLOAD_PASSWORD, + email: import.meta.env.PAYLOAD_USER, + password: import.meta.env.PAYLOAD_PASSWORD, }), }); logResponse(loginResult); @@ -74,7 +74,7 @@ const injectAuth = async (init?: RequestInit): Promise => ({ const logResponse = (res: Response) => console.log(res.status, res.statusText, res.url); const payloadApiUrl = (collection: Collections, endpoint?: string): string => - `${process.env.PAYLOAD_API_URL}/${collection}${endpoint === undefined ? "" : `/${endpoint}`}`; + `${import.meta.env.PAYLOAD_API_URL}/${collection}${endpoint === undefined ? "" : `/${endpoint}`}`; const request = async (url: string, init?: RequestInit): Promise => { const result = await fetch(url, await injectAuth(init)); @@ -159,14 +159,7 @@ export type EndpointEra = { }[]; }; -export type EndpointFolder = { - slug: string; - icon?: string; - translations: { - language: string; - name: string; - description?: string; - }[]; +export type EndpointFolder = EndpointFolderPreview & { sections: | { type: "single"; subfolders: EndpointFolderPreview[] } | { @@ -176,8 +169,20 @@ export type EndpointFolder = { subfolders: EndpointFolderPreview[]; }[]; }; - lightThumbnail?: PayloadImage; - darkThumbnail?: PayloadImage; + files: ( + | { + relationTo: "library-items"; + value: LibraryItem; + } + | { + relationTo: "contents"; + value: Content; + } + | { + relationTo: "pages"; + value: Page; + } + )[]; }; export type EndpointFolderPreview = { @@ -186,12 +191,115 @@ export type EndpointFolderPreview = { translations: { language: string; name: string; - description?: string; + description?: RichTextContent; }[]; lightThumbnail?: PayloadImage; darkThumbnail?: PayloadImage; }; +export type EndpointContent = { + slug: string; + thumbnail?: PayloadImage; + tagGroups: TagGroup[]; + translations: { + language: string; + sourceLanguage: string; + pretitle?: string; + title: string; + subtitle?: string; + summary?: RichTextContent; + format: { + text?: { + content: RichTextContent; + toc: TableOfContentEntry[]; + transcribers: string[]; + translators: string[]; + proofreaders: string[]; + notes?: RichTextContent; + }; + }; + }[]; +}; + +export type EndpointRecorder = { + id: string; + username: string; + avatar?: PayloadImage; + languages: string[]; + biographies: { + language: string; + biography: RichTextContent; + }[]; +}; + +export type EndpointKey = { + id: string; + name: string; + type: Key["type"]; + translations: { + language: string; + name: string; + short: string; + }[]; +}; + +export type EndpointTag = { + slug: string; + translations: { + language: string; + name: string; + }[]; + group: string; +}; + +export type EndpointTagsGroup = { + slug: string; + icon?: string; + translations: { + language: string; + name: string; + }[]; + tags: EndpointTag[]; +}; + +export type EndpointPage = { + slug: string; + type: PageType; + thumbnail?: PayloadImage; + authors: string[]; + tagGroups: TagGroup[]; + translations: { + language: string; + sourceLanguage: string; + pretitle?: string; + title: string; + subtitle?: string; + summary?: RichTextContent; + content: RichTextContent; + transcribers: string[]; + translators: string[]; + proofreaders: string[]; + toc: TableOfContentEntry[]; + }[]; + status: "draft" | "published"; + parentPages: ParentPage[]; +}; + +export type ParentPage = { + slug: string; + collection: Collections; + translations: { language: string; name: string }[]; + tag: string; +}; + +export type TagGroup = { slug: string; icon: string; values: string[] }; + +export type TableOfContentEntry = { + prefix: string; + title: string; + children: TableOfContentEntry[]; +}; + export type PayloadImage = { url: string; width: number; @@ -213,4 +321,16 @@ export const payload = { await (await request(payloadApiUrl(Collections.Languages, `all`))).json(), getCurrencies: async (): Promise => await (await request(payloadApiUrl(Collections.Currencies, `all`))).json(), + getContent: async (slug: string): Promise => + await (await request(payloadApiUrl(Collections.Contents, `slug/${slug}`))).json(), + getKeys: async (): Promise => + await (await request(payloadApiUrl(Collections.Keys, `all`))).json(), + getRecorders: async (): Promise => + await (await request(payloadApiUrl(Collections.Recorders, `all`))).json(), + getTags: async (): Promise => + await (await request(payloadApiUrl(Collections.Tags, `all`))).json(), + getTagsGroups: async (): Promise => + await (await request(payloadApiUrl(Collections.TagsGroups, `all`))).json(), + getPage: async (slug: string): Promise => + await (await request(payloadApiUrl(Collections.Pages, `slug/${slug}`))).json(), }; diff --git a/src/server.ts b/src/server.ts index 31a60d8..e919cce 100644 --- a/src/server.ts +++ b/src/server.ts @@ -59,19 +59,32 @@ const start = async () => { app.use("/public", express.static(path.join(__dirname, "../public"))); app.get("/api/sdk", (_, res) => { - const collections = readFileSync(path.join(__dirname, "types/collections.ts"), "utf-8"); + const removeMockingSection = (text: string): string => { + const lines = text.split("\n"); + const endMockingLine = lines.findIndex((line) => line === "// END MOCKING SECTION") ?? 0; + return lines.slice(endMockingLine + 1).join("\n"); + }; - const constantsHeader = "/////////////// CONSTANTS ///////////////\n"; - const constants = readFileSync(path.join(__dirname, "constants.ts"), "utf-8"); + const removeDeclare = (text: string): string => { + const lines = text.split("\n"); + const startDeclareLine = + lines.findIndex((line) => line === "declare module 'payload' {") ?? 0; + return lines.slice(0, startDeclareLine).join("\n"); + }; - const sdkHeader = "////////////////// SDK //////////////////\n"; - const sdkLines = readFileSync(path.join(__dirname, "sdk.ts"), "utf-8").split("\n"); - const endMockingLine = sdkLines.findIndex((line) => line === "// END MOCKING SECTION") ?? 0; - const sdk = - `import NodeCache from "node-cache";\n\n` + sdkLines.slice(endMockingLine + 1).join("\n"); + const result = []; + + result.push(removeDeclare(readFileSync(path.join(__dirname, "types/collections.ts"), "utf-8"))); + + result.push("/////////////// CONSTANTS ///////////////"); + result.push(removeMockingSection(readFileSync(path.join(__dirname, "constants.ts"), "utf-8"))); + + result.push("////////////////// SDK //////////////////"); + result.push(`import NodeCache from "node-cache";`); + result.push(removeMockingSection(readFileSync(path.join(__dirname, "sdk.ts"), "utf-8"))); res.type("text/plain"); - res.send([collections, constantsHeader, constants, sdkHeader, sdk].join("\n\n")); + res.send(result.join("\n\n")); }); app.get("/robots.txt", (_, res) => { diff --git a/src/types/collections.ts b/src/types/collections.ts index 8d6efc1..26c2051 100644 --- a/src/types/collections.ts +++ b/src/types/collections.ts @@ -6,6 +6,10 @@ * and re-run `payload generate:types` to regenerate this file. */ +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "RecorderBiographies". + */ export type RecorderBiographies = | { language: string | Language; @@ -27,6 +31,10 @@ export type RecorderBiographies = id?: string | null; }[] | null; +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "CategoryTranslations". + */ export type CategoryTranslations = | { language: string | Language; @@ -39,11 +47,11 @@ export type CategoryTranslations = export interface Config { collections: { folders: Folder; - FoldersThumbnails: FoldersThumbnail; + 'folders-thumbnails': FoldersThumbnail; 'library-items': LibraryItem; contents: Content; - 'contents-folders': ContentsFolder; posts: Post; + pages: Page; 'chronology-items': ChronologyItem; 'chronology-eras': ChronologyEra; weapons: Weapon; @@ -56,18 +64,25 @@ export interface Config { 'recorders-thumbnails': RecordersThumbnail; 'posts-thumbnails': PostThumbnail; files: File; - Notes: Note; + notes: Note; videos: Video; 'videos-channels': VideosChannel; languages: Language; currencies: Currency; recorders: Recorder; keys: Key; + tags: Tag; + 'tags-groups': TagsGroup; + images: Image; 'payload-preferences': PayloadPreference; 'payload-migrations': PayloadMigration; }; globals: {}; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "folders". + */ export interface Folder { id: string; slug: string; @@ -119,11 +134,19 @@ export interface Folder { relationTo: 'contents'; value: string | Content; } + | { + relationTo: 'pages'; + value: string | Page; + } )[] | null; updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "folders-thumbnails". + */ export interface FoldersThumbnail { id: string; updatedAt: string; @@ -143,20 +166,20 @@ export interface FoldersThumbnail { filesize?: number | null; filename?: string | null; }; - medium?: { - url?: string | null; - width?: number | null; - height?: number | null; - mimeType?: string | null; - filesize?: number | null; - filename?: string | null; - }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "languages". + */ export interface Language { id: string; name: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "library-items". + */ export interface LibraryItem { id: string; itemType?: ('Textual' | 'Audio' | 'Video' | 'Game' | 'Other') | null; @@ -323,6 +346,10 @@ export interface LibraryItem { createdAt: string; _status?: ('draft' | 'published') | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "library-items-thumbnails". + */ export interface LibraryItemThumbnail { id: string; libraryItem?: (string | LibraryItem)[] | null; @@ -361,6 +388,10 @@ export interface LibraryItemThumbnail { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "library-items-gallery". + */ export interface LibraryItemGallery { id: string; updatedAt: string; @@ -390,6 +421,10 @@ export interface LibraryItemGallery { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "recorders". + */ export interface Recorder { id: string; username: string; @@ -407,6 +442,10 @@ export interface Recorder { lockUntil?: string | null; password?: string | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "recorders-thumbnails". + */ export interface RecordersThumbnail { id: string; recorder?: (string | null) | Recorder; @@ -437,6 +476,10 @@ export interface RecordersThumbnail { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "library-items-scans". + */ export interface LibraryItemScans { id: string; updatedAt: string; @@ -482,6 +525,10 @@ export interface LibraryItemScans { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "files". + */ export interface File { id: string; filename: string; @@ -489,6 +536,10 @@ export interface File { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "keys". + */ export interface Key { id: string; name: string; @@ -505,16 +556,22 @@ export interface Key { | 'Wordings'; translations?: CategoryTranslations; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "currencies". + */ export interface Currency { id: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "contents". + */ export interface Content { id: string; slug: string; thumbnail?: string | ContentsThumbnail | null; - categories?: (string | Key)[] | null; - type?: (string | null) | Key; - libraryItems?: (string | LibraryItem)[] | null; + tags?: (string | Tag)[] | null; translations: { language: string | Language; sourceLanguage: string | Language; @@ -603,7 +660,8 @@ export interface Content { } | null; id?: string | null; }[]; - folders?: (string | ContentsFolder)[] | null; + folders?: (string | Folder)[] | null; + libraryItems?: (string | LibraryItem)[] | null; previousContents?: (string | Content)[] | null; nextContents?: (string | Content)[] | null; updatedBy: string | Recorder; @@ -611,6 +669,10 @@ export interface Content { createdAt: string; _status?: ('draft' | 'published') | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "contents-thumbnails". + */ export interface ContentsThumbnail { id: string; contents?: (string | Content)[] | null; @@ -649,8 +711,13 @@ export interface ContentsThumbnail { }; }; } -export interface ContentsFolder { +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "tags". + */ +export interface Tag { id: string; + name?: string | null; slug: string; translations?: | { @@ -659,9 +726,124 @@ export interface ContentsFolder { id?: string | null; }[] | null; - subfolders?: (string | ContentsFolder)[] | null; - contents?: (string | Content)[] | null; + group: string | TagsGroup; + updatedAt: string; + createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "tags-groups". + */ +export interface TagsGroup { + id: string; + slug: string; + icon?: string | null; + translations?: + | { + language: string | Language; + name: string; + id?: string | null; + }[] + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "pages". + */ +export interface Page { + id: string; + type: 'Content' | 'Article' | 'Generic'; + slug: string; + thumbnail?: string | Image | null; + tags?: (string | Tag)[] | null; + authors?: (string | Recorder)[] | null; + translations: { + language: string | Language; + sourceLanguage: string | Language; + pretitle?: string | null; + title: string; + subtitle?: string | null; + summary?: { + root: { + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + type: string; + version: number; + }; + [k: string]: unknown; + } | null; + content: { + root: { + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + type: string; + version: number; + }; + [k: string]: unknown; + }; + transcribers?: (string | Recorder)[] | null; + translators?: (string | Recorder)[] | null; + proofreaders?: (string | Recorder)[] | null; + id?: string | null; + }[]; + folders?: (string | Folder)[] | null; + collectibles?: (string | LibraryItem)[] | null; + updatedBy: string | Recorder; + updatedAt: string; + createdAt: string; + _status?: ('draft' | 'published') | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "images". + */ +export interface Image { + id: string; + updatedAt: string; + createdAt: string; + url?: string | null; + filename?: string | null; + mimeType?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + sizes?: { + thumb?: { + url?: string | null; + width?: number | null; + height?: number | null; + mimeType?: string | null; + filesize?: number | null; + filename?: string | null; + }; + og?: { + url?: string | null; + width?: number | null; + height?: number | null; + mimeType?: string | null; + filesize?: number | null; + filename?: string | null; + }; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "posts". + */ export interface Post { id: string; slug: string; @@ -713,6 +895,10 @@ export interface Post { createdAt: string; _status?: ('draft' | 'published') | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "posts-thumbnails". + */ export interface PostThumbnail { id: string; posts?: (string | Post)[] | null; @@ -751,6 +937,10 @@ export interface PostThumbnail { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "chronology-items". + */ export interface ChronologyItem { id: string; name?: string | null; @@ -806,6 +996,10 @@ export interface ChronologyItem { createdAt: string; _status?: ('draft' | 'published') | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "chronology-eras". + */ export interface ChronologyEra { id: string; slug: string; @@ -837,6 +1031,10 @@ export interface ChronologyEra { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "weapons". + */ export interface Weapon { id: string; slug: string; @@ -936,6 +1134,10 @@ export interface Weapon { createdAt: string; _status?: ('draft' | 'published') | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "weapons-thumbnails". + */ export interface WeaponsThumbnail { id: string; weapon?: (string | null) | Weapon; @@ -982,6 +1184,10 @@ export interface WeaponsThumbnail { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "weapons-groups". + */ export interface WeaponsGroup { id: string; slug: string; @@ -994,6 +1200,10 @@ export interface WeaponsGroup { | null; weapons?: (string | Weapon)[] | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "notes". + */ export interface Note { id: string; note: { @@ -1014,6 +1224,10 @@ export interface Note { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "videos". + */ export interface Video { id: string; uid: string; @@ -1026,12 +1240,20 @@ export interface Video { publishedDate: string; channel?: (string | null) | VideosChannel; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "videos-channels". + */ export interface VideosChannel { id: string; uid: string; title: string; subscribers?: number | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences". + */ export interface PayloadPreference { id: string; user: { @@ -1051,6 +1273,10 @@ export interface PayloadPreference { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-migrations". + */ export interface PayloadMigration { id: string; name?: string | null; @@ -1058,6 +1284,84 @@ export interface PayloadMigration { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "LineBlock". + */ +export interface LineBlock { + content: { + root: { + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + type: string; + version: number; + }; + [k: string]: unknown; + }; + blockType: 'lineBlock'; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "CueBlock". + */ +export interface CueBlock { + content: { + root: { + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + type: string; + version: number; + }; + [k: string]: unknown; + }; + blockType: 'cueBlock'; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "TranscriptBlock". + */ +export interface TranscriptBlock { + lines: (LineBlock | CueBlock)[]; + id?: string | null; + blockName?: string | null; + blockType: 'transcriptBlock'; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "SectionBlock". + */ +export interface SectionBlock { + lines: { + root: { + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + type: string; + version: number; + }; + [k: string]: unknown; + }; + id?: string | null; + blockName?: string | null; + blockType: 'sectionBlock'; +} declare module 'payload' { diff --git a/src/utils/asserts.ts b/src/utils/asserts.ts index 9a4d497..e05821a 100644 --- a/src/utils/asserts.ts +++ b/src/utils/asserts.ts @@ -32,9 +32,12 @@ export const isValidPayloadImage = ( height?: number | null; url?: string | null; } - | undefined | null + | undefined + | null + | string ): image is PayloadImage => { if (isUndefined(image)) return false; + if (typeof image === "string") return false; if (isEmpty(image.filename)) return false; if (isEmpty(image.url)) return false; if (isEmpty(image.mimeType)) return false; @@ -49,5 +52,6 @@ export const isString = (value: string | T): value is string = export const isPayloadType = (value: string | T): value is T => typeof value === "object"; -export const isPayloadArrayType = (value: string[] | T[]): value is T[] => - value.every(isPayloadType); +export const isPayloadArrayType = ( + value: (string | T)[] | null | undefined +): value is T[] => isDefined(value) && value.every(isPayloadType); diff --git a/src/utils/tags.ts b/src/utils/tags.ts new file mode 100644 index 0000000..a3f9fe9 --- /dev/null +++ b/src/utils/tags.ts @@ -0,0 +1,29 @@ +import { TagGroup } from "../sdk"; +import { Tag } from "../types/collections"; +import { isPayloadArrayType, isPayloadType } from "./asserts"; + +export const convertTagsToGroups = (tags: (string | Tag)[] | null | undefined): TagGroup[] => { + if (!isPayloadArrayType(tags)) { + return []; + } + + const groups: TagGroup[] = []; + + tags.forEach(({ group, slug }) => { + if (isPayloadType(group)) { + const existingGroup = groups.find((existingGroup) => existingGroup.slug === group.slug); + if (existingGroup) { + existingGroup.values.push(slug); + } else { + groups.push({ + slug: group.slug, + icon: group.icon ?? "material-symbols:category-outline", + values: [slug], + }); + } + } + }); + + return groups; + }; + \ No newline at end of file