diff --git a/.gitattributes b/.gitattributes index 07a424a2..b81d2065 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,4 @@ # Auto detect text files and perform LF normalization * text=auto -packages/datasources/erowid/dataset/index.json filter=lfs diff=lfs merge=lfs -text # .yarn/cache/*.zip filter=lfs diff=lfs merge=lfs -binary # cache.db.json filter=lfs diff=lfs merge=lfs -text diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 98d5f287..af1a0c14 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,31 +1,2 @@ # Generated by CODEOWNERS.com * @keinsell -/.github/CODEOWNERS @keinsell -/.github/workflows/main.yml @keinsell -/.yarn/cache/ @keinsell -/apps/server/ @keinsell -/apps/server/bin/server.js @keinsell -/apps/server/src/modules/user/password/password.vo.ts @keinsell -/apps/server/src/shared/common/domain/ @keinsell -/apps/server/src/shared/common/module/module.ts @keinsell -/apps/server/src/shared/configuration/environment-variables.ts @keinsell -/apps/server/src/shared/infrastructure/authorization/ @keinsell -/apps/server/src/shared/infrastructure/ioc/container.ts @keinsell -/apps/server/src/shared/infrastructure/prisma/prisma.ts @keinsell -/packages/database/prisma/schema.prisma @keinsell -/packages/dataset-effectindex/effectindex.json @keinsell -/packages/dataset-effectindex/src/index.ts @keinsell -/packages/hephaistos/cache/.gitkeep @keinsell -/packages/hephaistos/src/__core/localstorage.ts @keinsell -/packages/hephaistos/src/substance/provider/tripsit/README.md @keinsell -/packages/osiris/src/__core/valueobject.ts @keinsell -/packages/osiris/src/dosage/dosage-table/dosage-table.ts @keinsell -/packages/osiris/src/ingestion/ingestion.ts @keinsell -/packages/osiris/src/journal/journal.ts @keinsell -/packages/osiris/src/phase/duration/duration.ts @keinsell -/packages/osiris/src/phase/phase-table/phase-table.ts @keinsell -/packages/osiris/src/research-paper/research-paper.ts @keinsell -/packages/osiris/src/substance/chemical-nomenclature/chemical-nomenclature.ts @keinsell -/packages/osiris/src/substance/external-reference-table/external-reference-table.ts @keinsell -/packages/osiris/src/tolerance/tolerance.ts @keinsell -/packages/osiris/src/toxicity-table/toxicity-table.ts @keinsell diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..f0c0c3df --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +public-hoist-pattern[]=*prisma* diff --git a/.prettierignore b/.prettierignore index 67086e9a..dc8ce7f1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -16,3 +16,4 @@ yarn.lock *.png *.jpg swagger.json +/packages/db/generated/ diff --git a/Pulumi.yaml b/Pulumi.yaml deleted file mode 100644 index 3334e29b..00000000 --- a/Pulumi.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: neuronek -runtime: nodejs -description: 🧬 Intelligent dosage tracker application with purpose to monitor supplements, nootropics and psychoactive substances along with their long-term influence on one's mind and body. -main: infrastructure/ -stackConfigDir: infrastructure/stacks diff --git a/apps/server/.eslintrc.json b/apps/server/.eslintrc.json deleted file mode 100644 index cdb7fe1a..00000000 --- a/apps/server/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": ["node"] -} diff --git a/apps/server/.prettierrc.json b/apps/server/.prettierrc.json deleted file mode 100644 index 9c72155b..00000000 --- a/apps/server/.prettierrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "http://json.schemastore.org/prettierrc", - "trailingComma": "none", - "tabWidth": 2, - "useTabs": true, - "semi": false, - "singleQuote": true, - "printWidth": 120, - "quoteProps": "as-needed", - "jsxSingleQuote": true, - "bracketSpacing": true, - "bracketSameLine": true, - "arrowParens": "avoid", - "proseWrap": "preserve", - "htmlWhitespaceSensitivity": "css", - "endOfLine": "lf", - "importOrderParserPlugins": ["typescript", "decorators-legacy"] -} diff --git a/apps/server/Dockerfile b/apps/server/Dockerfile deleted file mode 100644 index b241a163..00000000 --- a/apps/server/Dockerfile +++ /dev/null @@ -1,66 +0,0 @@ -FROM node:18 AS base - -ARG TURBO_TARGET_PACKAGE=server - -LABEL org.opencontainers.image.source=https://github.com/keinsell/neuronek -LABEL org.opencontainers.image.description="🧬 Intelligent dosage tracker application with the purpose to monitor supplements, nootropics, and psychoactive substances along with their long-term influence on one's mind and body." -LABEL org.opencontainers.image.licenses=MIT - -# ------------- -# BUILDER ----- -# ------------- - -FROM base AS builder - -RUN apt-get update && apt-get install -y libc6-dev -RUN apt-get update - -RUN npm install -g pnpm turbo - -WORKDIR /app - -RUN corepack prepare pnpm@8.4.0 --activate - -COPY . . - -RUN turbo prune --scope=${TURBO_TARGET_PACKAGE} --docker - -# ------------- -# INSTALLER --- -# ------------- - -FROM base AS installer - -RUN apt-get update && apt-get install -y libc6-dev -RUN apt-get update - -WORKDIR /app - -RUN npm install -g pnpm turbo -RUN corepack prepare pnpm@8.4.0 --activate - -COPY .gitignore .gitignore -COPY --from=builder /app/out/json . -COPY --from=builder /app/out/pnpm-lock.yaml . - -RUN pnpm install - -COPY --from=builder /app/out/full/ . - -RUN turbo build --scope=${TURBO_TARGET_PACKAGE} - -# ------------- -# RUNNER ------ -# ------------- - -FROM base AS runner - -WORKDIR /app - -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 express -USER express - -COPY --from=installer /app/ . - -CMD ["node", "./apps/server/bin/server.js"] diff --git a/apps/server/README.md b/apps/server/README.md deleted file mode 100644 index c758b9ed..00000000 --- a/apps/server/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# `apps/server` - -Server is dedciated to provide cloud-storage for User's data and anonymously collect information about user's intake of different chemicals, to build open database of information, these infomation will be later used in `osiris` and other distributions of neuronek. diff --git a/apps/server/bin/server.js b/apps/server/bin/server.js deleted file mode 100644 index 3d271926..00000000 --- a/apps/server/bin/server.js +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env node -import { main } from '../dist/index.js' - -main() diff --git a/apps/server/docs/ADRs/230522-revoke-pgp-functionality.md b/apps/server/docs/ADRs/230522-revoke-pgp-functionality.md deleted file mode 100644 index 0a71250b..00000000 --- a/apps/server/docs/ADRs/230522-revoke-pgp-functionality.md +++ /dev/null @@ -1,8 +0,0 @@ -# ADR: Revoke PGP-related Functionality - -After longs chain of thought I've finally decided to revoke functionalities related to PGP encryption, this would be -valid method for ensuring data of users are properly encrypted and available only for them, however when it comes to -**Key Revocation** and **Key Rotation** we have a little troubles. - -Instead as a potential solution I would rather think about **Symmetric Key Encryption**, **Homomorphic Encryption** -or maybe **Tokenization** - future of encryption isn't clear at this moment and more research is needed. diff --git a/apps/server/docs/ADRs/230522-validation-library.md b/apps/server/docs/ADRs/230522-validation-library.md deleted file mode 100644 index 55ed88bd..00000000 --- a/apps/server/docs/ADRs/230522-validation-library.md +++ /dev/null @@ -1,40 +0,0 @@ -# Validation Library Selection - -## Context - -As we embark on the development of our TypeScript project, we recognize the importance of implementing robust validation mechanisms to ensure the integrity and consistency of our data. Several validation libraries are available for TypeScript, each offering different features and trade-offs. To make an informed decision, we have identified the potential candidates for our project as follows: - -- class-validator -- io-ts -- newtypes-ts -- superstruct -- runtypes -- zod - -## Considerations - -In selecting a validation library, we need to take into account various factors to ensure that it aligns with our project requirements and objectives. Here are some considerations to keep in mind: - -1. **Ease of Use**: We should prioritize a library that provides a straightforward and intuitive API for defining and applying validation rules. The library should facilitate the validation process without introducing unnecessary complexity. - -2. **Type Safety**: TypeScript offers strong static typing capabilities, and it is essential to leverage this feature in our validation library. The selected library should integrate well with TypeScript and provide type safety guarantees throughout the validation process. - -3. **Validation Features**: Different libraries may offer various validation features, such as support for nested objects, custom validators, conditional validation rules, and more. We should evaluate which features are essential for our project and ensure that the chosen library adequately supports them. - -4. **Performance**: The efficiency of the validation library is crucial, especially when dealing with large datasets or high-traffic applications. We should consider the performance characteristics of each library and evaluate their impact on the overall application performance. - -5. **Community Support and Documentation**: A vibrant community around a library can provide valuable support, documentation, and a repository of reusable code snippets. It is beneficial to select a library that has an active community and comprehensive documentation to help us overcome challenges and optimize our development process. - -6. **Maintainability and Longevity**: It is important to choose a library that is actively maintained and has a roadmap for future development. This ensures that we can rely on continuous updates, bug fixes, and improvements in the library, reducing the risk of technical debt. - -## Evaluation and Decision - -Given the number of potential candidates and the complexity of evaluating each one, it is prudent to postpone the final decision on the validation library. We should allocate some time to conduct further research, experiment with different options, and potentially seek recommendations from the TypeScript community. - -During this period, we can explore the documentation and examples provided by each library, assess their ease of integration with our existing codebase, and even create small prototypes to evaluate their performance and usability. This exploration phase will help us make a well-informed decision based on practical experience and concrete evidence. - -## Conclusion - -The validation library selection is an important decision for our TypeScript project. Considering the factors mentioned above, namely ease of use, type safety, validation features, performance, community support, and maintainability, we will defer the final decision until we have conducted thorough research and experimentation. - -By postponing the decision, we can ensure that we make the best choice for our project's specific requirements, reducing the risk of introducing unnecessary complexities or limitations. diff --git a/apps/server/docs/swagger.json b/apps/server/docs/swagger.json deleted file mode 100644 index ff94498d..00000000 --- a/apps/server/docs/swagger.json +++ /dev/null @@ -1,279 +0,0 @@ -{ - "components": { - "examples": {}, - "headers": {}, - "parameters": {}, - "requestBodies": {}, - "responses": {}, - "schemas": { - "CreateAccount": { - "description": "Represents the request body for creating an account.", - "properties": { - "username": { - "type": "string", - "description": "The username for the account." - }, - "password": { - "type": "string", - "description": "The password for the account." - } - }, - "required": [ - "username", - "password" - ], - "type": "object", - "additionalProperties": false, - "example": { - "username": "john_doe", - "password": "my-password" - } - }, - "AuthenticateResponse": { - "properties": { - "accessToken": { - "type": "string" - }, - "refreshToken": { - "type": "string" - } - }, - "required": [ - "accessToken", - "refreshToken" - ], - "type": "object", - "additionalProperties": false - }, - "AuthenticateAccount": { - "description": "Represents the request body for creating an account.", - "properties": { - "username": { - "type": "string", - "description": "The username for the account." - }, - "password": { - "type": "string", - "description": "The password for the account." - } - }, - "required": [ - "username", - "password" - ], - "type": "object", - "additionalProperties": false, - "example": { - "username": "john_doe", - "password": "my-password" - } - }, - "Subject": { - "properties": { - "accountId": { - "type": "string" - }, - "displayName": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "birthDate": { - "type": "string", - "format": "date-time" - }, - "weight": { - "type": "number", - "format": "double" - }, - "height": { - "type": "number", - "format": "double" - }, - "nationality": { - "type": "string" - } - }, - "type": "object", - "additionalProperties": false - } - }, - "securitySchemes": { - "Bearer": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } - } - }, - "info": { - "title": "server", - "version": "0.0.0", - "description": "🧬 Intelligent dosage tracker application with purpose to monitor supplements, nootropics and psychoactive substances along with their long-term influence on one's mind and body.", - "contact": { - "name": "Jakub Olan", - "email": "keinsell@protonmail.com", - "url": "https://github.com/keinsell" - } - }, - "openapi": "3.0.0", - "paths": { - "/account": { - "post": { - "operationId": "create-account", - "responses": { - "201": { - "description": "Created", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "properties": { - "id": { - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - }, - { - "properties": { - "error": { - "type": "string" - } - }, - "required": [ - "error" - ], - "type": "object" - } - ] - } - } - } - }, - "403": { - "description": "AlreadyExists" - } - }, - "description": "Creates an account.", - "tags": [ - "Account" - ], - "security": [], - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateAccount" - } - } - } - } - } - }, - "/authentication": { - "post": { - "operationId": "authenticate-account", - "responses": { - "200": { - "description": "Ok", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthenticateResponse" - }, - { - "properties": { - "error": { - "type": "string" - } - }, - "required": [ - "error" - ], - "type": "object" - } - ] - } - } - } - } - }, - "description": "Creates an account.", - "tags": [ - "Account" - ], - "security": [], - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AuthenticateAccount" - } - } - } - } - } - }, - "/subject": { - "post": { - "operationId": "create-subject", - "responses": { - "201": { - "description": "Created", - "content": { - "application/json": { - "schema": {} - } - } - } - }, - "description": "Creates an account.", - "tags": [ - "Subject" - ], - "security": [], - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Subject" - } - } - } - } - } - } - }, - "servers": [ - { - "url": "/" - } - ], - "tags": [ - { - "name": "Account", - "description": "Operations related to account", - "externalDocs": { - "description": "...", - "url": "http://swagger.io" - } - } - ] -} \ No newline at end of file diff --git a/apps/server/nodemon.blazing.json b/apps/server/nodemon.blazing.json deleted file mode 100644 index ff2c9c5c..00000000 --- a/apps/server/nodemon.blazing.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "quiet": true, - "watch": [ - "src" - ], - "ext": ".ts,.js", - "ignore": [], - "exec": "tsup-node src/index.ts --format esm --silent && node ./bin/server.js" -} diff --git a/apps/server/nodemon.json b/apps/server/nodemon.json deleted file mode 100644 index 11f15275..00000000 --- a/apps/server/nodemon.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "quiet": true, - "watch": [ - "src" - ], - "ext": ".ts,.js", - "ignore": [], - "exec": "tsoa spec-and-routes && tsup-node src/index.ts --format esm --silent && node ./bin/server.js" -} diff --git a/apps/server/package.json b/apps/server/package.json deleted file mode 100644 index 54b6d26c..00000000 --- a/apps/server/package.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "name": "server", - "version": "0.0.0", - "private": true, - "description": "🧬 Intelligent dosage tracker application with purpose to monitor supplements, nootropics and psychoactive substances along with their long-term influence on one's mind and body.", - "author": { - "name": "Jakub Olan", - "email": "keinsell@protonmail.com", - "url": "https://github.com/keinsell" - }, - "type": "module", - "scripts": { - "prebuild": "prisma generate && tsoa spec-and-routes", - "build": "pnpm run prebuild && tsup-node src/index.ts", - "db:generate": "prisma generate", - "db:migrate:deploy": "prisma migrate deploy", - "db:migrate:dev": "prisma migrate dev", - "db:push": "prisma db push --accept-data-loss", - "db:studio": "prisma studio", - "format": "rome format src/**/*.ts --write", - "dev": "nodemon", - "dev:fast": "nodemon --config nodemon.blazing.json", - "test": "ava" - }, - "ava": { - "extensions": { - "js": true, - "ts": "module" - }, - "nodeArguments": [ - "--loader=tsx" - ] - }, - "dependencies": { - "@prisma/client": "latest", - "@sentry/node": "^7.41.0", - "@sentry/tracing": "^7.41.0", - "argon2": "^0.30.3", - "chalk": "^5.2.0", - "cors": "^2.8.5", - "cuid": "^3.0.0", - "diod": "^2.0.0", - "envalid": "^7.3.1", - "escentia": "1.0.0-alpha.2", - "express": "^4.18.2", - "fastify": "^4.17.0", - "fp-ts": "^2.13.1", - "io-ts": "^2.2.20", - "jsonwebtoken": "^9.0.0", - "kbpgp": "^2.1.15", - "keyv": "^4.5.2", - "lodash": "^4.17.21", - "meilisearch": "^0.30.0", - "milliparsec": "^2.2.2", - "monocle-ts": "^2.3.13", - "nanoid": "^4.0.0", - "neverthrow": "^6.0.0", - "newtype-ts": "^0.3.5", - "openpgp": "latest", - "passport": "^0.6.0", - "passport-jwt": "^4.0.1", - "reflect-metadata": "^0.1.13", - "runtypes": "^6.6.0", - "supertest": "^6.3.3", - "swagger-ui-express": "^4.6.0", - "tsoa": "^5.1.1", - "type-fest": "^3.11.0", - "ulid": "^2.3.0" - }, - "devDependencies": { - "@ava/typescript": "^3.0.1", - "@babel/plugin-proposal-decorators": "^7.21.0", - "@openpgp/web-stream-tools": "^0.0.13", - "@types/express": "^4.17.16", - "@types/jsonwebtoken": "^9.0.1", - "@types/lodash": "^4.14.195", - "@types/node": "^18.11.18", - "@types/nodemon": "1.19.2", - "@types/openpgp": "^4.4.18", - "@types/passport": "^1.0.11", - "@types/passport-jwt": "^3.0.8", - "@types/supertest": "^2.0.12", - "@types/swagger-ui-express": "^4.1.3", - "@typescript-eslint/eslint-plugin": "^5.59.7", - "@typescript-eslint/parser": "^5.59.7", - "assemblyscript": "^0.27.5", - "ava": "^5.2.0", - "concurrently": "^8.0.1", - "cypress": "^12.12.0", - "eslint-config-node": "*", - "memphis-dev": "^1.0.4", - "nodemon": "2.0.20", - "prisma": "latest", - "ts-node": "^10.9.1", - "tsconfig-paths": "^4.2.0", - "tsup": "^6.5.0", - "tsx": "3.12.2", - "typescript": "^4.9.4" - }, - "packageManager": "pnpm@8.6.0", - "volta": { - "node": "19.4.0" - } -} diff --git a/apps/server/prisma/seed.ts b/apps/server/prisma/seed.ts deleted file mode 100644 index dd4787b1..00000000 --- a/apps/server/prisma/seed.ts +++ /dev/null @@ -1,44 +0,0 @@ -// 1. Seed Caffeine - -import { PrismaClient } from '@prisma/client' -import { RouteOfAdministrationClassification } from '../src/modules/substance-index/route-of-administration-table/route-of-administration/route-of-administration-classification' - -const prisma = new PrismaClient() - -async function main() { - // Seed Caffeine - const caffeine = await prisma.substance.create({ - data: { - name: 'Caffeine', - description: - '1,3,7-Trimethylxanthine (also known as caffeine) is a naturally-occurring stimulant substance of the xanthine class. Notable effects include stimulation, wakefulness, enhanced focus and motivation. It is the most widely consumed psychoactive substance in the world. ', - substitutive_name: '1,3,7-Trimethylxanthine', - systematic_name: '1,3,7-Trimethylpurine-2,6-dione', - common_names: ['Caffeine'], - routes_of_administration: { - createMany: { - skipDuplicates: true, - data: [{ name: RouteOfAdministrationClassification.ORAL, bioavailability: [0.1] }] - } - } - } - }) - - await prisma.dosage.create({ - data: { - intensivity: 'COMMON', - perKilogram: false, - amount_max: 200, - amount_min: 50, - unit: 'mg', - RouteOfAdministration: { - connect: { - name_substanceName: { - name: RouteOfAdministrationClassification.ORAL, - substanceName: 'Caffeine' - } - } - } - } - }) -} diff --git a/apps/server/rome.json b/apps/server/rome.json deleted file mode 100644 index 6a11479f..00000000 --- a/apps/server/rome.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "$schema": "https://docs.rome.tools/schemas/12.1.3/schema.json", - "organizeImports": { - "enabled": true - }, - "formatter": { - "enabled": true, - "indentStyle": "tab", - "lineWidth": 80 - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - } - }, - "javascript": { - "formatter": { - "quoteStyle": "double", - "trailingComma": "es5", - "semicolons": "asNeeded" - } - } -} diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts deleted file mode 100644 index aabbe739..00000000 --- a/apps/server/src/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -import 'reflect-metadata' -import { HttpApplication } from './interfaces/http/http.js' -import { prisma } from './shared/infrastructure/prisma/prisma.js' - -export function main() { - const application = HttpApplication.listen(Number(process.env['PORT'])).on('listening', () => { - const url = `${process.env['API_URL']}` - console.log(`🚀 Server started at ${url}/docs`) - }) - - const shutdown = () => { - console.info('SIGTERM signal received.'); - console.log('Closing http server.'); - application.close(() => { - console.log('Http server closed.'); - prisma.$disconnect().then(() => { - console.log('Prisma connection closed.'); - process.exit(0); - }).catch((error) => { - console.error('Error occurred while disconnecting from Prisma:', error); - process.exit(1); - }); - }); - }; - - process.on('SIGTERM', shutdown); - process.on('SIGINT', shutdown); -} diff --git a/apps/server/src/interfaces/http/http.ts b/apps/server/src/interfaces/http/http.ts deleted file mode 100644 index 5db3549a..00000000 --- a/apps/server/src/interfaces/http/http.ts +++ /dev/null @@ -1,36 +0,0 @@ -import * as Sentry from '@sentry/node' -import * as Tracing from '@sentry/tracing' -import express, { Application, Request as ExRequest, Response as ExResponse } from 'express' -import { json } from 'milliparsec' -import swaggerUi from 'swagger-ui-express' -import { RegisterRoutes } from '../../../dist/routes/routes.js' -import { - prisma, -} from '../../shared/infrastructure/prisma/prisma.js' - - - -const app : Application = express() - -Sentry.init( { - dsn: process.env['SENTRY_DSN']!, tracesSampleRate: 1.0, profilesSampleRate: 1.0, - - integrations: [ new Sentry.Integrations.Http( { tracing: true } ), new Tracing.Integrations.Express( { app } ), new Tracing.Integrations.Prisma( { client: prisma } ) ], -} ) - -// RequestHandler creates a separate execution context using domains, so that every -// transaction/span/breadcrumb is attached to its own Hub instance -app.use( Sentry.Handlers.requestHandler() ) - -// TracingHandler creates a trace for every incoming request -app.use( Sentry.Handlers.tracingHandler() ) - -app.use( json() ) - -app.use( '/docs', swaggerUi.serve, async(_req : ExRequest, res : ExResponse) => { - return res.send( swaggerUi.generateHTML( await import('../../../docs/swagger.json') ) ) -} ) - -RegisterRoutes( app ) - -export { app as HttpApplication } diff --git a/apps/server/src/interfaces/http/routes/account/account.post.ts b/apps/server/src/interfaces/http/routes/account/account.post.ts deleted file mode 100644 index 591a98a6..00000000 --- a/apps/server/src/interfaces/http/routes/account/account.post.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Body, Controller, OperationId, Post, Response, Route, SuccessResponse, Tags } from 'tsoa' -import { - IdentityAndAccessCommandBus, -} from '../../../../modules/identity-and-access-mangement/application/bus/identity-and-access-command.bus.js' -import { - IdentityAndAccessQueryBus, -} from '../../../../modules/identity-and-access-mangement/application/bus/identity-and-access-query-bus.js' -import { - CreateAccount as CreateAccountCommand, -} from '../../../../modules/identity-and-access-mangement/application/commands/create-account/create-account' -import { - CreateAccountUsecase, -} from '../../../../modules/identity-and-access-mangement/application/usecases/create-account-usecase' -import { - createPassword, -} from '../../../../modules/identity-and-access-mangement/domain/value-objects/password.js' -import { - createUsername, -} from '../../../../modules/identity-and-access-mangement/domain/value-objects/username/username.js' -import { - Exception, -} from '../../../../shared/@foundry/exceptions/exception.js' - - - -/** - * Represents the request body for creating an account. - * @example { "username": "john_doe", "password": "my-password" } - */ -interface CreateAccount { - /** The username for the account. */ - username: string - /** The password for the account. */ - password: string -} - - -@Route('account') @Tags('Account') -export class CreateAccountController - extends Controller { - /** - * Creates an account. - */ - @Post() @OperationId('create-account') @SuccessResponse('201', 'Created') @Response(403, 'AlreadyExists') - public async createAccount(@Body() body: CreateAccount): Promise<{ id: string } | { error: string }> { - try { - const command = new CreateAccountCommand({ - username: await createUsername(body.username), password: await createPassword(body.password), - }) - - console.log(command) - - const usecase = new CreateAccountUsecase(new IdentityAndAccessQueryBus(), new IdentityAndAccessCommandBus()) - - const result = await usecase.execute(command) - - result.unwrapOrElse() - - if (result.isOk()) { - this.setStatus(201) - return { id: result.unwrap().id as string } - } else { - const unwrappedError = result.unwrap() - - this.setStatus(result.mapErr(e => e.statusCode))) - return { error: result.left.message } - } - } - catch (error: unknown) { - if (error instanceof Exception) { - this.setStatus(error.statusCode) - return { error: error.message } - } - - this.setStatus(500) - return { error: 'Failed to create account' } - } - } -} diff --git a/apps/server/src/interfaces/http/routes/authentication/authentication.post.ts b/apps/server/src/interfaces/http/routes/authentication/authentication.post.ts deleted file mode 100644 index f5b737bf..00000000 --- a/apps/server/src/interfaces/http/routes/authentication/authentication.post.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Body, Controller, OperationId, Post, Route, Tags } from 'tsoa' -import { Exception } from '~foundry/exceptions/exception.js' -import { - IdentityAndAccessQueryBus, -} from '../../../../modules/identity-and-access-mangement/application/bus/identity-and-access-query-bus.js' -import { - Authenticate, -} from '../../../../modules/identity-and-access-mangement/application/commands/authenticate/authenticate.js' -import { - AuthenticateResponse, - AuthenticateUsecase, -} from '../../../../modules/identity-and-access-mangement/application/usecases/authenticate-usecase.js' -import { - createPassword, -} from '../../../../modules/identity-and-access-mangement/domain/value-objects/password.js' -import { - createUsername, -} from '../../../../modules/identity-and-access-mangement/domain/value-objects/username/username.js' - - - -/** - * Represents the request body for creating an account. - * @example { "username": "john_doe", "password": "my-password" } - */ -interface AuthenticateAccount { - /** The username for the account. */ - username: string - /** The password for the account. */ - password: string -} - -@Route('authentication') -@Tags('Account') -export class AuthenticateController extends Controller { - /** - * Creates an account. - */ - @Post() - @OperationId('authenticate-account') - public async createAccount(@Body() body: AuthenticateAccount): Promise { - try { - const command = new Authenticate({ - username: await createUsername(body.username), - password: await createPassword(body.password) - }) - - const usecase = new AuthenticateUsecase(new IdentityAndAccessQueryBus()) - - const result = await usecase.execute(command) - - if (result._tag === 'Right') { - this.setStatus(201) - return result.right - } else { - this.setStatus(result.left.statusCode) - return { error: result.left.message } - } - } catch (error: unknown) { - if (error instanceof Exception) { - this.setStatus(error.statusCode) - return { error: error.message } - } - - this.setStatus(500) - return { error: 'Failed to create account' } - } - } -} diff --git a/apps/server/src/interfaces/http/routes/ingestion.controller.ts b/apps/server/src/interfaces/http/routes/ingestion.controller.ts deleted file mode 100644 index 64f8eb50..00000000 --- a/apps/server/src/interfaces/http/routes/ingestion.controller.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Controller, Delete, Get, OperationId, Post, Route, SuccessResponse, Tags } from "tsoa" - -@Route('ingestion') -@Tags('Ingestion') -export class CreateSubjectController extends Controller { - @Post() - @OperationId('create-ingestion') - @SuccessResponse('201', 'Created') - public async createIngestion(): Promise { - this.setStatus(500) - return { error: 'Endpoint not implemented yet'} - } - - @Delete("{id}") - @OperationId('delete-ingestion') - @SuccessResponse('201', 'Created') - public async deleteIngestion(): Promise { - this.setStatus(500) - return { error: 'Endpoint not implemented yet'} - } - - @Get("{id}") - @OperationId('get-ingestion') - @SuccessResponse('201', 'Created') - public async getIngestion(): Promise { - this.setStatus(500) - return { error: 'Endpoint not implemented yet'} - } - - @Get() - @OperationId('get-ingestions') - @SuccessResponse('201', 'Created') - public async getIngestions(): Promise { - this.setStatus(500) - return { error: 'Endpoint not implemented yet'} - } -} diff --git a/apps/server/src/interfaces/http/routes/subject/subject.post.ts b/apps/server/src/interfaces/http/routes/subject/subject.post.ts deleted file mode 100644 index 80e791ad..00000000 --- a/apps/server/src/interfaces/http/routes/subject/subject.post.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { CreateSubjectUseCase } from '../../../../modules/subject/application/usecases/create-subject-usecase.js' -import type { Subject } from '../../../../modules/subject/subject.js' -import { Exception } from '../../../../shared/@foundry/exceptions/exception.js' -import { Body, Controller, OperationId, Post, Route, SuccessResponse, Tags } from 'tsoa' - -@Route('subject') -@Tags('Subject') -export class CreateSubjectController extends Controller { - /** - * Creates an account. - */ - @Post() - @OperationId('create-subject') - @SuccessResponse('201', 'Created') - public async createAccount(@Body() body: Subject): Promise { - try { - const result = await new CreateSubjectUseCase().execute(body) - - if (result._tag === 'Right') { - this.setStatus(201) - return { id: result.right } - } else { - this.setStatus(result.left.statusCode) - return { error: result.left.message } - } - } catch (error: unknown) { - if (error instanceof Exception) { - this.setStatus(error.statusCode) - return { error: error.message } - } - - this.setStatus(500) - return { error: 'Failed to create account' } - } - } -} diff --git a/apps/server/src/modules/__shared-kernel/domain/value-objects/account-id.ts b/apps/server/src/modules/__shared-kernel/domain/value-objects/account-id.ts deleted file mode 100644 index 326f9141..00000000 --- a/apps/server/src/modules/__shared-kernel/domain/value-objects/account-id.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Account } from '../../../identity-and-access-mangement/domain/entities/account.js' - - - -export type AccountId = Account['_id'] diff --git a/apps/server/src/modules/identity-and-access-mangement/README.md b/apps/server/src/modules/identity-and-access-mangement/README.md deleted file mode 100644 index 7043fa26..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/README.md +++ /dev/null @@ -1 +0,0 @@ -# Identity & Access Management (IAM) Context diff --git a/apps/server/src/modules/identity-and-access-mangement/application/bus/identity-and-access-command.bus.ts b/apps/server/src/modules/identity-and-access-mangement/application/bus/identity-and-access-command.bus.ts deleted file mode 100644 index b4e5fe1b..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/application/bus/identity-and-access-command.bus.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { InMemoryCommandBus } from '~components/command-bus/index.js' -import { AccountWriteRepository } from '../../infrastructure/repositories/account.write-repository.js' -import { CreateAccount } from '../commands/create-account/create-account' -import { CreateAccountHandler } from '../commands/create-account/create-account-handler' - - - -export class IdentityAndAccessCommandBus - extends InMemoryCommandBus { - constructor() { - super() - this.subscribe( CreateAccount, new CreateAccountHandler( new AccountWriteRepository() ) ) - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/application/bus/identity-and-access-query-bus.ts b/apps/server/src/modules/identity-and-access-mangement/application/bus/identity-and-access-query-bus.ts deleted file mode 100644 index ab637865..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/application/bus/identity-and-access-query-bus.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { InMemoryQueryBus } from '~components/query-bus/index.js' -import { FindAccountByUsername } from '../queries/get-account-by-username/find-account-by-username' -import { FindAccountByUsernameHandler } from '../queries/get-account-by-username/find-account-by-username.handler' - - - -export class IdentityAndAccessQueryBus extends InMemoryQueryBus { - constructor() { - super() - this.register(FindAccountByUsername, new FindAccountByUsernameHandler()) - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/application/commands/authenticate/authenticate.ts b/apps/server/src/modules/identity-and-access-mangement/application/commands/authenticate/authenticate.ts deleted file mode 100644 index 2191a57d..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/application/commands/authenticate/authenticate.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Command } from '~foundry/cqrs' -import { MessagePayload } from '~foundry/messaging/message.js' -import { Password } from '../../../domain/value-objects/password.js' -import { Username } from '../../../domain/value-objects/username/username.js' - - - -interface AuthenticateProperties { - password: Password - username: Username -} - - -export class Authenticate - extends Command - implements AuthenticateProperties { - password: Password - username: Username - - constructor(payload: MessagePayload) { - super(payload) - this.password = payload.password - this.username = payload.username - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/application/commands/change-username/change-username.ts b/apps/server/src/modules/identity-and-access-mangement/application/commands/change-username/change-username.ts deleted file mode 100644 index d4912d11..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/application/commands/change-username/change-username.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Username } from "~domain/iam/domain/value-objects/username/username"; - -interface ChangeUsernameProperties { - username: Username -} - -export class ChangeUsername { - username: Username - - constructor(properties: ChangeUsernameProperties) { - this.username = properties.username - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/application/commands/create-account/create-account-handler.ts b/apps/server/src/modules/identity-and-access-mangement/application/commands/create-account/create-account-handler.ts deleted file mode 100644 index 81745f6e..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/application/commands/create-account/create-account-handler.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { CommandHandler } from '~foundry/cqrs' -import { Account } from '../../../domain/entities/account.js' -import { Identity } from '../../../domain/identity.js' -import { hashPassword } from '../../../domain/value-objects/password.js' -import { AccountWriteRepository } from '../../../infrastructure/repositories/account.write-repository.js' -import { CreateAccount } from './create-account' - - - -export class CreateAccountHandler - extends CommandHandler { - - constructor(private accountWriteRepository: AccountWriteRepository) { - super() - } - - public async handle(command: CreateAccount): Promise { - console.log(`${this.constructor.name} handling ${command.constructor.name}`) - - const passwordHash = await hashPassword(command.password) - - const account = new Account({ - password: passwordHash, username: command.username, - }) - - const identity = new Identity(account) - - const saved = await this.accountWriteRepository.save(identity.account) - - identity.create() - - // for await (const event of identity.events) { - // await this.domainBus.dispatch( event ) - // } - - // TODO: Save events in persistence. - - return saved - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/application/commands/create-account/create-account.ts b/apps/server/src/modules/identity-and-access-mangement/application/commands/create-account/create-account.ts deleted file mode 100644 index a10a1901..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/application/commands/create-account/create-account.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Command } from '~foundry/cqrs' -import { MessagePayload } from '~foundry/messaging/message.js' -import { Account } from '../../../domain/entities/account.js' -import { Password } from '../../../domain/value-objects/password.js' -import { Username } from '../../../domain/value-objects/username/username.js' - - - -/** - * CreateAccountProperties interface defines the properties required to create an account. - * @publicKey - The PGP public key for the account. - * @username - The unique username for the account. - */ -interface CreateAccountProperties { - password: Password - username: Username -} - - -/** - * The CreateAccount command is used to create a new account. It extends the Command class. - * @publicKey - The PGP public key for the account. - * @username - The unique username for the account. - */ -export class CreateAccount - extends Command - implements CreateAccountProperties { - password: Password - username: Username - - constructor(payload: MessagePayload) { - super(payload) - this.password = payload.password - this.username = payload.username - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/application/commands/delete-account/delete-account.ts b/apps/server/src/modules/identity-and-access-mangement/application/commands/delete-account/delete-account.ts deleted file mode 100644 index 582a3f1b..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/application/commands/delete-account/delete-account.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Command } from '~foundry/cqrs' - - - -interface DeleteAccountProperties { - accountId: string -} - - -export class DeleteAccount - extends Command - implements DeleteAccountProperties { - public accountId: string -} diff --git a/apps/server/src/modules/identity-and-access-mangement/application/queries/get-account-by-username/find-account-by-username.handler.ts b/apps/server/src/modules/identity-and-access-mangement/application/queries/get-account-by-username/find-account-by-username.handler.ts deleted file mode 100644 index 77c7b884..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/application/queries/get-account-by-username/find-account-by-username.handler.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { QueryHandler } from '~foundry/cqrs' -import { Account } from '../../../domain/entities/account' -import { AccountReadRepository } from '../../../infrastructure/repositories/account.read-repository' -import { FindAccountByUsername } from './find-account-by-username' - - - -export class FindAccountByUsernameHandler - extends QueryHandler { - - public async handle(query: FindAccountByUsername): Promise { - const repository = new AccountReadRepository() - const account = await repository.findByUsername(query.username) - - if (account) { - console.log(`${ this.constructor.name } handling query: ${ query.constructor.name }`) - console.log(`Found account: ${ JSON.stringify(account) }`) - return account - } - else { - console.log(`${ this.constructor.name } handling query: ${ query.constructor.name }`) - console.log(`Account not found for username: ${ query.username }`) - return null - } - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/application/queries/get-account-by-username/find-account-by-username.ts b/apps/server/src/modules/identity-and-access-mangement/application/queries/get-account-by-username/find-account-by-username.ts deleted file mode 100644 index 8de49354..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/application/queries/get-account-by-username/find-account-by-username.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Query } from '~foundry/cqrs' -import { Account } from '../../../domain/entities/account.js' - - - -export class FindAccountByUsername - extends Query { - constructor(public readonly username: string) { - super() - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/application/usecases/authenticate-usecase.ts b/apps/server/src/modules/identity-and-access-mangement/application/usecases/authenticate-usecase.ts deleted file mode 100644 index 0d6361ab..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/application/usecases/authenticate-usecase.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Err, Ok, UseCase } from 'escentia' -import { InvalidCredentials } from '~foundry/exceptions/Invalid-credentials.js' -import { NotFound } from '~foundry/exceptions/not-found.js' -import { Account } from '../../domain/entities/account.js' -import { comparePasswordHash } from '../../domain/value-objects/password-hash.js' -import { generateTokens } from '../../services/jwt.js' -import { IdentityAndAccessQueryBus } from '../bus/identity-and-access-query-bus.js' -import { Authenticate } from '../commands/authenticate/authenticate.js' -import { FindAccountByUsername } from '../queries/get-account-by-username/find-account-by-username.js' - - - -export interface AuthenticateResponse { - accessToken: string - refreshToken: string -} - - -export class AuthenticateUsecase - extends UseCase { - constructor(private readonly queryBus: IdentityAndAccessQueryBus) { - super() - } - - public async execute(command: Authenticate) { - const getAccountByUsernameQuery = new FindAccountByUsername(command.username) - const account = await this.queryBus.handle(getAccountByUsernameQuery) - - if (!account) { - return Err(new NotFound(typeof Account)) - } - - const isPasswordSame = await comparePasswordHash(account.password, command.password) - - if (!isPasswordSame) { - return Err(new InvalidCredentials()) - } - - const token = generateTokens(account.id as any) - - return Ok({ - accessToken: token.accessToken, refreshToken: token.refreshToken, - }) - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/application/usecases/create-account-usecase.ts b/apps/server/src/modules/identity-and-access-mangement/application/usecases/create-account-usecase.ts deleted file mode 100644 index 14f074c1..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/application/usecases/create-account-usecase.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Err, Ok, UseCase } from 'escentia' -import { Account } from '~domain/iam/domain/entities/account.js' -import { PolicyViolation } from '~foundry/exceptions/policy-violation.js' -import { IdentityAndAccessCommandBus } from '../bus/identity-and-access-command.bus.js' -import { IdentityAndAccessQueryBus } from '../bus/identity-and-access-query-bus.js' -import { CreateAccount } from '../commands/create-account/create-account' -import { FindAccountByUsername } from '../queries/get-account-by-username/find-account-by-username' - - - -export class CreateAccountUsecase - extends UseCase { - constructor( - private readonly queryBus: IdentityAndAccessQueryBus, private readonly commandBus: IdentityAndAccessCommandBus) { - super() - } - - public async execute(command: CreateAccount) { - const getAccountByUsernameQuery = new FindAccountByUsername(command.username) - - const fetchExistingAccount = await this.queryBus.handle(getAccountByUsernameQuery) - - if (fetchExistingAccount) { - return Err(new PolicyViolation(409, 'CreateAccountWhenAccountWasNotCreatedBefore')) - } - - const account = await this.commandBus.handle(command) - - return Ok(account) - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/entities/account.ts b/apps/server/src/modules/identity-and-access-mangement/domain/entities/account.ts deleted file mode 100644 index 21f05917..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/entities/account.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { CUID } from 'escentia' -import { Entity } from '../../../../shared/@foundry/domain/enity.js' -import { PasswordHash } from '../value-objects/password-hash.js' -import { Username } from '../value-objects/username/username.js' - -// TODO: This should not be extended on Database Schema, however, it's a faster way for now and I expect quite a lot of -// changes in this are so this is helpful. -export interface AccountProperties { - password: PasswordHash - username: Username -} - - -export class Account - extends Entity - implements AccountProperties { - password: PasswordHash - username: Username - - constructor(properties: AccountProperties, id?: CUID) { - super(id) - this.username = properties.username - this.password = properties.password - } - - changeUsername(username: Username): void { - this.username = username - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/events/account-created/account-created-handler.ts b/apps/server/src/modules/identity-and-access-mangement/domain/events/account-created/account-created-handler.ts deleted file mode 100644 index 9ad2af87..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/events/account-created/account-created-handler.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { DomainHandler } from '~foundry/domain' -import { AccountCreated } from './account-created' - - - -export class AccountCreatedHandler - extends DomainHandler { - public async handle(event: AccountCreated): Promise { - console.log('AccountCreatedHandler', event) - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/events/account-created/account-created.ts b/apps/server/src/modules/identity-and-access-mangement/domain/events/account-created/account-created.ts deleted file mode 100644 index ec175671..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/events/account-created/account-created.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { DomainEvent } from '../../../../../shared/@foundry/domain/domain-event.js' -import { Account } from '../../entities/account' - - - -export class AccountCreated extends DomainEvent { - constructor(public readonly account: Account) { - super(account) - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/events/username-changed/username-changed-handler.ts b/apps/server/src/modules/identity-and-access-mangement/domain/events/username-changed/username-changed-handler.ts deleted file mode 100644 index ca744c8d..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/events/username-changed/username-changed-handler.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { DomainHandler } from '~foundry/domain' -import { AccountWriteRepository } from '../../../infrastructure/repositories/account.write-repository.js' -import { UsernameChanged } from './username-changed.js' - - - -export class UsernameChangedHandler extends DomainHandler { - public async handle(event: UsernameChanged): Promise { - await new AccountWriteRepository().save(event.account) - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/events/username-changed/username-changed.ts b/apps/server/src/modules/identity-and-access-mangement/domain/events/username-changed/username-changed.ts deleted file mode 100644 index b386ad8e..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/events/username-changed/username-changed.ts +++ /dev/null @@ -1,11 +0,0 @@ - -import { DomainEvent } from '../../../../../shared/@foundry/domain/domain-event.js' -import { Account } from '../../entities/account.js' - - - -export class UsernameChanged extends DomainEvent { - constructor(public readonly account: Account) { - super() - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/identity.ts b/apps/server/src/modules/identity-and-access-mangement/domain/identity.ts deleted file mode 100644 index b18c57a4..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/identity.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Aggregate } from '~foundry/domain' -import { Account } from './entities/account' -import { AccountCreated } from './events/account-created/account-created.js' -import { UsernameChanged } from './events/username-changed/username-changed.js' -import { Username } from './value-objects/username/username.js' - - - -export class Identity extends Aggregate { - constructor(public account: Account) { - super(account) - } - - create(): void { - this.addEvent(new AccountCreated(this.account)) - } - - changeUsername(username: Username): void { - this.account.changeUsername(username) - this.addEvent(new UsernameChanged(this.account)) - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/json-web-token.ts b/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/json-web-token.ts deleted file mode 100644 index 5ab5a5cc..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/json-web-token.ts +++ /dev/null @@ -1,21 +0,0 @@ -import * as t from 'io-ts' - - - -/** - * @typedef {Object} JsonWebToken - * @property {string} sub - Subject identifier of the token - * @property {string} jti - Unique identifier of the token - * @property {string} iss - Issuer of the token - * @property {string} aud - Audience of the token - * @property {number} exp - Expiration time of the token as a Unix timestamp - */ -export const JsonWebToken = t.type({ - sub: t.string, - jti: t.string, - iss: t.string, - aud: t.string, - exp: t.number -}) - -export type JsonWebToken = t.TypeOf diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/password-hash.ts b/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/password-hash.ts deleted file mode 100644 index 9365d128..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/password-hash.ts +++ /dev/null @@ -1,37 +0,0 @@ -import argon2 from 'argon2' -import { Static, String } from 'runtypes' -import { Password } from './password.js' - - - -const PasswordHash = String.withBrand('PasswordHash') -type PasswordHash = Static - -export async function createPasswordHash(password: string): Promise { - return password as PasswordHash -} - -export async function hashPassword(password: string): Promise { - try { - const hashedPassword = await argon2.hash(password) - return hashedPassword as PasswordHash - } catch (error) { - throw new Error('Error creating password hash') - } -} - -/** - * - * @param hash - * @param password - */ -export async function comparePasswordHash(hash: PasswordHash, password: Password): Promise { - try { - return await argon2.verify(hash, password) - } catch { - // Handle comparison error - throw new Error('Error comparing password hash') - } -} - -export { PasswordHash } diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/password.ts b/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/password.ts deleted file mode 100644 index 738a1b06..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/password.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Static, String } from 'runtypes' -import { - NotImplemented, -} from '../../../../shared/@foundry/exceptions/not-implemented.js' -import { hashPassword as createHashedPassword, PasswordHash } from './password-hash.js' - - - -/** asdsadffasd */ -const Password = String.withBrand('Password') - -type Password = Static - -/** - * - * @param password - */ -async function hashPassword(password: Password): Promise { - try { - return createHashedPassword(password) - } catch { - throw new Error('Error hashing password') - } -} - -/** - * Creates a password hash using Argon2. - * - * @param password The password to hash. - * @returns A Promise resolving to the hashed password. - * @throws Error if there's an error hashing the password. - */ -export async function createPassword(password: string): Promise { - try { - return password as Password - } catch { - // TODO: Throw error when validation fails - throw new NotImplemented('Password Validation') - } -} - -export { Password, hashPassword } diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/username/specification/username-is-above-minimal-character-limit.ts b/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/username/specification/username-is-above-minimal-character-limit.ts deleted file mode 100644 index ba56b033..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/username/specification/username-is-above-minimal-character-limit.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Username } from '../username.js' -import { Specification } from '~foundry/technical/specification.js' - -export class UsernameIsAboveMinimalCharacterLimit extends Specification { - static MINIMAL_LENGTH = 4 - - public satisfy(i: Username): boolean { - return i.length >= UsernameIsAboveMinimalCharacterLimit.MINIMAL_LENGTH - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/username/specification/username-is-below-maxium-character-limit.ts b/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/username/specification/username-is-below-maxium-character-limit.ts deleted file mode 100644 index fd92a9dd..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/username/specification/username-is-below-maxium-character-limit.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Username } from '../username.js' -import { Specification } from '~foundry/technical/specification.js' - -export class UsernameIsBelowMaxiumCharacterLimit extends Specification { - static MAXIMAL_LENGTH = 32 - - public satisfy(i: Username): boolean { - return i.length <= UsernameIsBelowMaxiumCharacterLimit.MAXIMAL_LENGTH - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/username/username.ts b/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/username/username.ts deleted file mode 100644 index db33c56d..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/domain/value-objects/username/username.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { UsernameIsAboveMinimalCharacterLimit } from './specification/username-is-above-minimal-character-limit.js' -import { UsernameIsBelowMaxiumCharacterLimit } from './specification/username-is-below-maxium-character-limit.js' -import * as t from 'io-ts' -import { InvalidValue } from '~foundry/exceptions/invalid-value.js' - -/** Username defines the shape and constraints of a username value object. */ -export const Username = new t.Type( - 'Username', - (input: unknown): input is string => { - return ( - typeof input === 'string' && - new UsernameIsAboveMinimalCharacterLimit().satisfy(input) && - new UsernameIsBelowMaxiumCharacterLimit().satisfy(input) - ) - }, - (input, context) => { - if (typeof input !== 'string') { - return t.failure(input, context, 'Username must be a string') - } - - return t.success(input) - }, - t.identity -) - -export type Username = t.TypeOf - -/** Create new Username value object */ -export async function createUsername(username: string): Promise { - const validationResult = Username.decode(username) - - let valid: string - - if (validationResult._tag === 'Left') { - // Handle validation error - throw new InvalidValue(validationResult.left.join(',')) - } else { - valid = validationResult.right - } - - if ( - !new UsernameIsAboveMinimalCharacterLimit().satisfy(valid) || - !new UsernameIsBelowMaxiumCharacterLimit().satisfy(valid) - ) { - throw new InvalidValue( - `Username must be between ${UsernameIsAboveMinimalCharacterLimit.MINIMAL_LENGTH} and ${UsernameIsBelowMaxiumCharacterLimit.MAXIMAL_LENGTH} characters long` - ) - } - - return username as Username -} diff --git a/apps/server/src/modules/identity-and-access-mangement/infrastructure/data-mappers/account.data-mapper.ts b/apps/server/src/modules/identity-and-access-mangement/infrastructure/data-mappers/account.data-mapper.ts deleted file mode 100644 index 256af64b..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/infrastructure/data-mappers/account.data-mapper.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Account as DatabaseRecord } from '@prisma/client' -import { cuid } from '~foundry/indexing/cuid.js' -import { Mapper } from '~foundry/persistence/mapper.js' -import { Account } from '../../domain/entities/account.js' -import { createPasswordHash } from '../../domain/value-objects/password-hash.js' -import { createUsername } from '../../domain/value-objects/username/username.js' - - - -export class AccountDataMapper - extends Mapper { - public map (input : Account) : DatabaseRecord { - return { - id: input.id as string, - username: input.username as string, - password: input.password as string, - } - } - - public async inverse (input : DatabaseRecord) : Promise { - return new Account ( - { - password: await createPasswordHash ( input.password as string ), - username: await createUsername ( input.username as string ), - }, - cuid ( input.id ), - ) - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/infrastructure/repositories/account.read-repository.ts b/apps/server/src/modules/identity-and-access-mangement/infrastructure/repositories/account.read-repository.ts deleted file mode 100644 index 7ce8914b..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/infrastructure/repositories/account.read-repository.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { UniqueId } from '~foundry/indexing/unique-id.js' -import { QueryRepository } from '~foundry/persistence/read-repository.js' -import { prisma } from '../../../../shared/infrastructure/prisma/prisma' -import { Account } from '../../domain/entities/account' -import { AccountDataMapper } from '../data-mappers/account.data-mapper.js' - - - -export class AccountReadRepository - implements QueryRepository { - private readonly accountDataMapper : AccountDataMapper - - constructor() { - this.accountDataMapper = new AccountDataMapper() - } - - public async findById(id : UniqueId) : Promise { - const account = await prisma.account.findUnique( { where: { id: id as string } } ) - return account ? this.accountDataMapper.inverse( account ) : null - } - - public async findAll() : Promise { - const accounts = await prisma.account.findMany() - return Promise.all( accounts.map( async account => { - return await this.accountDataMapper.inverse( account ) - } ) ) - } - - public async findByUsername(username : string) : Promise { - const account = await prisma.account.findUnique( { where: { username } } ) - return account ? this.accountDataMapper.inverse( account ) : null - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/infrastructure/repositories/account.write-repository.ts b/apps/server/src/modules/identity-and-access-mangement/infrastructure/repositories/account.write-repository.ts deleted file mode 100644 index 0ffe0cb6..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/infrastructure/repositories/account.write-repository.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { cuid } from '~foundry/indexing/cuid.js' -import { UniqueId } from '../../../../shared/@foundry/indexing/unique-id.js' -import { WriteRepository } from '../../../../shared/@foundry/persistence/write-repository.js' -import { prisma } from '../../../../shared/infrastructure/prisma/prisma' -import { Account } from '../../domain/entities/account' - - - -export class AccountWriteRepository - extends WriteRepository { - private prisma = prisma - - public async save(entity : Account) : Promise { - if(entity._id) { - // Existing account, perform update - await this.prisma.account.update( { - where: { id: entity.id as string }, data: { password: entity.password, username: entity.username }, - } ) - return entity - } - else { - // New account, perform creation - const account = await this.prisma.account.create( { - data: { ...entity, id: undefined }, - } ) - return new Account( { - password: entity.password, username: account.username, - }, cuid( account.id ) ) - } - } - - public async delete(id : UniqueId) : Promise { - try { - await this.prisma.account.delete( { where: { id: id as string } } ) - return true - } - catch(error) { - return false - } - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/services/jwt-strategy.ts b/apps/server/src/modules/identity-and-access-mangement/services/jwt-strategy.ts deleted file mode 100644 index c2d5f59c..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/services/jwt-strategy.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { PrismaClient } from '@prisma/client' -import { ExtractJwt, Strategy, StrategyOptions } from 'passport-jwt' - - - -const prisma = new PrismaClient() - -const options: StrategyOptions = { - jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - secretOrKey: process.env['JWT_SECRET'] || 'default_secret' -} - -export class JwtStrategy extends Strategy { - constructor() { - // TODO: Validate payload with JsonWebToken value object. - super(options, async (payload: any, done) => { - // Find user in database. - const user = await prisma.account.findUnique({ where: { id: payload.sub } }) - - // TODO: Find session in database and check if it is valid. - - if (user) { - return done(null, user) - } - - // TODO: Update last logged in date in Sessions. - // this.success(user) - return done(null, false) - }) - } -} diff --git a/apps/server/src/modules/identity-and-access-mangement/services/jwt.ts b/apps/server/src/modules/identity-and-access-mangement/services/jwt.ts deleted file mode 100644 index f00b9395..00000000 --- a/apps/server/src/modules/identity-and-access-mangement/services/jwt.ts +++ /dev/null @@ -1,53 +0,0 @@ -import jwt from 'jsonwebtoken' -import { nanoid } from 'nanoid' -import { UniqueId } from '~foundry/indexing/unique-id.js' -import { JsonWebToken } from '../domain/value-objects/json-web-token.js' - - - -const generateTokens = ( - accountId: UniqueId, - payload?: unknown -): { - refreshToken: string - accessToken: string -} => { - const jti = nanoid(128) - - const options: jwt.SignOptions = { - issuer: 'neuronek.xyz', - audience: 'account.neuronek.xyz', - jwtid: jti, - subject: accountId.toString() - } - - const refreshToken: string = jwt.sign(payload || {}, 'secretKey', { ...options, expiresIn: '7d' }) - const accessToken: string = jwt.sign(payload || {}, 'secretKey', { ...options, expiresIn: '2h' }) - - return { - refreshToken, - accessToken - } -} - -const verifyToken = (token: string): JsonWebToken => { - try { - const decodedToken = jwt.verify(token, 'secretKey', { - issuer: 'neuronek.xyz', - audience: 'account.neuronek.xyz' - }) as JsonWebToken - - // Validate the token with io-ts - const result = JsonWebToken.decode(decodedToken) - - if (result._tag !== 'Right') { - throw new Error('Invalid Token') - } - - return result.right - } catch (error) { - throw new Error('Invalid Token') - } -} - -export { generateTokens, verifyToken } diff --git a/apps/server/src/modules/subject-management/application/usecases/create-subject-usecase.ts b/apps/server/src/modules/subject-management/application/usecases/create-subject-usecase.ts deleted file mode 100644 index 178945d7..00000000 --- a/apps/server/src/modules/subject-management/application/usecases/create-subject-usecase.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { UseCase } from '~foundry/domain/use-case' -import { InvalidValue } from '~foundry/exceptions/invalid-value' -import { Subject } from '@prisma/client' -import { Result, right } from '~foundry/technical/result' -import { prisma } from '../../../../shared/infrastructure/prisma/prisma' - -export interface CreateSubjectPayload { - accountId?: string - displayName?: string - firstName?: string - lastName?: string - birthDate?: Date - weight?: number - height?: number - nationality?: string -} - -export class CreateSubjectUseCase extends UseCase { - async execute(request: CreateSubjectPayload): Promise> { - const subject = await prisma.subject.create({ - data: { - account: { - connect: { - id: request.accountId - } - }, - firstName: request.firstName, - lastName: request.lastName, - weight: request.weight, - height: request.height - } - }) - - return right(subject) - } -} diff --git a/apps/server/src/modules/subject-management/subject.ts b/apps/server/src/modules/subject-management/subject.ts deleted file mode 100644 index 96abb610..00000000 --- a/apps/server/src/modules/subject-management/subject.ts +++ /dev/null @@ -1,29 +0,0 @@ -// These data would be used mostly for in-platform sharing and are optional to respect user's privacy, weight, -// age, and height will be actually used to define personalised dosage. -// Additionall data will be anonimized and maybe sent to analitics to support public reseach. - -import { NotImplemented } from '~foundry/exceptions/not-implemented.js' -import { prisma } from '../../shared/infrastructure/prisma/prisma.js' - -export interface Subject { - // Subject may be linked to specific account. - // MAY because we'll be aggregating experience reports from external sources and we would like to segregate - // experiences by subjects which would make research a bit more transparent. - accountId?: string - displayName?: string - firstName?: string - lastName?: string - birthDate?: Date - weight?: number - height?: number - nationality?: string - // TODO: We may think about health conditions, mental disorders or some other data that may be worthly for analitics. -} - -export function updateSubject(_subjectId: string, _payload: Partial): Subject { - throw new NotImplemented(updateSubject) -} - -export function deleteSubject(_subjectId: string): Promise { - throw new NotImplemented(deleteSubject) -} diff --git a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/bioavailability/bioavailability.ts b/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/bioavailability/bioavailability.ts deleted file mode 100644 index eb2172c2..00000000 --- a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/bioavailability/bioavailability.ts +++ /dev/null @@ -1 +0,0 @@ -export type Bioavailability = [Number?, Number?] diff --git a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/dosage-table/dosage-classification.ts b/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/dosage-table/dosage-classification.ts deleted file mode 100644 index 1733dfcf..00000000 --- a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/dosage-table/dosage-classification.ts +++ /dev/null @@ -1 +0,0 @@ -export enum DosageClassification { diff --git a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase-table.ts b/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase-table.ts deleted file mode 100644 index 909e85a9..00000000 --- a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase-table.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Result } from "~foundry/technical/result"; -import { PhaseNotFound } from "./phase/errors/phase-not-found"; -import { Phase } from "./phase/phase"; -import { PhaseClassification } from "./phase/phase-classification"; - -export interface PhaseTable { - content: { [phase in PhaseClassification]?: Phase} - getPhase(phase: PhaseClassification): Result -} diff --git a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase/errors/phase-not-found.ts b/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase/errors/phase-not-found.ts deleted file mode 100644 index 69a5adee..00000000 --- a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase/errors/phase-not-found.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { NotFound } from "~foundry/exceptions/not-found"; - - -export class PhaseNotFound extends NotFound { - constructor(phase: string) { - super(`Phase ${phase} not found`) - } -} diff --git a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase/phase-classification.ts b/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase/phase-classification.ts deleted file mode 100644 index abae4ace..00000000 --- a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase/phase-classification.ts +++ /dev/null @@ -1,14 +0,0 @@ -export enum PhaseClassification { - /** The onset phase can be defined as the period until the very first changes in perception (i.e. "first alerts") are able to be detected. */ - onset = 'onset', - /** The "come up" phase can be defined as the period between the first noticeable changes in perception and the point of highest subjective intensity. This is colloquially known as "coming up." */ - comeup = 'comeup', - /** The peak phase can be defined as period of time in which the intensity of the substance's effects are at its height. */ - peak = 'peak', - /** The offset phase can be defined as the amount of time in between the conclusion of the peak and shifting into a sober state. This is colloquially referred to as "coming down." */ - offset = 'offset', - /** - * The after effects can be defined as any residual effects which may remain after the experience has reached its conclusion. This is colloquially known as a "hangover" or an "afterglow" depending on the substance and usage. - */ - aftereffects = 'aftereffects' -} diff --git a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase/phase.ts b/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase/phase.ts deleted file mode 100644 index d01e8c70..00000000 --- a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/phase-table/phase/phase.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Duration } from "src/shared/common/duration"; -import { PhaseClassification } from "./phase-classification"; - -export interface Phase { - clasification: PhaseClassification - range: [Duration?, Duration?] -} diff --git a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/route-of-administration-classification.ts b/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/route-of-administration-classification.ts deleted file mode 100644 index 1b716fd2..00000000 --- a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/route-of-administration-classification.ts +++ /dev/null @@ -1,12 +0,0 @@ -export enum RouteOfAdministrationClassification { - ORAL = 'oral', - SUBLINGUAL = 'sublingual', - BUCCAL = 'buccal', - INSUFFLATED = 'insufflated', - RECTAL = 'rectal', - TRANSDERMAL = 'transdermal', - SUBCUTANEOUS = 'subcutaneous', - INTRAMUSCULAR = 'intramuscular', - INTERVENOUS = 'interavenous', - SMOKED = 'smoked', -} diff --git a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/route-of-administration.ts b/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/route-of-administration.ts deleted file mode 100644 index 60e886aa..00000000 --- a/apps/server/src/modules/substance-index/route-of-administration-table/route-of-administration/route-of-administration.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Bioavailability } from "./bioavailability/bioavailability"; -import { PhaseTable } from "./phase-table/phase-table"; -import { RouteOfAdministrationClassification } from "./route-of-administration-classification"; - -export interface RouteOfAdmnistration { - readonly classification: RouteOfAdministrationClassification - readonly bioavailability?: Bioavailability - readonly dosage: any - readonly phase: PhaseTable -} diff --git a/apps/server/src/modules/substance-index/substance.ts b/apps/server/src/modules/substance-index/substance.ts deleted file mode 100644 index b5e6bd1c..00000000 --- a/apps/server/src/modules/substance-index/substance.ts +++ /dev/null @@ -1,18 +0,0 @@ -export interface Substance { - /** - * Most popular common name for the substance. - * @example "Amphetamine" - */ - readonly name: string - - /** - * Chemical nomenclature is the system of naming chemical compounds. The rules for naming compounds vary depending on the type of compound, but in general, they are based on the type and number of atoms present in the compound, as well as the chemical bonds between them. The most common system of chemical nomenclature is the International Union of Pure and Applied Chemistry (IUPAC) system, which is widely used in scientific literature and in industry. - */ - nomenclature?: any - - /** - * Class membership refers to the classification of a chemical compound based on its structural and/or functional properties. In chemistry, compounds are often grouped into classes based on their chemical characteristics, such as their chemical formula, functional groups, or reactivity. - */ - readonly class_membership?: any - -} diff --git a/apps/server/src/shared/@components/README.md b/apps/server/src/shared/@components/README.md deleted file mode 100644 index 5a63063c..00000000 --- a/apps/server/src/shared/@components/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# `@components` - -Components define real-world enterprise patterns that are connected to project's infrastructure, like `EventBus` or -any other part of the system. They are not connected to any specific domain, but rather to the whole system. diff --git a/apps/server/src/shared/@components/command-bus/in-memory-command-bus.ts b/apps/server/src/shared/@components/command-bus/in-memory-command-bus.ts deleted file mode 100644 index 4ac90eb1..00000000 --- a/apps/server/src/shared/@components/command-bus/in-memory-command-bus.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { EventEmitter } from 'events' -import { Command, CommandBus, CommandHandler } from '~foundry/cqrs' -import { ClassConstructor } from '~foundry/technical/class-constructor.js' - - - -export class InMemoryCommandBus> - implements CommandBus { - private bindingStorage : Map> - private eventEmitter : EventEmitter - - constructor() { - this.bindingStorage = new Map>() - this.eventEmitter = new EventEmitter() - } - - public async handle(command : T) : Promise { - const commandType = command.constructor.name - const handler = this.bindingStorage.get( commandType ) - if(handler) { - return await handler.handle( command ) - } - else { - throw new Error( `No handler registered for command: ${ commandType }` ) - } - } - - public async dispatch(command : COMMANDS) : Promise { - const commandType = command.constructor.name - this.eventEmitter.emit( commandType, command ) - } - - public async subscribe(command : ClassConstructor, - handler : CommandHandler, - ) : Promise { - const commandType = command.name - this.bindingStorage.set( commandType, handler ) - this.eventEmitter.on( commandType, (t : any) => handler.handle( t ) ) - } - - public async unsubscribe(command : ClassConstructor, - handler : CommandHandler, - ) : Promise { - const commandType = command.name - this.bindingStorage.delete( commandType ) - this.eventEmitter.off( commandType, handler.handle ) - } -} diff --git a/apps/server/src/shared/@components/command-bus/index.ts b/apps/server/src/shared/@components/command-bus/index.ts deleted file mode 100644 index e072bac8..00000000 --- a/apps/server/src/shared/@components/command-bus/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { InMemoryCommandBus } from './in-memory-command-bus' diff --git a/apps/server/src/shared/@components/domain-bus/in-memory-domain-bus.ts b/apps/server/src/shared/@components/domain-bus/in-memory-domain-bus.ts deleted file mode 100644 index dc797be1..00000000 --- a/apps/server/src/shared/@components/domain-bus/in-memory-domain-bus.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { EventEmitter } from 'events' -import { DomainEvent, DomainHandler } from '~foundry/domain' -import { ClassConstructor } from '~foundry/technical/class-constructor.js' -import { DomainBus } from '../../@foundry/domain/domain-bus.js' - - - -export class InMemoryDomainBus - implements DomainBus { - private bindingStorage : Map> - private eventEmitter : EventEmitter - - constructor() { - this.bindingStorage = new Map>() - this.eventEmitter = new EventEmitter() - - } - - public async dispatch(event : T) : Promise { - const eventType = event.constructor.name - this.eventEmitter.emit( eventType, event ) - } - - public async handle(event : T) : Promise { - const eventType = event.constructor.name - const handler = this.bindingStorage.get( eventType ) - - if(handler) { - await handler.handle( event ) - } - } - - public subscribe(event : ClassConstructor, handler : DomainHandler) : void { - console.log( event ) - const eventType = event.constructor.name - this.bindingStorage.set( eventType, handler ) - this.eventEmitter.on( eventType, handler.handle ) - } - - public unsubscribe(event : ClassConstructor, handler : DomainHandler) : void { - const eventType = event.constructor.name - this.bindingStorage.delete( eventType ) - this.eventEmitter.off( eventType, handler.handle ) - } -} diff --git a/apps/server/src/shared/@components/domain-bus/index.ts b/apps/server/src/shared/@components/domain-bus/index.ts deleted file mode 100644 index a14ead58..00000000 --- a/apps/server/src/shared/@components/domain-bus/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { InMemoryDomainBus } from './in-memory-domain-bus.js' diff --git a/apps/server/src/shared/@components/event-bus/in-memory-event-bus.ts b/apps/server/src/shared/@components/event-bus/in-memory-event-bus.ts deleted file mode 100644 index 67e2de0e..00000000 --- a/apps/server/src/shared/@components/event-bus/in-memory-event-bus.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { EventEmitter } from 'events' -import { EventBus, EventHandler, SystemEvent } from '~foundry/cqrs' -import { MessageConstructor } from '~foundry/technical/class-constructor.js' - - - -export class InMemoryEventBus - implements EventBus { - private bindingStorage : Map> - private eventEmitter : EventEmitter - - constructor() { - this.bindingStorage = new Map>() - this.eventEmitter = new EventEmitter() - } - - public async dispatch(event : SystemEvent) : Promise { - this.eventEmitter.emit( event._type, event ) - } - - public async handle(event : SystemEvent) : Promise { - const handler = this.bindingStorage.get( event._type ) - - if(handler) { - await handler.handle( event ) - } - } - - public async subscribe(event : MessageConstructor, - handler : EventHandler, - ) : Promise { - this.bindingStorage.set( event.type, handler ) - this.eventEmitter.on( event.type, handler.handle ) - } - - public async unsubscribe(event : MessageConstructor, - handler : EventHandler, - ) : Promise { - this.bindingStorage.delete( event.type ) - this.eventEmitter.off( event.type, handler.handle ) - } -} diff --git a/apps/server/src/shared/@components/event-bus/index.ts b/apps/server/src/shared/@components/event-bus/index.ts deleted file mode 100644 index badc6843..00000000 --- a/apps/server/src/shared/@components/event-bus/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { InMemoryEventBus } from './in-memory-event-bus' diff --git a/apps/server/src/shared/@components/message-bus/memphis-message-bus.ts b/apps/server/src/shared/@components/message-bus/memphis-message-bus.ts deleted file mode 100644 index 7ae57c53..00000000 --- a/apps/server/src/shared/@components/message-bus/memphis-message-bus.ts +++ /dev/null @@ -1,19 +0,0 @@ - -import { Message } from "~foundry/messaging/message"; -import { MessageHandler } from "~foundry/messaging/message-handler"; -import { MessageBus } from "~foundry/messaging/messaging-channels/message-bus"; -import { ClassConstructor } from "~foundry/technical/class-constructor"; - -export class MemphisMessageBus extends MessageBus> { - override send>(message: T): void | Promise { - throw new Error("Method not implemented."); - } - - override subscribe>(message: ClassConstructor, handler: MessageHandler): void | Promise { - throw new Error("Method not implemented."); - } - - override unsubscribe>(message: ClassConstructor, handler: MessageHandler): Promise { - throw new Error("Method not implemented."); - } -} diff --git a/apps/server/src/shared/@components/query-bus/in-memory-query-bus.ts b/apps/server/src/shared/@components/query-bus/in-memory-query-bus.ts deleted file mode 100644 index 50c8e7bb..00000000 --- a/apps/server/src/shared/@components/query-bus/in-memory-query-bus.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Query, QueryBus, QueryHandler } from '~foundry/cqrs' -import { NotFound } from '~foundry/exceptions/not-found.js' -import { kebabSpace } from '../../utils/kebab-space.js' - - - -export class InMemoryQueryBus - implements QueryBus { - private readonly bindingStorage : Map> - - constructor() { - this.bindingStorage = new Map>() - } - - public async handle>(query : T) : Promise { - const eventType = kebabSpace( query.constructor.name ) - const handler = this.bindingStorage.get( eventType ) - - console.log( this.bindingStorage ) - - if(!handler) { - throw new NotFound( `Query handler for ${ eventType } not found` ) - } - - return await handler.handle( query ) - } - - public register>(queryConstructor : { new(...args : any[]) : T }, - handler : QueryHandler, - ) : Promise | void { - const eventType = kebabSpace( queryConstructor.name ) - - if(this.bindingStorage.has( eventType )) { - throw new Error( `Query handler for ${ eventType } already registered` ) - } - - this.bindingStorage.set( eventType, handler ) - } -} diff --git a/apps/server/src/shared/@components/query-bus/index.ts b/apps/server/src/shared/@components/query-bus/index.ts deleted file mode 100644 index 28ca589e..00000000 --- a/apps/server/src/shared/@components/query-bus/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { InMemoryQueryBus } from './in-memory-query-bus' diff --git a/apps/server/src/shared/@foundry/README.md b/apps/server/src/shared/@foundry/README.md deleted file mode 100644 index b20e9f0c..00000000 --- a/apps/server/src/shared/@foundry/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# `@foundry` - -Collection of all abstractions and enterprise integration patterns that may be used in software, this is the core of -the framework, in future may be released as a separate library. diff --git a/apps/server/src/shared/@foundry/base/bus.ts b/apps/server/src/shared/@foundry/base/bus.ts deleted file mode 100644 index afc1bcdb..00000000 --- a/apps/server/src/shared/@foundry/base/bus.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Message } from '../messaging/message.js' -import { Handler } from './handler.js' - - - -export abstract class Bus> { - abstract publish(message : T) : Promise | void; - - abstract subscribe(message : T, handler : Handler) : Promise | void; - - abstract unsubscribe(message : T, handler : Handler) : Promise | void; -} - diff --git a/apps/server/src/shared/@foundry/base/conncetion.ts b/apps/server/src/shared/@foundry/base/conncetion.ts deleted file mode 100644 index 6929a9ad..00000000 --- a/apps/server/src/shared/@foundry/base/conncetion.ts +++ /dev/null @@ -1,10 +0,0 @@ -export abstract class Connection { - constructor(private readonly _instance: T) { - } - - public abstract connect(): Promise - public abstract disconnect(): Promise - get instance(): T { - return this._instance - } -} diff --git a/apps/server/src/shared/@foundry/base/handler.ts b/apps/server/src/shared/@foundry/base/handler.ts deleted file mode 100644 index 33e987b5..00000000 --- a/apps/server/src/shared/@foundry/base/handler.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface Handler { - handle(message : REQUEST) : RESPONSE | Promise -} diff --git a/apps/server/src/shared/@foundry/base/producer.ts b/apps/server/src/shared/@foundry/base/producer.ts deleted file mode 100644 index 9e595a16..00000000 --- a/apps/server/src/shared/@foundry/base/producer.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Topic } from "~foundry/base/topic"; -import { Message } from "~foundry/messaging/message"; - -export class Producer { - constructor(private readonly channel: any) { } - - async produce(message: Message, topic: Topic): Promise { - await this.channel.dispatch(message, topic); - } -} diff --git a/apps/server/src/shared/@foundry/base/store.ts b/apps/server/src/shared/@foundry/base/store.ts deleted file mode 100644 index 24c36c7b..00000000 --- a/apps/server/src/shared/@foundry/base/store.ts +++ /dev/null @@ -1,3 +0,0 @@ -export abstract class Store { - abstract save(entity : T) : Promise; -} diff --git a/apps/server/src/shared/@foundry/base/subscriber.ts b/apps/server/src/shared/@foundry/base/subscriber.ts deleted file mode 100644 index 8354c8e8..00000000 --- a/apps/server/src/shared/@foundry/base/subscriber.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Message } from "~foundry/messaging/message"; -import { MessageHandler } from "~foundry/messaging/message-handler"; - - -export class Subscriber> { - constructor( - private readonly handler: MessageHandler - ) { } - - handle(message: T): Promise | void { - this.handler.handle(message); - } -} diff --git a/apps/server/src/shared/@foundry/cqrs/README.md b/apps/server/src/shared/@foundry/cqrs/README.md deleted file mode 100644 index 18c91fd1..00000000 --- a/apps/server/src/shared/@foundry/cqrs/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Segregation of Responsibility for Command Queries (CQRS) - -- **Command**: A message that represents an intention to perform a write operation on the system. -- **Command Handler**: A component that receives a command message and performs the corresponding write operation on the - system. -- **Command Bus**: A message queue that receives command messages and routes them to the appropriate command handler. - -- **Query**: A message that represents an intention to perform a read operation on the system. -- **Query Handler**: A component that receives a query message and returns the corresponding data from the read model. -- **Query Bus**: A message queue that receives query messages and routes them to the appropriate query handler. - -- **Write Model**: A model that is optimized for writing data and is used to store data in the system. -- **Read Model**: A model that is optimized for reading data and is used to provide data to the application’s user - interface. - -- **Event**: A message that represents a fact that has occurred within the system. -- **Event Handler**: A component that receives an event message and performs some action in response (e.g., updating a - read model). -- **Event Bus**: A message queue that receives event messages and routes them to the appropriate event handler. diff --git a/apps/server/src/shared/@foundry/cqrs/command/command-bus.ts b/apps/server/src/shared/@foundry/cqrs/command/command-bus.ts deleted file mode 100644 index 606c714f..00000000 --- a/apps/server/src/shared/@foundry/cqrs/command/command-bus.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ClassConstructor } from '../../technical/class-constructor.js' -import { CommandHandler } from './command-handler.js' -import { Command } from './command.js' - - - -/** - * Command bus is responsible for sending commands from the client or application to the appropriate command - * h andler for processing. It acts as an intermediary between the client and the command handler, encapsulating the - * details of how the command is sent and processed. - */ -export abstract class CommandBus> { - /** Ensure execution of command */ - abstract handle(command: T): T['_response'] | Promise - - /** Fire and forget */ - abstract dispatch(command: T): Promise | void - - abstract subscribe( - command: ClassConstructor, handler: CommandHandler): Promise | void - - abstract unsubscribe( - command: ClassConstructor, handler: CommandHandler): Promise | void -} diff --git a/apps/server/src/shared/@foundry/cqrs/command/command-handler.ts b/apps/server/src/shared/@foundry/cqrs/command/command-handler.ts deleted file mode 100644 index d54424c4..00000000 --- a/apps/server/src/shared/@foundry/cqrs/command/command-handler.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Handler } from '../../base/handler.js' -import { Command } from './command' - - - -/** Command handler is responsible for processing a specific type of command. It receives a command as input from - * the command processor, performs validation, executes business logic, and updates the system's state accordingly. - * Command handlers are typically registered with the command bus or processor, associating specific command types with - * their respective handlers. This allows for dispatching commands to the appropriate handlers based on the command - * type. */ -export abstract class CommandHandler> - implements Handler { - public abstract handle(message: COMMAND): Promise | COMMAND['_response'] -} diff --git a/apps/server/src/shared/@foundry/cqrs/command/command-poller.ts b/apps/server/src/shared/@foundry/cqrs/command/command-poller.ts deleted file mode 100644 index acde796d..00000000 --- a/apps/server/src/shared/@foundry/cqrs/command/command-poller.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** Command poller is a component that initiates long-polling requests to the server to retrieve new commands from - * the command queue. It periodically sends a request to the server, waits for a response, and retrieves any new - * commands that are available. The command poller can be implemented using asynchronous mechanisms such as timers, - * event-driven architectures, or dedicated long-polling libraries. */ -export class CommandPoller { -} diff --git a/apps/server/src/shared/@foundry/cqrs/command/command-processor.ts b/apps/server/src/shared/@foundry/cqrs/command/command-processor.ts deleted file mode 100644 index ce0e1679..00000000 --- a/apps/server/src/shared/@foundry/cqrs/command/command-processor.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * The command processor is responsible for executing the commands retrieved from the command queue. It retrieves - * commands from the command queue one by one and passes them to the appropriate command handler for processing. The - * command processor coordinates the execution flow, error handling, and any necessary transaction management. After - * processing a command, the processor may publish events or perform other actions as required by the system. - */ -export class CommandProcessor { - -} diff --git a/apps/server/src/shared/@foundry/cqrs/command/command-publisher.ts b/apps/server/src/shared/@foundry/cqrs/command/command-publisher.ts deleted file mode 100644 index f60705c3..00000000 --- a/apps/server/src/shared/@foundry/cqrs/command/command-publisher.ts +++ /dev/null @@ -1,3 +0,0 @@ -/** The command publisher is responsible for publishing or sending commands to the command bus. It receives commands from the application layer or external systems and pushes them to the command bus for further processing. The command publisher abstracts away the details of how the commands are generated and delivered to the command bus. */ -export class CommandPublisher { -} diff --git a/apps/server/src/shared/@foundry/cqrs/command/command-queue.ts b/apps/server/src/shared/@foundry/cqrs/command/command-queue.ts deleted file mode 100644 index 95a2a7c1..00000000 --- a/apps/server/src/shared/@foundry/cqrs/command/command-queue.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * The command queue is a storage mechanism that holds the incoming commands until they are processed by the command - * processor. It can be implemented using a data structure such as a list or a message broker like RabbitMQ or Apache - * Kafka. The command queue ensures that commands are processed in the order they were received, providing a reliable - * and consistent processing order. - */ -export class CommandQueue { -} diff --git a/apps/server/src/shared/@foundry/cqrs/command/command-status.ts b/apps/server/src/shared/@foundry/cqrs/command/command-status.ts deleted file mode 100644 index def3d175..00000000 --- a/apps/server/src/shared/@foundry/cqrs/command/command-status.ts +++ /dev/null @@ -1,12 +0,0 @@ -export enum CommandStatus { - PENDING = 'PENDING', - PROCESSING = 'PROCESSING', - COMPLETED = 'COMPLETED', - FAILED = 'FAILED', - REJECTED = 'REJECTED', - CANCELLED = 'CANCELLED', - INVALID = 'INVALID', - TIMEOUT = 'TIMEOUT', - PENDING_RETRY = 'PENDING_RETRY', - UNKNOWN = 'UNKNOWN', -} diff --git a/apps/server/src/shared/@foundry/cqrs/command/command.ts b/apps/server/src/shared/@foundry/cqrs/command/command.ts deleted file mode 100644 index bfc30d4d..00000000 --- a/apps/server/src/shared/@foundry/cqrs/command/command.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Message, MessagePayload } from '../../messaging/message.js' - - - -export abstract class Command - extends Message { - public readonly _response : RESPONSE - - constructor(properties : MessagePayload) { - super( properties ) - Object.assign( this, properties ) - } -} diff --git a/apps/server/src/shared/@foundry/cqrs/event/event-bus.ts b/apps/server/src/shared/@foundry/cqrs/event/event-bus.ts deleted file mode 100644 index a5cd1d00..00000000 --- a/apps/server/src/shared/@foundry/cqrs/event/event-bus.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MessageConstructor } from '../../technical/class-constructor.js' -import { EventHandler } from './event-handler.js' -import { SystemEvent } from './system.event.js' - - - -/** - * Event bus is to enable loosely coupled communication between components or modules in a software system. It - * allows components to publish and subscribe to events, promoting decoupling, flexibility, and extensibility in the - * system's architecture. The event bus acts as a central hub for event exchange, facilitating efficient and - * asynchronous communication among different parts of the application. - */ -export abstract class EventBus { - /** - * Dispatch event to all subscribed handlers, this method uses "fire-and-forget" methods which makes the whole - * process asynchronous. - */ - abstract dispatch(event : SystemEvent) : Promise | void - - abstract handle(event : SystemEvent) : Promise - - abstract subscribe(event : MessageConstructor, - handler : EventHandler, - ) : Promise | void - - abstract unsubscribe(event : MessageConstructor, - handler : EventHandler, - ) : Promise | void -} diff --git a/apps/server/src/shared/@foundry/cqrs/event/event-handler.ts b/apps/server/src/shared/@foundry/cqrs/event/event-handler.ts deleted file mode 100644 index 34cd4a39..00000000 --- a/apps/server/src/shared/@foundry/cqrs/event/event-handler.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Handler } from '../../base/handler.js' -import { SystemEvent } from './system.event.js' - - - -export abstract class EventHandler - implements Handler { - abstract handle(message : T) : Promise | void -} diff --git a/apps/server/src/shared/@foundry/cqrs/event/event-store.ts b/apps/server/src/shared/@foundry/cqrs/event/event-store.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/server/src/shared/@foundry/cqrs/event/system.event.ts b/apps/server/src/shared/@foundry/cqrs/event/system.event.ts deleted file mode 100644 index 244b590a..00000000 --- a/apps/server/src/shared/@foundry/cqrs/event/system.event.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Message } from '../../messaging/message.js' - - - -export abstract class SystemEvent - extends Message { -} diff --git a/apps/server/src/shared/@foundry/cqrs/index.ts b/apps/server/src/shared/@foundry/cqrs/index.ts deleted file mode 100644 index 28de2302..00000000 --- a/apps/server/src/shared/@foundry/cqrs/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export { CommandBus } from './command/command-bus' -export { CommandHandler } from './command/command-handler' -export { Command } from './command/command' - -export { QueryBus } from './query/query-bus' -export { QueryHandler } from './query/query-handler' -export { Query } from './query/query' - -export { EventBus } from './event/event-bus' -export { EventHandler } from './event/event-handler' -export { SystemEvent } from './event/system.event.js' diff --git a/apps/server/src/shared/@foundry/cqrs/models/model-payload.ts b/apps/server/src/shared/@foundry/cqrs/models/model-payload.ts deleted file mode 100644 index d3f19fcd..00000000 --- a/apps/server/src/shared/@foundry/cqrs/models/model-payload.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type ModelPayload = { - id: ID -} & Properties diff --git a/apps/server/src/shared/@foundry/cqrs/models/read-model.ts b/apps/server/src/shared/@foundry/cqrs/models/read-model.ts deleted file mode 100644 index a0d1d9d4..00000000 --- a/apps/server/src/shared/@foundry/cqrs/models/read-model.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { UniqueId } from '../../indexing/unique-id' -import { ModelPayload } from './model-payload' - -export abstract class ReadModel { - readonly id: ID - - constructor(payload: ModelPayload) { - this.id = payload.id - Object.assign(this, payload) - } -} diff --git a/apps/server/src/shared/@foundry/cqrs/models/write-model.ts b/apps/server/src/shared/@foundry/cqrs/models/write-model.ts deleted file mode 100644 index 163fbf7f..00000000 --- a/apps/server/src/shared/@foundry/cqrs/models/write-model.ts +++ /dev/null @@ -1,5 +0,0 @@ - -import { UniqueId } from '~foundry/indexing/unique-id'; -import { ReadModel } from './read-model' - -export abstract class WriteModel extends ReadModel { } diff --git a/apps/server/src/shared/@foundry/cqrs/query/query-bus.ts b/apps/server/src/shared/@foundry/cqrs/query/query-bus.ts deleted file mode 100644 index 0b5c416c..00000000 --- a/apps/server/src/shared/@foundry/cqrs/query/query-bus.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { QueryHandler } from '~foundry/cqrs/index.js' -import { ClassConstructor } from '../../technical/class-constructor.js' -import { Query } from './query' - - - -export abstract class QueryBus { - abstract handle>(query : T) : Promise | T['_cast'] - - abstract register>( - query : ClassConstructor, handler : QueryHandler) : Promise | void -} diff --git a/apps/server/src/shared/@foundry/cqrs/query/query-handler.ts b/apps/server/src/shared/@foundry/cqrs/query/query-handler.ts deleted file mode 100644 index 05c2b5fd..00000000 --- a/apps/server/src/shared/@foundry/cqrs/query/query-handler.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Query } from './query' - - - -export abstract class QueryHandler> { - abstract handle(query: T): Promise | T['_cast'] -} diff --git a/apps/server/src/shared/@foundry/cqrs/query/query.ts b/apps/server/src/shared/@foundry/cqrs/query/query.ts deleted file mode 100644 index 815be9f1..00000000 --- a/apps/server/src/shared/@foundry/cqrs/query/query.ts +++ /dev/null @@ -1,3 +0,0 @@ -export abstract class Query { - public readonly _cast: T -} diff --git a/apps/server/src/shared/@foundry/domain/aggregate-root.ts b/apps/server/src/shared/@foundry/domain/aggregate-root.ts deleted file mode 100644 index 28187466..00000000 --- a/apps/server/src/shared/@foundry/domain/aggregate-root.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Entity } from '~foundry/domain/enity.js' - - - -export class AggregateRoot extends Entity { } diff --git a/apps/server/src/shared/@foundry/domain/aggregate.ts b/apps/server/src/shared/@foundry/domain/aggregate.ts deleted file mode 100644 index 9a8e61aa..00000000 --- a/apps/server/src/shared/@foundry/domain/aggregate.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { AggregateRoot } from '~foundry/domain/aggregate-root.js' -import { DomainEvent } from './domain-event.js' - - - -export abstract class Aggregate { - protected readonly _id: T['_id'] - protected root: T - - protected constructor(root: T, version?: number) { - this._id = root._id - this._version = version || 0 - this._events = [] - this.root = root - } - - protected _version: number - - public get version(): number { - return this._version - } - - protected _events: DomainEvent[] - - public get events(): DomainEvent[] { - return this._events - } - - public addEvent(event: DomainEvent): void { - this._events.push(event) - this.incrementVersion() - } - - public clearEvents(): void { - this._events.length = 0 - } - - private incrementVersion(): void { - this._version++ - } -} diff --git a/apps/server/src/shared/@foundry/domain/domain-bus.ts b/apps/server/src/shared/@foundry/domain/domain-bus.ts deleted file mode 100644 index a26eb264..00000000 --- a/apps/server/src/shared/@foundry/domain/domain-bus.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ClassConstructor } from '../technical/class-constructor.js' -import { DomainEvent } from './domain-event.js' -import { DomainHandler } from './domain-handler.js' -import { Entity } from './enity.js' - - - -export abstract class DomainBus> { - /** - * Dispatch event to all subscribed handlers, this method uses "fire-and-forget" methods which makes the whole - * process asynchronous. - */ - abstract dispatch(event: T): Promise | void - - abstract handle(event: T): Promise | void - - abstract subscribe(event: ClassConstructor, handler: DomainHandler): Promise | void - - abstract unsubscribe(event: ClassConstructor, handler: DomainHandler): Promise | void -} diff --git a/apps/server/src/shared/@foundry/domain/domain-event.ts b/apps/server/src/shared/@foundry/domain/domain-event.ts deleted file mode 100644 index d52b9fbc..00000000 --- a/apps/server/src/shared/@foundry/domain/domain-event.ts +++ /dev/null @@ -1,10 +0,0 @@ - -import { SystemEvent } from '../cqrs/event/system.event.js'; -import { Entity } from './enity.js' - - - -export abstract class DomainEvent - extends SystemEvent { - -} diff --git a/apps/server/src/shared/@foundry/domain/domain-handler.ts b/apps/server/src/shared/@foundry/domain/domain-handler.ts deleted file mode 100644 index 4fe8c558..00000000 --- a/apps/server/src/shared/@foundry/domain/domain-handler.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { DomainEvent } from './domain-event.js' -import { Entity } from './enity.js' - - - -export abstract class DomainHandler> { - abstract handle(event: T): Promise -} diff --git a/apps/server/src/shared/@foundry/domain/enity.ts b/apps/server/src/shared/@foundry/domain/enity.ts deleted file mode 100644 index 999b9537..00000000 --- a/apps/server/src/shared/@foundry/domain/enity.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { WriteModel } from '~foundry/cqrs/models/write-model.js' -import { IdentifierMissing } from '../exceptions/identifier-missing.js' -import { UniqueId } from '../indexing/unique-id.js' - - - -/** - * Entities are pretty much the bread and butter of domain modeling. - * - * They are the objects that represent the data that is being manipulated by the application. - * - * @version 1.0.0 - * @author Jakub "keinsell" Olan - * @see [Understanding Domain Entities](https://khalilstemmler.com/articles/typescript-domain-driven-design/entities/) - */ -export abstract class Entity implements WriteModel { - /** Automatically generated (or imported) id of specific entity. Used to - reference a right object in the persistence layer. */ - public readonly _id: T | undefined - - protected constructor(id?: T | undefined) { - this._id = id - } - - get id(): T { - if (!this._id) { - throw new IdentifierMissing(this) - } - return this._id - } -} diff --git a/apps/server/src/shared/@foundry/domain/index.ts b/apps/server/src/shared/@foundry/domain/index.ts deleted file mode 100644 index 5fe95063..00000000 --- a/apps/server/src/shared/@foundry/domain/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { Aggregate } from './aggregate.js' -export { DomainEvent } from './domain-event.js' -export { Entity } from './enity.js' -export { DomainHandler } from './domain-handler.js' -export { ValueObject } from './value-object.js' -export { AggregateRoot } from './aggregate-root.js' diff --git a/apps/server/src/shared/@foundry/domain/value-object.ts b/apps/server/src/shared/@foundry/domain/value-object.ts deleted file mode 100644 index a7f9d04c..00000000 --- a/apps/server/src/shared/@foundry/domain/value-object.ts +++ /dev/null @@ -1,5 +0,0 @@ -export abstract class ValueObject { - equals(other: ValueObject): boolean { - return this === other - } -} diff --git a/apps/server/src/shared/@foundry/exceptions/Invalid-credentials.ts b/apps/server/src/shared/@foundry/exceptions/Invalid-credentials.ts deleted file mode 100644 index ad025cca..00000000 --- a/apps/server/src/shared/@foundry/exceptions/Invalid-credentials.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Exception } from './exception.js' - - - -export class InvalidCredentials extends Exception { - constructor() { - super({ - statusCode: 401, - message: `Provided invalid credentials.` - }) - } -} diff --git a/apps/server/src/shared/@foundry/exceptions/exception.ts b/apps/server/src/shared/@foundry/exceptions/exception.ts deleted file mode 100644 index 57a4161d..00000000 --- a/apps/server/src/shared/@foundry/exceptions/exception.ts +++ /dev/null @@ -1,14 +0,0 @@ -interface ExceptionProperties { - message: string - statusCode: number -} - -export class Exception extends Error implements ExceptionProperties { - statusCode: number - - protected constructor(properites: ExceptionProperties) { - super(properites.message) - this.statusCode = properites.statusCode - this.name = this.constructor.name - } -} diff --git a/apps/server/src/shared/@foundry/exceptions/identifier-missing.ts b/apps/server/src/shared/@foundry/exceptions/identifier-missing.ts deleted file mode 100644 index 77a3f4da..00000000 --- a/apps/server/src/shared/@foundry/exceptions/identifier-missing.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Entity } from '../domain/enity.js' -import { Exception } from './exception.js' - - - -/** - * IdentifierMissing is responsible for when identifier is missing, this is mostly a case where we decide to save - * something in async way. - */ -export class IdentifierMissing extends Exception { - constructor(entity: Entity) { - super({ - statusCode: 422, - message: `Identifier of ${entity.constructor.name} is missing. Perhaps system delayed write to database because high load, please try again or wait a little moment and check if your action has been made.` - }) - } -} diff --git a/apps/server/src/shared/@foundry/exceptions/invalid-value.ts b/apps/server/src/shared/@foundry/exceptions/invalid-value.ts deleted file mode 100644 index 46cfce0a..00000000 --- a/apps/server/src/shared/@foundry/exceptions/invalid-value.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Exception } from './exception.js' - - - -export class InvalidValue extends Exception { - constructor(message: string) { - super({ - statusCode: 400, - message: message - }) - } -} diff --git a/apps/server/src/shared/@foundry/exceptions/not-found.ts b/apps/server/src/shared/@foundry/exceptions/not-found.ts deleted file mode 100644 index 24dde7d3..00000000 --- a/apps/server/src/shared/@foundry/exceptions/not-found.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Exception } from './exception.js' - - - -export class NotFound - extends Exception { - constructor(entity? : string) { - super( { - statusCode: 404, message: `${ entity || 'Entity' } was not found.`, - } ) - } -} diff --git a/apps/server/src/shared/@foundry/exceptions/not-implemented.ts b/apps/server/src/shared/@foundry/exceptions/not-implemented.ts deleted file mode 100644 index 070fdff1..00000000 --- a/apps/server/src/shared/@foundry/exceptions/not-implemented.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Exception } from './exception.js' - - - -export class NotImplemented extends Exception { - constructor(feature: Function | Object) { - super({ - statusCode: 501, - message: `Feature ${ - feature instanceof Function ? feature.name : feature.constructor.name - } is not implemented yet.` - }) - } -} diff --git a/apps/server/src/shared/@foundry/exceptions/policy-violation.ts b/apps/server/src/shared/@foundry/exceptions/policy-violation.ts deleted file mode 100644 index 4aa48f87..00000000 --- a/apps/server/src/shared/@foundry/exceptions/policy-violation.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Exception } from './exception.js' - - - -export class PolicyViolation extends Exception { - constructor(status: 403 | 422 | 409 | 400, policyName: string) { - super({ - statusCode: status, - message: `Action violated internal policy ${policyName}. Please try again with correct action.` - }) - } -} diff --git a/apps/server/src/shared/@foundry/http/controller.ts b/apps/server/src/shared/@foundry/http/controller.ts deleted file mode 100644 index 28cf6360..00000000 --- a/apps/server/src/shared/@foundry/http/controller.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Request } from './request.js' -import { Response } from './response.js' - - - -export abstract class Controller { - protected req: Request - protected res: Response - - public static json(response: Response, code: number, message: string) { - return response.status(code).json({ message }) - } - - public execute(request: Request, response: Response): void { - this.req = request - this.res = response - - this.executeImpl() - } - - public ok(response: Response, dto?: T) { - return dto ? response.status(200).json(dto) : response.sendStatus(200) - } - - public created(response: Response) { - return response.sendStatus(201) - } - - public clientError(message?: string) { - return Controller.json(this.res, 400, message ?? 'Unauthorized') - } - - public unauthorized(message?: string) { - return Controller.json(this.res, 401, message ?? 'Unauthorized') - } - - public paymentRequired(message?: string): Response { - return Controller.json(this.res, 402, message ?? 'Payment required') - } - - public forbidden(message?: string): Response { - return Controller.json(this.res, 403, message ?? 'Forbidden') - } - - public notFound(message?: string) { - return Controller.json(this.res, 404, message ?? 'Not found') - } - - public conflict(message?: string) { - return Controller.json(this.res, 409, message ?? 'Conflict') - } - - public tooMany(message?: string) { - return Controller.json(this.res, 429, message ?? 'Too many requests') - } - - public todo() { - return Controller.json(this.res, 400, 'TODO') - } - - public fail(error: Error | string) { - console.log(error) - return this.res.status(500).json({ - message: error.toString() - }) - } - - protected abstract executeImpl(): Promise -} diff --git a/apps/server/src/shared/@foundry/http/middleware.ts b/apps/server/src/shared/@foundry/http/middleware.ts deleted file mode 100644 index 7ec7e812..00000000 --- a/apps/server/src/shared/@foundry/http/middleware.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NextFunction } from './next-function.js' -import { Request } from './request.js' -import { Response } from './response.js' - - - -export abstract class Middleware { - abstract use(request: Request, res: Response, next: NextFunction): void -} diff --git a/apps/server/src/shared/@foundry/http/next-function.ts b/apps/server/src/shared/@foundry/http/next-function.ts deleted file mode 100644 index b8e3b810..00000000 --- a/apps/server/src/shared/@foundry/http/next-function.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { NextFunction as ExternalNextFunction } from 'express' - - - -export type NextFunction = ExternalNextFunction diff --git a/apps/server/src/shared/@foundry/http/request.ts b/apps/server/src/shared/@foundry/http/request.ts deleted file mode 100644 index 8d8f4792..00000000 --- a/apps/server/src/shared/@foundry/http/request.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Request as ExternalRequest } from 'express' - - - -export type Request = ExternalRequest diff --git a/apps/server/src/shared/@foundry/http/response.ts b/apps/server/src/shared/@foundry/http/response.ts deleted file mode 100644 index ae0273b3..00000000 --- a/apps/server/src/shared/@foundry/http/response.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Response as ExternalResponse } from 'express' - - - -export type Response = ExternalResponse diff --git a/apps/server/src/shared/@foundry/indexing/cuid.ts b/apps/server/src/shared/@foundry/indexing/cuid.ts deleted file mode 100644 index 7a88aa2e..00000000 --- a/apps/server/src/shared/@foundry/indexing/cuid.ts +++ /dev/null @@ -1,36 +0,0 @@ -import generateCuid from 'cuid' -import * as t from 'io-ts' -import { InvalidValue } from '~foundry/exceptions/invalid-value.js' - - - -interface CUIDBrand { - readonly CUID: unique symbol -} - -/** - * Determines if input is a valid CUID - * - * @param input - */ -function isCuid(input: string): boolean { - return generateCuid.isCuid(input) -} - -const CUIDCodec = t.brand(t.string, (s): s is t.Branded => isCuid(s), 'CUID') - -export type CUID = t.TypeOf - -/** - * Creates a new CUID - * - * @param id - Optional CUID - */ -export function cuid(id?: string): CUID { - const validationResult = CUIDCodec.decode(id || generateCuid()) - if (validationResult._tag === 'Left') { - throw new InvalidValue('Invalid CUID') - } else { - return validationResult.right - } -} diff --git a/apps/server/src/shared/@foundry/indexing/nanoid/index.ts b/apps/server/src/shared/@foundry/indexing/nanoid/index.ts deleted file mode 100644 index 264327fd..00000000 --- a/apps/server/src/shared/@foundry/indexing/nanoid/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type { NanoID } from './nanoid.js' -export { nanoid } from './nanoid.js' diff --git a/apps/server/src/shared/@foundry/indexing/nanoid/is-nanoid.ts b/apps/server/src/shared/@foundry/indexing/nanoid/is-nanoid.ts deleted file mode 100644 index 715c45fc..00000000 --- a/apps/server/src/shared/@foundry/indexing/nanoid/is-nanoid.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Specification } from '~foundry/technical/specification.js' - -export class IsNanoid extends Specification { - public satisfy(i: string): boolean { - const nanoidRegex = new RegExp(`^[a-zA-Z0-9_-]{8,64}$`) - return nanoidRegex.test(i) - } -} diff --git a/apps/server/src/shared/@foundry/indexing/nanoid/nanoid.spec.ts b/apps/server/src/shared/@foundry/indexing/nanoid/nanoid.spec.ts deleted file mode 100644 index 88094ac8..00000000 --- a/apps/server/src/shared/@foundry/indexing/nanoid/nanoid.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import test from 'ava' -import { InvalidValue } from '~foundry/exceptions/invalid-value.js' -import { NanoID, nanoid } from './nanoid.js' - -test('nanoid() generates a valid Nanoid', t => { - const id = nanoid() - t.true(isValidNanoid(id)) -}) - -test('nanoid(id) returns the provided Nanoid if valid', t => { - const validNanoid = 'UMmgcRhFekXDAmrtUJYFc' - const id = nanoid(validNanoid) - t.is(id, validNanoid as NanoID) -}) - -test('nanoid() throws InvalidValue error if invalid Nanoid is generated', t => { - t.throws(() => nanoid('xyz'), { instanceOf: InvalidValue }) -}) - -function isValidNanoid(id: string): boolean { - const nanoidRegex = new RegExp(`^[a-zA-Z0-9_-]{8,64}$`) - return nanoidRegex.test(id) -} diff --git a/apps/server/src/shared/@foundry/indexing/nanoid/nanoid.ts b/apps/server/src/shared/@foundry/indexing/nanoid/nanoid.ts deleted file mode 100644 index 503d535f..00000000 --- a/apps/server/src/shared/@foundry/indexing/nanoid/nanoid.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as t from 'io-ts' -import { nanoid as _nanoid } from 'nanoid' -import { InvalidValue } from '~foundry/exceptions/invalid-value.js' -import { IsNanoid } from '~foundry/indexing/nanoid/is-nanoid.js' - -const NanoidCodec = t.brand( - t.string, - (s: string): s is t.Branded => new IsNanoid().satisfy(s), - 'NanoID' -) - -/** - * Nanoid is a small, URL-friendly, and cryptographically secure unique ID generator library. It generates compact and random string identifiers that are suitable for various applications, such as generating short IDs for URLs, unique keys for objects, or session IDs. Nanoid is commonly used in web development for generating unique and easily shareable identifiers. - */ -export type NanoID = t.TypeOf - -/** - * Nanoid is a small, URL-friendly, and cryptographically secure unique ID generator library. It generates compact and random string identifiers that are suitable for various applications, such as generating short IDs for URLs, unique keys for objects, or session IDs. Nanoid is commonly used in web development for generating unique and easily shareable identifiers. - * @param {string} id - The id to validate - * @param {number} size - The number of characters in the id - * @returns {NanoID} - The validated id - */ -export function nanoid(id?: string, size: number = 36): NanoID { - const validationResult = NanoidCodec.decode(id || _nanoid(size)) - if (validationResult._tag === 'Left') { - throw new InvalidValue('Invalid Nanoid') - } else { - return validationResult.right - } -} diff --git a/apps/server/src/shared/@foundry/indexing/sequential-id/index.ts b/apps/server/src/shared/@foundry/indexing/sequential-id/index.ts deleted file mode 100644 index 83db4a68..00000000 --- a/apps/server/src/shared/@foundry/indexing/sequential-id/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type {SequentialID} from './sequential-id.js' diff --git a/apps/server/src/shared/@foundry/indexing/sequential-id/is-sequentialid.ts b/apps/server/src/shared/@foundry/indexing/sequential-id/is-sequentialid.ts deleted file mode 100644 index a591f772..00000000 --- a/apps/server/src/shared/@foundry/indexing/sequential-id/is-sequentialid.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Specification } from '~foundry/technical/specification.js' - - - -export class IsSequentialID - extends Specification { - public satisfy(i: number): boolean { - return i > 0 - } -} diff --git a/apps/server/src/shared/@foundry/indexing/sequential-id/sequential-id.ts b/apps/server/src/shared/@foundry/indexing/sequential-id/sequential-id.ts deleted file mode 100644 index 2a63a5cd..00000000 --- a/apps/server/src/shared/@foundry/indexing/sequential-id/sequential-id.ts +++ /dev/null @@ -1,34 +0,0 @@ -import * as t from 'io-ts' -import { InvalidValue } from '~foundry/exceptions/invalid-value.js' -import { IsSequentialID } from '~foundry/indexing/sequential-id/is-sequentialid.js' - - - -const SequentialIDCodec = t.brand( - t.number, - (s: number): s is t.Branded => new IsSequentialID().satisfy(s), - 'SequentialID', -) - -/** - * Sequential ID is a unique identifier assigned to data records in a sequential order, typically incrementing by - * one. It is commonly used in databases and systems where maintaining a consistent order of records is important. Sequential IDs are used to ensure data integrity, enable efficient indexing, and facilitate chronological sorting of records in applications such as transactional systems, logging systems, or content management systems. - */ -export type SequentialID = t.TypeOf - -/**ś - * Sequential ID is a unique identifier assigned to data records in a sequential order, typically incrementing by - * one. It is commonly used in databases and systems where maintaining a consistent order of records is important. Sequential IDs are used to ensure data integrity, enable efficient indexing, and facilitate chronological sorting of records in applications such as transactional systems, logging systems, or content management systems. - * - * @param {string} id - The id to validate - * @returns {SequentialID} - The validated id - */ -export function sequentialId(id?: number): SequentialID { - const validationResult = SequentialIDCodec.decode(id || 0) - if (validationResult._tag === 'Left') { - throw new InvalidValue('Invalid Sequential ID') - } - else { - return validationResult.right - } -} diff --git a/apps/server/src/shared/@foundry/indexing/sequential-id/sequentialid.spec.ts b/apps/server/src/shared/@foundry/indexing/sequential-id/sequentialid.spec.ts deleted file mode 100644 index 2d706d47..00000000 --- a/apps/server/src/shared/@foundry/indexing/sequential-id/sequentialid.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import test from 'ava' -import { InvalidValue } from '~foundry/exceptions/invalid-value.js' -import { SequentialID, sequentialId } from '~foundry/indexing/sequential-id/sequential-id.js' - - - -test('sequentialId should validate and return a SequentialID', (t) => { - const validID = 123 as SequentialID; - const invalidID = -12; - - t.is(sequentialId(validID), validID); - t.throws(() => sequentialId(invalidID), { instanceOf: InvalidValue }); -}); diff --git a/apps/server/src/shared/@foundry/indexing/todo.txt b/apps/server/src/shared/@foundry/indexing/todo.txt deleted file mode 100644 index 110c8887..00000000 --- a/apps/server/src/shared/@foundry/indexing/todo.txt +++ /dev/null @@ -1,3 +0,0 @@ -- UUID -- KSUID -- ULID diff --git a/apps/server/src/shared/@foundry/indexing/ulid/README.md b/apps/server/src/shared/@foundry/indexing/ulid/README.md deleted file mode 100644 index 68299320..00000000 --- a/apps/server/src/shared/@foundry/indexing/ulid/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Universally Unique Lexicographically Sortable Identifier (ULID) - -https://github.com/ulid/spec diff --git a/apps/server/src/shared/@foundry/indexing/ulid/index.ts b/apps/server/src/shared/@foundry/indexing/ulid/index.ts deleted file mode 100644 index a140bf12..00000000 --- a/apps/server/src/shared/@foundry/indexing/ulid/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type { ULID } from './ulid.js' -export { ulid } from './ulid.js' diff --git a/apps/server/src/shared/@foundry/indexing/ulid/is-ulid.ts b/apps/server/src/shared/@foundry/indexing/ulid/is-ulid.ts deleted file mode 100644 index 17128547..00000000 --- a/apps/server/src/shared/@foundry/indexing/ulid/is-ulid.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Specification } from '~foundry/technical/specification.js' - - - -export class IsUlid extends Specification { - public satisfy(i: string): boolean { - const ulidRegex = /^[0-9A-Z]{26}$/ - - if (!ulidRegex.test(i)) { - // The string doesn't match the basic format of a ULID - return false - } - - const timestamp = parseInt(i.substr(0, 10), 36) - // const entropy = i.substr(10) - - if (isNaN(timestamp)) { - // The timestamp part is not a valid base36 number - return false - } - - // You can perform additional checks on the timestamp and entropy if needed - // For example, ensuring that the timestamp falls within a valid range, etc. - - return true - } -} diff --git a/apps/server/src/shared/@foundry/indexing/ulid/ulid.spec.ts b/apps/server/src/shared/@foundry/indexing/ulid/ulid.spec.ts deleted file mode 100644 index 5dff98c8..00000000 --- a/apps/server/src/shared/@foundry/indexing/ulid/ulid.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import test from 'ava' -import { InvalidValue } from '../../exceptions/invalid-value.js' -import { IsUlid } from './is-ulid.js' -import { ULID, ulid } from './ulid' - - - -test('ulid() generates a valid ULID', t => { - const id = ulid() - t.true(new IsUlid().satisfy(id)) -}) - -test('ulid(id) returns the provided ULID if valid', t => { - const validULID = '01E6T42T1T65TNBCT6VZ8YHQNX' - const id = ulid(validULID) - t.is(id, validULID as ULID) -}) - -test('ulid() throws InvalidValue error if invalid ULID is generated', t => { - t.throws(() => ulid('invalid-ulid'), { instanceOf: InvalidValue }) -}) diff --git a/apps/server/src/shared/@foundry/indexing/ulid/ulid.ts b/apps/server/src/shared/@foundry/indexing/ulid/ulid.ts deleted file mode 100644 index dd2f62e4..00000000 --- a/apps/server/src/shared/@foundry/indexing/ulid/ulid.ts +++ /dev/null @@ -1,26 +0,0 @@ -import * as t from 'io-ts' -import _ulid from 'ulid' -import { InvalidValue } from '~foundry/exceptions/invalid-value.js' -import { IsUlid } from '~foundry/indexing/ulid/is-ulid.js' - - - -interface ULIDBrand { - readonly ULID: unique symbol -} - -const UlidCodec = t.brand(t.string, (s: string): s is t.Branded => new IsUlid().satisfy(s), 'ULID') - -/** - * Universally Unique Lexicographically Sortable Identifier (ULID) is a string identifier that combines randomness and time-based ordering. It is typically used in distributed systems and databases to generate unique identifiers that can be sorted in chronological order. ULIDs are compact, URL-safe, and suitable for applications that require uniqueness, sorting, and a human-readable format for IDs. - */ -export type ULID = t.TypeOf - -export function ulid(id?: string): ULID { - const validationResult = UlidCodec.decode(id || _ulid.ulid()) - if (validationResult._tag === 'Left') { - throw new InvalidValue('Invalid ULID') - } else { - return validationResult.right - } -} diff --git a/apps/server/src/shared/@foundry/indexing/unique-id.ts b/apps/server/src/shared/@foundry/indexing/unique-id.ts deleted file mode 100644 index b075d419..00000000 --- a/apps/server/src/shared/@foundry/indexing/unique-id.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NanoID } from '~foundry/indexing/nanoid/index.js' -import { ULID } from '~foundry/indexing/ulid/index.js' -import { CUID } from './cuid.js' -import { SequentialID } from './sequential-id/index.js' - -type Brand = T & { __brand: BrandName } -type UniqueIdBrand = 'UniqueIdBrand' - -export type UniqueId = Brand diff --git a/apps/server/src/shared/@foundry/persistence/criteria/criteria-filter.ts b/apps/server/src/shared/@foundry/persistence/criteria/criteria-filter.ts deleted file mode 100644 index 5b8f2295..00000000 --- a/apps/server/src/shared/@foundry/persistence/criteria/criteria-filter.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface CriteriaFilter { - property: keyof T - value: T[keyof T] -} diff --git a/apps/server/src/shared/@foundry/persistence/criteria/criteria.ts b/apps/server/src/shared/@foundry/persistence/criteria/criteria.ts deleted file mode 100644 index f5475341..00000000 --- a/apps/server/src/shared/@foundry/persistence/criteria/criteria.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { CriteriaFilter } from './criteria-filter' - - - -export interface Criteria { - filters?: CriteriaFilter[] - sort?: keyof T - limit?: number - offset?: number -} diff --git a/apps/server/src/shared/@foundry/persistence/mapper.ts b/apps/server/src/shared/@foundry/persistence/mapper.ts deleted file mode 100644 index 86777922..00000000 --- a/apps/server/src/shared/@foundry/persistence/mapper.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * The Mapper abstract class provides a foundation for mapping data between different representations or formats. - * It encapsulates the conversion logic and provides reusable methods for mapping operations. - */ -export abstract class Mapper { - /** - * Maps the input data to the desired output format. - * @param input The input data to be mapped. - * @returns The mapped output data. - */ - public abstract map(input: TInput): TOutput - - public abstract inverse(input: TOutput): Promise - - /** - * Maps an array of input data to an array of corresponding output data. - * @param inputs The array of input data to be mapped. - * @returns The array of mapped output data. - */ - public mapMultiple(inputs: TInput[]): TOutput[] { - return inputs.map(input => this.map(input)) - } -} diff --git a/apps/server/src/shared/@foundry/persistence/read-repository.ts b/apps/server/src/shared/@foundry/persistence/read-repository.ts deleted file mode 100644 index 4bc6f796..00000000 --- a/apps/server/src/shared/@foundry/persistence/read-repository.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Entity } from '../domain/enity' -import { UniqueId } from '../indexing/unique-id' - - - -/** - * The `QueryRepository` interface defines the methods required to retrieve entities from a read model. - * It provides an abstraction layer over the data persistence mechanism, allowing for flexibility in implementation. - */ -export abstract class QueryRepository { - /** - * Finds an entity in the read model by its unique identifier. - * @param id The unique identifier of the entity to be found. - * @returns A `Promise` that resolves with the found entity, or `null` if the entity was not found. - */ - public abstract findById(id: UniqueId): Promise - - /** - * Finds all entities in the read model. - * @returns A `Promise` that resolves with an array of all entities in the read model. - */ - public abstract findAll(): Promise -} diff --git a/apps/server/src/shared/@foundry/persistence/unit-of-work.ts b/apps/server/src/shared/@foundry/persistence/unit-of-work.ts deleted file mode 100644 index 3b570de8..00000000 --- a/apps/server/src/shared/@foundry/persistence/unit-of-work.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Unit of Work is a design pattern that helps ensure data consistency when working with multiple - * repositories in a single transaction. It provides methods for committing or rolling back a transaction - * that affects multiple repositories. - * - * A Unit of Work abstract class should define methods for each repository that it manages. - */ -export abstract class UnitOfWork { - abstract withTransaction(work: () => Promise): Promise -} diff --git a/apps/server/src/shared/@foundry/persistence/write-repository.ts b/apps/server/src/shared/@foundry/persistence/write-repository.ts deleted file mode 100644 index c9952874..00000000 --- a/apps/server/src/shared/@foundry/persistence/write-repository.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Entity } from '../domain/enity' -import { UniqueId } from '../indexing/unique-id' - - - -/** - * The `WriteRepository` interface defines the methods required to store and retrieve entities in a write model. - * It provides an abstraction layer over the data persistence mechanism, allowing for flexibility in implementation. - */ -export abstract class WriteRepository { - /** - * Saves an entity to the write model. - * @param entity The entity to be saved. - * @returns A `Promise` that resolves with the saved entity. - */ - public abstract save(aggregate: T): Promise - - /** - * Deletes an entity from the write model. - * @param id The unique identifier of the entity to be deleted. - * @returns A `Promise` that resolves with a boolean indicating whether the entity was successfully deleted. - */ - public abstract delete(id: UniqueId): Promise -} diff --git a/apps/server/src/shared/@foundry/technical/action-specification.ts b/apps/server/src/shared/@foundry/technical/action-specification.ts deleted file mode 100644 index ca46b65b..00000000 --- a/apps/server/src/shared/@foundry/technical/action-specification.ts +++ /dev/null @@ -1,3 +0,0 @@ -export abstract class ActionSpecification { - abstract satisfy(i: T): Promise -} diff --git a/apps/server/src/shared/@foundry/technical/class-constructor.ts b/apps/server/src/shared/@foundry/technical/class-constructor.ts deleted file mode 100644 index 0b2c893a..00000000 --- a/apps/server/src/shared/@foundry/technical/class-constructor.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Message } from '../messaging/message.js' - - - -export type ClassConstructor = new (...args : any[]) => T; -export type MessageConstructor> = ClassConstructor & { type : string }; diff --git a/apps/server/src/shared/@foundry/technical/result.ts b/apps/server/src/shared/@foundry/technical/result.ts deleted file mode 100644 index 3f6df54b..00000000 --- a/apps/server/src/shared/@foundry/technical/result.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as E from 'fp-ts/lib/Either.js' - - - -export type Result = E.Either - -export function left(payload: T): E.Either { - return E.left(payload) -} - -export function right(payload: T): E.Either { - return E.right(payload) -} diff --git a/apps/server/src/shared/@foundry/technical/specification.ts b/apps/server/src/shared/@foundry/technical/specification.ts deleted file mode 100644 index a248157f..00000000 --- a/apps/server/src/shared/@foundry/technical/specification.ts +++ /dev/null @@ -1,3 +0,0 @@ -export abstract class Specification { - abstract satisfy(i: T): boolean -} diff --git a/apps/server/src/shared/common/duration.ts b/apps/server/src/shared/common/duration.ts deleted file mode 100644 index 0f1c0fae..00000000 --- a/apps/server/src/shared/common/duration.ts +++ /dev/null @@ -1 +0,0 @@ -export type Duration = Number diff --git a/apps/server/src/shared/common/pretty-good-privacy.ts b/apps/server/src/shared/common/pretty-good-privacy.ts deleted file mode 100644 index 28078d22..00000000 --- a/apps/server/src/shared/common/pretty-good-privacy.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as openpgp from 'openpgp' - - - -export namespace PrettyGoodPrivacy { - export async function validatePublicKey(publicKey: string) { - try { - // Parse the PGP public key - await openpgp.readKey({ - armoredKey: publicKey.trim() - }) - - return true - } catch (error) { - console.error('Error validating PGP public key:', error) - return false - } - } - - // export function encryptMessageForPublicKeys(message: string, publicKeys: string[]): string { - // return '' - // } - // - // export function decryptMessageWithPrivateKey(message: string, privateKey: string): string { - // return '' - // } -} diff --git a/apps/server/src/shared/configuration/environment-variables.ts b/apps/server/src/shared/configuration/environment-variables.ts deleted file mode 100644 index 1d853523..00000000 --- a/apps/server/src/shared/configuration/environment-variables.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { cleanEnv, host, port, str } from 'envalid' -import { nanoid } from 'nanoid' - - - -const env = cleanEnv(process.env, { - NODE_ENV: str({ - default: 'development', - choices: ['development', 'production'] - }), - PROTOCOL: str({ - default: 'http' - }), - HOST: host({ - default: 'localhost' - }), - PORT: port({ - default: 3000 - }), - JWT_SECRET: str({ - devDefault: nanoid(512) - }) -}) - -export const NODE_ENV = env.NODE_ENV -export const HOST = env.HOST -export const PORT = env.PORT -export const PROTOCOL = env.PROTOCOL -export const JWT_SECRET = env.JWT_SECRET diff --git a/apps/server/src/shared/infrastructure/memphis.ts b/apps/server/src/shared/infrastructure/memphis.ts deleted file mode 100644 index 8c6a6c45..00000000 --- a/apps/server/src/shared/infrastructure/memphis.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Memphis, memphis } from 'memphis-dev' -import { Connection } from '~foundry/base/conncetion' - -export class MemphisConnection extends Connection { - public async connect(): Promise { - this.connection.connect({ - host: 'localhost', - username: 'root', - password: 'memphis' - }) - } - - public async disconnect(): Promise { - this.connection.close() - } - - static async createConnection() { - const connection = await memphis.connect({ - host: 'localhost', - username: 'root', - password: 'memphis' - }) - - new MemphisConnection(connection) - } -} diff --git a/apps/server/src/shared/infrastructure/prisma/prisma.ts b/apps/server/src/shared/infrastructure/prisma/prisma.ts deleted file mode 100644 index 9864e30a..00000000 --- a/apps/server/src/shared/infrastructure/prisma/prisma.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Prisma, PrismaClient } from '@prisma/client' - - - -export class PrismaService extends PrismaClient { - constructor() { - super({ - log: [ - { - emit: 'stdout', - level: 'query' - }, - { - emit: 'stdout', - level: 'error' - }, - { - emit: 'stdout', - level: 'info' - }, - { - emit: 'stdout', - level: 'warn' - } - ] - }) - this.$connect() - } -} - -export const prisma = new PrismaService() diff --git a/apps/server/src/shared/module.ts b/apps/server/src/shared/module.ts deleted file mode 100644 index 85f7e537..00000000 --- a/apps/server/src/shared/module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import diod, { ContainerBuilder } from "diod" - -/** - * This class tries to copy app.module.ts from Nest.js, but based on diod - */ -export abstract class DependencyInjectionModule { - public readonly containerBuilder: diod.ContainerBuilder - - constructor(builder: ContainerBuilder) { - this.containerBuilder = builder - } - - abstract register(): void -} diff --git a/apps/server/src/shared/utils/kebab-space.ts b/apps/server/src/shared/utils/kebab-space.ts deleted file mode 100644 index ac4b84c2..00000000 --- a/apps/server/src/shared/utils/kebab-space.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function kebabSpace(str: string) { - return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() -} diff --git a/apps/server/tsconfig.json b/apps/server/tsconfig.json deleted file mode 100644 index c1780566..00000000 --- a/apps/server/tsconfig.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "compilerOptions": { - "moduleResolution": "node", - "module": "NodeNext", - "target": "esnext", - "lib": [ - "esnext" - ], - "strict": true, - "composite": false, - "exactOptionalPropertyTypes": true, - "incremental": true, - "importHelpers": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "resolveJsonModule": true, - "allowJs": false, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "noImplicitAny": true, - "strictNullChecks": true, - "noImplicitThis": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noUncheckedIndexedAccess": true, - "skipLibCheck": true, - "sourceMap": true, - "inlineSources": true, - "inlineSourceMap": false, - "declaration": true, - "tsBuildInfoFile": ".tsbuildinfo", - "outDir": "dist", - "baseUrl": ".", - "paths": { - "~foundry/*": [ - "./src/shared/@foundry/*" - ], - "~foundry/cqrs": [ - "./src/shared/@foundry/cqrs" - ], - "~foundry/domain": [ - "./src/shared/@foundry/domain" - ], - "~components/*": [ - "./src/shared/@components/*" - ], - "~domain/iam/*": [ - "./src/modules/identity-and-access-mangement/*" - ] - } - }, - "ts-node": { - "swc": true, - "pretty": true - }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules", - "../../node_modules" - ] -} diff --git a/apps/server/tsoa.json b/apps/server/tsoa.json deleted file mode 100644 index 890f7f00..00000000 --- a/apps/server/tsoa.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "entryFile": "src/index.ts", - "noImplicitAdditionalProperties": "throw-on-extras", - "controllerPathGlobs": [ - "**/src/interfaces/http/routes/**/*.ts" - ], - "spec": { - "outputDirectory": "docs", - "specVersion": 3, - "securityDefinitions": { - "Bearer": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } - }, - "tags": [ - { - "name": "Account", - "description": "Operations related to account", - "externalDocs": { - "description": "...", - "url": "http://swagger.io" - } - } - ], - "security": [ - { - "Bearer": [] - } - ] - }, - "routes": { - "basePath": "/", - "entryFile": "src/index.ts", - "routesDir": "dist/routes", - "esm": true - } -} diff --git a/apps/server/tsup.config.js b/apps/server/tsup.config.js deleted file mode 100644 index ef683a82..00000000 --- a/apps/server/tsup.config.js +++ /dev/null @@ -1,18 +0,0 @@ -export default { - entry: ['src/index.ts'], - silent: true, - splitting: true, - target: 'node19', - sourcemap: true, - dts: true, - minify: false, - format: ['esm'], - clean: false, - treeshake: true, - metafile: true, - shims: true, - loader: { - '.md': 'file' - }, - plugins: [] -} diff --git a/apps/web/.eslintrc.json b/apps/web/.eslintrc.json deleted file mode 100644 index 0ba73ae6..00000000 --- a/apps/web/.eslintrc.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/eslintrc", - "root": true, - "extends": [ - "next/core-web-vitals", - "prettier", - "plugin:tailwindcss/recommended" - ], - "plugins": ["tailwindcss"], - "rules": { - "@next/next/no-html-link-for-pages": "off", - "react/jsx-key": "off", - "tailwindcss/no-custom-classname": "off", - "tailwindcss/classnames-order": "error" - }, - "settings": { - "tailwindcss": { - "callees": ["cn"], - "config": "tailwind.config.js" - }, - "next": { - "rootDir": true - } - }, - "overrides": [ - { - "files": ["*.ts", "*.tsx"], - "parser": "@typescript-eslint/parser" - } - ] -} diff --git a/apps/web/.gitignore b/apps/web/.gitignore deleted file mode 100644 index c87c9b39..00000000 --- a/apps/web/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# local env files -.env*.local - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/apps/web/.prettierignore b/apps/web/.prettierignore deleted file mode 100644 index db441f77..00000000 --- a/apps/web/.prettierignore +++ /dev/null @@ -1,5 +0,0 @@ -dist -node_modules -.next -build -.contentlayer diff --git a/apps/web/.vscode/settings.json b/apps/web/.vscode/settings.json deleted file mode 100644 index 4824881b..00000000 --- a/apps/web/.vscode/settings.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "typescript.tsdk": "node_modules/typescript/lib", - "typescript.enablePromptUseWorkspaceTsdk": true -} diff --git a/apps/web/README.md b/apps/web/README.md deleted file mode 100644 index 5bc7ca24..00000000 --- a/apps/web/README.md +++ /dev/null @@ -1,38 +0,0 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. - -The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. - -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/apps/web/contentlayer.config.js b/apps/web/contentlayer.config.js deleted file mode 100644 index 281f05a9..00000000 --- a/apps/web/contentlayer.config.js +++ /dev/null @@ -1,181 +0,0 @@ -import { defineDocumentType, makeSource } from "contentlayer/source-files" -import rehypeAutolinkHeadings from "rehype-autolink-headings" -import rehypePrettyCode from "rehype-pretty-code" -import rehypeSlug from "rehype-slug" -import remarkGfm from "remark-gfm" - -/** @type {import('contentlayer/source-files').ComputedFields} */ -const computedFields = { - slug: { - type: "string", - resolve: (doc) => `/${doc._raw.flattenedPath}`, - }, - slugAsParams: { - type: "string", - resolve: (doc) => doc._raw.flattenedPath.split("/").slice(1).join("/"), - }, -} - -export const Doc = defineDocumentType(() => ({ - name: "Doc", - filePathPattern: `docs/**/*.mdx`, - contentType: "mdx", - fields: { - title: { - type: "string", - required: true, - }, - description: { - type: "string", - }, - published: { - type: "boolean", - default: true, - }, - }, - computedFields, -})) - -export const Guide = defineDocumentType(() => ({ - name: "Guide", - filePathPattern: `guides/**/*.mdx`, - contentType: "mdx", - fields: { - title: { - type: "string", - required: true, - }, - description: { - type: "string", - }, - date: { - type: "date", - required: true, - }, - published: { - type: "boolean", - default: true, - }, - featured: { - type: "boolean", - default: false, - }, - }, - computedFields, -})) - -export const Post = defineDocumentType(() => ({ - name: "Post", - filePathPattern: `blog/**/*.mdx`, - contentType: "mdx", - fields: { - title: { - type: "string", - required: true, - }, - description: { - type: "string", - }, - date: { - type: "date", - required: true, - }, - published: { - type: "boolean", - default: true, - }, - image: { - type: "string", - required: true, - }, - authors: { - // Reference types are not embedded. - // Until this is fixed, we can use a simple list. - // type: "reference", - // of: Author, - type: "list", - of: { type: "string" }, - required: true, - }, - }, - computedFields, -})) - -export const Author = defineDocumentType(() => ({ - name: "Author", - filePathPattern: `authors/**/*.mdx`, - contentType: "mdx", - fields: { - title: { - type: "string", - required: true, - }, - description: { - type: "string", - }, - avatar: { - type: "string", - required: true, - }, - twitter: { - type: "string", - required: true, - }, - }, - computedFields, -})) - -export const Page = defineDocumentType(() => ({ - name: "Page", - filePathPattern: `pages/**/*.mdx`, - contentType: "mdx", - fields: { - title: { - type: "string", - required: true, - }, - description: { - type: "string", - }, - }, - computedFields, -})) - -export default makeSource({ - contentDirPath: "./content", - documentTypes: [Page, Doc, Guide, Post, Author], - mdx: { - remarkPlugins: [remarkGfm], - rehypePlugins: [ - rehypeSlug, - [ - rehypePrettyCode, - { - theme: "github-dark", - onVisitLine(node) { - // Prevent lines from collapsing in `display: grid` mode, and allow empty - // lines to be copy/pasted - if (node.children.length === 0) { - node.children = [{ type: "text", value: " " }] - } - }, - onVisitHighlightedLine(node) { - node.properties.className.push("line--highlighted") - }, - onVisitHighlightedWord(node) { - node.properties.className = ["word--highlighted"] - }, - }, - ], - [ - rehypeAutolinkHeadings, - { - properties: { - className: ["subheading-anchor"], - ariaLabel: "Link to section", - }, - }, - ], - ], - }, -}) diff --git a/apps/web/next.config.js b/apps/web/next.config.js deleted file mode 100644 index 1edf599c..00000000 --- a/apps/web/next.config.js +++ /dev/null @@ -1,8 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = { - experimental: { - appDir: true - } -} - -module.exports = nextConfig diff --git a/apps/web/package.json b/apps/web/package.json deleted file mode 100644 index 36dd7185..00000000 --- a/apps/web/package.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "name": "web", - "version": "0.1.0", - "private": true, - "scripts": { - "build": "next build", - "dev": "next dev", - "dev:fast": "next dev", - "lint": "next lint", - "start": "next start" - }, - "dependencies": { - "@editorjs/code": "^2.8.0", - "@editorjs/editorjs": "^2.26.5", - "@editorjs/embed": "^2.5.3", - "@editorjs/header": "^2.7.0", - "@editorjs/inline-code": "^1.4.0", - "@editorjs/link": "^2.5.0", - "@editorjs/list": "^1.8.0", - "@editorjs/paragraph": "^2.9.0", - "@editorjs/table": "^2.2.1", - "@hookform/resolvers": "^3.1.0", - "@next-auth/prisma-adapter": "^1.0.6", - "@prisma/client": "^4.13.0", - "@radix-ui/react-accessible-icon": "^1.0.2", - "@radix-ui/react-accordion": "^1.1.1", - "@radix-ui/react-alert-dialog": "^1.0.3", - "@radix-ui/react-aspect-ratio": "^1.0.2", - "@radix-ui/react-avatar": "^1.0.2", - "@radix-ui/react-checkbox": "^1.0.3", - "@radix-ui/react-collapsible": "^1.0.2", - "@radix-ui/react-context-menu": "^2.1.3", - "@radix-ui/react-dialog": "^1.0.3", - "@radix-ui/react-dropdown-menu": "^2.0.4", - "@radix-ui/react-hover-card": "^1.0.5", - "@radix-ui/react-label": "^2.0.1", - "@radix-ui/react-menubar": "^1.0.2", - "@radix-ui/react-navigation-menu": "^1.1.2", - "@radix-ui/react-popover": "^1.0.5", - "@radix-ui/react-progress": "^1.0.2", - "@radix-ui/react-radio-group": "^1.1.2", - "@radix-ui/react-scroll-area": "^1.0.3", - "@radix-ui/react-select": "^1.2.1", - "@radix-ui/react-separator": "^1.0.2", - "@radix-ui/react-slider": "^1.1.1", - "@radix-ui/react-slot": "^1.0.1", - "@radix-ui/react-switch": "^1.0.2", - "@radix-ui/react-tabs": "^1.0.3", - "@radix-ui/react-toast": "^1.1.3", - "@radix-ui/react-toggle": "^1.0.2", - "@radix-ui/react-toggle-group": "^1.0.3", - "@radix-ui/react-tooltip": "^1.0.5", - "@t3-oss/env-nextjs": "^0.2.2", - "@typescript-eslint/parser": "^5.59.0", - "@vercel/analytics": "^1.0.0", - "@vercel/og": "^0.0.21", - "class-variance-authority": "^0.4.0", - "clsx": "^1.2.1", - "cmdk": "^0.1.22", - "concurrently": "^8.0.1", - "contentlayer": "^0.3.1", - "date-fns": "^2.29.3", - "lucide-react": "^0.92.0", - "next": "13.3.2-canary.13", - "next-auth": "4.22.1", - "next-contentlayer": "^0.3.1", - "next-themes": "^0.2.1", - "nodemailer": "^6.9.1", - "postmark": "^3.0.15", - "prop-types": "^15.8.1", - "react": "^18.2.0", - "react-day-picker": "^8.7.1", - "react-dom": "^18.2.0", - "react-editor-js": "^2.1.0", - "react-hook-form": "^7.43.9", - "react-textarea-autosize": "^8.4.1", - "sharp": "^0.31.3", - "shiki": "^0.11.1", - "stripe": "^11.18.0", - "tailwind-merge": "^1.12.0", - "tailwindcss-animate": "^1.0.5", - "zod": "^3.21.4" - }, - "devDependencies": { - "@commitlint/cli": "^17.6.1", - "@commitlint/config-conventional": "^17.6.1", - "@ianvs/prettier-plugin-sort-imports": "^3.7.2", - "@tailwindcss/line-clamp": "^0.4.4", - "@tailwindcss/typography": "^0.5.9", - "@types/node": "^18.16.0", - "@types/react": "18.0.15", - "@types/react-dom": "18.0.6", - "autoprefixer": "^10.4.14", - "eslint": "^8.39.0", - "eslint-config-next": "13.0.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-tailwindcss": "^3.11.0", - "husky": "^8.0.3", - "mdast-util-toc": "^6.1.1", - "postcss": "^8.4.23", - "prettier": "^2.8.8", - "prettier-plugin-tailwindcss": "^0.1.13", - "pretty-quick": "^3.1.3", - "prisma": "^4.13.0", - "rehype": "^12.0.1", - "rehype-autolink-headings": "^6.1.1", - "rehype-pretty-code": "^0.9.5", - "rehype-slug": "^5.1.0", - "remark": "^14.0.2", - "remark-gfm": "^3.0.1", - "tailwindcss": "^3.3.1", - "typescript": "4.7.4", - "unist-util-visit": "^4.1.2" - } -} diff --git a/apps/web/postcss.config.js b/apps/web/postcss.config.js deleted file mode 100644 index 33ad091d..00000000 --- a/apps/web/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/apps/web/prettier.config.js b/apps/web/prettier.config.js deleted file mode 100644 index c72df582..00000000 --- a/apps/web/prettier.config.js +++ /dev/null @@ -1,33 +0,0 @@ -/** @type {import('prettier').Config} */ -module.exports = { - endOfLine: "lf", - semi: false, - singleQuote: false, - tabWidth: 2, - trailingComma: "es5", - importOrder: [ - "^(react/(.*)$)|^(react$)", - "^(next/(.*)$)|^(next$)", - "", - "", - "^types$", - "^@/env(.*)$", - "^@/types/(.*)$", - "^@/config/(.*)$", - "^@/lib/(.*)$", - "^@/hooks/(.*)$", - "^@/components/ui/(.*)$", - "^@/components/(.*)$", - "^@/styles/(.*)$", - "^@/app/(.*)$", - "", - "^[./]", - ], - importOrderSeparation: false, - importOrderSortSpecifiers: true, - importOrderBuiltinModulesToTop: true, - importOrderParserPlugins: ["typescript", "jsx", "decorators-legacy"], - importOrderMergeDuplicateImports: true, - importOrderCombineTypeAndValueImports: true, - plugins: ["@ianvs/prettier-plugin-sort-imports"], -} diff --git a/apps/web/public/favicon.ico b/apps/web/public/favicon.ico deleted file mode 100644 index 718d6fea..00000000 Binary files a/apps/web/public/favicon.ico and /dev/null differ diff --git a/apps/web/public/next.svg b/apps/web/public/next.svg deleted file mode 100644 index 5174b28c..00000000 --- a/apps/web/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/thirteen.svg b/apps/web/public/thirteen.svg deleted file mode 100644 index 8977c1bd..00000000 --- a/apps/web/public/thirteen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/public/vercel.svg b/apps/web/public/vercel.svg deleted file mode 100644 index d2f84222..00000000 --- a/apps/web/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/web/src/app/(marketing)/layout.tsx b/apps/web/src/app/(marketing)/layout.tsx deleted file mode 100644 index 902099c5..00000000 --- a/apps/web/src/app/(marketing)/layout.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import Link from "next/link" - -import { marketingConfig } from "@/config/marketing" -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" -import { MainNav } from "@/components/main-nav" -import { SiteFooter } from "@/components/site-footer" - -interface MarketingLayoutProps { - children: React.ReactNode -} - -export default async function MarketingLayout({ - children, -}: MarketingLayoutProps) { - return ( -
-
-
- - -
-
-
{children}
- -
- ) -} diff --git a/apps/web/src/app/(marketing)/page.tsx b/apps/web/src/app/(marketing)/page.tsx deleted file mode 100644 index ee77aeeb..00000000 --- a/apps/web/src/app/(marketing)/page.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import Link from "next/link" - -import { env } from "@/env.mjs" -import { siteConfig } from "@/config/site" -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" - -export default async function IndexPage() { - return ( - <> -
-
- - Follow along on Twitter - -

