refactor: remove useless code from starter project + yarn add fastify-git-server@@ -1,4 +1,5 @@
-# COOKIE_NAME="fake"
-# DEPLOYMENT_DOMAIN="fake"
-# DEPLOYMENT_SCHEME="fake"
-# COOKIE_SECRET="fake"
+# COOKIE_NAME='fake'
+# COOKIE_SECRET='fake'
+# DEPLOYMENT_DOMAIN='fake'
+# DEPLOYMENT_SCHEME='fake'
+# GIT_REPOSITORIES_ROOT='fake'
@@ -1,14 +1,8 @@
{
- "_generatedAtUnix": 1662851607522,
+ "_generatedAtUnix": 1662913620980,
"_hashAlgorithm": "sha1",
"_version": 2,
"islands": {
- "Counter": {
- "hash": "1a47f269e78e467e9f5ed803e037d4ee3deccfe2",
- "pathSource": "./app/islands/Counter.tsx",
- "pathBundle": "./public/.islands/Counter.bundle.js",
- "pathSourceMap": "./public/.islands/Counter.bundle.js.map"
- },
"InstantRouterIndicator": {
"hash": "89c6f145dfed92e98a03b22596fed9c852792ee9",
"pathSource": "./app/islands/InstantRouterIndicator.tsx",
@@ -24,7 +18,7 @@
},
"views": {
"DocHomeView": {
- "hash": "c4b04c9c09d88ea32bf7595c1a105e168d07c660",
+ "hash": "82b1841cde408e5bb5f85b457d58185f46a27263",
"pathSource": "./app/views/DocHomeView.tsx"
},
"DocPageView": {
@@ -32,7 +26,7 @@
"pathSource": "./app/views/DocPageView.tsx"
},
"HomeView": {
- "hash": "3a4d7b139d89afe9274ebd2f3ecf0a6f010e8c94",
+ "hash": "220c689add1c039287faae6e7d2b678c13a8d0ba",
"pathSource": "./app/views/HomeView.tsx"
},
"InternalErrorView": {
@@ -1,129 +0,0 @@
-import React, { VFC } from "react";
-import styled, { css } from "styled-components";
-
-import type { AppThemeScheme, WithThemeSchemeProp } from "../types";
-import { Card } from "./Card.styled";
-import { ChevronRightIcon } from "./icons";
-import { NamedColors } from "../utils/style";
-
-interface DocSectionEntryCardProps {
- coverImageUrl: string;
- href: string;
- summary: string;
- themeScheme: AppThemeScheme;
- title: string;
-}
-
-export const DocSectionEntryCard: VFC<DocSectionEntryCardProps> = ({
- coverImageUrl,
- href,
- summary,
- themeScheme,
- title,
-}) => {
- return (
- <StyledDocSectionEntryCard themeScheme={themeScheme}>
- <StyledDocSectionEntryLink href={href} title={title}>
- <StyledCoverImage src={coverImageUrl} themeScheme={themeScheme} />
- <StyledTitleRow themeScheme={themeScheme}>
- <h2>{title}</h2>
- <ChevronRightIcon />
- </StyledTitleRow>
- <StyledSummaryText themeScheme={themeScheme}>
- {summary}
- </StyledSummaryText>
- </StyledDocSectionEntryLink>
- </StyledDocSectionEntryCard>
- );
-};
-
-const StyledDocSectionEntryCard = styled(Card)`
- flex: 1;
- min-width: 350px;
- max-width: 100%;
- min-height: 395px;
-
- transition: transform 180ms ease-in-out 0s;
-
- &:hover {
- transform: translateY(-6px);
-
- & h2 {
- text-decoration: underline;
- }
- }
-`;
-
-const StyledDocSectionEntryLink = styled.a`
- height: 100%;
- width: 100%;
-
- text-decoration: unset;
- color: unset;
-`;
-
-const StyledCoverImage = styled.div<WithThemeSchemeProp & { src: string }>`
- width: 100%;
- min-height: 175px;
- height: 175px;
- max-height: 175px;
-
- ${({ src, themeScheme }) => css`
- background-color: ${NamedColors.CARD_OVERLAY[themeScheme]};
- background-image: url("${src}");
- background-position: center center;
- background-repeat: no-repeat;
- background-size: cover;
- `};
-
- appearance: none;
- border-image: none;
- border: none;
- border-color: transparent;
- border-radius: 8px;
- outline: none;
- overflow: hidden;
-`;
-
-const StyledTitleRow = styled.div<WithThemeSchemeProp>`
- display: flex;
- flex-flow: row nowrap;
- justify-content: center;
- align-items: center;
-
- margin-top: 20px;
-
- & > h2 {
- flex: 1;
- margin: 0;
- }
-
- & > div[aria-roledescription="icon"] {
- display: flex;
- flex-flow: row nowrap;
- justify-content: center;
- align-items: center;
-
- min-width: 32px;
- width: 32px;
- max-width: 32px;
- min-height: 32px;
- height: 32px;
- max-height: 32px;
-
- ${({ themeScheme }) => css`
- background-color: ${NamedColors.CARD_OVERLAY[themeScheme]};
- color: ${NamedColors.TEXT_DEFAULT[themeScheme]};
- `};
-
- border-radius: ${32 / 2}px;
- }
-`;
-
-const StyledSummaryText = styled.p<WithThemeSchemeProp>`
- line-height: 24px;
-
- ${({ themeScheme }) => css`
- color: ${NamedColors.TEXT_MUTED[themeScheme]};
- `};
-`;
@@ -7,8 +7,6 @@ import type { AppThemeScheme, WithThemeSchemeProp } from "../types";
import { Card } from "./Card.styled";
import { NamedColors } from "../utils/style";
-import Counter from "../islands/Counter";
-
type MarkdownToJsxProps = {
themeScheme: AppThemeScheme;
markdown: string;
@@ -74,9 +72,6 @@ export const MarkdownToJsx: VFC<MarkdownToJsxProps> = ({
{children}
</li>
),
- Counter: ({ defaultValue = 0 }) => (
- <Counter defaultValue={parseInt(defaultValue, 10)} />
- ),
ImageWithTheme: ({
alt,
lightSrc,
@@ -3,14 +3,13 @@ import React, { VFC } from "react";
import styled, { css } from "styled-components";
// app
import type { WithThemeSchemeProp } from "../types";
+import { Const } from "../const";
import { NamedColors } from "../utils/style";
-import { ReactMonolithLogo } from "./icons";
+// import { ReactMonolithLogo } from "./icons";
-interface PageHeaderProps {
- currentModule?: "documentation" | "api-reference" | "blueprints";
-}
+interface PageHeaderProps {}
-const REACT_MONOLITH_LOGO_SIZE = 36;
+// const LOGO_HEIGHT = 36;
const SIDE_MENU_WIDTH = 320;
export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
@@ -21,25 +20,13 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
<StyledPageHeader themeScheme={themeScheme}>
<StyledLogoArea themeScheme={themeScheme}>
<a href={"/"}>
- <ReactMonolithLogo size={REACT_MONOLITH_LOGO_SIZE} />
- <h1 style={{ margin: 0, marginLeft: 20 }}>React Monolith</h1>
+ {/*<ReactMonolithLogo size={LOGO_HEIGHT} />*/}
+ <h1 style={{ margin: 0, marginLeft: 20 }}>{Const.APP_NAME}</h1>
</a>
</StyledLogoArea>
<StyledPageHeaderNav>
- <a aria-label={"Documentation"} href={"/docs"}>
- Documentation
- </a>
- <a aria-label={"API Reference"} href={"/api-reference"}>
- API Reference
- </a>
- <a aria-label={"Blueprints"} href={"/blueprints"}>
- Blueprints
- </a>
- <a aria-label={"Playground"} href={"/playground"}>
- Playground
- </a>
- <a aria-label={"Contribute"} href={"/contribute"}>
- Contribute
+ <a aria-label={"Explore Projects"} href={"/explore/projects"}>
+ Explore Projects
</a>
</StyledPageHeaderNav>
<StyledActionsArea>
@@ -52,6 +39,12 @@ export const PageHeader: VFC<PageHeaderProps & WithThemeSchemeProp> = ({
>
{`${themeScheme === "light" ? "Dark" : "Light"} mode`}
</a>
+ <a aria-label={"Register a new account"} href={"/auth/register"}>
+ Register
+ </a>
+ <a aria-label={"Login to your account"} href={"/auth/login"}>
+ Login
+ </a>
</StyledActionsArea>
</StyledPageHeader>
);
@@ -1,6 +1,6 @@
export { Button, ButtonAnchor } from "./Button.styled";
export { Card } from "./Card.styled";
-export { DocSectionEntryCard } from "./DocSectionEntryCard";
+export * as Icons from "./icons";
export { Layout } from "./Layout";
export { MarkdownToJsx } from "./MarkdownToJsx";
export { MenuItem } from "./MenuItem";
@@ -1,3 +1,5 @@
+// beware to imports in this file, they must work in both server/client sides.
+
import type { AppThemeScheme, SectionsPagesIndex } from "./types";
type Const = {
@@ -10,7 +12,7 @@ type Const = {
};
export const Const: Const = {
- APP_NAME: "React Monolith",
+ APP_NAME: "GitFOSS",
DEFAULT_THEME_SCHEME: "dark",
SSR_CACHE_MAX_SIZE_BYTES: 50_000_000, // 50Mb in bytes
// TODO(refactor): all of this will move into folder/index.yml
@@ -1,140 +0,0 @@
-// 1st-party
-import { HeadTag } from "@ethicdevs/fastify-stream-react-views";
-import { ReqHandler } from "@ethicdevs/react-monolith";
-// app
-import type { Page, SectionsWithPages } from "../types";
-import { Const } from "../const";
-import { Env } from "../env";
-import { getDocFileContent } from "../utils/server";
-import { makeSectionsService } from "../services/SectionsService";
-
-import DocHomeView, { DocHomeViewProps } from "../views/DocHomeView";
-import DocPageView, { DocPageViewProps } from "../views/DocPageView";
-
-export const getDocHomeView: ReqHandler = async (request, reply) => {
- const reqHandler = reply.makeRequestHandler(request, reply);
- return reqHandler<DocHomeViewProps>(DocHomeView.name, {
- title: "Documentation",
- });
-};
-
-export const reloadDocsEndpoint: ReqHandler = async (request, reply) => {
- // Reload content data in memory
- const sectionsWithPages: SectionsWithPages = await Object.entries(
- Const.SECTIONS_WITH_PAGES
- ).reduce(async (accP, [sectionSlug, sectionPagesSlugs]) => {
- let acc = await accP;
- const pageForSection = await sectionPagesSlugs.reduce(
- async (accP, pageSlug) => {
- const acc = await accP;
- const page = await getDocFileContent(sectionSlug, pageSlug, "md");
- return {
- ...acc,
- [pageSlug]: page,
- };
- },
- Promise.resolve({} as { [pageSlug: string]: Page })
- );
- acc = {
- ...acc,
- [sectionSlug]: {
- slug: sectionSlug,
- title: Const.SECTIONS_TITLES[sectionSlug],
- summary: Const.SECTIONS_SUMMARIES[sectionSlug],
- pagesBySlug: pageForSection,
- },
- };
- return acc;
- }, Promise.resolve({} as SectionsWithPages));
-
- // (for the setter definition @see server.ts)
- request.sectionsWithPages = sectionsWithPages;
-
- return reply.send("OK");
-};
-
-export const getSectionEntrypoint: ReqHandler = async (request, reply) => {
- const { sectionSlug } = request.params as { sectionSlug: string };
-
- const sectionsService = await makeSectionsService(request);
- const section = await sectionsService.getSectionBySlug(sectionSlug);
- const firstPage = await sectionsService.getFirstPage(section);
-
- if (firstPage == null) {
- return reply.redirect(302, `/docs`);
- }
-
- return reply.redirect(302, `/docs/${section.slug}/${firstPage.slug}`);
-};
-
-export const getSectionPageView: ReqHandler = async (request, reply) => {
- const { sectionSlug, pageSlug } = request.params as {
- sectionSlug: string;
- pageSlug: string;
- };
-
- if (pageSlug == null || pageSlug.trim() === "") {
- return reply.redirect(307, `/docs/${sectionSlug}`);
- }
-
- const sectionsService = await makeSectionsService(request);
- const section = await sectionsService.getSectionBySlug(sectionSlug);
-
- if (
- section == null ||
- pageSlug in section.pagesBySlug === false ||
- section.pagesBySlug[pageSlug] == null
- ) {
- return reply.callNotFound();
- }
-
- const page = section.pagesBySlug[pageSlug];
-
- const reqHandler = reply.makeRequestHandler(request, reply);
- return reqHandler<DocPageViewProps>(
- DocPageView.name,
- {
- page,
- title: `${page.metas?.title} / ${section.title}`,
- },
- {
- head: [
- page.metas?.title && {
- kind: "meta",
- name: "title",
- content: page.metas?.title,
- },
- page.metas?.summary && {
- kind: "meta",
- name: "description",
- content: page.metas?.summary,
- },
- {
- kind: "meta",
- name: "og:type",
- content: "article",
- },
- {
- kind: "meta",
- name: "og:url",
- content: `${Env.DEPLOYMENT_SCHEME}://${Env.DEPLOYMENT_DOMAIN}/docs/${section.slug}/${page.slug}`,
- },
- {
- kind: "meta",
- name: "article:section",
- content: section.title,
- },
- page.metas?.title && {
- kind: "meta",
- name: "og:title",
- content: page.metas?.title,
- },
- page.metas?.summary && {
- kind: "meta",
- name: "og:description",
- content: page.metas?.summary,
- },
- ] as HeadTag[],
- }
- );
-};
@@ -12,6 +12,8 @@ export const getHomeView: ReqHandler = async (request, reply) => {
const foo = authService.isExistingUsername("test");
const user = authService.findUserByUid((request.params as any).uid);
+ await authService.validateUserEmailAddress("user-uid", "email@address.tld");
+
// TODO: Create a User model in db where to store user data.
user; // so typescript do not complains about unused variable.
@@ -1,13 +1,13 @@
// std
-import fs from "fs";
-import path from "path";
+import { existsSync } from "node:fs";
+import { join, resolve } from "node:path";
// 3rd-party
import dotEnvFlow from "dotenv-flow";
import { Env as NodeEnv } from "@ethicdevs/react-monolith";
const NODE_ENV = process.env.NODE_ENV;
-const ENV_FILES_DIR = path.resolve(path.join(__dirname, ".."));
+const ENV_FILES_DIR = resolve(join(__dirname, ".."));
const baseOpts = {
node_env: NODE_ENV,
@@ -16,7 +16,7 @@ const baseOpts = {
const files = dotEnvFlow.listDotenvFiles(ENV_FILES_DIR, baseOpts);
function getLoadableFilesDisplay(): string {
- return files.filter((path) => fs.existsSync(path) === true).join("\n * ");
+ return files.filter((path) => existsSync(path) === true).join("\n * ");
}
if (files.length > 0) {
@@ -96,13 +96,22 @@ const getCookieSecret = (cookieSecret?: string | null): string => {
}
return String(cookieSecret);
};
+const getGitRepositoriesRoot = (
+ gitRepositoriesRoot?: string | null
+): string => {
+ if (gitRepositoriesRoot == null || gitRepositoriesRoot === "fake") {
+ throw new Error("[env] GIT_REPOSITORIES_ROOT is missing.");
+ }
+ return String(gitRepositoriesRoot);
+};
interface IEnv {
NODE_ENV: NodeEnv;
COOKIE_NAME: string;
+ COOKIE_SECRET: string;
DEPLOYMENT_DOMAIN: string;
DEPLOYMENT_SCHEME: "http" | "https";
- COOKIE_SECRET: string;
+ GIT_REPOSITORIES_ROOT: string;
}
export const Env: IEnv = {
@@ -111,4 +120,7 @@ export const Env: IEnv = {
COOKIE_SECRET: getCookieSecret(process.env.COOKIE_SECRET),
DEPLOYMENT_DOMAIN: getDeploymentDomain(process.env.DEPLOYMENT_DOMAIN),
DEPLOYMENT_SCHEME: getDeploymentScheme(process.env.DEPLOYMENT_SCHEME),
+ GIT_REPOSITORIES_ROOT: getGitRepositoriesRoot(
+ process.env.GIT_REPOSITORIES_ROOT
+ ),
};
@@ -1,58 +0,0 @@
-import React, { CSSProperties, useCallback, useState } from "react";
-import type { ReactIsland } from "@ethicdevs/react-monolith";
-
-// app
-import { Button } from "../components";
-
-interface CounterProps {
- defaultValue?: number;
-}
-
-const Counter: ReactIsland<CounterProps> = ({ defaultValue = 42 }) => {
- const [counter, setCounter] = useState(defaultValue);
- const incrementCounter = useCallback(
- () => setCounter((prev) => prev + 1),
- [setCounter]
- );
- const decrementCounter = useCallback(
- () => setCounter((prev) => prev - 1),
- [setCounter]
- );
-
- return (
- <div style={styles.counterContainer}>
- <Button
- onClick={decrementCounter}
- type={"button"}
- title={"Click to Decrement"}
- >
- ➖
- </Button>
- <div style={styles.counterText}>{counter}</div>
- <Button
- onClick={incrementCounter}
- type={"button"}
- title={"Click to Increment"}
- >
- ➕
- </Button>
- </div>
- );
-};
-
-const styles: Record<string, CSSProperties> = {
- counterContainer: {
- display: "flex",
- flexFlow: "row nowrap",
- justifyContent: "flex-start",
- alignItems: "center",
- fontFamily: "monospace",
- },
- counterText: {
- padding: 10,
- fontSize: 18,
- fontWeight: "bold",
- },
-};
-
-export default Counter;
@@ -6,69 +6,32 @@ import React from "react";
// app
/* controllers */
import * as HomeController from "./controllers/HomeController";
-import * as DocumentationController from "./controllers/DocumentationController";
import * as ThemeController from "./controllers/ThemeController";
-export enum DocAppRoute {
+export enum AppRoute {
HOME = "home",
- DOCS_HOME = "docs.home",
- DOCS_MANAGE_MEMORY_RELOAD = "docs.mgmt.memory-reload",
- DOCS_SECTION_ENTRY = "docs.section.entry",
- DOCS_SECTION_PAGE = "docs.section.page",
THEME_SET = "theme.set",
}
-export interface DocAppRoutesParams extends IRouteParams {
- [DocAppRoute.HOME]: undefined;
- [DocAppRoute.DOCS_HOME]: undefined;
- [DocAppRoute.DOCS_SECTION_ENTRY]: {
- sectionSlug: string;
- };
- [DocAppRoute.DOCS_SECTION_PAGE]: {
- sectionSlug: string;
- pageSlug: string;
- };
- [DocAppRoute.THEME_SET]: {
+export interface AppRoutesParams extends IRouteParams {
+ [AppRoute.HOME]: undefined;
+ [AppRoute.THEME_SET]: {
themeScheme: string;
};
}
-const DocAppRouter: AppRouter = () => (
+const RootAppRouter: AppRouter = () => (
<Router.Root>
<></>
<Router.Group type={AppRouterGroup.API}>
<Router.Route
- name={DocAppRoute.HOME}
+ name={AppRoute.HOME}
method={"GET"}
path={"/"}
handler={HomeController.getHomeView}
/>
<Router.Route
- name={DocAppRoute.DOCS_MANAGE_MEMORY_RELOAD}
- method={"GET"}
- path={"/docs/mgmt/memory-reload"}
- handler={DocumentationController.reloadDocsEndpoint}
- />
- <Router.Route
- name={DocAppRoute.DOCS_HOME}
- method={"GET"}
- path={"/docs"}
- handler={DocumentationController.getDocHomeView}
- />
- <Router.Route
- name={DocAppRoute.DOCS_SECTION_ENTRY}
- method={"GET"}
- path={"/docs/:sectionSlug"}
- handler={DocumentationController.getSectionEntrypoint}
- />
- <Router.Route
- name={DocAppRoute.DOCS_SECTION_PAGE}
- method={"GET"}
- path={"/docs/:sectionSlug/:pageSlug"}
- handler={DocumentationController.getSectionPageView}
- />
- <Router.Route
- name={DocAppRoute.THEME_SET}
+ name={AppRoute.THEME_SET}
method={"GET"}
path={"/theme/:themeScheme"}
handler={ThemeController.getTheme}
@@ -77,4 +40,4 @@ const DocAppRouter: AppRouter = () => (
</Router.Root>
);
-export default DocAppRouter;
+export default RootAppRouter;
@@ -6,6 +6,7 @@ import {
startAppServer,
stopAppServerAndExit,
} from "@ethicdevs/react-monolith";
+import fastifyGitServer, { GitServer } from "@ethicdevs/fastify-git-server";
// 3rd-party
import fastifyCookie, { CookieSerializeOptions } from "@fastify/cookie";
import fastifyServeStatic from "fastify-static";
@@ -19,6 +20,7 @@ import {
localAppDomainPreHandler,
makeRequestHandler,
} from "./utils/server";
+import { join, resolve } from "node:path";
const HOST = process.env.HOST || "localhost";
const PORT = process.env.PORT || 4100;
@@ -107,16 +109,37 @@ async function main(): Promise<AppServer> {
parseOptions: cookiesOpts,
});
+ s.register(fastifyGitServer, {
+ async authorize(repoSlug, { username, password }) {
+ const [org, repo] = repoSlug.split("/");
+ return (
+ org === "wnemencha" &&
+ repo === "react-monolith-samples" &&
+ username === "wnemencha" &&
+ password === "secret"
+ );
+ },
+ async repositoryResolver(repoSlug) {
+ const [org, repo] = repoSlug.split("/");
+ return {
+ authMode: GitServer.AuthMode.ALWAYS,
+ gitRepositoryDir: resolve(
+ join(Env.GIT_REPOSITORIES_ROOT, org, repo)
+ ),
+ };
+ },
+ });
+
s.decorateReply("makeRequestHandler", makeRequestHandler);
- },
- });
- server.get("/interceptor-imsw.js", {}, async (_, reply) => {
- return reply.sendFile("interceptor-imsw.js");
- });
+ s.get("/interceptor-imsw.js", {}, async (_, reply) => {
+ return reply.sendFile("interceptor-imsw.js");
+ });
- server.get("/register-imsw.js", {}, async (_, reply) => {
- return reply.sendFile("register-imsw.js");
+ s.get("/register-imsw.js", {}, async (_, reply) => {
+ return reply.sendFile("register-imsw.js");
+ });
+ },
});
await startAppServer(server);
@@ -1,8 +1,7 @@
import type { AuthServiceDeps } from "./types";
-export function makeCompareUserPasswordHashes(deps: AuthServiceDeps) {
+export function makeCompareUserPasswordHashes(_: AuthServiceDeps) {
const compareUserPasswordHashes = (a: string, b: string) => {
- deps.request.id;
return a === b;
};
@@ -1,17 +1,16 @@
+// 1st-party
+import { makeService } from "@ethicdevs/react-monolith";
+// app
import type { AuthServiceAPI, AuthServiceDeps } from "./types";
-
import { makeCompareUserPasswordHashes } from "./compareUserPasswordHashes";
import { makeIsExistingUsername } from "./makeIsExistingUsername";
-export const makeAuthService: ServiceFactory<AuthServiceAPI, AuthServiceDeps> =
- (dependencies) => {
- return withDependencies<AuthServiceAPI, AuthServiceDeps>(dependencies, {
- compareUserPasswordHashes: makeCompareUserPasswordHashes,
- isExistingUsername: makeIsExistingUsername,
- isExistingUserUid: () => () => undefined,
- findUserByUid: () => () => undefined,
- findUserByUsername: () => () => undefined,
- sendUserEmailAddressV8nEmail: () => () => undefined,
- validateUserEmailAddress: () => () => undefined,
- });
- };
+export const makeAuthService = makeService<AuthServiceAPI, AuthServiceDeps>({
+ compareUserPasswordHashes: makeCompareUserPasswordHashes,
+ isExistingUsername: makeIsExistingUsername,
+ isExistingUserUid: () => () => undefined,
+ findUserByUid: () => () => undefined,
+ findUserByUsername: () => () => undefined,
+ sendUserEmailAddressV8nEmail: () => () => undefined,
+ validateUserEmailAddress: () => () => Promise.resolve(undefined),
+});
@@ -1,13 +1,25 @@
+import { FastifyRequest } from "fastify";
+import {
+ ServiceApiContract,
+ ServiceDependencies,
+} from "@ethicdevs/react-monolith";
+
export interface AuthServiceAPI extends ServiceApiContract {
- compareUserPasswordHashes: (a: string, b: string) => boolean;
- isExistingUsername: (username: string) => boolean;
- isExistingUserUid: (userUid: string) => boolean;
- findUserByUsername: (username: string) => void;
- findUserByUid: (userUid: string) => void;
- sendUserEmailAddressV8nEmail: (args: unknown[]) => void;
- validateUserEmailAddress: (userUid: string, emailAddress: string) => void;
+ compareUserPasswordHashes(a: string, b: string): boolean;
+ isExistingUsername(username: string): boolean;
+ isExistingUserUid(userUid: string): boolean;
+ findUserByUsername(username: string): void;
+ findUserByUid(userUid: string): void;
+ sendUserEmailAddressV8nEmail(args: unknown[]): void;
+ validateUserEmailAddress(
+ userUid: string,
+ emailAddress: string
+ ): Promise<void>;
}
export interface AuthServiceDeps extends ServiceDependencies {
+ // i.e. to access request decorators, one may pass request as a dependency
+ // to this service and all the methods within it would have access to
+ // a reference to it (i.e; database, cache, another service, etc...)
request: FastifyRequest;
}
@@ -1,53 +0,0 @@
-// TODO: extract the services things into its own package
-
-type ServiceApiContract = Record<string, ServiceMethod>;
-type ServiceDependencies = Record<string, any>;
-
-type ServiceMethod<
- Args extends any[] = any[],
- Return extends unknown = unknown
-> = (...args: Args) => Return;
-
-interface ServiceMethodFactory<
- Deps extends ServiceDependencies = ServiceDependencies,
- Args extends any[] = any[],
- Return extends unknown = unknown
-> {
- (deps: Deps): ServiceMethod<Args, Return>;
-}
-
-type Service<ApiContract extends ServiceApiContract = ServiceApiContract> =
- ApiContract;
-
-interface ServiceFactory<
- ApiContract extends ServiceApiContract,
- ServiceDeps extends ServiceDependencies = ServiceDependencies
-> {
- (deps: ServiceDeps): Service<ApiContract>;
-}
-
-function withDependencies<
- ApiContract extends ServiceApiContract,
- Deps extends ServiceDependencies = ServiceDependencies,
- InjectableMethods extends Record<string, ServiceMethodFactory<Deps>> = Record<
- string,
- ServiceMethodFactory<Deps>
- >
- //InjectedMethods extends {
- // [K in keyof InjectableMethods]: ReturnType<InjectableMethods[K]>;
- //} = { [K in keyof InjectableMethods]: ReturnType<InjectableMethods[K]> }
->(
- dependencies: Deps,
- injectableMethods: InjectableMethods
-): Service<ApiContract> {
- const methodsEntries = Object.entries(injectableMethods);
- const service = methodsEntries.reduce((apiContractAcc, [name, factoryFn]) => {
- apiContractAcc = {
- ...apiContractAcc,
- [name]: factoryFn(dependencies),
- };
- return apiContractAcc;
- }, {} as Service<ApiContract>);
-
- return service;
-}
@@ -1,6 +1,10 @@
import { default as Colors } from "./Colors";
const NamedColors = {
+ BACKGROUND: {
+ light: Colors.GRAY_LIGHT_05,
+ dark: Colors.BLACK_01,
+ },
BORDER_DEFAULT: {
dark: Colors.GRAY_DARK_02,
light: Colors.GRAY_LIGHT_02,
@@ -9,26 +13,10 @@ const NamedColors = {
dark: Colors.GRAY_LIGHT_04,
light: Colors.GRAY_LIGHT_02,
},
- TEXT_DEFAULT: {
- light: Colors.BLACK_01,
- dark: Colors.WHITE_01,
- },
- TEXT_MUTED: {
- light: Colors.GRAY_LIGHT_06,
- dark: Colors.GRAY_DARK_06,
- },
- TEXT_LINK: {
- light: Colors.CYAN_01,
- dark: Colors.CYAN_01,
- },
BRAND_LINE: {
light: Colors.PRIMARY_01,
dark: Colors.PRIMARY_01,
},
- BACKGROUND: {
- light: Colors.GRAY_LIGHT_01,
- dark: Colors.GRAY_DARK_01,
- },
CARD: {
dark: Colors.GRAY_DARK_02,
light: Colors.WHITE_01,
@@ -39,7 +27,7 @@ const NamedColors = {
},
HEADER: {
light: Colors.WHITE_01,
- dark: Colors.BLACK_01,
+ dark: Colors.GRAY_DARK_05,
},
SIDE_MENU: {
light: Colors.WHITE_01,
@@ -57,6 +45,18 @@ const NamedColors = {
light: Colors.GRAY_LIGHT_03,
dark: Colors.GRAY_DARK_04,
},
+ TEXT_DEFAULT: {
+ light: Colors.BLACK_01,
+ dark: Colors.WHITE_01,
+ },
+ TEXT_MUTED: {
+ light: Colors.GRAY_LIGHT_06,
+ dark: Colors.GRAY_DARK_06,
+ },
+ TEXT_LINK: {
+ light: Colors.CYAN_01,
+ dark: Colors.CYAN_01,
+ },
};
export default NamedColors;
@@ -5,7 +5,7 @@ import styled from "styled-components";
// app
import type { CommonProps } from "../types";
-import { Layout, DocSectionEntryCard } from "../components";
+import { Layout } from "../components";
export interface DocHomeViewProps extends CommonProps {}
@@ -14,25 +14,7 @@ const DocHomeView: ReactView<DocHomeViewProps> = (props) => {
return (
<Layout {...commonProps} showSideMenu={true}>
<StyledDocHomeWrapper>
- <StyledDocSectionEntryCardsGrid>
- {commonProps?.menuDefinition != null &&
- Object.entries(commonProps.menuDefinition).map(
- ([sectionSlug, section]) => (
- <DocSectionEntryCard
- key={sectionSlug}
- themeScheme={commonProps?.themeScheme}
- href={`/docs/${sectionSlug}/${
- Object.keys(section.pagesBySlug)[0]
- }`}
- coverImageUrl={
- "/public/assets/images/the-big-picture_light-on-dark.svg"
- }
- title={section.title}
- summary={section.summary}
- />
- )
- )}
- </StyledDocSectionEntryCardsGrid>
+ <StyledDocSectionEntryCardsGrid></StyledDocSectionEntryCardsGrid>
</StyledDocHomeWrapper>
</Layout>
);
@@ -5,8 +5,7 @@ import styled from "styled-components";
// app
import type { CommonProps } from "../types";
-import { Layout, DocSectionEntryCard, ButtonAnchor } from "../components";
-import { ReactMonolithLogo } from "../components/icons";
+import { ButtonAnchor, Layout } from "../components";
export interface HomeViewProps extends CommonProps {
foo?: boolean;
@@ -17,29 +16,10 @@ const HomeView: ReactView<HomeViewProps> = (props) => {
return (
<Layout {...commonProps} showSideMenu={false}>
<StyledHomeWrapper>
- <ReactMonolithLogo size={256} />
<StyledButtonsRow>
- <ButtonAnchor href={"/docs"}>Get Started</ButtonAnchor>
- <ButtonAnchor href={"/api-reference"}>API Reference</ButtonAnchor>
+ <ButtonAnchor href={"/auth/register"}>Get Started</ButtonAnchor>
+ <ButtonAnchor href={"/features"}>Learn More</ButtonAnchor>
</StyledButtonsRow>
- <StyledCardsGrid>
- {commonProps?.menuDefinition != null &&
- Object.entries(commonProps.menuDefinition)
- .slice(0, 3)
- .map(([sectionSlug, section]) => (
- <DocSectionEntryCard
- key={sectionSlug}
- themeScheme={commonProps?.themeScheme}
- href={`/docs/${sectionSlug}/${
- Object.keys(section.pagesBySlug)[0]
- }`}
- coverImageUrl={""}
- title={section.title}
- summary={section.summary}
- />
- ))}
- </StyledCardsGrid>
- <ButtonAnchor href={"/docs"}>Discover More</ButtonAnchor>
</StyledHomeWrapper>
</Layout>
);
@@ -58,15 +38,6 @@ const StyledHomeWrapper = styled.div`
margin: 0 auto;
`;
-const StyledCardsGrid = styled.div`
- display: flex;
- flex-flow: row wrap;
- align-items: stretch;
- justify-content: center;
- gap: 16px;
- margin-top: 24px;
-`;
-
const StyledButtonsRow = styled.div`
display: flex;
flex-flow: row wrap;
@@ -16,7 +16,8 @@
},
"dependencies": {
"@ethicdevs/fastify-stream-react-views": "1.9.9",
- "@ethicdevs/react-monolith": "1.5.0",
+ "@ethicdevs/fastify-git-server": "1.0.0",
+ "@ethicdevs/react-monolith": "1.6.1",
"@fastify/cookie": "6.0.0",
"cross-fetch": "^3.1.5",
"dotenv-flow": "^3.2.0",
@@ -291,6 +291,13 @@
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
+"@ethicdevs/fastify-git-server@1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@ethicdevs/fastify-git-server/-/fastify-git-server-1.0.0.tgz#741b5873b799395a7bca4fba684b291c84ae1ab2"
+ dependencies:
+ debug "^4.3.4"
+ fastify-plugin "^3.0.1"
+
"@ethicdevs/fastify-stream-react-views@1.9.9":
version "1.9.9"
resolved "https://registry.yarnpkg.com/@ethicdevs/fastify-stream-react-views/-/fastify-stream-react-views-1.9.9.tgz#3b1bd2da1170252eac926ba244fd248597c2a738"
@@ -308,9 +315,9 @@
terser "^5.14.1"
transform-modules-eumd "^1.0.0"
-"@ethicdevs/react-monolith@1.5.0":
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/@ethicdevs/react-monolith/-/react-monolith-1.5.0.tgz#419326efef717b93dea19d608aa645ec73d4573a"
+"@ethicdevs/react-monolith@1.6.1":
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/@ethicdevs/react-monolith/-/react-monolith-1.6.1.tgz#5b347344bef5545a1ac2b07dff74330321f9f272"
dependencies:
deepest-merge "^1.0.0"
react-ssr-prepass "^1.5.0"
@@ -1217,7 +1224,7 @@ debug@2.6.9:
dependencies:
ms "2.0.0"
-debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1:
+debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
dependencies: