initial commit

This commit is contained in:
Mrrp 2025-01-06 16:35:53 -08:00
commit ab06adb651
44 changed files with 8933 additions and 0 deletions

View file

@ -0,0 +1,2 @@
import { handlers } from "../../../auth";
export const { GET, POST } = handlers

View file

@ -0,0 +1,63 @@
import { startServerAndCreateNextHandler } from "@as-integrations/next";
import { ApolloServer } from "@apollo/server";
import { NextRequest } from "next/server";
import { gql } from "graphql-tag";
import { prisma } from "@/lib/prisma";
const typeDefs = gql`
type Query {
users: [User],
prisma_okay: String
}
type User {
id: ID!
name: String
email: String
}
`;
const resolvers = {
Query: {
users: async () => {
const db_users = await prisma.user.findMany();
if (!db_users) return [];
const map = db_users.map((user) => {
return {
id: user.id,
name: user.name,
email: user.email,
};
});
return map;
},
prisma_okay: async () => {
try {
await prisma.$connect();
return "Prisma is okay";
} catch (error) {
return "Prisma is not okay: " + error;
}
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
const handler = startServerAndCreateNextHandler<NextRequest>(server, {
context: async (req, res) => ({
req,
res,
dataSources: {},
}),
});
export async function GET(request: NextRequest) {
return handler(request);
}
export async function POST(request: NextRequest) {
return handler(request);
}

BIN
src/app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

50
src/app/globals.css Normal file
View file

@ -0,0 +1,50 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--background: #ffffff;
--foreground: #171717;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
color: var(--foreground);
background: var(--background);
font-family: Arial, Helvetica, sans-serif;
}
/* Import the WOFF IBM VGA font */
@font-face {
font-family: 'IBM VGA 8x16';
src: url('/Web437_IBM_VGA_8x16.woff') format('woff');
font-weight: normal;
font-style: normal;
}
.vga-font {
font-family: 'IBM VGA 8x16', monospace;
}
/* Make sure to inherit the text color for the glow color */
.glow {
text-shadow: 0 0 10px var(--foreground);
}
.contrast {
filter: invert(1);
}
.hue-rotate {
filter: hue-rotate(180deg);
}
.grayscale {
filter: grayscale(1);
}

128
src/app/layout.tsx Normal file
View file

@ -0,0 +1,128 @@
"use client";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import IntroAnim from "@/components/intro_anim";
import React from "react";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const [showIntro, setShowIntro] = React.useState(true);
// Increment this value by deltatime - If it exceeds 0.2 seconds, negate the check
const [checkExistsTime, setCheckExistsTime] = React.useState(0);
// Less is sharper, more is blurrier
const [focus, setFocus] = React.useState(1);
const [darkness, setDarkness] = React.useState(1);
const [lastFocusTime, setLastFocusTime] = React.useState(Date.now());
const [channel] = React.useState(new BroadcastChannel("felidae"));
// Skip the intro animation if the site is already open on another tab
React.useEffect(() => {
channel.onmessage = (event) => {
if (event.data === "ping" && checkExistsTime > 200) {
// Broadcast across ALL tabs
const channel = new BroadcastChannel("felidae");
channel.postMessage("pong");
console.log("Received ping message");
} else if (event.data === "pong" && checkExistsTime < 200) {
setShowIntro(false);
console.log("Received pong message");
}
};
});
// Initial ping to check if the site is already open on another tab
React.useEffect(() => {
channel.postMessage("ping");
});
// If the user has Reduced Motion enabled, skip the intro animation
React.useEffect(() => {
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
if (mediaQuery.matches) {
setShowIntro(false);
setFocus(0);
setDarkness(1);
}
}, []);
// When showIntro is false, reduce pixelation towards zero by a factor of 0.1 every tenth of a second.
React.useEffect(() => {
if (!showIntro) {
setLastFocusTime(Date.now());
const interval = setInterval(() => {
const timeSinceLastFocus = Date.now() - lastFocusTime;
const amount = focus - timeSinceLastFocus * 0.0003 < 0 ? 0 : focus - timeSinceLastFocus * 0.0003;
setFocus(amount);
setDarkness(1 - amount);
setLastFocusTime(Date.now());
if (focus <= 0) {
clearInterval(interval);
}
}, 30);
return () => clearInterval(interval);
} else {
// Increment the checkExistsTime by the time since the last frame using an interval
setLastFocusTime(Date.now());
const interval = setInterval(() => {
const timeSinceLastFocus = Date.now() - lastFocusTime;
setCheckExistsTime(checkExistsTime + timeSinceLastFocus);
setLastFocusTime(Date.now());
if (checkExistsTime > 200) {
clearInterval(interval);
}
}, 30);
return () => clearInterval(interval);
}
}, [showIntro]);
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{showIntro && <IntroAnim onFinish={() => setShowIntro(false)} />}
{!showIntro && <div>
{focus > 0 && <div>
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="0"
height="0"
>
<defs>
<filter id="blur">
<feGaussianBlur in="SourceGraphic" stdDeviation={focus * 3} />
</filter>
<filter id="darken">
<feComponentTransfer>
<feFuncA type="linear" slope={darkness} />
</feComponentTransfer>
</filter>
</defs>
</svg>
<div style={{ filter: "url(#blur) url(#darken)" }}>
{children}
</div>
</div>}
{focus <= 0 && children}
</div>}
</body>
</html>
);
}

