From b85f59c54152dd3bc9523ff1ad02c24bcc5252ff Mon Sep 17 00:00:00 2001 From: MuhammadHaseeb12 Date: Fri, 9 Feb 2024 01:59:35 +0500 Subject: [PATCH] add server actions and bug resistence package to execute them safely --- examples/with-server-actions/README.md | 30 ++++++++++++++ examples/with-server-actions/package.json | 22 ++++++++++ .../with-server-actions/public/favicon.ico | Bin 0 -> 664 bytes .../with-server-actions/src/actions/index.ts | 24 +++++++++++ examples/with-server-actions/src/app.css | 39 ++++++++++++++++++ examples/with-server-actions/src/app.tsx | 23 +++++++++++ .../src/components/ActionButton.css | 21 ++++++++++ .../src/components/ActionButton.tsx | 27 ++++++++++++ .../with-server-actions/src/entry-client.tsx | 3 ++ .../with-server-actions/src/entry-server.tsx | 20 +++++++++ examples/with-server-actions/src/global.d.ts | 1 + examples/with-server-actions/src/lib/mock.ts | 7 ++++ .../with-server-actions/src/lib/schema.ts | 8 ++++ examples/with-server-actions/src/lib/types.ts | 8 ++++ .../src/routes/[...404].tsx | 19 +++++++++ .../with-server-actions/src/routes/about.tsx | 10 +++++ .../with-server-actions/src/routes/index.tsx | 20 +++++++++ examples/with-server-actions/tsconfig.json | 19 +++++++++ examples/with-server-actions/vite.config.ts | 3 ++ 19 files changed, 304 insertions(+) create mode 100644 examples/with-server-actions/README.md create mode 100644 examples/with-server-actions/package.json create mode 100644 examples/with-server-actions/public/favicon.ico create mode 100644 examples/with-server-actions/src/actions/index.ts create mode 100644 examples/with-server-actions/src/app.css create mode 100644 examples/with-server-actions/src/app.tsx create mode 100644 examples/with-server-actions/src/components/ActionButton.css create mode 100644 examples/with-server-actions/src/components/ActionButton.tsx create mode 100644 examples/with-server-actions/src/entry-client.tsx create mode 100644 examples/with-server-actions/src/entry-server.tsx create mode 100644 examples/with-server-actions/src/global.d.ts create mode 100644 examples/with-server-actions/src/lib/mock.ts create mode 100644 examples/with-server-actions/src/lib/schema.ts create mode 100644 examples/with-server-actions/src/lib/types.ts create mode 100644 examples/with-server-actions/src/routes/[...404].tsx create mode 100644 examples/with-server-actions/src/routes/about.tsx create mode 100644 examples/with-server-actions/src/routes/index.tsx create mode 100644 examples/with-server-actions/tsconfig.json create mode 100644 examples/with-server-actions/vite.config.ts diff --git a/examples/with-server-actions/README.md b/examples/with-server-actions/README.md new file mode 100644 index 000000000..01282bfab --- /dev/null +++ b/examples/with-server-actions/README.md @@ -0,0 +1,30 @@ +# 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'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 _adapters_, 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 adapter, add it to the `devDependencies` in `package.json` and specify in your `vite.config.js`. diff --git a/examples/with-server-actions/package.json b/examples/with-server-actions/package.json new file mode 100644 index 000000000..fc33c6f47 --- /dev/null +++ b/examples/with-server-actions/package.json @@ -0,0 +1,22 @@ +{ + "name": "example-with-server-actions", + "type": "module", + "scripts": { + "dev": "vinxi dev", + "build": "vinxi build", + "start": "vinxi start" + }, + "dependencies": { + "@solidjs/meta": "^0.29.2", + "@solidjs/router": "^0.11.5", + "@solidjs/start": "^0.5.2", + "solid-js": "^1.8.14", + "vinxi": "^0.2.1", + "zod": "^3.22.4", + "solid-safe-action": "^1.0.0" + + }, + "engines": { + "node": ">=18" + } +} diff --git a/examples/with-server-actions/public/favicon.ico b/examples/with-server-actions/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..fb282da0719ef6ab4c1732df93be6216b0d85520 GIT binary patch literal 664 zcmV;J0%!e+P)m9ebk1R zejT~~6f_`?;`cEd!+`7(hw@%%2;?RN8gX-L?z6cM( zKoG@&w+0}f@Pfvwc+deid)qgE!L$ENKYjViZC_Zcr>L(`2oXUT8f0mRQ(6-=HN_Ai zeBBEz3WP+1Cw`m!49Wf!MnZzp5bH8VkR~BcJ1s-j90TAS2Yo4j!J|KodxYR%3Numw zA?gq6e`5@!W~F$_De3yt&uspo&2yLb$(NwcPPI-4LGc!}HdY%jfq@AFs8LiZ4k(p} zZ!c9o+qbWYs-Mg zgdyTALzJX&7QXHdI_DPTFL33;w}88{e6Zk)MX0kN{3DX9uz#O_L58&XRH$Nvvu;fO zf&)7@?C~$z1K<>j0ga$$MIg+5xN;eQ?1-CA=`^Y169@Ab6!vcaNP=hxfKN%@Ly^R* zK1iv*s1Yl6_dVyz8>ZqYhz6J4|3fQ@2LQeX@^%W(B~8>=MoEmBEGGD1;gHXlpX>!W ym)!leA2L@`cpb^hy)P75=I!`pBYxP7<2VfQ3j76qLgzIA0000 => { + const { title } = data; + let item; + + try { + // Mock database call; + item = await simulateDatabaseCall({ title}) + + } catch (error) { + return { error: 'Failed to create!' }; + } + + + return { data: item }; +}; + +export const createTitle = createSafeAction(CreateTitle, handler); \ No newline at end of file diff --git a/examples/with-server-actions/src/app.css b/examples/with-server-actions/src/app.css new file mode 100644 index 000000000..8596998a4 --- /dev/null +++ b/examples/with-server-actions/src/app.css @@ -0,0 +1,39 @@ +body { + font-family: Gordita, Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", 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; + } +} diff --git a/examples/with-server-actions/src/app.tsx b/examples/with-server-actions/src/app.tsx new file mode 100644 index 000000000..324967b0e --- /dev/null +++ b/examples/with-server-actions/src/app.tsx @@ -0,0 +1,23 @@ +// @refresh reload +import { MetaProvider, Title } from "@solidjs/meta"; +import { Router } from "@solidjs/router"; +import { FileRoutes } from "@solidjs/start"; +import { Suspense } from "solid-js"; +import "./app.css"; + +export default function App() { + return ( + ( + + SolidStart - Basic + Index + About + {props.children} + + )} + > + + + ); +} diff --git a/examples/with-server-actions/src/components/ActionButton.css b/examples/with-server-actions/src/components/ActionButton.css new file mode 100644 index 000000000..77580d86d --- /dev/null +++ b/examples/with-server-actions/src/components/ActionButton.css @@ -0,0 +1,21 @@ +.actionbtn { + font-family: inherit; + font-size: inherit; + padding: 1em 2em; + color: #335d92; + background-color: rgba(68, 107, 158, 0.1); + border-radius: 2em; + border: 2px solid rgba(68, 107, 158, 0); + outline: none; + width: 200px; + font-variant-numeric: tabular-nums; + cursor: pointer; +} + +.actionbtn:focus { + border: 2px solid #335d92; +} + +.actionbtn:active { + background-color: rgba(68, 107, 158, 0.2); +} \ No newline at end of file diff --git a/examples/with-server-actions/src/components/ActionButton.tsx b/examples/with-server-actions/src/components/ActionButton.tsx new file mode 100644 index 000000000..eb8e2bafc --- /dev/null +++ b/examples/with-server-actions/src/components/ActionButton.tsx @@ -0,0 +1,27 @@ +'use client' + +import { useSafeAction } from "solid-safe-action"; +import { createTitle } from "~/actions/index"; +import "./ActionButton.css"; +const ActionButton = () => { + const { execute, isLoading, } = useSafeAction(createTitle, { + onSuccess: (data) => { + window.alert(`Success: ${JSON.stringify(data, null, 2)}`); + }, + onError: (error) => { + window.alert("Error: " + error); + } + }); + + const onClick = (title: string) => { + execute({ title }); + }; + + return ( + + ); +}; + +export default ActionButton \ No newline at end of file diff --git a/examples/with-server-actions/src/entry-client.tsx b/examples/with-server-actions/src/entry-client.tsx new file mode 100644 index 000000000..e10a0fd99 --- /dev/null +++ b/examples/with-server-actions/src/entry-client.tsx @@ -0,0 +1,3 @@ +import { mount, StartClient } from "@solidjs/start/client"; + +mount(() => , document.getElementById("app")); diff --git a/examples/with-server-actions/src/entry-server.tsx b/examples/with-server-actions/src/entry-server.tsx new file mode 100644 index 000000000..407a2afa1 --- /dev/null +++ b/examples/with-server-actions/src/entry-server.tsx @@ -0,0 +1,20 @@ +import { createHandler, StartServer } from "@solidjs/start/server"; + +export default createHandler(() => ( + ( + + + + + + {assets} + + +
{children}
+ {scripts} + + + )} + /> +)); diff --git a/examples/with-server-actions/src/global.d.ts b/examples/with-server-actions/src/global.d.ts new file mode 100644 index 000000000..dc6f10c22 --- /dev/null +++ b/examples/with-server-actions/src/global.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/with-server-actions/src/lib/mock.ts b/examples/with-server-actions/src/lib/mock.ts new file mode 100644 index 000000000..c34c09d00 --- /dev/null +++ b/examples/with-server-actions/src/lib/mock.ts @@ -0,0 +1,7 @@ +export const simulateDatabaseCall = (data: { title: string }): Promise<{ title: string }> => { + return new Promise((resolve) => { + setTimeout(() => { + resolve({ title: data.title }); + }, 1000); + }); + }; \ No newline at end of file diff --git a/examples/with-server-actions/src/lib/schema.ts b/examples/with-server-actions/src/lib/schema.ts new file mode 100644 index 000000000..3552e4fe4 --- /dev/null +++ b/examples/with-server-actions/src/lib/schema.ts @@ -0,0 +1,8 @@ +import { z } from "zod"; + +export const CreateTitle = z.object({ + title: z.string({ + required_error: "Title is required", + invalid_type_error: "Title is required" + }).min(3, { message: 'Title too short' }), +}); \ No newline at end of file diff --git a/examples/with-server-actions/src/lib/types.ts b/examples/with-server-actions/src/lib/types.ts new file mode 100644 index 000000000..eaa90fd49 --- /dev/null +++ b/examples/with-server-actions/src/lib/types.ts @@ -0,0 +1,8 @@ +import { z } from "zod"; + + +import { ActionState } from "solid-safe-action"; +import { CreateTitle } from "./schema"; + +export type InputType = z.infer; +export type ReturnType = ActionState; \ No newline at end of file diff --git a/examples/with-server-actions/src/routes/[...404].tsx b/examples/with-server-actions/src/routes/[...404].tsx new file mode 100644 index 000000000..4ea71ec7f --- /dev/null +++ b/examples/with-server-actions/src/routes/[...404].tsx @@ -0,0 +1,19 @@ +import { Title } from "@solidjs/meta"; +import { HttpStatusCode } from "@solidjs/start"; + +export default function NotFound() { + return ( +
+ Not Found + +

Page Not Found

+

+ Visit{" "} + + start.solidjs.com + {" "} + to learn how to build SolidStart apps. +

+
+ ); +} diff --git a/examples/with-server-actions/src/routes/about.tsx b/examples/with-server-actions/src/routes/about.tsx new file mode 100644 index 000000000..8371d911c --- /dev/null +++ b/examples/with-server-actions/src/routes/about.tsx @@ -0,0 +1,10 @@ +import { Title } from "@solidjs/meta"; + +export default function Home() { + return ( +
+ About +

About

+
+ ); +} diff --git a/examples/with-server-actions/src/routes/index.tsx b/examples/with-server-actions/src/routes/index.tsx new file mode 100644 index 000000000..10c1d291f --- /dev/null +++ b/examples/with-server-actions/src/routes/index.tsx @@ -0,0 +1,20 @@ +import { Title } from "@solidjs/meta"; +import ActionButton from "~/components/ActionButton"; + + +export default function Home() { + return ( +
+ Hello World +

Hello world!

+ +

+ Visit{" "} + + start.solidjs.com + {" "} + to learn how to build SolidStart apps. +

+
+ ); +} diff --git a/examples/with-server-actions/tsconfig.json b/examples/with-server-actions/tsconfig.json new file mode 100644 index 000000000..b9dae7331 --- /dev/null +++ b/examples/with-server-actions/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "allowJs": true, + "strict": true, + "noEmit": true, + "types": ["vinxi/client"], + "isolatedModules": true, + "paths": { + "~/*": ["./src/*"] + } + } +} diff --git a/examples/with-server-actions/vite.config.ts b/examples/with-server-actions/vite.config.ts new file mode 100644 index 000000000..de7f83103 --- /dev/null +++ b/examples/with-server-actions/vite.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from "@solidjs/start/config"; + +export default defineConfig({});