UNPKG

@inrupt/solid-client

Version:

Make your web apps work with Solid Pods.

219 lines (216 loc) • 10.3 kB
import { ClientHttpError } from '@inrupt/solid-client-errors'; import { hasResourceInfo, hasServerResourceInfo, SolidClientError } from '../interfaces.mjs'; import { normalizeUrl, internal_toIriString } from '../interfaces.internal.mjs'; import { internal_isUnsuccessfulResponse, internal_isAuthenticationFailureResponse, internal_parseResourceInfo } from './resource.internal.mjs'; import { acp } from '../constants.mjs'; // Copyright Inrupt Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the // Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // This linter exception is introduced for legacy reasons. /** * Retrieve the information about a resource (e.g. access permissions) without * fetching the resource itself. * * @param url URL to fetch Resource metadata from. * @param options Optional parameter `options.fetch`: An alternative `fetch` function to make the HTTP request, compatible with the browser-native [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters). * @returns Promise resolving to the metadata describing the given Resource, or rejecting if fetching it failed. * @since 0.4.0 */ async function getResourceInfo(url, options) { var _a, _b; const response = await ((_a = options === null || options === void 0 ? void 0 : options.fetch) !== null && _a !== void 0 ? _a : fetch)(normalizeUrl(url), { method: "HEAD", }); return responseToResourceInfo(response, { ignoreAuthenticationErrors: (_b = options === null || options === void 0 ? void 0 : options.ignoreAuthenticationErrors) !== null && _b !== void 0 ? _b : false, }); } /** * Parse Solid metadata from a Response obtained by fetching a Resource from a Solid Pod, * * @param response A Fetch API Response. See {@link https://developer.mozilla.org/en-US/docs/Web/API/Response MDN}. * @returns Resource metadata readable by functions such as [[getSourceUrl]]. * @hidden This interface is not exposed yet until we've tried it out in practice. */ function responseToResourceInfo(response, options = { ignoreAuthenticationErrors: false }) { if (internal_isUnsuccessfulResponse(response) && (!internal_isAuthenticationFailureResponse(response) || !options.ignoreAuthenticationErrors)) { throw new FetchError(`Fetching the metadata of the Resource at [${response.url}] failed: [${response.status}] [${response.statusText}].`, response); } const resourceInfo = internal_parseResourceInfo(response); return { internal_resourceInfo: resourceInfo }; } /** * @param resource Resource for which to check whether it is a Container. * @returns Whether `resource` is a Container. */ function isContainer(resource) { const containerUrl = hasResourceInfo(resource) ? getSourceUrl(resource) : internal_toIriString(resource); return containerUrl.endsWith("/"); } /** * This function will tell you whether a given Resource contains raw data, or a SolidDataset. * * @param resource Resource for which to check whether it contains raw data. * @return Whether `resource` contains raw data. */ function isRawData(resource) { return resource.internal_resourceInfo.isRawData; } /** * @param resource Resource for which to determine the Content Type. * @returns The Content Type, if known, or null if not known. */ function getContentType(resource) { var _a; return (_a = resource.internal_resourceInfo.contentType) !== null && _a !== void 0 ? _a : null; } function getSourceUrl(resource) { if (hasResourceInfo(resource)) { return resource.internal_resourceInfo.sourceIri; } return null; } /** @hidden Alias of getSourceUrl for those who prefer to use IRI terminology. */ const getSourceIri = getSourceUrl; /** * Given a Resource that exposes information about the owner of the Pod it is in, returns the WebID of that owner. * * Data about the owner of the Pod is exposed when the following conditions hold: * - The Pod server supports exposing the Pod owner * - The current user is allowed to see who the Pod owner is. * * If one or more of those conditions are false, this function will return `null`. * * @param resource A Resource that contains information about the owner of the Pod it is in. * @returns The WebID of the owner of the Pod the Resource is in, if provided, or `null` if not. * @since 0.6.0 */ function getPodOwner(resource) { var _a; if (!hasServerResourceInfo(resource)) { return null; } const podOwners = (_a = getLinkedResourceUrlAll(resource)["http://www.w3.org/ns/solid/terms#podOwner"]) !== null && _a !== void 0 ? _a : []; return podOwners.length === 1 ? podOwners[0] : null; } /** * Given a WebID and a Resource that exposes information about the owner of the Pod it is in, returns whether the given WebID is the owner of the Pod. * * Data about the owner of the Pod is exposed when the following conditions hold: * - The Pod server supports exposing the Pod owner * - The current user is allowed to see who the Pod owner is. * * If one or more of those conditions are false, this function will return `null`. * * @param webId The WebID of which to check whether it is the Pod Owner's. * @param resource A Resource that contains information about the owner of the Pod it is in. * @returns Whether the given WebID is the Pod Owner's, if the Pod Owner is exposed, or `null` if it is not exposed. * @since 0.6.0 */ function isPodOwner(webId, resource) { const podOwner = getPodOwner(resource); if (typeof podOwner !== "string") { return null; } return podOwner === webId; } /** * Get the URLs of Resources linked to the given Resource. * * Solid servers can link Resources to each other. For example, in servers * implementing Web Access Control, Resources can have an Access Control List * Resource linked to it via the `acl` relation. * * @param resource A Resource fetched from a Solid Pod. * @returns The URLs of Resources linked to the given Resource, indexed by the key that links them. * @since 1.7.0 */ function getLinkedResourceUrlAll(resource) { return resource.internal_resourceInfo.linkedResources; } /** * Get what access the current user has to the given Resource. * * This function can tell you what access the current user has for the given * Resource, allowing you to e.g. determine that changes to it will be rejected * before attempting to do so. * Additionally, for servers adhering to the Web Access Control specification, * it will tell you what access unauthenticated users have to the given Resource. * * @param resource A Resource fetched from a Solid Pod. * @returns What access the current user and, if supported by the server, unauthenticated users have to the given Resource. * @since 1.7.0 */ function getEffectiveAccess(resource) { var _a, _b, _c, _d, _e, _f, _g; if (typeof resource.internal_resourceInfo.permissions === "object") { return { user: { read: resource.internal_resourceInfo.permissions.user.read, append: resource.internal_resourceInfo.permissions.user.append, write: resource.internal_resourceInfo.permissions.user.write, }, public: { read: resource.internal_resourceInfo.permissions.public.read, append: resource.internal_resourceInfo.permissions.public.append, write: resource.internal_resourceInfo.permissions.public.write, }, }; } const linkedResourceUrls = getLinkedResourceUrlAll(resource); return { user: { read: (_b = (_a = linkedResourceUrls[acp.allow]) === null || _a === void 0 ? void 0 : _a.includes(acp.Read)) !== null && _b !== void 0 ? _b : false, append: (_e = (((_c = linkedResourceUrls[acp.allow]) === null || _c === void 0 ? void 0 : _c.includes(acp.Append)) || ((_d = linkedResourceUrls[acp.allow]) === null || _d === void 0 ? void 0 : _d.includes(acp.Write)))) !== null && _e !== void 0 ? _e : false, write: (_g = (_f = linkedResourceUrls[acp.allow]) === null || _f === void 0 ? void 0 : _f.includes(acp.Write)) !== null && _g !== void 0 ? _g : false, }, }; } /** * Extends the regular JavaScript error object with access to the status code and status message. * @since 1.2.0 */ class FetchError extends SolidClientError { constructor(message, errorResponse, responseBody) { super(message); this.response = errorResponse; if (typeof responseBody === "string") { this.httpError = new ClientHttpError(errorResponse, responseBody, message); } else { // If no response body is provided, defaults are applied. this.httpError = new ClientHttpError(errorResponse, "", message); } } get statusCode() { return this.response.status; } get statusText() { return this.response.statusText; } get problemDetails() { return this.httpError.problemDetails; } } export { FetchError, getContentType, getEffectiveAccess, getLinkedResourceUrlAll, getPodOwner, getResourceInfo, getSourceIri, getSourceUrl, isContainer, isPodOwner, isRawData, responseToResourceInfo };