101
src/app/page.tsx Normal file
View file

@ -0,0 +1,101 @@
import Image from "next/image";
export default function Home() {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
<li className="mb-2">
Get started by editing{" "}
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold">
src/app/page.tsx
</code>
.
</li>
<li>Save and see your changes instantly.</li>
</ol>
<div className="flex gap-4 items-center flex-col sm:flex-row">
<a
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={20}
height={20}
/>
Deploy now
</a>
<a
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Read our docs
</a>
</div>
</main>
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/file.svg"
alt="File icon"
width={16}
height={16}
/>
Learn
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/window.svg"
alt="Window icon"
width={16}
height={16}
/>
Examples
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/globe.svg"
alt="Globe icon"
width={16}
height={16}
/>
Go to nextjs.org
</a>
</footer>
</div>
);
}

View file

@ -0,0 +1,10 @@
import Image from "next/image";
export default function Page() {
return (
<div className="vga-font">
<p>Style Testing</p>
<Image src="/cat.jpg" width={500} height={500} alt="cat"></Image>
</div>
);
}

73
src/components/anime.tsx Normal file
View file

@ -0,0 +1,73 @@
"use client";
// Utility component for executing animations
import anime, { AnimeParams } from "animejs";
import React from "react";
interface IProps {
params: AnimeParams;
children: React.ReactNode;
}
interface IState {
scopeState: string;
}
export default class Anime extends React.Component<IProps, IState> {
private anime: anime.AnimeInstance | null;
constructor(props: IProps) {
super(props);
this.state = {
scopeState: "",
};
this.anime = null;
}
private applyDescendantSelector(selector: string): string {
console.log("Applying descendant selector to: " + selector);
return selector.split(",").map((s) => {
return "." + this.state.scopeState + ' ' + s;
}).join(", ");
}
componentDidMount(): void {
const scope = "anime-scope-" + Math.random().toString(36).substring(4);
this.setState({
scopeState: scope,
}, () => {
console.log("Anime scope state: " + this.state.scopeState);
const postTargets = '.' + this.state.scopeState;
console.log("Targets: " + postTargets);
// Update all params targets CSS selectors to include a descendant selector
if (this.props.params.targets !== undefined) {
// Identify if is single or is array (type AnimeTarget)
this.props.params.targets = this.applyDescendantSelector(this.props.params.targets?.toString() as string);
console.log("Updated targets: " + this.props.params.targets);
} else {
this.props.params.targets = postTargets;
}
this.anime = anime({
...this.props.params,
});
});
}
render() {
return (
<div>
<style>
{`.${this.state.scopeState} {}`}
</style>
<div className={this.state.scopeState}>
{this.props.children}
</div>
</div>
)
}
}

8
src/components/card.tsx Normal file
View file

@ -0,0 +1,8 @@
export default function Card(props: { children: React.ReactNode }) {
return (
<div className="p-4 bg-white dark:bg-black/[.5] rounded-lg shadow-md">
{props.children}
</div>
)
}

View file

