diff --git a/package-lock.json b/package-lock.json index 0e819c7..0134b32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,46 +4,114 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@azure/abort-controller": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.0.0.tgz", + "integrity": "sha512-U4RM+AuCxlwq1GDP+VSswfzxvsmQ2hUAAhii2Em2xf0e00/6CsZAoQnQCxhvLDe39pebjivobU29LioN9x+DJQ==", + "requires": { + "tslib": "^1.9.3" + } + }, + "@azure/core-asynciterator-polyfill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.0.tgz", + "integrity": "sha512-kmv8CGrPfN9SwMwrkiBK9VTQYxdFQEGe0BmQk+M8io56P9KNzpAxcWE/1fxJj7uouwN4kXF0BHW8DNlgx+wtCg==" + }, + "@azure/core-auth": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.0.0.tgz", + "integrity": "sha512-DcXqxt0O0HDhYTcrN16e/hJutFkFTM8fQq6bJbHuDh5AUbDUKFrF64hj5RXATukThOszGFrR1MWJOGZPSo7fiA==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-tracing": "1.0.0-preview.5", + "tslib": "^1.9.3" + } + }, + "@azure/core-http": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-1.0.0.tgz", + "integrity": "sha512-vUVrALCoxY0gRfGWbEdiaFGK7qJMV/ZjZucN+LWZZGy/NdP5Iv6nVrxeb7YYIhPDsmcRvABYHrZUt01TB/8aAQ==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.0.0", + "@azure/core-tracing": "1.0.0-preview.5", + "@azure/logger": "^1.0.0", + "@types/node-fetch": "^2.5.0", + "@types/tunnel": "^0.0.1", + "form-data": "^2.5.0", + "node-fetch": "^2.6.0", + "process": "^0.11.10", + "tough-cookie": "^3.0.1", + "tslib": "^1.9.3", + "tunnel": "^0.0.6", + "uuid": "^3.3.2", + "xml2js": "^0.4.19" + } + }, + "@azure/core-lro": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-1.0.0.tgz", + "integrity": "sha512-l4abIb8S9qmlv3bJkonLvgGSVQcSXq5jByA7Z28GRGJaQN/mSFal9YQOuLvVag+JXQJsoftuxJFrZiggF2TwOg==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-http": "^1.0.0", + "events": "^3.0.0", + "tslib": "^1.9.3" + } + }, + "@azure/core-paging": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.0.0.tgz", + "integrity": "sha512-CzaT7LwxU97PZ+/Pn7uAbNGXY2mJ/3b56kmLsZzbR9stfrNfzlILxR94WHG/D1jZEQOk4lUNiaqJ2zP7nSGJhA==", + "requires": { + "@azure/core-asynciterator-polyfill": "^1.0.0" + } + }, + "@azure/core-tracing": { + "version": "1.0.0-preview.5", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.5.tgz", + "integrity": "sha512-i3hF4EQucZmn2l4zXscwG5bilnboKHtnLMFVuzXk55dt487/9EJ5uMOP3eyTFpULGjn6xubgYFAJVpUJGVQv4w==", + "requires": { + "@opencensus/web-types": "0.0.7", + "tslib": "^1.9.3" + } + }, "@azure/cosmos": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.3.6.tgz", - "integrity": "sha512-HCPIa4lgBQnetH8VVwLJBsBipAyCt1iQRoojgtLpZBfu4pKvg2z2Vj3oyxxc5lYaab7VzLLSMynpWt/8Bixhmg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.4.2.tgz", + "integrity": "sha512-dj0sR8xVv99wXcrEvnHzIFDj1d/4yV+koLih3g9k5Ec+SB405eZdp1O73oo7T4Jc00g/bY7eSC7vzNy+4D6DWw==", "requires": { "@types/debug": "^4.1.4", "debug": "^4.1.1", "fast-json-stable-stringify": "^2.0.0", "node-abort-controller": "^1.0.4", "node-fetch": "^2.6.0", + "os-name": "^3.1.0", "priorityqueuejs": "^1.0.0", "semaphore": "^1.0.5", "tslib": "^1.9.3", - "universal-user-agent": "^4.0.0", "uuid": "^3.3.2" } }, - "@azure/ms-rest-js": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.0.4.tgz", - "integrity": "sha512-nSOPt6st0RtxclYBQV65qXZpvMDqiDQssktvB/SMTAJ5bIytSPtBmlttTTigO5qHvwQcfzzpQE0sMceK+dJ/IQ==", + "@azure/logger": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.0.tgz", + "integrity": "sha512-g2qLDgvmhyIxR3JVS8N67CyIOeFRKQlX/llxYJQr1OSGQqM3HTpVP8MjmjcEKbL/OIt2N9C9UFaNQuKOw1laOA==", "requires": { - "@types/node-fetch": "^2.3.7", - "@types/tunnel": "0.0.1", - "abort-controller": "^3.0.0", - "form-data": "^2.5.0", - "node-fetch": "^2.6.0", - "tough-cookie": "^3.0.1", - "tslib": "^1.10.0", - "tunnel": "0.0.6", - "uuid": "^3.3.2", - "xml2js": "^0.4.19" + "tslib": "^1.9.3" } }, "@azure/storage-blob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-10.5.0.tgz", - "integrity": "sha512-67+0EP7STy9BQgzvN1RgmSvXhxRd044eDgepX7zBp7XslBxz8YGo2cSLm9w5o5Qf1FLCRlwuziRMikaPCLMpVw==", - "requires": { - "@azure/ms-rest-js": "^2.0.0", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.0.0.tgz", + "integrity": "sha512-kYR9uqbLLR8WSigtMlF3x0xa3TlDOb7p2GEPCEW1OyiXEImL0z9Iwws1o1HJuD/WidkczNXpRPjtMPyq4CYe1w==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-http": "^1.0.0", + "@azure/core-lro": "^1.0.0", + "@azure/core-paging": "^1.0.0", + "@azure/core-tracing": "1.0.0-preview.5", + "@azure/logger": "^1.0.0", "events": "^3.0.0", "tslib": "^1.9.3" } @@ -54,6 +122,11 @@ "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==", "dev": true }, + "@opencensus/web-types": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@opencensus/web-types/-/web-types-0.0.7.tgz", + "integrity": "sha512-xB+w7ZDAu3YBzqH44rCmG9/RlrOmFuDPt/bpf17eJr8eZSrLt7nc7LnWdxM9Mmoj/YKMHpxRg28txu3TcpiL+g==" + }, "@types/bcryptjs": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", @@ -66,12 +139,12 @@ "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==" }, "@types/dotenv": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz", - "integrity": "sha512-ftQl3DtBvqHl9L16tpqqzA4YzCSXZfi7g8cQceTz5rOlYtk/IZbFjAv3mLOQlNIgOaylCQWQoBdDQHPgEBJPHg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-ylSC9GhfRH7m1EUXBXofhgx4lUWmFeQDINW5oLuS+gxWdfUeW4zJdeVTYVkexEW+e2VUvlZR2kGnGGipAWR7kw==", "dev": true, "requires": { - "@types/node": "*" + "dotenv": "*" } }, "@types/jsonwebtoken": { @@ -84,9 +157,9 @@ } }, "@types/lodash": { - "version": "4.14.144", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz", - "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==", + "version": "4.14.146", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.146.tgz", + "integrity": "sha512-JzJcmQ/ikHSv7pbvrVNKJU5j9jL9VLf3/gqs048CEnBVVVEv4kve3vLxoPHGvclutS+Il4SBIuQQ087m1eHffw==", "dev": true }, "@types/node": { @@ -95,9 +168,9 @@ "integrity": "sha512-vqcj1MVm2Sla4PpMfYKh1MyDN4D2f/mPIZD7RdAGqEsbE+JxfeqQHHVbRDQ0Nqn8i73gJa1HQ1Pu3+nH4Q0Yiw==" }, "@types/node-fetch": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.0.tgz", - "integrity": "sha512-TLFRywthBgL68auWj+ziWu+vnmmcHCDFC/sqCOQf1xTz4hRq8cu79z8CtHU9lncExGBsB8fXA4TiLDLt6xvMzw==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.3.tgz", + "integrity": "sha512-X3TNlzZ7SuSwZsMkb5fV7GrPbVKvHc2iwHmslb8bIxRKWg2iqkfm3F/Wd79RhDpOXR7wCtKAwc5Y2JE6n/ibyw==", "requires": { "@types/node": "*" } @@ -111,9 +184,9 @@ } }, "@types/uuid": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.5.tgz", - "integrity": "sha512-MNL15wC3EKyw1VLF+RoVO4hJJdk9t/Hlv3rt1OL65Qvuadm4BYo6g9ZJQqoq7X8NBFSsQXgAujWciovh2lpVjA==", + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.6.tgz", + "integrity": "sha512-cCdlC/1kGEZdEglzOieLDYBxHsvEOIg7kp/2FYyVR9Pxakq+Qf/inL3RKQ+PA8gOlI/NnL+fXmQH12nwcGzsHw==", "dev": true, "requires": { "@types/node": "*" @@ -125,14 +198,6 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, "abstract-logging": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-1.0.0.tgz", @@ -867,11 +932,6 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, "events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", @@ -1088,11 +1148,11 @@ } }, "fastify-cors": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fastify-cors/-/fastify-cors-2.1.3.tgz", - "integrity": "sha512-ZHFzKn1DddymsxzvdtjEQfkuMfGgwcp++FKuTTMmAN2KFB7hJRmOINffjfRdmUcgXdE4LoSy5XJROWKx/b+CPQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/fastify-cors/-/fastify-cors-2.2.0.tgz", + "integrity": "sha512-xnZmYPWUxrIBEsv5x2JrsDlrskoFkOE0KAwedEe6dn8TCxpARwW6U+nofAKWZMDF+dXkEslRCgrd1ixdEIkB8w==", "requires": { - "fastify-plugin": "^1.5.0", + "fastify-plugin": "^1.6.0", "vary": "^1.1.2" } }, @@ -2857,9 +2917,9 @@ } }, "pino-pretty": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-3.2.2.tgz", - "integrity": "sha512-2SP++Wbo4EsH5RpLhcsYHOR/8CMTIJWZpU0aPiVK0Wq8SrRMQ9oHQNffVK5ZyDFZMtSuTdFCVfLVNFmtFMDEeA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-3.3.0.tgz", + "integrity": "sha512-aoQWRJscJrKG/YH8GKqvbYalp8rr0KDn/SUmt2XK7q3ovA8GTN6OqvomPan7soNXLUKuYJc4UQdh0Fx+15yQpw==", "dev": true, "requires": { "@hapi/bourne": "^1.3.2", @@ -2903,6 +2963,11 @@ "resolved": "https://registry.npmjs.org/priorityqueuejs/-/priorityqueuejs-1.0.0.tgz", "integrity": "sha1-LuTyPCVgkT4IwHzlzN1t498sWvg=" }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -3655,9 +3720,9 @@ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" }, "typescript": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz", - "integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz", + "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==", "dev": true }, "undefsafe": { @@ -3707,14 +3772,6 @@ "crypto-random-string": "^1.0.0" } }, - "universal-user-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz", - "integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==", - "requires": { - "os-name": "^3.1.0" - } - }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", diff --git a/package.json b/package.json index d6d7cf8..5cfefef 100644 --- a/package.json +++ b/package.json @@ -12,22 +12,22 @@ }, "devDependencies": { "@types/bcryptjs": "^2.4.2", - "@types/dotenv": "^6.1.1", + "@types/dotenv": "^8.2.0", "@types/jsonwebtoken": "^8.3.5", - "@types/lodash": "^4.14.144", - "@types/uuid": "^3.4.5", + "@types/lodash": "^4.14.146", + "@types/uuid": "^3.4.6", "nodemon": "^1.19.4", "npm-run-all": "^4.1.5", - "pino-pretty": "^3.2.2", - "typescript": "^3.6.4" + "pino-pretty": "^3.3.0", + "typescript": "^3.7.2" }, "dependencies": { - "@azure/cosmos": "^3.3.6", - "@azure/storage-blob": "^10.5.0", + "@azure/cosmos": "^3.4.2", + "@azure/storage-blob": "^12.0.0", "bcryptjs": "^2.4.3", "dotenv": "^8.2.0", "fastify": "^2.10.0", - "fastify-cors": "^2.1.3", + "fastify-cors": "^2.2.0", "fastify-helmet": "^3.0.2", "jsonwebtoken": "^8.5.1", "lodash": "^4.17.15", diff --git a/src/lib/media.ts b/src/lib/media.ts index 23204e1..099303c 100644 --- a/src/lib/media.ts +++ b/src/lib/media.ts @@ -1,31 +1,34 @@ import { Container } from '@azure/cosmos' -import { BlockBlobURL, SharedKeyCredential, Aborter, ContainerSASPermissions, generateBlobSASQueryParameters, AnonymousCredential } from '@azure/storage-blob' +import { ContainerSASPermissions, generateBlobSASQueryParameters, StorageSharedKeyCredential, BlobServiceClient } from '@azure/storage-blob' import moment from 'moment' import { MEDIA_PARTITION_KEY } from '../constants' import { Media } from '../types/collections' export function generateSAS(permissions: string, expirationMinutes: number) { - const sharedKeyCredential = new SharedKeyCredential(process.env.BLOB_STORAGE_ACCOUNT!, process.env.BLOB_STORAGE_ACCOUNT_KEY!) + const sharedKeyCredential = new StorageSharedKeyCredential(process.env.BLOB_STORAGE_ACCOUNT!, process.env.BLOB_STORAGE_ACCOUNT_KEY!) return generateBlobSASQueryParameters({ containerName: process.env.BLOB_STORAGE_CONTAINER!, - permissions: ContainerSASPermissions.parse(permissions).toString(), - startTime: new Date(), - expiryTime: moment().add(expirationMinutes, 'm').toDate(), + permissions: ContainerSASPermissions.parse(permissions), + startsOn: new Date(), + expiresOn: moment().add(expirationMinutes, 'm').toDate(), }, sharedKeyCredential).toString() } export async function deleteMedia(name: string) { - const blockBlobURL = new BlockBlobURL( + const blobServiceClient = new BlobServiceClient( `https://${process.env.BLOB_STORAGE_ACCOUNT!}.blob.core.windows.net/${process.env.BLOB_STORAGE_CONTAINER!}/${name}`, - BlockBlobURL.newPipeline(new SharedKeyCredential(process.env.BLOB_STORAGE_ACCOUNT!, process.env.BLOB_STORAGE_ACCOUNT_KEY!)) + new StorageSharedKeyCredential(process.env.BLOB_STORAGE_ACCOUNT!, process.env.BLOB_STORAGE_ACCOUNT_KEY!) ) + const containerClient = blobServiceClient.getContainerClient(process.env.BLOB_STORAGE_CONTAINER!) + containerClient.deleteBlob(name) + try { - await blockBlobURL.delete(Aborter.none) - } catch (e) { - + await containerClient.deleteBlob(name) + } catch (err) { + console.error(err) } } diff --git a/src/plugins/api/authentication.ts b/src/plugins/api/authentication.ts index 0b3d4b7..d6d0673 100644 --- a/src/plugins/api/authentication.ts +++ b/src/plugins/api/authentication.ts @@ -48,6 +48,7 @@ function registerRoute(server: FastifyInstance('/api/register', options, async (request, reply) => { if (!server.database) return serverError(reply) - const { name, email, password, requiresApproval, privacy, about, imageUrl, coverImageUrl, invitation: code } = request.body + const { name, email, password, requiresApproval, privacy, about, imageUrl, coverImageUrl, theme, invitation: code } = request.body const id = normalize(request.body.id) const userContainer = containerFor(server.database.client, 'Users') @@ -178,6 +180,7 @@ function registerRoute(server: FastifyInstance({ container: groupContainer, id }) @@ -156,6 +158,7 @@ function createRoute(server: FastifyInstance({ ...group, diff --git a/src/plugins/api/users.ts b/src/plugins/api/users.ts index fe446e5..b2548aa 100644 --- a/src/plugins/api/users.ts +++ b/src/plugins/api/users.ts @@ -87,6 +87,7 @@ function updateRoute(server: FastifyInstance(viewer) return viewer }) diff --git a/src/schemas.ts b/src/schemas.ts index 4aa605a..8448981 100644 --- a/src/schemas.ts +++ b/src/schemas.ts @@ -30,6 +30,7 @@ export const groupListingSchema: JSONSchema = { imageUrl: { type: 'string' }, coverImageUrl: { type: 'string' }, iconImageUrl: { type: 'string' }, + theme: { type: 'string' }, requiresApproval: { type: 'boolean' }, members: { type: 'number' }, posts: { type: 'number' }, @@ -62,6 +63,7 @@ export const userSchema: JSONSchema = { about: { type: 'string' }, imageUrl: { type: 'string' }, coverImageUrl: { type: 'string' }, + theme: { type: 'string' }, subscriptions: { type: 'array', items: subscriptionSchema, @@ -146,6 +148,7 @@ export const selfSchema: JSONSchema = { about: { type: 'string' }, imageUrl: { type: 'string' }, coverImageUrl: { type: 'string' }, + theme: { type: 'string' }, requiresApproval: { type: 'boolean' }, privacy: { type: 'string' }, membership: { type: 'string' }, diff --git a/src/types/collections.ts b/src/types/collections.ts index 4526cae..d2f62ea 100644 --- a/src/types/collections.ts +++ b/src/types/collections.ts @@ -109,6 +109,7 @@ export interface Group { imageUrl?: string coverImageUrl?: string iconImageUrl?: string + theme: string registration: GroupRegistrationType status: GroupStatus active: boolean @@ -177,6 +178,7 @@ export interface User { about?: string imageUrl?: string coverImageUrl?: string + theme: string email: string emailVerified: boolean passwordHash: string