import * as ipldDagCbor from '@ipld/dag-cbor';
import * as ipldDagJson from '@ipld/dag-json';
import * as dagPb from '@ipld/dag-pb';
import toBuffer from 'it-to-buffer';
import * as json from 'multiformats/codecs/json';
import * as raw from 'multiformats/codecs/raw';
import { identity } from 'multiformats/hashes/identity';
import { CODEC_CBOR } from "../constants.js";
import { getContentTypesForCid, MEDIA_TYPE_CBOR, MEDIA_TYPE_DAG_CBOR, MEDIA_TYPE_DAG_JSON, MEDIA_TYPE_JSON } from "../utils/content-types.js";
import { convertOutput } from "../utils/convert-output.js";
import { getContentDispositionFilename } from "../utils/get-content-disposition-filename.js";
import { notAcceptableResponse, okResponse, partialContentResponse } from "../utils/responses.js";
import { BasePlugin } from "./plugin-base.js";
/**
 * Handles loading JSON and CBOR content
 */
export class IpldPlugin extends BasePlugin {
    id = 'ipld-plugin';
    codes = [
        CODEC_CBOR,
        ipldDagCbor.code,
        ipldDagJson.code,
        json.code,
        raw.code,
        dagPb.code,
        identity.code
    ];
    canHandle({ terminalElement, accept }) {
        const supportsCid = this.codes.includes(terminalElement.cid.code);
        const supportsAccept = accept.length === 0 ||
            accept.some(header => header.contentType.mediaType === MEDIA_TYPE_CBOR ||
                header.contentType.mediaType === MEDIA_TYPE_DAG_CBOR ||
                header.contentType.mediaType === MEDIA_TYPE_JSON ||
                header.contentType.mediaType === MEDIA_TYPE_DAG_JSON);
        return supportsCid && supportsAccept;
    }
    async handle(context) {
        const { url, resource, accept, ipfsRoots, terminalElement, blockstore, requestedMimeTypes } = context;
        this.log.trace('fetching %c%s', terminalElement.cid, url.pathname);
        let block = await toBuffer(blockstore.get(terminalElement.cid, context));
        let contentType;
        try {
            // maybe convert output to different binary format
            const result = convertOutput(terminalElement.cid, block, accept);
            block = result.output;
            contentType = result.contentType;
        }
        catch (err) {
            this.log.error('could not decode object from block - %e', err);
            return notAcceptableResponse(resource, requestedMimeTypes, getContentTypesForCid(terminalElement.cid));
        }
        const headers = {
            'content-length': `${block.byteLength}`,
            'content-type': contentType.mediaType,
            'content-disposition': `${url.searchParams.get('download') === 'true' ? 'attachment' : contentType.disposition}; ${getContentDispositionFilename(url.searchParams.get('filename') ?? `${terminalElement.cid}${contentType.extension}`)}`,
            'x-ipfs-roots': ipfsRoots.map(cid => cid.toV1()).join(','),
            'x-content-type-options': 'nosniff',
            'accept-ranges': 'bytes'
        };
        if (context.range != null) {
            return partialContentResponse(resource, async function* (offset, length) {
                yield block.subarray(offset, offset + length);
            }, context.range, block.byteLength, {
                redirected: context.redirected,
                headers
            });
        }
        return okResponse(resource, block, {
            redirected: context.redirected,
            headers
        });
    }
}
//# sourceMappingURL=plugin-handle-ipld.js.map