@ -0,0 +1,94 @@
import anime from "animejs";
import Anime from "./anime";
import React from "react";
enum StatusSeverity {
OK = "OK",
WARNING = "WARN",
ERROR = "ERR",
}
interface Status {
severity: StatusSeverity;
message: string;
}
interface Diagnostic {
name: string;
status: Status;
get_status: () => Status;
}
const default_diagnostics: Diagnostic[] = [
{
name: "Example Diagnostic",
status: {
severity: StatusSeverity.OK,
message: "",
},
get_status: () => {
return {
severity: StatusSeverity.OK,
message: "This is an example diagnostic message",
}
}
}
];
export default function Diagnostics() {
const [diagnosticResults, setDiagnosticResults]: [Diagnostic[], React.Dispatch<React.SetStateAction<Diagnostic[]>>]
= React.useState(default_diagnostics);
const [diagnostics]: [Diagnostic[], React.Dispatch<React.SetStateAction<Diagnostic[]>>]
= React.useState(default_diagnostics);
React.useEffect(() => {
// Ensure diagnostics is always an array before trying to map
if (Array.isArray(diagnostics)) {
console.log("Diagnostics: ", diagnostics);
const new_diagnostics = diagnostics.map((d) => {
return {
name: d.name,
status: d.get_status(),
get_status: d.get_status,
}
});
// Update the diagnostics state with the new values
setDiagnosticResults(new_diagnostics);
}
}, [diagnostics]); // This will now only rerun when the state actually changes
return (
<div>
<Anime params={{
targets: ".text-stagger",
opacity: [0, 1],
duration: 1000,
delay: anime.stagger(300),
}}>
<ul>
{
diagnosticResults.map((d) => {
return (
<div key={d.name} className="text-stagger">
<h2>{d.name}</h2>
{/* SystemD style */}
<p>
[ <span style={{
color: d.status.severity === StatusSeverity.OK
? "lime" : d.status.severity === StatusSeverity.WARNING
? "yellow" : "red"
}}>
{d.status.severity}
</span> ] {d.status.message}
</p>
</div>
)
})
}
</ul>
</Anime>
</div>
)
}

View file

