create-pilotprojects-app 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/helpers/copy.js +32 -0
- package/dist/helpers/install.js +18 -0
- package/dist/helpers/package-json.js +25 -0
- package/dist/index.js +54 -0
- package/dist/prompts.js +75 -0
- package/dist/scaffold.js +84 -0
- package/dist/types.js +1 -0
- package/package.json +39 -0
- package/templates/apps/mobile/.env.example +15 -0
- package/templates/apps/mobile/app/(auth)/login.tsx +86 -0
- package/templates/apps/mobile/app/(tabs)/_layout.tsx +10 -0
- package/templates/apps/mobile/app/(tabs)/index.tsx +30 -0
- package/templates/apps/mobile/app/_layout.tsx +58 -0
- package/templates/apps/mobile/app.config.ts +73 -0
- package/templates/apps/mobile/babel.config.js +9 -0
- package/templates/apps/mobile/eas.json +48 -0
- package/templates/apps/mobile/global.css +44 -0
- package/templates/apps/mobile/lib/supabase.ts +15 -0
- package/templates/apps/mobile/lib/trpc/client.ts +30 -0
- package/templates/apps/mobile/package.json +48 -0
- package/templates/apps/mobile/tsconfig.json +16 -0
- package/templates/apps/web/.env.development.example +22 -0
- package/templates/apps/web/app/(auth)/login/page.tsx +102 -0
- package/templates/apps/web/app/(dashboard)/dashboard/page.tsx +21 -0
- package/templates/apps/web/app/(dashboard)/layout.tsx +14 -0
- package/templates/apps/web/app/api/trpc/[trpc]/route.ts +32 -0
- package/templates/apps/web/app/globals.css +51 -0
- package/templates/apps/web/app/layout.tsx +25 -0
- package/templates/apps/web/lib/trpc/client.tsx +7 -0
- package/templates/apps/web/lib/trpc/provider.tsx +37 -0
- package/templates/apps/web/lib/trpc/server.ts +20 -0
- package/templates/apps/web/middleware.ts +10 -0
- package/templates/apps/web/package.json +44 -0
- package/templates/apps/web/postcss.config.js +6 -0
- package/templates/apps/web/sentry.client.config.ts +10 -0
- package/templates/apps/web/sentry.edge.config.ts +6 -0
- package/templates/apps/web/sentry.server.config.ts +7 -0
- package/templates/apps/web/tailwind.config.ts +12 -0
- package/templates/apps/web/tsconfig.json +16 -0
- package/templates/apps/web/types/css.d.ts +1 -0
- package/templates/base/.prettierrc.js +9 -0
- package/templates/base/_gitignore +30 -0
- package/templates/base/package.json +30 -0
- package/templates/base/turbo.json +33 -0
- package/templates/packages/api/package.json +23 -0
- package/templates/packages/api/src/features/auth/auth.router.ts +8 -0
- package/templates/packages/api/src/features/auth/auth.schema.ts +9 -0
- package/templates/packages/api/src/features/auth/auth.service.ts +24 -0
- package/templates/packages/api/src/features/user/user.router.ts +21 -0
- package/templates/packages/api/src/features/user/user.schema.ts +13 -0
- package/templates/packages/api/src/features/user/user.service.ts +41 -0
- package/templates/packages/api/src/index.ts +9 -0
- package/templates/packages/api/src/root.ts +10 -0
- package/templates/packages/api/src/trpc.ts +42 -0
- package/templates/packages/api/tsconfig.json +4 -0
- package/templates/packages/auth/package.json +26 -0
- package/templates/packages/auth/src/client.ts +8 -0
- package/templates/packages/auth/src/index.ts +3 -0
- package/templates/packages/auth/src/middleware.ts +25 -0
- package/templates/packages/auth/src/server.ts +15 -0
- package/templates/packages/auth/tsconfig.json +4 -0
- package/templates/packages/config/eslint/base.js +28 -0
- package/templates/packages/config/eslint/nextjs.js +10 -0
- package/templates/packages/config/eslint/react-native.js +18 -0
- package/templates/packages/config/package.json +13 -0
- package/templates/packages/config/typescript/base.json +17 -0
- package/templates/packages/config/typescript/nextjs.json +18 -0
- package/templates/packages/config/typescript/react-native.json +11 -0
- package/templates/packages/db/.env.example +1 -0
- package/templates/packages/db/drizzle.config.ts +13 -0
- package/templates/packages/db/package.json +28 -0
- package/templates/packages/db/src/index.ts +14 -0
- package/templates/packages/db/src/schema/index.ts +1 -0
- package/templates/packages/db/src/schema/users.ts +13 -0
- package/templates/packages/db/tsconfig.json +4 -0
- package/templates/packages/email/package.json +23 -0
- package/templates/packages/email/src/index.ts +2 -0
- package/templates/packages/email/src/resend.ts +8 -0
- package/templates/packages/email/src/templates/welcome.tsx +54 -0
- package/templates/packages/email/tsconfig.json +8 -0
- package/templates/packages/ui/package.json +38 -0
- package/templates/packages/ui/src/lib/utils.ts +6 -0
- package/templates/packages/ui/src/native/button.tsx +58 -0
- package/templates/packages/ui/src/native/card.tsx +41 -0
- package/templates/packages/ui/src/native/input.tsx +24 -0
- package/templates/packages/ui/src/native.d.ts +24 -0
- package/templates/packages/ui/src/tailwind-preset.ts +50 -0
- package/templates/packages/ui/src/web/button.tsx +49 -0
- package/templates/packages/ui/src/web/card.tsx +51 -0
- package/templates/packages/ui/src/web/input.tsx +22 -0
- package/templates/packages/ui/tsconfig.json +8 -0
- package/templates/packages/validators/package.json +20 -0
- package/templates/packages/validators/src/auth.ts +15 -0
- package/templates/packages/validators/src/index.ts +2 -0
- package/templates/packages/validators/src/user.ts +8 -0
- package/templates/packages/validators/tsconfig.json +4 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"scripts": {
|
|
5
|
+
"build": "turbo build",
|
|
6
|
+
"dev": "turbo dev",
|
|
7
|
+
"lint": "turbo lint",
|
|
8
|
+
"type-check": "turbo type-check",
|
|
9
|
+
"test": "turbo test",
|
|
10
|
+
"format": "prettier --write \"**/*.{ts,tsx,md}\""
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"prettier": "^3.3.0",
|
|
14
|
+
"turbo": "^2.0.0",
|
|
15
|
+
"typescript": "^5.5.0"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=20.0.0",
|
|
19
|
+
"pnpm": ">=9.0.0"
|
|
20
|
+
},
|
|
21
|
+
"packageManager": "pnpm@9.0.0",
|
|
22
|
+
"pnpm": {
|
|
23
|
+
"overrides": {
|
|
24
|
+
"nativewind": "~4.1.0",
|
|
25
|
+
"react-native-css-interop": "~0.1.0",
|
|
26
|
+
"react-native-screens": "~4.4.0",
|
|
27
|
+
"react-native-reanimated": "~3.16.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://turbo.build/schema.json",
|
|
3
|
+
"globalEnv": [
|
|
4
|
+
"NODE_ENV",
|
|
5
|
+
"SUPABASE_URL",
|
|
6
|
+
"SUPABASE_ANON_KEY",
|
|
7
|
+
"NEXT_PUBLIC_SUPABASE_URL",
|
|
8
|
+
"NEXT_PUBLIC_SUPABASE_ANON_KEY"
|
|
9
|
+
],
|
|
10
|
+
"tasks": {
|
|
11
|
+
"build": {
|
|
12
|
+
"dependsOn": ["^build"],
|
|
13
|
+
"outputs": [".next/**", "dist/**", "!.next/cache/**"]
|
|
14
|
+
},
|
|
15
|
+
"dev": {
|
|
16
|
+
"cache": false,
|
|
17
|
+
"persistent": true
|
|
18
|
+
},
|
|
19
|
+
"lint": {
|
|
20
|
+
"dependsOn": ["^build"]
|
|
21
|
+
},
|
|
22
|
+
"type-check": {
|
|
23
|
+
"dependsOn": ["^build"]
|
|
24
|
+
},
|
|
25
|
+
"test": {
|
|
26
|
+
"dependsOn": ["^build"],
|
|
27
|
+
"outputs": ["coverage/**"]
|
|
28
|
+
},
|
|
29
|
+
"db:generate": { "cache": false },
|
|
30
|
+
"db:migrate": { "cache": false },
|
|
31
|
+
"db:studio": { "cache": false, "persistent": true }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PACKAGE_SCOPE}}/api",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./src/index.ts"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"type-check": "tsc --noEmit",
|
|
10
|
+
"lint": "eslint src"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"{{PACKAGE_SCOPE}}/db": "workspace:*",
|
|
14
|
+
"{{PACKAGE_SCOPE}}/validators": "workspace:*",
|
|
15
|
+
"@trpc/server": "^11.0.0",
|
|
16
|
+
"superjson": "^2.2.0",
|
|
17
|
+
"zod": "^3.23.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^20.0.0",
|
|
21
|
+
"typescript": "^5.5.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createTRPCRouter, protectedProcedure } from "../../trpc";
|
|
2
|
+
import { syncUserOnSignIn } from "./auth.service";
|
|
3
|
+
|
|
4
|
+
export const authRouter = createTRPCRouter({
|
|
5
|
+
syncUser: protectedProcedure.mutation(({ ctx }) =>
|
|
6
|
+
syncUserOnSignIn(ctx.db, ctx.user),
|
|
7
|
+
),
|
|
8
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TRPCError } from "@trpc/server";
|
|
2
|
+
|
|
3
|
+
import type { Db } from "{{PACKAGE_SCOPE}}/db";
|
|
4
|
+
|
|
5
|
+
import { upsertUser } from "../user/user.service";
|
|
6
|
+
|
|
7
|
+
export async function syncUserOnSignIn(
|
|
8
|
+
db: Db,
|
|
9
|
+
user: { id: string; email?: string; user_metadata?: Record<string, unknown> },
|
|
10
|
+
) {
|
|
11
|
+
if (!user.email) throw new TRPCError({ code: "BAD_REQUEST", message: "User has no email" });
|
|
12
|
+
|
|
13
|
+
const displayName =
|
|
14
|
+
typeof user.user_metadata?.["full_name"] === "string"
|
|
15
|
+
? user.user_metadata["full_name"]
|
|
16
|
+
: user.email.split("@")[0];
|
|
17
|
+
|
|
18
|
+
return upsertUser(db, { id: user.id, email: user.email, displayName });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function requireAuth(userId: string | undefined): Promise<string> {
|
|
22
|
+
if (!userId) throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
23
|
+
return userId;
|
|
24
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createTRPCRouter, protectedProcedure } from "../../trpc";
|
|
2
|
+
import { getUserSchema, updateUserSchema } from "./user.schema";
|
|
3
|
+
import { deleteUser, getUserById, updateUser } from "./user.service";
|
|
4
|
+
|
|
5
|
+
export const userRouter = createTRPCRouter({
|
|
6
|
+
me: protectedProcedure.query(({ ctx }) =>
|
|
7
|
+
getUserById(ctx.db, ctx.user.id),
|
|
8
|
+
),
|
|
9
|
+
|
|
10
|
+
byId: protectedProcedure
|
|
11
|
+
.input(getUserSchema)
|
|
12
|
+
.query(({ ctx, input }) => getUserById(ctx.db, input.userId)),
|
|
13
|
+
|
|
14
|
+
update: protectedProcedure
|
|
15
|
+
.input(updateUserSchema)
|
|
16
|
+
.mutation(({ ctx, input }) => updateUser(ctx.db, ctx.user.id, input)),
|
|
17
|
+
|
|
18
|
+
delete: protectedProcedure.mutation(({ ctx }) =>
|
|
19
|
+
deleteUser(ctx.db, ctx.user.id),
|
|
20
|
+
),
|
|
21
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const updateUserSchema = z.object({
|
|
4
|
+
displayName: z.string().min(1).max(50),
|
|
5
|
+
avatarUrl: z.string().url().optional(),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const getUserSchema = z.object({
|
|
9
|
+
userId: z.string().uuid(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type UpdateUserInput = z.infer<typeof updateUserSchema>;
|
|
13
|
+
export type GetUserInput = z.infer<typeof getUserSchema>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { TRPCError } from "@trpc/server";
|
|
2
|
+
import { eq } from "drizzle-orm";
|
|
3
|
+
|
|
4
|
+
import { users, type Db } from "{{PACKAGE_SCOPE}}/db";
|
|
5
|
+
|
|
6
|
+
import type { UpdateUserInput } from "./user.schema";
|
|
7
|
+
|
|
8
|
+
export async function getUserById(db: Db, userId: string) {
|
|
9
|
+
const [user] = await db.select().from(users).where(eq(users.id, userId));
|
|
10
|
+
if (!user) throw new TRPCError({ code: "NOT_FOUND", message: "User not found" });
|
|
11
|
+
return user;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function updateUser(db: Db, userId: string, input: UpdateUserInput) {
|
|
15
|
+
const [updated] = await db
|
|
16
|
+
.update(users)
|
|
17
|
+
.set({ ...input, updatedAt: new Date() })
|
|
18
|
+
.where(eq(users.id, userId))
|
|
19
|
+
.returning();
|
|
20
|
+
if (!updated) throw new TRPCError({ code: "NOT_FOUND" });
|
|
21
|
+
return updated;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function deleteUser(db: Db, userId: string) {
|
|
25
|
+
await db.delete(users).where(eq(users.id, userId));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function upsertUser(
|
|
29
|
+
db: Db,
|
|
30
|
+
data: { id: string; email: string; displayName?: string },
|
|
31
|
+
) {
|
|
32
|
+
const [user] = await db
|
|
33
|
+
.insert(users)
|
|
34
|
+
.values({ id: data.id, email: data.email, displayName: data.displayName })
|
|
35
|
+
.onConflictDoUpdate({
|
|
36
|
+
target: users.id,
|
|
37
|
+
set: { email: data.email, updatedAt: new Date() },
|
|
38
|
+
})
|
|
39
|
+
.returning();
|
|
40
|
+
return user!;
|
|
41
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { appRouter } from "./root";
|
|
2
|
+
export type { AppRouter } from "./root";
|
|
3
|
+
export type { TRPCContext, AuthedContext } from "./trpc";
|
|
4
|
+
|
|
5
|
+
import type { inferRouterInputs, inferRouterOutputs } from "@trpc/server";
|
|
6
|
+
import type { AppRouter } from "./root";
|
|
7
|
+
|
|
8
|
+
export type RouterInputs = inferRouterInputs<AppRouter>;
|
|
9
|
+
export type RouterOutputs = inferRouterOutputs<AppRouter>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createTRPCRouter } from "./trpc";
|
|
2
|
+
import { authRouter } from "./features/auth/auth.router";
|
|
3
|
+
import { userRouter } from "./features/user/user.router";
|
|
4
|
+
|
|
5
|
+
export const appRouter = createTRPCRouter({
|
|
6
|
+
auth: authRouter,
|
|
7
|
+
user: userRouter,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export type AppRouter = typeof appRouter;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { initTRPC, TRPCError } from "@trpc/server";
|
|
2
|
+
import superjson from "superjson";
|
|
3
|
+
import { ZodError } from "zod";
|
|
4
|
+
|
|
5
|
+
import type { db } from "{{PACKAGE_SCOPE}}/db";
|
|
6
|
+
import type { Session, User } from "@supabase/supabase-js";
|
|
7
|
+
|
|
8
|
+
export type TRPCContext = {
|
|
9
|
+
db: typeof db;
|
|
10
|
+
session: Session | null;
|
|
11
|
+
user: User | null;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type AuthedContext = TRPCContext & {
|
|
15
|
+
session: Session;
|
|
16
|
+
user: User;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const t = initTRPC.context<TRPCContext>().create({
|
|
20
|
+
transformer: superjson,
|
|
21
|
+
errorFormatter({ shape, error }) {
|
|
22
|
+
return {
|
|
23
|
+
...shape,
|
|
24
|
+
data: {
|
|
25
|
+
...shape.data,
|
|
26
|
+
zodError: error.cause instanceof ZodError ? error.cause.flatten() : null,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const createTRPCRouter = t.router;
|
|
33
|
+
export const publicProcedure = t.procedure;
|
|
34
|
+
|
|
35
|
+
const enforceAuth = t.middleware(({ ctx, next }) => {
|
|
36
|
+
if (!ctx.session || !ctx.user) {
|
|
37
|
+
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
38
|
+
}
|
|
39
|
+
return next({ ctx: { ...ctx, session: ctx.session, user: ctx.user } });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export const protectedProcedure = t.procedure.use(enforceAuth);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PACKAGE_SCOPE}}/auth",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./src/index.ts",
|
|
8
|
+
"./server": "./src/server.ts",
|
|
9
|
+
"./client": "./src/client.ts",
|
|
10
|
+
"./middleware": "./src/middleware.ts"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"type-check": "tsc --noEmit",
|
|
14
|
+
"lint": "eslint src"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@supabase/supabase-js": "^2.45.0",
|
|
18
|
+
"@supabase/ssr": "^0.5.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"{{PACKAGE_SCOPE}}/config": "workspace:*",
|
|
22
|
+
"@types/node": "^20.0.0",
|
|
23
|
+
"next": "15.0.0",
|
|
24
|
+
"typescript": "^5.5.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createServerClient, type CookieOptions } from "@supabase/ssr";
|
|
2
|
+
import { NextResponse, type NextRequest } from "next/server";
|
|
3
|
+
|
|
4
|
+
export async function updateSession(request: NextRequest) {
|
|
5
|
+
let response = NextResponse.next({ request });
|
|
6
|
+
|
|
7
|
+
const supabase = createServerClient(
|
|
8
|
+
process.env.SUPABASE_URL!,
|
|
9
|
+
process.env.SUPABASE_ANON_KEY!,
|
|
10
|
+
{
|
|
11
|
+
cookies: {
|
|
12
|
+
getAll: () => request.cookies.getAll(),
|
|
13
|
+
setAll: (cookiesToSet: { name: string; value: string; options: CookieOptions }[]) => {
|
|
14
|
+
cookiesToSet.forEach(({ name, value, options }) => {
|
|
15
|
+
request.cookies.set(name, value);
|
|
16
|
+
response.cookies.set(name, value, options);
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
await supabase.auth.getUser();
|
|
24
|
+
return response;
|
|
25
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createServerClient as _create, type CookieOptions } from "@supabase/ssr";
|
|
2
|
+
import type { ReadonlyRequestCookies } from "next/dist/server/web/spec-extension/adapters/request-cookies";
|
|
3
|
+
|
|
4
|
+
export function createServerClient(cookieStore: ReadonlyRequestCookies) {
|
|
5
|
+
return _create(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, {
|
|
6
|
+
cookies: {
|
|
7
|
+
getAll: () => cookieStore.getAll(),
|
|
8
|
+
setAll: (cookiesToSet: { name: string; value: string; options: CookieOptions }[]) => {
|
|
9
|
+
cookiesToSet.forEach(({ name, value, options }) =>
|
|
10
|
+
cookieStore.set(name, value, options),
|
|
11
|
+
);
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** @type {import("eslint").Linter.Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
extends: [
|
|
4
|
+
"eslint:recommended",
|
|
5
|
+
"plugin:@typescript-eslint/recommended",
|
|
6
|
+
"plugin:import/recommended",
|
|
7
|
+
"plugin:import/typescript",
|
|
8
|
+
"prettier",
|
|
9
|
+
],
|
|
10
|
+
plugins: ["@typescript-eslint", "import"],
|
|
11
|
+
parser: "@typescript-eslint/parser",
|
|
12
|
+
rules: {
|
|
13
|
+
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
|
|
14
|
+
"@typescript-eslint/consistent-type-imports": [
|
|
15
|
+
"error",
|
|
16
|
+
{ prefer: "type-imports", fixStyle: "inline-type-imports" },
|
|
17
|
+
],
|
|
18
|
+
"import/order": [
|
|
19
|
+
"error",
|
|
20
|
+
{
|
|
21
|
+
groups: ["builtin", "external", "internal", "parent", "sibling", "index"],
|
|
22
|
+
"newlines-between": "always",
|
|
23
|
+
alphabetize: { order: "asc" },
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
"no-console": ["warn", { allow: ["warn", "error"] }],
|
|
27
|
+
},
|
|
28
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** @type {import("eslint").Linter.Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
extends: [
|
|
4
|
+
"./base.js",
|
|
5
|
+
"plugin:react/recommended",
|
|
6
|
+
"plugin:react-hooks/recommended",
|
|
7
|
+
"plugin:react-native/all",
|
|
8
|
+
],
|
|
9
|
+
plugins: ["react", "react-hooks", "react-native"],
|
|
10
|
+
settings: {
|
|
11
|
+
react: { version: "detect" },
|
|
12
|
+
},
|
|
13
|
+
rules: {
|
|
14
|
+
"react/react-in-jsx-scope": "off",
|
|
15
|
+
"react-native/no-raw-text": "off",
|
|
16
|
+
"react-native/no-color-literals": "warn",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PACKAGE_SCOPE}}/config",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"exports": {
|
|
6
|
+
"./eslint/base": "./eslint/base.js",
|
|
7
|
+
"./eslint/nextjs": "./eslint/nextjs.js",
|
|
8
|
+
"./eslint/react-native": "./eslint/react-native.js",
|
|
9
|
+
"./typescript/base": "./typescript/base.json",
|
|
10
|
+
"./typescript/nextjs": "./typescript/nextjs.json",
|
|
11
|
+
"./typescript/react-native": "./typescript/react-native.json"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "Bundler",
|
|
8
|
+
"allowImportingTsExtensions": true,
|
|
9
|
+
"noEmit": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"isolatedModules": true
|
|
15
|
+
},
|
|
16
|
+
"exclude": ["node_modules", "dist"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"extends": "./base.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"target": "ES2017",
|
|
6
|
+
"lib": ["dom", "dom.iterable", "ES2022"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"moduleResolution": "Bundler",
|
|
9
|
+
"jsx": "preserve",
|
|
10
|
+
"allowJs": true,
|
|
11
|
+
"incremental": true,
|
|
12
|
+
"plugins": [{ "name": "next" }],
|
|
13
|
+
"paths": {
|
|
14
|
+
"@/*": ["./*"]
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"exclude": ["node_modules", ".next", "dist"]
|
|
18
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"extends": "./base.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"target": "ES2020",
|
|
6
|
+
"lib": ["ES2020"],
|
|
7
|
+
"jsx": "react-native",
|
|
8
|
+
"allowSyntheticDefaultImports": true
|
|
9
|
+
},
|
|
10
|
+
"exclude": ["node_modules", "dist", ".expo"]
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DATABASE_URL=postgresql://postgres:postgres@localhost:54322/postgres
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { defineConfig } from "drizzle-kit";
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
schema: "./src/schema/index.ts",
|
|
6
|
+
out: "./src/migrations",
|
|
7
|
+
dialect: "postgresql",
|
|
8
|
+
dbCredentials: {
|
|
9
|
+
url: process.env.DATABASE_URL!,
|
|
10
|
+
},
|
|
11
|
+
verbose: true,
|
|
12
|
+
strict: true,
|
|
13
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PACKAGE_SCOPE}}/db",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./src/index.ts",
|
|
8
|
+
"./schema": "./src/schema/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"db:generate": "drizzle-kit generate",
|
|
12
|
+
"db:migrate": "drizzle-kit migrate",
|
|
13
|
+
"db:studio": "drizzle-kit studio",
|
|
14
|
+
"db:push": "drizzle-kit push",
|
|
15
|
+
"type-check": "tsc --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"dotenv": "^16.4.0",
|
|
19
|
+
"drizzle-orm": "^0.33.0",
|
|
20
|
+
"postgres": "^3.4.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"{{PACKAGE_SCOPE}}/config": "workspace:*",
|
|
24
|
+
"@types/node": "^20.0.0",
|
|
25
|
+
"drizzle-kit": "^0.24.0",
|
|
26
|
+
"typescript": "^5.5.0"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { drizzle } from "drizzle-orm/postgres-js";
|
|
2
|
+
import postgres from "postgres";
|
|
3
|
+
|
|
4
|
+
import * as schema from "./schema";
|
|
5
|
+
|
|
6
|
+
const client = postgres(process.env.DATABASE_URL!, {
|
|
7
|
+
max: 1,
|
|
8
|
+
ssl: process.env.NODE_ENV === "production" ? "require" : false,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const db = drizzle(client, { schema });
|
|
12
|
+
|
|
13
|
+
export type Db = typeof db;
|
|
14
|
+
export * from "./schema";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./users";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
export const users = pgTable("users", {
|
|
4
|
+
id: uuid("id").primaryKey(),
|
|
5
|
+
email: text("email").notNull().unique(),
|
|
6
|
+
displayName: text("display_name"),
|
|
7
|
+
avatarUrl: text("avatar_url"),
|
|
8
|
+
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
9
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type User = typeof users.$inferSelect;
|
|
13
|
+
export type NewUser = typeof users.$inferInsert;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PACKAGE_SCOPE}}/email",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./src/index.ts",
|
|
7
|
+
"./templates/*": "./src/templates/*.tsx"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"email:dev": "react-email dev --dir src/templates --port 3100",
|
|
11
|
+
"type-check": "tsc --noEmit"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@react-email/components": "latest",
|
|
15
|
+
"react": "^18.3.0",
|
|
16
|
+
"react-email": "latest",
|
|
17
|
+
"resend": "^4.0.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/react": "^18.3.0",
|
|
21
|
+
"typescript": "^5.5.0"
|
|
22
|
+
}
|
|
23
|
+
}
|