From d14993f86648fa50788694dce96e4b4b5e551a35 Mon Sep 17 00:00:00 2001 From: Thomas Aribart Date: Fri, 22 Sep 2023 15:41:53 +0200 Subject: [PATCH 1/5] small improvements --- docs/docs/4-reacting-to-events/2-message-queues.md | 2 +- docs/docs/4-reacting-to-events/3-message-buses.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/4-reacting-to-events/2-message-queues.md b/docs/docs/4-reacting-to-events/2-message-queues.md index de5165b0..dde3ac27 100644 --- a/docs/docs/4-reacting-to-events/2-message-queues.md +++ b/docs/docs/4-reacting-to-events/2-message-queues.md @@ -129,7 +129,7 @@ The following methods interact with the messaging solution of your application t **Type Helpers:** -- MessageChannelMessage: Given a MessageQueue, returns the TS type of its messages +- `MessageChannelMessage`: Given a `MessageQueue`, returns the TS type of its messages ```ts import type { MessageChannelMessage } from '@castore/core'; diff --git a/docs/docs/4-reacting-to-events/3-message-buses.md b/docs/docs/4-reacting-to-events/3-message-buses.md index 2980ea58..7c83ce23 100644 --- a/docs/docs/4-reacting-to-events/3-message-buses.md +++ b/docs/docs/4-reacting-to-events/3-message-buses.md @@ -125,7 +125,7 @@ The following methods interact with the messaging solution of your application t **Type Helpers:** -- MessageChannelMessage: Given a MessageBus, returns the TS type of its messages +- `MessageChannelMessage`: Given a `MessageBus`, returns the TS type of its messages ```ts import type { MessageChannelMessage } from '@castore/core'; From 9b5fd973d8f432f37ccd444b6d6cdc7ab4dbbd93 Mon Sep 17 00:00:00 2001 From: Thomas Aribart Date: Fri, 22 Sep 2023 18:43:40 +0200 Subject: [PATCH 2/5] code Home page --- docs/assets/logo.svg | 1 + docs/docusaurus.config.js | 1 - docs/package.json | 1 + docs/src/css/custom.css | 332 +++++++++++++++++++++++++++ docs/src/pages/Home/BulletPoints.tsx | 88 +++++++ docs/src/pages/Home/Description.tsx | 43 ++++ docs/src/pages/Home/Footer.tsx | 40 ++++ docs/src/pages/Home/Home.tsx | 29 +++ docs/src/pages/Home/Logo.tsx | 282 +++++++++++++++++++++++ docs/src/pages/Home/Title.tsx | 14 ++ docs/src/pages/Home/TopLinks.tsx | 75 ++++++ docs/src/pages/Home/index.tsx | 1 + docs/src/pages/index.module.css | 23 -- docs/src/pages/index.tsx | 38 +-- docs/src/pages/markdown-page.md | 7 - docs/static/.nojekyll | 0 yarn.lock | 10 + 17 files changed, 917 insertions(+), 68 deletions(-) create mode 100644 docs/src/pages/Home/BulletPoints.tsx create mode 100644 docs/src/pages/Home/Description.tsx create mode 100644 docs/src/pages/Home/Footer.tsx create mode 100644 docs/src/pages/Home/Home.tsx create mode 100644 docs/src/pages/Home/Logo.tsx create mode 100644 docs/src/pages/Home/Title.tsx create mode 100644 docs/src/pages/Home/TopLinks.tsx create mode 100644 docs/src/pages/Home/index.tsx delete mode 100644 docs/src/pages/index.module.css delete mode 100644 docs/src/pages/markdown-page.md delete mode 100644 docs/static/.nojekyll diff --git a/docs/assets/logo.svg b/docs/assets/logo.svg index 431b8a54..086163db 100644 --- a/docs/assets/logo.svg +++ b/docs/assets/logo.svg @@ -2,6 +2,7 @@ +Castore Logo diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 81f44ac5..fdabb9d2 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -50,7 +50,6 @@ const config = { themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ - // Replace with your project's social card image: 'img/castore-social-card.jpg', navbar: { hideOnScroll: true, diff --git a/docs/package.json b/docs/package.json index e4c09078..3891c71b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -46,6 +46,7 @@ "clsx": "^1.2.1", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-icons": "^4.11.0", "uuid": "^9.0.0", "web-vitals": "^2.1.4" }, diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index d50b009a..0ab5d951 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -28,3 +28,335 @@ --ifm-color-primary-lightest: #fab854; --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); } + +.inline-block { + display: inline-block; +} + +.flex { + display: flex; +} + +.flex-1 { + flex: 1 1 0%; +} + +.flex-col { + flex-direction: column; +} + +.flex-wrap { + flex-wrap: wrap; +} + +.gap-12 { + gap: 3rem; +} + +.gap-8 { + gap: 2rem; +} + +.gap-3 { + gap: 0.75rem; +} + +.gap-2 { + gap: 0.5rem; +} + +.gap-1 { + gap: 0.25rem; +} + +.grid { + display: grid; +} + +.items-start { + align-items: flex-start; +} + +.items-center { + align-items: center; +} + +.justify-center { + justify-content: center; +} + +.mt-2 { + margin-top: 0.5rem; +} + +.p-10 { + padding: 2.5rem; +} + +.p-8 { + padding: 2rem; +} + +.p-2 { + padding: 0.5rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + +.text-transparent { + color: transparent; +} + +.text-white, +.text-white:hover { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.text-primary-light { + color: var(--ifm-color-primary-light); +} + +.text-primary-lighter { + color: var(--ifm-color-primary-lighter); +} + +.text-primary-lightest { + color: var(--ifm-color-primary-lightest); +} + +.uppercase { + text-transform: uppercase; +} + +.text-center { + text-align: center; +} + +.text-6xl { + font-size: 3.75rem; + line-height: 1; +} + +.text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; +} + +.text-2xl { + font-size: 1.5rem; + line-height: 2rem; +} + +.text-xl { + font-size: 1.25rem; +} + +.text-lg, +.text-xl { + line-height: 1.75rem; +} + +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.leading-6 { + line-height: 1.5rem; +} + +.font-black { + font-weight: 900; +} + +.font-extrabold { + font-weight: 800; +} + +.font-bold { + font-weight: 700; +} + +.font-regular { + font-weight: 400; +} + +.rounded { + border-radius: 0.25rem; +} + +.bg-clip-text { + -webkit-background-clip: text; + background-clip: text; +} + +.bg-gradient-to-r { + background-image: linear-gradient(to right, var(--tw-gradient-stops)); +} + +.bg-gradient-to-l { + background-image: linear-gradient(to left, var(--tw-gradient-stops)); +} + +a:hover, +.bg-gradient-to-r:hover, +.bg-gradient-to-l:hover, +.text-primary-light:hover, +.text-primary-lighter:hover, +.text-primary-lightest:hover { + filter: saturate(1.4); + transition: filter 0.3s ease-in-out; +} + +.bg-color-gradient { + --tw-gradient-stops: var(--ifm-color-primary-light), + var(--ifm-color-primary-lightest); +} + +.w-\[40px\] { + width: 40px; +} + +.max-w-screen-xl { + max-width: 1280px; +} + +.max-w-\[1200px\] { + max-width: 1200px; +} + +.max-w-\[500px\] { + max-width: 500px; +} + +.max-w-\[400px\] { + max-width: 400px; +} + +.max-w-md { + max-width: 28rem; +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.opacity-90 { + opacity: 0.9; +} + +.opacity-20 { + opacity: 0.2; +} + +.hover\:opacity-100:hover { + opacity: 1; +} + +.hover\:underline:hover { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; +} + +.shadow-black\/10 { + --tw-shadow-color: rgba(0, 0, 0, 0.1); + --tw-shadow: var(--tw-shadow-colored); +} + +.shadow-xl { + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), + var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-xl { + --tw-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.05), + 0 10px 10px -5px rgba(0, 0, 0, 0.02); + --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), + 0 10px 10px -5px var(--tw-shadow-color); +} + +@media (min-width: 640px) { + .sm\:grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (min-width: 768px) { + .md\:w-\[60px\] { + width: 60px; + } + + .md\:flex-row { + flex-direction: row; + } + + .md\:grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .md\:self-end { + align-self: flex-end; + } + + .md\:gap-16 { + gap: 4rem; + } + + .md\:text-base { + font-size: 1rem; + line-height: 1.5rem; + } + + .md\:text-6xl { + font-size: 3.75rem; + line-height: 1; + } + + .md\:text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; + } +} + +@media (min-width: 1024px) { + .lg\:w-\[100px\] { + width: 100px; + } + + .lg\:max-w-2xl { + max-width: 42rem; + } + + .lg\:max-w-\[600px\] { + max-width: 600px; + } + + .lg\:gap-4 { + gap: 1rem; + } + + .lg\:text-7xl { + font-size: 4.5rem; + line-height: 1; + } + + .lg\:text-5xl { + font-size: 3rem; + line-height: 1; + } + + .lg\:text-xl { + font-size: 1.25rem; + line-height: 1.75rem; + } +} diff --git a/docs/src/pages/Home/BulletPoints.tsx b/docs/src/pages/Home/BulletPoints.tsx new file mode 100644 index 00000000..ff53f96e --- /dev/null +++ b/docs/src/pages/Home/BulletPoints.tsx @@ -0,0 +1,88 @@ +import React from 'react'; +import { BsStars } from 'react-icons/bs'; +import { FaPuzzlePiece, FaHandHoldingHeart } from 'react-icons/fa'; + +export const BulletPoints = (): JSX.Element => ( +
+
+ +
+

Stack Agnostic

+

+ Castore is in TypeScript. Outside from that, it can + be used pretty much anywhere: React apps, containers, + Lambdas... you name it 🙌 +

+

+ For instance, EventStore classes are{' '} + stack agnostic: They need an{' '} + EventStorageAdapter class to interact with actual data. +

+

+ You can code your own EventStorageAdapter (simply + implement the interface), but it's much simpler to use off-the-shelf + adapters like the{' '} + + DynamoDBEventStorageAdapter + + . +

+
+
+
+ +
+

+ Modular & Type-safe +

+

+ Castore is a{' '} + collection of utility classes and helpers, but NOT a + framework: While some classes require compatible infrastructure, + Castore is not responsible for deploying it. +

+

+ Though that is not something we exclude in the future, we are a small + team and decided to focus on DevX first. +

+

+ Speaking of DevX, we absolutely love TypeScript! If you do too, you're + in the right place: We push type-safety to the limit{' '} + in everything we do! +

+
+
+
+ +
+

+ Comprehensive +

+

+ The Event Sourcing journey has many hidden pitfalls.{' '} + We ran into them for you! +

+

+ Castore is opiniated. It comes with a collection of best practices and + documented anti-patterns that we hope will help you out! +

+

+ It also comes with an awesome collection of packages that will make + your life easy, e.g. when working on{' '} + + unit tests + + ,{' '} + + data migration + {' '} + or{' '} + + data modelling + + . +

+
+
+
+); diff --git a/docs/src/pages/Home/Description.tsx b/docs/src/pages/Home/Description.tsx new file mode 100644 index 00000000..2f52fa35 --- /dev/null +++ b/docs/src/pages/Home/Description.tsx @@ -0,0 +1,43 @@ +import Link from '@docusaurus/Link'; +import React from 'react'; + +export const Description = (): JSX.Element => ( + <> +

+ + Event sourcing + {' '} + made easy +

+

+ + Event Sourcing + {' '} + is a data storage paradigm that saves{' '} + changes in your application state rather than the state + itself. +

+

+ It is powerful as it enables{' '} + rewinding to a previous state and{' '} + exploring audit trails for debugging or business/legal + purposes. It also integrates very well with{' '} + + event-driven architectures + + . +

+

+ However, it is tricky to implement 😅 +

+

+ ...well, not anymore 💪 +

+ + 👉 Get Started + + +); diff --git a/docs/src/pages/Home/Footer.tsx b/docs/src/pages/Home/Footer.tsx new file mode 100644 index 00000000..a5634f5a --- /dev/null +++ b/docs/src/pages/Home/Footer.tsx @@ -0,0 +1,40 @@ +import Link from '@docusaurus/Link'; +import React from 'react'; + +const footerLinks = [ + { + label: 'Theodo', + to: 'https://www.theodo.fr/', + }, + { + label: 'Serverless by Theodo', + to: 'https://dev.to/slsbytheodo', + }, + { + label: '@ThomasAribart Twitter', + to: 'https://twitter.com/aribartt', + }, +]; + +export const Footer = (): JSX.Element => ( +
+
+
+ {footerLinks.map(item => ( +
+ {item.to.startsWith('http') ? ( + + {item.label} + + ) : ( + {item.label} + )} +
+ ))} +
+
+ © {new Date().getFullYear()} Serverless by Theodo +
+
+
+); diff --git a/docs/src/pages/Home/Home.tsx b/docs/src/pages/Home/Home.tsx new file mode 100644 index 00000000..790c11d4 --- /dev/null +++ b/docs/src/pages/Home/Home.tsx @@ -0,0 +1,29 @@ +import Head from '@docusaurus/Head'; +import React from 'react'; + +import { BulletPoints } from './BulletPoints'; +import { Description } from './Description'; +import { Footer } from './Footer'; +import { Title } from './Title'; +import { TopLinks } from './TopLinks'; + +export const Home = (): JSX.Element => ( + <> + + Castore | Event sourcing made easy + + +
+ +
+ + <Description /> + </div> + <BulletPoints /> + </div> + <Footer /> + </> +); diff --git a/docs/src/pages/Home/Logo.tsx b/docs/src/pages/Home/Logo.tsx new file mode 100644 index 00000000..251d60b9 --- /dev/null +++ b/docs/src/pages/Home/Logo.tsx @@ -0,0 +1,282 @@ +/* eslint-disable max-lines */ +import React from 'react'; + +export const Logo = (props: React.HTMLProps<HTMLDivElement>): JSX.Element => ( + <div {...props}> + <svg + version="1.1" + id="Layer_1" + xmlns="http://www.w3.org/2000/svg" + x="0px" + y="0px" + viewBox="0 0 852 852" + enableBackground="new 0 0 852 852" + > + <title>Castore Logo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+); diff --git a/docs/src/pages/Home/Title.tsx b/docs/src/pages/Home/Title.tsx new file mode 100644 index 00000000..ac5ac504 --- /dev/null +++ b/docs/src/pages/Home/Title.tsx @@ -0,0 +1,14 @@ +import React from 'react'; + +import { Logo } from './Logo'; + +export const Title = (): JSX.Element => ( +
+ +

+ + Castore + +

+
+); diff --git a/docs/src/pages/Home/TopLinks.tsx b/docs/src/pages/Home/TopLinks.tsx new file mode 100644 index 00000000..28402ac7 --- /dev/null +++ b/docs/src/pages/Home/TopLinks.tsx @@ -0,0 +1,75 @@ +import Link from '@docusaurus/Link'; +import React from 'react'; +import { FaRegCopy, FaGithub, FaHeart } from 'react-icons/fa'; +import { MdOutlineImportContacts } from 'react-icons/md'; +import { SlSpeech } from 'react-icons/sl'; + +type Link = { id: string; label: JSX.Element; to: string }; + +const links: Link[] = [ + { + id: 'docs', + label: ( +
+ Docs +
+ ), + to: './docs/introduction', + }, + { + id: 'github', + label: ( +
+ GitHub +
+ ), + to: 'https://github.com/castore-dev/castore', + }, + { + id: 'examples', + label: ( +
+ Examples +
+ ), + to: 'https://github.com/castore-dev/castore/tree/main/demo/blueprint/src', + }, + { + id: 'sponsor', + label: ( +
+ Sponsor +
+ ), + to: 'https://github.com/sponsors/ThomasAribart', + }, + { + id: 'contact', + label: ( +
+ Contact +
+ ), + to: 'mailto:thomasa@theodo.fr', + }, +]; + +export const TopLinks = (): JSX.Element => ( +
+ {links.map(({ id, label, to }) => { + const children = ( +
{label}
+ ); + + return ( +
+ {to.startsWith('http') || to.startsWith('mailto') ? ( + {children} + ) : ( + {children} + )} +
+ ); + })} +
+); diff --git a/docs/src/pages/Home/index.tsx b/docs/src/pages/Home/index.tsx new file mode 100644 index 00000000..af9c1c67 --- /dev/null +++ b/docs/src/pages/Home/index.tsx @@ -0,0 +1 @@ +export { Home } from './Home'; diff --git a/docs/src/pages/index.module.css b/docs/src/pages/index.module.css deleted file mode 100644 index 9f71a5da..00000000 --- a/docs/src/pages/index.module.css +++ /dev/null @@ -1,23 +0,0 @@ -/** - * CSS files with the .module.css suffix will be treated as CSS modules - * and scoped locally. - */ - -.heroBanner { - padding: 4rem 0; - text-align: center; - position: relative; - overflow: hidden; -} - -@media screen and (max-width: 996px) { - .heroBanner { - padding: 2rem; - } -} - -.buttons { - display: flex; - align-items: center; - justify-content: center; -} diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx index 9ed8c45a..ca43e262 100644 --- a/docs/src/pages/index.tsx +++ b/docs/src/pages/index.tsx @@ -1,39 +1,3 @@ -import Link from '@docusaurus/Link'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -import Layout from '@theme/Layout'; -import clsx from 'clsx'; -import React from 'react'; - -import styles from './index.module.css'; - -const HomepageHeader = (): JSX.Element => { - const { siteConfig } = useDocusaurusContext(); - - return ( -
-
-

{siteConfig.title}

-

{siteConfig.tagline}

-
- - Get started! - -
-
-
- ); -}; - -const Home = (): JSX.Element => ( - - - -); +import { Home } from './Home'; export default Home; diff --git a/docs/src/pages/markdown-page.md b/docs/src/pages/markdown-page.md deleted file mode 100644 index 9756c5b6..00000000 --- a/docs/src/pages/markdown-page.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Markdown page example ---- - -# Markdown page example - -You don't need React to write simple standalone pages. diff --git a/docs/static/.nojekyll b/docs/static/.nojekyll deleted file mode 100644 index e69de29b..00000000 diff --git a/yarn.lock b/yarn.lock index eb1c54b5..50d793b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6165,6 +6165,7 @@ __metadata: eslint: ^8.14.0 react: ^17.0.2 react-dom: ^17.0.2 + react-icons: ^4.11.0 rollup-plugin-visualizer: ^5.6.0 typescript: ^4.6.3 uuid: ^9.0.0 @@ -21986,6 +21987,15 @@ __metadata: languageName: node linkType: hard +"react-icons@npm:^4.11.0": + version: 4.11.0 + resolution: "react-icons@npm:4.11.0" + peerDependencies: + react: "*" + checksum: 7b8b80bbe2dabcc54b6c2129b7761a04b19caebe24389adc7683478ef41212b9ca0b53c63abcc06b3c01b94c84855ec5142b4c357e19c4aaaad9a4db23a3c485 + languageName: node + linkType: hard + "react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" From 17b765d0a80176ed24d9acb04f7382233133409a Mon Sep 17 00:00:00 2001 From: Thomas Aribart Date: Fri, 22 Sep 2023 18:49:01 +0200 Subject: [PATCH 3/5] remove introduction section from docs --- .../{2-installation.md => 1-installation.md} | 2 +- docs/docs/1-introduction.md | 58 ------------------- .../1-events.md | 2 +- .../2-aggregates-reducers.md | 0 .../3-event-stores.md | 0 .../4-fetching-events.md | 2 +- .../5-pushing-events.md | 4 +- .../6-joining-data.md | 0 .../_category_.json | 2 +- .../1-messages.md | 0 .../2-message-queues.md | 2 +- .../3-message-buses.md | 2 +- .../4-connected-event-store.md | 0 .../5-snapshots.md | 0 .../6-read-models.md | 0 .../_category_.json | 2 +- docs/docs/{5-packages.md => 4-packages.md} | 2 +- docs/src/pages/Home/Description.tsx | 2 +- docs/src/pages/Home/TopLinks.tsx | 2 +- 19 files changed, 12 insertions(+), 70 deletions(-) rename docs/docs/{2-installation.md => 1-installation.md} (97%) delete mode 100644 docs/docs/1-introduction.md rename docs/docs/{3-event-sourcing => 2-event-sourcing}/1-events.md (90%) rename docs/docs/{3-event-sourcing => 2-event-sourcing}/2-aggregates-reducers.md (100%) rename docs/docs/{3-event-sourcing => 2-event-sourcing}/3-event-stores.md (100%) rename docs/docs/{3-event-sourcing => 2-event-sourcing}/4-fetching-events.md (94%) rename docs/docs/{3-event-sourcing => 2-event-sourcing}/5-pushing-events.md (91%) rename docs/docs/{3-event-sourcing => 2-event-sourcing}/6-joining-data.md (100%) rename docs/docs/{3-event-sourcing => 2-event-sourcing}/_category_.json (72%) rename docs/docs/{4-reacting-to-events => 3-reacting-to-events}/1-messages.md (100%) rename docs/docs/{4-reacting-to-events => 3-reacting-to-events}/2-message-queues.md (98%) rename docs/docs/{4-reacting-to-events => 3-reacting-to-events}/3-message-buses.md (98%) rename docs/docs/{4-reacting-to-events => 3-reacting-to-events}/4-connected-event-store.md (100%) rename docs/docs/{4-reacting-to-events => 3-reacting-to-events}/5-snapshots.md (100%) rename docs/docs/{4-reacting-to-events => 3-reacting-to-events}/6-read-models.md (100%) rename docs/docs/{4-reacting-to-events => 3-reacting-to-events}/_category_.json (69%) rename docs/docs/{5-packages.md => 4-packages.md} (99%) diff --git a/docs/docs/2-installation.md b/docs/docs/1-installation.md similarity index 97% rename from docs/docs/2-installation.md rename to docs/docs/1-installation.md index 90b65c63..ee6c6470 100644 --- a/docs/docs/2-installation.md +++ b/docs/docs/1-installation.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 1 --- # Installation diff --git a/docs/docs/1-introduction.md b/docs/docs/1-introduction.md deleted file mode 100644 index f7f2de50..00000000 --- a/docs/docs/1-introduction.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -sidebar_position: 1 ---- - -# Introduction - -[Event Sourcing](https://learn.microsoft.com/en-us/azure/architecture/patterns/event-sourcing) is a data storage paradigm that saves **changes in your application state** rather than the state itself. - -It is powerful as it enables **rewinding to a previous state** and **exploring audit trails** for debugging or business/legal purposes. It also integrates very well with [event-driven architectures](https://en.wikipedia.org/wiki/Event-driven_architecture). - -However, it is **tricky to implement** 😅 - -After years of using it at [Theodo](https://dev.to/slsbytheodo), we have grown to love it, but also experienced first-hand the lack of consensus and tooling around it. That's where Castore comes from! - ---- - -

