import * as drizzle from "drizzle-orm";
import { jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";
//#region src/settings-schema.ts
const settingsKv = pgTable("settings_kv", {
	key: text("key").primaryKey(),
	value: jsonb("value").notNull(),
	updatedAt: timestamp("updated_at", {
		withTimezone: true,
		precision: 3
	}).notNull().defaultNow()
});
const settingsSchema = { settingsKv };
//#endregion
//#region src/settings.ts
var SettingsValidationError = class extends Error {
	field;
	detail;
	name = "SettingsValidationError";
	constructor(field, detail) {
		super(`settings invalid: ${field} — ${detail}`);
		this.field = field;
		this.detail = detail;
	}
};
const SETTINGS_KEYS = {
	siteName: "site.name",
	siteUrl: "site.url",
	logo: "site.logo",
	homepage: "site.homepage",
	maintenance: "site.maintenance"
};
const MAX_KEY_LEN = 256;
const FORBIDDEN_KEYS = /* @__PURE__ */ new Set([
	"__proto__",
	"constructor",
	"prototype"
]);
function validateKey(key) {
	if (typeof key !== "string" || key.length === 0) throw new SettingsValidationError("key", "required");
	if (key.length > MAX_KEY_LEN) throw new SettingsValidationError("key", `exceeds ${MAX_KEY_LEN} chars`);
	if (FORBIDDEN_KEYS.has(key)) throw new SettingsValidationError("key", "reserved key not allowed");
}
function assertSerializable(value) {
	try {
		JSON.stringify(value);
	} catch {
		throw new SettingsValidationError("value", "not JSON-serializable");
	}
}
function tolerantRead(value) {
	if (value === null || value === void 0) return null;
	try {
		JSON.stringify(value);
		return value;
	} catch {
		return null;
	}
}
function settingsTableSql(table = "settings_kv") {
	return `
CREATE TABLE IF NOT EXISTS ${table} (
  key text PRIMARY KEY,
  value jsonb NOT NULL,
  updated_at timestamptz(3) NOT NULL DEFAULT NOW()
);
`.trim();
}
function createDbSettingsStore(db, _opts) {
	return {
		async get(key) {
			validateKey(key);
			const [row] = await db.select().from(settingsKv).where(drizzle.eq(settingsKv.key, key)).limit(1);
			if (!row) return null;
			return tolerantRead(row.value);
		},
		async getMany(keys) {
			for (const key of keys) validateKey(key);
			if (keys.length === 0) return {};
			const rows = await db.select().from(settingsKv).where(drizzle.inArray(settingsKv.key, keys));
			const out = Object.create(null);
			for (const row of rows) {
				const val = tolerantRead(row.value);
				if (val !== null) out[row.key] = val;
			}
			return out;
		},
		async set(key, value) {
			validateKey(key);
			assertSerializable(value);
			await db.insert(settingsKv).values({
				key,
				value
			}).onConflictDoUpdate({
				target: settingsKv.key,
				set: {
					value,
					updatedAt: /* @__PURE__ */ new Date()
				}
			});
		},
		async all() {
			const rows = await db.select().from(settingsKv);
			const out = Object.create(null);
			for (const row of rows) {
				const val = tolerantRead(row.value);
				if (val !== null) out[row.key] = val;
			}
			return out;
		},
		async remove(key) {
			validateKey(key);
			await db.delete(settingsKv).where(drizzle.eq(settingsKv.key, key));
		}
	};
}
//#endregion
export { SETTINGS_KEYS, SettingsValidationError, createDbSettingsStore, settingsKv, settingsSchema, settingsTableSql };