- An example app built using Next.js 13 server components. -

-

- I'm building a web app with Next.js 13 and open sourcing - everything. Follow along as we figure this out together. -

-
- - Get Started - - - GitHub - -
-
-
-
-
-

- Features -

-

- This project is an experiment to see how a modern app, with features - like auth, subscriptions, API routes, and static pages would work in - Next.js 13 app dir. -

-
-
-
-
- - - -
-

Next.js 13

-

- App dir, Routing, Layouts, Loading UI and API routes. -

-
-
-
-
-
- - - -
-

React 18

-

- Server and Client Components. Use hook. -

-
-
-
-
-
- - - -
-

Database

-

- ORM using Prisma and deployed on PlanetScale. -

-
-
-
-
-
- - - -
-

Components

-

- UI components built using Radix UI and styled with Tailwind - CSS. -

-
-
-
-
-
- - - -
-

Authentication

-

- Authentication using NextAuth.js and middlewares. -

-
-
-
-
-
- - - -
-

Subscriptions

-

- Free and paid subscriptions using Stripe. -

-
-
-
-
-
-

- Taxonomy also includes a blog and a full-featured documentation site - built using Contentlayer and MDX. -

-
-
-
-
-

- Proudly Open Source -

-

- Taxonomy is open source and powered by open source software.
{" "} - The code is available on{" "} - - GitHub - - .{" "} -

