UNPKG

ownfiles

Version:

A library to manage files in a Solid User's Pod

182 lines (164 loc) 5.5 kB
import url from 'url'; import mime from 'mime'; import { Namespace } from 'rdflib'; import ns from 'solid-namespace'; import FileClient from './fileClient'; import { Quad_Subject } from 'rdflib/lib/tf-types'; const typeNamespaceUrl = 'http://www.w3.org/ns/iana/media-types/'; const types = Namespace(typeNamespaceUrl); export interface CreateOptions { name: string; contents: any[] | Blob | string; contentType: string; headers?: Headers | Record<string, string>; } export type ExtendedResponseType = Response & { responseText: string; req?: Quad_Subject; size: number; error: string; }; export const create = function( this: FileClient, resourceAddress: string, options: Partial<CreateOptions> = {}, ) { if (!resourceAddress) { throw new Error('Please specify the location for the new resource.'); } else if (url.parse(resourceAddress).protocol !== 'https:') { throw new Error( 'Please specify a valid location for the new resource.', ); } const paths = resourceAddress.split('/'); if (!options.name) { if (paths[paths.length - 1] !== '') { options.name = paths[paths.length - 1]; paths.pop(); return this.createFile(paths.join('/') + '/', options); } else { options.name = paths[paths.length - 2]; paths.pop(); paths.pop(); return this.createFolder(paths.join('/') + '/', options); } } else if (resourceAddress.endsWith('/')) { paths.pop(); paths.pop(); return this.createFolder(paths.join('/') + '/', options); } else { paths.pop(); return this.createFile(paths.join('/') + '/', options); } }; export const createFolder = async function( this: FileClient, folderAddress: string, options?: Partial<CreateOptions>, ) { const request = { method: 'POST', headers: { Slug: options?.name ?? 'Untitled Folder', Link: '<http://www.w3.org/ns/ldp#BasicContainer>; rel="type"', 'Content-Type': 'text/turtle', }, }; const res = (await this.fetcher._fetch( folderAddress, request, )) as ExtendedResponseType; const location = res.headers.get('Location'); if (location && res.status < 304) { const parsedUrl = url.parse(folderAddress); const rootUrl = `${parsedUrl.protocol}//${parsedUrl.host}`; await this.addToIndex( { url: rootUrl + location, types: [ns().ldp('Container')] }, { force: true }, ); } return res; }; export const createFile = async function( this: FileClient, fileAddress: string, options: Partial<CreateOptions> = {}, ): Promise<Response> { const stringContent = options.contents as string; const blobContent = options.contents as Blob; const anyContent = options.contents as any[]; const body = stringContent ?? blobContent ?? bodyFromContent(anyContent); if (options.name) { options.contentType = options.contentType ?? mime.getType(options.name) ?? 'text/turtle'; const fileExtension = (options.contentType === 'image/jpeg' || options.contentType === 'application/octet-stream') && options.name && options.name.split('.')[1] === 'jpg' ? 'jpg' : mime.getExtension(options.contentType); fileAddress = `${fileAddress}${ options.name.split('.')[0] }.${fileExtension}`; } const request = { contentType: options.contentType, data: body, }; const res = await this.fetcher.webOperation('PUT', fileAddress, request); const location = res.headers.get('Location') ?? url.parse(fileAddress).pathname; if (location && res.status < 300) { const parsedUrl = url.parse(fileAddress); const rootUrl = `${parsedUrl.protocol}//${parsedUrl.host}`; await this.addToIndex({ url: rootUrl + location, types: [ types(options.contentType ?? 'text/plain' + '#Resource'), ns().ldp('Resource'), ], }); } return await res; }; export const createIfNotExist = function( this: FileClient, resourceAddress: string, options: Partial<CreateOptions> = { headers: {} }, ): Promise<Response | undefined> { return this.fetcher ._fetch(resourceAddress, { method: 'HEAD', headers: options.headers }) .then((res: Response) => { if (res.status === 200) { return; } else { return this.create(resourceAddress, options); } }) .catch((err) => { if (err.response.status === 404) return this.create(resourceAddress, options); }); }; function bodyFromContent(content: any[] | string | undefined) { if (content) { if (Array.isArray(content)) { if ( content.every((el) => { return el.constructor.name === 'Statement'; }) ) { let bodyString = ''; content.forEach((st) => { bodyString += st.toNT() + '\n'; }); return bodyString; } } else { return content; } } else { return ''; } }