mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-09-26 21:41:48 +02:00
refactor(upload)!: take headers, method and body via an options object (#3613)
`upload(url, path, onProgress, { headers, method })` and
`download(url, path, onProgress, { headers, body })` replace the
positional optional arguments.
`headers` accepts both a `Map` and a plain object; previously a `Map`
was silently serialized as an empty object.
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
"upload-js": major
|
||||||
|
---
|
||||||
|
|
||||||
|
**Breaking:** `upload` and `download` now take an `options` object as their last argument instead of positional `headers`, `method` and `body` arguments:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
await upload(url, filePath, onProgress, { headers, method: HttpMethod.Put })
|
||||||
|
await download(url, filePath, onProgress, { headers, body })
|
||||||
|
```
|
||||||
|
|
||||||
|
`headers` accepts both a `Map` and a plain object. Previously a `Map` was silently serialized as an empty object.
|
||||||
@@ -162,9 +162,7 @@
|
|||||||
percentage: progress.total > 0 ? Math.round((progress.progressTotal / progress.total) * 100) : 0
|
percentage: progress.total > 0 ? Math.round((progress.progressTotal / progress.total) * 100) : 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Map([
|
{ headers: { 'User-Agent': 'Tauri Upload Plugin Demo' } }
|
||||||
['User-Agent', 'Tauri Upload Plugin Demo']
|
|
||||||
])
|
|
||||||
)
|
)
|
||||||
|
|
||||||
downloadResult = {
|
downloadResult = {
|
||||||
@@ -211,10 +209,10 @@
|
|||||||
percentage: progress.total > 0 ? Math.round((progress.progressTotal / progress.total) * 100) : 0
|
percentage: progress.total > 0 ? Math.round((progress.progressTotal / progress.total) * 100) : 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Map([
|
{
|
||||||
['User-Agent', 'Tauri Upload Plugin Demo']
|
headers: { 'User-Agent': 'Tauri Upload Plugin Demo' },
|
||||||
]),
|
method: uploadMethod
|
||||||
uploadMethod
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
uploadResult = {
|
uploadResult = {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ upload(
|
|||||||
'./path/to/my/file.txt',
|
'./path/to/my/file.txt',
|
||||||
({ progressTotal, total }) =>
|
({ progressTotal, total }) =>
|
||||||
console.log(`Uploaded ${progressTotal} of ${total} bytes`), // a callback that will be called with the upload progress
|
console.log(`Uploaded ${progressTotal} of ${total} bytes`), // a callback that will be called with the upload progress
|
||||||
{ 'Content-Type': 'text/plain' } // optional headers to send with the request
|
{ headers: { 'Content-Type': 'text/plain' } } // optional headers to send with the request
|
||||||
)
|
)
|
||||||
|
|
||||||
// Upload with specific HTTP method
|
// Upload with specific HTTP method
|
||||||
@@ -77,8 +77,10 @@ upload(
|
|||||||
'./path/to/my/file.txt',
|
'./path/to/my/file.txt',
|
||||||
({ progressTotal, total }) =>
|
({ progressTotal, total }) =>
|
||||||
console.log(`Uploaded ${progressTotal} of ${total} bytes`),
|
console.log(`Uploaded ${progressTotal} of ${total} bytes`),
|
||||||
{ 'Content-Type': 'text/plain' },
|
{
|
||||||
HttpMethod.Put // Use HttpMethod enum - supports POST, PUT, PATCH
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
|
method: HttpMethod.Put // Use HttpMethod enum - supports POST, PUT, PATCH
|
||||||
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -90,7 +92,7 @@ download(
|
|||||||
'./path/to/save/my/file.txt',
|
'./path/to/save/my/file.txt',
|
||||||
({ progressTotal, total }) =>
|
({ progressTotal, total }) =>
|
||||||
console.log(`Downloaded ${progressTotal} of ${total} bytes`), // a callback that will be called with the download progress
|
console.log(`Downloaded ${progressTotal} of ${total} bytes`), // a callback that will be called with the download progress
|
||||||
{ 'Content-Type': 'text/plain' } // optional headers to send with the request
|
{ headers: { 'Content-Type': 'text/plain' } } // optional headers to send with the request
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_PLUGIN_UPLOAD__=function(t){"use strict";function e(t,e,n,s){if("function"==typeof e?t!==e||!s:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?s:"a"===n?s.call(t):s?s.value:e.get(t)}function n(t,e,n,s,i){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return e.set(t,n),n}var s,i,o,a;"function"==typeof SuppressedError&&SuppressedError;const r="__TAURI_TO_IPC_KEY__";class h{constructor(t){s.set(this,void 0),i.set(this,0),o.set(this,[]),a.set(this,void 0),n(this,s,t||(()=>{})),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}(t=>{const r=t.index;if("end"in t)return void(r==e(this,i,"f")?this.cleanupCallback():n(this,a,r));const h=t.message;if(r==e(this,i,"f")){for(e(this,s,"f").call(this,h),n(this,i,e(this,i,"f")+1);e(this,i,"f")in e(this,o,"f");){const t=e(this,o,"f")[e(this,i,"f")];e(this,s,"f").call(this,t),delete e(this,o,"f")[e(this,i,"f")],n(this,i,e(this,i,"f")+1)}e(this,i,"f")===e(this,a,"f")&&this.cleanupCallback()}else e(this,o,"f")[r]=h})}cleanupCallback(){window.__TAURI_INTERNALS__.unregisterCallback(this.id)}set onmessage(t){n(this,s,t)}get onmessage(){return e(this,s,"f")}[(s=new WeakMap,i=new WeakMap,o=new WeakMap,a=new WeakMap,r)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[r]()}}async function d(t,e={},n){return window.__TAURI_INTERNALS__.invoke(t,e,n)}var c;return t.HttpMethod=void 0,(c=t.HttpMethod||(t.HttpMethod={})).Post="POST",c.Put="PUT",c.Patch="PATCH",t.download=async function(t,e,n,s,i){const o=new Uint32Array(1);window.crypto.getRandomValues(o);const a=o[0],r=new h;n&&(r.onmessage=n),await d("plugin:upload|download",{id:a,url:t,filePath:e,headers:s??{},onProgress:r,body:i})},t.upload=async function(e,n,s,i,o){const a=new Uint32Array(1);window.crypto.getRandomValues(a);const r=a[0],c=new h;return s&&(c.onmessage=s),await d("plugin:upload|upload",{id:r,url:e,filePath:n,headers:i??{},method:o??t.HttpMethod.Post,onProgress:c})},t}({});Object.defineProperty(window.__TAURI__,"upload",{value:__TAURI_PLUGIN_UPLOAD__})}
|
if("__TAURI__"in window){var __TAURI_PLUGIN_UPLOAD__=function(t){"use strict";function e(t,e,n,s){if("function"==typeof e?t!==e||!s:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?s:"a"===n?s.call(t):s?s.value:e.get(t)}function n(t,e,n,s,i){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return e.set(t,n),n}var s,i,o,a;"function"==typeof SuppressedError&&SuppressedError;const r="__TAURI_TO_IPC_KEY__";class d{constructor(t){s.set(this,void 0),i.set(this,0),o.set(this,[]),a.set(this,void 0),n(this,s,t||(()=>{})),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}(t=>{const r=t.index;if("end"in t)return void(r==e(this,i,"f")?this.cleanupCallback():n(this,a,r));const d=t.message;if(r==e(this,i,"f")){for(e(this,s,"f").call(this,d),n(this,i,e(this,i,"f")+1);e(this,i,"f")in e(this,o,"f");){const t=e(this,o,"f")[e(this,i,"f")];e(this,s,"f").call(this,t),delete e(this,o,"f")[e(this,i,"f")],n(this,i,e(this,i,"f")+1)}e(this,i,"f")===e(this,a,"f")&&this.cleanupCallback()}else e(this,o,"f")[r]=d})}cleanupCallback(){window.__TAURI_INTERNALS__.unregisterCallback(this.id)}set onmessage(t){n(this,s,t)}get onmessage(){return e(this,s,"f")}[(s=new WeakMap,i=new WeakMap,o=new WeakMap,a=new WeakMap,r)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[r]()}}async function h(t,e={},n){return window.__TAURI_INTERNALS__.invoke(t,e,n)}var c;function _(t){return t instanceof Map?Object.fromEntries(t):t??{}}return t.HttpMethod=void 0,(c=t.HttpMethod||(t.HttpMethod={})).Post="POST",c.Put="PUT",c.Patch="PATCH",t.download=async function(t,e,n,s){const i=new Uint32Array(1);window.crypto.getRandomValues(i);const o=i[0],a=new d;n&&(a.onmessage=n),await h("plugin:upload|download",{id:o,url:t,filePath:e,headers:_(s?.headers),onProgress:a,body:s?.body})},t.upload=async function(e,n,s,i){const o=new Uint32Array(1);window.crypto.getRandomValues(o);const a=o[0],r=new d;return s&&(r.onmessage=s),await h("plugin:upload|upload",{id:a,url:e,filePath:n,headers:_(i?.headers),method:i?.method??t.HttpMethod.Post,onProgress:r})},t}({});Object.defineProperty(window.__TAURI__,"upload",{value:__TAURI_PLUGIN_UPLOAD__})}
|
||||||
|
|||||||
@@ -19,13 +19,57 @@ enum HttpMethod {
|
|||||||
Patch = 'PATCH'
|
Patch = 'PATCH'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for {@linkcode upload}.
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface UploadOptions {
|
||||||
|
/** Headers to send with the request. */
|
||||||
|
headers?: Map<string, string> | Record<string, string>
|
||||||
|
/** HTTP method to use. Defaults to {@linkcode HttpMethod.Post}. */
|
||||||
|
method?: HttpMethod
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for {@linkcode download}.
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
interface DownloadOptions {
|
||||||
|
/** Headers to send with the request. */
|
||||||
|
headers?: Map<string, string> | Record<string, string>
|
||||||
|
/** Body to send with the request. When set, a `POST` request is made instead of a `GET`. */
|
||||||
|
body?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function headersToRust(
|
||||||
|
headers: Map<string, string> | Record<string, string> | undefined
|
||||||
|
): Record<string, string> {
|
||||||
|
return headers instanceof Map ? Object.fromEntries(headers) : (headers ?? {})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload a file to the given url.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* import { upload, HttpMethod } from '@tauri-apps/plugin-upload';
|
||||||
|
* const response = await upload(
|
||||||
|
* 'https://example.com/file-upload',
|
||||||
|
* './path/to/my/file.txt',
|
||||||
|
* ({ progressTotal, total }) => console.log(`Uploaded ${progressTotal} of ${total} bytes`),
|
||||||
|
* { headers: { 'Content-Type': 'text/plain' }, method: HttpMethod.Put }
|
||||||
|
* );
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @returns The response body.
|
||||||
|
*/
|
||||||
async function upload(
|
async function upload(
|
||||||
url: string,
|
url: string,
|
||||||
filePath: string,
|
filePath: string,
|
||||||
progressHandler?: ProgressHandler,
|
progressHandler?: ProgressHandler,
|
||||||
// TODO: V3 - Combine headers and methods into one `options` object
|
options?: UploadOptions
|
||||||
headers?: Map<string, string>,
|
|
||||||
method?: HttpMethod
|
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const ids = new Uint32Array(1)
|
const ids = new Uint32Array(1)
|
||||||
window.crypto.getRandomValues(ids)
|
window.crypto.getRandomValues(ids)
|
||||||
@@ -40,22 +84,34 @@ async function upload(
|
|||||||
id,
|
id,
|
||||||
url,
|
url,
|
||||||
filePath,
|
filePath,
|
||||||
headers: headers ?? {},
|
headers: headersToRust(options?.headers),
|
||||||
method: method ?? HttpMethod.Post,
|
method: options?.method ?? HttpMethod.Post,
|
||||||
onProgress
|
onProgress
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Download file from given url.
|
/**
|
||||||
///
|
* Download a file from the given url.
|
||||||
/// Note that `filePath` currently must include the file name.
|
*
|
||||||
/// Furthermore the progress events will report a total length of 0 if the server did not sent a `Content-Length` header or if the file is compressed.
|
* Note that `filePath` currently must include the file name.
|
||||||
|
* Furthermore the progress events will report a total length of 0 if the server did not sent a `Content-Length` header or if the file is compressed.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* import { download } from '@tauri-apps/plugin-upload';
|
||||||
|
* await download(
|
||||||
|
* 'https://example.com/file-download-link',
|
||||||
|
* './path/to/save/my/file.txt',
|
||||||
|
* ({ progressTotal, total }) => console.log(`Downloaded ${progressTotal} of ${total} bytes`),
|
||||||
|
* { headers: { 'Content-Type': 'text/plain' } }
|
||||||
|
* );
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
async function download(
|
async function download(
|
||||||
url: string,
|
url: string,
|
||||||
filePath: string,
|
filePath: string,
|
||||||
progressHandler?: ProgressHandler,
|
progressHandler?: ProgressHandler,
|
||||||
headers?: Map<string, string>,
|
options?: DownloadOptions
|
||||||
body?: string
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const ids = new Uint32Array(1)
|
const ids = new Uint32Array(1)
|
||||||
window.crypto.getRandomValues(ids)
|
window.crypto.getRandomValues(ids)
|
||||||
@@ -70,10 +126,11 @@ async function download(
|
|||||||
id,
|
id,
|
||||||
url,
|
url,
|
||||||
filePath,
|
filePath,
|
||||||
headers: headers ?? {},
|
headers: headersToRust(options?.headers),
|
||||||
onProgress,
|
onProgress,
|
||||||
body
|
body: options?.body
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export { download, upload, HttpMethod }
|
export { download, upload, HttpMethod }
|
||||||
|
export type { ProgressPayload, ProgressHandler, UploadOptions, DownloadOptions }
|
||||||
|
|||||||
Reference in New Issue
Block a user