Skip to content

Commit 8a9fcdb

Browse files
authored
Merge pull request #178 from techulus/main
Update clerk
2 parents f40c9dd + 3f52f17 commit 8a9fcdb

9 files changed

Lines changed: 107 additions & 104 deletions

File tree

app/(dashboard)/[tenant]/layout.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ export default async function ConsoleLayout(props: {
1919
redirect("/start");
2020
}
2121

22-
const ready = await isDatabaseReady();
22+
// Parallelize database ready check and notifications wire setup
23+
const [ready, notificationsWire] = await Promise.all([
24+
isDatabaseReady(),
25+
caller.user.getNotificationsWire(),
26+
]);
27+
2328
if (!ready) {
2429
redirect("/start");
2530
}
2631

27-
const notificationsWire = await caller.user.getNotificationsWire();
28-
2932
return (
3033
<TRPCReactProvider>
3134
<NuqsAdapter>

bun.lock

Lines changed: 29 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

instrumentation-client.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,8 @@ import * as Sentry from "@sentry/nextjs";
66

77
Sentry.init({
88
dsn: process.env.SENTRY_DSN,
9-
109
// Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
1110
tracesSampleRate: 1,
12-
// Enable logs to be sent to Sentry
13-
enableLogs: true,
14-
15-
// Setting this option to true will print useful information to the console while you're setting up Sentry.
16-
debug: false,
1711
});
1812

1913
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;

lib/utils/useDatabase.ts

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import path from "node:path";
2+
import { currentUser } from "@clerk/nextjs/server";
23
import { sql } from "drizzle-orm";
4+
import { upstashCache } from "drizzle-orm/cache/upstash";
35
import { drizzle } from "drizzle-orm/node-postgres";
46
import { migrate } from "drizzle-orm/node-postgres/migrator";
57
import { err, ok, type Result, ResultAsync } from "neverthrow";
@@ -8,7 +10,9 @@ import { addUserToOpsDb } from "@/ops/useOps";
810
import * as schema from "../../drizzle/schema";
911
import { getOwner } from "./useOwner";
1012
import { addUserToTenantDb } from "./useUser";
11-
import { upstashCache } from "drizzle-orm/cache/upstash";
13+
14+
const connectionPool = new Map<string, Database>();
15+
const connectionTimestamps = new Map<string, number>();
1216

1317
function handleError(message: string) {
1418
return (error: unknown) => {
@@ -25,44 +29,49 @@ function getDatabaseName(ownerId: string): Result<string, string> {
2529
}
2630

2731
export async function isDatabaseReady(): Promise<boolean> {
28-
return await ResultAsync.fromPromise(
29-
migrateDatabase(),
30-
handleError("Migration failed"),
31-
)
32-
.andThen(() =>
33-
ResultAsync.fromPromise(
34-
addUserToTenantDb(),
35-
handleError("Failed to add user to tenant database"),
36-
),
37-
)
38-
.andThen(() =>
39-
ResultAsync.fromPromise(
40-
addUserToOpsDb(),
41-
handleError("Failed to add user to ops database"),
42-
),
43-
)
44-
.match(
45-
() => true,
46-
() => false,
47-
);
32+
try {
33+
const migrationResult = await migrateDatabase();
34+
35+
if (!migrationResult) {
36+
return false;
37+
}
38+
39+
const userData = await currentUser();
40+
if (!userData) {
41+
throw new Error("No user found");
42+
}
43+
44+
await Promise.all([addUserToTenantDb(userData), addUserToOpsDb(userData)]);
45+
46+
return true;
47+
} catch (error) {
48+
console.error("Database setup failed:", error);
49+
return false;
50+
}
4851
}
4952

5053
async function migrateDatabase(): Promise<boolean> {
51-
return await ResultAsync.fromPromise(
54+
const dbResult = await ResultAsync.fromPromise(
5255
database(),
5356
handleError("Failed to get database"),
54-
)
55-
.andThen((db) => {
56-
const migrationsFolder = path.resolve(process.cwd(), "drizzle");
57-
return ResultAsync.fromPromise(
58-
migrate(db, { migrationsFolder: migrationsFolder }),
59-
handleError("Failed to migrate database"),
60-
);
61-
})
62-
.match(
63-
() => true,
64-
() => false,
65-
);
57+
);
58+
59+
if (dbResult.isErr()) {
60+
return false;
61+
}
62+
63+
const db = dbResult.value;
64+
const migrationsFolder = path.resolve(process.cwd(), "drizzle");
65+
66+
const migrateResult = await ResultAsync.fromPromise(
67+
migrate(db, { migrationsFolder: migrationsFolder }),
68+
handleError("Failed to migrate database"),
69+
);
70+
71+
return migrateResult.match(
72+
() => true,
73+
() => false,
74+
);
6675
}
6776

6877
export async function database(): Promise<Database> {
@@ -75,6 +84,12 @@ export async function database(): Promise<Database> {
7584
}
7685

7786
export async function getDatabaseForOwner(ownerId: string): Promise<Database> {
87+
const cachedConnection = connectionPool.get(ownerId);
88+
if (cachedConnection) {
89+
connectionTimestamps.set(ownerId, Date.now());
90+
return cachedConnection;
91+
}
92+
7893
const databaseName = getDatabaseName(ownerId).match(
7994
(value) => {
8095
return value;
@@ -109,6 +124,9 @@ export async function getDatabaseForOwner(ownerId: string): Promise<Database> {
109124
},
110125
);
111126

127+
connectionPool.set(ownerId, tenantDb);
128+
connectionTimestamps.set(ownerId, Date.now());
129+
112130
return tenantDb;
113131
}
114132

@@ -122,6 +140,9 @@ export async function deleteDatabase(ownerId: string) {
122140
},
123141
);
124142

143+
connectionPool.delete(ownerId);
144+
connectionTimestamps.delete(ownerId);
145+
125146
const sslMode = process.env.DATABASE_SSL === "true" ? "?sslmode=require" : "";
126147

127148
const ownerDb = drizzle(`${process.env.DATABASE_URL}/manage${sslMode}`, {

lib/utils/useUser.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import type { currentUser } from "@clerk/nextjs/server";
12
import { user } from "@/drizzle/schema";
23
import type { User } from "@/drizzle/types";
3-
import { currentUser } from "@clerk/nextjs/server";
44
import { database } from "./useDatabase";
55
import { getOwner } from "./useOwner";
66

7-
export async function addUserToTenantDb() {
8-
const userData = await currentUser();
7+
export async function addUserToTenantDb(
8+
userData?: Awaited<ReturnType<typeof currentUser>>,
9+
) {
910
if (!userData) {
1011
throw new Error("No user found");
1112
}
@@ -15,7 +16,9 @@ export async function addUserToTenantDb() {
1516
}
1617

1718
const db = await database();
18-
db.insert(user)
19+
20+
await db
21+
.insert(user)
1922
.values({
2023
id: userData.id,
2124
email: userData.emailAddresses?.[0].emailAddress,

ops/useOps.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import path from "node:path";
2-
import { auth, clerkClient, currentUser } from "@clerk/nextjs/server";
2+
import { auth, clerkClient, type currentUser } from "@clerk/nextjs/server";
33
import { drizzle } from "drizzle-orm/node-postgres";
44
import { migrate } from "drizzle-orm/node-postgres/migrator";
55
import * as schema from "./drizzle/schema";
@@ -18,9 +18,11 @@ export async function getOpsDatabase(): Promise<OpsDatabase> {
1818
return ownerDb;
1919
}
2020

21-
export async function addUserToOpsDb() {
21+
export async function addUserToOpsDb(
22+
userData?: Awaited<ReturnType<typeof currentUser>>,
23+
) {
2224
const { orgId } = await auth();
23-
const userData = await currentUser();
25+
2426
if (!userData) {
2527
throw new Error("No user found");
2628
}
@@ -29,7 +31,9 @@ export async function addUserToOpsDb() {
2931
}
3032

3133
const db = await getOpsDatabase();
32-
db.insert(schema.opsUser)
34+
35+
await db
36+
.insert(schema.opsUser)
3337
.values({
3438
id: userData.id,
3539
email: userData.emailAddresses?.[0].emailAddress,

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
"@blocknote/core": "^0.27.2",
1919
"@blocknote/mantine": "^0.27.2",
2020
"@blocknote/react": "^0.27.2",
21-
"@clerk/nextjs": "^6.20.1",
22-
"@clerk/themes": "^2.2.47",
21+
"@clerk/nextjs": "^6.31.6",
22+
"@clerk/themes": "^2.4.15",
2323
"@dnd-kit/core": "^6.1.0",
2424
"@dnd-kit/sortable": "^8.0.0",
2525
"@dnd-kit/utilities": "^3.2.2",

sentry.edge.config.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,6 @@ import * as Sentry from "@sentry/nextjs";
77

88
Sentry.init({
99
dsn: process.env.SENTRY_DSN,
10-
1110
// Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
1211
tracesSampleRate: 1,
13-
14-
// Enable logs to be sent to Sentry
15-
enableLogs: true,
16-
17-
// Setting this option to true will print useful information to the console while you're setting up Sentry.
18-
debug: false,
1912
});

sentry.server.config.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,6 @@ import * as Sentry from "@sentry/nextjs";
66

77
Sentry.init({
88
dsn: process.env.SENTRY_DSN,
9-
109
// Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
1110
tracesSampleRate: 1,
12-
13-
// Enable logs to be sent to Sentry
14-
enableLogs: true,
15-
16-
// Setting this option to true will print useful information to the console while you're setting up Sentry.
17-
debug: false,
1811
});

0 commit comments

Comments
 (0)