├── .github ├── FUNDING.yml ├── changeset-version.js └── workflows │ └── release.yml ├── .eslintignore ├── .gitignore ├── .npmrc ├── src ├── helpers │ ├── .DS_Store │ ├── utils │ │ ├── getAppLocation.ts │ │ ├── getIndexLocation.ts │ │ └── getReadMe.ts │ ├── solid.ts │ ├── packages.ts │ ├── env.ts │ ├── config.ts │ └── installer.ts ├── installers │ ├── TailwindCSS │ │ ├── files │ │ │ ├── styles.txt │ │ │ ├── postcss.config.txt │ │ │ ├── vscode-settings.txt │ │ │ └── tailwind.config.txt │ │ └── index.ts │ ├── AuthJS │ │ ├── files │ │ │ ├── handler.txt │ │ │ ├── middleware.txt │ │ │ ├── config.txt │ │ │ ├── app.txt │ │ │ └── prisma-config.txt │ │ └── index.ts │ ├── pRPC │ │ ├── files │ │ │ ├── user.txt │ │ │ └── hello.txt │ │ ├── index.ts │ │ └── utils │ │ │ └── getBuilder.ts │ └── Prisma │ │ ├── files │ │ ├── api.txt │ │ └── client.txt │ │ ├── index.ts │ │ └── utils │ │ └── getSchema.ts ├── utils │ ├── jsx.ts │ ├── files.ts │ ├── helpers.ts │ └── project.ts ├── index.ts └── types.ts ├── .husky └── pre-commit ├── template ├── base │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── app.css │ │ ├── entry-client.tsx │ │ ├── env │ │ │ ├── schema.ts │ │ │ ├── server.ts │ │ │ └── client.ts │ │ ├── app.tsx │ │ ├── entry-server.tsx │ │ └── routes │ │ │ ├── index.tsx │ │ │ └── index.module.css │ ├── app.config.ts │ ├── _gitignore │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── README.MD │ └── package.json ├── app │ ├── with-prpc.tsx │ └── with-auth-prpc.tsx └── index │ ├── with-prpc.tsx │ ├── with-tw.tsx │ ├── with-prpc-tw.tsx │ ├── with-auth.tsx │ ├── with-auth-prpc.tsx │ ├── with-auth-tw.tsx │ └── with-auth-prpc-tw.tsx ├── .editorconfig ├── .changeset ├── config.json └── README.md ├── tsconfig.json ├── .eslintrc.json ├── scripts └── copyFiles.ts ├── README.MD ├── package.json └── CHANGELOG.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: orjdev 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | template 2 | dist 3 | scripts -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | my-app 4 | .DS_Store -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | //registry.npmjs.org/:_authToken=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 2 | -------------------------------------------------------------------------------- /src/helpers/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrJDev/create-jd-app/HEAD/src/helpers/.DS_Store -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | pmpm lint-staged 5 | -------------------------------------------------------------------------------- /src/installers/TailwindCSS/files/styles.txt: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /template/base/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrJDev/create-jd-app/HEAD/template/base/public/favicon.ico -------------------------------------------------------------------------------- /template/base/src/app.css: -------------------------------------------------------------------------------- 1 | div { 2 | font-family: system-ui; 3 | font-weight: bold; 4 | font-size: 1.5rem; 5 | color: darkgray; 6 | } 7 | -------------------------------------------------------------------------------- /template/base/app.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "@solidjs/start/config"; 2 | 3 | export default defineConfig({ 4 | ssr: true, 5 | }); 6 | -------------------------------------------------------------------------------- /src/installers/TailwindCSS/files/postcss.config.txt: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /template/base/src/entry-client.tsx: -------------------------------------------------------------------------------- 1 | import { mount, StartClient } from "@solidjs/start/client"; 2 | 3 | mount(() => , document.getElementById("app")!); 4 | -------------------------------------------------------------------------------- /src/installers/TailwindCSS/files/vscode-settings.txt: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.css": "tailwindcss" 4 | }, 5 | "editor.quickSuggestions": { 6 | "strings": true 7 | }, 8 | } -------------------------------------------------------------------------------- /src/installers/AuthJS/files/handler.txt: -------------------------------------------------------------------------------- 1 | import { SolidAuth } from "@solid-mediakit/auth"; 2 | import { authOptions } from "~/server/auth"; 3 | 4 | export const { GET, POST } = SolidAuth(authOptions); 5 | -------------------------------------------------------------------------------- /src/installers/TailwindCSS/files/tailwind.config.txt: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ['./src/**/*.{js,ts,jsx,tsx}'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = false 13 | -------------------------------------------------------------------------------- /src/installers/pRPC/files/user.txt: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { userCaller } from "../prpc"; 3 | 4 | export const protectedQuery = userCaller( 5 | z.object({ 6 | hello: z.string(), 7 | }), 8 | ({ input$, ctx$ }) => { 9 | return `this is top secret: ${input$.hello} ${ctx$.user.name}`; 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /template/base/_gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .solid 3 | .output 4 | .vercel 5 | .netlify 6 | netlify 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | *.launch 16 | .settings/ 17 | 18 | # Temp 19 | gitignore 20 | 21 | # System Files 22 | .DS_Store 23 | Thumbs.db 24 | 25 | .env 26 | -------------------------------------------------------------------------------- /template/base/src/env/schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | export const serverScheme = z.object({ 4 | NODE_ENV: z 5 | .enum(["development", "production", "test"]) 6 | .default("development"), 7 | }); 8 | 9 | export const clientScheme = z.object({ 10 | MODE: z.enum(["development", "production", "test"]).default("development"), 11 | }); 12 | -------------------------------------------------------------------------------- /src/installers/pRPC/files/hello.txt: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { helloCaller } from "../prpc"; 3 | 4 | export const helloQuery = helloCaller( 5 | z.object({ 6 | hello: z.string(), 7 | }), 8 | ({ input$, ctx$ }) => { 9 | if (input$.hello === "hello") { 10 | return ctx$.hello; 11 | } 12 | return ctx$.world; 13 | }, 14 | ); 15 | -------------------------------------------------------------------------------- /src/installers/AuthJS/files/middleware.txt: -------------------------------------------------------------------------------- 1 | import { authMiddleware } from "@solid-mediakit/auth"; 2 | import { createMiddleware } from "@solidjs/start/middleware"; 3 | import { authOptions } from "./server/auth"; 4 | 5 | const pathsToPreload = ["/"]; 6 | 7 | export default createMiddleware({ 8 | onRequest: [authMiddleware(pathsToPreload, authOptions)], 9 | }); 10 | -------------------------------------------------------------------------------- /template/base/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | }, 6 | "plugins": ["@typescript-eslint"], 7 | "extends": [ 8 | "plugin:solid/typescript", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/consistent-type-imports": "warn" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.2.0/schema.json", 3 | "changelog": [ 4 | "@changesets/changelog-github", 5 | { "repo": "OrJDev/create-jd-app" } 6 | ], 7 | "commit": false, 8 | "fixed": [], 9 | "linked": [], 10 | "access": "public", 11 | "baseBranch": "main", 12 | "updateInternalDependencies": "patch" 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "baseUrl": "./", 6 | "paths": { 7 | "~*": ["./src/*"] 8 | }, 9 | "noEmit": false, 10 | "esModuleInterop": true, 11 | "strict": true, 12 | "noUnusedLocals": true, 13 | "outDir": "dist", 14 | }, 15 | "include": ["./src/"], 16 | "exclude": ["node_modules", "template"] 17 | } 18 | -------------------------------------------------------------------------------- /src/installers/Prisma/files/api.txt: -------------------------------------------------------------------------------- 1 | import { prisma } from "~/server/db"; 2 | import { APIEvent } from '@solidjs/start/server/types' 3 | 4 | export async function GET() { 5 | return await prisma.notes.findMany(); 6 | } 7 | 8 | export async function POST(event: APIEvent) { 9 | const { text } = await event.request.json(); 10 | return await prisma.notes.create({ 11 | data: { 12 | text, 13 | }, 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "plugin:@typescript-eslint/recommended", 5 | "plugin:promise/recommended", 6 | "prettier" 7 | ], 8 | "parser": "@typescript-eslint/parser", 9 | "plugins": ["@typescript-eslint"], 10 | "parserOptions": { 11 | "project": ["./tsconfig.json"] 12 | }, 13 | "rules": { 14 | "@typescript-eslint/consistent-type-imports": "warn" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/helpers/utils/getAppLocation.ts: -------------------------------------------------------------------------------- 1 | import type { ICtx } from "~types"; 2 | 3 | const getAppLocation = (ctx: ICtx) => { 4 | const usingPRPC = ctx.installers.includes("pRPC"); 5 | const usingAuth = ctx.installers.includes("AuthJS"); 6 | 7 | if (usingPRPC && usingAuth) 8 | return `${ctx.templateDir}/app/with-auth-prpc.tsx`; 9 | else if (usingPRPC) return `${ctx.templateDir}/app/with-prpc.tsx`; 10 | return ``; 11 | }; 12 | 13 | export default getAppLocation; 14 | -------------------------------------------------------------------------------- /template/base/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "esModuleInterop": true, 5 | "strict": true, 6 | "target": "ESNext", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "jsxImportSource": "solid-js", 10 | "jsx": "preserve", 11 | "types": ["vite/client", "@solidjs/start/env"], 12 | "baseUrl": "./", 13 | "paths": { 14 | "~/*": ["./src/*"] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /src/installers/Prisma/files/client.txt: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | import { serverEnv } from "~/env/server"; 3 | 4 | declare global { 5 | // eslint-disable-next-line no-var 6 | var prisma: PrismaClient | undefined; 7 | } 8 | 9 | export const prisma = 10 | global.prisma || 11 | new PrismaClient({ 12 | log: 13 | serverEnv.NODE_ENV === "development" 14 | ? ["query", "error", "warn"] 15 | : ["error"], 16 | }); 17 | 18 | if (serverEnv.NODE_ENV !== "production") { 19 | global.prisma = prisma; 20 | } 21 | -------------------------------------------------------------------------------- /template/base/README.MD: -------------------------------------------------------------------------------- 1 | This project was created using [Create JD App](https://github.com/OrJDev/create-jd-app) 2 | 3 | ## Start Dev Server 4 | 5 | ```bash 6 | pnpm dev 7 | ``` 8 | 9 | This will start a dev server on port `3000` and will watch for changes. 10 | 11 | ## Testing Production Build 12 | 13 | ### Build 14 | 15 | ```bash 16 | pnpm build 17 | ``` 18 | 19 | ### Start 20 | 21 | ```bash 22 | pnpm start 23 | ``` 24 | 25 | This will start a production server on port `3000`. 26 | 27 | [Sponsor Create JD App](https://github.com/sponsors/OrJDev) 28 | -------------------------------------------------------------------------------- /template/base/src/app.tsx: -------------------------------------------------------------------------------- 1 | // @refresh reload 2 | import "./app.css"; 3 | import { MetaProvider, Title } from "@solidjs/meta"; 4 | import { Router } from "@solidjs/router"; 5 | import { FileRoutes } from "@solidjs/start/router"; 6 | import { Suspense } from "solid-js"; 7 | 8 | export default function App() { 9 | return ( 10 | ( 12 | 13 | Create JD APP 14 | {props.children} 15 | 16 | )} 17 | > 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/installers/AuthJS/files/config.txt: -------------------------------------------------------------------------------- 1 | import { type SolidAuthConfig } from "@solid-mediakit/auth"; 2 | import Discord from "@auth/core/providers/discord"; 3 | import { serverEnv } from "~/env/server"; 4 | 5 | declare module "@auth/core/types" { 6 | export interface Session { 7 | user: DefaultSession["user"]; 8 | } 9 | } 10 | 11 | export const authOptions: SolidAuthConfig = { 12 | providers: [ 13 | Discord({ 14 | clientId: serverEnv.DISCORD_ID, 15 | clientSecret: serverEnv.DISCORD_SECRET, 16 | }), 17 | ], 18 | debug: false, 19 | basePath: import.meta.env.VITE_AUTH_PATH, 20 | }; 21 | -------------------------------------------------------------------------------- /template/base/src/entry-server.tsx: -------------------------------------------------------------------------------- 1 | import { createHandler, StartServer } from "@solidjs/start/server"; 2 | 3 | export default createHandler(() => ( 4 | ( 6 | 7 | 8 | 9 | 10 | 11 | {assets} 12 | 13 | 14 | {children} 15 | {scripts} 16 | 17 | 18 | )} 19 | /> 20 | )); 21 | -------------------------------------------------------------------------------- /scripts/copyFiles.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs-extra"; 2 | import path from "path"; 3 | 4 | const basePath = path.join(__dirname, "../src", "installers"); 5 | 6 | async function main() { 7 | await Promise.all([ 8 | ...( 9 | await fs.readdir(basePath) 10 | ).map(async (installer) => { 11 | const oldPath = path.join(basePath, installer, "files"); 12 | const newPath = oldPath.replace("src", "dist"); 13 | if (await fs.pathExists(oldPath)) { 14 | await fs.copy(oldPath, newPath); 15 | } 16 | }), 17 | fs.copy( 18 | path.join(__dirname, "../README.MD"), 19 | path.join(__dirname, "../dist/README.MD") 20 | ), 21 | ]); 22 | } 23 | 24 | main(); -------------------------------------------------------------------------------- /.github/changeset-version.js: -------------------------------------------------------------------------------- 1 | // ORIGINALLY FROM CLOUDFLARE WRANGLER: 2 | // https://github.com/cloudflare/wrangler2/blob/main/.github/changeset-version.js 3 | 4 | const { exec } = require("child_process"); 5 | // This script is used by the `release.yml` workflow to update the version of the packages being released. 6 | // The standard step is only to run `changeset version` but this does not update the package-lock.json file. 7 | // So we also run `npm install`, which does this update. 8 | // This is a workaround until this is handled automatically by `changeset version`. 9 | // See https://github.com/changesets/changesets/issues/421. 10 | exec("pnpm changeset version"); 11 | exec("pnpm i --lockfile-only --no-frozen-lockfile"); 12 | -------------------------------------------------------------------------------- /src/installers/AuthJS/files/app.txt: -------------------------------------------------------------------------------- 1 | // @refresh reload 2 | import { MetaProvider, Title } from '@solidjs/meta' 3 | import { Router } from '@solidjs/router' 4 | import { FileRoutes } from '@solidjs/start/router' 5 | import { Suspense } from 'solid-js' 6 | import './app.css' 7 | import { SessionProvider } from '@solid-mediakit/auth/client' 8 | 9 | export default function App() { 10 | return ( 11 | ( 13 | 14 | Create JD APP 15 | 16 | {props.children} 17 | 18 | 19 | )} 20 | > 21 | 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/jsx.ts: -------------------------------------------------------------------------------- 1 | const SPACES_PER_LINE = 5; 2 | const ADD_SPACES_PER_LINE = 2; 3 | 4 | export function resolveProviders( 5 | providers: string[], 6 | children: string[], 7 | spaces = SPACES_PER_LINE 8 | ): string { 9 | const SPACES = " ".repeat(spaces - 1); 10 | if (!providers.length) 11 | return children.map((child) => `${SPACES}${child}`).join("\n"); 12 | const el = providers.shift(); 13 | const elWithoutProps = el.split(" ").shift(); 14 | return `${SPACES}<${el}>\n${resolveProviders( 15 | providers, 16 | children, 17 | spaces + ADD_SPACES_PER_LINE 18 | )}\n${SPACES}${elWithoutProps}>`; 19 | } 20 | 21 | export const getStyle = (useTW: boolean, style: string) => 22 | useTW ? ` class="${style}"` : ""; 23 | -------------------------------------------------------------------------------- /template/base/src/env/server.ts: -------------------------------------------------------------------------------- 1 | import { serverScheme } from "./schema"; 2 | import type { ZodFormattedError } from "zod"; 3 | 4 | export const formatErrors = ( 5 | errors: ZodFormattedError, string> 6 | ) => 7 | Object.entries(errors) 8 | .map(([name, value]) => { 9 | if (value && "_errors" in value) 10 | return `${name}: ${value._errors.join(", ")}\n`; 11 | }) 12 | .filter(Boolean); 13 | 14 | const env = serverScheme.safeParse(process.env); 15 | 16 | if (env.success === false) { 17 | console.error( 18 | "❌ Invalid environment variables:\n", 19 | ...formatErrors(env.error.format()) 20 | ); 21 | throw new Error("Invalid environment variables"); 22 | } 23 | 24 | export const serverEnv = env.data; 25 | -------------------------------------------------------------------------------- /template/base/src/env/client.ts: -------------------------------------------------------------------------------- 1 | import type { ZodFormattedError } from "zod"; 2 | import { clientScheme } from "./schema"; 3 | 4 | export const formatErrors = ( 5 | errors: ZodFormattedError, string> 6 | ) => 7 | Object.entries(errors) 8 | .map(([name, value]) => { 9 | if (value && "_errors" in value) 10 | return `${name}: ${value._errors.join(", ")}\n`; 11 | }) 12 | .filter(Boolean); 13 | 14 | const env = clientScheme.safeParse(import.meta.env); 15 | 16 | if (env.success === false) { 17 | console.error( 18 | "❌ Invalid environment variables:\n", 19 | ...formatErrors(env.error.format()) 20 | ); 21 | throw new Error("Invalid environment variables"); 22 | } 23 | 24 | export const clientEnv = env.data; 25 | -------------------------------------------------------------------------------- /template/app/with-prpc.tsx: -------------------------------------------------------------------------------- 1 | // @refresh reload 2 | import "./app.css"; 3 | import { MetaProvider, Title } from "@solidjs/meta"; 4 | import { Router } from "@solidjs/router"; 5 | import { FileRoutes } from "@solidjs/start/router"; 6 | import { Suspense } from "solid-js"; 7 | import { QueryClient, QueryClientProvider } from "@tanstack/solid-query"; 8 | 9 | export default function App() { 10 | const queryClient = new QueryClient(); 11 | return ( 12 | ( 14 | 15 | Create JD App 16 | 17 | {props.children} 18 | 19 | 20 | )} 21 | > 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /template/base/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "template", 3 | "scripts": { 4 | "dev": "vinxi dev", 5 | "build": "vinxi build", 6 | "start": "vinxi start", 7 | "lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"" 8 | }, 9 | "type": "module", 10 | "devDependencies": { 11 | "@types/node": "^20.11.26", 12 | "@typescript-eslint/eslint-plugin": "^7.6.0", 13 | "@typescript-eslint/parser": "^7.6.0", 14 | "eslint": "^9.13.0", 15 | "eslint-plugin-solid": "^0.14.3", 16 | "typescript": "^5.6.2", 17 | "vite": "^6.2.2" 18 | }, 19 | "dependencies": { 20 | "@solidjs/meta": "^0.29.4", 21 | "@solidjs/router": "^0.15.1", 22 | "@solidjs/start": "^1.1.3", 23 | "solid-js": "^1.9.5", 24 | "vinxi": "^0.5.3", 25 | "zod": "^3.23.8" 26 | }, 27 | "engines": { 28 | "node": ">=16" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Create JD App 2 | 3 | Create advanced SolidStart web application within seconds. 4 | 5 | ## Getting Started 6 | 7 | ```bash 8 | pnpm create jd-app@latest 9 | ``` 10 | 11 | ## Base Template 12 | 13 | - [Solid Start](https://github.com/solidjs/solid-start) 14 | - [TypeScript](https://github.com/microsoft/TypeScript) 15 | - [Zod](https://github.com/colinhacks/zod) 16 | - [Solid EsLint](https://github.com/solidjs-community/eslint-plugin-solid) 17 | 18 | ## Addons 19 | 20 | All addons are optional, you may select some, you may select all and you may select none. 21 | 22 | - [Prisma](https://github.com/prisma/prisma) 23 | - [pRPC](https://github.com/solidjs-community/mediakit/tree/main/packages/prpc/solid) 24 | - [TailwindCSS](https://github.com/tailwindlabs/tailwindcss) 25 | - [AuthJS](https://github.com/solidjs-community/mediakit/tree/main/packages/auth) 26 | -------------------------------------------------------------------------------- /src/installers/TailwindCSS/index.ts: -------------------------------------------------------------------------------- 1 | import { withPackages } from "~helpers/packages"; 2 | import type { IInstaller } from "~types"; 3 | 4 | const config: IInstaller = (ctx) => ({ 5 | files: [ 6 | { 7 | path: `${__dirname}/files/styles.txt`, 8 | to: `${ctx.userDir}/src/app.css`, 9 | }, 10 | { 11 | path: `${__dirname}/files/postcss.config.txt`, 12 | to: `${ctx.userDir}/postcss.config.cjs`, 13 | }, 14 | { 15 | path: `${__dirname}/files/tailwind.config.txt`, 16 | to: `${ctx.userDir}/tailwind.config.cjs`, 17 | }, 18 | { 19 | path: `${__dirname}/files/vscode-settings.txt`, 20 | to: `${ctx.userDir}/.vscode/settings.json`, 21 | }, 22 | { 23 | to: `${ctx.userDir}/src/routes/index.module.css`, 24 | type: "delete", 25 | }, 26 | ], 27 | pkgs: withPackages({ 28 | normal: ["postcss", "autoprefixer", "tailwindcss"], 29 | }), 30 | }); 31 | 32 | export default config; 33 | -------------------------------------------------------------------------------- /template/app/with-auth-prpc.tsx: -------------------------------------------------------------------------------- 1 | // @refresh reload 2 | import "./app.css"; 3 | import { MetaProvider, Title } from "@solidjs/meta"; 4 | import { Router } from "@solidjs/router"; 5 | import { FileRoutes } from "@solidjs/start/router"; 6 | import { Suspense } from "solid-js"; 7 | import { QueryClient, QueryClientProvider } from "@tanstack/solid-query"; 8 | import { SessionProvider } from "@solid-mediakit/auth/client"; 9 | 10 | export default function App() { 11 | const queryClient = new QueryClient(); 12 | return ( 13 | ( 15 | 16 | Create JD App 17 | 18 | 19 | {props.children} 20 | 21 | 22 | 23 | )} 24 | > 25 | 26 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /src/installers/AuthJS/files/prisma-config.txt: -------------------------------------------------------------------------------- 1 | import { type SolidAuthConfig } from "@solid-mediakit/auth"; 2 | import Discord from "@auth/core/providers/discord"; 3 | import { PrismaAdapter } from "@auth/prisma-adapter"; 4 | import { prisma } from "./db"; 5 | import { serverEnv } from "~/env/server"; 6 | 7 | declare module "@auth/core/types" { 8 | export interface Session { 9 | user: { 10 | id: string; 11 | } & DefaultSession["user"]; 12 | } 13 | } 14 | 15 | export const authOptions: SolidAuthConfig = { 16 | callbacks: { 17 | session({ session, user }) { 18 | if (session.user) { 19 | session.user.id = user.id; 20 | } 21 | return session; 22 | }, 23 | }, 24 | adapter: PrismaAdapter(prisma), 25 | providers: [ 26 | Discord({ 27 | clientId: serverEnv.DISCORD_ID, 28 | clientSecret: serverEnv.DISCORD_SECRET, 29 | }), 30 | ], 31 | debug: false, 32 | basePath: import.meta.env.VITE_AUTH_PATH, 33 | }; 34 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import * as project from "./utils/project"; 4 | import { formatError } from "./utils/helpers"; 5 | import chalk from "chalk"; 6 | import runInstallers, { getCtxWithInstallers } from "./helpers/installer"; 7 | 8 | async function main() { 9 | const args = process.argv 10 | .slice(2) 11 | .filter((arg) => arg.startsWith("--")) 12 | .map((arg) => arg.slice(2).toLowerCase()); 13 | const appCtx = await project.initApp(args); 14 | await project.copyTemplate(appCtx); 15 | const ctx = await getCtxWithInstallers(appCtx, args); 16 | const [scripts, deps, env, commands] = await runInstallers(ctx); 17 | await project.modifyProject(ctx, deps, scripts, env); 18 | await project.installDeps(ctx); 19 | await project.runCommands(appCtx, commands); 20 | project.finished(ctx); 21 | } 22 | 23 | main().catch((e) => { 24 | console.log( 25 | `\n ${chalk.blue("Something went wrong:")} ${chalk.red(formatError(e))}\n`, 26 | ); 27 | process.exit(1); 28 | }); 29 | -------------------------------------------------------------------------------- /src/installers/pRPC/index.ts: -------------------------------------------------------------------------------- 1 | import { withPackages } from "~helpers/packages"; 2 | import type { IInstaller } from "~types"; 3 | 4 | const config: IInstaller = (ctx) => { 5 | const useAuth = ctx.installers.includes("AuthJS"); 6 | return { 7 | pkgs: withPackages({ 8 | normal: [ 9 | "@solid-mediakit/prpc", 10 | "@solid-mediakit/prpc-plugin", 11 | "@tanstack/solid-query", 12 | ], 13 | }), 14 | files: [ 15 | { 16 | path: `${__dirname}/files/hello.txt`, 17 | to: `${ctx.userDir}/src/server/hello/hello.queries.ts`, 18 | }, 19 | { 20 | path: `${__dirname}/utils/getBuilder`, 21 | to: `${ctx.userDir}/src/server/prpc.ts`, 22 | type: "exec", 23 | }, 24 | useAuth 25 | ? { 26 | path: `${__dirname}/files/user.txt`, 27 | to: `${ctx.userDir}/src/server/user/user.queries.ts`, 28 | } 29 | : undefined, 30 | ], 31 | }; 32 | }; 33 | 34 | export default config; 35 | -------------------------------------------------------------------------------- /src/helpers/solid.ts: -------------------------------------------------------------------------------- 1 | import { execFiles } from "~utils/files"; 2 | import type { ICtx, IEnv, IFile } from "~types"; 3 | import getIndexLocation from "./utils/getIndexLocation"; 4 | import getAppLocation from "./utils/getAppLocation"; 5 | 6 | const helperFunc = async (ctx: ICtx, env: IEnv[]) => { 7 | const indexLocation = getIndexLocation(ctx); 8 | const appLocation = getAppLocation(ctx); 9 | const files: IFile[] = [ 10 | { 11 | path: `${__dirname}/utils/getReadMe`, 12 | type: "exec", 13 | to: `${ctx.userDir}/README.MD`, 14 | pass: env, 15 | ignorePrettier: true 16 | }, 17 | ]; 18 | if (indexLocation) { 19 | files.push({ 20 | path: indexLocation, 21 | type: "copy", 22 | to: `${ctx.userDir}/src/routes/index.tsx`, 23 | }); 24 | } 25 | if (appLocation) { 26 | files.push({ 27 | path: appLocation, 28 | type: "copy", 29 | to: `${ctx.userDir}/src/app.tsx`, 30 | }); 31 | } 32 | await execFiles(files, ctx); 33 | }; 34 | 35 | export default helperFunc; 36 | -------------------------------------------------------------------------------- /src/installers/pRPC/utils/getBuilder.ts: -------------------------------------------------------------------------------- 1 | import type { IUtil } from "~types"; 2 | 3 | const getBuilder: IUtil = (ctx) => { 4 | const useAuth = ctx.installers.includes("AuthJS"); 5 | return `import { createCaller${ 6 | useAuth ? ", error$" : "" 7 | } } from "@solid-mediakit/prpc";${ 8 | useAuth 9 | ? `\nimport { authOptions } from "./auth";\nimport { getSession } from "@solid-mediakit/auth";` 10 | : "" 11 | } 12 | 13 | export const helloCaller = createCaller 14 | .use(() => { 15 | return { 16 | hello: 1, 17 | }; 18 | }) 19 | .use(({ ctx$ }) => { 20 | return { 21 | ...ctx$, 22 | world: 2, 23 | }; 24 | });${ 25 | useAuth 26 | ? `\n\nexport const userCaller = createCaller.use(async ({ event$ }) => { 27 | const session = await getSession(event$.request, authOptions); 28 | if (!session) { 29 | return error$("Unauthorized", { 30 | status: 401, 31 | }); 32 | } 33 | return session; 34 | });` 35 | : "" 36 | } 37 | `; 38 | }; 39 | 40 | export default getBuilder; 41 | -------------------------------------------------------------------------------- /src/installers/Prisma/index.ts: -------------------------------------------------------------------------------- 1 | import { withPackages } from "~helpers/packages"; 2 | import type { IInstaller } from "~types"; 3 | 4 | const config: IInstaller = (ctx) => ({ 5 | files: [ 6 | { 7 | path: `${__dirname}/utils/getSchema`, 8 | type: "exec", 9 | to: `${ctx.userDir}/prisma/schema.prisma`, 10 | ignorePrettier: true, 11 | }, 12 | { 13 | path: `${__dirname}/files/client.txt`, 14 | to: `${ctx.userDir}/src/server/db.ts`, 15 | }, 16 | !ctx.installers.includes("AuthJS") 17 | ? { 18 | path: `${__dirname}/files/api.txt`, 19 | to: `${ctx.userDir}/src/routes/api/notes.ts`, 20 | } 21 | : undefined, 22 | ], 23 | scripts: { 24 | push: "prisma db push", 25 | postinstall: "prisma generate", 26 | }, 27 | env: [ 28 | { 29 | key: "DATABASE_URL", 30 | type: "string()", 31 | defaulValue: "file:./db.sqlite", 32 | kind: "server", 33 | }, 34 | ], 35 | pkgs: withPackages({ 36 | dev: "prisma", 37 | normal: "@prisma/client", 38 | }), 39 | commands: `${ctx.pkgManager === "npm" ? "npx" : "pnpm"} prisma db push`, 40 | }); 41 | 42 | export default config; 43 | -------------------------------------------------------------------------------- /src/helpers/utils/getIndexLocation.ts: -------------------------------------------------------------------------------- 1 | import type { ICtx } from "~types"; 2 | 3 | const getIndexLocation = (ctx: ICtx) => { 4 | const usingPRPC = ctx.installers.includes("pRPC"); 5 | const usingTw = ctx.installers.includes("TailwindCSS"); 6 | const usingAuth = ctx.installers.includes("AuthJS"); 7 | return createFileHelper(usingPRPC, usingTw, usingAuth, ctx); 8 | }; 9 | 10 | export default getIndexLocation; 11 | 12 | function createFileHelper( 13 | usingPRPC: boolean, 14 | usingTw: boolean, 15 | usingAuth: boolean, 16 | ctx: ICtx, 17 | ) { 18 | const fileName = usingPRPC ? `prpc` : ""; 19 | let indexFile = ""; 20 | if (usingPRPC && usingTw && usingAuth) { 21 | indexFile = `with-auth-${fileName}-tw.tsx`; 22 | } else if (usingPRPC && !usingTw && usingAuth) { 23 | indexFile = `with-auth-${fileName}.tsx`; 24 | } else if (usingPRPC && usingTw) { 25 | indexFile = `with-${fileName}-tw.tsx`; 26 | } else if (usingPRPC && !usingTw) { 27 | indexFile = `with-${fileName}.tsx`; 28 | } else if (usingAuth && usingTw) { 29 | indexFile = "with-auth-tw.tsx"; 30 | } else if (!usingPRPC && usingTw) { 31 | indexFile = "with-tw.tsx"; 32 | } else if (usingAuth) { 33 | indexFile = "with-auth.tsx"; 34 | } 35 | 36 | return indexFile ? `${ctx.templateDir}/index/${indexFile}` : ``; 37 | } 38 | -------------------------------------------------------------------------------- /template/base/src/routes/index.tsx: -------------------------------------------------------------------------------- 1 | import styles from "./index.module.css"; 2 | import { type VoidComponent } from "solid-js"; 3 | import { A } from "@solidjs/router"; 4 | 5 | const Home: VoidComponent = () => { 6 | return ( 7 | 8 | 9 | 10 | Create JD App 11 | 12 | 13 | 18 | Solid Start → 19 | 20 | Learn more about Solid Start and the basics. 21 | 22 | 23 | 28 | JD End → 29 | 30 | Learn more about Create JD App, the libraries it uses, and how to 31 | deploy it 32 | 33 | 34 | 35 | 36 | 37 | ); 38 | }; 39 | 40 | export default Home; 41 | -------------------------------------------------------------------------------- /src/helpers/utils/getReadMe.ts: -------------------------------------------------------------------------------- 1 | import type { IEnv, IUtil } from "~types"; 2 | 3 | const getReadMe: IUtil = (ctx, passed = []) => { 4 | const envContent = `### Enviroment Variables 5 | 6 | ${passed 7 | .filter((env) => !env.ignore || env.key === "ENABLE_VC_BUILD") 8 | .map((env) => `- \`${env.key}\`=${env.defaulValue ?? ""}`) 9 | .join("\n")} 10 | `; 11 | const runCmd = ctx.pkgManager === "pnpm" ? "" : " run"; 12 | return `This project was created using [Create JD App](https://github.com/OrJDev/create-jd-app) 13 | 14 | ## Start Dev Server 15 | 16 | \`\`\`bash 17 | ${ctx.pkgManager}${runCmd} dev 18 | \`\`\` 19 | 20 | This will start a dev server on port \`3000\` and will watch for changes. 21 | 22 | ## Testing Production Build 23 | 24 | ### Build 25 | 26 | \`\`\`bash 27 | ${ctx.pkgManager}${runCmd} build 28 | \`\`\` 29 | 30 | ### Start 31 | 32 | \`\`\`bash 33 | ${ctx.pkgManager}${runCmd} start 34 | \`\`\` 35 | 36 | This will start a production server on port \`3000\`. 37 | ${ 38 | ctx.vercel === "Cli" 39 | ? `\n## Deploying To Vercel 40 | 41 | ### Building 42 | 43 | \`\`\`bash 44 | vercel build --prod 45 | \`\`\` 46 | 47 | ### Deploying 48 | 49 | \`\`\`bash 50 | vercel deploy --prod --prebuilt 51 | \`\`\`` 52 | : "" 53 | } 54 | ${envContent} 55 | [Sponsor Create JD App](https://github.com/sponsors/OrJDev) 56 | `; 57 | }; 58 | 59 | export default getReadMe; 60 | -------------------------------------------------------------------------------- /template/index/with-prpc.tsx: -------------------------------------------------------------------------------- 1 | import { type VoidComponent } from "solid-js"; 2 | import { A } from "@solidjs/router"; 3 | import styles from "./index.module.css"; 4 | import { helloQuery } from "~/server/hello/hello.queries"; 5 | 6 | const Home: VoidComponent = () => { 7 | const hello = helloQuery(() => ({ hello: "from pRPC" })); 8 | return ( 9 | 10 | 11 | 12 | Create JD App 13 | 14 | 15 | 20 | Solid Start → 21 | 22 | Learn more about Solid Start and the basics. 23 | 24 | 25 | 30 | JD End → 31 | 32 | Learn more about Create JD App, the libraries it uses, and how to 33 | deploy it 34 | 35 | 36 | 37 | {hello.data} 38 | 39 | 40 | ); 41 | }; 42 | 43 | export default Home; 44 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { IExpectedPackages } from "~helpers/packages"; 2 | import type { getUserPackageManager } from "~utils/helpers"; 3 | 4 | export type IAppCtx = { 5 | userDir: string; 6 | appName: string; 7 | templateDir: string; 8 | vercel?: IVercelOpt; 9 | pkgManager: ReturnType; 10 | }; 11 | 12 | export type IVercelOpt = "Cli" | "Dashboard"; 13 | 14 | export type INullAble = T | null; 15 | 16 | export type IPromiseOrType = Promise | T; 17 | 18 | export type ICtxWith = IAppCtx & T; 19 | 20 | export type ICtx = ICtxWith<{ 21 | installers: TInstallers[]; 22 | }>; 23 | 24 | export type IConfig = { 25 | files?: Array; 26 | pkgs?: IExpectedPackages; 27 | scripts?: Record; 28 | env?: IEnv[]; 29 | commands?: string | string[]; 30 | }; 31 | 32 | type IInstallerCB = (ctx: ICtx) => IPromiseOrType; 33 | export type IInstaller = IConfig | IInstallerCB; 34 | 35 | export type IFile = { 36 | to: string; 37 | content?: string; 38 | type?: "copy" | "exec" | "delete" | "write" | "append"; 39 | path?: string; 40 | sep?: boolean; 41 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 42 | pass?: any; 43 | ignorePrettier?: boolean; 44 | }; 45 | 46 | export type IEnv = { 47 | type: string; 48 | key: string; 49 | defaulValue?: string; 50 | ignore?: boolean; 51 | kind: "server" | "client"; 52 | }; 53 | 54 | export type IUtil = ( 55 | ctx: ICtx, 56 | passed?: T, 57 | ) => string | Promise; 58 | 59 | export type TInstallers = "AuthJS" | "Prisma" | "TailwindCSS" | "pRPC"; 60 | -------------------------------------------------------------------------------- /template/index/with-tw.tsx: -------------------------------------------------------------------------------- 1 | import { type VoidComponent } from "solid-js"; 2 | import { A } from "@solidjs/router"; 3 | 4 | const Home: VoidComponent = () => { 5 | return ( 6 | 7 | 8 | 9 | Create JD App 10 | 11 | 12 | 17 | Solid Start → 18 | 19 | Learn more about Solid Start and the basics. 20 | 21 | 22 | 27 | JD End → 28 | 29 | Learn more about Create JD App, the libraries it uses, and how to 30 | deploy it. 31 | 32 | 33 | 34 | 35 | 36 | ); 37 | }; 38 | 39 | export default Home; 40 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | concurrency: ${{ github.workflow }}-${{ github.ref }} 8 | 9 | jobs: 10 | release: 11 | name: Release 12 | runs-on: ubuntu-latest 13 | env: 14 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} 15 | TURBO_TEAM: ${{ secrets.TURBO_TEAM }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | 22 | - uses: pnpm/action-setup@v4 23 | 24 | - name: Setup Node.js 25 | uses: actions/setup-node@v4 26 | with: 27 | node-version: 20 28 | cache: "pnpm" 29 | 30 | - name: Creating .npmrc 31 | run: | 32 | cat << EOF > "$HOME/.npmrc" 33 | //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }} 34 | EOF 35 | 36 | - name: Verify NPM Authentication 37 | continue-on-error: true 38 | run: | 39 | echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc 40 | npm whoami 41 | 42 | - name: Install dependencies 43 | run: pnpm install 44 | 45 | - name: Build 46 | run: pnpm build 47 | 48 | - name: Create Release 49 | uses: changesets/action@v1.4.7 50 | with: 51 | commit: "chore(release): 📦 version packages" 52 | title: "chore(release): 📦 version packages" 53 | version: node .github/changeset-version.js 54 | publish: pnpm changeset publish 55 | env: 56 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 58 | -------------------------------------------------------------------------------- /src/helpers/packages.ts: -------------------------------------------------------------------------------- 1 | const packages = { 2 | dev: { 3 | // prisma 4 | prisma: "^6.5.0", 5 | }, 6 | normal: { 7 | // prisma 8 | "@prisma/client": "^6.5.0", 9 | // prpc 10 | "@tanstack/solid-query": "^5.69.0", 11 | "@solid-mediakit/prpc": "^2.1.2", 12 | "@solid-mediakit/prpc-plugin": "^2.1.1", 13 | // authjs 14 | "@solid-mediakit/auth": "^3.1.3", 15 | "@auth/core": "^0.38.0", 16 | "@auth/prisma-adapter": "^2.8.0", 17 | // tailwind 18 | postcss: "^8.4.40", 19 | tailwindcss: "^3.4.7", 20 | autoprefixer: "^10.4.19", 21 | }, 22 | }; 23 | 24 | export type IPkgs = typeof packages; 25 | export type KeyOrKeyArray = 26 | | keyof IPkgs[K] 27 | | (keyof IPkgs[K])[]; 28 | 29 | export function withPackages(optIn: { [K in keyof IPkgs]?: KeyOrKeyArray }) { 30 | const devs: { [K in keyof IPkgs["dev"]]?: string } = {}; 31 | const normals: { [K in keyof IPkgs["normal"]]?: string } = {}; 32 | for (const keyType in optIn) { 33 | type OptIn = keyof typeof optIn; 34 | const __curr = optIn[keyType as OptIn]; 35 | const arrOptIn = Array.isArray(__curr) ? __curr : [__curr]; 36 | for (const curr of arrOptIn) { 37 | const name = curr?.includes("->") ? curr.split("->")[0] : curr; 38 | if (keyType === "dev") { 39 | devs[name as keyof typeof devs] = 40 | packages.dev[curr as keyof typeof packages.dev]; 41 | } else { 42 | normals[name as keyof typeof normals] = 43 | packages.normal[curr as keyof typeof packages.normal]; 44 | } 45 | } 46 | } 47 | return [normals, devs]; 48 | } 49 | 50 | export type IExpectedPackages = ReturnType; 51 | -------------------------------------------------------------------------------- /template/index/with-prpc-tw.tsx: -------------------------------------------------------------------------------- 1 | import { type VoidComponent } from "solid-js"; 2 | import { A } from "@solidjs/router"; 3 | import { helloQuery } from "~/server/hello/hello.queries"; 4 | 5 | const Home: VoidComponent = () => { 6 | const hello = helloQuery(() => ({ hello: "from pRPC" })); 7 | return ( 8 | 9 | 10 | 11 | Create JD App 12 | 13 | 14 | 19 | Solid Start → 20 | 21 | Learn more about Solid Start and the basics. 22 | 23 | 24 | 29 | JD End → 30 | 31 | Learn more about Create JD App, the libraries it uses, and how to 32 | deploy it 33 | 34 | 35 | 36 | {hello.data} 37 | 38 | 39 | ); 40 | }; 41 | 42 | export default Home; 43 | -------------------------------------------------------------------------------- /src/helpers/env.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fs from "fs-extra"; 3 | import type { IEnv } from "~types"; 4 | 5 | export type IResolveEnvResp = { 6 | newServerScheme: string; 7 | newClientScheme: string; 8 | newEnv: string; 9 | }; 10 | 11 | export async function updateEnv(userDir: string, _env: IEnv[]) { 12 | const env = await resolveEnv(_env); 13 | const ENV_DIR = path.join(userDir, "src", "env"); 14 | const schema = path.join(ENV_DIR, "schema.ts"); 15 | await fs.writeFile( 16 | schema, 17 | `import { z } from "zod"; 18 | 19 | export const serverScheme = z.object({\n${env.newServerScheme} 20 | }); 21 | 22 | export const clientScheme = z.object({\n${env.newClientScheme} 23 | }); 24 | ` 25 | ); 26 | if (env.newEnv.trim().length) { 27 | await Promise.all([ 28 | fs.outputFile(path.join(userDir, ".env"), env.newEnv), 29 | fs.outputFile(path.join(userDir, ".env.example"), env.newEnv), 30 | ]); 31 | } 32 | } 33 | 34 | export const resolveEnv = (env: IEnv[]): Promise => { 35 | return new Promise((resolve) => { 36 | let newEnv = ""; 37 | let newClientScheme = ""; 38 | let newServerScheme = ""; 39 | 40 | let serverWasIn = false; 41 | let clientWasIn = false; 42 | for (const element of env) { 43 | const shouldAddNewLine = 44 | element.kind === "server" ? serverWasIn : clientWasIn; 45 | const value = `${shouldAddNewLine ? "\n" : ""} ${element.key}: z.${ 46 | element.type 47 | },`; 48 | if (element.kind === "server") { 49 | serverWasIn = true; 50 | newServerScheme += value; 51 | } else { 52 | clientWasIn = true; 53 | newClientScheme += value; 54 | } 55 | if (!element.ignore) { 56 | newEnv += `${element.key}=${element.defaulValue ?? ""}\n`; 57 | } 58 | } 59 | return resolve({ newEnv, newClientScheme, newServerScheme }); 60 | }); 61 | }; 62 | -------------------------------------------------------------------------------- /src/installers/Prisma/utils/getSchema.ts: -------------------------------------------------------------------------------- 1 | import type { IUtil } from "~types"; 2 | 3 | const getSchema: IUtil = (ctx) => { 4 | const useNextAuth = ctx.installers.includes("AuthJS"); 5 | return `generator client { 6 | provider = "prisma-client-js"${ 7 | ctx.vercel === "Cli" 8 | ? `\n binaryTargets = ["native", "rhel-openssl-1.0.x"]` 9 | : "" 10 | } 11 | } 12 | 13 | datasource db { 14 | provider = "sqlite" 15 | url = env("DATABASE_URL") 16 | } 17 | 18 | ${ 19 | useNextAuth 20 | ? `model Account { 21 | id String @id @default(cuid()) 22 | userId String 23 | type String 24 | provider String 25 | providerAccountId String 26 | refresh_token String? // @db.Text 27 | access_token String? // @db.Text 28 | expires_in Int? 29 | expires_at Int? 30 | token_type String? 31 | scope String? 32 | id_token String? // @db.Text 33 | session_state String? 34 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 35 | @@unique([provider, providerAccountId]) 36 | } 37 | 38 | model Session { 39 | id String @id @default(cuid()) 40 | sessionToken String @unique 41 | userId String 42 | expires DateTime 43 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 44 | } 45 | 46 | model User { 47 | id String @id @default(cuid()) 48 | name String? 49 | email String? @unique 50 | emailVerified DateTime? 51 | image String? 52 | accounts Account[] 53 | sessions Session[] 54 | } 55 | 56 | model VerificationToken { 57 | identifier String 58 | token String @unique 59 | expires DateTime 60 | @@unique([identifier, token]) 61 | }` 62 | : `model Notes { 63 | id String @id @default(cuid()) 64 | text String 65 | }` 66 | } 67 | `; 68 | }; 69 | 70 | export default getSchema; 71 | -------------------------------------------------------------------------------- /src/installers/AuthJS/index.ts: -------------------------------------------------------------------------------- 1 | import type { KeyOrKeyArray } from "~helpers/packages"; 2 | import { withPackages } from "~helpers/packages"; 3 | import type { IInstaller } from "~types"; 4 | 5 | const config: IInstaller = (ctx) => { 6 | const usePrisma = ctx.installers.includes("Prisma"); 7 | const normal: KeyOrKeyArray<"normal"> = [ 8 | "@auth/core", 9 | "@solid-mediakit/auth", 10 | ]; 11 | if (usePrisma) { 12 | normal.push("@auth/prisma-adapter"); 13 | } 14 | return { 15 | pkgs: withPackages({ 16 | normal, 17 | }), 18 | files: [ 19 | { 20 | path: `${__dirname}/files/${usePrisma ? "prisma-" : ""}config.txt`, 21 | to: `${ctx.userDir}/src/server/auth.ts`, 22 | }, 23 | { 24 | path: `${__dirname}/files/handler.txt`, 25 | to: `${ctx.userDir}/src/routes/api/auth/[...solidauth].ts`, 26 | }, 27 | { 28 | path: `${__dirname}/files/middleware.txt`, 29 | to: `${ctx.userDir}/src/middleware.ts`, 30 | }, 31 | !ctx.installers.includes("pRPC") 32 | ? { 33 | path: `${__dirname}/files/app.txt`, 34 | to: `${ctx.userDir}/src/app.tsx`, 35 | } 36 | : undefined, 37 | ], 38 | env: [ 39 | { 40 | key: "DISCORD_ID", 41 | type: "string()", 42 | kind: "server", 43 | }, 44 | { 45 | key: "DISCORD_SECRET", 46 | type: "string()", 47 | kind: "server", 48 | }, 49 | { 50 | key: "AUTH_SECRET", 51 | type: "string()", 52 | defaulValue: "b198e07a64406260b98f06e21c457b84", 53 | kind: "server", 54 | }, 55 | { 56 | key: "AUTH_TRUST_HOST", 57 | type: "string().optional()", 58 | kind: "server", 59 | defaulValue: "true", 60 | }, 61 | { 62 | key: "AUTH_URL", 63 | defaulValue: "http://localhost:3000", 64 | type: "string().optional()", 65 | kind: "server", 66 | }, 67 | { 68 | key: "VITE_AUTH_PATH", 69 | defaulValue: "/api/auth", 70 | type: "string().optional()", 71 | kind: "client", 72 | }, 73 | ], 74 | }; 75 | }; 76 | 77 | export default config; 78 | -------------------------------------------------------------------------------- /template/index/with-auth.tsx: -------------------------------------------------------------------------------- 1 | import styles from "./index.module.css"; 2 | import { A } from "@solidjs/router"; 3 | import { useAuth } from "@solid-mediakit/auth/client"; 4 | import { type VoidComponent, Match, Switch } from "solid-js"; 5 | 6 | const Home: VoidComponent = () => { 7 | return ( 8 | 9 | 10 | 11 | Create JD App 12 | 13 | 14 | 19 | Solid Start → 20 | 21 | Learn more about Solid Start and the basics. 22 | 23 | 24 | 29 | JD End → 30 | 31 | Learn more about Create JD App, the libraries it uses, and how to 32 | deploy it 33 | 34 | 35 | 36 | 37 | 38 | 39 | ); 40 | }; 41 | 42 | export default Home; 43 | 44 | const AuthShowcase: VoidComponent = () => { 45 | const auth = useAuth(); 46 | return ( 47 | 48 | Loading...}> 49 | 50 | 51 | Welcome {auth.session()?.user?.name} 52 | 53 | auth.signOut({ redirectTo: "/" })} 55 | class={styles.loginButton} 56 | > 57 | Sign out 58 | 59 | 60 | 61 | auth.signIn("discord", { redirectTo: "/" })} 63 | class={styles.loginButton} 64 | > 65 | Sign in 66 | 67 | 68 | 69 | 70 | ); 71 | }; 72 | -------------------------------------------------------------------------------- /src/utils/files.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs-extra"; 2 | import ora from "ora"; 3 | import type { ICtx, IFile } from "~types"; 4 | import { formatError } from "./helpers"; 5 | import prettier from "prettier"; 6 | 7 | export async function execFiles(files: (IFile | undefined)[], ctx: ICtx) { 8 | const actualFiles = files.filter((f) => f !== undefined) as IFile[]; 9 | // `sep` files are parent files, so they should be executed first ro resolve conflicts 10 | for (const file of actualFiles.filter((e) => e.sep)) { 11 | await execFile(file, ctx); 12 | } 13 | await Promise.all( 14 | actualFiles 15 | .filter((e) => !e.sep) 16 | .map(async (file) => { 17 | await execFile(file, ctx); 18 | }), 19 | ); 20 | } 21 | 22 | async function execFile(file: IFile, ctx: ICtx) { 23 | if (file.type && file.type !== "copy") { 24 | if (file.type === "exec") { 25 | if (!file.path) { 26 | return; 27 | } 28 | const method = await import(file.path); 29 | let code = await method.default(ctx, file.pass); 30 | if (!file.ignorePrettier) { 31 | code = await prettier.format(code, { 32 | parser: "typescript", 33 | }); 34 | } 35 | await fs.outputFile(file.to, code); 36 | } else if (file.type === "delete") { 37 | await fs.remove(file.to); 38 | } else if (file.type === "write") { 39 | let code = file.content!; 40 | if (!file.ignorePrettier) { 41 | code = await prettier.format(code, { 42 | parser: "typescript", 43 | }); 44 | } 45 | await fs.outputFile(file.to, code); 46 | } else if (file.type === "append") { 47 | await fs.appendFile(file.to, file.content); 48 | } 49 | } else { 50 | if (!file.path) { 51 | return; 52 | } 53 | await fs.copy(file.path, file.to); 54 | } 55 | } 56 | 57 | export async function existsOrCreate(path: string): Promise { 58 | try { 59 | await fs.access(path); 60 | return true; 61 | } catch { 62 | await fs.mkdir(path); 63 | } 64 | return false; 65 | } 66 | 67 | export async function overWriteFile(userDir: string) { 68 | const spinner = ora("Emptying directory").start(); 69 | try { 70 | await fs.emptyDir(userDir); 71 | spinner.succeed("Emptied directory"); 72 | } catch (e) { 73 | spinner.fail(`Couldn't empty directory: ${formatError(e)}`); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/utils/helpers.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs-extra"; 2 | import path from "path"; 3 | import { exec } from "child_process"; 4 | import { promisify } from "util"; 5 | import type { ICtx } from "~types"; 6 | import type { IExpectedPackages } from "~helpers/packages"; 7 | 8 | export const execa = promisify(exec); 9 | 10 | const DEFAULT_ERR = "Something Went Wrong"; 11 | 12 | const errCheck = (message?: string): string => 13 | message?.length ? message : DEFAULT_ERR; 14 | 15 | export const formatError = (err: unknown): string => { 16 | if (typeof err === "string") return errCheck(err); 17 | else if (typeof err === "object") { 18 | if (Array.isArray(err)) { 19 | if (err.length) { 20 | return formatError(err.shift()); 21 | } else return errCheck(); 22 | } else if (err && "message" in err) { 23 | return formatError(err.message); 24 | } else if (err && "stack" in err) { 25 | return formatError(err.stack); 26 | } 27 | } 28 | return errCheck(); 29 | }; 30 | 31 | export const validateName = (name: string) => { 32 | if (!name.length) return false; 33 | return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name) 34 | ? true 35 | : "This is not a valid name"; 36 | }; 37 | 38 | export async function modifyJSON( 39 | userDir: string, 40 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 41 | cb: (json: any) => Promise 42 | ) { 43 | const json = await fs.readJSON(path.join(userDir, "package.json")); 44 | const newJson = await cb({ ...json }); 45 | await fs.writeFile( 46 | path.join(userDir, "package.json"), 47 | JSON.stringify(newJson, null, 2) 48 | ); 49 | return newJson; 50 | } 51 | 52 | export const getUserPackageManager = () => { 53 | const userAgent = process.env.npm_config_user_agent; 54 | if (userAgent?.startsWith("yarn")) return "yarn"; 55 | if (userAgent?.startsWith("pnpm")) return "pnpm"; 56 | return "npm"; 57 | }; 58 | 59 | export const solidUpdateJSON = async ( 60 | ctx: ICtx, 61 | scripts: Record, 62 | pkgs: IExpectedPackages 63 | ) => { 64 | const [normalDeps, devModeDeps] = pkgs; 65 | await modifyJSON(ctx.userDir, (json) => { 66 | json.name = ctx.appName; 67 | json.scripts = { ...json.scripts, ...scripts }; 68 | json.dependencies = { ...json.dependencies, ...normalDeps }; 69 | json.devDependencies = { ...json.devDependencies, ...devModeDeps }; 70 | return json; 71 | }); 72 | }; 73 | -------------------------------------------------------------------------------- /src/helpers/config.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs-extra"; 2 | import path from "path"; 3 | import type { ICtx, IUtil } from "~types"; 4 | import prettier from "prettier"; 5 | 6 | export const getAppConfig: IUtil = async (ctx) => { 7 | const usePrisma = ctx.installers.includes("Prisma"); 8 | const usePRPC = ctx.installers.includes("pRPC"); 9 | const useAuth = ctx.installers.includes("AuthJS"); 10 | if (usePRPC) { 11 | return await prettier.format( 12 | `import { withPRPC } from "@solid-mediakit/prpc-plugin"; 13 | 14 | const config = withPRPC( 15 | { 16 | ssr: true,${useAuth ? "\n middleware: './src/middleware.ts'," : ""}${ 17 | usePrisma 18 | ? `\n vite: { 19 | ssr: { 20 | external: ["@prisma/client"], 21 | }, 22 | },` 23 | : "" 24 | }${ 25 | ctx.vercel 26 | ? `\n server: { 27 | preset: 'vercel', 28 | },` 29 | : "" 30 | } 31 | },${ 32 | useAuth 33 | ? `\n { 34 | auth: "authjs", 35 | authCfg: { 36 | configName: "authOptions", 37 | source: "~/server/auth", 38 | }, 39 | }` 40 | : "" 41 | } 42 | ); 43 | 44 | export default config; 45 | 46 | declare module "@solid-mediakit/prpc" { 47 | interface Settings { 48 | config: typeof config; 49 | } 50 | } 51 | `, 52 | { 53 | parser: "typescript", 54 | }, 55 | ); 56 | } 57 | return await prettier.format( 58 | `import { defineConfig } from "@solidjs/start/config";${ 59 | useAuth ? `\nimport { authVite } from "@solid-mediakit/auth-plugin";` : "" 60 | } 61 | 62 | export default defineConfig({ 63 | ssr: true,${ 64 | usePrisma 65 | ? `\n vite: { 66 | ${ 67 | usePrisma 68 | ? `ssr: { 69 | external: ["@prisma/client"], 70 | },` 71 | : "" 72 | } 73 | },` 74 | : "" 75 | }${ 76 | ctx.vercel 77 | ? `\n server: { 78 | preset: 'vercel', 79 | },` 80 | : "" 81 | } 82 | }); 83 | `, 84 | { 85 | parser: "typescript", 86 | }, 87 | ); 88 | }; 89 | 90 | export const modifyConfigIfNeeded = async (ctx: ICtx) => { 91 | if ( 92 | ctx.vercel || 93 | ctx.installers.includes("pRPC") || 94 | ctx.installers.includes("Prisma") 95 | ) { 96 | await fs.writeFile( 97 | path.join(ctx.userDir, "app.config.ts"), 98 | await getAppConfig(ctx), 99 | ); 100 | } 101 | }; 102 | -------------------------------------------------------------------------------- /template/index/with-auth-prpc.tsx: -------------------------------------------------------------------------------- 1 | import styles from "./index.module.css"; 2 | import { A } from "@solidjs/router"; 3 | import { useAuth } from "@solid-mediakit/auth/client"; 4 | import { type VoidComponent, Match, Switch } from "solid-js"; 5 | import { helloQuery } from "~/server/hello/hello.queries"; 6 | 7 | const Home: VoidComponent = () => { 8 | const hello = helloQuery(() => ({ hello: "from pRPC" })); 9 | return ( 10 | 11 | 12 | 13 | Create JD App 14 | 15 | 16 | 21 | Solid Start → 22 | 23 | Learn more about Solid Start and the basics. 24 | 25 | 26 | 31 | JD End → 32 | 33 | Learn more about Create JD App, the libraries it uses, and how to 34 | deploy it 35 | 36 | 37 | 38 | 39 | {hello.data} 40 | 41 | 42 | 43 | 44 | ); 45 | }; 46 | 47 | export default Home; 48 | 49 | const AuthShowcase: VoidComponent = () => { 50 | const auth = useAuth(); 51 | return ( 52 | 53 | Loading...}> 54 | 55 | 56 | Welcome {auth.session()?.user?.name} 57 | 58 | auth.signOut({ redirectTo: "/" })} 60 | class={styles.loginButton} 61 | > 62 | Sign out 63 | 64 | 65 | 66 | auth.signIn("discord", { redirectTo: "/" })} 68 | class={styles.loginButton} 69 | > 70 | Sign in 71 | 72 | 73 | 74 | 75 | ); 76 | }; 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-jd-app", 3 | "version": "5.1.0", 4 | "private": false, 5 | "scripts": { 6 | "build": "rm -rf dist && tsc -p . && tsc-alias -p tsconfig.json && pnpm postbuild", 7 | "postbuild": "ts-node -r tsconfig-paths/register scripts/copyFiles", 8 | "patch": "npm version patch --no-git-tag-version", 9 | "dev": "npm link && cd dist && npm link create-jd-app", 10 | "test:ts": "ts-node -r tsconfig-paths/register src", 11 | "test:js": "node dist/index.js", 12 | "lint": "eslint . --fix --ext .ts,.tsx,.js,.jsx", 13 | "prepare": "husky install" 14 | }, 15 | "files": [ 16 | "dist", 17 | "template" 18 | ], 19 | "main": "dist/index.js", 20 | "bin": { 21 | "create-jd-app": "dist/index.js" 22 | }, 23 | "dependencies": { 24 | "chalk": "^4.1.0", 25 | "fs-extra": "^10.1.0", 26 | "inquirer": "^8.2.4", 27 | "ora": "^5.4.0", 28 | "prettier": "^3.2.5" 29 | }, 30 | "devDependencies": { 31 | "@changesets/changelog-github": "^0.4.7", 32 | "@changesets/cli": "^2.25.2", 33 | "@types/fs-extra": "^9.0.13", 34 | "@types/inquirer": "^9.0.0", 35 | "@types/node": "^18.6.4", 36 | "@types/ora": "^3.2.0", 37 | "@typescript-eslint/eslint-plugin": "^5.44.0", 38 | "@typescript-eslint/parser": "^5.44.0", 39 | "eslint": "^8.28.0", 40 | "eslint-config-prettier": "^8.5.0", 41 | "eslint-config-standard-with-typescript": "^23.0.0", 42 | "eslint-plugin-import": "^2.26.0", 43 | "eslint-plugin-n": "^15.5.1", 44 | "eslint-plugin-promise": "^6.1.1", 45 | "husky": "^8.0.0", 46 | "lint-staged": "^13.0.4", 47 | "sort-package-json": "^2.1.0", 48 | "ts-node": "^10.9.1", 49 | "tsc-alias": "^1.7.0", 50 | "tsconfig-paths": "^4.1.0", 51 | "typescript": "^4.9.4" 52 | }, 53 | "lint-staged": { 54 | "*.{js,json}": "prettier --write", 55 | "packages/**/*.{js,jsx,ts,tsx}": [ 56 | "eslint --fix", 57 | "prettier --write" 58 | ], 59 | "examples/**/*.{js,jsx,ts,tsx}": [ 60 | "eslint --fix", 61 | "prettier --write" 62 | ], 63 | "package.json": "sort-package-json" 64 | }, 65 | "description": "Create modern type safed Solid web application within seconds", 66 | "repository": { 67 | "type": "git", 68 | "url": "git+https://github.com/OrJDev/create-jd-app.git" 69 | }, 70 | "keywords": [ 71 | "JDev", 72 | "pRPC", 73 | "TypeScript", 74 | "Tailwind", 75 | "Solid", 76 | "SolidStart" 77 | ], 78 | "author": "OrJDev", 79 | "bugs": { 80 | "url": "https://github.com/OrJDev/create-jd-app/issues" 81 | }, 82 | "homepage": "https://github.com/OrJDev/create-jd-app#readme", 83 | "packageManager": "pnpm@9.6.0" 84 | } 85 | -------------------------------------------------------------------------------- /template/index/with-auth-tw.tsx: -------------------------------------------------------------------------------- 1 | import { A } from "@solidjs/router"; 2 | import { useAuth } from "@solid-mediakit/auth/client"; 3 | import { type VoidComponent, Match, Switch } from "solid-js"; 4 | 5 | const Home: VoidComponent = () => { 6 | return ( 7 | 8 | 9 | 10 | Create JD App 11 | 12 | 13 | 18 | Solid Start → 19 | 20 | Learn more about Solid Start and the basics. 21 | 22 | 23 | 28 | JD End → 29 | 30 | Learn more about Create JD App, the libraries it uses, and how to 31 | deploy it. 32 | 33 | 34 | 35 | 36 | 37 | 38 | ); 39 | }; 40 | 41 | export default Home; 42 | 43 | const AuthShowcase: VoidComponent = () => { 44 | const auth = useAuth(); 45 | return ( 46 | 47 | Loading...}> 48 | 49 | 50 | 51 | Welcome {auth.session()?.user?.name} 52 | 53 | auth.signOut({ redirectTo: "/" })} 55 | class="rounded-full bg-white/10 px-10 py-3 font-semibold text-white no-underline transition hover:bg-white/20" 56 | > 57 | Sign out 58 | 59 | 60 | 61 | 62 | auth.signIn("discord", { redirectTo: "/" })} 64 | class="rounded-full bg-white/10 px-10 py-3 font-semibold text-white no-underline transition hover:bg-white/20" 65 | > 66 | Sign in 67 | 68 | 69 | 70 | 71 | ); 72 | }; 73 | -------------------------------------------------------------------------------- /template/base/src/routes/index.module.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | min-height: 100vh; 7 | background-image: linear-gradient(to bottom, #026d56, #152a2c); 8 | } 9 | 10 | a { 11 | text-decoration: none; 12 | } 13 | 14 | .container { 15 | width: 100%; 16 | display: flex; 17 | flex-direction: column; 18 | align-items: center; 19 | justify-content: center; 20 | gap: 3rem; 21 | padding: 4rem 1rem; 22 | } 23 | 24 | @media (min-width: 640px) { 25 | .container { 26 | max-width: 640px; 27 | } 28 | } 29 | 30 | @media (min-width: 768px) { 31 | .container { 32 | max-width: 768px; 33 | } 34 | } 35 | 36 | @media (min-width: 1024px) { 37 | .container { 38 | max-width: 1024px; 39 | } 40 | } 41 | 42 | @media (min-width: 1280px) { 43 | .container { 44 | max-width: 1280px; 45 | } 46 | } 47 | 48 | @media (min-width: 1536px) { 49 | .container { 50 | max-width: 1536px; 51 | } 52 | } 53 | 54 | .title { 55 | font-size: 3rem; 56 | line-height: 1; 57 | font-weight: 800; 58 | letter-spacing: -0.025em; 59 | margin: 0; 60 | color: white; 61 | } 62 | 63 | @media (min-width: 640px) { 64 | .title { 65 | font-size: 5rem; 66 | } 67 | } 68 | 69 | .greenSpan { 70 | color: hsl(88, 77%, 78%); 71 | } 72 | 73 | .cardRow { 74 | display: grid; 75 | grid-template-columns: repeat(1, minmax(0, 1fr)); 76 | gap: 1rem; 77 | } 78 | 79 | @media (min-width: 640px) { 80 | .cardRow { 81 | grid-template-columns: repeat(2, minmax(0, 1fr)); 82 | } 83 | } 84 | 85 | @media (min-width: 768px) { 86 | .cardRow { 87 | gap: 2rem; 88 | } 89 | } 90 | 91 | .card { 92 | max-width: 20rem; 93 | display: flex; 94 | flex-direction: column; 95 | gap: 1rem; 96 | padding: 1rem; 97 | border-radius: 0.75rem; 98 | color: white; 99 | background-color: rgb(255 255 255 / 0.1); 100 | } 101 | 102 | .card:hover { 103 | background-color: rgb(255 255 255 / 0.2); 104 | transition: background-color 150ms cubic-bezier(0.5, 0, 0.2, 1); 105 | } 106 | 107 | .cardTitle { 108 | font-size: 1.5rem; 109 | line-height: 2rem; 110 | font-weight: 700; 111 | margin: 0; 112 | } 113 | 114 | .cardText { 115 | font-size: 1.125rem; 116 | line-height: 1.75rem; 117 | } 118 | 119 | .showcaseContainer { 120 | display: flex; 121 | flex-direction: column; 122 | align-items: center; 123 | gap: 0.5rem; 124 | } 125 | 126 | .showcaseText { 127 | color: white; 128 | text-align: center; 129 | font-size: 1.5rem; 130 | line-height: 2rem; 131 | } 132 | 133 | .authContainer { 134 | display: flex; 135 | flex-direction: column; 136 | align-items: center; 137 | justify-content: center; 138 | gap: 1rem; 139 | } 140 | 141 | .loginButton { 142 | border-radius: 9999px; 143 | background-color: rgb(255 255 255 / 0.1); 144 | padding: 0.75rem 2.5rem; 145 | font-weight: 600; 146 | color: white; 147 | border: none; 148 | text-decoration-line: none; 149 | transition: background-color 150ms cubic-bezier(0.5, 0, 0.2, 1); 150 | } 151 | 152 | .loginButton:hover { 153 | background-color: rgb(255 255 255 / 0.2); 154 | } 155 | -------------------------------------------------------------------------------- /template/index/with-auth-prpc-tw.tsx: -------------------------------------------------------------------------------- 1 | import { A } from "@solidjs/router"; 2 | import { useAuth } from "@solid-mediakit/auth/client"; 3 | import { type VoidComponent, Match, Switch } from "solid-js"; 4 | import { helloQuery } from "~/server/hello/hello.queries"; 5 | 6 | const Home: VoidComponent = () => { 7 | const hello = helloQuery(() => ({ hello: "from pRPC" })); 8 | return ( 9 | 10 | 11 | 12 | Create JD App 13 | 14 | 15 | 20 | Solid Start → 21 | 22 | Learn more about Solid Start and the basics. 23 | 24 | 25 | 30 | JD End → 31 | 32 | Learn more about Create JD App, the libraries it uses, and how to 33 | deploy it 34 | 35 | 36 | 37 | 38 | {hello.data} 39 | 40 | 41 | 42 | 43 | ); 44 | }; 45 | 46 | export default Home; 47 | 48 | const AuthShowcase: VoidComponent = () => { 49 | const auth = useAuth(); 50 | return ( 51 | 52 | Loading...}> 53 | 54 | 55 | 56 | Welcome {auth.session()?.user?.name} 57 | 58 | auth.signOut({ redirectTo: "/" })} 60 | class="rounded-full bg-white/10 px-10 py-3 font-semibold text-white no-underline transition hover:bg-white/20" 61 | > 62 | Sign out 63 | 64 | 65 | 66 | 67 | auth.signIn("discord", { redirectTo: "/" })} 69 | class="rounded-full bg-white/10 px-10 py-3 font-semibold text-white no-underline transition hover:bg-white/20" 70 | > 71 | Sign in 72 | 73 | 74 | 75 | 76 | ); 77 | }; 78 | -------------------------------------------------------------------------------- /src/helpers/installer.ts: -------------------------------------------------------------------------------- 1 | import ora from "ora"; 2 | import path from "path"; 3 | import fs from "fs-extra"; 4 | import inquirer from "inquirer"; 5 | import type { IInstaller, ICtx, IEnv, IAppCtx, IConfig } from "~types"; 6 | import { execFiles } from "~utils/files"; 7 | import { formatError } from "~utils/helpers"; 8 | import chalk from "chalk"; 9 | import type { IExpectedPackages } from "./packages"; 10 | import type { TInstallers } from "~types"; 11 | 12 | export default async ( 13 | ctx: ICtx, 14 | ): Promise<[Record, IExpectedPackages, IEnv[], string[]]> => { 15 | let normalDeps: IExpectedPackages[0] = {}; 16 | let devModeDeps: IExpectedPackages[1] = {}; 17 | let scripts: Record = {}; 18 | let env: IEnv[] = [ 19 | { 20 | key: "NODE_ENV", 21 | type: "enum(['development', 'production', 'test']).default('development')", 22 | ignore: true, 23 | kind: "server", 24 | }, 25 | { 26 | key: "MODE", 27 | type: "enum(['development', 'production', 'test']).default('development')", 28 | ignore: true, 29 | kind: "client", 30 | }, 31 | ]; 32 | let commands: string[] = []; 33 | 34 | const execInstaller = async (cfg: IConfig) => { 35 | if (cfg.pkgs) { 36 | normalDeps = { ...normalDeps, ...cfg.pkgs[0] }; 37 | devModeDeps = { ...devModeDeps, ...cfg.pkgs[1] }; 38 | } 39 | if (cfg.scripts) { 40 | scripts = { ...scripts, ...cfg.scripts }; 41 | } 42 | if (cfg.files?.length) { 43 | await execFiles(cfg.files, ctx); 44 | } 45 | if (cfg.commands) { 46 | if (Array.isArray(cfg.commands)) { 47 | commands = [...cfg.commands, ...commands]; 48 | } else { 49 | commands.unshift(cfg.commands); 50 | } 51 | } 52 | if (cfg.env?.length) { 53 | env = [...env, ...cfg.env]; 54 | } 55 | }; 56 | const resp = await Promise.all( 57 | ctx.installers.map((pkg) => 58 | import(`../installers/${pkg}/index`).then( 59 | (installer: { default: IInstaller }) => 60 | typeof installer.default === "function" 61 | ? installer.default(ctx) 62 | : installer.default, 63 | ), 64 | ), 65 | ); 66 | 67 | console.log(); 68 | const spinner = ora("Initializing installers").start(); 69 | 70 | if (resp.length) { 71 | try { 72 | for (const installer of resp) { 73 | await execInstaller(installer); 74 | } 75 | spinner.succeed(`Initialized ${resp.length} installers`); 76 | } catch (e) { 77 | spinner.fail(`Couldn't initialize installers: ${formatError(e)}`); 78 | process.exit(1); 79 | } 80 | } else { 81 | spinner.succeed("No installers to initialize"); 82 | } 83 | return [scripts, [normalDeps, devModeDeps], env, commands]; 84 | }; 85 | 86 | export async function getCtxWithInstallers( 87 | ctx: IAppCtx, 88 | curr: string[], 89 | ): Promise { 90 | let installers: string[] = []; 91 | let pkgs: TInstallers[] = []; 92 | const skip = curr.includes("skip"); 93 | try { 94 | installers = await fs.readdir(path.join(__dirname, "../installers")); 95 | } catch { 96 | // do nothing 97 | } 98 | if (installers.length) { 99 | const validInstallers = curr.length 100 | ? installers.filter((i) => curr.some((c) => c === i.toLowerCase())) 101 | : []; 102 | if (validInstallers.length) { 103 | console.log( 104 | `${chalk.green("√")} Using installers: ${validInstallers 105 | .map((installer) => chalk.blue(installer)) 106 | .join(", ")}`, 107 | ); 108 | } 109 | if (!skip) { 110 | let optInstallers = installers.filter( 111 | (pkg) => !validInstallers.includes(pkg), 112 | ); 113 | const newPkgs = ( 114 | await inquirer.prompt<{ pkgs: TInstallers[] }>({ 115 | name: "pkgs", 116 | type: "checkbox", 117 | message: "What should we use for this app?", 118 | choices: optInstallers, 119 | validate: (ans: string[]) => { 120 | // for (const opt of opts) { 121 | // if (opt.every((o) => ans.includes(o))) { 122 | // return `You can't use both ${opt 123 | // .map((o) => chalk.blue(o)) 124 | // .join(" and ")} at the same time`; 125 | // } 126 | // } 127 | return true; 128 | }, 129 | }) 130 | ).pkgs; 131 | pkgs = [...validInstallers, ...newPkgs] as TInstallers[]; 132 | } else { 133 | pkgs = validInstallers as TInstallers[]; 134 | } 135 | } 136 | 137 | return { 138 | ...ctx, 139 | installers: pkgs, 140 | }; 141 | } 142 | -------------------------------------------------------------------------------- /src/utils/project.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fs from "fs-extra"; 3 | import ora from "ora"; 4 | import solidHelper from "~helpers/solid"; 5 | import inquirer from "inquirer"; 6 | import chalk from "chalk"; 7 | import { existsOrCreate, overWriteFile } from "./files"; 8 | import { 9 | execa, 10 | formatError, 11 | validateName, 12 | getUserPackageManager, 13 | solidUpdateJSON, 14 | } from "./helpers"; 15 | import type { IAppCtx, ICtx, IEnv, IVercelOpt } from "~types"; 16 | import { updateEnv } from "~helpers/env"; 17 | import { modifyConfigIfNeeded } from "~helpers/config"; 18 | import type { IExpectedPackages } from "~helpers/packages"; 19 | 20 | export async function initApp(args: string[]): Promise { 21 | console.log(); 22 | let pName = args 23 | .find((o) => o.startsWith("pname=")) 24 | ?.split("pname=") 25 | .pop(); 26 | if (pName && !validateName(pName)) { 27 | pName = undefined; 28 | } 29 | const appName = 30 | pName || 31 | ( 32 | await inquirer.prompt<{ appName: string }>({ 33 | name: "appName", 34 | type: "input", 35 | message: "What is the name of the app?", 36 | validate: validateName, 37 | default: "my-app", 38 | }) 39 | ).appName; 40 | const useCurrentDir = args.includes("current"); 41 | const userDir = path.resolve(process.cwd(), useCurrentDir ? "" : appName); 42 | const exists = await existsOrCreate(userDir); 43 | if (exists && !useCurrentDir) { 44 | if ( 45 | ( 46 | await inquirer.prompt<{ overWrite: boolean }>({ 47 | name: "overWrite", 48 | type: "confirm", 49 | message: `Do you want to overwrite this directory?`, 50 | }) 51 | ).overWrite 52 | ) { 53 | await overWriteFile(userDir); 54 | } else { 55 | console.log(chalk.red("Aborting...")); 56 | process.exit(1); 57 | } 58 | } 59 | const getTempVercel = (): IVercelOpt | undefined | null => { 60 | const temp = args 61 | .find((o) => o.startsWith("vercel=")) 62 | ?.split("vercel=") 63 | .pop() 64 | ?.toLowerCase(); 65 | const ve = temp 66 | ? temp === "Cli" || temp === "Dashboard" 67 | ? temp 68 | : temp === "none" 69 | ? null 70 | : "Cli" 71 | : undefined; 72 | if (ve) { 73 | console.log(`Using Vercel ${chalk.blue(ve)} for deployment`); 74 | } 75 | 76 | return ve; 77 | }; 78 | let vercel: IVercelOpt | undefined; 79 | if (args.includes("skip")) { 80 | const temp = getTempVercel(); 81 | vercel = temp ?? undefined; 82 | } else { 83 | const temp = getTempVercel(); 84 | if (temp !== undefined) { 85 | vercel = temp ?? undefined; 86 | } else { 87 | const temp = ( 88 | await inquirer.prompt<{ vercel: IVercelOpt | "None" }>({ 89 | name: "vercel", 90 | type: "list", 91 | choices: ["Cli", "Dashboard", "None"], 92 | message: "Will you deploy this project to vercel? If so, how", 93 | }) 94 | ).vercel; 95 | vercel = temp === "None" ? undefined : temp; 96 | } 97 | } 98 | const pkgManager = getUserPackageManager(); 99 | return { 100 | appName, 101 | userDir, 102 | vercel, 103 | pkgManager, 104 | templateDir: path.join(__dirname, "../../template"), 105 | }; 106 | } 107 | 108 | export async function copyTemplate(appContext: IAppCtx) { 109 | console.log(); 110 | const spinner = ora("Copying template files").start(); 111 | const templateDir = path.join(__dirname, "../..", "template"); 112 | try { 113 | await fs.copy( 114 | path.join(templateDir, "base"), 115 | path.join(appContext.userDir) 116 | ); 117 | await Promise.all([ 118 | fs.rename( 119 | path.join(appContext.userDir, "_gitignore"), 120 | path.join(appContext.userDir, ".gitignore") 121 | ), 122 | ]); 123 | spinner.succeed(`Copied template files to ${appContext.userDir}`); 124 | } catch (e) { 125 | spinner.fail(`Couldn't copy template files: ${formatError(e)}`); 126 | process.exit(1); 127 | } 128 | } 129 | export async function modifyProject( 130 | ctx: ICtx, 131 | pkgs: IExpectedPackages, 132 | scripts: Record, 133 | env: IEnv[] 134 | ) { 135 | const spinner = ora("Modifying project").start(); 136 | try { 137 | await Promise.all([ 138 | solidHelper(ctx, env), 139 | updateEnv(ctx.userDir, env), 140 | solidUpdateJSON(ctx, scripts, pkgs), 141 | modifyConfigIfNeeded(ctx), 142 | ]); 143 | spinner.succeed("Modified project"); 144 | } catch (e) { 145 | spinner.fail(`Couldn't modify project: ${formatError(e)}`); 146 | process.exit(1); 147 | } 148 | } 149 | 150 | export async function installDeps(ctx: ICtx) { 151 | console.log( 152 | `\n${chalk.blue("Using")} ${chalk.bold( 153 | chalk.yellow(ctx.pkgManager.toUpperCase()) 154 | )} ${chalk.bold(chalk.blue("as package manager"))}` 155 | ); 156 | const spinner = ora("Installing dependencies").start(); 157 | try { 158 | const flags = ctx.pkgManager === "npm" ? " --legacy-peer-deps" : ""; 159 | await execa(`${ctx.pkgManager} install${flags}`, { cwd: ctx.userDir }); 160 | spinner.succeed("Installed dependencies"); 161 | } catch (e) { 162 | console.error(e); 163 | spinner.fail(`Cann't install dependencies: ${formatError(e)}`); 164 | process.exit(1); 165 | } 166 | } 167 | 168 | export async function runCommands(ctx: IAppCtx, commands: string[]) { 169 | const spinner = ora("Running queued commands").start(); 170 | try { 171 | for (const cmd of commands) { 172 | await execa(cmd, { 173 | cwd: ctx.userDir, 174 | }); 175 | } 176 | spinner.succeed("Ran queued commands"); 177 | } catch (e) { 178 | spinner.fail(`Couldn't run queued commands: ${formatError(e)}`); 179 | process.exit(1); 180 | } 181 | } 182 | 183 | export function finished(ctx: ICtx) { 184 | console.log(`\n\t${chalk.green(`cd ${ctx.appName}`)}`); 185 | const withRun = ctx.pkgManager === "pnpm" ? "" : " run"; 186 | ctx.installers.includes("Prisma") && 187 | console.log( 188 | `${chalk.yellow(`\t${ctx.pkgManager}${withRun} push`)}\t${chalk.gray( 189 | "// pushes db to Prisma" 190 | )}` 191 | ); 192 | console.log(chalk.bold(chalk.blue(`\t${ctx.pkgManager}${withRun} dev`))); 193 | console.log(); 194 | process.exit(0); 195 | } 196 | 197 | // 198 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # create-jd-app 2 | 3 | ## 5.1.0 4 | 5 | ### Minor Changes 6 | 7 | - [`3b05d5e`](https://github.com/OrJDev/create-jd-app/commit/3b05d5eae14c34041c0db290b56902d8b44dd1b2) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: bump everything to its latest version 8 | 9 | ## 5.0.1 10 | 11 | ### Patch Changes 12 | 13 | - [`99a2ebe`](https://github.com/OrJDev/create-jd-app/commit/99a2ebe036cca1297b69d22e2672eeaf65d796bf) Thanks [@OrJDev](https://github.com/OrJDev)! - deps: bump everything 14 | 15 | ## 5.0.0 16 | 17 | ### Major Changes 18 | 19 | - testing 20 | 21 | ### Minor Changes 22 | 23 | - [`280b89e`](https://github.com/OrJDev/create-jd-app/commit/280b89e575d7a9f14de870ece9b86f6c711fda3f) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: use new prpc 24 | 25 | - [`e722670`](https://github.com/OrJDev/create-jd-app/commit/e72267073f36d025fc402fce05d9e2b903a9f650) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: remove prpc & add pRPC + bump 26 | 27 | ## 4.2.0 28 | 29 | ### Minor Changes 30 | 31 | - [`e722670`](https://github.com/OrJDev/create-jd-app/commit/e72267073f36d025fc402fce05d9e2b903a9f650) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: remove prpc & add AuthPC + bump 32 | 33 | ## 4.1.2 34 | 35 | ### Patch Changes 36 | 37 | - [`9858a28`](https://github.com/OrJDev/create-jd-app/commit/9858a28e592fea1be99086765f9adc0efbc5bd08) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: latest 38 | 39 | ## 4.1.1 40 | 41 | ### Patch Changes 42 | 43 | - [`a6e45df`](https://github.com/OrJDev/create-jd-app/commit/a6e45dfea179dd0ede038cafd4e2e45443cd3090) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: use latest's auth api 44 | 45 | ## 4.1.0 46 | 47 | ### Minor Changes 48 | 49 | - [`0681403`](https://github.com/OrJDev/create-jd-app/commit/0681403a2c4ea6b7804dabad86c40a86a3af70db) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: get everything up to date 50 | 51 | ## 4.0.0 52 | 53 | ### Major Changes 54 | 55 | - [`3560fa0`](https://github.com/OrJDev/create-jd-app/commit/3560fa0a7dab4d9d4d9b12add4876d5992c97ad9) Thanks [@OrJDev](https://github.com/OrJDev)! - update all deps 56 | 57 | ### Minor Changes 58 | 59 | - [`5fae24d`](https://github.com/OrJDev/create-jd-app/commit/5fae24dcd3696646615905e6a5192ea2f1ca9137) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: revert tailwind to its latest version 60 | 61 | ### Patch Changes 62 | 63 | - [`8eb3a71`](https://github.com/OrJDev/create-jd-app/commit/8eb3a713e362eb9ddc9330ca111525e8aaf81358) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: fix the auth env variables 64 | 65 | - [`f3cc8c7`](https://github.com/OrJDev/create-jd-app/commit/f3cc8c7252326faf3ae36aea3ceba95992668ea4) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: bump prpc 66 | 67 | ## 3.3.0 68 | 69 | ### Minor Changes 70 | 71 | - [`8152ce9`](https://github.com/OrJDev/create-jd-app/commit/8152ce9c2ec85bca18bafc538814b79e80ec5d0f) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: add prettier to the deps 72 | 73 | ## 3.2.0 74 | 75 | ### Minor Changes 76 | 77 | - [`6748179`](https://github.com/OrJDev/create-jd-app/commit/67481798126f514b999bd014ac69aaebae95c003) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: move to tailwind v4 78 | 79 | - [`e4f62f6`](https://github.com/OrJDev/create-jd-app/commit/e4f62f618a275a9e8fe818e9e2b2f3b8840ba972) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: add prettier and use protected$ api 80 | 81 | ### Patch Changes 82 | 83 | - [`4390dc9`](https://github.com/OrJDev/create-jd-app/commit/4390dc95711fcfadc7b61238f742a08fe22d73fc) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: prettify all files 84 | 85 | ## 3.1.0 86 | 87 | ### Minor Changes 88 | 89 | - [`0635596`](https://github.com/OrJDev/create-jd-app/commit/06355962f98a5c641acbf12163c16386ecbdc2a6) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: use correct version of prisma 90 | 91 | ### Patch Changes 92 | 93 | - [`378b327`](https://github.com/OrJDev/create-jd-app/commit/378b3270642a2b3c9881215822a524afa05ec209) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: use correct eslint version 94 | 95 | ## 3.0.0 96 | 97 | ### Major Changes 98 | 99 | - [`40ec503`](https://github.com/OrJDev/create-jd-app/commit/40ec5035344c9be7378dec24ac24cdffb1277fd4) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: add pRPC & remove tRPC 100 | 101 | ### Minor Changes 102 | 103 | - [`9616cef`](https://github.com/OrJDev/create-jd-app/commit/9616cef9604ee22aec481408a4f7701c9fb9e63e) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: use the builder$ api from prpc 104 | 105 | ### Patch Changes 106 | 107 | - [`eaad67f`](https://github.com/OrJDev/create-jd-app/commit/eaad67fe2abf4185537269fa0a23e7048e1a84dd) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: bump everything to its lateset version 108 | 109 | ## 2.3.0 110 | 111 | ### Minor Changes 112 | 113 | - [`774df7d`](https://github.com/OrJDev/create-jd-app/commit/774df7d44d9ac885d0c527e44e6e5fb41f873f7d) Thanks [@OrJDev](https://github.com/OrJDev)! - fix/feat: use latest auth/core and remove upstash 114 | 115 | ## 2.2.4 116 | 117 | ### Patch Changes 118 | 119 | - [`e52da36`](https://github.com/OrJDev/create-jd-app/commit/e52da36b0e18eeb2c7229a4e29b731becb9d467d) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: update auth deps 120 | 121 | - [`c890f64`](https://github.com/OrJDev/create-jd-app/commit/c890f64cb28a76a32d6eaec27e8d966e6f81c076) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: use latest versions to fix ssr bugs 122 | 123 | ## 2.2.3 124 | 125 | ### Patch Changes 126 | 127 | - [`937d8ae`](https://github.com/OrJDev/create-jd-app/commit/937d8aea438743fdbda584cca71331eed11a1a12) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: use vite.ssr.external for prisma 128 | 129 | ## 2.2.2 130 | 131 | ### Patch Changes 132 | 133 | - [`ecb8ff9`](https://github.com/OrJDev/create-jd-app/commit/ecb8ff96f4bb1f28773aa929af7c5d46ba67707f) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: use the correct import for FileRoutes 134 | 135 | - [`a11abd0`](https://github.com/OrJDev/create-jd-app/commit/a11abd02f9303967688519260240d0d29fdcc077) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: prettify app.config 136 | 137 | - [`97c9329`](https://github.com/OrJDev/create-jd-app/commit/97c93290ecf8c3fc25cc87b2247229c816ae7e57) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: re-create queryClient on app.tsx 138 | 139 | - [`6e64869`](https://github.com/OrJDev/create-jd-app/commit/6e648691588f42a0c6337d0dd8af0d3fd239bd76) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: bump base template and packages to latest versions 140 | 141 | - [`aee3a7a`](https://github.com/OrJDev/create-jd-app/commit/aee3a7a7f2d2cd54da6982d10616d8bb5092cff2) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: move from vite to app config 142 | 143 | ## 2.2.1 144 | 145 | ### Patch Changes 146 | 147 | - [`e0a2ce7`](https://github.com/OrJDev/create-jd-app/commit/e0a2ce7a5a997e5fd9fdbf45dfdb10de14f9a266) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: use the correct import for the auth api handler 148 | 149 | ## 2.2.0 150 | 151 | ### Minor Changes 152 | 153 | - [`fc23fb5`](https://github.com/OrJDev/create-jd-app/commit/fc23fb516ac6d465f9ab262d270208e49ddd68b0) Thanks [@OrJDev](https://github.com/OrJDev)! - bump: use trpc.createQuery instead of .useQuery 154 | 155 | ## 2.1.2 156 | 157 | ### Patch Changes 158 | 159 | - [`849a487`](https://github.com/OrJDev/create-jd-app/commit/849a48713d6c34f33d9774b85198bd2be9e24339) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: trpc api endpoint 160 | 161 | ## 2.1.1 162 | 163 | ### Patch Changes 164 | 165 | - [`3aa091a`](https://github.com/OrJDev/create-jd-app/commit/3aa091af814d5d8c70fa55f81a9d2ad059704a34) Thanks [@OrJDev](https://github.com/OrJDev)! - fix trpc package version 166 | 167 | ## 2.1.0 168 | 169 | ### Minor Changes 170 | 171 | - [`94c1b94`](https://github.com/OrJDev/create-jd-app/commit/94c1b94de1e2f1dd576a161a29653819dcb0dc79) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: wrong usage of dirs 172 | 173 | ## 2.0.0 174 | 175 | ### Major Changes 176 | 177 | - [`218649d`](https://github.com/OrJDev/create-jd-app/commit/218649d2fb760a5ca4455498068d10e755f17c73) Thanks [@OrJDev](https://github.com/OrJDev)! - finally: use solid start 2.0 178 | 179 | ## 1.5.2 180 | 181 | ### Patch Changes 182 | 183 | - [`9a966d2`](https://github.com/OrJDev/create-jd-app/commit/9a966d244f1889d64efe40bdb62b7b4d07c84ebe) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: don't use latest solid start version 184 | 185 | ## 1.5.1 186 | 187 | ### Patch Changes 188 | 189 | - [`f8b97de`](https://github.com/OrJDev/create-jd-app/commit/f8b97de260d37e9ea7d02c7a544b3ff24c28d796) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: correct readme links to repo 190 | 191 | - [`9b01d49`](https://github.com/OrJDev/create-jd-app/commit/9b01d49fd6f9cc1bbd7c9f25805ed87da95c0edd) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: get solid up to date 192 | 193 | ## 1.0.0 194 | 195 | ### Major Changes 196 | 197 | - [`d95e613`](https://github.com/OrJDev/create-jd-app/commit/d95e6136984c1c5f7b92f44590c221942bbf1a27) Thanks [@OrJDev](https://github.com/OrJDev)! - get everything to the latest versions of Solid (Query, Start, Etc) 198 | 199 | ## 0.2.9 200 | 201 | ### Patch Changes 202 | 203 | - [`3d2517d`](https://github.com/OrJDev/create-jd-app/commit/3d2517d7fc6277325c2006aea2fd6d31725ce35e) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: bump everything to latest 204 | 205 | - [`727642a`](https://github.com/OrJDev/create-jd-app/commit/727642a59a3ac974f67668dda151db4c8e32adc1) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: use the correct prisma adapter for authjs 206 | 207 | - [`8706b54`](https://github.com/OrJDev/create-jd-app/commit/8706b546c422e29a929f81f80a4eef9f01245308) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: update solid query & trpc to its beta version 208 | 209 | - [`0a81a7b`](https://github.com/OrJDev/create-jd-app/commit/0a81a7bbe0d20e5db476ba90277ececb75e00bd6) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: use a better version of solid-auth 210 | 211 | ## 0.2.8 212 | 213 | ### Patch Changes 214 | 215 | - [`e6cb8a0`](https://github.com/OrJDev/create-jd-app/commit/e6cb8a0d213123a7e9e4e1a8b52188f843b45a49) Thanks [@OrJDev](https://github.com/OrJDev)! - bump: @prpc/solid to latest 216 | 217 | - [`92b6ec6`](https://github.com/OrJDev/create-jd-app/commit/92b6ec6ba94678895fb7b213f47c7941ace75455) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: lock solid query 218 | 219 | ## 0.2.7 220 | 221 | ### Patch Changes 222 | 223 | - [`1280672`](https://github.com/OrJDev/create-jd-app/commit/1280672d482e6033f2c26ef84ecaec193cde8af6) Thanks [@OrJDev](https://github.com/OrJDev)! - prpc: use reuseable$ for auth and limiting 224 | 225 | - [`9dca4b6`](https://github.com/OrJDev/create-jd-app/commit/9dca4b6d66e0845a4c92a149e0d374459866d49c) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: authjs hydration & prpc reuseable$ 226 | 227 | - [#92](https://github.com/OrJDev/create-jd-app/pull/92) [`2fd363d`](https://github.com/OrJDev/create-jd-app/commit/2fd363d04e4bd16cb141cdc78129a5c5cb11f75e) Thanks [@jesseb34r](https://github.com/jesseb34r)! - fix: use correct tailwind hsl syntax for arbitrary colors 228 | 229 | - [#92](https://github.com/OrJDev/create-jd-app/pull/92) [`e04fc70`](https://github.com/OrJDev/create-jd-app/commit/e04fc70bd3eccd80e3efcc1aaff1ac40113d6027) Thanks [@jesseb34r](https://github.com/jesseb34r)! - feat: add recommended vscode editor settings to tailwindcss template 230 | 231 | ## 0.2.6 232 | 233 | ### Patch Changes 234 | 235 | - [`51f3377`](https://github.com/OrJDev/create-jd-app/commit/51f3377cf93c1e065bab14ab35905d542b024bca) Thanks [@OrJDev](https://github.com/OrJDev)! - change: signIn to discord 236 | 237 | ## 0.2.5 238 | 239 | ### Patch Changes 240 | 241 | - [`06739a9`](https://github.com/OrJDev/create-jd-app/commit/06739a976593a014f0c0262cba6665208241c08f) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: use prpc query to fetch logged in user 242 | 243 | ## 0.2.4 244 | 245 | ### Patch Changes 246 | 247 | - [`d832a4a`](https://github.com/OrJDev/create-jd-app/commit/d832a4a64bc265a9ddbe3d97d0bff6944befe584) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: prpc import build alias 248 | 249 | ## 0.2.3 250 | 251 | ### Patch Changes 252 | 253 | - [`15a9ca5`](https://github.com/OrJDev/create-jd-app/commit/15a9ca5b3931049904ade4ca069484dbae3f4d53) Thanks [@OrJDev](https://github.com/OrJDev)! - clean the path of prisma 254 | 255 | - [`70853d1`](https://github.com/OrJDev/create-jd-app/commit/70853d10cde4ab1de472bb5815fe79077b837087) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: import alias for prpc 256 | 257 | ## 0.2.2 258 | 259 | ### Patch Changes 260 | 261 | - [`6aed32c`](https://github.com/OrJDev/create-jd-app/commit/6aed32cb28a790d6b7902133957012aef64df771) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: new folder structure 262 | 263 | - [`c6a5c7e`](https://github.com/OrJDev/create-jd-app/commit/c6a5c7e0a5739681a76a7637e8fc69870be6245c) Thanks [@OrJDev](https://github.com/OrJDev)! - bump packages + prpc object syntax 264 | 265 | ## 0.2.1 266 | 267 | ### Patch Changes 268 | 269 | - [`4bedfa7`](https://github.com/OrJDev/create-jd-app/commit/4bedfa75d9f557ce246cdbb2598b4478bad8aac4) Thanks [@OrJDev](https://github.com/OrJDev)! - bump prpc/vite 270 | 271 | - [`620d065`](https://github.com/OrJDev/create-jd-app/commit/620d0655a605e2d584050fdcae924c679b2d8d08) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: bump @prpc/solid 272 | 273 | ## 0.2.0 274 | 275 | ### Minor Changes 276 | 277 | - [`730f3f5`](https://github.com/OrJDev/create-jd-app/commit/730f3f57d497084e14f791205130575461719815) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: move to the new solid-auth 278 | 279 | ### Patch Changes 280 | 281 | - [`628a058`](https://github.com/OrJDev/create-jd-app/commit/628a058565ac08fe8f539a37fbab95ee409138ef) Thanks [@OrJDev](https://github.com/OrJDev)! - Organize the pRPC middlewares better 282 | 283 | - [`e19923f`](https://github.com/OrJDev/create-jd-app/commit/e19923f49d8d877a2816ea3fc82cccb64ae72290) Thanks [@OrJDev](https://github.com/OrJDev)! - move prisma to server/db instead of server/db/client 284 | 285 | - [`6476be8`](https://github.com/OrJDev/create-jd-app/commit/6476be884f9ea20e9e0ec6858024c4156c049fcb) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: pRPC protected query example 286 | 287 | ## 0.1.33 288 | 289 | ### Patch Changes 290 | 291 | - [`fb74ef1`](https://github.com/OrJDev/create-jd-app/commit/fb74ef1d13f4ff17e91a9347db7ba4d27affdeb3) Thanks [@OrJDev](https://github.com/OrJDev)! - bump: solidjs/router 292 | 293 | ## 0.1.32 294 | 295 | ### Patch Changes 296 | 297 | - [`810d5cc`](https://github.com/OrJDev/create-jd-app/commit/810d5cc186a968732a6a1da1ceae62c3bb16005d) Thanks [@OrJDev](https://github.com/OrJDev)! - bump pRPC packages 298 | 299 | ## 0.1.31 300 | 301 | ### Patch Changes 302 | 303 | - [`e41b776`](https://github.com/OrJDev/create-jd-app/commit/e41b77626715b1a0793687eba1c5f1df19ba527b) Thanks [@OrJDev](https://github.com/OrJDev)! - move(prpc): use tanstack solid query alpha 304 | 305 | - [#63](https://github.com/OrJDev/create-jd-app/pull/63) [`b329f02`](https://github.com/OrJDev/create-jd-app/commit/b329f02dd9c5f6bfe9347c135d8ff2eab631e9e3) Thanks [@va3y](https://github.com/va3y)! - reworked non-tRPC rate lmiter as Solid Start middleware 306 | added rate limiter support for pRPC 307 | 308 | ## 0.1.30 309 | 310 | ### Patch Changes 311 | 312 | - [#77](https://github.com/OrJDev/create-jd-app/pull/77) [`9079a90`](https://github.com/OrJDev/create-jd-app/commit/9079a90cc5b74b80057d9eb775130cc5da0dbbf7) Thanks [@lnxcz](https://github.com/lnxcz)! - prevent UnoCSS imports being overwritten by TRPC/PRPC addon 313 | 314 | ## 0.1.29 315 | 316 | ### Patch Changes 317 | 318 | - [`86efe20`](https://github.com/OrJDev/create-jd-app/commit/86efe20aa47eb13b7f0896ea8b2d9892ecebb903) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: pRPC directly import the vite plugin from @prpc/vite 319 | 320 | ## 0.1.28 321 | 322 | ### Patch Changes 323 | 324 | - [`51d0ae0`](https://github.com/OrJDev/create-jd-app/commit/51d0ae08fbbe0bc5294932512c590cab6bc94bc6) Thanks [@OrJDev](https://github.com/OrJDev)! - fix: trpc api location 325 | 326 | ## 0.1.27 327 | 328 | ### Patch Changes 329 | 330 | - [`0d70686`](https://github.com/OrJDev/create-jd-app/commit/0d70686bcc0229fcb5ca55ad11de024524a70cfa) Thanks [@OrJDev](https://github.com/OrJDev)! - Fix: prpc vite / packages 331 | 332 | ## 0.1.26 333 | 334 | ### Patch Changes 335 | 336 | - [`83d5d20`](https://github.com/OrJDev/create-jd-app/commit/83d5d206d2871a8da201373084ca255cf3f747d9) Thanks [@OrJDev](https://github.com/OrJDev)! - Feat: tRPC installer 337 | 338 | ## 0.1.25 339 | 340 | ### Patch Changes 341 | 342 | - [`f6bb655`](https://github.com/OrJDev/create-jd-app/commit/f6bb655a5a9f9736fc1e3f98c183c1c049ee6b78) Thanks [@OrJDev](https://github.com/OrJDev)! - feat: pRPC installer 343 | 344 | ## 0.1.24 345 | 346 | ### Patch Changes 347 | 348 | - [`e351894`](https://github.com/OrJDev/create-jd-app/commit/e351894c02fa0f03ade089ef1b4b59e13d62fc61) Thanks [@OrJDev](https://github.com/OrJDev)! - trpc: move to @tanstack/solid-query@alpha 349 | --------------------------------------------------------------------------------
{hello.data}