<html lang="en">
<head></head>
<body>

<form id="mainForm" method="post" action="https://stackblitz.com/run" target="_self">
<input type="hidden" name="project[files][README.md]" value="# SolidStart

Everything you need to build a Solid project, powered by [`solid-start`](https://start.solidjs.com);

## Creating a project

```bash
# create a new project in the current directory
npm init solid@latest

# create a new project in my-app
npm init solid@latest my-app
```

## Developing

Once you&#39;ve created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:

```bash
npm run dev

# or start the server and open the app in a new browser tab
npm run dev -- --open
```

## Building

Solid apps are built with _presets_, which optimise your project for deployment to different environments.

By default, `npm run build` will generate a Node app that you can run with `npm start`. To use a different preset, add it to the `devDependencies` in `package.json` and specify in your `app.config.js`.
">
<input type="hidden" name="project[files][app.config.ts]" value="import { defineConfig } from &quot;@solidjs/start/config&quot;;

export default defineConfig({
  vite: {
    ssr: { external: [&quot;@prisma/client&quot;] }
  }
});
">
<input type="hidden" name="project[files][package.json]" value="{&quot;name&quot;:&quot;example-with-prisma&quot;,&quot;type&quot;:&quot;module&quot;,&quot;scripts&quot;:{&quot;dev&quot;:&quot;vinxi dev&quot;,&quot;build&quot;:&quot;vinxi build&quot;,&quot;start&quot;:&quot;vinxi start&quot;},&quot;devDependencies&quot;:{&quot;@types/node&quot;:&quot;^20.12.7&quot;},&quot;dependencies&quot;:{&quot;@prisma/client&quot;:&quot;^5.12.1&quot;,&quot;@solidjs/router&quot;:&quot;^0.15.0&quot;,&quot;@solidjs/start&quot;:&quot;https://pkg.pr.new/solidjs/solid-start/@solidjs/start@e2d3bd2&quot;,&quot;prisma&quot;:&quot;^5.12.1&quot;,&quot;solid-js&quot;:&quot;^1.9.5&quot;,&quot;vinxi&quot;:&quot;^0.5.3&quot;},&quot;engines&quot;:{&quot;node&quot;:&quot;&gt;=22&quot;}}">
<input type="hidden" name="project[files][tsconfig.json]" value="{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;ESNext&quot;,
    &quot;module&quot;: &quot;ESNext&quot;,
    &quot;moduleResolution&quot;: &quot;bundler&quot;,
    &quot;allowSyntheticDefaultImports&quot;: true,
    &quot;esModuleInterop&quot;: true,
    &quot;jsx&quot;: &quot;preserve&quot;,
    &quot;jsxImportSource&quot;: &quot;solid-js&quot;,
    &quot;allowJs&quot;: true,
    &quot;strict&quot;: true,
    &quot;noEmit&quot;: true,
    &quot;types&quot;: [&quot;vinxi/types/client&quot;, &quot;node&quot;],
    &quot;isolatedModules&quot;: true,
    &quot;paths&quot;: {
      &quot;~/*&quot;: [&quot;./src/*&quot;]
    }
  }
}
">
<input type="hidden" name="project[files][prisma/dev.db]" value="https://pkg.pr.new/template/f8d5fd1e-abf0-4cad-8994-07dbb85cebc1">
<input type="hidden" name="project[files][prisma/schema.prisma]" value="// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = &quot;prisma-client-js&quot;
}

datasource db {
  provider = &quot;sqlite&quot;
  url      = &quot;file:./dev.db&quot;
}

model User {
  id       String @id @default(uuid())
  username String @unique
  password String
}
">
<input type="hidden" name="project[files][public/favicon.ico]" value="https://pkg.pr.new/template/0b44926f-6137-4361-b796-7cefe53d9658">
<input type="hidden" name="project[files][src/app.css]" value="body {
  font-family: Gordita, Roboto, Oxygen, Ubuntu, Cantarell, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;
}

a {
  margin-right: 1rem;
}

main {
  text-align: center;
  padding: 1em;
  margin: 0 auto;
}

h1 {
  color: #335d92;
  text-transform: uppercase;
  font-size: 4rem;
  font-weight: 100;
  line-height: 1.1;
  margin: 4rem auto;
  max-width: 14rem;
}

p {
  max-width: 14rem;
  margin: 2rem auto;
  line-height: 1.35;
}

@media (min-width: 480px) {
  h1 {
    max-width: none;
  }

  p {
    max-width: none;
  }
}
">
<input type="hidden" name="project[files][src/app.tsx]" value="import { Router } from &quot;@solidjs/router&quot;;
import { FileRoutes } from &quot;@solidjs/start/router&quot;;
import { Suspense } from &quot;solid-js&quot;;
import &quot;./app.css&quot;;

export default function App() {
  return (
    &lt;Router
      root={props =&gt; (
        &lt;&gt;
          &lt;a href=&quot;/&quot;&gt;Index&lt;/a&gt;
          &lt;a href=&quot;/about&quot;&gt;About&lt;/a&gt;
          &lt;Suspense&gt;{props.children}&lt;/Suspense&gt;
        &lt;/&gt;
      )}
    &gt;
      &lt;FileRoutes /&gt;
    &lt;/Router&gt;
  );
}
">
<input type="hidden" name="project[files][src/entry-client.tsx]" value="// @refresh reload
import { mount, StartClient } from &quot;@solidjs/start/client&quot;;

mount(() =&gt; &lt;StartClient /&gt;, document.getElementById(&quot;app&quot;)!);
">
<input type="hidden" name="project[files][src/entry-server.tsx]" value="// @refresh reload
import { createHandler, StartServer } from &quot;@solidjs/start/server&quot;;

export default createHandler(() =&gt; (
  &lt;StartServer
    document={({ assets, children, scripts }) =&gt; (
      &lt;html lang=&quot;en&quot;&gt;
        &lt;head&gt;
          &lt;meta charset=&quot;utf-8&quot; /&gt;
          &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot; /&gt;
          &lt;link rel=&quot;icon&quot; href=&quot;/favicon.ico&quot; /&gt;
          {assets}
        &lt;/head&gt;
        &lt;body&gt;
          &lt;div id=&quot;app&quot;&gt;{children}&lt;/div&gt;
          {scripts}
        &lt;/body&gt;
      &lt;/html&gt;
    )}
  /&gt;
));
">
<input type="hidden" name="project[files][src/global.d.ts]" value="/// &lt;reference types=&quot;@solidjs/start/env&quot; /&gt;
">
<input type="hidden" name="project[files][src/routes/%5B...404%5D.tsx]" value="export default function NotFound() {
  return (
    &lt;main class=&quot;w-full p-4 space-y-2&quot;&gt;
      &lt;h1 class=&quot;font-bold text-xl&quot;&gt;Page Not Found&lt;/h1&gt;
    &lt;/main&gt;
  );
}
">
<input type="hidden" name="project[files][src/routes/index.tsx]" value="import { createAsync, type RouteDefinition } from &quot;@solidjs/router&quot;;
import { getUser, logout } from &quot;~/lib&quot;;

export const route = {
  preload() {
    getUser();
  }
} satisfies RouteDefinition;

export default function Home() {
  const user = createAsync(() =&gt; getUser(), { deferStream: true });
  return (
    &lt;main class=&quot;w-full p-4 space-y-2&quot;&gt;
      &lt;h2 class=&quot;font-bold text-3xl&quot;&gt;Hello {user()?.username}&lt;/h2&gt;
      &lt;h3 class=&quot;font-bold text-xl&quot;&gt;Message board&lt;/h3&gt;
      &lt;form action={logout} method=&quot;post&quot;&gt;
        &lt;button name=&quot;logout&quot; type=&quot;submit&quot;&gt;
          Logout
        &lt;/button&gt;
      &lt;/form&gt;
    &lt;/main&gt;
  );
}
">
<input type="hidden" name="project[files][src/routes/login.tsx]" value="import {
  useSubmission,
  type RouteSectionProps
} from &quot;@solidjs/router&quot;;
import { Show } from &quot;solid-js&quot;;
import { loginOrRegister } from &quot;~/lib&quot;;

export default function Login(props: RouteSectionProps) {
  const loggingIn = useSubmission(loginOrRegister);

  return (
    &lt;main&gt;
      &lt;h1&gt;Login&lt;/h1&gt;
      &lt;form action={loginOrRegister} method=&quot;post&quot;&gt;
        &lt;input type=&quot;hidden&quot; name=&quot;redirectTo&quot; value={props.params.redirectTo ?? &quot;/&quot;} /&gt;
        &lt;fieldset&gt;
          &lt;legend&gt;Login or Register?&lt;/legend&gt;
          &lt;label&gt;
            &lt;input type=&quot;radio&quot; name=&quot;loginType&quot; value=&quot;login&quot; checked={true} /&gt; Login
          &lt;/label&gt;
          &lt;label&gt;
            &lt;input type=&quot;radio&quot; name=&quot;loginType&quot; value=&quot;register&quot; /&gt; Register
          &lt;/label&gt;
        &lt;/fieldset&gt;
        &lt;div&gt;
          &lt;label for=&quot;username-input&quot;&gt;Username&lt;/label&gt;
          &lt;input name=&quot;username&quot; placeholder=&quot;kody&quot; /&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;label for=&quot;password-input&quot;&gt;Password&lt;/label&gt;
          &lt;input name=&quot;password&quot; type=&quot;password&quot; placeholder=&quot;twixrox&quot; /&gt;
        &lt;/div&gt;
        &lt;button type=&quot;submit&quot;&gt;Login&lt;/button&gt;
        &lt;Show when={loggingIn.result}&gt;
          &lt;p style={{color: &quot;red&quot;}} role=&quot;alert&quot; id=&quot;error-message&quot;&gt;
            {loggingIn.result!.message}
          &lt;/p&gt;
        &lt;/Show&gt;
      &lt;/form&gt;
    &lt;/main&gt;
  );
}
">
<input type="hidden" name="project[files][src/lib/db.ts]" value="import { PrismaClient } from &quot;@prisma/client&quot;;
export const db = new PrismaClient();">
<input type="hidden" name="project[files][src/lib/index.ts]" value="import { action, query, redirect } from &quot;@solidjs/router&quot;;
import { db } from &quot;./db&quot;;
import {
  getSession,
  login,
  logout as logoutSession,
  register,
  validatePassword,
  validateUsername
} from &quot;./server&quot;;

export const getUser = query(async () =&gt; {
  &quot;use server&quot;;
  try {
    const session = await getSession();
    const userId = session.data.userId;
    if (userId === undefined) throw new Error(&quot;User not found&quot;);
    const user = await db.user.findUnique({ where: { id: userId } });
    if (!user) throw new Error(&quot;User not found&quot;);
    return { id: user.id, username: user.username };
  } catch {
    await logoutSession();
    throw redirect(&quot;/login&quot;);
  }
}, &quot;user&quot;);

export const loginOrRegister = action(async (formData: FormData) =&gt; {
  &quot;use server&quot;;
  const username = String(formData.get(&quot;username&quot;));
  const password = String(formData.get(&quot;password&quot;));
  const loginType = String(formData.get(&quot;loginType&quot;));
  let error = validateUsername(username) || validatePassword(password);
  if (error) return new Error(error);

  try {
    const user = await (loginType !== &quot;login&quot;
      ? register(username, password)
      : login(username, password));
    const session = await getSession();
    await session.update(d =&gt; {
      d.userId = user.id;
    });
  } catch (err) {
    return err as Error;
  }
  return redirect(&quot;/&quot;);
});

export const logout = action(async () =&gt; {
  &quot;use server&quot;;
  await logoutSession();
  return redirect(&quot;/login&quot;);
});
">
<input type="hidden" name="project[files][src/lib/server.ts]" value="import { useSession } from &quot;vinxi/http&quot;;
import { db } from &quot;./db&quot;;

export function validateUsername(username: unknown) {
  if (typeof username !== &quot;string&quot; || username.length &lt; 3) {
    return `Usernames must be at least 3 characters long`;
  }
}

export function validatePassword(password: unknown) {
  if (typeof password !== &quot;string&quot; || password.length &lt; 6) {
    return `Passwords must be at least 6 characters long`;
  }
}

export async function login(username: string, password: string) {
  const user = await db.user.findUnique({ where: { username } });
  if (!user || password !== user.password) throw new Error(&quot;Invalid login&quot;);
  return user;
}

export async function logout() {
  const session = await getSession();
  await session.update(d =&gt; {
    d.userId = undefined;
  });
}

export async function register(username: string, password: string) {
  const existingUser = await db.user.findUnique({ where: { username } });
  if (existingUser) throw new Error(&quot;User already exists&quot;);
  return db.user.create({
    data: { username: username, password }
  });
}

export function getSession() {
  return useSession({
    password: process.env.SESSION_SECRET ?? &quot;areallylongsecretthatyoushouldreplace&quot;
  });
}
">
<input type="hidden" name="project[description]" value="generated by https://pkg.pr.new">
<input type="hidden" name="project[template]" value="node">
<input type="hidden" name="project[title]" value="example-with-prisma">
</form>
<script>document.getElementById("mainForm").submit();</script>

</body></html>