- Castore is a TypeScript library that makes Event Sourcing easy 😎 -

- ---- - -With Castore, you'll be able to: - -- Define your [event stores](./3-event-sourcing/3-event-stores.md) -- Fetch and push new [events](./3-event-sourcing/1-events.md) seamlessly -- Implement and test your [commands](./3-event-sourcing/5-pushing-events.md) -- ...and much more! - -All that with first-class developer experience and minimal boilerplate ✨ - -## 🫀 Core Design - -Some important decisions that we've made early on: - -### 💭 **Abstractions first** - -Castore has been designed with **flexibility** in mind. It gives you abstractions that are meant to be used **anywhere**: React apps, containers, Lambdas... you name it! - -For instance, `EventStore` classes are **stack agnostic**: They need an `EventStorageAdapter` class to interact with actual data. You can code your own `EventStorageAdapter` (simply implement the interface), but it's much simpler to use an off-the-shelf adapter like [`DynamoDBEventStorageAdapter`](https://www.npmjs.com/package/@castore/dynamodb-event-storage-adapter). - -### 🙅‍♂️ **We do NOT deploy resources** - -While some packages like `DynamoDBEventStorageAdapter` require compatible infrastructure, Castore is not responsible for deploying it. - -Though that is not something we exclude in the future, we are a small team and decided to focus on DevX first. - -### ⛑ **Full type safety** - -Speaking of DevX, we absolutely love TypeScript! If you do too, you're in the right place: We push type-safety to the limit in everything we do! - -If you don't, that's fine 👍 Castore is still available in Node/JS. And you can still profit from some nice JSDocs! - -### 📖 **Best practices** - -The Event Sourcing journey has many hidden pitfalls. We ran into them for you! - -Castore is opiniated. It comes with a collection of best practices and documented anti-patterns that we hope will help you out! diff --git a/docs/docs/3-event-sourcing/1-events.md b/docs/docs/2-event-sourcing/1-events.md similarity index 90% rename from docs/docs/3-event-sourcing/1-events.md rename to docs/docs/2-event-sourcing/1-events.md index c7233147..6d743012 100644 --- a/docs/docs/3-event-sourcing/1-events.md +++ b/docs/docs/2-event-sourcing/1-events.md @@ -53,7 +53,7 @@ const pokemonAppearedEventType = new EventType< :::info -Note that we only provided TS types for `payload` and `metadata` properties. That is because, as stated in the [core design](../1-introduction.md#-core-design), **Castore is meant to be as flexible as possible**, and that includes the validation library you want to use (if any): The `EventType` class can be used directly if no validation is required, or implemented by [other classes](../5-packages.md#-event-types) which will add run-time validation methods to it 👍 +Note that we only provided TS types for `payload` and `metadata` properties. That is because, as stated in the [core design](../../../), **Castore is meant to be as flexible as possible**, and that includes the validation library you want to use (if any): The `EventType` class can be used directly if no validation is required, or implemented by [other classes](../4-packages.md#-event-types) which will add run-time validation methods to it 👍 ::: diff --git a/docs/docs/3-event-sourcing/2-aggregates-reducers.md b/docs/docs/2-event-sourcing/2-aggregates-reducers.md similarity index 100% rename from docs/docs/3-event-sourcing/2-aggregates-reducers.md rename to docs/docs/2-event-sourcing/2-aggregates-reducers.md diff --git a/docs/docs/3-event-sourcing/3-event-stores.md b/docs/docs/2-event-sourcing/3-event-stores.md similarity index 100% rename from docs/docs/3-event-sourcing/3-event-stores.md rename to docs/docs/2-event-sourcing/3-event-stores.md diff --git a/docs/docs/3-event-sourcing/4-fetching-events.md b/docs/docs/2-event-sourcing/4-fetching-events.md similarity index 94% rename from docs/docs/3-event-sourcing/4-fetching-events.md rename to docs/docs/2-event-sourcing/4-fetching-events.md index c2eb3716..0f75bc53 100644 --- a/docs/docs/3-event-sourcing/4-fetching-events.md +++ b/docs/docs/2-event-sourcing/4-fetching-events.md @@ -30,6 +30,6 @@ const { aggregate } = await pokemonsEventStore.getAggregate('pikachu1'); :::info -You can choose to build an event storage adapter that suits your usage. However, we highly recommend using an [off-the-shelf adapter](../5-packages.md#-event-storage-adapters) (if the storage solution that you use does not have an adapter yet, feel free to create/upvote an issue, or contribute 🤗). +You can choose to build an event storage adapter that suits your usage. However, we highly recommend using an [off-the-shelf adapter](../4-packages.md#-event-storage-adapters) (if the storage solution that you use does not have an adapter yet, feel free to create/upvote an issue, or contribute 🤗). ::: diff --git a/docs/docs/3-event-sourcing/5-pushing-events.md b/docs/docs/2-event-sourcing/5-pushing-events.md similarity index 91% rename from docs/docs/3-event-sourcing/5-pushing-events.md rename to docs/docs/2-event-sourcing/5-pushing-events.md index 41bfe9a7..6724dab8 100644 --- a/docs/docs/3-event-sourcing/5-pushing-events.md +++ b/docs/docs/2-event-sourcing/5-pushing-events.md @@ -47,11 +47,11 @@ const catchPokemonCommand = new Command({ :::info -Note that we only provided TS types for `Input` and `Output` properties. That is because, as stated in the [core design](../1-introduction.md#-core-design), **Castore is meant to be as flexible as possible**, and that includes the validation library you want to use (if any): The `Command` class can be used directly if no validation is required, or implemented by [other classes](../5-packages.md#-commands) which will add run-time validation methods to it 👍 +Note that we only provided TS types for `Input` and `Output` properties. That is because, as stated in the [core design](../../../), **Castore is meant to be as flexible as possible**, and that includes the validation library you want to use (if any): The `Command` class can be used directly if no validation is required, or implemented by [other classes](../4-packages.md#-commands) which will add run-time validation methods to it 👍 ::: -`Commands` handlers should NOT use [read models](../4-reacting-to-events/6-read-models.md) when validating that a modification is acceptable. Read models are like cache: They are not the source of truth, and may not represent the freshest state. +`Commands` handlers should NOT use [read models](../3-reacting-to-events/6-read-models.md) when validating that a modification is acceptable. Read models are like cache: They are not the source of truth, and may not represent the freshest state. Fetching and pushing events non-simultaneously exposes your application to [race conditions](https://en.wikipedia.org/wiki/Race_condition). To counter that, commands are designed to be retried when an `EventAlreadyExistsError` is triggered (which is part of the `EventStorageAdapter` interface). diff --git a/docs/docs/3-event-sourcing/6-joining-data.md b/docs/docs/2-event-sourcing/6-joining-data.md similarity index 100% rename from docs/docs/3-event-sourcing/6-joining-data.md rename to docs/docs/2-event-sourcing/6-joining-data.md diff --git a/docs/docs/3-event-sourcing/_category_.json b/docs/docs/2-event-sourcing/_category_.json similarity index 72% rename from docs/docs/3-event-sourcing/_category_.json rename to docs/docs/2-event-sourcing/_category_.json index 3a6c5ef9..8474ce80 100644 --- a/docs/docs/3-event-sourcing/_category_.json +++ b/docs/docs/2-event-sourcing/_category_.json @@ -1,4 +1,4 @@ { "label": "Event Sourcing concepts", - "position": 3 + "position": 2 } diff --git a/docs/docs/4-reacting-to-events/1-messages.md b/docs/docs/3-reacting-to-events/1-messages.md similarity index 100% rename from docs/docs/4-reacting-to-events/1-messages.md rename to docs/docs/3-reacting-to-events/1-messages.md diff --git a/docs/docs/4-reacting-to-events/2-message-queues.md b/docs/docs/3-reacting-to-events/2-message-queues.md similarity index 98% rename from docs/docs/4-reacting-to-events/2-message-queues.md rename to docs/docs/3-reacting-to-events/2-message-queues.md index dde3ac27..28a63d36 100644 --- a/docs/docs/4-reacting-to-events/2-message-queues.md +++ b/docs/docs/3-reacting-to-events/2-message-queues.md @@ -53,7 +53,7 @@ await messageQueue.publishMessage(...); :::info -You can code your own `MessageQueueAdapter` (simply implement the `MessageChannelAdapter` interface), but we highly recommend using an [off-the-shelf adapter](../5-packages.md#-message-queue-adapters) (if the messaging solution that you use does not have an adapter yet, feel free to create/upvote an issue, or contribute 🤗). +You can code your own `MessageQueueAdapter` (simply implement the `MessageChannelAdapter` interface), but we highly recommend using an [off-the-shelf adapter](../4-packages.md#-message-queue-adapters) (if the messaging solution that you use does not have an adapter yet, feel free to create/upvote an issue, or contribute 🤗). ::: diff --git a/docs/docs/4-reacting-to-events/3-message-buses.md b/docs/docs/3-reacting-to-events/3-message-buses.md similarity index 98% rename from docs/docs/4-reacting-to-events/3-message-buses.md rename to docs/docs/3-reacting-to-events/3-message-buses.md index 7c83ce23..f9a1b66a 100644 --- a/docs/docs/4-reacting-to-events/3-message-buses.md +++ b/docs/docs/3-reacting-to-events/3-message-buses.md @@ -53,7 +53,7 @@ await messageBus.publishMessage(...); :::info -You can code your own `MessageBusAdapter` (simply implement the `MessageChannelAdapter` interface), but we highly recommend using an [off-the-shelf adapter](../5-packages.md#-message-buses-adapters) (if the messaging solution that you use is missing, feel free to create/upvote an issue, or contribute 🤗). +You can code your own `MessageBusAdapter` (simply implement the `MessageChannelAdapter` interface), but we highly recommend using an [off-the-shelf adapter](../4-packages.md#-message-buses-adapters) (if the messaging solution that you use is missing, feel free to create/upvote an issue, or contribute 🤗). ::: diff --git a/docs/docs/4-reacting-to-events/4-connected-event-store.md b/docs/docs/3-reacting-to-events/4-connected-event-store.md similarity index 100% rename from docs/docs/4-reacting-to-events/4-connected-event-store.md rename to docs/docs/3-reacting-to-events/4-connected-event-store.md diff --git a/docs/docs/4-reacting-to-events/5-snapshots.md b/docs/docs/3-reacting-to-events/5-snapshots.md similarity index 100% rename from docs/docs/4-reacting-to-events/5-snapshots.md rename to docs/docs/3-reacting-to-events/5-snapshots.md diff --git a/docs/docs/4-reacting-to-events/6-read-models.md b/docs/docs/3-reacting-to-events/6-read-models.md similarity index 100% rename from docs/docs/4-reacting-to-events/6-read-models.md rename to docs/docs/3-reacting-to-events/6-read-models.md diff --git a/docs/docs/4-reacting-to-events/_category_.json b/docs/docs/3-reacting-to-events/_category_.json similarity index 69% rename from docs/docs/4-reacting-to-events/_category_.json rename to docs/docs/3-reacting-to-events/_category_.json index a1ef477c..df2c4186 100644 --- a/docs/docs/4-reacting-to-events/_category_.json +++ b/docs/docs/3-reacting-to-events/_category_.json @@ -1,4 +1,4 @@ { "label": "Reacting to events", - "position": 4 + "position": 3 } diff --git a/docs/docs/5-packages.md b/docs/docs/4-packages.md similarity index 99% rename from docs/docs/5-packages.md rename to docs/docs/4-packages.md index 37c8d944..2343927e 100644 --- a/docs/docs/5-packages.md +++ b/docs/docs/4-packages.md @@ -1,5 +1,5 @@ --- -sidebar_position: 5 +sidebar_position: 4 --- # Packages diff --git a/docs/src/pages/Home/Description.tsx b/docs/src/pages/Home/Description.tsx index 2f52fa35..950c217c 100644 --- a/docs/src/pages/Home/Description.tsx +++ b/docs/src/pages/Home/Description.tsx @@ -34,7 +34,7 @@ export const Description = (): JSX.Element => ( ...well, not anymore 💪

👉 Get Started diff --git a/docs/src/pages/Home/TopLinks.tsx b/docs/src/pages/Home/TopLinks.tsx index 28402ac7..4f6f859b 100644 --- a/docs/src/pages/Home/TopLinks.tsx +++ b/docs/src/pages/Home/TopLinks.tsx @@ -14,7 +14,7 @@ const links: Link[] = [ Docs
), - to: './docs/introduction', + to: './docs/installation', }, { id: 'github', From b5e8e282859abe1c62a9f870caf8380358b9bd40 Mon Sep 17 00:00:00 2001 From: Thomas Aribart Date: Fri, 22 Sep 2023 19:03:23 +0200 Subject: [PATCH 4/5] improve code color --- docs/docusaurus.config.js | 147 +++----------------------------------- docs/package.json | 2 +- yarn.lock | 2 +- 3 files changed, 12 insertions(+), 139 deletions(-) diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index fdabb9d2..baa64aa1 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -2,6 +2,14 @@ // @ts-check // Note: type annotations allow type checking and IDEs autocompletion +const lightCodeTheme = require('prism-react-renderer/themes/vsLight'); +const darkCodeTheme = require('prism-react-renderer/themes/vsDark'); + +// @ts-expect-error bad typing +lightCodeTheme.plain.backgroundColor = '#f8f8f8'; +// @ts-expect-error bad typing +darkCodeTheme.plain.backgroundColor = '#242424'; + /** @type {import('@docusaurus/types').Config} */ const config = { title: 'Castore', @@ -75,143 +83,8 @@ const config = { ], }, prism: { - theme: { - plain: { - color: '#393A34', - backgroundColor: '#f6f8fa', - }, - styles: [ - { - types: ['comment', 'prolog', 'doctype', 'cdata'], - style: { - color: '#999988', - fontStyle: 'italic', - }, - }, - { - types: ['namespace'], - style: { - opacity: 0.7, - }, - }, - { - types: ['string', 'attr-value'], - style: { - color: '#e3116c', - }, - }, - { - types: ['punctuation', 'operator'], - style: { - color: '#393A34', - }, - }, - { - types: [ - 'entity', - 'url', - 'symbol', - 'number', - 'boolean', - 'variable', - 'constant', - 'property', - 'regex', - 'inserted', - ], - style: { - color: '#36acaa', - }, - }, - { - types: ['atrule', 'keyword', 'attr-name', 'selector'], - style: { - color: '#00a4db', - }, - }, - { - types: ['function', 'deleted', 'tag'], - style: { - color: '#d73a49', - }, - }, - { - types: ['function-variable'], - style: { - color: '#6f42c1', - }, - }, - { - types: ['tag', 'selector', 'keyword'], - style: { - color: '#00009f', - }, - }, - ], - }, - darkTheme: { - plain: { - color: '#F8F8F2', - backgroundColor: '#282A36', - }, - styles: [ - { - types: ['prolog', 'constant', 'builtin'], - style: { - color: 'rgb(189, 147, 249)', - }, - }, - { - types: ['inserted', 'function'], - style: { - color: 'rgb(80, 250, 123)', - }, - }, - { - types: ['deleted'], - style: { - color: 'rgb(255, 85, 85)', - }, - }, - { - types: ['changed'], - style: { - color: 'rgb(255, 184, 108)', - }, - }, - { - types: ['punctuation', 'symbol'], - style: { - color: 'rgb(248, 248, 242)', - }, - }, - { - types: ['string', 'char', 'tag', 'selector'], - style: { - color: 'rgb(255, 121, 198)', - }, - }, - { - types: ['keyword', 'variable'], - style: { - color: 'rgb(189, 147, 249)', - fontStyle: 'italic', - }, - }, - { - types: ['comment'], - style: { - color: 'rgb(98, 114, 164)', - }, - }, - { - types: ['attr-name'], - style: { - color: 'rgb(241, 250, 140)', - }, - }, - ], - }, + theme: lightCodeTheme, + darkTheme: darkCodeTheme, }, algolia: { // The application ID provided by Algolia diff --git a/docs/package.json b/docs/package.json index 3891c71b..072f58cf 100644 --- a/docs/package.json +++ b/docs/package.json @@ -43,7 +43,7 @@ "@docusaurus/preset-classic": "2.4.1", "@mdx-js/react": "^1.6.22", "@mui/material": "^5.6.3", - "clsx": "^1.2.1", + "prism-react-renderer": "^1.3.5", "react": "^17.0.2", "react-dom": "^17.0.2", "react-icons": "^4.11.0", diff --git a/yarn.lock b/yarn.lock index 50d793b8..7d740601 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6160,9 +6160,9 @@ __metadata: "@types/react-dom": ^17.0.11 "@types/uuid": ^8.3.4 "@vitejs/plugin-react": ^1.3.2 - clsx: ^1.2.1 dependency-cruiser: ^11.7.0 eslint: ^8.14.0 + prism-react-renderer: ^1.3.5 react: ^17.0.2 react-dom: ^17.0.2 react-icons: ^4.11.0 From ce73afb282713696d4e45bf2e03915bee6270af6 Mon Sep 17 00:00:00 2001 From: Thomas Aribart Date: Fri, 22 Sep 2023 19:24:08 +0200 Subject: [PATCH 5/5] merge Home files in single file --- docs/src/pages/Home/BulletPoints.tsx | 88 ----- docs/src/pages/Home/Description.tsx | 43 --- docs/src/pages/Home/Footer.tsx | 40 -- docs/src/pages/Home/Home.tsx | 29 -- docs/src/pages/Home/Logo.tsx | 282 -------------- docs/src/pages/Home/Title.tsx | 14 - docs/src/pages/Home/TopLinks.tsx | 75 ---- docs/src/pages/Home/index.tsx | 1 - docs/src/pages/index.tsx | 537 ++++++++++++++++++++++++++- 9 files changed, 536 insertions(+), 573 deletions(-) delete mode 100644 docs/src/pages/Home/BulletPoints.tsx delete mode 100644 docs/src/pages/Home/Description.tsx delete mode 100644 docs/src/pages/Home/Footer.tsx delete mode 100644 docs/src/pages/Home/Home.tsx delete mode 100644 docs/src/pages/Home/Logo.tsx delete mode 100644 docs/src/pages/Home/Title.tsx delete mode 100644 docs/src/pages/Home/TopLinks.tsx delete mode 100644 docs/src/pages/Home/index.tsx diff --git a/docs/src/pages/Home/BulletPoints.tsx b/docs/src/pages/Home/BulletPoints.tsx deleted file mode 100644 index ff53f96e..00000000 --- a/docs/src/pages/Home/BulletPoints.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import React from 'react'; -import { BsStars } from 'react-icons/bs'; -import { FaPuzzlePiece, FaHandHoldingHeart } from 'react-icons/fa'; - -export const BulletPoints = (): JSX.Element => ( -
-
- -
-

Stack Agnostic

-

- Castore is in TypeScript. Outside from that, it can - be used pretty much anywhere: React apps, containers, - Lambdas... you name it 🙌 -

-

- For instance, EventStore classes are{' '} - stack agnostic: They need an{' '} - EventStorageAdapter class to interact with actual data. -

-

- You can code your own EventStorageAdapter (simply - implement the interface), but it's much simpler to use off-the-shelf - adapters like the{' '} - - DynamoDBEventStorageAdapter - - . -

-
-
-
- -
-

- Modular & Type-safe -

-

- Castore is a{' '} - collection of utility classes and helpers, but NOT a - framework: While some classes require compatible infrastructure, - Castore is not responsible for deploying it. -

-

- Though that is not something we exclude in the future, we are a small - team and decided to focus on DevX first. -

-

- Speaking of DevX, we absolutely love TypeScript! If you do too, you're - in the right place: We push type-safety to the limit{' '} - in everything we do! -

-
-
-
- -
-

- Comprehensive -

-

- The Event Sourcing journey has many hidden pitfalls.{' '} - We ran into them for you! -

-

- Castore is opiniated. It comes with a collection of best practices and - documented anti-patterns that we hope will help you out! -

-

- It also comes with an awesome collection of packages that will make - your life easy, e.g. when working on{' '} - - unit tests - - ,{' '} - - data migration - {' '} - or{' '} - - data modelling - - . -

-
-
-
-); diff --git a/docs/src/pages/Home/Description.tsx b/docs/src/pages/Home/Description.tsx deleted file mode 100644 index 950c217c..00000000 --- a/docs/src/pages/Home/Description.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import Link from '@docusaurus/Link'; -import React from 'react'; - -export const Description = (): JSX.Element => ( - <> -

- - Event sourcing - {' '} - made easy -

-

- - Event Sourcing - {' '} - is a data storage paradigm that saves{' '} - changes in your application state rather than the state - itself. -

-

- It is powerful as it enables{' '} - rewinding to a previous state and{' '} - exploring audit trails for debugging or business/legal - purposes. It also integrates very well with{' '} - - event-driven architectures - - . -

-

- However, it is tricky to implement 😅 -

-

- ...well, not anymore 💪 -

- - 👉 Get Started - - -); diff --git a/docs/src/pages/Home/Footer.tsx b/docs/src/pages/Home/Footer.tsx deleted file mode 100644 index a5634f5a..00000000 --- a/docs/src/pages/Home/Footer.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import Link from '@docusaurus/Link'; -import React from 'react'; - -const footerLinks = [ - { - label: 'Theodo', - to: 'https://www.theodo.fr/', - }, - { - label: 'Serverless by Theodo', - to: 'https://dev.to/slsbytheodo', - }, - { - label: '@ThomasAribart Twitter', - to: 'https://twitter.com/aribartt', - }, -]; - -export const Footer = (): JSX.Element => ( -
-
-
- {footerLinks.map(item => ( -
- {item.to.startsWith('http') ? ( - - {item.label} - - ) : ( - {item.label} - )} -
- ))} -
-
- © {new Date().getFullYear()} Serverless by Theodo -
-
-
-); diff --git a/docs/src/pages/Home/Home.tsx b/docs/src/pages/Home/Home.tsx deleted file mode 100644 index 790c11d4..00000000 --- a/docs/src/pages/Home/Home.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import Head from '@docusaurus/Head'; -import React from 'react'; - -import { BulletPoints } from './BulletPoints'; -import { Description } from './Description'; -import { Footer } from './Footer'; -import { Title } from './Title'; -import { TopLinks } from './TopLinks'; - -export const Home = (): JSX.Element => ( - <> - - Castore | Event sourcing made easy - - -
- -
- - <Description /> - </div> - <BulletPoints /> - </div> - <Footer /> - </> -); diff --git a/docs/src/pages/Home/Logo.tsx b/docs/src/pages/Home/Logo.tsx deleted file mode 100644 index 251d60b9..00000000 --- a/docs/src/pages/Home/Logo.tsx +++ /dev/null @@ -1,282 +0,0 @@ -/* eslint-disable max-lines */ -import React from 'react'; - -export const Logo = (props: React.HTMLProps<HTMLDivElement>): JSX.Element => ( - <div {...props}> - <svg - version="1.1" - id="Layer_1" - xmlns="http://www.w3.org/2000/svg" - x="0px" - y="0px" - viewBox="0 0 852 852" - enableBackground="new 0 0 852 852" - > - <title>Castore Logo - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-); diff --git a/docs/src/pages/Home/Title.tsx b/docs/src/pages/Home/Title.tsx deleted file mode 100644 index ac5ac504..00000000 --- a/docs/src/pages/Home/Title.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; - -import { Logo } from './Logo'; - -export const Title = (): JSX.Element => ( -
- -

- - Castore - -

-
-); diff --git a/docs/src/pages/Home/TopLinks.tsx b/docs/src/pages/Home/TopLinks.tsx deleted file mode 100644 index 4f6f859b..00000000 --- a/docs/src/pages/Home/TopLinks.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import Link from '@docusaurus/Link'; -import React from 'react'; -import { FaRegCopy, FaGithub, FaHeart } from 'react-icons/fa'; -import { MdOutlineImportContacts } from 'react-icons/md'; -import { SlSpeech } from 'react-icons/sl'; - -type Link = { id: string; label: JSX.Element; to: string }; - -const links: Link[] = [ - { - id: 'docs', - label: ( -
- Docs -
- ), - to: './docs/installation', - }, - { - id: 'github', - label: ( -
- GitHub -
- ), - to: 'https://github.com/castore-dev/castore', - }, - { - id: 'examples', - label: ( -
- Examples -
- ), - to: 'https://github.com/castore-dev/castore/tree/main/demo/blueprint/src', - }, - { - id: 'sponsor', - label: ( -
- Sponsor -
- ), - to: 'https://github.com/sponsors/ThomasAribart', - }, - { - id: 'contact', - label: ( -
- Contact -
- ), - to: 'mailto:thomasa@theodo.fr', - }, -]; - -export const TopLinks = (): JSX.Element => ( -
- {links.map(({ id, label, to }) => { - const children = ( -
{label}
- ); - - return ( -
- {to.startsWith('http') || to.startsWith('mailto') ? ( - {children} - ) : ( - {children} - )} -
- ); - })} -
-); diff --git a/docs/src/pages/Home/index.tsx b/docs/src/pages/Home/index.tsx deleted file mode 100644 index af9c1c67..00000000 --- a/docs/src/pages/Home/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { Home } from './Home'; diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx index ca43e262..49737380 100644 --- a/docs/src/pages/index.tsx +++ b/docs/src/pages/index.tsx @@ -1,3 +1,538 @@ -import { Home } from './Home'; +/* eslint-disable max-lines */ +import Head from '@docusaurus/Head'; +import Link from '@docusaurus/Link'; +import React from 'react'; +import { BsStars } from 'react-icons/bs'; +import { + FaRegCopy, + FaGithub, + FaHeart, + FaPuzzlePiece, + FaHandHoldingHeart, +} from 'react-icons/fa'; +import { MdOutlineImportContacts } from 'react-icons/md'; +import { SlSpeech } from 'react-icons/sl'; + +type Link = { id: string; label: JSX.Element; to: string }; + +const links: Link[] = [ + { + id: 'docs', + label: ( +
+ Docs +
+ ), + to: './docs/installation', + }, + { + id: 'github', + label: ( +
+ GitHub +
+ ), + to: 'https://github.com/castore-dev/castore', + }, + { + id: 'examples', + label: ( +
+ Examples +
+ ), + to: 'https://github.com/castore-dev/castore/tree/main/demo/blueprint/src', + }, + { + id: 'sponsor', + label: ( +
+ Sponsor +
+ ), + to: 'https://github.com/sponsors/ThomasAribart', + }, + { + id: 'contact', + label: ( +
+ Contact +
+ ), + to: 'mailto:thomasa@theodo.fr', + }, +]; + +const footerLinks = [ + { + label: 'Theodo', + to: 'https://www.theodo.fr/', + }, + { + label: 'Serverless by Theodo', + to: 'https://dev.to/slsbytheodo', + }, + { + label: '@ThomasAribart Twitter', + to: 'https://twitter.com/aribartt', + }, +]; + +const Home = (): JSX.Element => ( + <> + + Castore | Event sourcing made easy + + +
+
+ {links.map(({ id, label, to }) => { + const children = ( +
{label}
+ ); + + return ( +
+ {to.startsWith('http') || to.startsWith('mailto') ? ( + {children} + ) : ( + {children} + )} +
+ ); + })} +
+
+
+
+ + Castore Logo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ + Castore + +

+
+

+ + Event sourcing + {' '} + made easy +

+

+ + Event Sourcing + {' '} + is a data storage paradigm that saves{' '} + changes in your application state rather than the + state itself. +

+

+ It is powerful as it enables{' '} + rewinding to a previous state and{' '} + exploring audit trails for debugging or + business/legal purposes. It also integrates very well with{' '} + + event-driven architectures + + . +

+

+ However, it is tricky to implement 😅 +

+

+ ...well, not anymore 💪 +

+ + 👉 Get Started + +
+
+
+ +
+

Stack Agnostic

+

+ Castore is in TypeScript. Outside from that, it + can be used pretty much anywhere: React apps, + containers, Lambdas... you name it 🙌 +

+

+ For instance, EventStore classes are{' '} + stack agnostic: They need an{' '} + EventStorageAdapter class to interact with actual + data. +

+

+ You can code your own EventStorageAdapter (simply + implement the interface), but it's much simpler to use + off-the-shelf adapters like the{' '} + + DynamoDBEventStorageAdapter + + . +

+
+
+
+ +
+

+ Modular & Type-safe +

+

+ Castore is a{' '} + collection of utility classes and helpers, but + NOT a framework: While some classes require compatible + infrastructure, Castore is not responsible for deploying it. +

+

+ Though that is not something we exclude in the future, we are a + small team and decided to focus on DevX first. +

+

+ Speaking of DevX, we absolutely love TypeScript! If you do too, + you're in the right place: We{' '} + push type-safety to the limit in everything we + do! +

+
+
+
+ +
+

+ Comprehensive +

+

+ The Event Sourcing journey has many hidden pitfalls.{' '} + We ran into them for you! +

+

+ Castore is opiniated. It comes with a collection of best practices + and documented anti-patterns that we hope will help you out! +

+

+ It also comes with an awesome collection of packages that will + make your life easy, e.g. when working on{' '} + + unit tests + + ,{' '} + + data migration + {' '} + or{' '} + + data modelling + + . +

+
+
+
+
+
+
+
+ {footerLinks.map(item => ( +
+ {item.to.startsWith('http') ? ( + + {item.label} + + ) : ( + {item.label} + )} +
+ ))} +
+
+ © {new Date().getFullYear()} Serverless by Theodo +
+
+
+ +); export default Home;