/**
 * Shared server-side helpers for the artifact-asset capability flow: compute the
 * allowlist of assets a bundle references that actually live in a repo, and mint
 * a token from it. Used by the mint endpoint, PNG/PDF render, and HTML export so
 * they can't drift on what an artifact is allowed to load.
 */
import { findArtifactAssetRefs } from '../core/artifact-asset-urls.js';
import { hasRepoAccess, isWorkspaceWide } from '../services/access-control.js';
import { signArtifactAssetToken, artifactAssetKey, ARTIFACT_ASSET_TOKEN_TTL_SECONDS, } from '../services/artifact-asset-token.js';
/** Concatenate a bundle's text file contents (where asset refs live). */
function bundleText(bundle) {
    const files = bundle?.files && typeof bundle.files === 'object' ? bundle.files : {};
    return Object.values(files).filter((v) => typeof v === 'string').join('\n');
}
/**
 * The asset refs in arbitrary artifact text (a bundle's file contents, or a raw
 * entity body — even a historical version) that resolve to an indexed asset the
 * artifact's `repo` is allowed to load: one OWNED BY `repo`, OR one in a
 * workspace-wide shared store (`workspace_wide` — e.g. the `workspace-assets`
 * folder, shared across every repo and readable by every member). Other
 * cross-repo / filename-mismatch / unknown refs are dropped — fail-closed.
 * Carries `size` for export byte-budgeting. The regex only matches
 * `/api/assets/...` URLs, so scanning a raw JSON body (refs inside escaped
 * strings) or a frontmatter+body file is safe.
 */
export function authorizedArtifactAssetsFromText(workspaceManager, repo, text) {
    const refs = findArtifactAssetRefs(text);
    if (refs.length === 0)
        return []; // nothing to authorize — skip the index lookup
    const index = workspaceManager.getAssetIndex();
    const out = [];
    for (const ref of refs) {
        const row = index.get(ref.assetId);
        // Owned by this repo, or a workspace-wide shared asset (loadable from any
        // artifact — every member already has read access to the shared store).
        const repoAllowed = !!row && (row.repo === repo || isWorkspaceWide(row.repo, workspaceManager));
        if (row && repoAllowed && row.filename === ref.filename) {
            out.push({ ...ref, size: row.size ?? null });
        }
    }
    return out;
}
/** Bundle-typed convenience over {@link authorizedArtifactAssetsFromText} (used
 *  by export, which always has the validated live bundle). */
export function authorizedArtifactAssets(workspaceManager, repo, bundle) {
    return authorizedArtifactAssetsFromText(workspaceManager, repo, bundleText(bundle));
}
/**
 * D11b export model: every asset ref in the bundle the EXPORTING USER can read
 * — the artifact's repo, workspace-wide stores, and any other repo the user has
 * access to (authz per asset via the same `hasRepoAccess` the serve route
 * uses). Wider than {@link authorizedArtifactAssets} (the render/canvas token
 * scope) by design: the self-contained HTML export transfers custody to the
 * authenticated exporter — the same trust model as a screenshot. Refs that
 * don't resolve (unknown id / filename mismatch / no access) are NOT returned;
 * the export renders them as labeled placeholders. Carries the owning `repo`
 * so the caller downloads through the right graph.
 */
export function exporterAccessibleArtifactAssets(workspaceManager, authService, user, bundle) {
    const refs = findArtifactAssetRefs(bundleText(bundle));
    if (refs.length === 0)
        return [];
    const index = workspaceManager.getAssetIndex();
    const out = [];
    for (const ref of refs) {
        const row = index.get(ref.assetId);
        if (!row || row.filename !== ref.filename)
            continue;
        if (!hasRepoAccess(user, row.repo, workspaceManager, authService))
            continue;
        out.push({ ...ref, size: row.size ?? null, repo: row.repo });
    }
    return out;
}
/** Allowlist of `assetId/filename` keys a bundle authorizes (for tests + callers
 *  that want the keys without minting). */
export function artifactAssetAllowlist(workspaceManager, repo, bundle) {
    return authorizedArtifactAssets(workspaceManager, repo, bundle).map((a) => artifactAssetKey(a.assetId, a.filename));
}
/** Mint a 12h artifact-scoped token from artifact text. `userId` is re-checked
 *  at serve time, so a token never outlives the user's access. The allowlist is
 *  derived from THIS text (live body or a specific historical commit), so a
 *  preview token authorizes exactly the previewed version's assets. */
export function mintArtifactAssetTokenForText(workspaceManager, authService, repo, artifactId, text, userId) {
    const assets = authorizedArtifactAssetsFromText(workspaceManager, repo, text)
        .map((a) => artifactAssetKey(a.assetId, a.filename));
    const token = signArtifactAssetToken({ purpose: 'artifact-asset', repo, artifactId, assets, userId }, authService.getJwtSecret());
    return { token, expiresInSeconds: ARTIFACT_ASSET_TOKEN_TTL_SECONDS };
}
export function mintArtifactAssetTokenForBundle(workspaceManager, authService, repo, artifactId, bundle, userId) {
    return mintArtifactAssetTokenForText(workspaceManager, authService, repo, artifactId, bundleText(bundle), userId);
}
//# sourceMappingURL=artifact-asset-mint.js.map