Reconcile validated Turso runtime fix with republished main history

Hop-State: A_06FP6A2CG8PVBRDVQ5WGCN0
Hop-Proposal: R_06FP6A0YW23RY0N7Z5M8DW0
Hop-Task: T_06FP67JVF4BHPYKKC37XKQ8
Hop-Attempt: AT_06FP69RZ96ZMNF9Y5S02MT0
This commit is contained in:
2026-07-14 17:23:33 -07:00
committed by Hop
20 changed files with 65 additions and 41 deletions
+12 -6
View File
@@ -1,14 +1,20 @@
import { sql } from 'drizzle-orm';
import { migrate } from 'drizzle-orm/tursodatabase/migrator';
import { db } from '../src/db';
import { closeDb, db } from '../src/db';
async function main() {
const result = await migrate(db, { migrationsFolder: './drizzle' });
try {
const result = await migrate(db, { migrationsFolder: './drizzle' });
if (result) {
throw new Error(`Database migration failed: ${JSON.stringify(result)}`);
if (result) {
throw new Error(`Database migration failed: ${JSON.stringify(result)}`);
}
await db.run(sql.raw('PRAGMA wal_checkpoint(TRUNCATE)'));
console.log('Database migrations are up to date.');
} finally {
await closeDb();
}
console.log('Database migrations are up to date.');
}
main().catch((error) => {
+1 -1
View File
@@ -16,7 +16,7 @@ export async function GET() {
await requireAdmin();
const nodes = await db.query.swarmNodes.findMany({
orderBy: () => [desc(swarmNodes.isBlocked), desc(swarmNodes.blockedAt), desc(swarmNodes.lastSeenAt)],
orderBy: (swarmNodes, { desc }) => [desc(swarmNodes.isBlocked), desc(swarmNodes.blockedAt), desc(swarmNodes.lastSeenAt)],
});
return NextResponse.json({
+1 -1
View File
@@ -24,7 +24,7 @@ export async function GET(request: Request) {
with: {
author: true,
},
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit,
});
+1 -1
View File
@@ -17,7 +17,7 @@ export async function GET(request: Request) {
const reportRows = await db.query.reports.findMany({
where: status === 'all' ? undefined : { status: status },
orderBy: () => [desc(reports.createdAt)],
orderBy: (reports, { desc }) => [desc(reports.createdAt)],
limit,
with: {
reporter: true,
+1 -1
View File
@@ -50,7 +50,7 @@ export async function GET(request: Request) {
userId: user.id,
...(unreadOnly ? { readAt: { isNull: true as const } } : {}),
},
orderBy: () => [desc(notifications.createdAt)],
orderBy: (notifications, { desc }) => [desc(notifications.createdAt)],
limit,
});
+1 -1
View File
@@ -178,7 +178,7 @@ export async function GET(
const replies = await db.query.posts.findMany({
where: { AND: [{ replyToId: id }, { isRemoved: false }] },
with: postDetailRelations,
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
});
mainPost = {
+8 -8
View File
@@ -631,7 +631,7 @@ export async function GET(request: Request) {
feedPosts = await db.query.posts.findMany({
where: whereCondition,
with: feedPostRelations,
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit,
});
} else if (type === 'public') {
@@ -639,13 +639,13 @@ export async function GET(request: Request) {
const localPosts = await db.query.posts.findMany({
where: baseFilter,
with: feedPostRelations,
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit: limit * 2,
});
// Get all cached remote posts
const remotePostsData = await db.query.remotePosts.findMany({
orderBy: () => [desc(remotePosts.publishedAt)],
orderBy: (remotePosts, { desc }) => [desc(remotePosts.publishedAt)],
limit: limit,
});
@@ -676,7 +676,7 @@ export async function GET(request: Request) {
feedPosts = await db.query.posts.findMany({
where: whereCondition,
with: feedPostRelations,
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit,
});
} else if (type === 'replies' && userId) {
@@ -700,7 +700,7 @@ export async function GET(request: Request) {
feedPosts = await db.query.posts.findMany({
where: whereCondition,
with: feedPostRelations,
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit,
});
} else if (type === 'curated') {
@@ -868,7 +868,7 @@ export async function GET(request: Request) {
const localPosts = await db.query.posts.findMany({
where: whereCondition,
with: feedPostRelations,
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit: cursor ? limit : limit * 2, // Get more on first load to account for mixing with remote
});
@@ -878,7 +878,7 @@ export async function GET(request: Request) {
};
const swarmRepostRows = await db.query.userSwarmReposts.findMany({
where: swarmRepostWhere,
orderBy: () => [desc(userSwarmReposts.repostedAt)],
orderBy: (userSwarmReposts, { desc }) => [desc(userSwarmReposts.repostedAt)],
limit: cursor ? limit : limit * 2,
});
@@ -967,7 +967,7 @@ export async function GET(request: Request) {
feedPosts = await db.query.posts.findMany({
where: baseFilter,
with: feedPostRelations,
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit,
});
}
+1 -1
View File
@@ -194,7 +194,7 @@ export async function GET(request: Request) {
...(moderatedIds.length ? { userId: { notIn: moderatedIds } } : {}),
},
with: searchPostRelations,
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit,
});
searchPosts = postResults;
@@ -23,10 +23,10 @@ export async function GET(request: NextRequest) {
// Get all conversations for this user
const conversations = await db.query.chatConversations.findMany({
where: { participant1Id: session.user.id },
orderBy: () => [desc(chatConversations.lastMessageAt)],
orderBy: (chatConversations, { desc }) => [desc(chatConversations.lastMessageAt)],
with: {
messages: {
orderBy: () => [desc(chatMessages.createdAt)],
orderBy: (chatMessages, { desc }) => [desc(chatMessages.createdAt)],
limit: 1,
},
},
+1 -1
View File
@@ -67,7 +67,7 @@ export async function GET(request: NextRequest) {
// Get messages
const messages = await db.query.chatMessages.findMany({
where: whereCondition,
orderBy: () => [desc(chatMessages.createdAt)],
orderBy: (chatMessages, { desc }) => [desc(chatMessages.createdAt)],
limit,
});
+1 -1
View File
@@ -109,7 +109,7 @@ export async function GET(request: NextRequest, context: RouteContext) {
author: true,
media: true,
},
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit: 50,
});
+2 -2
View File
@@ -224,13 +224,13 @@ export async function GET(request: NextRequest, context: RouteContext) {
const localPosts = await db.query.posts.findMany({
where: { AND: [{ userId: user.id }, { isRemoved: false }, { replyToId: { isNull: true } }, { swarmReplyToId: { isNull: true } }] },
with: profilePostRelations,
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit: limit * 2,
});
const remoteRepostRows = await db.query.userSwarmReposts.findMany({
where: { userId: user.id },
orderBy: () => [desc(userSwarmReposts.repostedAt)],
orderBy: (userSwarmReposts, { desc }) => [desc(userSwarmReposts.repostedAt)],
limit: limit * 2,
});
+2 -2
View File
@@ -147,7 +147,7 @@ export async function GET(request: Request, context: RouteContext) {
with: likedPostRelations,
},
},
orderBy: () => [desc(likes.createdAt)],
orderBy: (likes, { desc }) => [desc(likes.createdAt)],
limit,
});
@@ -157,7 +157,7 @@ export async function GET(request: Request, context: RouteContext) {
const swarmLikedRows = await db.query.userSwarmLikes.findMany({
where: { userId: user.id },
orderBy: () => [desc(userSwarmLikes.likedAt)],
orderBy: (userSwarmLikes, { desc }) => [desc(userSwarmLikes.likedAt)],
limit,
});
+2 -2
View File
@@ -341,7 +341,7 @@ export async function GET(request: Request, context: RouteContext) {
const localPosts = await db.query.posts.findMany({
where: whereConditions,
with: userPostRelations,
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit: cursor ? limit : limit * 2,
});
@@ -351,7 +351,7 @@ export async function GET(request: Request, context: RouteContext) {
};
const swarmRepostRows = await db.query.userSwarmReposts.findMany({
where: swarmRepostWhere,
orderBy: () => [desc(userSwarmReposts.repostedAt)],
orderBy: (userSwarmReposts, { desc }) => [desc(userSwarmReposts.repostedAt)],
limit: cursor ? limit : limit * 2,
});
let userPosts: any[] = [
+1 -1
View File
@@ -143,7 +143,7 @@ export async function GET(request: Request, context: RouteContext) {
...(cursorDate ? { createdAt: { lt: cursorDate } } : {}),
},
with: replyRelations,
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit,
});
+19 -1
View File
@@ -10,7 +10,25 @@ if (databasePath !== ':memory:') {
mkdirSync(dirname(databasePath), { recursive: true });
}
export const db = drizzle(databasePath, { relations });
const createDb = () => drizzle(databasePath, { relations });
type SynapsisDatabase = ReturnType<typeof createDb>;
const globalForDb = globalThis as typeof globalThis & {
synapsisDb?: SynapsisDatabase;
};
export const db = globalForDb.synapsisDb ?? createDb();
globalForDb.synapsisDb = db;
export async function closeDb(): Promise<void> {
if (!globalForDb.synapsisDb) {
return;
}
await globalForDb.synapsisDb.$client.close();
delete globalForDb.synapsisDb;
}
// Embedded Turso is always available; DATABASE_PATH only changes its location.
export const isDbAvailable = () => true;
+2 -2
View File
@@ -107,7 +107,7 @@ export async function getLogsForBot(
},
} : {}),
},
orderBy: () => [desc(botActivityLogs.createdAt)], // Reverse chronological
orderBy: (botActivityLogs, { desc }) => [desc(botActivityLogs.createdAt)], // Reverse chronological
limit: options.limit || 100,
offset: options.offset || 0,
});
@@ -140,7 +140,7 @@ export async function getErrorLogs(
): Promise<ActivityLog[]> {
const logs = await db.query.botActivityLogs.findMany({
where: { AND: [{ botId: botId }, { success: false }] },
orderBy: () => [desc(botActivityLogs.createdAt)],
orderBy: (botActivityLogs, { desc }) => [desc(botActivityLogs.createdAt)],
limit,
});
+3 -3
View File
@@ -150,7 +150,7 @@ export async function detectMentions(botId: string): Promise<MentionDetectionRes
},
},
},
orderBy: () => [desc(posts.createdAt)],
orderBy: (posts, { desc }) => [desc(posts.createdAt)],
limit: 1000, // Reasonable limit for scanning
});
@@ -217,7 +217,7 @@ export async function getUnprocessedMentions(botId: string): Promise<Mention[]>
try {
const mentions = await db.query.botMentions.findMany({
where: { AND: [{ botId: botId }, { isProcessed: false }] },
orderBy: () => [asc(botMentions.createdAt)], // Chronological order (oldest first)
orderBy: (botMentions, { asc }) => [asc(botMentions.createdAt)], // Chronological order (oldest first)
});
return mentions.map(m => ({
@@ -252,7 +252,7 @@ export async function getAllMentions(botId: string): Promise<Mention[]> {
try {
const mentions = await db.query.botMentions.findMany({
where: { botId: botId },
orderBy: () => [desc(botMentions.createdAt)],
orderBy: (botMentions, { desc }) => [desc(botMentions.createdAt)],
});
return mentions.map(m => ({
+1 -1
View File
@@ -57,7 +57,7 @@ export async function buildGossipPayload(since?: string): Promise<SwarmGossipPay
const sinceDate = since ? new Date(since) : undefined;
const handleEntries = await db.query.handleRegistry.findMany({
where: sinceDate ? { updatedAt: { gt: sinceDate } } : undefined,
orderBy: () => [desc(handleRegistry.updatedAt)],
orderBy: (handleRegistry, { desc }) => [desc(handleRegistry.updatedAt)],
limit: SWARM_CONFIG.maxHandlesPerGossip,
});
+3 -3
View File
@@ -111,7 +111,7 @@ export async function getActiveSwarmNodes(limit = 100): Promise<SwarmNodeInfo[]>
const nodes = await db.query.swarmNodes.findMany({
where: { AND: [{ isActive: true }, { isBlocked: false }] },
orderBy: () => [desc(swarmNodes.lastSeenAt)],
orderBy: (swarmNodes, { desc }) => [desc(swarmNodes.lastSeenAt)],
limit,
});
@@ -146,7 +146,7 @@ export async function getNodesSince(since: Date, limit = 100): Promise<SwarmNode
const nodes = await db.query.swarmNodes.findMany({
where: { AND: [{ updatedAt: { gt: since } }, { isBlocked: false }] },
orderBy: () => [desc(swarmNodes.updatedAt)],
orderBy: (swarmNodes, { desc }) => [desc(swarmNodes.updatedAt)],
limit,
});
@@ -265,7 +265,7 @@ export async function getSeedNodes(): Promise<string[]> {
const seeds = await db.query.swarmSeeds.findMany({
where: { isEnabled: true },
orderBy: () => [swarmSeeds.priority],
orderBy: (swarmSeeds) => [swarmSeeds.priority],
});
if (seeds.length === 0) {