mirror of
https://git.v0l.io/Kieran/void.cat.git
synced 2025-04-11 04:39:03 +02:00
Add headers to request
This commit is contained in:
parent
1babc8e4e0
commit
e0652dfbb8
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "@void-cat/api",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.4",
|
||||
"description": "void.cat API package",
|
||||
"main": "dist/index.js",
|
||||
"main": "dist/lib.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"repository": "https://git.v0l.io/Kieran/void.cat",
|
||||
"author": "Kieran",
|
||||
|
@ -52,9 +52,9 @@ export class VoidApi {
|
||||
*/
|
||||
getUploader(
|
||||
file: File | Blob,
|
||||
stateChange: StateChangeHandler,
|
||||
progress: ProgressHandler,
|
||||
proxyChallenge: ProxyChallengeHandler,
|
||||
stateChange?: StateChangeHandler,
|
||||
progress?: ProgressHandler,
|
||||
proxyChallenge?: ProxyChallengeHandler,
|
||||
chunkSize?: number
|
||||
): VoidUploader {
|
||||
if (StreamUploader.canUse()) {
|
||||
|
@ -27,15 +27,15 @@ export class StreamUploader extends VoidUploader {
|
||||
return this.#encrypt?.getKey()
|
||||
}
|
||||
|
||||
async upload(): Promise<VoidUploadResult> {
|
||||
this.onStateChange(UploadState.Hashing);
|
||||
async upload(headers?: HeadersInit): Promise<VoidUploadResult> {
|
||||
this.onStateChange?.(UploadState.Hashing);
|
||||
const hash = await this.digest(this.file);
|
||||
let offset = 0;
|
||||
|
||||
const DefaultChunkSize = 1024 * 1024;
|
||||
const rsBase = new ReadableStream({
|
||||
start: async () => {
|
||||
this.onStateChange(UploadState.Uploading);
|
||||
this.onStateChange?.(UploadState.Uploading);
|
||||
},
|
||||
pull: async (controller) => {
|
||||
const chunk = await this.readChunk(offset, controller.desiredSize ?? DefaultChunkSize);
|
||||
@ -43,7 +43,7 @@ export class StreamUploader extends VoidUploader {
|
||||
controller.close();
|
||||
return;
|
||||
}
|
||||
this.onProgress(offset + chunk.byteLength);
|
||||
this.onProgress?.(offset + chunk.byteLength);
|
||||
offset += chunk.byteLength
|
||||
controller.enqueue(chunk);
|
||||
},
|
||||
@ -55,23 +55,26 @@ export class StreamUploader extends VoidUploader {
|
||||
highWaterMark: DefaultChunkSize
|
||||
});
|
||||
|
||||
const headers = {
|
||||
const reqHeaders = {
|
||||
"Content-Type": "application/octet-stream",
|
||||
"V-Content-Type": !this.file.type ? "application/octet-stream" : this.file.type,
|
||||
"V-Filename": "name" in this.file ? this.file.name : "",
|
||||
"V-Full-Digest": hash
|
||||
"V-Full-Digest": hash,
|
||||
} as Record<string, string>;
|
||||
if (this.#encrypt) {
|
||||
headers["V-EncryptionParams"] = JSON.stringify(this.#encrypt!.getParams());
|
||||
reqHeaders["V-EncryptionParams"] = JSON.stringify(this.#encrypt!.getParams());
|
||||
}
|
||||
if (this.auth) {
|
||||
headers["Authorization"] = `Bearer ${this.auth}`;
|
||||
reqHeaders["Authorization"] = `Bearer ${this.auth}`;
|
||||
}
|
||||
const req = await fetch(`${this.uri}/upload`, {
|
||||
method: "POST",
|
||||
mode: "cors",
|
||||
body: this.#encrypt ? rsBase.pipeThrough(this.#encrypt!.getEncryptionTransform()) : rsBase,
|
||||
headers,
|
||||
headers: {
|
||||
...reqHeaders,
|
||||
...headers
|
||||
},
|
||||
// @ts-ignore New stream spec
|
||||
duplex: 'half'
|
||||
});
|
||||
|
@ -27,16 +27,16 @@ export abstract class VoidUploader {
|
||||
protected file: File | Blob;
|
||||
protected auth?: string;
|
||||
protected maxChunkSize: number;
|
||||
protected onStateChange: StateChangeHandler;
|
||||
protected onProgress: ProgressHandler;
|
||||
protected onProxyChallenge: ProxyChallengeHandler;
|
||||
protected onStateChange?: StateChangeHandler;
|
||||
protected onProgress?: ProgressHandler;
|
||||
protected onProxyChallenge?: ProxyChallengeHandler;
|
||||
|
||||
constructor(
|
||||
uri: string,
|
||||
file: File | Blob,
|
||||
stateChange: StateChangeHandler,
|
||||
progress: ProgressHandler,
|
||||
proxyChallenge: ProxyChallengeHandler,
|
||||
stateChange?: StateChangeHandler,
|
||||
progress?: ProgressHandler,
|
||||
proxyChallenge?: ProxyChallengeHandler,
|
||||
auth?: string,
|
||||
chunkSize?: number
|
||||
) {
|
||||
@ -65,12 +65,16 @@ export abstract class VoidUploader {
|
||||
const slice = file.slice(offset, offset + ChunkSize);
|
||||
const chunk = await slice.arrayBuffer();
|
||||
sha.update(sjclcodec.toBits(new Uint8Array(chunk)));
|
||||
this.onProgress(progress += chunk.byteLength);
|
||||
this.onProgress?.(progress += chunk.byteLength);
|
||||
}
|
||||
return buf2hex(sjclcodec.fromBits(sha.finalize()));
|
||||
}
|
||||
|
||||
abstract upload(): Promise<VoidUploadResult>;
|
||||
/**
|
||||
* Upload a file to the API
|
||||
* @param headers any additional headers to send with the request
|
||||
*/
|
||||
abstract upload(headers?: HeadersInit): Promise<VoidUploadResult>;
|
||||
|
||||
/**
|
||||
* Can we use local encryption
|
||||
|
@ -14,23 +14,23 @@ export class XHRUploader extends VoidUploader {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async upload(): Promise<VoidUploadResult> {
|
||||
this.onStateChange(UploadState.Hashing);
|
||||
async upload(headers?: HeadersInit): Promise<VoidUploadResult> {
|
||||
this.onStateChange?.(UploadState.Hashing);
|
||||
const hash = await this.digest(this.file);
|
||||
if (this.file.size > this.maxChunkSize) {
|
||||
return await this.#doSplitXHRUpload(hash, this.maxChunkSize);
|
||||
return await this.#doSplitXHRUpload(hash, this.maxChunkSize, headers);
|
||||
} else {
|
||||
return await this.#xhrSegment(this.file, hash);
|
||||
return await this.#xhrSegment(this.file, hash, undefined, undefined, 1, 1, headers);
|
||||
}
|
||||
}
|
||||
|
||||
async #doSplitXHRUpload(hash: string, splitSize: number) {
|
||||
async #doSplitXHRUpload(hash: string, splitSize: number, headers?: HeadersInit) {
|
||||
let xhr: VoidUploadResult | null = null;
|
||||
const segments = Math.ceil(this.file.size / splitSize);
|
||||
for (let s = 0; s < segments; s++) {
|
||||
const offset = s * splitSize;
|
||||
const slice = this.file.slice(offset, offset + splitSize, this.file.type);
|
||||
xhr = await this.#xhrSegment(slice, hash, xhr?.file?.id, xhr?.file?.metadata?.editSecret, s + 1, segments);
|
||||
xhr = await this.#xhrSegment(slice, hash, xhr?.file?.id, xhr?.file?.metadata?.editSecret, s + 1, segments, headers);
|
||||
if (!xhr.ok) {
|
||||
break;
|
||||
}
|
||||
@ -46,9 +46,11 @@ export class XHRUploader extends VoidUploader {
|
||||
* @param editSecret
|
||||
* @param part Segment number
|
||||
* @param partOf Total number of segments
|
||||
* @param headers
|
||||
*/
|
||||
async #xhrSegment(segment: ArrayBuffer | Blob, fullDigest: string, id?: string, editSecret?: string, part?: number, partOf?: number) {
|
||||
this.onStateChange(UploadState.Uploading);
|
||||
async #xhrSegment(segment: ArrayBuffer | Blob, fullDigest: string,
|
||||
id?: string, editSecret?: string, part?: number, partOf?: number, headers?: HeadersInit) {
|
||||
this.onStateChange?.(UploadState.Uploading);
|
||||
|
||||
return await new Promise<VoidUploadResult>((resolve, reject) => {
|
||||
try {
|
||||
@ -60,15 +62,15 @@ export class XHRUploader extends VoidUploader {
|
||||
} else if (req.readyState === XMLHttpRequest.DONE && req.status === 403) {
|
||||
const contentType = req.getResponseHeader("content-type");
|
||||
if (contentType?.toLowerCase().trim().indexOf("text/html") === 0) {
|
||||
this.onProxyChallenge(req.response);
|
||||
this.onStateChange(UploadState.Challenge);
|
||||
this.onProxyChallenge?.(req.response);
|
||||
this.onStateChange?.(UploadState.Challenge);
|
||||
reject(new Error("CF Challenge"));
|
||||
}
|
||||
}
|
||||
};
|
||||
req.upload.onprogress = (e) => {
|
||||
if (e instanceof ProgressEvent) {
|
||||
this.onProgress(e.loaded);
|
||||
this.onProgress?.(e.loaded);
|
||||
}
|
||||
};
|
||||
req.open("POST", id ? `${this.uri}/upload/${id}` : `${this.uri}/upload`);
|
||||
@ -84,6 +86,11 @@ export class XHRUploader extends VoidUploader {
|
||||
if (editSecret) {
|
||||
req.setRequestHeader("V-EditSecret", editSecret);
|
||||
}
|
||||
if (headers) {
|
||||
for (const [k, v] of Object.entries(headers)) {
|
||||
req.setRequestHeader(k, v);
|
||||
}
|
||||
}
|
||||
req.send(segment);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
|
@ -3,7 +3,9 @@
|
||||
const path = require('path');
|
||||
const isProduction = process.env.NODE_ENV == 'production';
|
||||
const config = {
|
||||
entry: './src/index.ts',
|
||||
entry: {
|
||||
lib: './src/index.ts',
|
||||
},
|
||||
devtool: isProduction ? "source-map" : "eval",
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user