/**
 * Boot-time backstop for the MCP pre-signed asset upload flow.
 *
 * Pre-signed PUT URLs land bytes under `pending/{assetId}/{filename}`.
 * Finalize promotes them to canonical keys + deletes pending. Two cases
 * leave bytes orphaned in `pending/`:
 *   - agent presigns but never PUTs (URL expires, blob never existed)
 *   - agent PUTs but never finalizes (CopyObject + delete-pending skipped)
 *
 * The bucket's lifecycle rule (`pending/` TTL 24h) is the only mechanism
 * bounding storage cost for these. This check runs once per workspace per
 * boot, confirms the rule exists, and emits a structured WARN if missing.
 * It does NOT crash boot — operators get a loud reminder instead. See
 * docs/r2-lifecycle.md for the dashboard steps.
 *
 * Auto-fix is intentionally NOT attempted: the R2 IAM token used by the
 * server typically lacks `s3:PutBucketLifecycleConfiguration` (which would
 * let any compromised deploy disable orphan cleanup). One-shot operator
 * action per bucket is the right boundary.
 */
import { log } from '../utils/log.js';
const PENDING_PREFIX = 'pending/';
const MAX_TTL_DAYS = 1;
export async function checkAssetLifecycleRule(wm) {
    // The check uses the first available graph as a lens onto the workspace's
    // asset config (every graph shares the same AssetService instance under
    // the hood, so any one will do). When the workspace has no folders yet
    // (fresh init), there's nothing to check — skip silently.
    let assetService;
    for (const repoName of wm.getRepoNames()) {
        try {
            const graph = wm.getGraph(repoName);
            assetService = graph.getAssetService();
            if (assetService)
                break;
        }
        catch { /* keep looking */ }
    }
    if (!assetService)
        return;
    // Only R2 has lifecycle; local FS has nothing to check.
    if (assetService.getStorage() !== 'r2')
        return;
    let rules;
    try {
        rules = await assetService.getBucketLifecycle();
    }
    catch (err) {
        // Permission-denied, R2 outage, network error at boot — degrade. The
        // alternative (crash boot) would be a worse failure mode: a transient
        // R2 hiccup shouldn't prevent the workspace from serving.
        log.warn('[asset-lifecycle] could not verify pending/ lifecycle rule — continuing', {
            event: 'asset-lifecycle-check-failed',
            err: err instanceof Error ? err.message : String(err),
        });
        return;
    }
    const ok = (rules ?? []).some(rule => {
        // Disabled rules don't fire; an operator who turned the rule off
        // expects orphans to NOT be reaped. Codex P2 (2026-05-28).
        if (!rule.enabled)
            return false;
        if (rule.expirationDays === undefined)
            return false;
        if (rule.expirationDays > MAX_TTL_DAYS)
            return false;
        // Empty/missing prefix matches everything → also covers pending/.
        if (!rule.prefix)
            return true;
        return PENDING_PREFIX.startsWith(rule.prefix);
    });
    if (!ok) {
        log.warn('[asset-lifecycle] WARNING: no R2 lifecycle rule covers prefix=pending/ with TTL≤24h', {
            event: 'asset-lifecycle-missing',
            hint: 'Set the rule via the Cloudflare R2 dashboard. See docs/r2-lifecycle.md.',
            rulesFound: rules?.length ?? 0,
        });
    }
}
//# sourceMappingURL=asset-lifecycle-check.js.map