example: remove with-supertokens (#93212)

Retaking the example clean up cycle.
This commit is contained in:
Joseph
2026-04-24 22:02:27 +02:00
committed by GitHub
parent b92745fe16
commit fb06f5f389
34 changed files with 0 additions and 1041 deletions
-43
View File
@@ -1,43 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
# VSCode
.vscode
-46
View File
@@ -1,46 +0,0 @@
# SuperTokens App with Next.js app directory
This is a simple application that is protected by SuperTokens. This app uses the Next.js app directory.
## How to use
### Using `create-next-app`
- Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example with-supertokens with-supertokens-app
```
```bash
yarn create next-app --example with-supertokens with-supertokens-app
```
```bash
pnpm create next-app --example with-supertokens with-supertokens-app
```
### Using `create-supertokens-app`
- Run the following command
```bash
npx create-supertokens-app@latest --frontend=next
```
```bash
yarn create-supertokens-app@latest --frontend=next
```
```bash
pnpm create-supertokens-app@latest --frontend=next
```
- Select the option to use the app directory
Follow the instructions after `create-supertokens-app` has finished
## Notes
- To know more about how this app works and to learn how to customise it based on your use cases refer to the [SuperTokens Documentation](https://supertokens.com/docs/guides)
- We have provided development OAuth keys for the various built-in third party providers in the `/app/config/backend.ts` file. Feel free to use them for development purposes, but **please create your own keys for production use**.
@@ -1,39 +0,0 @@
import { getAppDirRequestHandler } from "supertokens-node/nextjs";
import { NextRequest, NextResponse } from "next/server";
import { ensureSuperTokensInit } from "../../../config/backend";
ensureSuperTokensInit();
const handleCall = getAppDirRequestHandler(NextResponse);
export async function GET(request: NextRequest) {
const res = await handleCall(request);
if (!res.headers.has("Cache-Control")) {
// This is needed for production deployments with Vercel
res.headers.set(
"Cache-Control",
"no-cache, no-store, max-age=0, must-revalidate",
);
}
return res;
}
export async function POST(request: NextRequest) {
return handleCall(request);
}
export async function DELETE(request: NextRequest) {
return handleCall(request);
}
export async function PUT(request: NextRequest) {
return handleCall(request);
}
export async function PATCH(request: NextRequest) {
return handleCall(request);
}
export async function HEAD(request: NextRequest) {
return handleCall(request);
}
@@ -1,23 +0,0 @@
import { ensureSuperTokensInit } from "@/app/config/backend";
import { NextResponse, NextRequest } from "next/server";
import { withSession } from "supertokens-node/nextjs";
ensureSuperTokensInit();
export function GET(request: NextRequest) {
return withSession(request, async (err, session) => {
if (err) {
return NextResponse.json(err, { status: 500 });
}
if (!session) {
return new NextResponse("Authentication required", { status: 401 });
}
return NextResponse.json({
note: "Fetch any data from your application for authenticated user after using verifySession middleware",
userId: session.getUserId(),
sessionHandle: session.getHandle(),
accessTokenPayload: session.getAccessTokenPayload(),
});
});
}
@@ -1,24 +0,0 @@
"use client";
import { useEffect, useState } from "react";
import { redirectToAuth } from "supertokens-auth-react";
import SuperTokens from "supertokens-auth-react/ui";
import { PreBuiltUIList } from "../../config/frontend";
export default function Auth() {
// if the user visits a page that is not handled by us (like /auth/random), then we redirect them back to the auth page.
const [loaded, setLoaded] = useState(false);
useEffect(() => {
if (SuperTokens.canHandleRoute(PreBuiltUIList) === false) {
redirectToAuth({ redirectBack: false });
} else {
setLoaded(true);
}
}, []);
if (loaded) {
return SuperTokens.getRoutingComponent(PreBuiltUIList);
}
return null;
}
@@ -1,17 +0,0 @@
"use client";
import styles from "../page.module.css";
export const CallAPIButton = () => {
const fetchUserData = async () => {
const userInfoResponse = await fetch("http://localhost:3000/api/user");
alert(JSON.stringify(await userInfoResponse.json()));
};
return (
<div onClick={fetchUserData} className={styles.sessionButton}>
Call API
</div>
);
};
@@ -1,140 +0,0 @@
import { cookies } from "next/headers";
import { TryRefreshComponent } from "./tryRefreshClientComponent";
import styles from "../page.module.css";
import { redirect } from "next/navigation";
import Image from "next/image";
import { CelebrateIcon, SeparatorLine } from "../../assets/images";
import { CallAPIButton } from "./callApiButton";
import { LinksComponent } from "./linksComponent";
import { SessionAuthForNextJS } from "./sessionAuthForNextJS";
import jwksClient from "jwks-rsa";
import JsonWebToken from "jsonwebtoken";
import type { JwtHeader, JwtPayload, SigningKeyCallback } from "jsonwebtoken";
import { appInfo } from "../config/appInfo";
const client = jwksClient({
jwksUri: `${appInfo.apiDomain}${appInfo.apiBasePath}/jwt/jwks.json`,
});
function getAccessToken(): string | undefined {
return cookies().get("sAccessToken")?.value;
}
function getPublicKey(header: JwtHeader, callback: SigningKeyCallback) {
client.getSigningKey(header.kid, (err, key) => {
if (err) {
callback(err);
} else {
const signingKey = key?.getPublicKey();
callback(null, signingKey);
}
});
}
async function verifyToken(token: string): Promise<JwtPayload> {
return new Promise((resolve, reject) => {
JsonWebToken.verify(token, getPublicKey, {}, (err, decoded) => {
if (err) {
reject(err);
} else {
resolve(decoded as JwtPayload);
}
});
});
}
/**
* A helper function to retrieve session details on the server side.
*
* NOTE: This function does not use the getSSRSession function from the supertokens-node SDK
* because getSession can update the access token. These updated tokens would not be
* propagated to the client side, as request interceptors do not run on the server side.
*/
async function getSSRSessionHelper(): Promise<{
accessTokenPayload: JwtPayload | undefined;
hasToken: boolean;
error: Error | undefined;
}> {
const accessToken = getAccessToken();
const hasToken = !!accessToken;
try {
if (accessToken) {
const decoded = await verifyToken(accessToken);
return { accessTokenPayload: decoded, hasToken, error: undefined };
}
return { accessTokenPayload: undefined, hasToken, error: undefined };
} catch (error) {
if (error instanceof JsonWebToken.TokenExpiredError) {
return { accessTokenPayload: undefined, hasToken, error: undefined };
}
return { accessTokenPayload: undefined, hasToken, error: error as Error };
}
}
export async function HomePage() {
const { accessTokenPayload, hasToken, error } = await getSSRSessionHelper();
if (error) {
return (
<div>
Something went wrong while trying to get the session. Error -{" "}
{error.message}
</div>
);
}
// `accessTokenPayload` will be undefined if it the session does not exist or has expired
if (accessTokenPayload === undefined) {
if (!hasToken) {
/**
* This means that the user is not logged in. If you want to display some other UI in this
* case, you can do so here.
*/
return redirect("/auth");
}
/**
* This means that the session does not exist but we have session tokens for the user. In this case
* the `TryRefreshComponent` will try to refresh the session.
*
* To learn about why the 'key' attribute is required refer to: https://github.com/supertokens/supertokens-node/issues/826#issuecomment-2092144048
*/
return <TryRefreshComponent key={Date.now()} />;
}
/**
* SessionAuthForNextJS will handle proper redirection for the user based on the different session states.
* It will redirect to the login page if the session does not exist etc.
*/
return (
<SessionAuthForNextJS>
<div className={styles.homeContainer}>
<div className={styles.mainContainer}>
<div
className={`${styles.topBand} ${styles.successTitle} ${styles.bold500}`}
>
<Image
src={CelebrateIcon}
alt="Login successful"
className={styles.successIcon}
/>{" "}
Login successful
</div>
<div className={styles.innerContent}>
<div>Your userID is:</div>
<div className={`${styles.truncate} ${styles.userId}`}>
{accessTokenPayload.sub}
</div>
<CallAPIButton />
</div>
</div>
<LinksComponent />
<Image
className={styles.separatorLine}
src={SeparatorLine}
alt="separator"
/>
</div>
</SessionAuthForNextJS>
);
}
@@ -1,80 +0,0 @@
"use client";
import styles from "../page.module.css";
import { BlogsIcon, GuideIcon, SignOutIcon } from "../../assets/images";
import { recipeDetails } from "../config/frontend";
import Link from "next/link";
import Image from "next/image";
import Session from "supertokens-auth-react/recipe/session";
import SuperTokens from "supertokens-auth-react";
const SignOutLink = (props: { name: string; link: string; icon: string }) => {
return (
<div
className={styles.linksContainerLink}
onClick={async () => {
await Session.signOut();
SuperTokens.redirectToAuth();
}}
>
<Image className={styles.linkIcon} src={props.icon} alt={props.name} />
<div role={"button"}>{props.name}</div>
</div>
);
};
export const LinksComponent = () => {
const links: {
name: string;
link: string;
icon: string;
}[] = [
{
name: "Blogs",
link: "https://supertokens.com/blog",
icon: BlogsIcon,
},
{
name: "Guides",
link: recipeDetails.docsLink,
icon: GuideIcon,
},
{
name: "Sign Out",
link: "",
icon: SignOutIcon,
},
];
return (
<div className={styles.bottomLinksContainer}>
{links.map((link) => {
if (link.name === "Sign Out") {
return (
<SignOutLink
name={link.name}
link={link.link}
icon={link.icon}
key={link.name}
/>
);
}
return (
<Link
href={link.link}
className={styles.linksContainerLink}
key={link.name}
target="_blank"
>
<Image
className={styles.linkIcon}
src={link.icon}
alt={link.name}
/>
<div role={"button"}>{link.name}</div>
</Link>
);
})}
</div>
);
};
@@ -1,19 +0,0 @@
"use client";
import React, { useState, useEffect } from "react";
import { SessionAuth } from "supertokens-auth-react/recipe/session";
type Props = Parameters<typeof SessionAuth>[0] & {
children?: React.ReactNode | undefined;
};
export const SessionAuthForNextJS = (props: Props) => {
const [loaded, setLoaded] = useState(false);
useEffect(() => {
setLoaded(true);
}, []);
if (!loaded) {
return props.children;
}
return <SessionAuth {...props}>{props.children}</SessionAuth>;
};
@@ -1,19 +0,0 @@
"use client";
import React from "react";
import { SuperTokensWrapper } from "supertokens-auth-react";
import SuperTokensReact from "supertokens-auth-react";
import { frontendConfig, setRouter } from "../config/frontend";
import { usePathname, useRouter } from "next/navigation";
if (typeof window !== "undefined") {
// we only want to call this init function on the frontend, so we check typeof window !== 'undefined'
SuperTokensReact.init(frontendConfig());
}
export const SuperTokensProvider: React.FC<React.PropsWithChildren<{}>> = ({
children,
}) => {
setRouter(useRouter(), usePathname() || window.location.pathname);
return <SuperTokensWrapper>{children}</SuperTokensWrapper>;
};
@@ -1,31 +0,0 @@
"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import Session from "supertokens-auth-react/recipe/session";
import SuperTokens from "supertokens-auth-react";
export const TryRefreshComponent = () => {
const router = useRouter();
const [didError, setDidError] = useState(false);
useEffect(() => {
void Session.attemptRefreshingSession()
.then((hasSession) => {
if (hasSession) {
router.refresh();
} else {
SuperTokens.redirectToAuth();
}
})
.catch(() => {
setDidError(true);
});
}, [router]);
if (didError) {
return <div>Something went wrong, please reload the page</div>;
}
return <div>Loading...</div>;
};
@@ -1,7 +0,0 @@
export const appInfo = {
appName: "SuperTokens Next.js demo app",
apiDomain: "http://localhost:3000",
websiteDomain: "http://localhost:3000",
apiBasePath: "/api/auth",
websiteBasePath: "/auth",
};
@@ -1,95 +0,0 @@
import ThirdPartyNode from "supertokens-node/recipe/thirdparty";
import EmailPasswordNode from "supertokens-node/recipe/emailpassword";
import SessionNode from "supertokens-node/recipe/session";
import Dashboard from "supertokens-node/recipe/dashboard";
import UserRoles from "supertokens-node/recipe/userroles";
import { appInfo } from "./appInfo";
import { TypeInput } from "supertokens-node/types";
import SuperTokens from "supertokens-node";
export let backendConfig = (): TypeInput => {
return {
supertokens: {
// this is the location of the SuperTokens core.
connectionURI: "https://try.supertokens.com",
},
appInfo,
// recipeList contains all the modules that you want to
// use from SuperTokens. See the full list here: https://supertokens.com/docs/guides
recipeList: [
EmailPasswordNode.init(),
ThirdPartyNode.init({
signInAndUpFeature: {
providers: [
// We have provided you with development keys which you can use for testing.
// IMPORTANT: Please replace them with your own OAuth keys for production use.
{
config: {
thirdPartyId: "google",
clients: [
{
clientId:
"1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com",
clientSecret: "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",
},
],
},
},
{
config: {
thirdPartyId: "github",
clients: [
{
clientId: "467101b197249757c71f",
clientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd",
},
],
},
},
{
config: {
thirdPartyId: "apple",
clients: [
{
clientId: "4398792-io.supertokens.example.service",
additionalConfig: {
keyId: "7M48Y4RYDL",
privateKey:
"-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----",
teamId: "YWQCXGJRJL",
},
},
],
},
},
{
config: {
thirdPartyId: "twitter",
clients: [
{
clientId: "4398792-WXpqVXRiazdRMGNJdEZIa3RVQXc6MTpjaQ",
clientSecret:
"BivMbtwmcygbRLNQ0zk45yxvW246tnYnTFFq-LH39NwZMxFpdC",
},
],
},
},
],
},
}),
SessionNode.init(),
Dashboard.init(),
UserRoles.init(),
],
isInServerlessEnv: true,
framework: "custom",
};
};
let initialized = false;
export function ensureSuperTokensInit() {
if (!initialized) {
SuperTokens.init(backendConfig());
initialized = true;
}
}
@@ -1,55 +0,0 @@
import ThirdPartyReact from "supertokens-auth-react/recipe/thirdparty";
import EmailPasswordReact from "supertokens-auth-react/recipe/emailpassword";
import Session from "supertokens-auth-react/recipe/session";
import { appInfo } from "./appInfo";
import { type useRouter } from "next/navigation";
import { SuperTokensConfig } from "supertokens-auth-react/lib/build/types";
import { ThirdPartyPreBuiltUI } from "supertokens-auth-react/recipe/thirdparty/prebuiltui";
import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui";
const routerInfo: { router?: ReturnType<typeof useRouter>; pathname?: string } =
{};
export function setRouter(
router: ReturnType<typeof useRouter>,
pathname: string,
) {
routerInfo.router = router;
routerInfo.pathname = pathname;
}
export const frontendConfig = (): SuperTokensConfig => {
return {
appInfo,
recipeList: [
EmailPasswordReact.init(),
ThirdPartyReact.init({
signInAndUpFeature: {
providers: [
ThirdPartyReact.Google.init(),
ThirdPartyReact.Github.init(),
ThirdPartyReact.Apple.init(),
],
},
}),
Session.init(),
],
windowHandler: (orig) => {
return {
...orig,
location: {
...orig.location,
getPathname: () => routerInfo.pathname!,
assign: (url) => routerInfo.router!.push(url.toString()),
setHref: (url) => routerInfo.router!.push(url.toString()),
},
};
},
};
};
export const recipeDetails = {
docsLink: "https://supertokens.com/docs/thirdpartyemailpassword/introduction",
};
export const PreBuiltUIList = [ThirdPartyPreBuiltUI, EmailPasswordPreBuiltUI];
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

@@ -1,3 +0,0 @@
html {
height: 100%;
}
-25
View File
@@ -1,25 +0,0 @@
import "./globals.css";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { SuperTokensProvider } from "./components/supertokensProvider";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "SuperTokens 💫",
description: "SuperTokens demo app",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>
<SuperTokensProvider>{children}</SuperTokensProvider>
</body>
</html>
);
}
@@ -1,218 +0,0 @@
.main {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
}
@font-face {
font-family: Menlo;
src: url("../assets/fonts/MenloRegular.ttf");
}
.appContainer {
font-family: Rubik, sans-serif;
}
.appContainer * {
box-sizing: border-box;
}
.bold400 {
font-variation-settings: "wght" 400;
}
.bold500 {
font-variation-settings: "wght" 500;
}
.bold600 {
font-variation-settings: "wght" 600;
}
.homeContainer {
min-height: 100vh;
min-width: 100vw;
background: url("../assets/images/background.png");
background-size: cover;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.bold700 {
font-variation-settings: "wght" 700;
}
.mainContainer {
box-shadow: 0px 0px 60px 0px rgba(0, 0, 0, 0.16);
width: min(635px, calc(100% - 24px));
border-radius: 16px;
margin-block-end: 159px;
background-color: #ffffff;
}
.successTitle {
line-height: 1;
padding-block: 26px;
background-color: #e7ffed;
text-align: center;
color: #3eb655;
display: flex;
justify-content: center;
align-items: flex-end;
font-size: 20px;
}
.successIcon {
margin-right: 8px;
}
.innerContent {
padding-block: 48px;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
}
.userId {
position: relative;
padding: 14px 17px;
border-image-slice: 1;
width: min(430px, calc(100% - 30px));
margin-inline: auto;
margin-block: 11px 23px;
border-radius: 9px;
line-height: 1;
font-family: Menlo, serif;
cursor: text;
}
.userId:before {
content: "";
position: absolute;
inset: 0;
border-radius: 9px;
padding: 2px;
background: linear-gradient(90.31deg, #ff9933 0.11%, #ff3f33 99.82%);
mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
}
.topBand,
.bottomBand {
border-radius: inherit;
}
.topBand {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.bottomBand {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.sessionButton {
padding-left: 13px;
padding-right: 13px;
padding-top: 8px;
padding-bottom: 8px;
cursor: pointer;
color: white;
font-weight: bold;
font-size: 17px;
box-sizing: border-box;
background: #ff9933;
border: 1px solid #ff8a15;
box-shadow: 0px 3px 6px rgba(255, 153, 51, 0.16);
border-radius: 6px;
font-size: 16px;
}
.bottomCTAContainer {
display: flex;
justify-content: flex-end;
padding-inline: 21px;
background-color: #212d4f;
}
.viewCode {
padding-block: 11px;
color: #bac9f5;
cursor: pointer;
font-size: 14px;
}
.bottomLinksContainer {
display: grid;
grid-template-columns: repeat(4, auto);
margin-bottom: 22px;
}
.linksContainerLink {
display: flex;
align-items: center;
margin-inline-end: 68px;
cursor: pointer;
text-decoration: none;
color: #000000;
}
.linksContainerLink:last-child {
margin-right: 0;
}
.truncate {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.separatorLine {
max-width: 100%;
}
.linkIcon {
width: 15px;
margin-right: 5px;
}
@media screen and (max-width: 768px) {
.bottomLinksContainer {
grid-template-columns: repeat(2, 1fr);
column-gap: 64px;
row-gap: 34px;
}
.linksContainerLink {
margin-inline-end: 0;
}
.separatorLine {
max-width: 200px;
}
}
@media screen and (max-width: 480px) {
.homeContainer {
justify-content: start;
padding-block-start: 25px;
}
.mainContainer {
margin-block-end: 90px;
}
}
-10
View File
@@ -1,10 +0,0 @@
import { HomePage } from "./components/home";
import styles from "./page.module.css";
export default function Home() {
return (
<main className={styles.main}>
<HomePage />
</main>
);
}
@@ -1,3 +0,0 @@
<svg width="13" height="11" viewBox="0 0 13 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.64867 6.69299H1.63067L9.34667 6.69299L6.92167 9.12099C6.80247 9.24042 6.73553 9.40226 6.73553 9.57099C6.73553 9.73973 6.80247 9.90157 6.92167 10.021L7.29867 10.394C7.41695 10.5119 7.57716 10.5781 7.74417 10.5781C7.91119 10.5781 8.07139 10.5119 8.18967 10.394L12.3477 6.23699C12.4653 6.11795 12.5312 5.95734 12.5312 5.78999C12.5312 5.62264 12.4653 5.46204 12.3477 5.34299L8.18967 1.18399C8.07127 1.06632 7.91111 1.00027 7.74417 1.00027C7.57724 1.00027 7.41708 1.06632 7.29867 1.18399L6.92167 1.56199C6.8631 1.62031 6.81668 1.68968 6.7851 1.76606C6.75351 1.84245 6.73739 1.92434 6.73767 2.00699C6.73739 2.08846 6.75354 2.16915 6.78516 2.24424C6.81677 2.31932 6.8632 2.38726 6.92167 2.44399L9.37467 4.88899L1.64067 4.88899C1.47078 4.89237 1.3089 4.96184 1.1894 5.08264C1.0699 5.20345 1.0022 5.36608 1.00067 5.53599V6.06999C1.00538 6.23808 1.07595 6.39758 1.19717 6.51412C1.31838 6.63065 1.48053 6.6949 1.64867 6.69299Z" fill="#BAC9F5" stroke="#212D4F" stroke-width="0.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

@@ -1,3 +0,0 @@
<svg width="16" height="14" viewBox="0 0 16 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.34272 0.0267221C0.710774 0.121007 0.1734 0.636512 0.0398429 1.27659C0.0170474 1.38568 4.32967e-06 1.82922 4.32967e-06 2.31199V3.15656H7.3467H14.6934L14.676 2.2292C14.6608 1.4129 14.6499 1.27745 14.5856 1.09832C14.4153 0.624123 14.0643 0.263154 13.6055 0.0903228L13.3808 0.00568978L7.4675 0.000431738C4.21521 -0.00244938 1.45906 0.00939935 1.34272 0.0267221ZM2.48986 1.21C2.63421 1.2987 2.69163 1.40714 2.69163 1.59088C2.69163 2.09198 2.00379 2.2091 1.826 1.73829C1.67873 1.34826 2.13021 0.988981 2.48986 1.21ZM4.07175 1.19869C4.20817 1.2799 4.28756 1.4294 4.28756 1.60504C4.28756 1.72183 4.26305 1.78003 4.1714 1.8808C3.96214 2.11096 3.62788 2.07916 3.46224 1.81327C3.28874 1.53481 3.50208 1.13977 3.82597 1.13977C3.90675 1.13977 4.01734 1.16628 4.07175 1.19869ZM5.75855 1.27893C5.89057 1.42785 5.91765 1.55303 5.85627 1.73051C5.69074 2.20928 4.9988 2.09072 5.0034 1.5844C5.00601 1.29913 5.19699 1.12645 5.4824 1.15122C5.62453 1.16354 5.6783 1.18843 5.75855 1.27893ZM4.32967e-06 7.63267C4.32967e-06 11.5161 -0.00342567 11.4373 0.182797 11.81C0.364983 12.1746 0.689158 12.4502 1.10005 12.5896C1.31829 12.6638 1.35927 12.6645 4.66901 12.6554L8.01716 12.6463L8.09999 12.1637C8.23997 11.3484 8.02109 11.6174 10.8909 8.73304C13.2137 6.39832 13.4356 6.18527 13.6543 6.07949C13.8927 5.96421 14.1971 5.87907 14.5158 5.83863L14.6861 5.81699L14.6766 4.92794L14.667 4.0389L7.33351 4.02983L4.32967e-06 4.02071V7.63267ZM14.4223 6.72371C14.1115 6.77629 13.9052 6.91088 13.4884 7.33303L13.0958 7.7307L14.0418 8.68471L14.9878 9.63876L15.3738 9.25175C15.8333 8.79117 15.9626 8.56748 15.9951 8.17659C16.0545 7.462 15.5678 6.83964 14.8589 6.72371C14.7337 6.70322 14.6233 6.68827 14.6134 6.69043C14.6036 6.69263 14.5176 6.70758 14.4223 6.72371ZM10.7681 10.0802C9.82255 11.036 9.03878 11.8476 9.02642 11.8838C8.96561 12.062 8.75041 13.4915 8.76602 13.6137C8.77688 13.6988 8.82219 13.7931 8.88286 13.857C9.05847 14.0417 9.13779 14.0436 10.0484 13.885C10.5017 13.806 10.8984 13.7269 10.9298 13.7092C10.9612 13.6916 11.7506 12.9063 12.6839 11.9642L14.381 10.2512L13.4341 9.29688L12.4873 8.3425L10.7681 10.0802Z" fill="#212D4F"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 30 KiB

@@ -1,3 +0,0 @@
<svg width="13" height="14" viewBox="0 0 13 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.85572 0.029056C0.990534 0.169641 0.278576 0.818617 0.0594541 1.6664C0.00119265 1.89188 0 1.99774 0 7.00566C0 12.0136 0.00119265 12.1194 0.0594541 12.3449C0.260268 13.1218 0.869688 13.7282 1.66972 13.947C1.85396 13.9974 2.12723 14 7.20069 14C12.1136 14 12.545 13.9962 12.6279 13.9518C12.8578 13.8288 12.9983 13.602 12.9993 13.352C13.0004 13.0979 12.8691 12.8809 12.65 12.7747C12.5421 12.7224 12.339 12.7198 7.27523 12.7058L2.01261 12.6913L1.86353 12.6193C1.4467 12.4181 1.24302 11.9518 1.38921 11.5333C1.44667 11.3688 1.66284 11.1268 1.83035 11.0394L1.95298 10.9754L7.2156 10.9609C12.2043 10.9471 12.4844 10.9436 12.5975 10.8939C12.755 10.8246 12.8757 10.7111 12.9435 10.5683C12.9965 10.4565 12.9987 10.2573 12.9993 5.47726L13 0.502606L12.9245 0.354751C12.8438 0.196862 12.6923 0.0732324 12.5206 0.0251881C12.3918 -0.0108161 2.07812 -0.00706442 1.85572 0.029056ZM6.92972 2.01798C7.92323 2.22327 8.63441 3.19061 8.50125 4.1556C8.41473 4.78279 8.08877 5.28453 7.54921 5.62104C7.36507 5.73589 7.31998 5.78056 7.2588 5.90875C7.2147 6.00109 7.18626 6.11399 7.18608 6.19719C7.1853 6.56404 7.04934 6.81656 6.78892 6.93481C6.5825 7.02855 6.40614 7.0268 6.20497 6.92903C5.89365 6.77771 5.78721 6.51536 5.84213 6.03485C5.91971 5.35619 6.23085 4.88019 6.84527 4.50011C7.28832 4.22607 7.26432 3.60007 6.80171 3.36432C6.58832 3.25559 6.41168 3.25559 6.19829 3.36432C5.94186 3.49499 5.87612 3.61653 5.79967 4.10125C5.77412 4.26341 5.62602 4.43974 5.44718 4.52096C5.09609 4.68042 4.73641 4.56284 4.55197 4.22828C4.50065 4.13521 4.48837 4.06539 4.49052 3.87929C4.49904 3.14708 4.94313 2.48932 5.65238 2.15845C6.03131 1.98168 6.50301 1.9298 6.92972 2.01798ZM6.71698 7.70538C6.77893 7.72216 6.877 7.77646 6.9349 7.82608C7.3354 8.16905 7.19323 8.79929 6.68275 8.94404C6.12264 9.10286 5.64173 8.53351 5.90525 8.02355C6.05096 7.74153 6.37769 7.61348 6.71698 7.70538Z" fill="#212D4F"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

@@ -1,15 +0,0 @@
import SeparatorLine from "./separator-line.svg";
import ArrowRight from "./arrow-right-icon.svg";
import SignOutIcon from "./sign-out-icon.svg";
import GuideIcon from "./guide-icon.svg";
import BlogsIcon from "./blogs-icon.svg";
import CelebrateIcon from "./celebrate-icon.svg";
export {
SeparatorLine,
ArrowRight,
SignOutIcon,
GuideIcon,
BlogsIcon,
CelebrateIcon,
};
@@ -1,10 +0,0 @@
<svg width="530" height="1" viewBox="0 0 530 1" fill="none" xmlns="http://www.w3.org/2000/svg">
<line opacity="0.2" x1="0.5" y1="0.5" x2="529.5" y2="0.5" stroke="url(#paint0_linear_2144_48022)" stroke-linecap="round"/>
<defs>
<linearGradient id="paint0_linear_2144_48022" x1="530" y1="1.00041" x2="0" y2="1" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="0.503472" stop-color="#212D4F"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 485 B

@@ -1,3 +0,0 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.952012 0.0390744C0.51903 0.146482 0.157855 0.50616 0.0407246 0.946584C0.00735517 1.07209 0.000499641 2.07489 0.000206669 6.87688C-0.000174194 13.2011 -0.00998874 12.8335 0.167464 13.1368C0.273959 13.3187 0.492574 13.53 0.662527 13.6151C0.74119 13.6546 1.68884 13.9823 2.76844 14.3434L4.73134 15L4.99502 14.9999C5.3179 14.9999 5.49858 14.9427 5.74139 14.7638C5.93903 14.6181 6.09518 14.4027 6.18161 14.1565C6.2298 14.0193 6.24015 13.9145 6.24015 13.5638V13.1377L7.27287 13.1372C8.45281 13.1366 8.57006 13.1222 8.96478 12.9288C9.43884 12.6964 9.82421 12.2134 9.94456 11.7005C10.0116 11.4151 10.0118 8.67078 9.94483 8.51034C9.74871 8.04041 9.07069 8.00974 8.82284 8.45954C8.78018 8.53695 8.77259 8.72038 8.7597 9.98472L8.74505 11.4219L8.67181 11.5526C8.63153 11.6245 8.54141 11.7235 8.47156 11.7726L8.34459 11.8619L7.2927 11.8702L6.24082 11.8786L6.23317 7.03075L6.2255 2.18286L6.13277 1.98693C5.98002 1.66412 5.77456 1.47327 5.42299 1.32758L5.25869 1.25951L6.80163 1.26658L8.34456 1.27362L8.47156 1.3629C8.54141 1.41203 8.63153 1.51102 8.67181 1.58288L8.74505 1.71357L8.7597 2.84769L8.77435 3.98177L8.86224 4.10663C8.99411 4.29394 9.16711 4.37498 9.40781 4.36213C9.631 4.35025 9.77868 4.26736 9.90229 4.08466L9.97553 3.97638L9.98382 2.8097C9.99314 1.49782 9.98435 1.41625 9.7919 1.02431C9.63372 0.702204 9.2973 0.369686 8.96478 0.206726C8.51943 -0.0115204 8.72768 -0.00146014 4.70205 0.000739632C1.94032 0.00226481 1.06428 0.0112399 0.952012 0.0390744ZM11.6159 3.19079C11.4682 3.25796 11.321 3.42373 11.281 3.56792C11.2624 3.63494 11.2502 4.06393 11.2501 4.65394L11.25 5.62917H9.93733H8.62473L8.47051 5.7061C8.20678 5.83768 8.07816 6.11511 8.14724 6.40343C8.19459 6.60094 8.39642 6.80702 8.59039 6.85591C8.68452 6.87964 9.11956 6.89037 9.98851 6.89037H11.25V7.8622C11.25 8.54619 11.2606 8.86979 11.286 8.95476C11.3571 9.19289 11.631 9.38453 11.8979 9.3828C12.1309 9.38128 12.2108 9.31314 13.5579 7.96682C14.9082 6.61737 15 6.50993 15 6.27942C15 6.00272 15.0163 6.02234 13.5962 4.59442C12.7161 3.70956 12.2201 3.232 12.1416 3.1939C11.992 3.12131 11.7716 3.11999 11.6159 3.19079Z" fill="#212D4F"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

-41
View File
@@ -1,41 +0,0 @@
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { SessionContainer } from "supertokens-node/recipe/session";
import { withSession } from "supertokens-node/nextjs";
import { ensureSuperTokensInit } from "./app/config/backend";
ensureSuperTokensInit();
export async function middleware(
request: NextRequest & { session?: SessionContainer },
) {
if (request.headers.has("x-user-id")) {
console.warn(
"The FE tried to pass x-user-id, which is only supposed to be a backend internal header. Ignoring.",
);
request.headers.delete("x-user-id");
}
if (request.nextUrl.pathname.startsWith("/api/auth")) {
// this hits our pages/api/auth/* endpoints
return NextResponse.next();
}
return withSession(request, async (err, session) => {
if (err) {
return NextResponse.json(err, { status: 500 });
}
if (session === undefined) {
return NextResponse.next();
}
return NextResponse.next({
headers: {
"x-user-id": session.getUserId(),
},
});
});
}
export const config = {
matcher: "/api/:path*",
};
-4
View File
@@ -1,4 +0,0 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
module.exports = nextConfig;
-27
View File
@@ -1,27 +0,0 @@
{
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint ."
},
"dependencies": {
"jsonwebtoken": "^9.0.2",
"jwks-rsa": "^3.1.0",
"next": "latest",
"react": "^18",
"react-dom": "^18",
"supertokens-auth-react": "latest",
"supertokens-node": "latest"
},
"devDependencies": {
"@types/cookie": "^0.5.2",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^9",
"eslint-config-next": "13.5.4",
"typescript": "^5"
}
}
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>

Before

Width:  |  Height:  |  Size: 629 B

-27
View File
@@ -1,27 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}