import { t as RelationalDbProcessor } from "./processors-B9mjV_SJ.mjs";
//#region processors/graph-indexer/migrations.ts
async function up(db) {
	await db.schema.createTable("graph_nodes").addColumn("id", "varchar(255)", (col) => col.primaryKey()).addColumn("document_id", "varchar(255)", (col) => col.notNull().unique()).addColumn("title", "varchar(1024)").addColumn("description", "text").addColumn("note_type", "varchar(255)").addColumn("status", "varchar(50)").addColumn("updated_at", "varchar(50)", (col) => col.notNull()).ifNotExists().execute();
	await db.schema.createTable("graph_edges").addColumn("id", "varchar(255)", (col) => col.primaryKey()).addColumn("source_document_id", "varchar(255)", (col) => col.notNull()).addColumn("target_document_id", "varchar(255)", (col) => col.notNull()).addColumn("link_type", "varchar(100)").addColumn("target_title", "varchar(1024)").addColumn("updated_at", "varchar(50)", (col) => col.notNull()).ifNotExists().execute();
	await db.schema.createIndex("idx_graph_edges_source").on("graph_edges").column("source_document_id").ifNotExists().execute();
	await db.schema.createIndex("idx_graph_edges_target").on("graph_edges").column("target_document_id").ifNotExists().execute();
	await db.schema.createIndex("idx_graph_nodes_status").on("graph_nodes").column("status").ifNotExists().execute();
	for (const col of [
		"content",
		"author",
		"source_origin",
		"created_at"
	]) try {
		await db.schema.alterTable("graph_nodes").addColumn(col, col === "content" ? "text" : "varchar(1024)").execute();
	} catch {}
	await db.schema.createTable("graph_topics").addColumn("id", "varchar(255)", (col) => col.primaryKey()).addColumn("document_id", "varchar(255)", (col) => col.notNull()).addColumn("name", "varchar(512)", (col) => col.notNull()).addColumn("updated_at", "varchar(50)", (col) => col.notNull()).ifNotExists().execute();
	await db.schema.createIndex("idx_graph_topics_document_id").on("graph_topics").column("document_id").ifNotExists().execute();
	await db.schema.createIndex("idx_graph_topics_name").on("graph_topics").column("name").ifNotExists().execute();
	await db.schema.createTable("graph_operations").addColumn("id", "varchar(255)", (col) => col.primaryKey()).addColumn("document_id", "varchar(255)", (col) => col.notNull()).addColumn("operation_type", "varchar(100)", (col) => col.notNull()).addColumn("timestamp", "varchar(50)", (col) => col.notNull()).addColumn("index", "integer", (col) => col.notNull()).addColumn("scope", "varchar(20)", (col) => col.notNull()).addColumn("summary", "text").addColumn("input_json", "text").addColumn("signer_address", "varchar(255)").addColumn("signer_app", "varchar(255)").ifNotExists().execute();
	await db.schema.createIndex("idx_graph_ops_doc").on("graph_operations").column("document_id").ifNotExists().execute();
	await db.schema.createIndex("idx_graph_ops_timestamp").on("graph_operations").column("timestamp").ifNotExists().execute();
	await db.schema.createIndex("idx_graph_ops_type").on("graph_operations").column("operation_type").ifNotExists().execute();
	for (const col of ["signer_address", "signer_app"]) try {
		await db.schema.alterTable("graph_operations").addColumn(col, "varchar(255)").execute();
	} catch {}
}
//#endregion
//#region processors/graph-indexer/embedding-store.ts
let db = null;
/**
* Lazy-load PGlite at first use. The shared Powerhouse build config
* marks `@electric-sql/pglite` as `nodeNeverBundle`, so the bare import
* survives into our dist. On vetra's HTTP CDN deployments where
* transitive runtime deps aren't installed, a top-level import would
* crash module load — and module load is required for our processor +
* subgraph to register at all. Deferring the import to first call keeps
* registration unaffected.
*/
async function getEmbeddingDb() {
	if (db) return db;
	const { PGlite } = await import("@electric-sql/pglite");
	const { vector } = await import("./vector-BvjvFSml.mjs");
	db = new PGlite({
		dataDir: typeof window !== "undefined" ? "idb://knowledge-embeddings" : "memory://knowledge-embeddings",
		extensions: { vector }
	});
	await db.exec("CREATE EXTENSION IF NOT EXISTS vector;");
	await db.exec(`
    CREATE TABLE IF NOT EXISTS note_embeddings (
      document_id VARCHAR(255) PRIMARY KEY,
      embedding vector(384) NOT NULL,
      updated_at VARCHAR(50) NOT NULL
    );
  `);
	await db.exec(`
    CREATE INDEX IF NOT EXISTS idx_note_embeddings_hnsw
    ON note_embeddings USING hnsw (embedding vector_cosine_ops);
  `);
	return db;
}
async function upsertEmbedding(documentId, embedding) {
	const store = await getEmbeddingDb();
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const embeddingStr = `[${embedding.join(",")}]`;
	await store.query(`INSERT INTO note_embeddings (document_id, embedding, updated_at)
     VALUES ($1, $2::vector, $3)
     ON CONFLICT (document_id) DO UPDATE SET
       embedding = EXCLUDED.embedding,
       updated_at = EXCLUDED.updated_at`, [
		documentId,
		embeddingStr,
		now
	]);
}
async function searchSimilar(queryEmbedding, limit = 10) {
	const store = await getEmbeddingDb();
	const embeddingStr = `[${queryEmbedding.join(",")}]`;
	return ((await store.query(`SELECT document_id, embedding <=> $1::vector AS distance
     FROM note_embeddings
     ORDER BY distance ASC
     LIMIT $2`, [embeddingStr, limit])).rows ?? []).map((row) => ({
		documentId: row.document_id,
		similarity: 1 - row.distance
	}));
}
async function getEmbedding(documentId) {
	const result = await (await getEmbeddingDb()).query(`SELECT embedding::text FROM note_embeddings WHERE document_id = $1`, [documentId]);
	if (!result.rows || result.rows.length === 0) return null;
	const raw = result.rows[0].embedding;
	return JSON.parse(raw);
}
async function deleteEmbedding(documentId) {
	await (await getEmbeddingDb()).query(`DELETE FROM note_embeddings WHERE document_id = $1`, [documentId]);
}
async function listEmbeddedDocumentIds() {
	return ((await (await getEmbeddingDb()).query(`SELECT document_id FROM note_embeddings`)).rows ?? []).map((row) => row.document_id);
}
//#endregion
//#region processors/graph-indexer/factory.ts
const graphIndexerFactoryBuilder = (module) => async (driveHeader) => {
	const namespace = GraphIndexerProcessor.getNamespace(driveHeader.id);
	console.log(`[GraphIndexer] Factory called for drive: ${driveHeader.id}, namespace: ${namespace}`);
	const store = await module.relationalDb.createNamespace(namespace);
	const filter = {
		branch: ["main"],
		documentId: ["*"],
		documentType: [
			"bai/knowledge-note",
			"bai/moc",
			"powerhouse/document-drive"
		],
		scope: ["global", "document"]
	};
	const processor = new GraphIndexerProcessor(namespace, filter, store);
	await processor.initAndUpgrade();
	console.log(`[GraphIndexer] Processor created for drive: ${driveHeader.id}`);
	return [{
		processor,
		filter,
		startFrom: "beginning"
	}];
};
//#endregion
//#region processors/graph-indexer/index.ts
function summarizeOperation(type, input) {
	switch (type) {
		case "SET_TITLE": return `Title changed to "${truncate(input.title)}"`;
		case "SET_DESCRIPTION": return `Description updated`;
		case "SET_CONTENT": return `Content updated (${typeof input.content === "string" ? input.content.length : 0} chars)`;
		case "SET_NOTE_TYPE": return `Type set to ${String(input.noteType)}`;
		case "SET_STATUS": return `Status changed to ${String(input.status)}`;
		case "ADD_LINK": return `Linked to "${truncate(input.targetTitle)}" (${s(input.linkType, "RELATES_TO")})`;
		case "REMOVE_LINK": return `Removed link ${s(input.id)}`;
		case "UPDATE_LINK_TYPE": return `Link type changed to ${s(input.linkType)}`;
		case "ADD_TOPIC": return `Added topic #${s(input.name)}`;
		case "REMOVE_TOPIC": return `Removed topic`;
		case "SET_PROVENANCE": return `Provenance set: ${s(input.author, "unknown")}, ${s(input.sourceOrigin)}`;
		case "SUBMIT_FOR_REVIEW": return `Submitted for review`;
		case "APPROVE_NOTE": return `Approved by ${s(input.actor, "unknown")}`;
		case "REJECT_NOTE": return `Rejected: ${truncate(input.comment)}`;
		case "ARCHIVE_NOTE": return `Archived`;
		case "RESTORE_NOTE": return `Restored from archive`;
		case "SET_METADATA_FIELD": return `Metadata: ${String(input.field)} = ${truncate(input.value)}`;
		default: return type;
	}
}
/** Safely stringify an unknown value with optional fallback */
function s(val, fallback = "") {
	if (val == null) return fallback;
	if (typeof val === "string") return val;
	if (typeof val === "number" || typeof val === "boolean") return String(val);
	return fallback;
}
function truncate(val, max = 60) {
	const str = s(val);
	return str.length > max ? str.slice(0, max) + "..." : str;
}
var GraphIndexerProcessor = class extends RelationalDbProcessor {
	static getNamespace(driveId) {
		return super.getNamespace(driveId);
	}
	async initAndUpgrade() {
		await up(this.relationalDb);
	}
	async onOperations(operations) {
		if (operations.length === 0) return;
		const lastByDocument = /* @__PURE__ */ new Map();
		for (const entry of operations) {
			const { operation, context } = entry;
			const documentId = context.documentId;
			if (operation.action.type === "ADD_RELATIONSHIP") {
				await this.applyAddRelationship(operation.action.input);
				continue;
			}
			if (operation.action.type === "REMOVE_RELATIONSHIP") {
				await this.applyRemoveRelationship(operation.action.input);
				continue;
			}
			if (context.documentType === "powerhouse/document-drive" && operation.action.type === "DELETE_NODE") {
				const deleteInput = operation.action.input;
				await this.deleteNode(deleteInput.id);
				lastByDocument.delete(deleteInput.id);
				continue;
			}
			if (context.documentType !== "bai/knowledge-note" && context.documentType !== "bai/moc") continue;
			try {
				const input = operation.action.input;
				const signer = operation.action.context?.signer;
				await this.relationalDb.insertInto("graph_operations").values({
					id: `${documentId}-${operation.index}`,
					document_id: documentId,
					operation_type: operation.action.type,
					timestamp: operation.timestampUtcMs ?? (/* @__PURE__ */ new Date()).toISOString(),
					index: operation.index,
					scope: context.scope ?? "global",
					summary: summarizeOperation(operation.action.type, input),
					input_json: JSON.stringify(input),
					signer_address: signer?.user?.address || null,
					signer_app: signer?.app?.name || null
				}).onConflict((oc) => oc.column("id").doNothing()).execute();
			} catch {}
			if (context.resultingState) lastByDocument.set(documentId, entry);
		}
		for (const [documentId, entry] of lastByDocument) try {
			const stateJson = entry.context.resultingState;
			if (!stateJson) continue;
			const parsed = JSON.parse(stateJson);
			const global = parsed.global ?? parsed;
			const now = (/* @__PURE__ */ new Date()).toISOString();
			const isMoc = entry.context.documentType === "bai/moc";
			const provenance = global.provenance;
			const noteType = isMoc ? `MOC (${s(global.tier, "TOPIC")})` : global.noteType ?? null;
			const content = isMoc ? global.orientation ?? null : global.content ?? null;
			const status = isMoc ? "MOC" : global.status ?? "DRAFT";
			await this.relationalDb.insertInto("graph_nodes").values({
				id: documentId,
				document_id: documentId,
				title: global.title ?? null,
				description: global.description ?? null,
				note_type: noteType,
				status,
				content,
				author: provenance?.author ?? null,
				source_origin: provenance?.sourceOrigin ?? null,
				created_at: global.createdAt ?? provenance?.createdAt ?? null,
				updated_at: now
			}).onConflict((oc) => oc.column("document_id").doUpdateSet({
				title: global.title ?? null,
				description: global.description ?? null,
				note_type: noteType,
				status,
				content,
				author: provenance?.author ?? null,
				source_origin: provenance?.sourceOrigin ?? null,
				created_at: global.createdAt ?? provenance?.createdAt ?? null,
				updated_at: now
			})).execute();
			await this.relationalDb.deleteFrom("graph_topics").where("document_id", "=", documentId).execute();
			const topics = global.topics ?? [];
			if (topics.length > 0) await this.relationalDb.insertInto("graph_topics").values(topics.map((topic, idx) => {
				const name = typeof topic === "string" ? topic : topic.name ?? "";
				return {
					id: `${documentId}-topic-${idx}`,
					document_id: documentId,
					name,
					updated_at: now
				};
			})).execute();
		} catch (err) {
			console.error(`[GraphIndexer] Error reconciling document ${documentId}:`, err);
		}
	}
	/**
	* Mirror an ADD_RELATIONSHIP event into `graph_edges`. Backfills the
	* `target_title` from `graph_nodes` if the target is already indexed;
	* otherwise leaves it null (rendering falls back to the target's slug
	* until the target's own state reconciles).
	*/
	async applyAddRelationship(input) {
		if (!input.sourceId || !input.targetId) return;
		const now = (/* @__PURE__ */ new Date()).toISOString();
		const relType = input.relationshipType ?? null;
		const edgeId = `${input.sourceId}-${input.targetId}-${relType ?? "_"}`;
		let targetTitle = null;
		try {
			targetTitle = (await this.relationalDb.selectFrom("graph_nodes").where("document_id", "=", input.targetId).select("title").executeTakeFirst())?.title ?? null;
		} catch {}
		await this.relationalDb.insertInto("graph_edges").values({
			id: edgeId,
			source_document_id: input.sourceId,
			target_document_id: input.targetId,
			link_type: relType,
			target_title: targetTitle,
			updated_at: now
		}).onConflict((oc) => oc.column("id").doUpdateSet({
			link_type: (eb) => eb.ref("excluded.link_type"),
			target_title: (eb) => eb.ref("excluded.target_title"),
			updated_at: (eb) => eb.ref("excluded.updated_at")
		})).execute();
	}
	async applyRemoveRelationship(input) {
		if (!input.sourceId || !input.targetId) return;
		const relType = input.relationshipType ?? null;
		const edgeId = `${input.sourceId}-${input.targetId}-${relType ?? "_"}`;
		await this.relationalDb.deleteFrom("graph_edges").where("id", "=", edgeId).execute();
	}
	async onDisconnect() {}
	async deleteNode(documentId) {
		try {
			await this.relationalDb.deleteFrom("graph_topics").where("document_id", "=", documentId).execute();
			await this.relationalDb.deleteFrom("graph_edges").where((eb) => eb.or([eb("source_document_id", "=", documentId), eb("target_document_id", "=", documentId)])).execute();
			await this.relationalDb.deleteFrom("graph_nodes").where("document_id", "=", documentId).execute();
			await this.relationalDb.deleteFrom("graph_operations").where("document_id", "=", documentId).execute();
			deleteEmbedding(documentId).catch((err) => console.warn(`[GraphIndexer] Embedding delete failed for ${documentId}:`, err));
			console.log(`[GraphIndexer] Deleted node ${documentId}`);
		} catch (err) {
			console.error(`[GraphIndexer] Error deleting node ${documentId}:`, err);
		}
	}
};
//#endregion
export { searchSimilar as a, listEmbeddedDocumentIds as i, graphIndexerFactoryBuilder as n, upsertEmbedding as o, getEmbedding as r, GraphIndexerProcessor as t };

//# sourceMappingURL=graph-indexer-BKUdEn8U.mjs.map