Replace PostgreSQL and Docker deployment with embedded Turso, Drizzle relational queries v2, native systemd deployment on port 43821, and fresh SQLite migrations.

Hop-State: A_06FP5KEDBTB4A9ZT7QB498G
Hop-Proposal: R_06FP5KDWMCKVVMQZT4MVZ28
Hop-Task: T_06FP5DZ7T0G45FG93PT90B8
Hop-Attempt: AT_06FP5DZ7T0PKQW99V27JCV8
This commit is contained in:
2026-07-14 15:44:42 -07:00
committed by Hop
184 changed files with 8375 additions and 53944 deletions
+2 -2
View File
@@ -22,7 +22,7 @@ function normalizeOptionalUrl(value: string | null | undefined): string | undefi
* Build this node's announcement payload
*/
export async function buildAnnouncement(): Promise<SwarmAnnouncement> {
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000';
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:43821';
let name = 'Synapsis Node';
let description: string | undefined;
@@ -35,7 +35,7 @@ export async function buildAnnouncement(): Promise<SwarmAnnouncement> {
if (db) {
// Get node info
const node = await db.query.nodes.findFirst({
where: eq(nodes.domain, domain),
where: { domain: domain },
});
if (node) {
+3 -3
View File
@@ -25,7 +25,7 @@ import { buildAnnouncement } from './discovery';
* Build a gossip payload to send to another node
*/
export async function buildGossipPayload(since?: string): Promise<SwarmGossipPayload> {
const ourDomain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000';
const ourDomain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:43821';
// Get nodes to share
let nodes: SwarmNodeInfo[];
@@ -56,8 +56,8 @@ export async function buildGossipPayload(since?: string): Promise<SwarmGossipPay
if (db) {
const sinceDate = since ? new Date(since) : undefined;
const handleEntries = await db.query.handleRegistry.findMany({
where: sinceDate ? gt(handleRegistry.updatedAt, sinceDate) : undefined,
orderBy: [desc(handleRegistry.updatedAt)],
where: sinceDate ? { updatedAt: { gt: sinceDate } } : undefined,
orderBy: () => [desc(handleRegistry.updatedAt)],
limit: SWARM_CONFIG.maxHandlesPerGossip,
});
+1 -1
View File
@@ -20,7 +20,7 @@ interface IdentityCacheEntry {
*/
export async function getCachedIdentity(did: string): Promise<IdentityCacheEntry | null> {
const cached = await db.query.remoteIdentityCache.findFirst({
where: eq(remoteIdentityCache.did, did),
where: { did: did },
});
return cached || null;
+2 -2
View File
@@ -465,7 +465,7 @@ export async function cacheSwarmUserPosts(
// Check if we already have this post
const existing = await db.query.remotePosts.findFirst({
where: eq(remotePosts.apId, apId),
where: { apId: apId },
});
if (existing) {
@@ -673,7 +673,7 @@ export async function getSwarmFollowerDomains(userId: string): Promise<string[]>
if (!db) return [];
const followers = await db.query.remoteFollowers.findMany({
where: eq(remoteFollowers.userId, userId),
where: { userId: userId },
});
// Filter for swarm followers (actorUrl starts with swarm://)
+5 -8
View File
@@ -17,7 +17,7 @@ export async function isNodeBlocked(domain: string | null | undefined): Promise<
if (!normalized) return false;
const node = await db.query.swarmNodes.findFirst({
where: eq(swarmNodes.domain, normalized),
where: { domain: normalized },
columns: {
isBlocked: true,
},
@@ -30,7 +30,7 @@ export async function getBlockedNodeDomains(): Promise<Set<string>> {
if (!db) return new Set();
const rows = await db.query.swarmNodes.findMany({
where: eq(swarmNodes.isBlocked, true),
where: { isBlocked: true },
columns: {
domain: true,
},
@@ -46,10 +46,7 @@ export async function filterBlockedDomains(domains: string[]): Promise<string[]>
if (normalized.length === 0) return [];
const blocked = await db.query.swarmNodes.findMany({
where: and(
inArray(swarmNodes.domain, normalized),
eq(swarmNodes.isBlocked, true),
),
where: { AND: [{ domain: { in: normalized } }, { isBlocked: true }] },
columns: {
domain: true,
},
@@ -66,7 +63,7 @@ export async function upsertBlockedNode(domain: string, reason?: string | null)
if (!normalized) return null;
const existing = await db.query.swarmNodes.findFirst({
where: eq(swarmNodes.domain, normalized),
where: { domain: normalized },
});
if (existing) {
@@ -105,7 +102,7 @@ export async function unblockNode(domain: string) {
if (!normalized) return null;
const existing = await db.query.swarmNodes.findFirst({
where: eq(swarmNodes.domain, normalized),
where: { domain: normalized },
});
if (!existing) return null;
+4 -4
View File
@@ -68,11 +68,11 @@ export async function getNodeKeypair(): Promise<{ privateKey: string; publicKey:
throw new Error('Database not available');
}
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000';
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:43821';
// Try to get existing node
let node = await db.query.nodes.findFirst({
where: eq(nodes.domain, domain),
where: { domain: domain },
});
// If node doesn't exist, create it
@@ -118,9 +118,9 @@ export async function getNodeKeypair(): Promise<{ privateKey: string; publicKey:
export async function getNodePublicKey(): Promise<string | null> {
if (!db) return null;
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000';
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:43821';
const node = await db.query.nodes.findFirst({
where: eq(nodes.domain, domain),
where: { domain: domain },
});
if (!node?.publicKey) {
+11 -21
View File
@@ -22,7 +22,7 @@ export async function upsertSwarmNode(
}
const existing = await db.query.swarmNodes.findFirst({
where: eq(swarmNodes.domain, normalizeNodeDomain(node.domain)),
where: { domain: normalizeNodeDomain(node.domain) },
});
const normalizedDomain = normalizeNodeDomain(node.domain);
@@ -110,11 +110,8 @@ export async function getActiveSwarmNodes(limit = 100): Promise<SwarmNodeInfo[]>
}
const nodes = await db.query.swarmNodes.findMany({
where: and(
eq(swarmNodes.isActive, true),
eq(swarmNodes.isBlocked, false),
),
orderBy: [desc(swarmNodes.lastSeenAt)],
where: { AND: [{ isActive: true }, { isBlocked: false }] },
orderBy: () => [desc(swarmNodes.lastSeenAt)],
limit,
});
@@ -131,12 +128,8 @@ export async function getNodesForGossip(count: number): Promise<SwarmNodeInfo[]>
// Get active nodes with decent trust scores, ordered randomly
const nodes = await db.query.swarmNodes.findMany({
where: and(
eq(swarmNodes.isActive, true),
eq(swarmNodes.isBlocked, false),
gt(swarmNodes.trustScore, 20)
),
orderBy: sql`RANDOM()`,
where: { AND: [{ isActive: true }, { isBlocked: false }, { trustScore: { gt: 20 } }] },
orderBy: () => sql`RANDOM()`,
limit: count,
});
@@ -152,11 +145,8 @@ export async function getNodesSince(since: Date, limit = 100): Promise<SwarmNode
}
const nodes = await db.query.swarmNodes.findMany({
where: and(
gt(swarmNodes.updatedAt, since),
eq(swarmNodes.isBlocked, false),
),
orderBy: [desc(swarmNodes.updatedAt)],
where: { AND: [{ updatedAt: { gt: since } }, { isBlocked: false }] },
orderBy: () => [desc(swarmNodes.updatedAt)],
limit,
});
@@ -173,7 +163,7 @@ export async function markNodeFailure(domain: string): Promise<void> {
try {
const node = await db.query.swarmNodes.findFirst({
where: eq(swarmNodes.domain, domain),
where: { domain: domain },
});
if (!node) return;
@@ -209,7 +199,7 @@ export async function markNodeSuccess(domain: string): Promise<void> {
try {
const node = await db.query.swarmNodes.findFirst({
where: eq(swarmNodes.domain, domain),
where: { domain: domain },
});
if (!node) return;
@@ -274,8 +264,8 @@ export async function getSeedNodes(): Promise<string[]> {
}
const seeds = await db.query.swarmSeeds.findMany({
where: eq(swarmSeeds.isEnabled, true),
orderBy: [swarmSeeds.priority],
where: { isEnabled: true },
orderBy: () => [swarmSeeds.priority],
});
if (seeds.length === 0) {
+1 -5
View File
@@ -21,11 +21,7 @@ export async function getViewerSwarmRepostedPostIds(
const originalPostIds = Array.from(new Set(targets.map((target) => target.originalPostId)));
const rows = await db.query.userSwarmReposts.findMany({
where: and(
eq(userSwarmReposts.userId, viewerId),
inArray(userSwarmReposts.nodeDomain, domains),
inArray(userSwarmReposts.originalPostId, originalPostIds),
),
where: { AND: [{ userId: viewerId }, { nodeDomain: { in: domains } }, { originalPostId: { in: originalPostIds } }] },
});
const rowKeys = new Set(rows.map((row) => `${row.nodeDomain}:${row.originalPostId}`));
+1 -1
View File
@@ -141,7 +141,7 @@ export async function verifyUserInteraction(
// Try to get cached user
const fullHandle = `${userHandle}@${normalizedDomain}`;
let user = await db?.query.users.findFirst({
where: eq(users.handle, fullHandle),
where: { handle: fullHandle },
});
let publicKey: string | null = null;
+1 -4
View File
@@ -21,10 +21,7 @@ export async function upsertRemoteUser(profile: RemoteProfile): Promise<void> {
try {
// Check if user already exists
const existing = await db.query.users.findFirst({
where: or(
eq(users.did, profile.did),
eq(users.handle, profile.handle),
),
where: { OR: [{ did: profile.did }, { handle: profile.handle }] },
});
if (existing) {