Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* RitualChain feedback source — auto-provisioned passive connector.
*
* One ritualchain source exists per deployment. Created on startup if absent.
* All new posts (including widget-submitted) are ingested automatically
* via the feedback_pipeline event hook on post.created.
Comment on lines +1 to +6
*/

import { db, eq, feedbackSources } from '@/lib/server/db'
import { sql } from 'drizzle-orm'
import { hashCode } from '@/lib/server/utils'
import { logger } from '@/lib/server/logger'

const log = logger.child({ component: 'ritualchain-source' })

/**
* Ensure the ritualchain feedback source exists.
* Uses an advisory lock to prevent duplicate sources from concurrent startups.
*/
export async function ensureRitualChainFeedbackSource(): Promise<void> {
await db.transaction(async (tx) => {
// Advisory lock scoped to this transaction prevents concurrent creation
await tx.execute(
sql`SELECT pg_advisory_xact_lock(${sql.raw(String(hashCode('ritualchain_feedback_source')))})`
)

const existing = await tx.query.feedbackSources.findFirst({
where: eq(feedbackSources.sourceType, 'ritualchain'),
columns: { id: true },
})

if (existing) {
log.debug({ source_id: existing.id }, 'ritualchain feedback source already exists')
return
}

const [created] = await tx
.insert(feedbackSources)
.values({
sourceType: 'ritualchain',
deliveryMode: 'passive',
name: 'RitualChain',
enabled: true,
config: {},
})
.returning({ id: feedbackSources.id })

log.info({ source_id: created.id }, 'created ritualchain feedback source')
})
}