Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions apps/web/actions/account/remove-profile-image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"use server";

import path from "node:path";
import { db } from "@cap/database";
import { getCurrentUser } from "@cap/web-backend/auth/session";

Check failure on line 5 in apps/web/actions/account/remove-profile-image.ts

View workflow job for this annotation

GitHub Actions / Typecheck

Cannot find module '@cap/web-backend/auth/session' or its corresponding type declarations.
import { users } from "@cap/database/schema";
import { S3Buckets } from "@cap/web-backend";
import { eq } from "drizzle-orm";
import { Effect, Option } from "effect";
import { revalidatePath } from "next/cache";
import { runPromise } from "@/lib/server";

export async function removeProfileImage() {
const user = await getCurrentUser();

if (!user) {
throw new Error("Unauthorized");
}

const image = user.image;

// Delete the profile image from S3 if it exists
if (image) {
try {
// Extract the S3 key - handle both old URL format and new key format
let s3Key = image;
if (image.startsWith("http://") || image.startsWith("https://")) {
const url = new URL(image);
// Only extract key from URLs with amazonaws.com hostname
if (
url.hostname.endsWith(".amazonaws.com") ||
url.hostname === "amazonaws.com"
) {
const raw = url.pathname.startsWith("/")
? url.pathname.slice(1)
: url.pathname;
const decoded = decodeURIComponent(raw);
const normalized = path.posix.normalize(decoded);
if (normalized.includes("..")) {
throw new Error("Invalid S3 key path");
}
s3Key = normalized;
} else {
// Not an S3 URL, skip deletion of S3 object; continue with DB update below
}
}

// Only delete if it looks like a user profile image key
if (s3Key.startsWith("users/")) {
await Effect.gen(function* () {
const [bucket] = yield* S3Buckets.getBucketAccess(Option.none());
yield* bucket.deleteObject(s3Key);
}).pipe(runPromise);
}
} catch (error) {
console.error("Error deleting profile image from S3:", error);
// Continue with database update even if S3 deletion fails
}
}

await db().update(users).set({ image: null }).where(eq(users.id, user.id));

revalidatePath("/dashboard/settings/account");

return { success: true } as const;
}
File renamed without changes.
35 changes: 35 additions & 0 deletions packages/auth/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "@cap/auth",
"private": true,
"type": "module",
"scripts": {
"build": "tsdown"
},
"dependencies": {
"drizzle-orm": "0.44.6",
"next": "15.5.4",
"next-auth": "^4.24.5",
"zod": "^3"
},
"devDependencies": {
"@cap/ui": "workspace:*",
"@cap/utils": "workspace:*",
"@types/node": "^20.10.0",
"@types/react": "^19.1.13",
"@types/react-dom": "19.1.9",
"dotenv-cli": "latest",
"drizzle-kit": "0.31.0",
"nodemailer": "^6.9.8",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-router-dom": "^6.18.0",
"tsconfig": "workspace:*",
"typescript": "^5.8.3"
},
"engines": {
"node": "20"
},
"exports": {
".": "./src/index.ts"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import EmailProvider from "next-auth/providers/email";
import GoogleProvider from "next-auth/providers/google";
import type { Provider } from "next-auth/providers/index";
import WorkOSProvider from "next-auth/providers/workos";
import { dub } from "../dub.ts";
import { sendEmail } from "../emails/config.ts";
import { nanoId } from "../helpers.ts";
import { db } from "../index.ts";
import { organizationMembers, organizations, users } from "../schema.ts";
import { users } from "../schema.ts";
import { isEmailAllowedForSignup } from "./domain-utils.ts";
import { DrizzleAdapter } from "./drizzle-adapter.ts";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { and, eq } from "drizzle-orm";
import type { MySql2Database } from "drizzle-orm/mysql2";
import type { Adapter } from "next-auth/adapters";
import type Stripe from "stripe";
import { nanoId } from "../helpers.ts";
import { nanoId } from "../helpers";
import {
accounts,
organizationInvites,
Expand All @@ -13,7 +13,7 @@ import {
sessions,
users,
verificationTokens,
} from "../schema.ts";
} from "../schema";

export function DrizzleAdapter(db: MySql2Database): Adapter {
return {
Expand Down
3 changes: 3 additions & 0 deletions packages/auth/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./session";
export * from "./drizzle-adapter";
export * from "./session";
File renamed without changes.
17 changes: 17 additions & 0 deletions packages/auth/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "../config/base.tsconfig.json",
"exclude": ["node_modules", "dist"],
"include": [
"next-env.d.ts",
".next/types/**/*.ts",
"**/*.ts",
"**/*.tsx",
"./package.json"
],
"compilerOptions": {
"composite": true,
"outDir": "dist",
"noEmit": false,
"emitDeclarationOnly": true
}
}
9 changes: 9 additions & 0 deletions packages/auth/tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { defineConfig } from "tsdown";
import pkgJson from "./package.json" with { type: "json" };

export default defineConfig({
entry: Object.values(pkgJson.exports),
platform: "node",
treeshake: true,
dts: false,
});
Empty file removed packages/database/.gitignore
Empty file.
29 changes: 1 addition & 28 deletions packages/database/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,17 @@
"@mattrax/mysql-planetscale": "^0.0.3",
"@paralleldrive/cuid2": "^2.2.2",
"@planetscale/database": "^1.19.0",
"@react-email/components": "^0.1.0",
"@react-email/render": "1.1.2",
"@react-email/tailwind": "^1.0.5",
"drizzle-orm": "0.44.6",
"dub": "^0.64.0",
"effect": "^3.18.4",
"mysql2": "^3.15.2",
"nanoid": "^5.0.4",
"next": "15.5.4",
"next-auth": "^4.24.5",
"react-email": "^4.0.16",
"resend": "4.6.0",
"zod": "^3"
"nanoid": "^5.0.4"
},
"devDependencies": {
"@cap/ui": "workspace:*",
"@cap/utils": "workspace:*",
"@types/node": "^20.10.0",
"@types/react": "^19.1.13",
"@types/react-dom": "19.1.9",
"dotenv-cli": "latest",
"drizzle-kit": "0.31.0",
"nodemailer": "^6.9.8",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-router-dom": "^6.18.0",
"tsconfig": "workspace:*",
"typescript": "^5.8.3"
},
Expand All @@ -62,18 +47,6 @@
"./schema": "./schema.ts",
"./crypto": "./crypto.ts",
"./helpers": "./helpers.ts",
"./emails/config": "./emails/config.ts",
"./emails/*": "./emails/*.tsx",
"./types": "./types/index.ts"
},
"publishConfig": {
"exports": {
".": "./dist/index.js",
"./auth/auth-options": "./dist/auth/auth-options.js",
"./auth/session": "./dist/auth/session.js",
"./schema": "./dist/schema.js",
"./crypto": "./dist/crypto.js",
"./helpers": "./dist/helpers.js"
}
}
}
2 changes: 1 addition & 1 deletion packages/database/tsdown.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { defineConfig } from "tsdown";
import pkgJson from "./package.json" with { type: "json" };

