├── .cargo └── config.toml ├── .editorconfig ├── .env-template ├── .eslintrc.json ├── .gitignore ├── .pnp.loader.mjs ├── .prettierignore ├── .prettierrc ├── .snyk ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── .yarn ├── patches │ └── nx-npm-14.4.2-ee5778b3a0.patch ├── plugins │ └── @yarnpkg │ │ ├── plugin-constraints.cjs │ │ ├── plugin-exec.cjs │ │ ├── plugin-interactive-tools.cjs │ │ ├── plugin-prune-prod.cjs │ │ ├── plugin-stage.cjs │ │ ├── plugin-typescript.cjs │ │ ├── plugin-version.cjs │ │ └── plugin-workspace-tools.cjs ├── releases │ └── yarn-4.0.0-rc.13.git.20220720.hash-02a48ec.cjs └── sdks │ ├── eslint │ ├── bin │ │ └── eslint.js │ ├── lib │ │ └── api.js │ └── package.json │ ├── integrations.yml │ ├── prettier │ ├── index.js │ └── package.json │ └── typescript │ ├── bin │ ├── tsc │ └── tsserver │ ├── lib │ ├── tsc.js │ ├── tsserver.js │ ├── tsserverlibrary.js │ └── typescript.js │ └── package.json ├── .yarnrc.yml ├── Cargo.lock ├── Cargo.toml ├── Jenkinsfile ├── LICENSE ├── README.md ├── apps ├── backend │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── src │ │ ├── app │ │ │ ├── app.controller.spec.ts │ │ │ ├── app.controller.ts │ │ │ ├── app.module.ts │ │ │ └── app.service.ts │ │ ├── main.ts │ │ ├── migrate.ts │ │ ├── seed.ts │ │ └── static │ │ │ └── .gitkeep │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.test.json │ └── webpack.config.js ├── docker │ ├── docker-compose-dev.yml │ ├── docker-compose-prod.yml │ ├── docker-deploy-colors.yml │ ├── secrets │ │ └── EXAMPLE_SECRET │ └── src │ │ ├── backend.Dockerfile │ │ ├── certbot.Dockerfile │ │ ├── certbot │ │ ├── deploy-hook.sh │ │ └── entrypoint.sh │ │ ├── db-mongo.Dockerfile │ │ ├── db-postgres.Dockerfile │ │ ├── db │ │ └── postgres-uuid.sh │ │ ├── jenkins.Dockerfile │ │ ├── nginx.Dockerfile │ │ ├── nginx │ │ ├── confs │ │ │ ├── basic_auth.conf │ │ │ ├── blue.conf │ │ │ ├── certbot.conf │ │ │ ├── error_pages.conf │ │ │ ├── frontends.conf │ │ │ ├── green.conf │ │ │ ├── headers.conf │ │ │ ├── http.conf │ │ │ ├── https.conf │ │ │ ├── init.conf │ │ │ ├── nginx.conf │ │ │ └── ssl.conf │ │ ├── dev-certs │ │ │ └── dev-domains.ext │ │ └── scripts │ │ │ ├── 40-handle-ssl-certs.sh │ │ │ └── 50-set-upstreams.sh │ │ ├── placeholder.Dockerfile │ │ ├── utils │ │ └── clean.sh │ │ ├── worker.Dockerfile │ │ └── worker │ │ └── entrypoint.sh ├── frontend │ ├── .eslintrc.cjs │ ├── env.d.ts │ ├── index.html │ ├── postcss.config.js │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ ├── base.css │ │ │ ├── index.css │ │ │ └── logo.svg │ │ ├── components │ │ │ ├── HelloWorld.vue │ │ │ ├── TheWelcome.vue │ │ │ ├── WelcomeItem.vue │ │ │ ├── __tests__ │ │ │ │ └── HelloWorld.spec.ts │ │ │ └── icons │ │ │ │ ├── IconBackend.vue │ │ │ │ ├── IconEcosystem.vue │ │ │ │ ├── IconServer.vue │ │ │ │ ├── IconSupport.vue │ │ │ │ └── IconTooling.vue │ │ ├── main.ts │ │ ├── router │ │ │ └── index.ts │ │ ├── static │ │ │ └── favicon.ico │ │ ├── stores │ │ │ └── counter.ts │ │ └── views │ │ │ ├── HomeView.vue │ │ │ └── TryView.vue │ ├── tailwind.config.js │ ├── tsconfig.app.json │ ├── tsconfig.config.json │ ├── tsconfig.json │ ├── tsconfig.vitest.json │ └── vite.config.ts └── placeholder │ ├── Cargo.toml │ └── src │ ├── lib.rs │ └── main.rs ├── docker-compose.yml ├── docs ├── .vitepress │ ├── components │ │ ├── CodeGroup.ts │ │ └── CodeGroupItem.vue │ ├── config.ts │ ├── configs │ │ ├── index.ts │ │ ├── navbar │ │ │ ├── en.ts │ │ │ └── index.ts │ │ └── sidebar │ │ │ ├── en.ts │ │ │ └── index.ts │ ├── public │ │ ├── backend │ │ ├── favicon.ico │ │ ├── frontend │ │ └── images │ │ │ ├── hero.png │ │ │ ├── logo.png │ │ │ └── sslreport.png │ └── theme │ │ └── index.ts ├── demo │ └── index.md ├── guide │ ├── backend │ │ ├── auth.md │ │ ├── commands.md │ │ ├── configuration.md │ │ ├── data.md │ │ ├── index.md │ │ └── models.md │ ├── containers │ │ ├── backend.md │ │ ├── certbot.md │ │ ├── db.md │ │ ├── migrator.md │ │ ├── nginx.md │ │ ├── placeholder.md │ │ └── worker.md │ ├── customize.md │ ├── deploy.md │ ├── deployment │ │ ├── commands.md │ │ ├── docker.md │ │ ├── jenkins.md │ │ └── kubernetes.md │ ├── frontend │ │ ├── commands.md │ │ └── index.md │ ├── index.md │ ├── setup.md │ ├── tools │ │ ├── nx.md │ │ └── yarn.md │ └── why.md ├── index.md └── reference │ ├── api.md │ ├── backend.md │ ├── benchmarks.md │ ├── create-host.md │ ├── frontend.md │ ├── proxy.md │ ├── ratings.md │ └── scripts.md ├── e2e ├── backend │ ├── jest.config.ts │ ├── src │ │ └── app.e2e.ts │ ├── tsconfig.json │ └── tsconfig.test.json └── frontend │ ├── .eslintrc.json │ ├── cypress.config.ts │ ├── cypress │ ├── fixtures │ │ └── example.json │ ├── plugins │ │ └── index.js │ └── support │ │ ├── commands.ts │ │ └── e2e.ts │ ├── src │ └── app.e2e.ts │ ├── tsconfig.json │ └── tsconfig.test.json ├── jest.config.ts ├── jest.preset.js ├── libs ├── deploy-scripts │ ├── backend.sh │ ├── color.sh │ ├── deploy.sh │ ├── frontend.sh │ ├── init.sh │ ├── placeholder.sh │ └── swap.sh ├── deployment │ └── src │ │ └── .gitkeep ├── docker-handler │ ├── .babelrc │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── docker-handler.spec.ts │ │ │ └── docker-handler.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── nest │ ├── auth │ │ ├── .babelrc │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── auth.controller.ts │ │ │ │ ├── auth.interface.ts │ │ │ │ ├── auth.module.ts │ │ │ │ ├── guards │ │ │ │ ├── email.auth.guard.ts │ │ │ │ └── session.guard.ts │ │ │ │ ├── providers │ │ │ │ └── auth.service.ts │ │ │ │ └── strategies │ │ │ │ ├── email.strategy.ts │ │ │ │ ├── nest-fastify-session │ │ │ │ ├── base.ts │ │ │ │ ├── index.ts │ │ │ │ └── strategy.ts │ │ │ │ └── session.strategy.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ └── tsconfig.spec.json │ ├── config │ │ ├── app │ │ │ ├── .babelrc │ │ │ ├── .eslintrc.json │ │ │ ├── README.md │ │ │ ├── jest.config.ts │ │ │ ├── src │ │ │ │ ├── index.ts │ │ │ │ └── lib │ │ │ │ │ ├── config.module.ts │ │ │ │ │ ├── config.service.ts │ │ │ │ │ ├── config.types.ts │ │ │ │ │ ├── config.validation.ts │ │ │ │ │ └── configuration.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.lib.json │ │ │ └── tsconfig.spec.json │ │ ├── db │ │ │ ├── .babelrc │ │ │ ├── .eslintrc.json │ │ │ ├── README.md │ │ │ ├── jest.config.ts │ │ │ ├── src │ │ │ │ ├── index.ts │ │ │ │ └── lib │ │ │ │ │ ├── config.module.ts │ │ │ │ │ ├── config.types.ts │ │ │ │ │ ├── config.validation.ts │ │ │ │ │ ├── connections.ts │ │ │ │ │ ├── default-mongo │ │ │ │ │ ├── config.service.ts │ │ │ │ │ └── configuration.ts │ │ │ │ │ ├── default-postgres │ │ │ │ │ ├── config.service.ts │ │ │ │ │ └── configuration.ts │ │ │ │ │ └── migration.list.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.lib.json │ │ │ └── tsconfig.spec.json │ │ └── graphql │ │ │ ├── .babelrc │ │ │ ├── .eslintrc.json │ │ │ ├── README.md │ │ │ ├── jest.config.ts │ │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── config.module.ts │ │ │ │ ├── config.service.ts │ │ │ │ ├── config.types.ts │ │ │ │ ├── config.validation.ts │ │ │ │ └── configuration.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.lib.json │ │ │ └── tsconfig.spec.json │ ├── models │ │ ├── base-model │ │ │ ├── .babelrc │ │ │ ├── .eslintrc.json │ │ │ ├── README.md │ │ │ ├── jest.config.ts │ │ │ ├── src │ │ │ │ ├── index.ts │ │ │ │ └── lib │ │ │ │ │ ├── base.entity.ts │ │ │ │ │ ├── base.seeder.service.ts │ │ │ │ │ └── base.service.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.lib.json │ │ │ └── tsconfig.spec.json │ │ ├── session │ │ │ ├── .babelrc │ │ │ ├── .eslintrc.json │ │ │ ├── README.md │ │ │ ├── jest.config.ts │ │ │ ├── src │ │ │ │ ├── index.ts │ │ │ │ └── lib │ │ │ │ │ ├── migrations │ │ │ │ │ ├── 1617686200270-Session.migration.ts │ │ │ │ │ ├── session.seeder.service.ts │ │ │ │ │ └── session.seeder.ts │ │ │ │ │ ├── providers │ │ │ │ │ ├── session.resolver.ts │ │ │ │ │ └── session.service.ts │ │ │ │ │ ├── session.dto.ts │ │ │ │ │ ├── session.entity.ts │ │ │ │ │ ├── session.module.ts │ │ │ │ │ └── session.pg.prisma │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.lib.json │ │ │ └── tsconfig.spec.json │ │ └── user │ │ │ ├── .babelrc │ │ │ ├── .eslintrc.json │ │ │ ├── README.md │ │ │ ├── jest.config.ts │ │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── migrations │ │ │ │ ├── 1616910769703-User.migration.ts │ │ │ │ ├── user.seeder.service.ts │ │ │ │ └── user.seeder.ts │ │ │ │ ├── providers │ │ │ │ ├── user.resolver.ts │ │ │ │ └── user.service.ts │ │ │ │ ├── user.controller.ts │ │ │ │ ├── user.dto.ts │ │ │ │ ├── user.entity.ts │ │ │ │ ├── user.module.ts │ │ │ │ └── user.pg.prisma │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.lib.json │ │ │ └── tsconfig.spec.json │ └── providers │ │ ├── cipher │ │ ├── .babelrc │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ └── cipher.provider.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ └── tsconfig.spec.json │ │ ├── db │ │ ├── .babelrc │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── db.provider.ts │ │ │ │ └── prisma │ │ │ │ ├── default.service.ts │ │ │ │ ├── mongo.service.ts │ │ │ │ └── postgres.service.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ └── tsconfig.spec.json │ │ ├── graphql │ │ ├── .babelrc │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ └── graphql.provider.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ └── tsconfig.spec.json │ │ ├── migrator │ │ ├── .babelrc │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── migration.provider.ts │ │ │ │ └── migrator.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ └── tsconfig.spec.json │ │ └── seeders │ │ ├── .babelrc │ │ ├── .eslintrc.json │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── seed.provider.ts │ │ │ └── seeders.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.lib.json │ │ └── tsconfig.spec.json └── prisma │ ├── mongo │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── base.prisma │ │ │ └── wrapper.ts │ │ └── prismerge.json │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json │ ├── postgres │ ├── .babelrc │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── base.prisma │ │ │ └── wrapper.ts │ │ ├── migrations │ │ │ ├── 20220707040353_init │ │ │ │ └── migration.sql │ │ │ └── migration_lock.toml │ │ ├── prismerge.json │ │ └── schema.prisma │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json │ └── wrapper │ ├── .babelrc │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── src │ ├── index.ts │ └── lib │ │ ├── wrapper.spec.ts │ │ └── wrapper.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── nest-cli.json ├── nx.json ├── package.json ├── rust-toolchain.toml ├── rustfmt.toml ├── tools ├── nx │ └── executors │ │ └── workspace │ │ ├── executor.json │ │ ├── interactive-command │ │ ├── impl.js │ │ ├── impl.ts │ │ └── schema.json │ │ └── package.json └── tsconfig.tools.json ├── tsconfig.base.json ├── workspace.json └── yarn.lock /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [alias] 2 | alpine = ["build", "--release", "--target", "x86_64-unknown-linux-musl"] 3 | 4 | [build] 5 | target-dir = "dist/cargo" 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = tab 6 | indent_size = 4 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.md] 11 | max_line_length = off 12 | trim_trailing_whitespace = false 13 | 14 | [*.yml] 15 | charset = utf-8 16 | indent_style = space 17 | indent_size = 4 18 | insert_final_newline = true 19 | trim_trailing_whitespace = true 20 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["**/*"], 4 | "plugins": ["@nrwl/nx"], 5 | "overrides": [ 6 | { 7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 8 | "rules": { 9 | "@nrwl/nx/enforce-module-boundaries": [ 10 | "error", 11 | { 12 | "enforceBuildableLibDependency": true, 13 | "allow": [], 14 | "depConstraints": [ 15 | { 16 | "sourceTag": "*", 17 | "onlyDependOnLibsWithTags": ["*"] 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | }, 24 | { 25 | "files": ["*.ts", "*.tsx"], 26 | "extends": ["plugin:@nrwl/nx/typescript"], 27 | "rules": {} 28 | }, 29 | { 30 | "files": ["*.js", "*.jsx"], 31 | "extends": ["plugin:@nrwl/nx/javascript"], 32 | "rules": {} 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /.yarn 2 | /node_modules 3 | /dist 4 | docs/.vitepress/public/backend 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": false, 4 | "tabWidth": 4, 5 | "trailingComma": "none", 6 | "useTabs": true, 7 | "vueIndentScriptAndStyle": true 8 | } 9 | -------------------------------------------------------------------------------- /.snyk: -------------------------------------------------------------------------------- 1 | # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. 2 | version: v1.22.1 3 | ignore: {} 4 | patch: {} 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "adrianwilczynski.toggle-hidden", 4 | "arcanis.vscode-zipfs", 5 | "bradlc.vscode-tailwindcss", 6 | "dbaeumer.vscode-eslint", 7 | "esbenp.prettier-vscode", 8 | "firsttris.vscode-jest-runner", 9 | "nrwl.angular-console", 10 | "prisma.prisma", 11 | "vue.volar", 12 | "vue.vscode-typescript-vue-plugin" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.nodePath": ".yarn/sdks", 3 | "prettier.prettierPath": ".yarn/sdks/prettier/index.js", 4 | "typescript.tsdk": ".yarn/sdks/typescript/lib", 5 | "typescript.enablePromptUseWorkspaceTsdk": true, 6 | "js/ts.implicitProjectConfig.experimentalDecorators": true, 7 | "[rust]": { 8 | "editor.defaultFormatter": "rust-lang.rust-analyzer", // Makes the magic 9 | "editor.formatOnSave": true 10 | }, 11 | "eslint.workingDirectories": [ 12 | { 13 | "directory": "apps/backend", 14 | "changeProcessCWD": true 15 | }, 16 | { 17 | "directory": "apps/frontend", 18 | "changeProcessCWD": true 19 | }, 20 | { 21 | "directory": "e2e/backend", 22 | "changeProcessCWD": true 23 | }, 24 | { 25 | "directory": "e2e/frontend", 26 | "changeProcessCWD": true 27 | } 28 | ], 29 | "files.exclude": { 30 | "**/.babelrc": false, 31 | "**/.cargo": false, 32 | "**/.editorconfig": false, 33 | "**/.eslintrc.json": false, 34 | "**/.gitignore": false, 35 | "**/.pnp.*": false, 36 | "**/.prettier*": false, 37 | "**/.snyk": false, 38 | "**/.vscode": false, 39 | "**/.yarn": false, 40 | "**/.yarnrc.yml": false, 41 | "**/Cargo.lock": false, 42 | "**/docs/.vitepress/.cache": false, 43 | "**/docs/.vitepress/.temp": false, 44 | "**/jest.config.ts": false, 45 | "**/jest.preset.js": false, 46 | "**/LICENSE": false, 47 | "**/nest-cli.json": false, 48 | "**/node_modules": false, 49 | "**/nx.json": false, 50 | "**/postcss.config.js": false, 51 | "rust-toolchain.toml": false, 52 | "**/rustfmt.toml": false, 53 | "**/tailwind.config.js": false, 54 | "**/tsconfig.json": false, 55 | "**/tsconfig.*.json": false, 56 | "**/webpack.config.js": false, 57 | "**/workspace.json": false, 58 | "**/yarn.lock": false 59 | }, 60 | "search.exclude": { 61 | "**/.pnp.*": true, 62 | "**/.yarn": true, 63 | "**/yarn.lock": true, 64 | "**/node_modules": true 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /.yarn/patches/nx-npm-14.4.2-ee5778b3a0.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/project-graph/build-dependencies/typescript-import-locator.js b/src/project-graph/build-dependencies/typescript-import-locator.js 2 | index 9f9745331b361154c54857ba77e2c8917e283330..2bdf67aa4426bc06f5e0064031ac8de9a5f69057 100644 3 | --- a/src/project-graph/build-dependencies/typescript-import-locator.js 4 | +++ b/src/project-graph/build-dependencies/typescript-import-locator.js 5 | @@ -15,6 +15,8 @@ class TypeScriptImportLocator { 6 | const extension = path.extname(filePath); 7 | if (extension !== '.ts' && 8 | extension !== '.tsx' && 9 | + // Patch dep-graph builder function to support Vue files: https://github.com/nrwl/nx/issues/2960 10 | + extension !== '.vue' && 11 | extension !== '.js' && 12 | extension !== '.jsx') { 13 | return; 14 | -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-constraints.cjs: -------------------------------------------------------------------------------- 1 | module.exports = {name: "@yarnpkg/plugin-constraints"}; -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-exec.cjs: -------------------------------------------------------------------------------- 1 | module.exports = {name: "@yarnpkg/plugin-exec"}; -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs: -------------------------------------------------------------------------------- 1 | module.exports = {name: "@yarnpkg/plugin-interactive-tools"}; -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-prune-prod.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | //prettier-ignore 3 | module.exports = { 4 | name: "@yarnpkg/plugin-prune-prod", 5 | factory: function (require) { 6 | var plugin=(()=>{var d=Object.create,c=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var m=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var g=t=>c(t,"__esModule",{value:!0});var r=t=>{if(typeof require!="undefined")return require(t);throw new Error('Dynamic require of "'+t+'" is not supported')};var h=(t,e)=>{for(var a in e)c(t,a,{get:e[a],enumerable:!0})},x=(t,e,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of f(e))!w.call(t,o)&&o!=="default"&&c(t,o,{get:()=>e[o],enumerable:!(a=u(e,o))||a.enumerable});return t},p=t=>x(g(c(t!=null?d(m(t)):{},"default",t&&t.__esModule&&"default"in t?{get:()=>t.default,enumerable:!0}:{value:t,enumerable:!0})),t);var k={};h(k,{default:()=>j});var l=p(r("@yarnpkg/cli")),s=p(r("@yarnpkg/core")),i=class extends l.BaseCommand{async execute(){let e=await s.Configuration.find(this.context.cwd,this.context.plugins),{project:a}=await s.Project.find(e,this.context.cwd),o=await s.Cache.find(e);await a.restoreInstallState({restoreResolutions:!1});for(let n of a.workspaces)n.manifest.devDependencies.clear();return(await s.StreamReport.start({configuration:e,json:!1,stdout:this.context.stdout,includeLogs:!0},async n=>{await a.install({cache:o,report:n,persistProject:!1}),await a.cacheCleanup({cache:o,report:n})})).exitCode()}};i.paths=[["prune-prod"]];var C={commands:[i]},j=C;return k;})(); 7 | return plugin; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-stage.cjs: -------------------------------------------------------------------------------- 1 | module.exports = {name: "@yarnpkg/plugin-stage"}; -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-typescript.cjs: -------------------------------------------------------------------------------- 1 | module.exports = {name: "@yarnpkg/plugin-typescript"}; -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-version.cjs: -------------------------------------------------------------------------------- 1 | module.exports = {name: "@yarnpkg/plugin-version"}; -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs: -------------------------------------------------------------------------------- 1 | module.exports = {name: "@yarnpkg/plugin-workspace-tools"}; -------------------------------------------------------------------------------- /.yarn/sdks/eslint/bin/eslint.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require eslint/bin/eslint.js 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real eslint/bin/eslint.js your application uses 20 | module.exports = absRequire(`eslint/bin/eslint.js`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/lib/api.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require eslint 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real eslint your application uses 20 | module.exports = absRequire(`eslint`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint", 3 | "version": "8.15.0-sdk", 4 | "main": "./lib/api.js", 5 | "type": "commonjs" 6 | } 7 | -------------------------------------------------------------------------------- /.yarn/sdks/integrations.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by @yarnpkg/sdks. 2 | # Manual changes might be lost! 3 | 4 | integrations: 5 | - vscode 6 | -------------------------------------------------------------------------------- /.yarn/sdks/prettier/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require prettier/index.js 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real prettier/index.js your application uses 20 | module.exports = absRequire(`prettier/index.js`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/prettier/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prettier", 3 | "version": "2.7.1-sdk", 4 | "main": "./index.js", 5 | "type": "commonjs" 6 | } 7 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/bin/tsc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/bin/tsc 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/bin/tsc your application uses 20 | module.exports = absRequire(`typescript/bin/tsc`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/bin/tsserver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/bin/tsserver 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/bin/tsserver your application uses 20 | module.exports = absRequire(`typescript/bin/tsserver`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/tsc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/lib/tsc.js 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/lib/tsc.js your application uses 20 | module.exports = absRequire(`typescript/lib/tsc.js`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/typescript.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/lib/typescript.js 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/lib/typescript.js your application uses 20 | module.exports = absRequire(`typescript/lib/typescript.js`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript", 3 | "version": "4.7.4-sdk", 4 | "main": "./lib/typescript.js", 5 | "type": "commonjs" 6 | } 7 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | enableGlobalCache: false 2 | 3 | packageExtensions: 4 | "@compodoc/compodoc@*": 5 | dependencies: 6 | "@babel/plugin-proposal-private-methods": "*" 7 | "@nestjs/mercurius@*": 8 | dependencies: 9 | lodash: "*" 10 | "@nrwl/nest@*": 11 | dependencies: 12 | semver: "*" 13 | "@nrwl/tao@*": 14 | dependencies: 15 | "@angular-devkit/architect": "*" 16 | "@angular-devkit/core": "*" 17 | "@angular-devkit/schematics": "*" 18 | "@nrwl/workspace@*": 19 | dependencies: 20 | "@angular-devkit/core": "*" 21 | "@angular-devkit/schematics": "*" 22 | "@nx-plus/vue@*": 23 | dependencies: 24 | "@nrwl/devkit": "*" 25 | "@vue/cli-service@*": 26 | dependencies: 27 | "@vue/compiler-sfc": "*" 28 | nx@*: 29 | dependencies: 30 | "@angular-devkit/architect": "*" 31 | "@angular-devkit/core": "*" 32 | snyk-docker-plugin@*: 33 | dependencies: 34 | minimatch: "*" 35 | snyk@*: 36 | dependencies: 37 | lodash: "*" 38 | 39 | plugins: 40 | - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs 41 | spec: "@yarnpkg/plugin-workspace-tools" 42 | - path: .yarn/plugins/@yarnpkg/plugin-prune-prod.cjs 43 | spec: "https://raw.githubusercontent.com/troncali/yarn-prune-prod/main/bundles/%40yarnpkg/plugin-prune-prod.js" 44 | - path: .yarn/plugins/@yarnpkg/plugin-version.cjs 45 | spec: "@yarnpkg/plugin-version" 46 | - path: .yarn/plugins/@yarnpkg/plugin-constraints.cjs 47 | spec: "@yarnpkg/plugin-constraints" 48 | - path: .yarn/plugins/@yarnpkg/plugin-exec.cjs 49 | spec: "@yarnpkg/plugin-exec" 50 | - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs 51 | spec: "@yarnpkg/plugin-interactive-tools" 52 | - path: .yarn/plugins/@yarnpkg/plugin-stage.cjs 53 | spec: "@yarnpkg/plugin-stage" 54 | - path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs 55 | spec: "@yarnpkg/plugin-typescript" 56 | 57 | yarnPath: .yarn/releases/yarn-4.0.0-rc.13.git.20220720.hash-02a48ec.cjs 58 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "placeholder" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "apps/placeholder" 4 | ] 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-present Matt Troncali 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /apps/backend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "parserOptions": { 8 | "project": ["apps/backend/tsconfig.*?.json"] 9 | }, 10 | "rules": { 11 | "@typescript-eslint/interface-name-prefix": "off", 12 | "@typescript-eslint/explicit-function-return-type": "off", 13 | "@typescript-eslint/explicit-module-boundary-types": "off", 14 | "@typescript-eslint/no-explicit-any": "off" 15 | } 16 | }, 17 | { 18 | "files": ["*.ts", "*.tsx"], 19 | "rules": {} 20 | }, 21 | { 22 | "files": ["*.js", "*.jsx"], 23 | "rules": {} 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /apps/backend/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "backend", 4 | preset: "../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.test.json" 8 | } 9 | }, 10 | transform: { 11 | "^.+\\.[tj]s$": "ts-jest" 12 | }, 13 | moduleFileExtensions: ["ts", "js", "html"], 14 | coverageDirectory: "../../dist/coverage/backend", 15 | testEnvironment: "node", 16 | reporters: [ 17 | "default", 18 | [ 19 | "jest-junit", 20 | { 21 | suiteName: "Backend Unit Tests", 22 | outputDirectory: "./dist/tests", 23 | outputName: "junit-backend-unit.xml" 24 | } 25 | ] 26 | ] 27 | }; 28 | -------------------------------------------------------------------------------- /apps/backend/src/app/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from "@nestjs/testing"; 2 | import { AppController } from "./app.controller"; 3 | import { AppService } from "./app.service"; 4 | 5 | describe("AppController", () => { 6 | let appController: AppController; 7 | // let appService: AppService; 8 | 9 | beforeEach(async () => { 10 | const app: TestingModule = await Test.createTestingModule({ 11 | controllers: [AppController], 12 | providers: [AppService] 13 | }).compile(); 14 | 15 | // appService = app.get(AppService); 16 | appController = app.get(AppController); 17 | }); 18 | 19 | describe("root", () => { 20 | it('should return "Hello World!"', async () => { 21 | // Mocking a provider 22 | // const result = new Promise((resolve, _) => 23 | // resolve("Hello World!") 24 | // ); 25 | // jest.spyOn(appService, "getHello").mockImplementation(() => result); 26 | 27 | expect(await appController.getHello()).toBe("Hello World!"); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /apps/backend/src/app/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from "@nestjs/common"; 2 | 3 | import { AppService } from "./app.service"; 4 | 5 | /** Base app-related routing, prefixed with `/{BACKEND_BASE_PATH}/` */ 6 | @Controller() 7 | export class AppController { 8 | /** 9 | * Initialize controller dependencies. 10 | * @param appService The injected `AppService` instance. 11 | */ 12 | constructor(private readonly appService: AppService) {} 13 | 14 | /** 15 | * Get a test route: `/` 16 | */ 17 | @Get() 18 | async getHello(): Promise { 19 | return this.appService.getHello(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /apps/backend/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | 3 | import { DatabaseProvider } from "@nest-vue/nest/providers/db"; 4 | import { GraphQLProvider } from "@nest-vue/nest/providers/graphql"; 5 | 6 | import { AppConfigModule } from "@nest-vue/nest/config/app"; 7 | import { AuthModule } from "@nest-vue/nest/auth"; 8 | import { UserModule } from "@nest-vue/models/user"; 9 | 10 | import { AppController } from "./app.controller"; 11 | import { AppService } from "./app.service"; 12 | 13 | @Module({ 14 | imports: [ 15 | AppConfigModule, 16 | DatabaseProvider, 17 | GraphQLProvider, 18 | AuthModule, 19 | UserModule 20 | ], 21 | controllers: [AppController], 22 | providers: [AppService] 23 | }) 24 | export class AppModule {} 25 | -------------------------------------------------------------------------------- /apps/backend/src/app/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from "@nestjs/common"; 2 | 3 | /** 4 | * Base service for the application. 5 | * 6 | * @class 7 | */ 8 | @Injectable() 9 | export class AppService { 10 | /** 11 | * Provide a test response. 12 | * @returns "Hello World!" 13 | */ 14 | async getHello(): Promise { 15 | return "Hello World!"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /apps/backend/src/migrate.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from "@nestjs/common"; 2 | import { NestFactory } from "@nestjs/core"; 3 | 4 | import { Migrator, MigrationProvider } from "@nest-vue/nest/providers/migrator"; 5 | 6 | /** 7 | * Start NestJS instance for migrations. 8 | */ 9 | async function bootstrap() { 10 | const app = await NestFactory.createApplicationContext(Migrator); 11 | const migrator = app.get(MigrationProvider); 12 | const arg = process.argv.slice(2); 13 | 14 | // Use command line argument to call `run` or `undo` migration methods. 15 | const handle = async ( 16 | methodName: "run" | "undo", 17 | startMessage: string, 18 | failMessage: string, 19 | completeMessage: string 20 | ) => { 21 | Logger.debug(`${startMessage}`); 22 | await migrator[methodName]().catch((error) => { 23 | Logger.error(`${failMessage}`); 24 | throw error; 25 | }); 26 | Logger.debug(`${completeMessage}`); 27 | }; 28 | 29 | switch (arg[0]) { 30 | case "undo": 31 | await handle( 32 | "undo", 33 | "Reverting last migration", 34 | "Rollback failed", 35 | "Rollback complete" 36 | ); 37 | break; 38 | 39 | case "run": 40 | default: 41 | await handle( 42 | "run", 43 | "Running migrations", 44 | "Migrations failed", 45 | "Migrations complete" 46 | ); 47 | } 48 | 49 | app.close(); 50 | } 51 | bootstrap(); 52 | -------------------------------------------------------------------------------- /apps/backend/src/seed.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from "@nestjs/common"; 2 | import { NestFactory } from "@nestjs/core"; 3 | 4 | import { Seeders, SeedProvider } from "@nest-vue/nest/providers/seeders"; 5 | 6 | /** 7 | * Start NestJS instance for seeding data. 8 | */ 9 | async function bootstrap() { 10 | const app = await NestFactory.createApplicationContext(Seeders); 11 | const seeder = app.get(SeedProvider); 12 | 13 | // Use the command line to specify which ORM will seed data 14 | const orm = process.argv.slice(2)[0] == "prisma" ? "Prisma" : "TypeORM"; 15 | 16 | Logger.debug(`Seeding with ${orm}`); 17 | 18 | await seeder.seed(orm).catch((error: any) => { 19 | Logger.error("Seeding failed"); 20 | throw error; 21 | }); 22 | 23 | Logger.debug("Seeding complete"); 24 | 25 | app.close(); 26 | } 27 | bootstrap(); 28 | -------------------------------------------------------------------------------- /apps/backend/src/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troncali/nest-vue/0136634f001e132c4120a1bcb5fa4fa6411766a2/apps/backend/src/static/.gitkeep -------------------------------------------------------------------------------- /apps/backend/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["node"], 7 | "emitDecoratorMetadata": true, 8 | "target": "es2017", 9 | "allowSyntheticDefaultImports": true 10 | }, 11 | "exclude": [ 12 | "**/*.spec.ts", 13 | "**/*.test.ts", 14 | "../../libs/**/*.spec.ts", 15 | "../../libs/**/*.test.ts", 16 | "jest.config.ts" 17 | ], 18 | "include": ["**/*.ts", "../../libs/**/*.ts", "webpack.config.js"] 19 | } 20 | -------------------------------------------------------------------------------- /apps/backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "references": [ 4 | { 5 | "path": "./tsconfig.app.json" 6 | }, 7 | { 8 | "path": "./tsconfig.test.json" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /apps/backend/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.spec.ts", 10 | "**/*.test.ts", 11 | "**/*.ts", 12 | "**/*.d.ts", 13 | "jest.config.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /apps/backend/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { WebpackPnpExternals } = require("webpack-pnp-externals"); 2 | // const BundleAnalyzerPlugin = 3 | // require("webpack-bundle-analyzer").BundleAnalyzerPlugin; 4 | 5 | module.exports = (config) => { 6 | // Keep PnP packages external to bundle 7 | config.externals = [ 8 | WebpackPnpExternals(), 9 | // Below are needed for Prisma client. See https://github.com/prisma/prisma/issues/6564#issuecomment-850273211 10 | "_http_common", 11 | "encoding" 12 | ]; 13 | 14 | // Output a report that allows visual inspection of chunk sizes 15 | // config.plugins.push( 16 | // new BundleAnalyzerPlugin({ 17 | // analyzerMode: "static", 18 | // reportFilename: "bundle-analysis.html", 19 | // openAnalyzer: false 20 | // }) 21 | // ); 22 | 23 | return config; 24 | }; 25 | -------------------------------------------------------------------------------- /apps/docker/docker-compose-dev.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | db: 5 | ports: 6 | - ${DB_PORT}:${DB_PORT} # For local connections during development 7 | command: [ 8 | "postgres", 9 | # Set runtime parameters 10 | "-c", 11 | "log_statement=all" # Which SQL statements to log 12 | ] 13 | 14 | nginx: 15 | volumes: 16 | - ./apps/docker/src/nginx/dev-certs:/etc/letsencrypt/live/localhost:ro 17 | - ./dist/frontend:/usr/share/nginx/html/blue:ro 18 | environment: 19 | - APP_DOMAIN=localhost 20 | - BACKEND_BLUE_NAME=host.docker.internal # localhost on host matchine 21 | - BACKEND_GREEN_NAME=host.docker.internal 22 | ports: 23 | - "80:80" 24 | - "443:443" 25 | 26 | certbot: 27 | environment: 28 | - CERTBOT_MODE=local 29 | -------------------------------------------------------------------------------- /apps/docker/docker-compose-prod.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | backend: 5 | depends_on: 6 | - db 7 | 8 | nginx: 9 | depends_on: 10 | - backend 11 | - placeholder 12 | - db 13 | volumes: 14 | - certbot-etc:/etc/letsencrypt:ro 15 | # USE 1. ports if mapping the nginx service directly to host ports 16 | ports: 17 | - "80:80" 18 | - "443:443" 19 | # OR 2. settings below if using a proxy in front of the nginx service 20 | # networks: 21 | # - proxy-network 22 | # environment: 23 | # - VIRTUAL_HOST=${APP_DOMAIN},www.${APP_DOMAIN},${STAGING_DOMAIN} 24 | # - VIRTUAL_PROTO=https 25 | # - VIRTUAL_PORT=443 26 | # expose: 27 | # - 80 28 | # - 443 29 | 30 | certbot: 31 | depends_on: 32 | - nginx 33 | 34 | worker: 35 | depends_on: 36 | - nginx 37 | - certbot 38 | 39 | secrets: 40 | DB_USERNAME: 41 | file: /srv/nest-vue/secrets/DB_USERNAME 42 | DB_PASSWORD: 43 | file: /srv/nest-vue/secrets/DB_PASSWORD 44 | BACKEND_SESSION_KEY_1: 45 | file: /srv/nest-vue/secrets/BACKEND_SESSION_KEY_1 46 | NGINX_STAGING_AUTH: 47 | file: /srv/nest-vue/secrets/NGINX_STAGING_AUTH 48 | # networks: 49 | # proxy-network: 50 | # name: proxy-network 51 | # external: true 52 | -------------------------------------------------------------------------------- /apps/docker/docker-deploy-colors.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | backend-blue: 5 | extends: 6 | file: docker-compose.yml 7 | service: backend 8 | container_name: backend-blue 9 | 10 | backend-green: 11 | extends: 12 | file: docker-compose.yml 13 | service: backend 14 | container_name: backend-green 15 | 16 | placeholder-blue: 17 | extends: 18 | file: docker-compose.yml 19 | service: placeholder 20 | container_name: backend-blue 21 | 22 | placeholder-green: 23 | extends: 24 | file: docker-compose.yml 25 | service: placeholder 26 | container_name: backend-green 27 | -------------------------------------------------------------------------------- /apps/docker/secrets/EXAMPLE_SECRET: -------------------------------------------------------------------------------- 1 | thisisasecret -------------------------------------------------------------------------------- /apps/docker/src/certbot.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM certbot/certbot:v1.29.0 2 | 3 | COPY ["./apps/docker/src/certbot/*", "./apps/docker/src/nginx/dev-certs/dev-domains.ext", "./"] 4 | 5 | RUN chmod +x entrypoint.sh deploy-hook.sh 6 | 7 | ENTRYPOINT ["./entrypoint.sh"] 8 | -------------------------------------------------------------------------------- /apps/docker/src/certbot/deploy-hook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Apply permissions for nginx to read certificates 4 | chown -R ${NGINX_UID}:${NGINX_GID} /etc/letsencrypt 5 | 6 | # Set flag to reload nginx with new certificate 7 | touch /opt/certbot/flags/restart_nginx 8 | -------------------------------------------------------------------------------- /apps/docker/src/certbot/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | if [ "${CERTBOT_MODE}" == "local" ]; then 6 | echo "CERTBOT MODE: LOCALHOST" 7 | if [ -f ./dev-certs/fullchain.pem ]; then 8 | echo "Development certificates already exist" 9 | echo "To regenerate, delete certificates from /apps/docker/src/nginx/dev-certs" 10 | else 11 | echo "Generating development certificates for localhost" 12 | openssl req -x509 -nodes -new -sha256 -days 365 -newkey rsa:2048 \ 13 | -keyout ./dev-certs/RootCA.key -out ./dev-certs/RootCA.pem \ 14 | -subj "/C=US/CN=Localhost Root CA" 15 | openssl x509 -outform pem -in ./dev-certs/RootCA.pem \ 16 | -out ./dev-certs/RootCA.crt 17 | openssl req -new -nodes -newkey rsa:2048 \ 18 | -keyout ./dev-certs/privkey.pem -out ./dev-certs/localhost.csr \ 19 | -subj "/C=US/ST=CA/L=Los Angeles/O=Localhost Certificates/CN=localhost.local" 20 | openssl x509 -req -sha256 -days 365 -in ./dev-certs/localhost.csr \ 21 | -CA ./dev-certs/RootCA.pem -CAkey ./dev-certs/RootCA.key \ 22 | -CAcreateserial -extfile ./dev-certs/dev-domains.ext \ 23 | -out ./dev-certs/fullchain.pem 24 | cat ./dev-certs/RootCA.pem >> ./dev-certs/fullchain.pem 25 | echo "IMPORTANT: add RootCA.pem and fullchain.pem to your trusted certificates" 26 | fi 27 | else 28 | echo "CERTBOT MODE: REMOTE" 29 | # Run certbot with parameters from `command` in docker-compose.yml, then run 30 | # deployment hook if a new certificate is generated 31 | certbot "$@" --deploy-hook ./deploy-hook.sh 32 | fi 33 | -------------------------------------------------------------------------------- /apps/docker/src/db-mongo.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mongo:5.0.9-focal 2 | 3 | # TODO: harden mongo security 4 | -------------------------------------------------------------------------------- /apps/docker/src/db-postgres.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:14.4-alpine3.16 2 | 3 | # Configuration scripts to run for initial db startup 4 | COPY ./apps/docker/src/db /docker-entrypoint-initdb.d 5 | 6 | RUN chmod +x /docker-entrypoint-initdb.d/*.sh 7 | 8 | # TODO: harden postgres security - see PostgreSQL Resources 1-2 9 | -------------------------------------------------------------------------------- /apps/docker/src/db/postgres-uuid.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Make uuid_generate_v4() available. 5 | 6 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname="$POSTGRES_DB"<<-EOSQL 7 | CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; 8 | EOSQL 9 | -------------------------------------------------------------------------------- /apps/docker/src/jenkins.Dockerfile: -------------------------------------------------------------------------------- 1 | # TODO: set up Jenkins container - https://www.jenkins.io/doc/book/installing/docker/ 2 | 3 | # For now, install jenkins with `brew install jenkins` 4 | -------------------------------------------------------------------------------- /apps/docker/src/nginx.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.23.1-alpine 2 | 3 | WORKDIR /etc/nginx 4 | 5 | ARG NGINX_DH_BITS 6 | ARG NGINX_GID 7 | ARG NGINX_UID 8 | 9 | # Configurations: use templates for variable interpolation (requires nginx@^1.19) 10 | COPY ./apps/docker/src/nginx/confs ./templates 11 | 12 | # Configuration scripts to run before each nginx start 13 | COPY ./apps/docker/src/nginx/scripts /docker-entrypoint.d 14 | 15 | RUN chmod +x /docker-entrypoint.d/*.sh \ 16 | # Add .template extension to all .conf files for variable interpolation 17 | && for f in ./templates/*.conf; do mv -- "$f" "${f}.template"; done \ 18 | # Generate dhparam on first image build; cached for future builds 19 | && mkdir /var/certs && apk add openssl \ 20 | && echo "Generating DH parameters (dhparam-${NGINX_DH_BITS}.pem) for SSL configuration:" \ 21 | && echo "${NGINX_DH_BITS} bit long safe prime (takes some time)" \ 22 | && openssl dhparam -out /var/certs/dhparam-${NGINX_DH_BITS}.pem ${NGINX_DH_BITS} 2>/dev/null \ 23 | # For read only support, write interpolated .conf files to /tmp/conf but read from ./confs 24 | && mkdir /tmp/confs && rm /etc/nginx/nginx.conf \ 25 | && ln -s /etc/nginx/confs/nginx.conf /etc/nginx/nginx.conf \ 26 | # Set non-root user permissions on required folders 27 | && chown -R ${NGINX_UID}:${NGINX_GID} /etc/nginx \ 28 | && touch /tmp/nginx.pid && touch /tmp/nginx-temp.pid \ 29 | && touch /tmp/error.log && touch /tmp/access.log \ 30 | && mkdir /tmp/proxy_temp && mkdir /tmp/client_temp \ 31 | && mkdir /tmp/fastcgi_temp && mkdir /tmp/uwsgi_temp \ 32 | && mkdir /tmp/scgi_temp && chown -R ${NGINX_UID}:${NGINX_GID} /tmp /opt 33 | 34 | # Run nginx as non-root user 35 | USER ${NGINX_UID}:${NGINX_GID} 36 | 37 | CMD ["nginx", "-g", "daemon off;"] 38 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/confs/basic_auth.conf: -------------------------------------------------------------------------------- 1 | auth_basic "Restricted Access"; 2 | auth_basic_user_file /run/secrets/NGINX_STAGING_AUTH; 3 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/confs/blue.conf: -------------------------------------------------------------------------------- 1 | # Set the upstreams for a "blue" deployment 2 | 3 | # Production 4 | upstream backends { 5 | # Use docker_container_name:port 6 | server ${BACKEND_BLUE_NAME}:${BACKEND_PORT}; 7 | } 8 | 9 | upstream frontends { 10 | server localhost:8081; 11 | } 12 | 13 | # Staging 14 | upstream staging_backends { 15 | server ${BACKEND_GREEN_NAME}:${BACKEND_PORT}; 16 | } 17 | 18 | upstream staging_frontends { 19 | server localhost:8091; 20 | } 21 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/confs/certbot.conf: -------------------------------------------------------------------------------- 1 | location ~ /.well-known/acme-challenge { 2 | allow all; 3 | root /usr/share/nginx/html/certbot; 4 | try_files $uri =404; 5 | } 6 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/confs/error_pages.conf: -------------------------------------------------------------------------------- 1 | # Reserved for future use 2 | 3 | #error_page 404 /404.html; 4 | 5 | # redirect server error pages to the static page /50x.html 6 | # error_page 500 502 503 504 /50x.html; 7 | # location = /50x.html { 8 | # root /usr/share/nginx/html; 9 | # } 10 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/confs/frontends.conf: -------------------------------------------------------------------------------- 1 | # Serve static files through nginx (fastest) or send to frontend for routing 2 | 3 | # Blue Deployment 4 | server { 5 | listen 8081; 6 | listen [::]:8081; 7 | server_name _; 8 | root /usr/share/nginx/html/blue; 9 | 10 | location /id { 11 | return 200 "blue"; 12 | } 13 | 14 | location / { 15 | try_files $uri $uri/ /index.html; 16 | } 17 | } 18 | 19 | # Green Deployment 20 | server { 21 | listen 8091; 22 | listen [::]:8091; 23 | server_name _; 24 | root /usr/share/nginx/html/green; 25 | 26 | location /id { 27 | return 200 "green"; 28 | } 29 | 30 | location / { 31 | try_files $uri $uri/ /index.html; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/confs/green.conf: -------------------------------------------------------------------------------- 1 | # Set the upstreams for a "green" deployment 2 | 3 | # Production 4 | upstream backends { 5 | # Use docker_container_name:port 6 | server ${BACKEND_GREEN_NAME}:${BACKEND_PORT}; 7 | } 8 | 9 | upstream frontends { 10 | server localhost:8091; 11 | } 12 | 13 | # Staging 14 | upstream staging_backends { 15 | server ${BACKEND_BLUE_NAME}:${BACKEND_PORT}; 16 | } 17 | 18 | upstream staging_frontends { 19 | server localhost:8081; 20 | } 21 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/confs/headers.conf: -------------------------------------------------------------------------------- 1 | add_header X-Frame-Options "SAMEORIGIN" always; 2 | add_header X-XSS-Protection "1; mode=block" always; 3 | add_header X-Content-Type-Options "nosniff" always; 4 | add_header Referrer-Policy "no-referrer-when-downgrade" always; 5 | add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; 6 | ### A+ SSL Rating available only with HSTS >= 6 months 7 | ### Enable HSTS only if you understand the implications: 8 | ### https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/ 9 | ### 15768000 seconds = 6 months; 31536000s = 1 year; 0 = disabled 10 | # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; 11 | proxy_set_header Host $http_host; 12 | proxy_set_header X-Real-IP $remote_addr; 13 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 14 | proxy_cache_bypass $http_upgrade; 15 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/confs/http.conf: -------------------------------------------------------------------------------- 1 | # Send all http traffic to https, except certbot challenge 2 | server { 3 | listen 80; 4 | listen [::]:80; 5 | server_name ${APP_DOMAIN} www.${APP_DOMAIN}; 6 | 7 | # Ensure successful certbot challenges if proxy is forcing SSL to nginx 8 | include /etc/nginx/confs/certbot.conf; 9 | 10 | location / { 11 | rewrite ^ https://${APP_DOMAIN}$request_uri? permanent; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/confs/https.conf: -------------------------------------------------------------------------------- 1 | # Optional: redirect https traffic to remove `www` from domain 2 | server { 3 | listen 443 ssl http2; 4 | listen [::]:443 ssl http2; 5 | server_name www.${APP_DOMAIN}; 6 | 7 | include /etc/nginx/confs/ssl.conf; 8 | 9 | return 301 https://${APP_DOMAIN}$request_uri; 10 | } 11 | 12 | # Production 13 | server { 14 | listen 443 ssl http2 default_server; 15 | listen [::]:443 ssl http2 default_server; 16 | server_name ${APP_DOMAIN}; 17 | 18 | include /etc/nginx/confs/ssl.conf; 19 | 20 | location / { 21 | proxy_pass http://frontends; 22 | } 23 | 24 | location /${BACKEND_BASE_ROUTE} { 25 | proxy_pass http://backends; 26 | } 27 | } 28 | 29 | # Staging 30 | server { 31 | listen 443 ssl http2; 32 | listen [::]:443 ssl http2; 33 | server_name ${STAGING_DOMAIN}; 34 | 35 | include /etc/nginx/confs/ssl.conf; 36 | 37 | location / { 38 | include /etc/nginx/confs/basic_auth.conf; 39 | proxy_pass http://staging_frontends; 40 | } 41 | 42 | location /${BACKEND_BASE_ROUTE} { 43 | include /etc/nginx/confs/basic_auth.conf; 44 | proxy_pass http://staging_backends; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/confs/init.conf: -------------------------------------------------------------------------------- 1 | # Temporary http configuration for initial ngxin run for certbot challenge 2 | 3 | # PID file for non-root user 4 | pid /tmp/nginx-temp.pid; 5 | 6 | http { 7 | server_tokens off; 8 | 9 | # Temporary file paths for non-root user 10 | client_body_temp_path /tmp/client_temp; 11 | proxy_temp_path /tmp/proxy_temp_path; 12 | fastcgi_temp_path /tmp/fastcgi_temp; 13 | uwsgi_temp_path /tmp/uwsgi_temp; 14 | scgi_temp_path /tmp/scgi_temp; 15 | 16 | server { 17 | listen 80 default_server; 18 | listen [::]:80; 19 | server_name _; 20 | 21 | include /etc/nginx/confs/certbot.conf; 22 | } 23 | } 24 | 25 | events {} 26 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/confs/ssl.conf: -------------------------------------------------------------------------------- 1 | 2 | # SSL Rating Guide to help tweak settings for grade vs. compatability: 3 | # https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide 4 | 5 | # certbot generates certificates (self-signed for localhost) 6 | # dhparam-*.pem is generated during first nginx image build 7 | # 90% key score for DH parameter >=2048 bits, 100% for >=4096 bits 8 | ssl_certificate /etc/letsencrypt/live/${APP_DOMAIN}/fullchain.pem; 9 | ssl_certificate_key /etc/letsencrypt/live/${APP_DOMAIN}/privkey.pem; 10 | ssl_dhparam /var/certs/dhparam-${NGINX_DH_BITS}.pem; 11 | 12 | ssl_session_timeout 1d; 13 | ssl_session_tickets off; 14 | ssl_session_cache shared:SSLcache:10m; # 4000 sessions/megabyte 15 | ssl_buffer_size 8k; 16 | ssl_stapling on; 17 | ssl_stapling_verify on; 18 | 19 | # 100% protocol score for >=TLSv1.2; 100% cipher score for >=256 bit ciphers 20 | # 90% cipher score if >=128 bit ciphers 21 | ssl_protocols TLSv1.2 TLSv1.3; 22 | ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384; 23 | ssl_ecdh_curve X25519:secp384r1:prime256v1; 24 | ssl_prefer_server_ciphers on; 25 | 26 | include /etc/nginx/confs/headers.conf; 27 | # include /etc/nginx/confs/error_pages.conf; 28 | 29 | # Ensure successful certbot challenges (if proxy in front of nginx forces SSL) 30 | include /etc/nginx/confs/certbot.conf; 31 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/dev-certs/dev-domains.ext: -------------------------------------------------------------------------------- 1 | authorityKeyIdentifier=keyid,issuer 2 | basicConstraints=CA:FALSE 3 | keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment 4 | subjectAltName = @alt_names 5 | [alt_names] 6 | DNS.1 = localhost 7 | DNS.2 = www.localhost 8 | DNS.3 = staging.localhost 9 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/scripts/40-handle-ssl-certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ME=$(basename $0) 4 | CERT_FILE="/etc/letsencrypt/live/${APP_DOMAIN}/fullchain.pem" 5 | 6 | wait_for_certbot() { 7 | echo >&3 "$ME: Waiting for certbot to generate certificate" 8 | until [ -f "$CERT_FILE" ] ; do 9 | sleep 10 10 | done 11 | } 12 | 13 | echo >&3 "$ME: Looking for existing certificate: ${CERT_FILE}" 14 | if [ ! -f "$CERT_FILE" ] ; then 15 | 16 | if [ ! "${CERTBOT_MODE}" == "local" ]; then 17 | echo >&3 "$ME: Certificate not found; starting nginx with temporary http configuration" 18 | nginx -c /etc/nginx/confs/init.conf 19 | 20 | wait_for_certbot 21 | 22 | echo >&3 "$ME: Stopping temporary configuration" 23 | nginx -c /etc/nginx/confs/init.conf -s quit 24 | else 25 | wait_for_certbot 26 | fi 27 | fi 28 | -------------------------------------------------------------------------------- /apps/docker/src/nginx/scripts/50-set-upstreams.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ME=$(basename $0) 4 | 5 | echo >&3 "$ME: Looking for existing upstreams" 6 | if [ ! -e /tmp/confs/upstreams ]; then 7 | 8 | # Default to blue deployment 9 | DEPLOY_COLOR="blue" 10 | 11 | if [ -e /opt/flags/blue ]; then 12 | rm /opt/flags/blue 13 | elif [ -e /opt/flags/green ]; then 14 | DEPLOY_COLOR="green"; 15 | rm /opt/flags/green 16 | else 17 | echo "$ME: No flag set (using default)"; 18 | fi 19 | 20 | ln -s /etc/nginx/confs/${DEPLOY_COLOR}.conf /tmp/confs/upstreams 21 | echo >&3 "$ME: Set upstreams to ${DEPLOY_COLOR}.conf" 22 | fi 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /apps/docker/src/placeholder.Dockerfile: -------------------------------------------------------------------------------- 1 | # Reduce image bloat with a prebuild to gather production files and dependencies 2 | FROM ekidd/rust-musl-builder:1.57.0 AS prebuild 3 | # Cache dependencies 4 | WORKDIR /home/rust/src/ 5 | RUN cargo new --bin apps/placeholder 6 | COPY ./Cargo.lock ./Cargo.toml ./ 7 | RUN cargo build --release && rm ./apps/placeholder/src/*.rs 8 | # Build code 9 | ADD ./apps/placeholder ./apps/placeholder 10 | RUN rm ./target/x86_64-unknown-linux-musl/release/deps/placeholder* \ 11 | && cargo build --release 12 | 13 | # Build the production image 14 | FROM alpine:3.16.1 AS production 15 | RUN addgroup -S placeholder && adduser -S -g placeholder placeholder \ 16 | && mkdir -p /app && chown -R placeholder:placeholder /app 17 | WORKDIR /app 18 | COPY --from=prebuild --chown=placeholder:placeholder \ 19 | /home/rust/src/target/x86_64-unknown-linux-musl/release/placeholder . 20 | USER placeholder 21 | EXPOSE ${BACKEND_PORT} 22 | CMD ["./placeholder"] 23 | -------------------------------------------------------------------------------- /apps/docker/src/utils/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Delete all docker containers, images, networks, and volumes, thanks to 3 | # https://stackoverflow.com/questions/34658836/docker-is-in-volume-in-use-but-there-arent-any-docker-containers 4 | 5 | removecontainers() { 6 | docker stop $(docker ps -aq) 7 | docker rm $(docker ps -aq) 8 | } 9 | 10 | armageddon() { 11 | removecontainers 12 | docker network prune -f 13 | docker rmi -f $(docker images --filter dangling=true -qa) 14 | docker volume rm $(docker volume ls --filter dangling=true -q) 15 | docker rmi -f $(docker images -qa) 16 | } 17 | 18 | removecontainers 19 | armageddon 20 | -------------------------------------------------------------------------------- /apps/docker/src/worker.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.16.1 2 | 3 | WORKDIR /app 4 | 5 | COPY ./apps/docker/src/worker/entrypoint.sh . 6 | 7 | RUN chmod +x ./entrypoint.sh \ 8 | && apk add --update --no-cache netcat-openbsd tzdata 9 | 10 | CMD [ "./entrypoint.sh" ] 11 | -------------------------------------------------------------------------------- /apps/docker/src/worker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Check every 6 hours if nginx should be reloaded 4 | function restart_nginx() { 5 | while :; do 6 | # Look for restart flag in mounted volume 7 | if [ -f ./flags/restart_nginx ]; then 8 | echo "Restarting nginx" 9 | # Signal nginx to gracefully reload without affecting traffic 10 | echo -e "POST /containers/${NGINX_CONTAINER_NAME}/kill?signal=SIGHUP HTTP/1.0\r\n" | nc -U /var/run/docker.sock 11 | rm ./flags/restart_nginx 12 | fi 13 | echo "Next nginx restart check in 6 hours" 14 | sleep 6h 15 | done 16 | } 17 | restart_nginx & 18 | 19 | # Attempt certificate renewal every 7 days 20 | function renew_certificates() { 21 | while :; do 22 | echo "Checking certificate renewal status" 23 | # Signal certbot to run 24 | echo -e "POST /containers/${CERTBOT_CONTAINER_NAME}/start HTTP/1.0\r\n" | nc -U /var/run/docker.sock 25 | echo "Next certificate renewal attempt in 7 days" 26 | sleep 7d 27 | done 28 | } 29 | renew_certificates & 30 | 31 | wait 32 | -------------------------------------------------------------------------------- /apps/frontend/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | require("@rushstack/eslint-patch/modern-module-resolution"); 3 | 4 | module.exports = { 5 | root: true, 6 | extends: [ 7 | "plugin:vue/vue3-essential", 8 | "eslint:recommended", 9 | "@vue/eslint-config-typescript/recommended", 10 | "@vue/eslint-config-prettier" 11 | ], 12 | overrides: [ 13 | { 14 | files: ["cypress/e2e/**.{cy,spec}.{js,ts,jsx,tsx}"], 15 | extends: ["plugin:cypress/recommended"] 16 | } 17 | ] 18 | }; 19 | -------------------------------------------------------------------------------- /apps/frontend/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: { config: "./apps/frontend/tailwind.config.js" }, 4 | autoprefixer: {} 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /apps/frontend/src/assets/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /apps/frontend/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/frontend/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | 19 | 42 | -------------------------------------------------------------------------------- /apps/frontend/src/components/WelcomeItem.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 87 | -------------------------------------------------------------------------------- /apps/frontend/src/components/__tests__/HelloWorld.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from "vitest"; 2 | 3 | import { mount } from "@vue/test-utils"; 4 | import HelloWorld from "../HelloWorld.vue"; 5 | 6 | describe("HelloWorld", () => { 7 | it("renders properly", () => { 8 | const wrapper = mount(HelloWorld, { props: { msg: "Hello Vitest" } }); 9 | expect(wrapper.text()).toContain("Hello Vitest"); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /apps/frontend/src/components/icons/IconBackend.vue: -------------------------------------------------------------------------------- 1 | 32 | -------------------------------------------------------------------------------- /apps/frontend/src/components/icons/IconEcosystem.vue: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /apps/frontend/src/components/icons/IconSupport.vue: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /apps/frontend/src/components/icons/IconTooling.vue: -------------------------------------------------------------------------------- 1 | 2 | 20 | -------------------------------------------------------------------------------- /apps/frontend/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import { createPinia } from "pinia"; 3 | 4 | import "@/assets/index.css"; 5 | 6 | import App from "./App.vue"; 7 | import router from "./router"; 8 | 9 | const app = createApp(App); 10 | 11 | app.use(createPinia()).use(router).mount("#app"); 12 | 13 | // TODO: ionicons for UI icons? 14 | -------------------------------------------------------------------------------- /apps/frontend/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from "vue-router"; 2 | import HomeView from "../views/HomeView.vue"; 3 | 4 | const router = createRouter({ 5 | history: createWebHistory(import.meta.env.BASE_URL), 6 | routes: [ 7 | { 8 | path: "/", 9 | name: "home", 10 | component: HomeView 11 | }, 12 | { 13 | path: "/try", 14 | name: "try", 15 | // route level code-splitting 16 | // this generates a separate chunk (About.[hash].js) for this route 17 | // which is lazy-loaded when the route is visited. 18 | component: () => import("../views/TryView.vue") 19 | } 20 | ] 21 | }); 22 | 23 | export default router; 24 | -------------------------------------------------------------------------------- /apps/frontend/src/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troncali/nest-vue/0136634f001e132c4120a1bcb5fa4fa6411766a2/apps/frontend/src/static/favicon.ico -------------------------------------------------------------------------------- /apps/frontend/src/stores/counter.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from "pinia"; 2 | 3 | export const useCounterStore = defineStore({ 4 | id: "counter", 5 | state: () => ({ 6 | counter: 0 7 | }), 8 | getters: { 9 | doubleCount: (state) => state.counter * 2 10 | }, 11 | actions: { 12 | increment() { 13 | this.counter++; 14 | } 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /apps/frontend/src/views/HomeView.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /apps/frontend/src/views/TryView.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 22 | -------------------------------------------------------------------------------- /apps/frontend/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./apps/frontend/index.html", 5 | "./apps/frontend/src/**/*.{vue,js,ts,jsx,tsx}" 6 | ], 7 | theme: { 8 | extend: {} 9 | }, 10 | plugins: [] 11 | }; 12 | -------------------------------------------------------------------------------- /apps/frontend/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../.yarn/cache/out-tsc", 5 | "types": ["node"], 6 | "composite": true, 7 | "paths": { 8 | "@/*": ["apps/frontend/src/*"] 9 | } 10 | }, 11 | "exclude": [ 12 | "src/**/*.spec.ts", 13 | "src/**/*.test.ts", 14 | "src/**/*.spec.tsx", 15 | "src/**/*.test.tsx" 16 | ], 17 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"] 18 | } 19 | -------------------------------------------------------------------------------- /apps/frontend/tsconfig.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": [ 4 | "vite.config.*", 5 | "vitest.config.*", 6 | "cypress.config.*", 7 | "tailwind.config.*", 8 | "postcss.config.*" 9 | ], 10 | "compilerOptions": { 11 | "composite": true, 12 | "types": ["node"] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /apps/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "preserve", 5 | "importHelpers": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "skipLibCheck": true, 9 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"] 10 | }, 11 | "references": [ 12 | { 13 | "path": "./tsconfig.config.json" 14 | }, 15 | { 16 | "path": "./tsconfig.app.json" 17 | }, 18 | { 19 | "path": "./tsconfig.vitest.json" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /apps/frontend/tsconfig.vitest.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "lib": [], 6 | "types": ["node", "jsdom"], 7 | "outDir": "../../.yarn/cache/out-tsc", 8 | "paths": { 9 | "@/*": ["./src/*"] 10 | } 11 | }, 12 | "include": [ 13 | "**/src/**/*.spec.ts", 14 | "**/src/**/*.test.ts", 15 | "**/src/**/*.spec.tsx", 16 | "**/src/**/*.test.tsx", 17 | "**/src/**/*.vue", 18 | "**/src/env.d.ts" 19 | ], 20 | "exclude": [] 21 | } 22 | -------------------------------------------------------------------------------- /apps/frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig, type UserConfigExport } from "vite"; 3 | import type { UserConfigExport as VitestConfig } from "vitest/config"; 4 | import { fileURLToPath, URL } from "url"; 5 | import vue from "@vitejs/plugin-vue"; 6 | import vueJsx from "@vitejs/plugin-vue-jsx"; 7 | 8 | // https://vitejs.dev/config/ 9 | export default defineConfig({ 10 | plugins: [vue(), vueJsx()], 11 | publicDir: "./src/static", 12 | cacheDir: "../../.yarn/cache/vite", 13 | resolve: { 14 | alias: { 15 | "@": fileURLToPath(new URL("./src", import.meta.url)) 16 | } 17 | }, 18 | build: { 19 | outDir: "../../dist/apps/frontend" 20 | }, 21 | preview: { 22 | open: false 23 | }, 24 | server: { 25 | port: 8080, 26 | strictPort: true, 27 | open: true 28 | }, 29 | test: { 30 | environment: "jsdom", 31 | watch: false, 32 | cache: { dir: "../../.yarn/cache/vitest/frontend" }, 33 | reporters: ["default", "json", "junit"], 34 | outputFile: { 35 | json: "../../dist/tests/vitest-frontend-unit.json", 36 | junit: "../../dist/tests/junit-vitest-frontend-unit.xml" 37 | } 38 | }, 39 | css: { 40 | postcss: "./apps/frontend" 41 | } 42 | } as UserConfigExport & VitestConfig); 43 | -------------------------------------------------------------------------------- /apps/placeholder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "placeholder" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | 10 | -------------------------------------------------------------------------------- /apps/placeholder/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::prelude::*; 2 | use std::net::TcpListener; 3 | use std::net::TcpStream; 4 | 5 | use placeholder::ThreadPool; 6 | 7 | const GET: &[u8; 15] = b"GET /api HTTP/1"; 8 | const FOUND: &str = "HTTP/1.1 200 OK"; 9 | const ERROR: &str = "HTTP/1.1 404 NOT FOUND"; 10 | const PLACEHOLDER: &str = "Placeholder"; 11 | const NOT_FOUND: &str = "Not found (Placeholder)"; 12 | 13 | fn main() { 14 | let listener = TcpListener::bind("0.0.0.0:3001").unwrap(); 15 | let pool = ThreadPool::new(1); 16 | 17 | for stream in listener.incoming() { 18 | let stream = stream.unwrap(); 19 | 20 | pool.execute(|| { 21 | handle_connection(stream); 22 | }); 23 | } 24 | 25 | println!("Shutting down."); 26 | } 27 | 28 | fn handle_connection(mut stream: TcpStream) { 29 | let mut buffer = [0; 1024]; 30 | stream.read(&mut buffer).unwrap(); 31 | 32 | let (status_line, content) = if buffer.starts_with(GET) { 33 | (&FOUND, &PLACEHOLDER) 34 | } else { 35 | (&ERROR, &NOT_FOUND) 36 | }; 37 | 38 | let response = format!( 39 | "{}\r\nContent-Length: {}\r\nContent-Type: text/plain\r\n\r\n{}", 40 | status_line, 41 | content.len(), 42 | content 43 | ); 44 | 45 | stream.write(response.as_bytes()).unwrap(); 46 | stream.flush().unwrap(); 47 | } 48 | -------------------------------------------------------------------------------- /docs/.vitepress/config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitepress"; 2 | import { fileURLToPath, URL } from "url"; 3 | 4 | import { navbar } from "./configs"; 5 | import { sidebar } from "./configs"; 6 | 7 | export default defineConfig({ 8 | base: "/", 9 | outDir: "../dist/docs/vitepress", 10 | 11 | // site config 12 | lang: "en-US", 13 | title: "nest-vue", 14 | description: "Full-stack monorepo template.", 15 | 16 | // theme and its config 17 | themeConfig: { 18 | logo: "/images/logo.png", 19 | siteTitle: "nest‑vue", 20 | nav: navbar.en, 21 | sidebar: sidebar.en, 22 | socialLinks: [ 23 | { 24 | icon: "github", 25 | link: "https://github.com/troncali/nest-vue" 26 | } 27 | ], 28 | editLink: { 29 | pattern: "https://github.com/troncali/nest-vue/edit/main/docs/:path" 30 | }, 31 | footer: { 32 | message: "MIT Licensed.", 33 | copyright: "Copyright © 2020-present Matt Troncali" 34 | } 35 | }, 36 | vite: { 37 | publicDir: "./.vitepress/public", 38 | cacheDir: "../.yarn/cache/vitepress", 39 | server: { 40 | port: 9998, 41 | strictPort: true, 42 | open: true 43 | } 44 | }, 45 | markdown: { 46 | theme: "github-dark-dimmed" 47 | } 48 | }); 49 | -------------------------------------------------------------------------------- /docs/.vitepress/configs/index.ts: -------------------------------------------------------------------------------- 1 | export * as navbar from "./navbar"; 2 | export * as sidebar from "./sidebar"; 3 | -------------------------------------------------------------------------------- /docs/.vitepress/configs/navbar/en.ts: -------------------------------------------------------------------------------- 1 | import { DefaultTheme } from "vitepress"; 2 | 3 | export const en: DefaultTheme.NavItem[] = [ 4 | { 5 | text: "Why?", 6 | link: "/guide/why.md" 7 | }, 8 | { 9 | text: "Guide", 10 | link: "/guide/index.md" 11 | }, 12 | { 13 | text: "Reference", 14 | items: [ 15 | { 16 | text: "Yarn Scripts", 17 | link: "/reference/scripts.md" 18 | }, 19 | { 20 | text: "Benchmarks", 21 | link: "/reference/benchmarks.md" 22 | }, 23 | { 24 | text: "SSL & Other Ratings", 25 | link: "/reference/ratings.md" 26 | }, 27 | { 28 | text: "Create A Host", 29 | link: "/reference/create-host.md" 30 | }, 31 | { 32 | text: "Multi-Project Proxy", 33 | link: "/reference/proxy.md" 34 | }, 35 | { 36 | text: "Backend (NestJS)", 37 | items: [ 38 | { 39 | text: "Project Documentation", 40 | link: "/reference/backend.md" 41 | }, 42 | { 43 | text: "Postman API", 44 | link: "https://www.postman.com/troncali/workspace/nest-vue" 45 | } 46 | ] 47 | }, 48 | { 49 | text: "Frontend (Vue)", 50 | items: [ 51 | { 52 | text: "Project Documentation", 53 | link: "/reference/frontend.md" 54 | } 55 | ] 56 | } 57 | ] 58 | }, 59 | { 60 | text: "Demo", 61 | link: "/demo/index.md" 62 | } 63 | ]; 64 | -------------------------------------------------------------------------------- /docs/.vitepress/configs/navbar/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./en"; 2 | -------------------------------------------------------------------------------- /docs/.vitepress/configs/sidebar/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./en"; 2 | -------------------------------------------------------------------------------- /docs/.vitepress/public/backend: -------------------------------------------------------------------------------- 1 | ../../../dist/docs/backend -------------------------------------------------------------------------------- /docs/.vitepress/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troncali/nest-vue/0136634f001e132c4120a1bcb5fa4fa6411766a2/docs/.vitepress/public/favicon.ico -------------------------------------------------------------------------------- /docs/.vitepress/public/frontend: -------------------------------------------------------------------------------- 1 | ../../../dist/apps/frontend -------------------------------------------------------------------------------- /docs/.vitepress/public/images/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troncali/nest-vue/0136634f001e132c4120a1bcb5fa4fa6411766a2/docs/.vitepress/public/images/hero.png -------------------------------------------------------------------------------- /docs/.vitepress/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troncali/nest-vue/0136634f001e132c4120a1bcb5fa4fa6411766a2/docs/.vitepress/public/images/logo.png -------------------------------------------------------------------------------- /docs/.vitepress/public/images/sslreport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troncali/nest-vue/0136634f001e132c4120a1bcb5fa4fa6411766a2/docs/.vitepress/public/images/sslreport.png -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import DefaultTheme from "vitepress/theme"; 2 | 3 | import CodeGroup from "../components/CodeGroup"; 4 | import CodeGroupItem from "../components/CodeGroupItem.vue"; 5 | 6 | export default { 7 | ...DefaultTheme, 8 | enhanceApp({ app }) { 9 | // register global components 10 | app.component("CodeGroup", CodeGroup); 11 | app.component("CodeGroupItem", CodeGroupItem); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /docs/demo/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | --- 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/guide/backend/auth.md: -------------------------------------------------------------------------------- 1 | # Backend Authentication 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/backend/index.md: -------------------------------------------------------------------------------- 1 | # Backend Structure 2 | 3 | The backend is an implementation of NestJS. NestJS's documentation is available at [https://docs.nestjs.com](https://docs.nestjs.com). Monorepo documentation specific to this backend is [available here](/reference/backend.md). 4 | 5 | ## App 6 | 7 | The backend application has the following structure in `apps/backend/src`: 8 | 9 | | File | Purpose | 10 | | :---------------------- | :----------------------------------------------------------------------------------------- | 11 | | `main.ts` | Bootstraps the main application and settings. | 12 | | `migrate.ts` | Bootstraps the application to run TypeORM migrations. | 13 | | `seed.ts` | Bootstraps the application to seed data. | 14 | | `app/app.module.ts` | Encapsulates all application dependencies, including controllers, providers, and services. | 15 | | `app/app.controller.ts` | Establishes global application routes that are not handled by other controllers. | 16 | | `app/app.service.ts` | Provides global application functions to be used by other modules. | 17 | 18 | ## Libs 19 | 20 | The `AppModule` primarily imports library modules from `libs/nest` and `libs/prisma`. These libraries establish the controllers, models, providers, and services that implement the core functionality of the backend application. [Documentation for these modules is available here](/reference/backend.md), and the following pages provide high-level overviews of key parts. 21 | -------------------------------------------------------------------------------- /docs/guide/containers/backend.md: -------------------------------------------------------------------------------- 1 | # Backend Container 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/containers/certbot.md: -------------------------------------------------------------------------------- 1 | # Certbot 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/containers/db.md: -------------------------------------------------------------------------------- 1 | # Database 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/containers/migrator.md: -------------------------------------------------------------------------------- 1 | # Migrator 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/containers/nginx.md: -------------------------------------------------------------------------------- 1 | # NGINX 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/containers/placeholder.md: -------------------------------------------------------------------------------- 1 | # Placeholder 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/containers/worker.md: -------------------------------------------------------------------------------- 1 | # Worker 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/customize.md: -------------------------------------------------------------------------------- 1 | # Customize 2 | 3 | There are a number of ways to extend the monorepo or replace parts of it. [36 official Nx plugins](https://nx.dev/community#create-nx-plugin) support frameworks and libraries like React, Express, and Angular—plus contributions from the community for Vite, Rust, Solid, and others. 4 | 5 | These plugins provide generators, executors, and other tools to help scaffold new applications that add to or replace pieces of the monorepo. It is also possible to implement any CLI-based framework or library that does not have a specific plugin by using Nx's `run-commands` executor and specifying implicit file dependencies along with file outputs to cache. (See the `frontend` and Prisma projects in `workspace.json` for example configurations.) 6 | 7 | Ultimatley, there are many directions the monorepo can go. 8 | -------------------------------------------------------------------------------- /docs/guide/deployment/commands.md: -------------------------------------------------------------------------------- 1 | # Deployment Commands 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/deployment/docker.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | 3 | In progress. 4 | 5 | ## Share Host Ports 80/443 6 | 7 | To deploy multiple instances of this monorepo on one host—or other HTTP/HTTPS projects that must be publicly exposed on standard ports—[set up a proxy](/reference/proxy.md) to route traffic from ports 80 and 443 of the host to the appropriate Docker container. 8 | -------------------------------------------------------------------------------- /docs/guide/deployment/jenkins.md: -------------------------------------------------------------------------------- 1 | # Jenkins 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/deployment/kubernetes.md: -------------------------------------------------------------------------------- 1 | # Kubernetes 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/frontend/commands.md: -------------------------------------------------------------------------------- 1 | # Frontend Commands 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/frontend/index.md: -------------------------------------------------------------------------------- 1 | # Frontend Structure 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/index.md: -------------------------------------------------------------------------------- 1 | # The Stack 2 | 3 | Here's what this [monorepo](https://nx.dev/guides/why-monorepos) helps to more easily deploy, so the focus can stay on substance: 4 | 5 | ## Apps 6 | 7 | - [**Nest 9 Backend**](https://nestjs.com) – progressive [Node.js](https://nodejs.org/en/) framework for building efficient, reliable, and scalable server-side applications. Configured with [Fastify](https://www.fastify.io) for [better performance than Express](../reference/benchmarks.md#nest). 8 | - [**Vue 3 Frontend**](https://vuejs.org) – JavaScript framework with a declarative and component-based programming model that helps efficiently develop user interfaces. With [Vite](https://vitejs.dev), [Vitest](https://vitest.dev), and [TailwindCSS 3](https://tailwindcss.com). 9 | - [**NGINX**](https://www.nginx.com/resources/wiki/) – high-performance HTTP server and reverse proxy with simple configuration and low resource consumption. 10 | - **Database of Choice** – agnostic data access through [Prisma 4](https://prisma.io), [TypeORM 0.3](https://typeorm.io), and [GraphQL](https://graphql.org) via [Mercurius](https://mercurius.dev) for [better performance than Apollo](../reference/benchmarks.md#mercurius-graphql). [PostgreSQL](https://www.postgresql.org) and [MongoDB](https://www.mongodb.com) setups included, but configure and use any supported database. 11 | 12 | ## Tools 13 | 14 | - [**Nx 14**](https://nx.dev) – extensible build framework with computation caching to rebuild only what is necessary; includes Nest and Vue plugins that expose their CLI generators, etc. 15 | - [**Yarn 3**](https://yarnpkg.com) – slim dependency management using [Plug'N'Play](https://yarnpkg.com/features/pnp) for smaller repositories. 16 | - [**Docker**](https://www.docker.com/get-started) – spin up the database, backend, and frontend with consistent environments both locally and on remote hosts. 17 | - [**Jenkins**](https://www.jenkins.io) – base CI/CD pipeline that can be built out to meet requirements. 18 | - [**Certbot**](https://certbot.eff.org) – SSL certificate generation for both local development and remote hosts. 19 | -------------------------------------------------------------------------------- /docs/guide/tools/nx.md: -------------------------------------------------------------------------------- 1 | # Nx 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/tools/yarn.md: -------------------------------------------------------------------------------- 1 | # Yarn 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/guide/why.md: -------------------------------------------------------------------------------- 1 | # Why? 2 | 3 | Packages, tools, and applications take time to research, select, configure, optimize, and deploy across different platforms, environments, and repositories. This monorepo collects an opinionated (but customizable) implementation of these various decision points with default selections that balance security, performance, and developer productivity. There are also [other benefits of a monorepo](https://nx.dev/guides/why-monorepos). 4 | 5 | However, this monorepo is just a starting point. Use it as a base to build upon, add or replace parts to make it a more ideal stack, or simply use it as a reference to implement pieces in another project. 6 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | title: nest-vue 5 | titleTemplate: Full-stack monorepo template 6 | 7 | hero: 8 | name: nest-vue 9 | title: home 10 | text: monorepo template 11 | tagline: NGINX, Nest 9, and Vue 3. Container deployments. Replaceable frameworks. 12 | image: /images/hero.png 13 | actions: 14 | - text: Why? 15 | link: /guide/why 16 | theme: alt 17 | - text: Get Started 18 | link: /guide/setup 19 | theme: brand 20 | - text: Demo 21 | link: /demo/index 22 | theme: alt 23 | features: 24 | - title: Yarn + Nx 25 | details: Slim Plug'n'Play dependency management, workspace generators for apps and libs, and computation caching for builds and tests. 26 | - title: Modular 27 | details: Default frameworks include boilerplate plumbing but can be replaced or supplemented with Angular, Express, React, Rust, and more. 28 | - title: Data Agnostic 29 | details: Access data through Prisma, TypeORM, and GraphQL, with Postgres and Mongo setups included and others supported. 30 | - title: Docker-ized 31 | details: Apps, the database, and NGINX build into deployable containers for local development and production, with no-fuss SSL. 32 | - title: CI/CD Ready 33 | details: Blue-green deployment strategy for zero downtime, with yarn scripts for deployment consistency and base Jenkins pipeline. 34 | - title: Opinionated 35 | details: Default implementations attempt to follow best practices and optimize performance and security, which is subjective. 36 | -------------------------------------------------------------------------------- /docs/reference/api.md: -------------------------------------------------------------------------------- 1 | # Postman API 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/reference/backend.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | --- 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/reference/frontend.md: -------------------------------------------------------------------------------- 1 | # Frontend Documentation 2 | 3 | In progress. 4 | -------------------------------------------------------------------------------- /docs/reference/ratings.md: -------------------------------------------------------------------------------- 1 | # SSL & Other Ratings 2 | 3 | ## SSL Labs: A+ 4 | 5 | This monorepo's default NGINX configuration results in an "A" rating out of the box. An "A+" rating is easy: set the HSTS header on line 10 of `/apps/docker/src/nginx/confs/headers.conf` to 6 months or longer, but only when ready and the implications are understood ([see section on Testing HTTP Strict Transport Security with Care](https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/)). 6 | 7 | ![](/images/sslreport.png) 8 | _This site is now deployed [behind a proxy](./proxy.md) with slightly different SSL settings, but the result above was captured as a direct deployment without the proxy._ 9 | -------------------------------------------------------------------------------- /e2e/backend/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "backend-e2e", 4 | preset: "../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.test.json" 8 | } 9 | }, 10 | transform: { 11 | "^.+\\.[tj]s$": "ts-jest" 12 | }, 13 | moduleFileExtensions: ["ts", "js", "html", "json"], 14 | coverageDirectory: "../../dist/tests/coverage/backend", 15 | testEnvironment: "node", 16 | reporters: [ 17 | "default", 18 | [ 19 | "jest-junit", 20 | { 21 | suiteName: "Backend E2E Tests", 22 | outputDirectory: "./dist/tests", 23 | outputName: "junit-backend-e2e.xml" 24 | } 25 | ] 26 | ], 27 | testMatch: ["/**/*.e2e.[jt]s?(x)"] 28 | }; 29 | -------------------------------------------------------------------------------- /e2e/backend/src/app.e2e.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from "@nestjs/testing"; 2 | import { INestApplication } from "@nestjs/common"; 3 | import { 4 | FastifyAdapter, 5 | NestFastifyApplication 6 | } from "@nestjs/platform-fastify"; 7 | import * as request from "supertest"; 8 | import { AppModule } from "@apps/backend/src/app/app.module"; 9 | 10 | describe("AppController (e2e)", () => { 11 | let app: INestApplication; 12 | 13 | beforeEach(async () => { 14 | const moduleFixture: TestingModule = await Test.createTestingModule({ 15 | imports: [AppModule] 16 | }).compile(); 17 | 18 | // For @nestjs/platform-express 19 | // app = moduleFixture.createNestApplication(); 20 | 21 | // For @nestjs/platform-fastify 22 | app = moduleFixture.createNestApplication( 23 | new FastifyAdapter() 24 | ); 25 | await app.init(); 26 | await app.getHttpAdapter().getInstance().ready(); // For Fastify 27 | }); 28 | 29 | it("/ (GET)", () => { 30 | return request(app.getHttpServer()) 31 | .get("/") 32 | .expect(200) 33 | .expect("Hello World!"); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /e2e/backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "references": [ 4 | { 5 | "path": "./tsconfig.test.json" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /e2e/backend/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.e2e.[jt]s", 10 | "@apps/backend/**/*.[jt]s", 11 | "@libs/**/*.[jt]s", 12 | "jest.config.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /e2e/frontend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["src/plugins/index.js"], 11 | "rules": { 12 | "@typescript-eslint/no-var-requires": "off", 13 | "no-undef": "off" 14 | } 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /e2e/frontend/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "cypress"; 2 | 3 | module.exports = defineConfig({ 4 | e2e: { 5 | specPattern: "./src/**/*.{cy,spec,e2e}.{js,jsx,ts,tsx}", 6 | baseUrl: "http://localhost:4173", 7 | fixturesFolder: "./cypress/fixtures", 8 | supportFolder: "./cypress/support", 9 | video: false, 10 | videosFolder: "../../dist/e2e/frontend/videos", 11 | screenshotsFolder: "../../dist/e2e/frontend/screenshots", 12 | reporter: "junit", 13 | reporterOptions: { 14 | mochaFile: "../../dist/tests/junit-frontend-e2e-[hash].xml", 15 | toConsole: false 16 | } 17 | } 18 | }); 19 | -------------------------------------------------------------------------------- /e2e/frontend/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /e2e/frontend/cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | const { preprocessTypescript } = require("@nrwl/cypress/plugins/preprocessor"); 15 | 16 | module.exports = (on, config) => { 17 | // `on` is used to hook into various events Cypress emits 18 | // `config` is the resolved Cypress config 19 | // Preprocess Typescript file using Nx helper 20 | // on("file:preprocessor", preprocessTypescript(config)); // taken out in nx@12.9.0 21 | }; 22 | -------------------------------------------------------------------------------- /e2e/frontend/cypress/support/commands.ts: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************** 3 | // This example commands.ts shows you how to 4 | // create various custom commands and overwrite 5 | // existing commands. 6 | // 7 | // For more comprehensive examples of custom 8 | // commands please read more here: 9 | // https://on.cypress.io/custom-commands 10 | // *********************************************** 11 | // 12 | // 13 | // -- This is a parent command -- 14 | // Cypress.Commands.add('login', (email, password) => { ... }) 15 | // 16 | // 17 | // -- This is a child command -- 18 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 19 | // 20 | // 21 | // -- This is a dual command -- 22 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 23 | // 24 | // 25 | // -- This will overwrite an existing command -- 26 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) 27 | // 28 | // declare global { 29 | // namespace Cypress { 30 | // interface Chainable { 31 | // login(email: string, password: string): Chainable 32 | // drag(subject: string, options?: Partial): Chainable 33 | // dismiss(subject: string, options?: Partial): Chainable 34 | // visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable 35 | // } 36 | // } 37 | // } 38 | -------------------------------------------------------------------------------- /e2e/frontend/cypress/support/e2e.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import "./commands"; 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /e2e/frontend/src/app.e2e.ts: -------------------------------------------------------------------------------- 1 | // https://docs.cypress.io/api/introduction/api.html 2 | 3 | describe("frontend-e2e", () => { 4 | it("visits the app root url", () => { 5 | cy.visit("/"); 6 | cy.contains("h1", "Frontend Demo"); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /e2e/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.test.json" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /e2e/frontend/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.web.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "composite": true, 6 | "isolatedModules": false, 7 | "target": "es5", 8 | "outDir": "../../.yarn/cache/out-tsc", 9 | "allowJs": true, 10 | "lib": ["es5", "dom"], 11 | "types": ["cypress"] 12 | }, 13 | "include": [ 14 | "./**/*.ts", 15 | "./cypress.config.ts", 16 | "./src/**/*", 17 | "./cypress/support/**/*", 18 | "../../apps/frontend/**/*.[jt]s", 19 | "../../apps/frontend/**/*.vue", 20 | "../../libs/**/*.[jt]s" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | const { getJestProjects } = require("@nrwl/jest"); 2 | 3 | export default { 4 | projects: getJestProjects() 5 | // projects: [ 6 | // "/apps/backend/", 7 | // "/e2e/backend/", 8 | // "/apps/frontend/" 9 | // ] 10 | }; 11 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require("@nrwl/jest/preset").default; 2 | 3 | module.exports = { ...nxPreset }; 4 | -------------------------------------------------------------------------------- /libs/deploy-scripts/backend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z $DEPLOY_COLOR ]; then 4 | . ./libs/deploy-scripts/color.sh $@ 5 | fi 6 | 7 | echo "Deploying backend to ${DEPLOY_COLOR}" 8 | 9 | # Stop current backend container if it's running 10 | docker --context ${DOCKER_REMOTE_CONTEXT} stop backend-${DEPLOY_COLOR} 11 | docker --context ${DOCKER_REMOTE_CONTEXT} rm -f backend-${DEPLOY_COLOR} 12 | 13 | # Start backend container 14 | docker --context ${DOCKER_REMOTE_CONTEXT} compose -p ${DOCKER_PROJECT_NAME} \ 15 | -f docker-compose.yml -f ./apps/docker/docker-compose-prod.yml \ 16 | -f ./apps/docker/docker-deploy-colors.yml up -d backend-${DEPLOY_COLOR} 17 | -------------------------------------------------------------------------------- /libs/deploy-scripts/color.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "${1}" == "production" ] 4 | then 5 | DEPLOY_COLOR="$(curl -s https://${APP_DOMAIN}/id)" 6 | else 7 | if [ "$(curl -s https://${APP_DOMAIN}/id)" == "${DEPLOY_COLOR:=blue}" ] 8 | then 9 | DEPLOY_COLOR=green 10 | fi 11 | fi 12 | -------------------------------------------------------------------------------- /libs/deploy-scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z $DEPLOY_COLOR ]; then 4 | . ./libs/deploy-scripts/color.sh $@ 5 | fi 6 | 7 | . ./libs/deploy-scripts/backend.sh 8 | . ./libs/deploy-scripts/frontend.sh 9 | -------------------------------------------------------------------------------- /libs/deploy-scripts/frontend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z $DEPLOY_COLOR ]; then 4 | . ./libs/deploy-scripts/color.sh $@ 5 | fi 6 | 7 | echo "Deploying frontend to ${DEPLOY_COLOR}" 8 | 9 | # Clear existing files 10 | ssh ${SSH_HOST_ALIAS} "rm -rf /var/lib/docker/volumes/${DOCKER_PROJECT_NAME}_frontend-${DEPLOY_COLOR}/_data/{..?*,.[!.]*,*}" 11 | 12 | # Copy frontend files 13 | scp -r ./dist/frontend/* ${SSH_HOST_ALIAS}:/var/lib/docker/volumes/${DOCKER_PROJECT_NAME}_frontend-${DEPLOY_COLOR}/_data 14 | -------------------------------------------------------------------------------- /libs/deploy-scripts/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | docker --context $DOCKER_REMOTE_CONTEXT compose \ 4 | -p $DOCKER_PROJECT_NAME -f docker-compose.yml \ 5 | -f ./apps/docker/docker-compose-prod.yml up -d 6 | 7 | . ./libs/deploy-scripts/frontend.sh production 8 | -------------------------------------------------------------------------------- /libs/deploy-scripts/placeholder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z $DEPLOY_COLOR ]; then 4 | . ./libs/deploy-scripts/color.sh $@ 5 | fi 6 | 7 | echo "Deploying placeholder to ${DEPLOY_COLOR}" 8 | 9 | # Stop current backend container if it's running 10 | docker --context ${DOCKER_REMOTE_CONTEXT} stop backend-${DEPLOY_COLOR} 11 | docker --context ${DOCKER_REMOTE_CONTEXT} rm -f backend-${DEPLOY_COLOR} 12 | 13 | # Start placeholder container 14 | docker --context ${DOCKER_REMOTE_CONTEXT} compose -p ${DOCKER_PROJECT_NAME} \ 15 | -f docker-compose.yml -f ./apps/docker/docker-compose-prod.yml \ 16 | -f ./apps/docker/docker-deploy-colors.yml up -d placeholder-${DEPLOY_COLOR} 17 | -------------------------------------------------------------------------------- /libs/deploy-scripts/swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z $DEPLOY_COLOR ]; then 4 | . ./libs/deploy-scripts/color.sh $@ 5 | fi 6 | 7 | echo "Swapping $DEPLOY_COLOR to production" 8 | # Update nginx upstreams based on deployment color 9 | ssh $SSH_HOST_ALIAS \ 10 | "rm /var/lib/docker/volumes/${DOCKER_PROJECT_NAME}_nginx-confs/_data/upstreams" 11 | docker --context $DOCKER_REMOTE_CONTEXT exec nginx ln \ 12 | -s /etc/nginx/confs/${DEPLOY_COLOR}.conf /tmp/confs/upstreams 13 | 14 | echo "Gracefully reloading nginx configuration" 15 | # Set flag to restart nginx; restart worker container to trigger now. (Worker 16 | # checks nginx flags every 6 hours by default.) 17 | ssh $SSH_HOST_ALIAS \ 18 | "touch /var/lib/docker/volumes/${DOCKER_PROJECT_NAME}_worker-flags/_data/restart_nginx; \ 19 | docker restart worker > /dev/null" 20 | -------------------------------------------------------------------------------- /libs/deployment/src/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troncali/nest-vue/0136634f001e132c4120a1bcb5fa4fa6411766a2/libs/deployment/src/.gitkeep -------------------------------------------------------------------------------- /libs/docker-handler/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/docker-handler/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/docker-handler/README.md: -------------------------------------------------------------------------------- 1 | # docker-handler 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test docker-handler` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/docker-handler/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "docker-handler", 4 | preset: "../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../coverage/libs/docker-handler" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/docker-handler/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/docker-handler"; 2 | -------------------------------------------------------------------------------- /libs/docker-handler/src/lib/docker-handler.spec.ts: -------------------------------------------------------------------------------- 1 | // import { DockerHandler } from "./docker-handler"; 2 | 3 | // describe("dockerHandler", () => { 4 | // it("should work", () => { 5 | // expect(DockerHandler()).toEqual("docker-handler"); 6 | // }); 7 | // }); 8 | -------------------------------------------------------------------------------- /libs/docker-handler/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/docker-handler/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"] 8 | }, 9 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 10 | "include": ["**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /libs/docker-handler/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/auth/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/auth/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/auth/README.md: -------------------------------------------------------------------------------- 1 | # nest-auth 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test nest-auth` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/auth/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "nest-auth", 4 | preset: "../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../coverage/libs/nest/auth" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/auth/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/auth.module"; 2 | -------------------------------------------------------------------------------- /libs/nest/auth/src/lib/auth.interface.ts: -------------------------------------------------------------------------------- 1 | import { FastifyRequest } from "fastify"; 2 | import { UserSession } from "@nest-vue/models/session"; 3 | 4 | export interface AuthRequest extends FastifyRequest { 5 | /** Session of the authenticated user making the request. */ 6 | user?: UserSession | null; 7 | } 8 | 9 | /** The credentials asserted for authentication. */ 10 | export interface AuthCredentials { 11 | /** The email asserted for authentication. */ 12 | email: string; 13 | /** The password asserted for authentication. */ 14 | password: string; 15 | } 16 | -------------------------------------------------------------------------------- /libs/nest/auth/src/lib/auth.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | import { PassportModule } from "@nestjs/passport"; 3 | 4 | import { AppConfigModule } from "@nest-vue/nest/config/app"; 5 | import { CipherProvider } from "@nest-vue/nest/providers/cipher"; 6 | import { SessionModule } from "@nest-vue/models/session"; 7 | import { UserModule } from "@nest-vue/models/user"; 8 | 9 | import { AuthController } from "./auth.controller"; 10 | import { AuthService } from "./providers/auth.service"; 11 | 12 | import { EmailStrategy } from "./strategies/email.strategy"; 13 | import { SessionStrategy } from "./strategies/session.strategy"; 14 | 15 | /** 16 | * Import and provide authentication-related classes. 17 | * 18 | * @module 19 | */ 20 | @Module({ 21 | imports: [UserModule, SessionModule, PassportModule, AppConfigModule], 22 | controllers: [AuthController], 23 | providers: [AuthService, CipherProvider, EmailStrategy, SessionStrategy] 24 | }) 25 | export class AuthModule {} 26 | 27 | // TODO: use fastify-passport? 28 | // TODO: add check for revoked sessionId 29 | -------------------------------------------------------------------------------- /libs/nest/auth/src/lib/guards/email.auth.guard.ts: -------------------------------------------------------------------------------- 1 | import { AuthGuard } from "@nestjs/passport"; 2 | import { Injectable } from "@nestjs/common"; 3 | 4 | /** 5 | * Authenticates an asserted email and password. Implements `local` Passport 6 | * strategy if `fastify-session` strategy does not find an active session. 7 | */ 8 | @Injectable() 9 | export class EmailAuthGuard extends AuthGuard(["fastify-session", "local"]) {} 10 | -------------------------------------------------------------------------------- /libs/nest/auth/src/lib/guards/session.guard.ts: -------------------------------------------------------------------------------- 1 | import { AuthGuard } from "@nestjs/passport"; 2 | import { Injectable } from "@nestjs/common"; 3 | 4 | /** 5 | * Validates encrypted `fastify-secure-session` cookie to allow requests only 6 | * from authenticated users with an active session. Implements 7 | * `fastify-session` Passport strategy. 8 | */ 9 | @Injectable() 10 | export class SessionGuard extends AuthGuard("fastify-session") { 11 | constructor() { 12 | super({ 13 | // Set options passed to Strategy.authenticate() 14 | }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libs/nest/auth/src/lib/providers/auth.service.ts: -------------------------------------------------------------------------------- 1 | import { forwardRef, Inject, Injectable } from "@nestjs/common"; 2 | 3 | import { CipherProvider } from "@nest-vue/nest/providers/cipher"; 4 | import { SessionService } from "@nest-vue/models/session"; 5 | import { UserService } from "@nest-vue/models/user"; 6 | import { UserSession } from "@nest-vue/models/session"; 7 | 8 | import { AuthCredentials } from "../auth.interface"; 9 | 10 | /** 11 | * Verifies authentication. 12 | */ 13 | @Injectable() 14 | export class AuthService { 15 | /** 16 | * Initialize authorization dependencies. 17 | * @param userService The injected `UserService` instance. 18 | * @param sessionService The injected `SessionService` instance. 19 | * @param cipherProvider The injected `CipherProvider` instance. 20 | */ 21 | constructor( 22 | @Inject(forwardRef(() => UserService)) 23 | private readonly userService: UserService, 24 | @Inject(forwardRef(() => SessionService)) 25 | private readonly sessionService: SessionService, 26 | private readonly cipherProvider: CipherProvider 27 | ) {} 28 | 29 | /** 30 | * Evaluates whether the asserted email and password match a `User` in the 31 | * database, and creates a session if authentication succeeds. 32 | * 33 | * @example 34 | * const session = await this.authService.authenticate({ email, password }); 35 | * 36 | * @param asserted The credentials asserted for authentication. 37 | * 38 | * @returns A `UserSession`, if successful, or `false`. 39 | */ 40 | async authenticate( 41 | asserted: AuthCredentials 42 | ): Promise { 43 | const user = await this.userService.getUserForAuth(asserted.email); 44 | 45 | if (user?.password) { 46 | const attempt = await this.cipherProvider.verifyHash( 47 | user.password, 48 | asserted.password 49 | ); 50 | delete user.password; 51 | return attempt ? await this.sessionService.create(user) : false; 52 | } 53 | 54 | return false; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /libs/nest/auth/src/lib/strategies/email.strategy.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, UnauthorizedException } from "@nestjs/common"; 2 | import { PassportStrategy } from "@nestjs/passport"; 3 | import { Strategy } from "passport-local"; 4 | 5 | import { UserSession } from "@nest-vue/models/session"; 6 | 7 | import { AuthRequest } from "../auth.interface"; 8 | import { AuthService } from "../providers/auth.service"; 9 | 10 | /** 11 | * Passport strategy for local authentication via email and password. 12 | */ 13 | @Injectable() 14 | export class EmailStrategy extends PassportStrategy(Strategy) { 15 | /** 16 | * Initialize authentication dependencies and options. 17 | * @param authService The injected AuthService instance. 18 | */ 19 | constructor(private readonly authService: AuthService) { 20 | super({ usernameField: "email", passReqToCallback: true }); 21 | } 22 | 23 | /** 24 | * Authenticates the asserted user. If successful, returns a session that 25 | * is appended to the `Request` object as `req.user`. 26 | * @param request The current `Request` object. 27 | * @param email The email asserted for authentication. 28 | * @param password The password asserted for authentication. 29 | * @returns UserSession or void 30 | */ 31 | async validate( 32 | request: AuthRequest, 33 | email: string, 34 | password: string 35 | ): Promise { 36 | // Skip authentication if `UserSession` exists from prior strategy 37 | if (request.user) return; 38 | 39 | const session = await this.authService.authenticate({ 40 | email, 41 | password 42 | }); 43 | if (!session) throw new UnauthorizedException(); 44 | return session; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /libs/nest/auth/src/lib/strategies/nest-fastify-session/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./base"; 2 | export * from "./strategy"; 3 | -------------------------------------------------------------------------------- /libs/nest/auth/src/lib/strategies/session.strategy.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from "@nestjs/common"; 2 | import { FastifyRequest } from "fastify"; 3 | import { PassportStrategy } from "@nestjs/passport"; 4 | 5 | import { AppConfigService } from "@nest-vue/nest/config/app"; 6 | import { UserSession } from "@nest-vue/models/session"; 7 | 8 | import { 9 | FastifySessionStrategy, 10 | SessionValidatorCallback 11 | } from "./nest-fastify-session"; 12 | 13 | /** 14 | * Passport strategy for authentication via session cookie. 15 | */ 16 | @Injectable() 17 | export class SessionStrategy extends PassportStrategy(FastifySessionStrategy) { 18 | /** 19 | * Initialize authentication dependencies and options. 20 | * @param authService The injected AuthService instance. 21 | */ 22 | constructor(private readonly appConfig: AppConfigService) { 23 | super({ 24 | // Set options for FastifySessionStrategy 25 | }); 26 | } 27 | 28 | /** 29 | * Validates the session cookie. If successful, appends the `UserSession` to 30 | * the `Request` object as `req.user`. 31 | * @param request The current `Request` object with the session cookie. 32 | * @param done A function that exposes this strategy's success() method. 33 | */ 34 | async validate(request: FastifyRequest, done: SessionValidatorCallback) { 35 | const user: UserSession = request.session.get( 36 | this.appConfig.sessionUserProperty 37 | ); 38 | // If there is no valid session, calling fail() method has the desired 39 | // effect for routes protected only by SessionGuard (blocks accesss) 40 | // but when combined with EmailAuthGuard the 'local' strategy is called 41 | // twice. Returning without success or failure prevents duplication. 42 | if (!user || !user.sessionId) return; 43 | return done(user); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /libs/nest/auth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/auth/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/auth/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/config/app/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/config/app/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/config/app/README.md: -------------------------------------------------------------------------------- 1 | # nest-config-app 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test nest-config-app` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/config/app/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "nest-config-app", 4 | preset: "../../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../../coverage/libs/nest/config/app" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/config/app/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/config.module"; 2 | export * from "./lib/config.service"; 3 | -------------------------------------------------------------------------------- /libs/nest/config/app/src/lib/config.module.ts: -------------------------------------------------------------------------------- 1 | // import * as Joi from "@hapi/joi"; 2 | import { Module } from "@nestjs/common"; 3 | import { ConfigModule, ConfigService } from "@nestjs/config"; 4 | 5 | import { AppConfigService } from "./config.service"; 6 | import configuration from "./configuration"; 7 | import validationSchema from "./config.validation"; 8 | 9 | /** 10 | * Import and provide base application configuration classes. 11 | * 12 | * @module 13 | */ 14 | @Module({ 15 | imports: [ 16 | ConfigModule.forRoot({ 17 | load: [configuration], 18 | cache: true, 19 | validationSchema: validationSchema 20 | }) 21 | ], 22 | providers: [ConfigService, AppConfigService], 23 | exports: [ConfigService, AppConfigService] 24 | }) 25 | export class AppConfigModule {} 26 | -------------------------------------------------------------------------------- /libs/nest/config/app/src/lib/config.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from "@nestjs/common"; 2 | import { ConfigService } from "@nestjs/config"; 3 | 4 | import { AppEnvVars } from "./config.types"; 5 | 6 | /** 7 | * Configuration service for core application. 8 | * 9 | * @class 10 | */ 11 | @Injectable() 12 | export class AppConfigService { 13 | /** 14 | * Initialize configuration service dependencies. 15 | * @param configService The injected `ConfigService` instance. 16 | */ 17 | constructor(private configService: ConfigService) {} 18 | 19 | /** Environment in which the application is running. */ 20 | get env(): string | undefined { 21 | return this.configService.get("app.env"); 22 | } 23 | 24 | /** Port on which the application is listening. */ 25 | get port(): number { 26 | return Number(this.configService.get("app.port")); 27 | } 28 | 29 | /** 30 | * Global route prefix for the application. Used for NGINX proxy routing. 31 | * @example basePath=api : NestJS routes will begin with https://localhost/api/ 32 | */ 33 | get baseRoute(): string | undefined { 34 | return this.configService.get("app.baseRoute"); 35 | } 36 | 37 | /** Name of the cookie in which encrypted session data is stored. */ 38 | get sessionCookieName(): string { 39 | return this.configService.get("app.sessionCookieName") || "session"; 40 | } 41 | 42 | /** Property on the session object where authenticated user data is stored. */ 43 | get sessionUserProperty(): string { 44 | return this.configService.get("app.sessionUserProperty") || "user"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /libs/nest/config/app/src/lib/config.types.ts: -------------------------------------------------------------------------------- 1 | /** Application configuration properties for intellisense */ 2 | export interface AppEnvVars { 3 | // Full property path is required for nested properties 4 | 5 | /** Environment in which the application is running. */ 6 | "app.env": string; 7 | /** Port on which the application is listening. */ 8 | "app.port": number; 9 | /** Global route prefix for the application. */ 10 | "app.baseRoute": string; 11 | /** Name of the cookie in which encrypted session data is stored. */ 12 | "app.sessionCookieName": string; 13 | /** Property on the session object where authenticated user data is stored. */ 14 | "app.sessionUserProperty": string; 15 | } 16 | -------------------------------------------------------------------------------- /libs/nest/config/app/src/lib/config.validation.ts: -------------------------------------------------------------------------------- 1 | import * as Joi from "joi"; 2 | 3 | /** 4 | * Set the validation schema for environment variables used by the 5 | * base application configuration service. 6 | */ 7 | export default Joi.object({ 8 | NODE_ENV: Joi.string() 9 | .valid("development", "production", "test") 10 | .default("development"), 11 | BACKEND_PORT: Joi.number().required().default(3001), 12 | BACKEND_BASE_ROUTE: Joi.string().required() 13 | }); 14 | -------------------------------------------------------------------------------- /libs/nest/config/app/src/lib/configuration.ts: -------------------------------------------------------------------------------- 1 | import { registerAs } from "@nestjs/config"; 2 | 3 | /** 4 | * Set configurable properties for the base application 5 | */ 6 | export default registerAs("app", () => ({ 7 | env: process.env.NODE_ENV, 8 | port: process.env.BACKEND_PORT, 9 | baseRoute: process.env.BACKEND_BASE_ROUTE, 10 | sessionCookieName: "session", 11 | sessionUserProperty: "user" 12 | })); 13 | -------------------------------------------------------------------------------- /libs/nest/config/app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/config/app/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/config/app/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/config/db/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/config/db/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/config/db/README.md: -------------------------------------------------------------------------------- 1 | # nest-config-db 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test nest-config-db` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/config/db/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "nest-config-db", 4 | preset: "../../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../../coverage/libs/nest/config/db" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/config/db/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/config.module"; 2 | export * from "./lib/default-postgres/config.service"; 3 | -------------------------------------------------------------------------------- /libs/nest/config/db/src/lib/config.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | import { ConfigModule, ConfigService } from "@nestjs/config"; 3 | 4 | import { DefaultDbConfigService } from "./default-postgres/config.service"; 5 | import configuration from "./default-postgres/configuration"; 6 | import validationSchema from "./config.validation"; 7 | 8 | /** 9 | * Import and provide database-related configuration classes. 10 | * 11 | * @module 12 | */ 13 | @Module({ 14 | imports: [ 15 | ConfigModule.forRoot({ 16 | load: [configuration], 17 | cache: true, 18 | validationSchema: validationSchema 19 | }) 20 | ], 21 | providers: [ConfigService, DefaultDbConfigService], 22 | exports: [ConfigService, DefaultDbConfigService] 23 | }) 24 | export class DbConfigModule {} 25 | -------------------------------------------------------------------------------- /libs/nest/config/db/src/lib/config.validation.ts: -------------------------------------------------------------------------------- 1 | import * as Joi from "joi"; 2 | 3 | /** 4 | * Set the validation schema for environment variables used by the default 5 | * database configuration service. 6 | */ 7 | export default Joi.object({ 8 | DB_HOST: Joi.string().required(), 9 | DB_PORT: Joi.number().required().default(5432) 10 | }); 11 | -------------------------------------------------------------------------------- /libs/nest/config/db/src/lib/connections.ts: -------------------------------------------------------------------------------- 1 | import "dotenv/config"; 2 | import { DockerHandler } from "@nest-vue/docker-handler"; 3 | import { DbConnectionTypes, DbEnvUrl } from "./config.types"; 4 | 5 | /** Connection details for the default database. */ 6 | export const DefaultDbConnection: DbConnectionTypes = { 7 | host: process.env.DOCKER_ENV !== "true" ? "localhost" : process.env.DB_HOST, 8 | port: Number(process.env.DB_PORT), 9 | username: DockerHandler.getSecretSync("DB_USERNAME"), 10 | password: DockerHandler.getSecretSync("DB_PASSWORD"), 11 | database: process.env.DB_DATABASE_NAME 12 | }; 13 | 14 | /** Postgres URL details for the default database. (Used by Prisma.) */ 15 | export const PostgresUrl: DbEnvUrl = { 16 | envVar: "POSTGRES_URL", 17 | url: 18 | `postgresql://${DefaultDbConnection.username}:` + 19 | `${DefaultDbConnection.password}@${DefaultDbConnection.host}:` + 20 | `${DefaultDbConnection.port}/${DefaultDbConnection.database}` + 21 | `?schema=${process.env.DB_SCHEMA}` 22 | }; 23 | 24 | /** MongoDB URL details for the default database. (Used by Prisma.) */ 25 | export const MongoUrl: DbEnvUrl = { 26 | envVar: "MONGO_URL", 27 | url: 28 | `mongodb://${DefaultDbConnection.username}:` + 29 | `${DefaultDbConnection.password}@${DefaultDbConnection.host}:` + 30 | `${DefaultDbConnection.port}/${DefaultDbConnection.database}` 31 | }; 32 | -------------------------------------------------------------------------------- /libs/nest/config/db/src/lib/default-mongo/configuration.ts: -------------------------------------------------------------------------------- 1 | import { registerAs } from "@nestjs/config"; 2 | import { TypeOrmModuleOptions } from "@nestjs/typeorm"; 3 | 4 | import { DefaultDbConnection } from "../connections"; 5 | import { MigrationList } from "../migration.list"; 6 | import { TypeOrmDatabaseTypes } from "../config.types"; 7 | 8 | // Available connection options: 9 | // - https://typeorm.io/#/connection-options 10 | // - https://docs.nestjs.com/techniques/database 11 | 12 | export default registerAs( 13 | "db", 14 | (): TypeOrmModuleOptions => ({ 15 | type: TypeOrmDatabaseTypes.MongoDB, 16 | name: "default", 17 | ...DefaultDbConnection, 18 | // Note: `.ts` glob patterns do not work with webpack; Nest provides a 19 | // feature to auto-load entities that are registered with `forFeature()` 20 | autoLoadEntities: true, 21 | migrations: MigrationList 22 | // synchronize: process.env.NODE_ENV == "production" ? false : true 23 | }) 24 | ); 25 | -------------------------------------------------------------------------------- /libs/nest/config/db/src/lib/default-postgres/configuration.ts: -------------------------------------------------------------------------------- 1 | import { registerAs } from "@nestjs/config"; 2 | import { TypeOrmModuleOptions } from "@nestjs/typeorm"; 3 | 4 | import { DefaultDbConnection } from "../connections"; 5 | import { MigrationList } from "../migration.list"; 6 | import { TypeOrmDatabaseTypes } from "../config.types"; 7 | 8 | // Available connection options: 9 | // - https://typeorm.io/#/connection-options 10 | // - https://docs.nestjs.com/techniques/database 11 | 12 | export default registerAs( 13 | "db", 14 | (): TypeOrmModuleOptions => ({ 15 | type: TypeOrmDatabaseTypes.Postgres, 16 | name: "default", 17 | ...DefaultDbConnection, 18 | schema: process.env.DB_SCHEMA, 19 | // Note: `.ts` glob patterns do not work with webpack; Nest has a 20 | // feature to auto-load entities registered with `forFeature()`. 21 | autoLoadEntities: true, 22 | migrations: MigrationList 23 | // synchronize: process.env.NODE_ENV == "production" ? false : true 24 | }) 25 | ); 26 | -------------------------------------------------------------------------------- /libs/nest/config/db/src/lib/migration.list.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @nrwl/nx/enforce-module-boundaries */ 2 | import { Session1617686200270 } from "@libs/nest/models/session/src"; 3 | import { User1616910769703 } from "@libs/nest/models/user/src"; 4 | 5 | /** 6 | * Centralized index of all model migrations used by the application. 7 | */ 8 | export const MigrationList = [User1616910769703, Session1617686200270]; 9 | -------------------------------------------------------------------------------- /libs/nest/config/db/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/config/db/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/config/db/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/README.md: -------------------------------------------------------------------------------- 1 | # nest-config-graphql 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test nest-config-graphql` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "nest-config-graphql", 4 | preset: "../../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../../coverage/libs/nest/config/graphql" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/config.module"; 2 | export * from "./lib/config.service"; 3 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/src/lib/config.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | import { ConfigModule, ConfigService } from "@nestjs/config"; 3 | 4 | import { GqlConfigService } from "./config.service"; 5 | import configuration from "./configuration"; 6 | import validationSchema from "./config.validation"; 7 | 8 | /** 9 | * Import and provide GraphQL-related configuration classes. 10 | * 11 | * @module 12 | */ 13 | @Module({ 14 | imports: [ 15 | ConfigModule.forRoot({ 16 | load: [configuration], 17 | cache: true, 18 | validationSchema: validationSchema 19 | }) 20 | ], 21 | providers: [ConfigService, GqlConfigService], 22 | exports: [ConfigService, GqlConfigService] 23 | }) 24 | export class GqlConfigModule {} 25 | // TODO: configure GraphQL options - https://www.apollographql.com/docs/apollo-server/api/apollo-server/#constructor 26 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/src/lib/config.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from "@nestjs/common"; 2 | import { ConfigService } from "@nestjs/config"; 3 | import { GqlModuleOptions, GqlOptionsFactory } from "@nestjs/graphql"; 4 | 5 | import { GqlOptionTypes } from "./config.types"; 6 | 7 | /** 8 | * Configuration service for GraphQL. See options available options at 9 | * - https://docs.nestjs.com/graphql/quick-start 10 | * - https://www.apollographql.com/docs/apollo-server/api/apollo-server/#constructor. 11 | * 12 | * @class 13 | */ 14 | @Injectable() 15 | export class GqlConfigService implements GqlOptionsFactory { 16 | /** 17 | * Initialize configuration service dependencies. 18 | * @param configService The injected `ConfigService` instance. 19 | */ 20 | constructor(private configService: ConfigService) {} 21 | 22 | /** Generate the full GraphQL configuration object. */ 23 | createGqlOptions(): GqlModuleOptions { 24 | return { 25 | autoSchemaFile: this.autoSchemaFile, 26 | sortSchema: this.sortSchema, 27 | path: this.path 28 | }; 29 | } 30 | 31 | /** Path where automatically generated schema will be created. */ 32 | get autoSchemaFile(): GqlModuleOptions["autoSchemaFile"] { 33 | return this.configService.get("gql.autoSchemaFile"); 34 | } 35 | 36 | /** Whether to sort schema lexicographically. */ 37 | get sortSchema(): GqlModuleOptions["sortSchema"] { 38 | return this.configService.get("gql.sortSchema"); 39 | } 40 | 41 | /** 42 | * Route at which GraphQL will be accessed 43 | * @example path=gql : GraphQL route will be https://localhost/basePath/gql 44 | */ 45 | get path(): GqlModuleOptions["path"] { 46 | return this.configService.get("gql.path"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/src/lib/config.types.ts: -------------------------------------------------------------------------------- 1 | /** GraphQL configuration properties for intellisense. */ 2 | interface GqlOptionTypes { 3 | /** Path where automatically generated schema will be created. */ 4 | "gql.autoSchemaFile": string; 5 | /** Whether to sort schema lexicographically. */ 6 | "gql.sortSchema": boolean; 7 | /** Route at which GraphQL will be accessed */ 8 | "gql.path": string; 9 | } 10 | 11 | export { GqlOptionTypes }; 12 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/src/lib/config.validation.ts: -------------------------------------------------------------------------------- 1 | import * as Joi from "joi"; 2 | 3 | /** 4 | * Set the validation schema for environment variables used by the GraphQL 5 | * configuration service. 6 | */ 7 | export default Joi.object({ 8 | BACKEND_BASE_ROUTE: Joi.string().required(), 9 | GRAPHQL_PATH: Joi.string().required().default("graphql") 10 | }); 11 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/src/lib/configuration.ts: -------------------------------------------------------------------------------- 1 | import { registerAs } from "@nestjs/config"; 2 | import { MercuriusDriverConfig } from "@nestjs/mercurius"; 3 | import { join } from "path"; 4 | 5 | /** 6 | * Available configuration options: 7 | * - https://docs.nestjs.com/graphql/quick-start 8 | * - https://www.apollographql.com/docs/apollo-server/api/apollo-server/#constructor 9 | */ 10 | export default registerAs( 11 | "gql", 12 | (): MercuriusDriverConfig => ({ 13 | autoSchemaFile: join(process.cwd(), "apps/backend/schema.gql"), 14 | sortSchema: true, 15 | path: `${process.env.BACKEND_BASE_ROUTE}/${process.env.GRAPHQL_PATH}`, 16 | graphiql: false, 17 | ide: false, 18 | jit: 1 19 | }) 20 | ); 21 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/config/graphql/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/models/base-model/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/models/base-model/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/models/base-model/README.md: -------------------------------------------------------------------------------- 1 | # models-base-model 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test models-base-model` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/models/base-model/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "models-base-model", 4 | preset: "../../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../coverage/libs/models/base-model" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/models/base-model/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/base.entity"; 2 | export * from "./lib/base.seeder.service"; 3 | export * from "./lib/base.service"; 4 | -------------------------------------------------------------------------------- /libs/nest/models/base-model/src/lib/base.entity.ts: -------------------------------------------------------------------------------- 1 | /** Defines the base structure of model entities. */ 2 | export class BaseModelEntity { 3 | /** Require entities to have an internal database identifier. */ 4 | dbId!: number; 5 | /** Require entities to have a public-facing identifier. */ 6 | id!: string; 7 | } 8 | -------------------------------------------------------------------------------- /libs/nest/models/base-model/src/lib/base.seeder.service.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import { Logger } from "@nestjs/common"; 3 | import { Repository } from "typeorm"; 4 | 5 | /** 6 | * Establish methods for all Seeder services. 7 | * 8 | * @class 9 | */ 10 | export abstract class BaseSeederService { 11 | /** 12 | * Initialize seeder dependencies. 13 | * @param repository The injected repository instance. 14 | */ 15 | constructor( 16 | public readonly repository: Repository, 17 | public readonly prisma: any 18 | ) {} 19 | 20 | /** 21 | * Build and return an array of entities and/or DTOs containing data to 22 | * seed. 23 | */ 24 | abstract buildSeed(): Promise; 25 | 26 | /** 27 | * Saves seed data returned by `buildSeed` method. 28 | * @param seederName Name of the seeder. 29 | */ 30 | async hydrate(seederName: string, orm: "Prisma" | "TypeORM") { 31 | const seed = await this.buildSeed(); 32 | 33 | try { 34 | if (orm == "TypeORM") { 35 | await this.repository.delete({}); 36 | await this.repository.save(seed); 37 | } else { 38 | await this.prisma.deleteMany(); 39 | await this.prisma.createMany({ data: seed }); 40 | } 41 | Logger.log(`√ ${seederName}`); 42 | } catch (e: any) { 43 | Logger.error( 44 | `${seederName} failed: ${ 45 | e.detail ? e.message + " - " + e.detail : e.message 46 | }` 47 | ); 48 | } 49 | } 50 | 51 | /** 52 | * Can be invoked to delay the return of `buildSeed` method when a dependent 53 | * seeder needs another seeder to complete first. For example, the User 54 | * seeder must be complete for the Session seeder to succeed, because the 55 | * User `id` must exist. 56 | * @param ms Length of delay in milliseconds. 57 | */ 58 | stall(ms: number) { 59 | return new Promise((resolve) => { 60 | setTimeout(() => resolve(""), ms); 61 | }); 62 | } 63 | } 64 | 65 | // TODO: turn BaseSeederService into a dynamic module, or function that returns a class as described here: https://youtu.be/jo-1EUxMmxc 66 | -------------------------------------------------------------------------------- /libs/nest/models/base-model/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/models/base-model/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/models/base-model/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/models/session/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/models/session/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/models/session/README.md: -------------------------------------------------------------------------------- 1 | # models-session 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test models-session` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/models/session/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "models-session", 4 | preset: "../../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../coverage/libs/models/session" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/models/session/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/session.module"; 2 | export * from "./lib/session.entity"; 3 | export * from "./lib/session.dto"; 4 | export * from "./lib/providers/session.service"; 5 | export * from "./lib/migrations/session.seeder"; 6 | export * from "./lib/migrations/session.seeder.service"; 7 | export * from "./lib/migrations/1617686200270-Session.migration"; 8 | -------------------------------------------------------------------------------- /libs/nest/models/session/src/lib/migrations/session.seeder.service.ts: -------------------------------------------------------------------------------- 1 | import { PrismaService } from "@libs/nest/providers/db/src/lib/prisma/default.service"; 2 | import { Inject, Injectable } from "@nestjs/common"; 3 | import { InjectRepository } from "@nestjs/typeorm"; 4 | 5 | import { BaseSeederService } from "@nest-vue/models/base-model"; 6 | import { Repository } from "typeorm"; 7 | import { Session } from "../session.entity"; 8 | 9 | /** 10 | * Seeder service for `Session` entity. 11 | * 12 | * @class 13 | */ 14 | @Injectable() 15 | export class SessionSeederService extends BaseSeederService { 16 | /** 17 | * Initialize seeder dependencies. 18 | * @param repository The injected `Session` repository instance. 19 | */ 20 | constructor( 21 | @InjectRepository(Session) 22 | public readonly repository: Repository, 23 | prisma: PrismaService 24 | ) { 25 | super(repository, prisma.session); 26 | } 27 | 28 | /** 29 | * Build the `Session` data to seed. Use negative integers for primary IDs 30 | * to avoid autoincrement collision. 31 | * @returns An array of entities and/or DTOs containing data to seed. 32 | */ 33 | async buildSeed() { 34 | let staticSession1 = new Session(); 35 | staticSession1 = { 36 | dbId: -1, 37 | id: "c6ad267e-1755-414e-9402-0a83c149f1ac", 38 | userDbId: -1, 39 | createdAt: new Date() 40 | }; 41 | 42 | let staticSession2 = new Session(); 43 | staticSession2 = { 44 | dbId: -2, 45 | id: "489bbd01-9c12-426a-a090-1a86a6859921", 46 | userDbId: -2, 47 | createdAt: new Date() 48 | }; 49 | 50 | await this.stall(50); 51 | return [staticSession1, staticSession2]; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /libs/nest/models/session/src/lib/migrations/session.seeder.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | import { TypeOrmModule } from "@nestjs/typeorm"; 3 | 4 | // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries 5 | import { PrismaService } from "@libs/nest/providers/db/src/lib/prisma/default.service"; 6 | import { Session } from "../session.entity"; 7 | import { SessionSeederService } from "./session.seeder.service"; 8 | 9 | /** 10 | * Import and provide Session-related seeder classes. 11 | * 12 | * @module 13 | */ 14 | @Module({ 15 | imports: [TypeOrmModule.forFeature([Session])], 16 | providers: [SessionSeederService, PrismaService], 17 | exports: [SessionSeederService, TypeOrmModule] 18 | }) 19 | export class SessionSeeder {} 20 | -------------------------------------------------------------------------------- /libs/nest/models/session/src/lib/session.dto.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from "@nestjs/graphql"; 2 | import { Expose } from "class-transformer"; 3 | // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries 4 | import { BasicUserDto, UserDto } from "@nest-vue/models/user"; 5 | 6 | /** DTO for storing session and user details in an encrypted cookie. */ 7 | @ObjectType() 8 | export class UserSessionDto extends BasicUserDto { 9 | /** UUID of the user's current session. */ 10 | @Expose() @Field() sessionId!: string; 11 | } 12 | @ObjectType() 13 | export class UserSession extends UserSessionDto { 14 | /** UUID of the user's current session. */ 15 | @Field() sessionDbId!: number; 16 | } 17 | 18 | /** DTO for transferring all safe (non-sensitive) session details. */ 19 | @ObjectType() 20 | export class SessionDto { 21 | /** Session's UUID. */ 22 | @Expose() @Field() id!: string; 23 | /** Date of Session's creation in the database. */ 24 | @Expose() @Field() createdAt!: Date; 25 | /** Session's associated User entity. */ 26 | @Expose() @Field() user!: UserDto; 27 | /** User's UUID. */ 28 | @Expose() @Field() userDbId!: number; 29 | } 30 | 31 | /** DTO for transferring all safe (non-sensitive) session details. */ 32 | @ObjectType() 33 | export class SessionSeed { 34 | /** Session's UUID. */ 35 | @Expose() @Field() id!: string; 36 | /** Date of Session's creation in the database. */ 37 | @Expose() @Field() createdAt!: Date; 38 | /** User's UUID. */ 39 | @Expose() @Field() userDbId!: number; 40 | } 41 | -------------------------------------------------------------------------------- /libs/nest/models/session/src/lib/session.entity.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from "@nestjs/graphql"; 2 | import { Exclude, Expose } from "class-transformer"; 3 | import { 4 | Column, 5 | CreateDateColumn, 6 | Entity, 7 | Generated, 8 | ManyToOne, 9 | PrimaryGeneratedColumn 10 | } from "typeorm"; 11 | 12 | // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries 13 | import { User, UserDto } from "@nest-vue/models/user"; 14 | 15 | /** 16 | * Complete data structure of the Session entity for the database and GraphQL. 17 | */ 18 | @ObjectType() 19 | @Entity() 20 | export class Session { 21 | /** Session's internal (non-public) identfier for the database. */ 22 | @Field() 23 | @Exclude() 24 | @Column("bigint") 25 | @PrimaryGeneratedColumn("identity") 26 | dbId!: number; 27 | 28 | /** Session's UUID. */ 29 | @Expose() 30 | @Field() 31 | @Generated("uuid") 32 | @Column({ name: "id" }) 33 | id!: string; 34 | 35 | /** Session's associated User entity. */ 36 | @Expose() 37 | @Field(() => UserDto) 38 | @ManyToOne(() => User, (user) => user.sessions) 39 | user?: UserDto; 40 | 41 | /** The database identifier of the User associated with this Session. */ 42 | @Expose() 43 | @Field() 44 | @Column("bigint") 45 | userDbId!: number; 46 | 47 | /** Date of Session's creation in the database. */ 48 | @Expose() 49 | @Field() 50 | @CreateDateColumn() 51 | createdAt!: Date; 52 | } 53 | 54 | // TODO: Track more session details like IP, device, location 55 | -------------------------------------------------------------------------------- /libs/nest/models/session/src/lib/session.module.ts: -------------------------------------------------------------------------------- 1 | // https://blog.logrocket.com/how-to-build-a-graphql-api-with-nestjs/ 2 | import { forwardRef, Module } from "@nestjs/common"; 3 | import { TypeOrmModule } from "@nestjs/typeorm"; 4 | 5 | // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries 6 | import { UserModule } from "@nest-vue/models/user"; 7 | 8 | import { Session } from "./session.entity"; 9 | import { SessionResolver } from "./providers/session.resolver"; 10 | import { SessionService } from "./providers/session.service"; 11 | 12 | /** 13 | * Import and provide session-related classes. 14 | * 15 | * @module 16 | */ 17 | @Module({ 18 | imports: [ 19 | TypeOrmModule.forFeature([Session]), 20 | forwardRef(() => UserModule) 21 | ], 22 | providers: [SessionService, SessionResolver], 23 | exports: [SessionService, TypeOrmModule] 24 | }) 25 | export class SessionModule {} 26 | -------------------------------------------------------------------------------- /libs/nest/models/session/src/lib/session.pg.prisma: -------------------------------------------------------------------------------- 1 | /// Complete data structure of the Session entity for the database and GraphQL. 2 | /// A session represents a User's interaction with the API. 3 | model Session { 4 | /// Session's internal (non-public) identifier for the database 5 | dbId BigInt @id(map: "session_dbid_pkey") @default(autoincrement()) @db.BigInt 6 | /// Session's unique identifier 7 | id String @unique(map: "session_id_key") @default(dbgenerated("uuid_generate_v4()")) @db.Uuid 8 | /// Date of Session's creation in the database 9 | createdAt DateTime @default(now()) @db.Timestamp(6) 10 | /// Session's associated User entity 11 | user User @relation(fields: [userDbId], references: [dbId], onDelete: Cascade, onUpdate: NoAction, map: "user_dbid_fkey") 12 | /// The database identifier of the User associated with this Session 13 | userDbId BigInt @db.BigInt 14 | 15 | @@map("session") 16 | } 17 | -------------------------------------------------------------------------------- /libs/nest/models/session/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/models/session/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/models/session/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/models/user/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/models/user/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/models/user/README.md: -------------------------------------------------------------------------------- 1 | # models-user 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test models-user` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/models/user/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "models-user", 4 | preset: "../../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../coverage/libs/models/user" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/models/user/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/user.module"; 2 | export * from "./lib/user.dto"; 3 | export * from "./lib/user.entity"; 4 | export * from "./lib/migrations/1616910769703-User.migration"; 5 | export * from "./lib/migrations/user.seeder"; 6 | export * from "./lib/migrations/user.seeder.service"; 7 | export * from "./lib/providers/user.service"; 8 | -------------------------------------------------------------------------------- /libs/nest/models/user/src/lib/migrations/user.seeder.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from "@nestjs/common"; 2 | import { InjectRepository } from "@nestjs/typeorm"; 3 | import { faker } from "@faker-js/faker"; 4 | import { Repository } from "typeorm"; 5 | 6 | import { BaseSeederService } from "@nest-vue/models/base-model"; 7 | // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries 8 | import { PrismaService } from "@libs/nest/providers/db/src/lib/prisma/default.service"; 9 | 10 | import { CreateUserDto } from "../user.dto"; 11 | import { User } from "../user.entity"; 12 | 13 | /** 14 | * Seeder service for `User` entity. 15 | * 16 | * @class 17 | */ 18 | @Injectable() 19 | export class UserSeederService extends BaseSeederService { 20 | /** 21 | * Initialize seeder dependencies. 22 | * @param repository The injected `User` repository instance. 23 | */ 24 | constructor( 25 | @InjectRepository(User) readonly repository: Repository, 26 | prisma: PrismaService 27 | ) { 28 | super(repository, prisma.user); 29 | } 30 | 31 | /** 32 | * Build the `User` data to seed. Use negative integers for primary IDs to 33 | * avoid autoincrement collision. 34 | * @returns An array of entities and/or DTOs containing data to seed. 35 | */ 36 | async buildSeed() { 37 | let staticUser1 = new User(); 38 | staticUser1 = { 39 | dbId: -1, 40 | id: "d3f6bcef-b1c6-4e54-a473-7d710f88c9d2", 41 | email: "user1@example.com", 42 | password: "testing", 43 | createdAt: new Date(), 44 | updatedAt: new Date() 45 | }; 46 | 47 | let staticUser2 = new User(); 48 | staticUser2 = { 49 | dbId: -2, 50 | id: "31a16647-5a2b-46ad-9974-39c950d86547", 51 | email: "user2@example.com", 52 | password: "testing2", 53 | createdAt: new Date(), 54 | updatedAt: new Date() 55 | }; 56 | 57 | let randomUser: CreateUserDto & { updatedAt?: Date } = 58 | new CreateUserDto(); 59 | randomUser = { 60 | email: faker.internet.email(), 61 | password: faker.internet.password(), 62 | updatedAt: new Date() 63 | }; 64 | 65 | return [staticUser1, staticUser2, randomUser]; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /libs/nest/models/user/src/lib/migrations/user.seeder.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | import { TypeOrmModule } from "@nestjs/typeorm"; 3 | 4 | // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries 5 | import { PrismaService } from "@libs/nest/providers/db/src/lib/prisma/default.service"; 6 | import { User } from "../user.entity"; 7 | import { UserSeederService } from "./user.seeder.service"; 8 | 9 | /** 10 | * Import and provide User-related seeder classes. 11 | * 12 | * @module 13 | */ 14 | @Module({ 15 | imports: [TypeOrmModule.forFeature([User])], 16 | providers: [UserSeederService, PrismaService], 17 | exports: [UserSeederService, TypeOrmModule] 18 | }) 19 | export class UserSeeder {} 20 | -------------------------------------------------------------------------------- /libs/nest/models/user/src/lib/user.controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Body, 3 | Controller, 4 | Get, 5 | HttpException, 6 | HttpStatus, 7 | Param, 8 | Post, 9 | Version 10 | } from "@nestjs/common"; 11 | 12 | import { LoginUserDto } from "./user.dto"; 13 | import { UserService } from "./providers/user.service"; 14 | 15 | /** User-related routing, prefixed with `/{BACKEND_BASE_PATH}/{version}/user/` */ 16 | @Controller("user") 17 | export class UserController { 18 | /** 19 | * Initialize controller dependencies. 20 | * @param userService The injected `UserService` instance. 21 | */ 22 | constructor(private readonly userService: UserService) {} 23 | 24 | /** 25 | * Get a `User` record: `/user/{id}` 26 | * @param id The User's UUID. 27 | */ 28 | @Get("/:id") 29 | @Version("1") 30 | async get(@Param("id") id: string) { 31 | return await this.userService.getByIds(id); 32 | } 33 | 34 | /** 35 | * Create a `User` record: `/user/create` 36 | * @param body The request body. 37 | * @returns A `User` record. 38 | */ 39 | @Post("/create") 40 | @Version("1") 41 | async create(@Body() body: LoginUserDto) { 42 | return await this.userService 43 | .create(body.email, body.password) 44 | .catch(({ message, detail }) => { 45 | throw new HttpException( 46 | { message, detail }, 47 | HttpStatus.UNPROCESSABLE_ENTITY 48 | ); 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /libs/nest/models/user/src/lib/user.dto.ts: -------------------------------------------------------------------------------- 1 | import { Field, ObjectType } from "@nestjs/graphql"; 2 | import { Expose } from "class-transformer"; 3 | 4 | // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries 5 | import { SessionDto } from "@nest-vue/models/session"; 6 | 7 | // TODO: Implement data validation (removed class-validator, which wasn't hooked up and has an unresolved vulnerability) 8 | 9 | /** Unsafe DTO to server with user email and password to create a new user. */ 10 | export class CreateUserDto { 11 | /** User's email. */ 12 | email!: string; 13 | /** User's initial, unencrypted password from registration form. */ 14 | password!: string; 15 | } 16 | 17 | /** DTO for transfering basic user details. */ 18 | @ObjectType() 19 | export class BasicUserDto { 20 | /** User's UUID. */ 21 | @Expose() @Field() id!: string; 22 | /** User's email. */ 23 | @Expose() @Field() email!: string; 24 | } 25 | 26 | /** DTO for transfering all safe (non-sensitive) user details. */ 27 | @ObjectType() 28 | export class UserDto extends BasicUserDto { 29 | /** Date of User's creation in the database. */ 30 | @Expose() @Field() createdAt!: Date; 31 | /** Date of last update to User's record. */ 32 | @Expose() @Field() updatedAt!: Date; 33 | /** User's sessions. */ 34 | @Expose() @Field(() => [SessionDto]) sessions?: SessionDto[]; 35 | } 36 | 37 | /** DTO to server with asserted user email and password for login. */ 38 | export class LoginUserDto { 39 | /** The asserted `User` email from login form. */ 40 | readonly email!: string; 41 | /** The asserted `User` password from login form. */ 42 | readonly password!: string; 43 | } 44 | -------------------------------------------------------------------------------- /libs/nest/models/user/src/lib/user.module.ts: -------------------------------------------------------------------------------- 1 | // https://blog.logrocket.com/how-to-build-a-graphql-api-with-nestjs/ 2 | import { forwardRef, Module } from "@nestjs/common"; 3 | import { TypeOrmModule } from "@nestjs/typeorm"; 4 | 5 | import { CipherProvider } from "@nest-vue/nest/providers/cipher"; 6 | // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries 7 | import { SessionModule } from "@nest-vue/models/session"; 8 | 9 | import { User } from "./user.entity"; 10 | import { UserController } from "./user.controller"; 11 | import { UserResolver } from "./providers/user.resolver"; 12 | import { UserService } from "./providers/user.service"; 13 | 14 | /** 15 | * Import and provide user-related classes. 16 | * 17 | * @module 18 | */ 19 | @Module({ 20 | imports: [ 21 | TypeOrmModule.forFeature([User]), 22 | forwardRef(() => SessionModule) 23 | ], 24 | controllers: [UserController], 25 | providers: [UserService, UserResolver, CipherProvider], 26 | exports: [UserService, TypeOrmModule] 27 | }) 28 | export class UserModule {} 29 | -------------------------------------------------------------------------------- /libs/nest/models/user/src/lib/user.pg.prisma: -------------------------------------------------------------------------------- 1 | /// Complete data structure of the User entity for the database and GraphQL. 2 | /// A User represents an account holder. 3 | model User { 4 | /// User's internal (non-public) identifier for the database 5 | dbId BigInt @id(map: "user_dbid_pkey") @default(autoincrement()) @db.BigInt 6 | /// User's unique identifier 7 | id String @unique(map: "user_id_key") @default(dbgenerated("uuid_generate_v4()")) @db.Uuid 8 | /// User's email address 9 | email String @unique(map: "user_email_key") 10 | /// User's password 11 | password String 12 | /// Date of User's creation in the database 13 | createdAt DateTime @default(now()) @db.Timestamp(6) 14 | /// Date of last update to User's record 15 | updatedAt DateTime @updatedAt @db.Timestamp(6) 16 | /// Date of User's deletion from the database 17 | deletedAt DateTime? @db.Timestamp(6) 18 | /// User's sessions 19 | sessions Session[] 20 | // TODO: Exclude password field by default when Prisma implements this functionality: https://www.notion.so/Exclude-Fields-by-Default-ccb00ca22090437eb3b1726a722d0ae6 21 | 22 | @@map("user") 23 | } 24 | -------------------------------------------------------------------------------- /libs/nest/models/user/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/models/user/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/models/user/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/providers/cipher/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/providers/cipher/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/providers/cipher/README.md: -------------------------------------------------------------------------------- 1 | # nest-providers-cipher 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test nest-providers-cipher` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/providers/cipher/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "nest-providers-cipher", 4 | preset: "../../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../../coverage/libs/nest/providers/cipher" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/providers/cipher/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/cipher.provider"; 2 | -------------------------------------------------------------------------------- /libs/nest/providers/cipher/src/lib/cipher.provider.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from "@nestjs/common"; 2 | import * as argon2 from "argon2"; 3 | 4 | /** Service for handling ciphers. */ 5 | @Injectable() 6 | export class CipherProvider { 7 | /** 8 | * Hashes the provided string using the `Argon2id` algorithm recommended by 9 | * OWASP. See: 10 | * - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html 11 | * - https://security.stackexchange.com/questions/193351/in-2018-what-is-the-recommended-hash-to-store-passwords-bcrypt-scrypt-argon2 12 | * 13 | * @example const hash = await CipherProvider.oneWayHash(password); 14 | * 15 | * @param data The data to encrypt 16 | * 17 | * @returns {Promise} Hashed string. 18 | */ 19 | async oneWayHash(data: string): Promise { 20 | return await argon2.hash(data, { 21 | // Options: https://github.com/ranisalt/node-argon2/wiki/Options 22 | type: argon2.argon2id, 23 | memoryCost: 4096, // KiB 24 | timeCost: 8, // iterations 25 | parallelism: 1 // threads 26 | }); 27 | } 28 | 29 | /** 30 | * Verifies whether a `utf8` string matches the provided hash. 31 | * 32 | * @example const attempt = await this.cipherProvider.verifyHash(user.password, password); 33 | * 34 | * @param hash The hash to verify against. 35 | * @param plain The string to verify. 36 | * 37 | * @returns {Promise} True if the string and hash match. 38 | */ 39 | async verifyHash(hash: string, plain: string): Promise { 40 | return await argon2.verify(hash, plain); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /libs/nest/providers/cipher/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/providers/cipher/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/providers/cipher/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/providers/db/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/providers/db/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/providers/db/README.md: -------------------------------------------------------------------------------- 1 | # nest-providers-db 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test nest-providers-db` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/providers/db/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "nest-providers-db", 4 | preset: "../../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../../coverage/libs/nest/providers/db" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/providers/db/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/db.provider"; 2 | -------------------------------------------------------------------------------- /libs/nest/providers/db/src/lib/db.provider.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | import { TypeOrmModule } from "@nestjs/typeorm"; 3 | 4 | // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries 5 | import { 6 | DbConfigModule, 7 | DefaultDbConfigService 8 | } from "@nest-vue/nest/config/db"; 9 | import { PrismaService } from "./prisma/default.service"; 10 | 11 | /** 12 | * Import and provide database-related classes. 13 | * 14 | * @module 15 | */ 16 | @Module({ 17 | imports: [ 18 | TypeOrmModule.forRootAsync({ 19 | imports: [DbConfigModule], 20 | useExisting: DefaultDbConfigService 21 | }) 22 | ], 23 | providers: [PrismaService], 24 | exports: [PrismaService] 25 | }) 26 | export class DatabaseProvider {} 27 | -------------------------------------------------------------------------------- /libs/nest/providers/db/src/lib/prisma/default.service.ts: -------------------------------------------------------------------------------- 1 | import { INestApplication, Injectable, OnModuleInit } from "@nestjs/common"; 2 | import { PrismaPostgresService } from "./postgres.service"; 3 | 4 | /** Initialization for default Prisma service. */ 5 | @Injectable() 6 | export class PrismaService 7 | extends PrismaPostgresService 8 | implements OnModuleInit 9 | { 10 | /** Initialize the Prisma Client. */ 11 | constructor() { 12 | super(); 13 | } 14 | 15 | /** Start the connection to the default database. */ 16 | async onModuleInit() { 17 | await this.$connect(); 18 | } 19 | 20 | /** 21 | * Shut down Prisma Client. 22 | * @param app The Nest application instance. 23 | */ 24 | async enableShutdownHooks(app: INestApplication) { 25 | this.$on("beforeExit", async () => { 26 | await app.close(); 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /libs/nest/providers/db/src/lib/prisma/mongo.service.ts: -------------------------------------------------------------------------------- 1 | // import { Injectable } from "@nestjs/common"; 2 | 3 | // // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries 4 | // import { MongoUrl } from "@libs/nest/config/db/src/lib/connections"; 5 | // import { PrismaClient } from "@nest-vue/prisma/mongo"; 6 | 7 | // /** Prisma Client wrapper for the default MongoDB connection. */ 8 | // @Injectable() 9 | // export class PrismaMongoService extends PrismaClient { 10 | // /** Initialize Prisma Client for the default MongoDB connection. */ 11 | // constructor() { 12 | // // Ensure environment URL is set for Prisma 13 | // if (!process.env[MongoUrl.envVar]) { 14 | // process.env[MongoUrl.envVar] = MongoUrl.url; 15 | // } 16 | // super(); 17 | // } 18 | // } 19 | -------------------------------------------------------------------------------- /libs/nest/providers/db/src/lib/prisma/postgres.service.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @nrwl/nx/enforce-module-boundaries */ 2 | import { Injectable } from "@nestjs/common"; 3 | 4 | import { PostgresUrl } from "@libs/nest/config/db/src/lib/connections"; 5 | import { PrismaClient } from "@nest-vue/prisma/postgres"; 6 | 7 | /** Prisma Client wrapper for the default PostgreSQL connection. */ 8 | @Injectable() 9 | export class PrismaPostgresService extends PrismaClient { 10 | /** Initialize Prisma Client for the default PostgreSQL connection. */ 11 | constructor() { 12 | // Ensure environment URL is set for Prisma 13 | if (!process.env[PostgresUrl.envVar]) { 14 | process.env[PostgresUrl.envVar] = PostgresUrl.url; 15 | } 16 | super(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/providers/db/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/providers/db/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts", "../../config/**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/providers/db/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/providers/graphql/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/providers/graphql/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/providers/graphql/README.md: -------------------------------------------------------------------------------- 1 | # nest-providers-graphql 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test nest-providers-graphql` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/providers/graphql/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "nest-providers-graphql", 4 | preset: "../../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../../coverage/libs/nest/providers/graphql" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/providers/graphql/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/graphql.provider"; 2 | -------------------------------------------------------------------------------- /libs/nest/providers/graphql/src/lib/graphql.provider.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | import { GraphQLModule } from "@nestjs/graphql"; 3 | import { MercuriusDriver, MercuriusDriverConfig } from "@nestjs/mercurius"; 4 | 5 | import { 6 | GqlConfigModule, 7 | GqlConfigService 8 | } from "@nest-vue/nest/config/graphql"; 9 | 10 | @Module({ 11 | imports: [ 12 | GraphQLModule.forRootAsync({ 13 | driver: MercuriusDriver, 14 | imports: [GqlConfigModule], 15 | useExisting: GqlConfigService 16 | }) 17 | ] 18 | }) 19 | export class GraphQLProvider {} 20 | -------------------------------------------------------------------------------- /libs/nest/providers/graphql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/providers/graphql/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/providers/graphql/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/providers/migrator/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/providers/migrator/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/providers/migrator/README.md: -------------------------------------------------------------------------------- 1 | # nest-providers-migrator 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test nest-providers-migrator` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/providers/migrator/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "nest-providers-migrator", 4 | preset: "../../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../../coverage/libs/nest/providers/migrator" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/providers/migrator/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/migrator"; 2 | export * from "./lib/migration.provider"; 3 | -------------------------------------------------------------------------------- /libs/nest/providers/migrator/src/lib/migration.provider.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Logger } from "@nestjs/common"; 2 | import { DataSource } from "typeorm"; 3 | 4 | /** 5 | * Migration service that dispatches database actions. 6 | * 7 | * @class 8 | */ 9 | @Injectable() 10 | export class MigrationProvider { 11 | /** 12 | * Initialize migration dependencies. 13 | * @param dataSource The TypeORM Connection instance. 14 | */ 15 | constructor(private readonly dataSource: DataSource) {} 16 | 17 | /** 18 | * Runs all migrations created since the last run. 19 | */ 20 | async run() { 21 | (await this.dataSource.showMigrations()) 22 | ? await this.dataSource.runMigrations() 23 | : Logger.error("No new migrations"); 24 | } 25 | 26 | /** 27 | * Reverts only the very last migration file that was run. Repeat to roll 28 | * back additional files, one by one. 29 | */ 30 | async undo() { 31 | await this.dataSource.undoLastMigration(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /libs/nest/providers/migrator/src/lib/migrator.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | 3 | import { DatabaseProvider } from "@nest-vue/nest/providers/db"; 4 | import { MigrationProvider } from "./migration.provider"; 5 | 6 | /** 7 | * Import and provide migration classes. 8 | * 9 | * @module 10 | */ 11 | @Module({ 12 | imports: [DatabaseProvider], 13 | providers: [MigrationProvider] 14 | }) 15 | export class Migrator {} 16 | -------------------------------------------------------------------------------- /libs/nest/providers/migrator/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/providers/migrator/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/providers/migrator/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/nest/providers/seeders/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/nest/providers/seeders/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/nest/providers/seeders/README.md: -------------------------------------------------------------------------------- 1 | # nest-providers-seeders 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test nest-providers-seeders` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /libs/nest/providers/seeders/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "nest-providers-seeders", 4 | preset: "../../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../../coverage/libs/nest/providers/seeders" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/nest/providers/seeders/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/seeders"; 2 | export * from "./lib/seed.provider"; 3 | -------------------------------------------------------------------------------- /libs/nest/providers/seeders/src/lib/seed.provider.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from "@nestjs/common"; 2 | 3 | import { BaseSeederService } from "@nest-vue/models/base-model"; 4 | import { SessionSeederService } from "@nest-vue/models/session"; 5 | import { UserSeederService } from "@nest-vue/models/user"; 6 | 7 | /** 8 | * Seed service that dispatches database actions. 9 | * 10 | * @class 11 | */ 12 | @Injectable() 13 | export class SeedProvider { 14 | /** Load each SeederService. */ 15 | constructor( 16 | // Order matters for data with dependent relationships (Users/Sessions) 17 | private readonly Users: UserSeederService, 18 | private readonly Sessions: SessionSeederService 19 | ) {} 20 | 21 | /** 22 | * Runs `hydrate` method for every `SeederService` in `SeedProvider`'s 23 | * constructor. 24 | * @param orm The ORM to use for seeding data. Either Prisma or TypeORM. 25 | */ 26 | async seed(orm: "Prisma" | "TypeORM") { 27 | await Promise.all( 28 | Object.entries(this).map(async ([key, value]) => { 29 | if (value instanceof BaseSeederService) 30 | await value.hydrate(key, orm); 31 | }) 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /libs/nest/providers/seeders/src/lib/seeders.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "@nestjs/common"; 2 | 3 | import { DatabaseProvider } from "@nest-vue/nest/providers/db"; 4 | import { SessionSeeder } from "@nest-vue/models/session"; 5 | import { UserSeeder } from "@nest-vue/models/user"; 6 | 7 | import { SeedProvider } from "./seed.provider"; 8 | 9 | /** 10 | * Import and provide seed-related classes. 11 | * 12 | * @module 13 | */ 14 | @Module({ 15 | imports: [DatabaseProvider, UserSeeder, SessionSeeder], 16 | providers: [SeedProvider] 17 | }) 18 | export class Seeders {} 19 | -------------------------------------------------------------------------------- /libs/nest/providers/seeders/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/nest/providers/seeders/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"], 8 | "target": "es6" 9 | }, 10 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /libs/nest/providers/seeders/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/prisma/mongo/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/prisma/mongo/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "PrismaPostgres", 4 | preset: "../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../coverage/libs/prisma/postgres" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/prisma/mongo/src/index.ts: -------------------------------------------------------------------------------- 1 | // Export generated PrismaClient for easier import from "@nest-vue/prisma/mongo" 2 | // export * from "./client"; 3 | -------------------------------------------------------------------------------- /libs/prisma/mongo/src/lib/base.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | output = "client" 4 | binaryTargets = ["native", "linux-musl", "linux-arm64-openssl-1.1.x", "debian-openssl-1.1.x"] 5 | } 6 | 7 | datasource db { 8 | provider = "mongodb" 9 | url = env("MONGO_URL") 10 | } 11 | 12 | // TODO: update split schema file handling when Prisma implements it - https://www.notion.so/Support-splitting-the-Prisma-Schema-into-Multiple-Files-83867e7f70ce40038cdfa9eb32ed4449 13 | -------------------------------------------------------------------------------- /libs/prisma/mongo/src/lib/wrapper.ts: -------------------------------------------------------------------------------- 1 | import { PrismaWrapper } from "@nest-vue/prisma/wrapper"; 2 | import { MongoUrl } from "@libs/nest/config/db/src/lib/connections"; 3 | 4 | /** Invokes the PrismaWrapper for a MongoDB connection. */ 5 | PrismaWrapper(process.argv.slice(2), MongoUrl); 6 | -------------------------------------------------------------------------------- /libs/prisma/mongo/src/prismerge.json: -------------------------------------------------------------------------------- 1 | { 2 | "mongo-client": { 3 | "inputs": [ 4 | "libs/prisma/mongo/src/lib/base.prisma", 5 | "libs/nest/models/**/*.mdb.prisma" 6 | ], 7 | "fragments": {}, 8 | "output": "libs/prisma/mongo/src/schema.prisma" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/prisma/mongo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/prisma/mongo/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"] 8 | }, 9 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 10 | "include": ["**/*.ts", "../../nest/config/db/**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /libs/prisma/mongo/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/prisma/postgres/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/prisma/postgres/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/prisma/postgres/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "PrismaPostgres", 4 | preset: "../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../coverage/libs/prisma/postgres" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/prisma/postgres/src/index.ts: -------------------------------------------------------------------------------- 1 | // Export generated PrismaClient for easier import from "@nest-vue/prisma/postgres" 2 | export * from "./client"; 3 | -------------------------------------------------------------------------------- /libs/prisma/postgres/src/lib/base.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | output = "client" 4 | binaryTargets = ["native", "linux-musl", "linux-arm64-openssl-1.1.x", "debian-openssl-1.1.x"] 5 | } 6 | 7 | datasource db { 8 | provider = "postgresql" 9 | url = env("POSTGRES_URL") 10 | } 11 | 12 | // TODO: update split schema file handling when Prisma implements it - https://www.notion.so/Support-splitting-the-Prisma-Schema-into-Multiple-Files-83867e7f70ce40038cdfa9eb32ed4449 13 | // TODO: remove linux-arm64-openssl-1.1.x target after Prisma #8478 is resolved - https://github.com/prisma/prisma/issues/8478 14 | -------------------------------------------------------------------------------- /libs/prisma/postgres/src/lib/wrapper.ts: -------------------------------------------------------------------------------- 1 | import { PrismaWrapper } from "@nest-vue/prisma/wrapper"; 2 | import { PostgresUrl } from "@libs/nest/config/db/src/lib/connections"; 3 | 4 | /** Invokes the PrismaWrapper for a PostgreSQL connection. */ 5 | PrismaWrapper(process.argv.slice(2), PostgresUrl); 6 | -------------------------------------------------------------------------------- /libs/prisma/postgres/src/migrations/20220707040353_init/migration.sql: -------------------------------------------------------------------------------- 1 | -- Ensure uuid_generate_v4() function is available when shadow is created 2 | CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; 3 | 4 | -- CreateTable 5 | CREATE TABLE "user" ( 6 | "dbId" BIGSERIAL NOT NULL, 7 | "id" UUID NOT NULL DEFAULT uuid_generate_v4(), 8 | "email" TEXT NOT NULL, 9 | "password" TEXT NOT NULL, 10 | "createdAt" TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP, 11 | "updatedAt" TIMESTAMP(6) NOT NULL, 12 | "deletedAt" TIMESTAMP(6), 13 | 14 | CONSTRAINT "user_dbid_pkey" PRIMARY KEY ("dbId") 15 | ); 16 | 17 | -- CreateTable 18 | CREATE TABLE "session" ( 19 | "dbId" BIGSERIAL NOT NULL, 20 | "id" UUID NOT NULL DEFAULT uuid_generate_v4(), 21 | "createdAt" TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP, 22 | "userDbId" BIGINT NOT NULL, 23 | 24 | CONSTRAINT "session_dbid_pkey" PRIMARY KEY ("dbId") 25 | ); 26 | 27 | -- CreateIndex 28 | CREATE UNIQUE INDEX "user_id_key" ON "user"("id"); 29 | 30 | -- CreateIndex 31 | CREATE UNIQUE INDEX "user_email_key" ON "user"("email"); 32 | 33 | -- CreateIndex 34 | CREATE UNIQUE INDEX "session_id_key" ON "session"("id"); 35 | 36 | -- AddForeignKey 37 | ALTER TABLE "session" ADD CONSTRAINT "user_dbid_fkey" FOREIGN KEY ("userDbId") REFERENCES "user"("dbId") ON DELETE CASCADE ON UPDATE NO ACTION; 38 | -------------------------------------------------------------------------------- /libs/prisma/postgres/src/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /libs/prisma/postgres/src/prismerge.json: -------------------------------------------------------------------------------- 1 | { 2 | "postgres-client": { 3 | "inputs": [ 4 | "libs/prisma/postgres/src/lib/base.prisma", 5 | "libs/nest/models/**/*.pg.prisma" 6 | ], 7 | "fragments": {}, 8 | "output": "libs/prisma/postgres/src/schema.prisma" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/prisma/postgres/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/prisma/postgres/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"] 8 | }, 9 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 10 | "include": ["**/*.ts", "../../nest/config/db/**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /libs/prisma/postgres/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.test.ts", 10 | "**/*.spec.ts", 11 | "**/*.test.tsx", 12 | "**/*.spec.tsx", 13 | "**/*.test.js", 14 | "**/*.spec.js", 15 | "**/*.test.jsx", 16 | "**/*.spec.jsx", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /libs/prisma/wrapper/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] 3 | } 4 | -------------------------------------------------------------------------------- /libs/prisma/wrapper/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/prisma/wrapper/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: "PrismaWrapper", 4 | preset: "../../../jest.preset.js", 5 | globals: { 6 | "ts-jest": { 7 | tsconfig: "/tsconfig.spec.json" 8 | } 9 | }, 10 | testEnvironment: "node", 11 | transform: { 12 | "^.+\\.[tj]sx?$": "ts-jest" 13 | }, 14 | moduleFileExtensions: ["ts", "tsx", "js", "jsx"], 15 | coverageDirectory: "../../../coverage/libs/prisma/wrapper" 16 | }; 17 | -------------------------------------------------------------------------------- /libs/prisma/wrapper/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib/wrapper"; 2 | -------------------------------------------------------------------------------- /libs/prisma/wrapper/src/lib/wrapper.spec.ts: -------------------------------------------------------------------------------- 1 | describe("PrismaWrapper", () => { 2 | it("should work", () => { 3 | expect("prisma-wrapper").toEqual("prisma-wrapper"); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /libs/prisma/wrapper/src/lib/wrapper.ts: -------------------------------------------------------------------------------- 1 | import { spawn } from "child_process"; 2 | import { DbEnvUrl } from "@libs/nest/config/db/src/lib/config.types"; 3 | 4 | /** 5 | * Wrapper for invoking `prisma` via command line. Sets the environment URL that 6 | * Prisma expects while preserving Docker secrets and other existing 7 | * configuration variables. Also enables the ability to implement more than one 8 | * Prisma Client and database. 9 | * @param args The command line arguments passed to Prisma. 10 | * @param connection Object containing the connection URL and environment 11 | * variable to which Prisma expects it to be assigned. 12 | */ 13 | export function PrismaWrapper(args: string[], connection: DbEnvUrl) { 14 | process.env[connection.envVar] = connection.url; 15 | 16 | const prisma = spawn("prisma", args, { 17 | stdio: "inherit" 18 | }); 19 | 20 | prisma.on("spawn", () => { 21 | console.log(`Starting Prisma with environment wrapper`); 22 | }); 23 | 24 | prisma.stdout?.on("data", (data) => { 25 | process.stdout.write(data); 26 | }); 27 | 28 | prisma.stderr?.on("data", (data) => { 29 | process.stderr.write(data); 30 | }); 31 | 32 | prisma.on("close", (code) => { 33 | console.log(`Prisma exited wrapper with code ${code}`); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /libs/prisma/wrapper/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /libs/prisma/wrapper/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../../.yarn/cache/out-tsc", 6 | "declaration": true, 7 | "types": ["node"] 8 | }, 9 | "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], 10 | "include": ["**/*.ts", "../../nest/**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /libs/prisma/wrapper/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../.yarn/cache/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.ts", 10 | "../../nest/**/*.ts", 11 | "**/*.test.ts", 12 | "**/*.spec.ts", 13 | "**/*.test.tsx", 14 | "**/*.spec.tsx", 15 | "**/*.test.js", 16 | "**/*.spec.js", 17 | "**/*.test.jsx", 18 | "**/*.spec.jsx", 19 | "**/*.d.ts", 20 | "jest.config.ts" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "libs/nest" 4 | } 5 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmScope": "nest-vue", 3 | "affected": { 4 | "defaultBase": "main" 5 | }, 6 | "workspaceLayout": { 7 | "appsDir": "apps", 8 | "libsDir": "libs" 9 | }, 10 | "implicitDependencies": { 11 | "workspace.json": "*", 12 | "package.json": { 13 | "dependencies": "*", 14 | "devDependencies": "*" 15 | }, 16 | "tsconfig.base.json": "*", 17 | ".eslintrc.json": "*", 18 | "nx.json": "*" 19 | }, 20 | "tasksRunnerOptions": { 21 | "default": { 22 | "runner": "nx/tasks-runners/default", 23 | "options": { 24 | "cacheableOperations": [ 25 | "build", 26 | "lint", 27 | "merge", 28 | "test", 29 | "e2e" 30 | ], 31 | "cacheDirectory": ".yarn/cache/nx" 32 | } 33 | } 34 | }, 35 | "targetDependencies": { 36 | "build": [ 37 | { 38 | "target": "build", 39 | "projects": "dependencies" 40 | } 41 | ] 42 | }, 43 | "cli": { 44 | "defaultCollection": "@nrwl/nest" 45 | }, 46 | "defaultProject": "backend", 47 | "plugins": ["@nxrs/cargo"] 48 | } 49 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "stable" 3 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/troncali/nest-vue/0136634f001e132c4120a1bcb5fa4fa6411766a2/rustfmt.toml -------------------------------------------------------------------------------- /tools/nx/executors/workspace/executor.json: -------------------------------------------------------------------------------- 1 | { 2 | "executors": { 3 | "interactive-command": { 4 | "implementation": "./interactive-command/impl", 5 | "schema": "./interactive-command/schema.json", 6 | "description": "Runs a command interactively" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tools/nx/executors/workspace/interactive-command/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "type": "object", 4 | "cli": "nx", 5 | "properties": { 6 | "command": { 7 | "type": "string", 8 | "description": "The command to run interactively" 9 | }, 10 | "cwd": { 11 | "type": "string", 12 | "description": "The working directory to run the command in" 13 | } 14 | }, 15 | "required": [ 16 | "command" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tools/nx/executors/workspace/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "executors": "./executor.json" 3 | } 4 | -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../.yarn/cache/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"], 9 | "importHelpers": false 10 | }, 11 | "include": ["**/*.ts"] 12 | } 13 | --------------------------------------------------------------------------------