UNPKG

@inrupt/solid-client

Version:

Make your web apps work with Solid Pods.

206 lines (195 loc) • 8 kB
// 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. // import type { SolidDataset, UrlString, WebId, WithServerResourceInfo, } from ".."; import { asIri, getIriAll, getSolidDataset, getThing, getThingAll } from ".."; import { foaf, pim, rdfs } from "../constants"; import { getSourceIri } from "../resource/resource"; export type ProfileAll<T extends SolidDataset & WithServerResourceInfo> = { webIdProfile: T; altProfileAll: Array<SolidDataset & WithServerResourceInfo>; }; /** * List all the alternative profiles IRI found in a given WebID profile. * * Note that some of these profiles may be private, and you may not have access to * the resulting resource. * * @param webId The WebID of the user's whose alternative profiles you are discovering. * @param webIdProfile The WebID profile obtained dereferencing the provided WebID. * @returns A list of URLs of the user's alternative profiles. * @since 1.20.0 */ export function getAltProfileUrlAllFrom( webId: WebId, webIdProfile: SolidDataset, ): UrlString[] { const webIdThing = getThing(webIdProfile, webId); const altProfileUrlAll = getThingAll(webIdProfile) .filter((thing) => getIriAll(thing, foaf.primaryTopic).length > 0) .map(asIri) .concat(webIdThing ? getIriAll(webIdThing, rdfs.seeAlso) : []) .concat(webIdThing ? getIriAll(webIdThing, foaf.isPrimaryTopicOf) : []) .filter((profileIri) => profileIri !== getSourceIri(webIdProfile)); // Deduplicate the results. return Array.from(new Set(altProfileUrlAll)); } /** * Get all the Profile Resources discoverable from a WebID Profile. * * A WebID Profile may be any RDF resource on the Web, it doesn't have * to be a Solid resource. That is why, in order to expose a Solid-enabled part * of their profile, some WebID profiles link to one or more Extended Profile Resources, * which may are Solid resources. A WebID resource should be public, so `getProfileAll` will * issue an unauthenticated request to the WebID, and only use the provided * authenticated `fetch` (if any) to access extended profile documents. * * @param webId WebID of the agent you want the profile of. * @param options Optional parameter * - `options.webIdProfile`: The data retrieved when looking up the WebID. This * will be fetched if not provided. * - `options.fetch`: An alternative `fetch` function to make the HTTP request, * compatible with the browser-native [fetch API](https://developer.mozilla.org/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters). * @returns Promise resolving to an array of [[SolidDataset]], each corresponding * to a personal profile document discoverable from the WebID Profile Document. * If none are found, the WebID profile document itself is returned. * @since 1.16.0 */ export async function getProfileAll< T extends SolidDataset & WithServerResourceInfo, >( webId: WebId, options?: { fetch?: typeof fetch; webIdProfile?: T; }, ): Promise<ProfileAll<T>>; export async function getProfileAll( webId: WebId, options?: { fetch?: typeof fetch; webIdProfile: undefined }, ): Promise<ProfileAll<SolidDataset & WithServerResourceInfo>>; export async function getProfileAll< T extends SolidDataset & WithServerResourceInfo, >( webId: WebId, options?: { fetch?: typeof fetch; webIdProfile?: T; }, ): Promise<ProfileAll<T | (SolidDataset & WithServerResourceInfo)>> { const authFetch = options?.fetch ?? fetch; const webIdProfile = options?.webIdProfile ?? // This should always use an unauthenticated fetch. (await getSolidDataset(webId)); const altProfileAll = ( await Promise.allSettled( getAltProfileUrlAllFrom(webId, webIdProfile).map((uniqueProfileIri) => getSolidDataset(uniqueProfileIri, { fetch: authFetch }), ), ) ) // Ignore the alternative profiles lookup which failed. .filter( (result): result is PromiseFulfilledResult<T> => result.status === "fulfilled", ) .map((successfulResult) => successfulResult.value); return { webIdProfile, altProfileAll, }; } /** * Discover the Pods an agent advertises for in their profile resources. Both the * agent's WebID and alternative profiles are fetched. Note that this function will * only return URLs of Pods linked to using the `pim:storage`, i.e. a triple * looking like <myWebid, pim:storage, myPodUrl> should appear in the profile * resources. * * @param webId The WebID of the agent whose Pods should be discovered * @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/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters). * @returns a Promise resolving to an array containing the URLs of all the Pods * linked from the agent's profile resource using the `pim:storage` predicate. * @since 1.18.0 */ export async function getPodUrlAll( webId: WebId, options?: { fetch?: typeof fetch }, ): Promise<UrlString[]> { const profiles = await getProfileAll(webId, options); return getPodUrlAllFrom(profiles, webId); } /** * Discover the Pods advertised for in the provided profile resources. Note that * this function will only return URLs of Pods linked to using the `pim:storage` * predicate, i.e. a triple looking like <myWebid, pim:storage, myPodUrl> * should appear in the profile resources. * * @param profiles The profile resources in which the Pods should be discovered * @param webId The WebID of the agent whose Pods should be discovered * @returns An array containing the URLs of all the Pods linked from the agent's * profile resource using the `pim:storage` predicate. * @since 1.18.0 */ export function getPodUrlAllFrom( profiles: ProfileAll<SolidDataset & WithServerResourceInfo>, webId: WebId, ): UrlString[] { const result: Set<string> = new Set(); [profiles.webIdProfile, ...profiles.altProfileAll].forEach( (profileResource) => { const webIdThing = getThing(profileResource, webId); if (webIdThing !== null) { getIriAll(webIdThing, pim.storage).forEach((podIri) => result.add(podIri), ); } }, ); return Array.from(result); } /** * Get the WebID Profile document dataset. * * @example * ``` * const webId = "https://example.org/people/me"; * const profile = await getWebIdDataset(webId); * const podRoot = getPodUrlAllFrom({ webIdProfile: profile, altProfileAll: [] }, webId); * const profileThing = getThing(profile, webId); * const name = getStringNoLocale(profileThing, FOAF.name); * ``` * * @param webId The WebID of the agent whose WebID Profile dataset is to be fetched. * @returns a SolidDataset for the WebID Profile document. * @since 1.24.0 */ export async function getWebIdDataset( webId: WebId, ): Promise<ReturnType<typeof getSolidDataset>> { return getSolidDataset(webId); }