@helia/verified-fetch
Version:
A fetch-like API for obtaining verified & trustless IPFS content on the web
176 lines • 5.44 kB
JavaScript
function setField(response, name, value) {
Object.defineProperty(response, name, {
enumerable: true,
configurable: false,
set: () => { },
get: () => value
});
}
function setType(response, value) {
setField(response, 'type', value);
}
function setUrl(response, value) {
setField(response, 'url', value);
}
function setRedirected(response) {
setField(response, 'redirected', true);
}
export function okResponse(url, body, init) {
const response = new Response(body, {
...(init ?? {}),
status: 200,
statusText: 'OK'
});
if (init?.redirected === true) {
setRedirected(response);
}
setType(response, 'basic');
setUrl(response, url);
return response;
}
export function badGatewayResponse(url, body, init) {
const response = new Response(body, {
...(init ?? {}),
status: 502,
statusText: 'Bad Gateway'
});
setType(response, 'basic');
setUrl(response, url);
return response;
}
export function notSupportedResponse(url, body, init) {
const response = new Response(body, {
...(init ?? {}),
status: 501,
statusText: 'Not Implemented'
});
response.headers.set('X-Content-Type-Options', 'nosniff'); // see https://specs.ipfs.tech/http-gateways/path-gateway/#x-content-type-options-response-header
setType(response, 'basic');
setUrl(response, url);
return response;
}
export function notAcceptableResponse(url, body, init) {
const response = new Response(body, {
...(init ?? {}),
status: 406,
statusText: 'Not Acceptable'
});
setType(response, 'basic');
setUrl(response, url);
return response;
}
export function notFoundResponse(url, body, init) {
const response = new Response(body, {
...(init ?? {}),
status: 404,
statusText: 'Not Found'
});
setType(response, 'basic');
setUrl(response, url);
return response;
}
function isArrayOfErrors(body) {
return Array.isArray(body) && body.every(e => e instanceof Error);
}
export function badRequestResponse(url, errors, init) {
// stacktrace of the single error, or the stacktrace of the last error in the array
let stack;
let convertedErrors;
if (isArrayOfErrors(errors)) {
stack = errors[errors.length - 1].stack;
convertedErrors = errors.map(e => ({ message: e.message, stack: e.stack ?? '' }));
}
else if (errors instanceof Error) {
stack = errors.stack;
convertedErrors = [{ message: errors.message, stack: errors.stack ?? '' }];
}
const bodyJson = JSON.stringify({
stack,
errors: convertedErrors
});
const response = new Response(bodyJson, {
status: 400,
statusText: 'Bad Request',
...(init ?? {}),
headers: {
...(init?.headers ?? {}),
'Content-Type': 'application/json'
}
});
setType(response, 'basic');
setUrl(response, url);
return response;
}
export function movedPermanentlyResponse(url, location, init) {
const response = new Response(null, {
...(init ?? {}),
status: 301,
statusText: 'Moved Permanently',
headers: {
...(init?.headers ?? {}),
location
}
});
setType(response, 'basic');
setUrl(response, url);
return response;
}
export function okRangeResponse(url, body, { byteRangeContext, log }, init) {
if (!byteRangeContext.isRangeRequest) {
return okResponse(url, body, init);
}
if (!byteRangeContext.isValidRangeRequest) {
return badRangeResponse(url, body, init);
}
let response;
try {
// Create headers object with any initial headers from init
const headers = new Headers(init?.headers);
// For multipart responses, we should use the content-type header instead of content-range
const multipartContentType = byteRangeContext.getContentType();
if (multipartContentType != null) {
headers.set('content-type', multipartContentType);
}
else {
if (byteRangeContext.isMultiRangeRequest) {
headers.set('content-type', 'multipart/byteranges');
}
else {
headers.set('content-range', byteRangeContext.contentRangeHeaderValue);
}
}
response = new Response(body, {
...(init ?? {}),
status: 206,
statusText: 'Partial Content',
headers
});
}
catch (e) {
log?.error('failed to create range response', e);
return badRangeResponse(url, body, init);
}
if (init?.redirected === true) {
setRedirected(response);
}
setType(response, 'basic');
setUrl(response, url);
return response;
}
/**
* We likely need to catch errors handled by upstream helia libraries if range-request throws an error. Some examples:
* - The range is out of bounds
* - The range is invalid
* - The range is not supported for the given type
*/
export function badRangeResponse(url, body, init) {
const response = new Response(body, {
...(init ?? {}),
status: 416,
statusText: 'Requested Range Not Satisfiable'
});
setType(response, 'basic');
setUrl(response, url);
return response;
}
//# sourceMappingURL=responses.js.map