export default defineConfig({
entry: Object.values(pkgJson.exports).filter((s) => !s.includes("email")),
entry: Object.values(pkgJson.exports),
platform: "node",
treeshake: true,
dts: false,
Expand Down
37 changes: 37 additions & 0 deletions packages/emails/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@cap/email",
"private": true,
"type": "module",
"scripts": {
"build": "tsdown"
},
"dependencies": {
"@react-email/components": "^0.1.0",
"@react-email/render": "1.1.2",
"@react-email/tailwind": "^1.0.5",
"react-email": "^4.0.16",
"resend": "4.6.0"
},
"devDependencies": {
"@cap/ui": "workspace:*",
"@cap/utils": "workspace:*",
"@types/node": "^20.10.0",
"@types/react": "^19.1.13",
"@types/react-dom": "19.1.9",
"dotenv-cli": "latest",
"drizzle-kit": "0.31.0",
"nodemailer": "^6.9.8",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-router-dom": "^6.18.0",
"tsconfig": "workspace:*",
"typescript": "^5.8.3"
},
"engines": {
"node": "20"
},
"exports": {
"./emails/config": "./emails/config.ts",
"./emails/*": "./emails/*.tsx"
}
}
File renamed without changes.
20 changes: 20 additions & 0 deletions packages/emails/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"extends": "../config/base.tsconfig.json",
"exclude": ["node_modules", "dist"],
"include": [
"next-env.d.ts",
".next/types/**/*.ts",
"**/*.ts",
"**/*.tsx",
"./package.json"
],
"compilerOptions": {
"composite": true,
"outDir": "dist",
"noEmit": false,
"emitDeclarationOnly": true,
"paths": {
"@/emails/*": ["./emails/*"]
}
}
}
9 changes: 9 additions & 0 deletions packages/emails/tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { defineConfig } from "tsdown";
import pkgJson from "./package.json" with { type: "json" };

export default defineConfig({
entry: Object.values(pkgJson.exports),
platform: "node",
treeshake: true,
dts: false,
});
1 change: 1 addition & 0 deletions packages/web-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@smithy/types": "^4.3.1",
"@vercel/functions": "^3.1.0",
"drizzle-orm": "0.44.6",
"dub": "^0.64.0",
"effect": "^3.18.4",
"next": "15.5.4",
"server-only": "^0.0.1"
Expand Down
2 changes: 2 additions & 0 deletions packages/database/dub.ts → packages/web-backend/src/Dub.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// TODO: Move to Effect service

import { serverEnv } from "@cap/env";

Check failure on line 3 in packages/web-backend/src/Dub.ts

View workflow job for this annotation

GitHub Actions / Typecheck

Cannot find module '@cap/env' or its corresponding type declarations.
import { Dub } from "dub";

export const dub = () =>
Expand Down
Loading
Loading