import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
//#region extensions/crypto/src/services/webhook-routes.ts
/**
* Webhook Routes — registry that maps URL paths to event triggers.
*
* Each route defines:
* - A URL path (e.g. "/github", "/stripe", "/monitor")
* - A source label for display
* - An optional HMAC secret for signature verification
* - An optional plan name to trigger when the webhook fires
* - Enable/disable lifecycle
*
* Routes persist to ~/.openclawnch/webhooks/routes.json.
*/
function isValidRouteName(name) {
	return /^[a-z][a-z0-9\-]{1,40}$/.test(name);
}
function isValidPath(path) {
	return /^\/[a-z0-9\-_\/]{0,100}$/.test(path);
}
var WebhookRouteRegistry = class {
	routes = /* @__PURE__ */ new Map();
	stateDir;
	constructor(opts) {
		this.stateDir = opts?.stateDir ?? join(process.env.HOME ?? "", ".openclawnch", "webhooks");
		this.loadState();
	}
	/** Create a new webhook route. */
	create(params) {
		if (!isValidRouteName(params.name)) throw new WebhookRouteError(`Invalid route name "${params.name}". Must be 2-40 chars, lowercase alphanumeric + hyphens.`);
		if (!isValidPath(params.path)) throw new WebhookRouteError(`Invalid path "${params.path}". Must start with / and contain only lowercase alphanumeric, hyphens, underscores.`);
		if (this.getByName(params.name)) throw new WebhookRouteError(`A route named "${params.name}" already exists.`);
		if (this.getByPath(params.path)) throw new WebhookRouteError(`A route with path "${params.path}" already exists.`);
		const id = `wh_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
		const now = Date.now();
		const route = {
			id,
			name: params.name,
			path: params.path,
			source: params.source,
			secret: params.secret ?? "",
			triggerPlan: params.triggerPlan ?? "",
			enabled: true,
			createdBy: params.createdBy,
			hitCount: 0,
			createdAt: now,
			updatedAt: now
		};
		this.routes.set(id, route);
		this.saveState();
		return route;
	}
	update(id, updates) {
		const route = this.routes.get(id);
		if (!route) return null;
		Object.assign(route, updates, { updatedAt: Date.now() });
		this.saveState();
		return route;
	}
	delete(id) {
		const existed = this.routes.delete(id);
		if (existed) this.saveState();
		return existed;
	}
	get(id) {
		return this.routes.get(id) ?? null;
	}
	getByName(name) {
		for (const r of this.routes.values()) if (r.name === name) return r;
		return null;
	}
	getByPath(path) {
		for (const r of this.routes.values()) if (r.path === path) return r;
		return null;
	}
	list(opts) {
		let all = Array.from(this.routes.values());
		if (opts?.enabled !== void 0) all = all.filter((r) => r.enabled === opts.enabled);
		return all.sort((a, b) => b.updatedAt - a.updatedAt);
	}
	recordHit(id) {
		const route = this.routes.get(id);
		if (route) {
			route.hitCount += 1;
			route.updatedAt = Date.now();
			this.saveState();
		}
	}
	clear() {
		this.routes.clear();
	}
	loadState() {
		try {
			const filePath = join(this.stateDir, "routes.json");
			if (existsSync(filePath)) {
				const data = JSON.parse(readFileSync(filePath, "utf8"));
				for (const r of data) this.routes.set(r.id, r);
			}
		} catch {}
	}
	saveState() {
		try {
			if (!existsSync(this.stateDir)) mkdirSync(this.stateDir, { recursive: true });
			writeFileSync(join(this.stateDir, "routes.json"), JSON.stringify(Array.from(this.routes.values()), null, 2), "utf8");
		} catch {}
	}
};
var WebhookRouteError = class extends Error {
	constructor(message) {
		super(message);
		this.name = "WebhookRouteError";
	}
};
let instance = null;
function getWebhookRoutes(opts) {
	if (!instance) instance = new WebhookRouteRegistry(opts);
	return instance;
}
function resetWebhookRoutes() {
	instance?.clear();
	instance = null;
}
//#endregion
export { WebhookRouteError, WebhookRouteRegistry, getWebhookRoutes, resetWebhookRoutes };

//# sourceMappingURL=webhook-routes.mjs.map