-
-
- - ) -} diff --git a/apps/web/src/app/(marketing)/pricing/page.tsx b/apps/web/src/app/(marketing)/pricing/page.tsx deleted file mode 100644 index 15285345..00000000 --- a/apps/web/src/app/(marketing)/pricing/page.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import Link from "next/link" - -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" -import { Icons } from "@/components/icons" - -export const metadata = { - title: "Pricing", -} - -export default function PricingPage() { - return ( -
-
-

- Simple, transparent pricing -

-

- Unlock all features including unlimited posts for your blog. -

-
-
-
-

- What's included in the PRO plan -

-
    -
  • - Unlimited Posts -
  • -
  • - Unlimited Users -
  • - -
  • - Custom domain -
  • -
  • - Dashboard Analytics -
  • -
  • - Access to Discord -
  • -
  • - Premium Support -
  • -
-
-
-
-

$19

-

- Billed Monthly -

-
- - Get Started - -
-
-
-

- Taxonomy is a demo app.{" "} - You can test the upgrade and won't be charged. -

-
-
- ) -} diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx deleted file mode 100644 index 9ba740fe..00000000 --- a/apps/web/src/app/layout.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { Inter as FontSans } from "next/font/google" -import localFont from "next/font/local" - -import "@/styles/globals.css" -import { siteConfig } from "@/config/site" -import { absoluteUrl, cn } from "@/lib/utils" -import { Toaster } from "@/components/ui/toaster" -import { Analytics } from "@/components/analytics" -import { TailwindIndicator } from "@/components/tailwind-indicator" -import { ThemeProvider } from "@/components/theme-provider" - -const fontSans = FontSans({ - subsets: ["latin"], - variable: "--font-sans", -}) - -// Font files can be colocated inside of `pages` -const fontHeading = localFont({ - src: "../assets/fonts/CalSans-SemiBold.woff2", - variable: "--font-heading", -}) - -interface RootLayoutProps { - children: React.ReactNode -} - -export const metadata = { - title: { - default: siteConfig.name, - template: `%s | ${siteConfig.name}`, - }, - description: siteConfig.description, - keywords: [ - "Next.js", - "React", - "Tailwind CSS", - "Server Components", - "Radix UI", - ], - authors: [ - { - name: "shadcn", - url: "https://shadcn.com", - }, - ], - creator: "shadcn", - themeColor: [ - { media: "(prefers-color-scheme: light)", color: "white" }, - { media: "(prefers-color-scheme: dark)", color: "black" }, - ], - openGraph: { - type: "website", - locale: "en_US", - url: siteConfig.url, - title: siteConfig.name, - description: siteConfig.description, - siteName: siteConfig.name, - }, - twitter: { - card: "summary_large_image", - title: siteConfig.name, - description: siteConfig.description, - images: [`${siteConfig.url}/og.jpg`], - creator: "@shadcn", - }, - icons: { - icon: "/favicon.ico", - shortcut: "/favicon-16x16.png", - apple: "/apple-touch-icon.png", - }, - manifest: `${siteConfig.url}/site.webmanifest`, -} - -export default function RootLayout({ children }: RootLayoutProps) { - return ( - - - - - {children} - - - - - - - ) -} diff --git a/apps/web/src/app/opengraph-image.jpg b/apps/web/src/app/opengraph-image.jpg deleted file mode 100644 index 75473bf8..00000000 Binary files a/apps/web/src/app/opengraph-image.jpg and /dev/null differ diff --git a/apps/web/src/app/robots.ts b/apps/web/src/app/robots.ts deleted file mode 100644 index f86f1678..00000000 --- a/apps/web/src/app/robots.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { MetadataRoute } from "next" - -export default function robots(): MetadataRoute.Robots { - return { - rules: { - userAgent: "*", - allow: "/", - }, - } -} diff --git a/apps/web/src/assets/fonts/CalSans-SemiBold.ttf b/apps/web/src/assets/fonts/CalSans-SemiBold.ttf deleted file mode 100644 index 4a2950a0..00000000 Binary files a/apps/web/src/assets/fonts/CalSans-SemiBold.ttf and /dev/null differ diff --git a/apps/web/src/assets/fonts/CalSans-SemiBold.woff b/apps/web/src/assets/fonts/CalSans-SemiBold.woff deleted file mode 100644 index da459913..00000000 Binary files a/apps/web/src/assets/fonts/CalSans-SemiBold.woff and /dev/null differ diff --git a/apps/web/src/assets/fonts/CalSans-SemiBold.woff2 b/apps/web/src/assets/fonts/CalSans-SemiBold.woff2 deleted file mode 100644 index 36d71b70..00000000 Binary files a/apps/web/src/assets/fonts/CalSans-SemiBold.woff2 and /dev/null differ diff --git a/apps/web/src/assets/fonts/Inter-Bold.ttf b/apps/web/src/assets/fonts/Inter-Bold.ttf deleted file mode 100644 index 8e82c70d..00000000 Binary files a/apps/web/src/assets/fonts/Inter-Bold.ttf and /dev/null differ diff --git a/apps/web/src/assets/fonts/Inter-Regular.ttf b/apps/web/src/assets/fonts/Inter-Regular.ttf deleted file mode 100644 index 8d4eebf2..00000000 Binary files a/apps/web/src/assets/fonts/Inter-Regular.ttf and /dev/null differ diff --git a/apps/web/src/components/analytics.tsx b/apps/web/src/components/analytics.tsx deleted file mode 100644 index 164e9b79..00000000 --- a/apps/web/src/components/analytics.tsx +++ /dev/null @@ -1,7 +0,0 @@ -"use client" - -import { Analytics as VercelAnalytics } from "@vercel/analytics/react" - -export function Analytics() { - return -} diff --git a/apps/web/src/components/billing-form.tsx b/apps/web/src/components/billing-form.tsx deleted file mode 100644 index e6e6f62f..00000000 --- a/apps/web/src/components/billing-form.tsx +++ /dev/null @@ -1,90 +0,0 @@ -"use client" - -import * as React from "react" - -import { UserSubscriptionPlan } from "@/types/index.js" -import { cn, formatDate } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card" -import { toast } from "@/components/ui/use-toast" -import { Icons } from "@/components/icons" - -interface BillingFormProps extends React.HTMLAttributes { - subscriptionPlan: UserSubscriptionPlan & { - isCanceled: boolean - } -} - -export function BillingForm({ - subscriptionPlan, - className, - ...props -}: BillingFormProps) { - const [isLoading, setIsLoading] = React.useState(false) - - async function onSubmit(event) { - event.preventDefault() - setIsLoading(!isLoading) - - // Get a Stripe session URL. - const response = await fetch("/api/users/stripe") - - if (!response?.ok) { - return toast({ - title: "Something went wrong.", - description: "Please refresh the page and try again.", - variant: "destructive", - }) - } - - // Redirect to the Stripe session. - // This could be a checkout page for initial upgrade. - // Or portal to manage existing subscription. - const session = await response.json() - if (session) { - window.location.href = session.url - } - } - - return ( -
- - - Subscription Plan - - You are currently on the {subscriptionPlan.name}{" "} - plan. - - - {subscriptionPlan.description} - - - {subscriptionPlan.isPro ? ( -

- {subscriptionPlan.isCanceled - ? "Your plan will be canceled on " - : "Your plan renews on "} - {formatDate(subscriptionPlan.stripeCurrentPeriodEnd)}. -

- ) : null} -
-
-
- ) -} diff --git a/apps/web/src/components/callout.tsx b/apps/web/src/components/callout.tsx deleted file mode 100644 index 7b3b60a8..00000000 --- a/apps/web/src/components/callout.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { cn } from "@/lib/utils" - -interface CalloutProps { - icon?: string - children?: React.ReactNode - type?: "default" | "warning" | "danger" -} - -export function Callout({ - children, - icon, - type = "default", - ...props -}: CalloutProps) { - return ( -
- {icon && {icon}} -
{children}
-
- ) -} diff --git a/apps/web/src/components/card-skeleton.tsx b/apps/web/src/components/card-skeleton.tsx deleted file mode 100644 index e945cc05..00000000 --- a/apps/web/src/components/card-skeleton.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card" -import { Skeleton } from "@/components/ui/skeleton" - -export function CardSkeleton() { - return ( - - - - - - - - - - - ) -} diff --git a/apps/web/src/components/empty-placeholder.tsx b/apps/web/src/components/empty-placeholder.tsx deleted file mode 100644 index 717d44bb..00000000 --- a/apps/web/src/components/empty-placeholder.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" -import { Icons } from "@/components/icons" - -interface EmptyPlaceholderProps extends React.HTMLAttributes {} - -export function EmptyPlaceholder({ - className, - children, - ...props -}: EmptyPlaceholderProps) { - return ( -
-
- {children} -
-
- ) -} - -interface EmptyPlaceholderIconProps - extends Partial> { - name: keyof typeof Icons -} - -EmptyPlaceholder.Icon = function EmptyPlaceHolderIcon({ - name, - className, - ...props -}: EmptyPlaceholderIconProps) { - const Icon = Icons[name] - - if (!Icon) { - return null - } - - return ( -
- -
- ) -} - -interface EmptyPlacholderTitleProps - extends React.HTMLAttributes {} - -EmptyPlaceholder.Title = function EmptyPlaceholderTitle({ - className, - ...props -}: EmptyPlacholderTitleProps) { - return ( -

- ) -} - -interface EmptyPlacholderDescriptionProps - extends React.HTMLAttributes {} - -EmptyPlaceholder.Description = function EmptyPlaceholderDescription({ - className, - ...props -}: EmptyPlacholderDescriptionProps) { - return ( -

- ) -} diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx deleted file mode 100644 index e8d1a436..00000000 --- a/apps/web/src/components/header.tsx +++ /dev/null @@ -1,21 +0,0 @@ -interface DashboardHeaderProps { - heading: string - text?: string - children?: React.ReactNode -} - -export function DashboardHeader({ - heading, - text, - children, -}: DashboardHeaderProps) { - return ( -

-
-

{heading}

- {text &&

{text}

} -
- {children} -
- ) -} diff --git a/apps/web/src/components/icons.tsx b/apps/web/src/components/icons.tsx deleted file mode 100644 index 37c1651c..00000000 --- a/apps/web/src/components/icons.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { - AlertTriangle, - ArrowRight, - Check, - ChevronLeft, - ChevronRight, - Command, - CreditCard, - File, - FileText, - HelpCircle, - Image, - Laptop, - Loader2, - LucideProps, - Moon, - MoreVertical, - Pizza, - Plus, - Settings, - SunMedium, - Trash, - Twitter, - User, - X, - type Icon as LucideIcon, -} from "lucide-react" - -export type Icon = LucideIcon - -export const Icons = { - logo: Command, - close: X, - spinner: Loader2, - chevronLeft: ChevronLeft, - chevronRight: ChevronRight, - trash: Trash, - post: FileText, - page: File, - media: Image, - settings: Settings, - billing: CreditCard, - ellipsis: MoreVertical, - add: Plus, - warning: AlertTriangle, - user: User, - arrowRight: ArrowRight, - help: HelpCircle, - pizza: Pizza, - sun: SunMedium, - moon: Moon, - laptop: Laptop, - gitHub: ({ ...props }: LucideProps) => ( - - ), - twitter: Twitter, - check: Check, -} diff --git a/apps/web/src/components/main-nav.tsx b/apps/web/src/components/main-nav.tsx deleted file mode 100644 index 949f3642..00000000 --- a/apps/web/src/components/main-nav.tsx +++ /dev/null @@ -1,61 +0,0 @@ -"use client" - -import * as React from "react" -import Link from "next/link" -import { useSelectedLayoutSegment } from "next/navigation" -import { MainNavItem } from "@/types" - -import { siteConfig } from "@/config/site" -import { cn } from "@/lib/utils" -import { Icons } from "@/components/icons" -import { MobileNav } from "@/components/mobile-nav" - -interface MainNavProps { - items?: MainNavItem[] - children?: React.ReactNode -} - -export function MainNav({ items, children }: MainNavProps) { - const segment = useSelectedLayoutSegment() - const [showMobileMenu, setShowMobileMenu] = React.useState(false) - - return ( -
- - - - {siteConfig.name} - - - {items?.length ? ( - - ) : null} - - {showMobileMenu && items && ( - {children} - )} -
- ) -} diff --git a/apps/web/src/components/mdx-card.tsx b/apps/web/src/components/mdx-card.tsx deleted file mode 100644 index c1295957..00000000 --- a/apps/web/src/components/mdx-card.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import Link from "next/link" - -import { cn } from "@/lib/utils" - -interface CardProps extends React.HTMLAttributes { - href?: string - disabled?: boolean -} - -export function MdxCard({ - href, - className, - children, - disabled, - ...props -}: CardProps) { - return ( -
-
-
- {children} -
-
- {href && ( - - View - - )} -
- ) -} diff --git a/apps/web/src/components/mdx-components.tsx b/apps/web/src/components/mdx-components.tsx deleted file mode 100644 index 35d6d362..00000000 --- a/apps/web/src/components/mdx-components.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import * as React from "react" -import Image from "next/image" -import { useMDXComponent } from "next-contentlayer/hooks" - -import { cn } from "@/lib/utils" -import { Callout } from "@/components/callout" -import { MdxCard } from "@/components/mdx-card" - -const components = { - h1: ({ className, ...props }) => ( -

- ), - h2: ({ className, ...props }) => ( -

- ), - h3: ({ className, ...props }) => ( -

- ), - h4: ({ className, ...props }) => ( -

- ), - h5: ({ className, ...props }) => ( -

- ), - h6: ({ className, ...props }) => ( -
- ), - a: ({ className, ...props }) => ( - - ), - p: ({ className, ...props }) => ( -

- ), - ul: ({ className, ...props }) => ( -

    - ), - ol: ({ className, ...props }) => ( -
      - ), - li: ({ className, ...props }) => ( -
    1. - ), - blockquote: ({ className, ...props }) => ( -
      *]:text-muted-foreground", - className - )} - {...props} - /> - ), - img: ({ - className, - alt, - ...props - }: React.ImgHTMLAttributes) => ( - // eslint-disable-next-line @next/next/no-img-element - {alt} - ), - hr: ({ ...props }) =>
      , - table: ({ className, ...props }: React.HTMLAttributes) => ( -
      - - - ), - tr: ({ className, ...props }: React.HTMLAttributes) => ( - - ), - th: ({ className, ...props }) => ( -
      - ), - td: ({ className, ...props }) => ( - - ), - pre: ({ className, ...props }) => ( -
      -  ),
      -  code: ({ className, ...props }) => (
      -    
      -  ),
      -  Image,
      -  Callout,
      -  Card: MdxCard,
      -}
      -
      -interface MdxProps {
      -  code: string
      -}
      -
      -export function Mdx({ code }: MdxProps) {
      -  const Component = useMDXComponent(code)
      -
      -  return (
      -    
      - -
      - ) -} diff --git a/apps/web/src/components/mobile-nav.tsx b/apps/web/src/components/mobile-nav.tsx deleted file mode 100644 index 5fd90bd8..00000000 --- a/apps/web/src/components/mobile-nav.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import * as React from "react" -import Link from "next/link" -import { MainNavItem } from "@/types" - -import { siteConfig } from "@/config/site" -import { cn } from "@/lib/utils" -import { useLockBody } from "@/hooks/use-lock-body" -import { Icons } from "@/components/icons" - -interface MobileNavProps { - items: MainNavItem[] - children?: React.ReactNode -} - -export function MobileNav({ items, children }: MobileNavProps) { - useLockBody() - - return ( -
      -
      - - - {siteConfig.name} - - - {children} -
      -
      - ) -} diff --git a/apps/web/src/components/mode-toggle.tsx b/apps/web/src/components/mode-toggle.tsx deleted file mode 100644 index 93654e83..00000000 --- a/apps/web/src/components/mode-toggle.tsx +++ /dev/null @@ -1,43 +0,0 @@ -"use client" - -import * as React from "react" -import { useTheme } from "next-themes" - -import { Button } from "@/components/ui/button" -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" -import { Icons } from "@/components/icons" - -export function ModeToggle() { - const { setTheme } = useTheme() - - return ( - - - - - - setTheme("light")}> - - Light - - setTheme("dark")}> - - Dark - - setTheme("system")}> - - System - - - - ) -} diff --git a/apps/web/src/components/nav.tsx b/apps/web/src/components/nav.tsx deleted file mode 100644 index 096077d6..00000000 --- a/apps/web/src/components/nav.tsx +++ /dev/null @@ -1,44 +0,0 @@ -"use client" - -import Link from "next/link" -import { usePathname } from "next/navigation" -import { SidebarNavItem } from "@/types" - -import { cn } from "@/lib/utils" -import { Icons } from "@/components/icons" - -interface DashboardNavProps { - items: SidebarNavItem[] -} - -export function DashboardNav({ items }: DashboardNavProps) { - const path = usePathname() - - if (!items?.length) { - return null - } - - return ( - - ) -} diff --git a/apps/web/src/components/page-header.tsx b/apps/web/src/components/page-header.tsx deleted file mode 100644 index 0cec4517..00000000 --- a/apps/web/src/components/page-header.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { cn } from "@/lib/utils" - -interface DocsPageHeaderProps extends React.HTMLAttributes { - heading: string - text?: string -} - -export function DocsPageHeader({ - heading, - text, - className, - ...props -}: DocsPageHeaderProps) { - return ( - <> -
      -

      - {heading} -

      - {text &&

      {text}

      } -
      -
      - - ) -} diff --git a/apps/web/src/components/post-create-button.tsx b/apps/web/src/components/post-create-button.tsx deleted file mode 100644 index 94cbee4f..00000000 --- a/apps/web/src/components/post-create-button.tsx +++ /dev/null @@ -1,81 +0,0 @@ -"use client" - -import * as React from "react" -import { useRouter } from "next/navigation" - -import { cn } from "@/lib/utils" -import { ButtonProps, buttonVariants } from "@/components/ui/button" -import { toast } from "@/components/ui/use-toast" -import { Icons } from "@/components/icons" - -interface PostCreateButtonProps extends ButtonProps {} - -export function PostCreateButton({ - className, - variant, - ...props -}: PostCreateButtonProps) { - const router = useRouter() - const [isLoading, setIsLoading] = React.useState(false) - - async function onClick() { - setIsLoading(true) - - const response = await fetch("/api/posts", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - title: "Untitled Post", - }), - }) - - setIsLoading(false) - - if (!response?.ok) { - if (response.status === 402) { - return toast({ - title: "Limit of 3 posts reached.", - description: "Please upgrade to the PRO plan.", - variant: "destructive", - }) - } - - return toast({ - title: "Something went wrong.", - description: "Your post was not created. Please try again.", - variant: "destructive", - }) - } - - const post = await response.json() - - // This forces a cache invalidation. - router.refresh() - - router.push(`/editor/${post.id}`) - } - - return ( - - ) -} diff --git a/apps/web/src/components/search.tsx b/apps/web/src/components/search.tsx deleted file mode 100644 index 1557f875..00000000 --- a/apps/web/src/components/search.tsx +++ /dev/null @@ -1,37 +0,0 @@ -"use client" - -import * as React from "react" - -import { cn } from "@/lib/utils" -import { Input } from "@/components/ui/input" -import { toast } from "@/components/ui/use-toast" - -interface DocsSearchProps extends React.HTMLAttributes {} - -export function DocsSearch({ className, ...props }: DocsSearchProps) { - function onSubmit(event: React.SyntheticEvent) { - event.preventDefault() - - return toast({ - title: "Not implemented", - description: "We're still working on the search.", - }) - } - - return ( -
      - - - ⌘K - -
      - ) -} diff --git a/apps/web/src/components/shell.tsx b/apps/web/src/components/shell.tsx deleted file mode 100644 index ee95821c..00000000 --- a/apps/web/src/components/shell.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -interface DashboardShellProps extends React.HTMLAttributes {} - -export function DashboardShell({ - children, - className, - ...props -}: DashboardShellProps) { - return ( -
      - {children} -
      - ) -} diff --git a/apps/web/src/components/sidebar-nav.tsx b/apps/web/src/components/sidebar-nav.tsx deleted file mode 100644 index 50416f5f..00000000 --- a/apps/web/src/components/sidebar-nav.tsx +++ /dev/null @@ -1,67 +0,0 @@ -"use client" - -import Link from "next/link" -import { usePathname } from "next/navigation" -import { SidebarNavItem } from "@/types" - -import { cn } from "@/lib/utils" - -export interface DocsSidebarNavProps { - items: SidebarNavItem[] -} - -export function DocsSidebarNav({ items }: DocsSidebarNavProps) { - const pathname = usePathname() - - return items.length ? ( -
      - {items.map((item, index) => ( -
      -

      - {item.title} -

      - {item.items ? ( - - ) : null} -
      - ))} -
      - ) : null -} - -interface DocsSidebarNavItemsProps { - items: SidebarNavItem[] - pathname: string | null -} - -export function DocsSidebarNavItems({ - items, - pathname, -}: DocsSidebarNavItemsProps) { - return items?.length ? ( -
      - {items.map((item, index) => - !item.disabled && item.href ? ( - - {item.title} - - ) : ( - - {item.title} - - ) - )} -
      - ) : null -} diff --git a/apps/web/src/components/site-footer.tsx b/apps/web/src/components/site-footer.tsx deleted file mode 100644 index fc6a5b8e..00000000 --- a/apps/web/src/components/site-footer.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import * as React from "react" - -import { siteConfig } from "@/config/site" -import { cn } from "@/lib/utils" -import { Icons } from "@/components/icons" -import { ModeToggle } from "@/components/mode-toggle" - -export function SiteFooter({ className }: React.HTMLAttributes) { - return ( - - ) -} diff --git a/apps/web/src/components/tailwind-indicator.tsx b/apps/web/src/components/tailwind-indicator.tsx deleted file mode 100644 index 5bd69ace..00000000 --- a/apps/web/src/components/tailwind-indicator.tsx +++ /dev/null @@ -1,16 +0,0 @@ -export function TailwindIndicator() { - if (process.env.NODE_ENV === "production") return null - - return ( -
      -
      xs
      -
      - sm -
      -
      md
      -
      lg
      -
      xl
      -
      2xl
      -
      - ) -} diff --git a/apps/web/src/components/theme-provider.tsx b/apps/web/src/components/theme-provider.tsx deleted file mode 100644 index 691554dd..00000000 --- a/apps/web/src/components/theme-provider.tsx +++ /dev/null @@ -1,9 +0,0 @@ -"use client" - -import * as React from "react" -import { ThemeProvider as NextThemesProvider } from "next-themes" -import { ThemeProviderProps } from "next-themes/dist/types" - -export function ThemeProvider({ children, ...props }: ThemeProviderProps) { - return {children} -} diff --git a/apps/web/src/components/toc.tsx b/apps/web/src/components/toc.tsx deleted file mode 100644 index 8dd3ff23..00000000 --- a/apps/web/src/components/toc.tsx +++ /dev/null @@ -1,114 +0,0 @@ -"use client" - -import * as React from "react" - -import { TableOfContents } from "@/lib/toc" -import { cn } from "@/lib/utils" -import { useMounted } from "@/hooks/use-mounted" - -interface TocProps { - toc: TableOfContents -} - -export function DashboardTableOfContents({ toc }: TocProps) { - const itemIds = React.useMemo( - () => - toc.items - ? toc.items - .flatMap((item) => [item.url, item?.items?.map((item) => item.url)]) - .flat() - .filter(Boolean) - .map((id) => id?.split("#")[1]) - : [], - [toc] - ) - const activeHeading = useActiveItem(itemIds) - const mounted = useMounted() - - if (!toc?.items) { - return null - } - - return mounted ? ( -
      -

      On This Page

      - -
      - ) : null -} - -function useActiveItem(itemIds: (string | undefined)[]) { - const [activeId, setActiveId] = React.useState("") - - React.useEffect(() => { - const observer = new IntersectionObserver( - (entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - setActiveId(entry.target.id) - } - }) - }, - { rootMargin: `0% 0% -80% 0%` } - ) - - itemIds?.forEach((id) => { - if (!id) { - return - } - - const element = document.getElementById(id) - if (element) { - observer.observe(element) - } - }) - - return () => { - itemIds?.forEach((id) => { - if (!id) { - return - } - - const element = document.getElementById(id) - if (element) { - observer.unobserve(element) - } - }) - } - }, [itemIds]) - - return activeId -} - -interface TreeProps { - tree: TableOfContents - level?: number - activeItem?: string | null -} - -function Tree({ tree, level = 1, activeItem }: TreeProps) { - return tree?.items?.length && level < 3 ? ( -
        - {tree.items.map((item, index) => { - return ( -
      • - - {item.title} - - {item.items?.length ? ( - - ) : null} -
      • - ) - })} -
      - ) : null -} diff --git a/apps/web/src/components/ui/accordion.tsx b/apps/web/src/components/ui/accordion.tsx deleted file mode 100644 index a6583d9f..00000000 --- a/apps/web/src/components/ui/accordion.tsx +++ /dev/null @@ -1,60 +0,0 @@ -"use client" - -import * as React from "react" -import * as AccordionPrimitive from "@radix-ui/react-accordion" -import { ChevronDown } from "lucide-react" - -import { cn } from "@/lib/utils" - -const Accordion = AccordionPrimitive.Root - -const AccordionItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AccordionItem.displayName = "AccordionItem" - -const AccordionTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - svg]:rotate-180", - className - )} - {...props} - > - {children} - - - -)) -AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName - -const AccordionContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - -
      {children}
      -
      -)) -AccordionContent.displayName = AccordionPrimitive.Content.displayName - -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/apps/web/src/components/ui/alert-dialog.tsx b/apps/web/src/components/ui/alert-dialog.tsx deleted file mode 100644 index 8e03ce52..00000000 --- a/apps/web/src/components/ui/alert-dialog.tsx +++ /dev/null @@ -1,150 +0,0 @@ -"use client" - -import * as React from "react" -import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" - -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" - -const AlertDialog = AlertDialogPrimitive.Root - -const AlertDialogTrigger = AlertDialogPrimitive.Trigger - -const AlertDialogPortal = ({ - className, - children, - ...props -}: AlertDialogPrimitive.AlertDialogPortalProps) => ( - -
      - {children} -
      -
      -) -AlertDialogPortal.displayName = AlertDialogPrimitive.Portal.displayName - -const AlertDialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - -)) -AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName - -const AlertDialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - - -)) -AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName - -const AlertDialogHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
      -) -AlertDialogHeader.displayName = "AlertDialogHeader" - -const AlertDialogFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
      -) -AlertDialogFooter.displayName = "AlertDialogFooter" - -const AlertDialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName - -const AlertDialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogDescription.displayName = - AlertDialogPrimitive.Description.displayName - -const AlertDialogAction = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName - -const AlertDialogCancel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName - -export { - AlertDialog, - AlertDialogTrigger, - AlertDialogContent, - AlertDialogHeader, - AlertDialogFooter, - AlertDialogTitle, - AlertDialogDescription, - AlertDialogAction, - AlertDialogCancel, -} diff --git a/apps/web/src/components/ui/alert.tsx b/apps/web/src/components/ui/alert.tsx deleted file mode 100644 index 6cd63fbb..00000000 --- a/apps/web/src/components/ui/alert.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import * as React from "react" -import { VariantProps, cva } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const alertVariants = cva( - "relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11", - { - variants: { - variant: { - default: "bg-background text-foreground", - destructive: - "text-destructive border-destructive/50 dark:border-destructive [&>svg]:text-destructive text-destructive", - }, - }, - defaultVariants: { - variant: "default", - }, - } -) - -const Alert = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes & VariantProps ->(({ className, variant, ...props }, ref) => ( -
      -)) -Alert.displayName = "Alert" - -const AlertTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
      -)) -AlertTitle.displayName = "AlertTitle" - -const AlertDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
      -)) -AlertDescription.displayName = "AlertDescription" - -export { Alert, AlertTitle, AlertDescription } diff --git a/apps/web/src/components/ui/aspect-ratio.tsx b/apps/web/src/components/ui/aspect-ratio.tsx deleted file mode 100644 index d6a5226f..00000000 --- a/apps/web/src/components/ui/aspect-ratio.tsx +++ /dev/null @@ -1,7 +0,0 @@ -"use client" - -import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" - -const AspectRatio = AspectRatioPrimitive.Root - -export { AspectRatio } diff --git a/apps/web/src/components/ui/avatar.tsx b/apps/web/src/components/ui/avatar.tsx deleted file mode 100644 index 51e507ba..00000000 --- a/apps/web/src/components/ui/avatar.tsx +++ /dev/null @@ -1,50 +0,0 @@ -"use client" - -import * as React from "react" -import * as AvatarPrimitive from "@radix-ui/react-avatar" - -import { cn } from "@/lib/utils" - -const Avatar = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -Avatar.displayName = AvatarPrimitive.Root.displayName - -const AvatarImage = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AvatarImage.displayName = AvatarPrimitive.Image.displayName - -const AvatarFallback = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName - -export { Avatar, AvatarImage, AvatarFallback } diff --git a/apps/web/src/components/ui/badge.tsx b/apps/web/src/components/ui/badge.tsx deleted file mode 100644 index bb37dc82..00000000 --- a/apps/web/src/components/ui/badge.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import * as React from "react" -import { VariantProps, cva } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const badgeVariants = cva( - "inline-flex items-center border rounded-full px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", - { - variants: { - variant: { - default: - "bg-primary hover:bg-primary/80 border-transparent text-primary-foreground", - secondary: - "bg-secondary hover:bg-secondary/80 border-transparent text-secondary-foreground", - destructive: - "bg-destructive hover:bg-destructive/80 border-transparent text-destructive-foreground", - outline: "text-foreground", - }, - }, - defaultVariants: { - variant: "default", - }, - } -) - -export interface BadgeProps - extends React.HTMLAttributes, - VariantProps {} - -function Badge({ className, variant, ...props }: BadgeProps) { - return ( -
      - ) -} - -export { Badge, badgeVariants } diff --git a/apps/web/src/components/ui/button.tsx b/apps/web/src/components/ui/button.tsx deleted file mode 100644 index 89f2d3c0..00000000 --- a/apps/web/src/components/ui/button.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import * as React from "react" -import { VariantProps, cva } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const buttonVariants = cva( - "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background", - { - variants: { - variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", - destructive: - "bg-destructive text-destructive-foreground hover:bg-destructive/90", - outline: - "border border-input hover:bg-accent hover:text-accent-foreground", - secondary: - "bg-secondary text-secondary-foreground hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "underline-offset-4 hover:underline text-primary", - }, - size: { - default: "h-10 py-2 px-4", - sm: "h-9 px-3 rounded-md", - lg: "h-11 px-8 rounded-md", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - } -) - -export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps {} - -const Button = React.forwardRef( - ({ className, variant, size, ...props }, ref) => { - return ( -