UNPKG

4.96 kBPlain TextView Raw
1/**
2 * Copyright 2020 Inrupt Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal in
6 * the Software without restriction, including without limitation the rights to use,
7 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8 * Software, and to permit persons to whom the Software is furnished to do so,
9 * subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22import { fetch } from "./fetcher";
23import { Headers } from "cross-fetch";
24import { unstable_UploadRequestInit } from "./interfaces";
25
26type FetchFileOptions = {
27 fetch: typeof window.fetch;
28 init: unstable_UploadRequestInit;
29};
30
31const defaultFetchFileOptions = {
32 fetch: fetch,
33};
34
35const RESERVED_HEADERS = ["Slug", "If-None-Match", "Content-Type"];
36
37/**
38 * Some of the headers must be set by the library, rather than directly.
39 */
40function containsReserved(header: Headers): boolean {
41 return RESERVED_HEADERS.some((reserved) => header.has(reserved));
42}
43
44/**
45 * Fetches a file at a given URL, and returns it as a blob of data.
46 *
47 * Please note that this function is still experimental: its API can change in non-major releases.
48 *
49 * @param url The URL of the fetched file
50 * @param options Fetching options: a custom fetcher and/or headers.
51 */
52export async function unstable_fetchFile(
53 input: RequestInfo,
54 options: Partial<FetchFileOptions> = defaultFetchFileOptions
55): Promise<Response> {
56 const config = {
57 ...defaultFetchFileOptions,
58 ...options,
59 };
60 return config.fetch(input, config.init);
61}
62
63/**
64 * Deletes a file at a given URL
65 *
66 * Please note that this function is still experimental: its API can change in non-major releases.
67 *
68 * @param input The URL of the file to delete
69 */
70export async function unstable_deleteFile(
71 input: RequestInfo,
72 options: Partial<FetchFileOptions> = defaultFetchFileOptions
73): Promise<Response> {
74 const config = {
75 ...defaultFetchFileOptions,
76 ...options,
77 };
78 return config.fetch(input, {
79 ...config.init,
80 method: "DELETE",
81 });
82}
83
84type SaveFileOptions = FetchFileOptions & {
85 slug?: string;
86};
87
88/**
89 * Saves a file in a folder at a given URL. The server will return the final
90 * filename (which may or may not be the given `slug`), it will return it in
91 * the response's Location header.
92 *
93 * @param folderUrl The URL of the folder where the new file is saved
94 * @param file The file to be written
95 * @param options Additional parameters for file creation (e.g. a slug)
96 */
97export async function unstable_saveFileInContainer(
98 folderUrl: RequestInfo,
99 file: Blob,
100 options: Partial<SaveFileOptions> = defaultFetchFileOptions
101): Promise<Response> {
102 return writeFile(folderUrl, file, "POST", options);
103}
104
105/**
106 * Saves a file at a given URL, erasing any previous content.
107 *
108 * @param fileUrl The URL where the file is saved
109 * @param file The file to be written
110 * @param options Additional parameters for file creation (e.g. a slug)
111 */
112export async function unstable_overwriteFile(
113 fileUrl: RequestInfo,
114 file: Blob,
115 options: Partial<FetchFileOptions> = defaultFetchFileOptions
116): Promise<Response> {
117 return writeFile(fileUrl, file, "PUT", options);
118}
119
120/**
121 * Internal function that performs the actual write HTTP query, either POST
122 * or PUT depending on the use case.
123 *
124 * @param fileUrl The URL where the file is saved
125 * @param file The file to be written
126 * @param method The HTTP method
127 * @param options Additional parameters for file creation (e.g. a slug)
128 */
129async function writeFile(
130 targetUrl: RequestInfo,
131 file: Blob,
132 method: "PUT" | "POST",
133 options: Partial<SaveFileOptions>
134): Promise<Response> {
135 const config = {
136 ...defaultFetchFileOptions,
137 ...options,
138 };
139 const headers = new Headers(config.init?.headers ?? {});
140 if (containsReserved(headers)) {
141 throw new Error(
142 `No reserved header (${RESERVED_HEADERS.join(
143 ", "
144 )}) should be set in the optional RequestInit.`
145 );
146 }
147
148 // If a slug is in the parameters, set the request headers accordingly
149 if (config.slug !== undefined) {
150 headers.append("Slug", config.slug);
151 }
152 headers.append("Content-Type", file.type);
153
154 return await config.fetch(targetUrl, {
155 ...config.init,
156 headers,
157 method,
158 body: file,
159 });
160}