@ -0,0 +1,326 @@
"use client";
import React from "react";
class TextNode {
private time_elapsed: number = 0;
private last_time: number = Date.now();
public duration: number;
private finished_text: string;
private loading_text: string;
public active: boolean = false;
private status: "OK" | "WARN" | "FAIL" = "OK";
public decorational: boolean = false;
constructor(
duration: number,
loading_text: string,
finished_text: string | undefined = undefined,
decorational: boolean =false
) {
this.duration = duration;
this.loading_text = loading_text;
this.finished_text = finished_text ?? loading_text;
this.decorational = decorational;
}
public finish_now() {
this.time_elapsed = this.duration;
}
public get_text() {
return this.is_finished() ? this.finished_text : this.loading_text
}
public tick() {
if (this.is_finished()) {
return;
}
const now = Date.now();
const delta = now - this.last_time;
this.time_elapsed += delta;
this.last_time = now;
}
public is_finished(): boolean {
return this.time_elapsed >= this.duration;
}
public start() {
this.active = true;
this.last_time = Date.now();
}
public get_status_decorator() {
if (this.decorational) {
return "";
}
// [ ] (empty)
// (looping) [*** ] [**** ] [ **** ] [ ****] [ ***] (and 0.3 delay before looping, 0.2 delay interframe)
// [ OK ]
// [ WARN ]
// [ FAIL ]
// Use colors for the text, but not brackets - brackets stay white.
// Loading dots are orange, and the leftmost and rightmost are yellow
switch (this.is_finished()) {
case true:
switch (this.status) {
case "OK":
return (
<span>[ &nbsp;<span className="text-green-500">OK</span> &nbsp;]</span>
);
case "WARN":
return (
<span>[ <span className="text-yellow-500">WARN</span> ]</span>
);
case "FAIL":
return (
<span>[ <span className="text-red-500">FAIL</span> ]</span>
);
}
case false:
// Run the [*** ] [**** ] [ **** ] [ ****] [ ***] animation
const seconds = this.time_elapsed / 100;
// Divisible into 5 phases each second
let phase = Math.floor(seconds % 7) - 1;
if (phase === -1) {
phase = 0;
}
if (phase === 5) {
phase = 4;
}
const half = Math.floor(seconds % 14);
// Flip the phase if it's in the second half
if (half >= 7) {
phase = 4 - phase;
}
let spaces_left = 0;
let spaces_right = 0;
let dots = 0;
switch (phase) {
case 0:
spaces_left = 0;
spaces_right = 3;
dots = 3;
break;
case 1:
spaces_left = 0;
spaces_right = 2;
dots = 4;
break;
case 2:
spaces_left = 1;
spaces_right = 1;
dots = 4;
break;
case 3:
spaces_left = 2;
spaces_right = 0;
dots = 4;
break;
case 4:
spaces_left = 3;
spaces_right = 0;
dots = 3;
break;
}
return (
<span>
[<span>{"\xa0".repeat(spaces_left)}</span>
{<span className="text-orange-500">{"*".repeat(dots)}</span>}
<span>{"\xa0".repeat(spaces_right)}</span>]
</span>
);
}
}
}
// Decoration "loading" messages (fill with random things to do that aren't actually loading, etc.)
// Style it like it's an Init System (E.g. SystemD, OpenRC, etc. It isn't, but it looks like it)
const textNodes: TextNode[] = [
new TextNode(1000, `
\xa0___\xa0\xa0___\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0__\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0___\xa0
|__\xa0\xa0|__\xa0\xa0|\xa0\xa0\xa0\xa0|\xa0|\xa0\xa0\\\xa0\xa0/\\\xa0\xa0|__\xa0\xa0
|\xa0\xa0\xa0\xa0|___\xa0|___\xa0|\xa0|__/\xa0/~~\\\xa0|___\xa0
\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0
`, undefined, true),
new TextNode(2000, "Starting services", "Started services"),
new TextNode(1000, "Checking for updates", "No updates found"),
// Begin the jokes here.
];
// These are comic ones.
// No jokes about destructive commands, etc.
const randomTextNodes: TextNode[] = [
new TextNode(1000, "Loading the loading screen", "Loaded the loading screen"),
new TextNode(500, "Checking for updates", "Found updates, but they're not important"),
// Math
new TextNode(500, "Counting past infinity", "Counted past infinity"),
new TextNode(500, "Solving P vs NP", "Solved P vs NP"),
new TextNode(500, "Finding the last digit of pi", "Found the last digit of pi"),
new TextNode(500, "Dividing by zero", "Divided by zero"),
// Science
new TextNode(500, "Creating a black hole", "Created a black hole"),
new TextNode(500, "Finding the Higgs Boson", "Found the Higgs Boson"),
new TextNode(500, "Creating a new element", "Created a new element"),
new TextNode(500, "Creating a new universe", "Created a new universe"),
// Computer Science
new TextNode(500, "Rewriting it in Rust", "Rewrote it in Rust"),
new TextNode(1000, "Generating a random number between " + Math.floor(Math.random() * 100000) + " and " + Math.floor(Math.random() * 100000)),
new TextNode(500, "Downloading more RAM", "Downloaded more RAM"),
new TextNode(500, "Compiling the kernel", "Compiled the kernel"),
new TextNode(500, "Running Arch Linux", "Ran Arch Linux (btw)"),
new TextNode(500, "Compiling Gentoo", "Compiled Gentoo"),
new TextNode(500, "Running Windows Update", "Ran Windows Update"),
// - Programming
new TextNode(500, "Writing a new programming language", "Wrote a new programming language"),
// Mundane
new TextNode(500, "Finding the meaning of life", "Found the meaning of life"),
new TextNode(500, "Making a cup of tea", "Made a cup of tea"),
new TextNode(500, "Taking a break", "Took a break"),
new TextNode(500, "Doing something else", "Did something else"),
new TextNode(500, "Changing the world", "Changed the world"),
new TextNode(500, "Making a sandwich", "Made a sandwich"),
new TextNode(500, "Doing absolutely nothing", "Did absolutely nothing"),
// Occult
new TextNode(500, "Summoning Cthulhu", "Summoned Cthulhu"),
new TextNode(500, "Summoning Satan himself", "Summoned Satan himself"),
new TextNode(500, "Summoning a demon", "Summoned a demon"),
// LGBTQ+
new TextNode(500, "Supporting LGBTQ+ rights", "Supported LGBTQ+ rights"),
new TextNode(500, "Respecting pronouns", "Respected pronouns"),
// Game references
new TextNode(500, "Running the Konami Code", "Ran the Konami Code"),
new TextNode(500, "Running the Doom cheat codes", "Ran the Doom cheat codes"),
new TextNode(500, "Teleporting bread", "Teleported bread"),
new TextNode(500, "Building a sentry", "Built a sentry"),
new TextNode(500, "Building a dispenser", "Built a dispenser"),
new TextNode(500, "Building a teleporter", "Built a teleporter"),
new TextNode(500, "Spy checking", "Checked for spies"),
new TextNode(500, "Rocket jumping", "Jumped with rockets"),
new TextNode(500, "Demoknighting", "Demoknighted"),
new TextNode(500, "Waiting for random crits", "Got random crits"),
// Pop culture references
new TextNode(500, "Finding the Holy Grail", "Found the Holy Grail"),
new TextNode(500, "Finding the One Ring", "Found the One Ring"),
new TextNode(500, "Finding the Death Star plans", "Found the Death Star plans"),
new TextNode(500, "Finding the Infinity Stones", "Found the Infinity Stones"),
new TextNode(500, "Finding the Ark of the Covenant", "Found the Ark of the Covenant"),
new TextNode(500, "Finding the Philosopher's Stone", "Found the Philosopher's Stone"),
// References towards franchises
new TextNode(500, "Containing SCP-173", "Contained SCP-173"),
// Joke programs that do weird, though not destructive or harmful things
new TextNode(5000, "Running cowsay", "Ran cowsa- Moo."),
];
const postNodes = [
new TextNode(10000, "Entering site now", "Entered site"),
];
// Randomly shuffle randomTextNodes into textNodes, but leave the elements already in textNodes in place
// Only pop in ~50% of the randomTextNodes so as to have some variety
const randomTextNodesLength = randomTextNodes.length / 2;
// Use to avoid duplicates
const pushedRandomTextNodes: Array<number> = [];
for (let i = 0; i < randomTextNodesLength; i++) {
let index = Math.floor(Math.random() * randomTextNodes.length);
while (pushedRandomTextNodes.includes(index)) {
index = Math.floor(Math.random() * randomTextNodes.length);
}
pushedRandomTextNodes.push(index);
const duration = randomTextNodes[index].duration * Math.random();
randomTextNodes[index].duration = duration;
textNodes.push(randomTextNodes[index]);
}
for (let i = 0; i < postNodes.length; i++) {
textNodes.push(postNodes[i]);
}
const speedMultiplier = 0.1;
// Multiply the duration of each textNode by the speedMultiplier
for (let i = 0; i < textNodes.length; i++) {
textNodes[i].duration *= speedMultiplier;
}
export default function IntroAnim(props: { onFinish: () => void }) {
// Run the textNodes tick function every frame for each textNode
const [textNodesState, setTextNodesState] = React.useState(textNodes);
React.useEffect(() => {
// Ensure only one interval is running (textNode.active)
const interval = setInterval(() => {
// Mark the last textNode active if
// - it's not active
// - it's not finished
// - the previous textNode is finished
for (let i = 0; i < textNodesState.length; i++) {
const t = textNodesState[i];
if (!t.active && !t.is_finished() && (i === 0 || textNodesState[i - 1].is_finished())) {
t.start();
break;
}
}
// Tick all active textNodes
for (let i = 0; i < textNodesState.length; i++) {
const t = textNodesState[i];
if (t.active) {
t.tick();
}
}
if (textNodesState[textNodesState.length - 1].is_finished()) {
props.onFinish();
}
// Update the state
setTextNodesState([...textNodesState]);
}, 16);
return () => clearInterval(interval);
});
return (
<div className="vga-font">
<div className="text-left">
{
textNodesState.filter(t => t.active || t.is_finished()).map((t) => (
<div style={
{
lineHeight: "1",
whiteSpace: 'pre-line'
}
} key={t.get_text()}>
{t.get_status_decorator()}
<span> </span>
{t.get_text()}
</div>
))
}
</div>
</div>
);
}

View file

@ -0,0 +1,6 @@
export default function Navbar() {
return (
<nav>
</nav>
)
}

7
src/lib/prisma.ts Normal file
View file

@ -0,0 +1,7 @@
import { PrismaClient } from "@prisma/client"
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient }
export const prisma = globalForPrisma.prisma || new PrismaClient()
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma