Add headers to request

This commit is contained in:
Kieran 2023-05-22 15:14:22 +01:00
parent 1babc8e4e0
commit e0652dfbb8
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
6 changed files with 50 additions and 34 deletions

View File

@ -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",

View File

@ -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()) {

View File

@ -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'
});

View File

@ -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

View File

@ -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);

View File

@ -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'),