/**
 * Webhook subscription persistence helpers for CLI.3.
 *
 * Split out of `webhooks.ts` (file-size budget). Three concerns:
 *
 *   1. `readWebhooksFile` / `writeWebhooksFile` — load + atomically rewrite
 *      `~/.opensquid/webhooks.yaml`. Schema mirrors the SCHED.1 runtime
 *      loader (`src/runtime/webhook_subscriptions.ts`) so anything the CLI
 *      writes is consumable by the daemon without a second migration step.
 *      Atomic write via `tmp + rename` (now delegated to `state_io.ts`).
 *   2. `genSecret` — `crypto.randomBytes(32).toString('hex')` returning the
 *      64-char lowercase hex string used for HMAC-SHA256 signing keys. The
 *      caller embeds it via a `literal:<hex>` URI so the runtime's secret
 *      resolver (post-`literalBackend()` registration) reads it back.
 *   3. `defaultWebhooksPath` / `defaultWebhookPort` — `~/.opensquid/
 *      webhooks.yaml` + `8765` matching `DEFAULT_WEBHOOK_PORT` in
 *      `src/runtime/daemon.ts`.
 *
 * Secret-handling discipline (audit-critical):
 *
 *   We DO NOT use the runtime `SecretResolver` here. The CLI is the
 *   authoritative writer of inline-literal subscriptions; introducing
 *   resolver indirection in the CLI write path would couple the CLI to
 *   the resolver's env-var / 1Password backends and break the locked
 *   "write new secret to webhooks.yaml BEFORE invalidating old" atomic
 *   rotation contract. The `secret:` field is stored as the URI
 *   `literal:<64-hex>` directly — readers (CLI + daemon) get the hex by
 *   either stripping the `literal:` prefix (CLI) or routing through the
 *   resolver with `literalBackend()` registered (daemon, configured at
 *   setup time outside this task's scope).
 *
 * Imports from: node:crypto, ../../runtime/paths, ./state_io.
 * Imported by: src/setup/cli/webhooks.ts + src/setup/cli/webhooks_actions.ts.
 */
import { randomBytes } from 'node:crypto';
import { join } from 'node:path';
import { OPENSQUID_HOME } from '../../runtime/paths.js';
import { readKeyedYamlList, writeKeyedYamlList } from './state_io.js';
export const defaultWebhooksPath = () => join(OPENSQUID_HOME(), 'webhooks.yaml');
/** Mirrors `DEFAULT_WEBHOOK_PORT` in `src/runtime/daemon.ts`. */
export const defaultWebhookPort = () => 8765;
/** Generate a 64-char lowercase hex HMAC-SHA256 signing key (32 bytes). */
export function genSecret() {
    return randomBytes(32).toString('hex');
}
/** Compose the `literal:` URI the CLI persists into `secret:`. */
export function literalSecretUri(hex) {
    return `literal:${hex}`;
}
/** Strip a `literal:` prefix; returns the URI unchanged if not literal. */
export function unwrapLiteralSecret(uri) {
    if (uri.startsWith('literal:'))
        return { literal: true, value: uri.slice('literal:'.length) };
    return { literal: false, value: uri };
}
/** Canonical `http://localhost:<port>/webhook/<id>` URL — daemon route. */
export function webhookUrl(id, port) {
    return `http://localhost:${String(port)}/webhook/${id}`;
}
const isSubscriptionRecord = (v) => typeof v === 'object' && v !== null;
export async function readWebhooksFile(path) {
    return readKeyedYamlList(path, 'subscriptions', 'webhooks.yaml', isSubscriptionRecord);
}
/**
 * Atomic write — delegates to `writeKeyedYamlList` (T-SIC L9 byte-preserves
 * the `subscriptions: []\n` empty form). Callers MUST pass the FULL
 * desired subscription set; we never merge here because partial writes
 * risk dropping unrelated subscriptions on concurrent CLI invocations.
 */
export async function writeWebhooksFile(path, subscriptions) {
    return writeKeyedYamlList(path, 'subscriptions', subscriptions);
}
//# sourceMappingURL=webhooks_state.js.map