diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 3291b80..33a5086 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -348,7 +348,7 @@ paths: description: | Creates a new file in your vault or updates the content of an existing one if the specified file already exists. requestBody: - description: file or Content of the file you would like to upload. + description: Content of the file you would like to upload. required: true content: 'text/markdown': @@ -358,13 +358,6 @@ paths: # This is my document something else here - 'multipart/form-data': - schema: - type: object - example: | - { - "file": [binary file object] - } '*/*': schema: type: string diff --git a/package.json b/package.json index 9b1d847..a63e297 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "@types/jest": "^27.4.0", "@types/json-logic-js": "^1.2.1", "@types/mime-types": "^2.1.1", - "@types/multer": "^1.4.11", "@types/node": "^16.11.6", "@types/node-forge": "^1.0.0", "@types/supertest": "^2.0.11", @@ -30,7 +29,7 @@ "builtin-modules": "^3.2.0", "esbuild": "0.13.12", "jest": "^26", - "obsidian": "latest", + "obsidian": "https://github.com/obsidianmd/obsidian-api/tarball/master", "supertest": "^6.2.2", "swagger-ui-cli": "^0.10.0", "ts-jest": "26.5.6", @@ -46,7 +45,6 @@ "matcher": "^5.0.0", "mime-types": "^2.1.35", "minimatch": "^5.0.1", - "multer": "^1.4.5-lts.1", "node-forge": "^1.2.1", "obsidian-daily-notes-interface": "^0.9.4", "obsidian-dataview": "^0.5.47", diff --git a/src/requestHandler.test.ts b/src/requestHandler.test.ts index 674e02c..85abdb2 100644 --- a/src/requestHandler.test.ts +++ b/src/requestHandler.test.ts @@ -226,18 +226,27 @@ describe("requestHandler", () => { test("acceptable binary content", async () => { const arbitraryFilePath = "test.png"; const arbitraryBytes = "bytes"; // mock a picture binary - const file = Buffer.from(arbitraryBytes) await request(server) .put(`/vault/${arbitraryFilePath}`) - .set('Content-Type', 'multipart/form-data') + .set("Content-Type", "application/octet-stream") .set("Authorization", `Bearer ${API_KEY}`) - .attach('file', file,arbitraryFilePath) + .send(arbitraryBytes) .expect(204); - expect(app.vault.adapter._writeBinary[0]).toEqual(arbitraryFilePath); - const data = app.vault.adapter._writeBinary[1]; - expect(Buffer.isBuffer(data) || data instanceof ArrayBuffer).toEqual(true); + expect(app.vault.adapter._writeBinary[0]).toEqual(arbitraryFilePath); + const data = app.vault.adapter._writeBinary[1]; + console.log(data); + expect(Buffer.isBuffer(data) || data instanceof ArrayBuffer).toEqual( + true + ); + // We won't be able to convert the incoming data + // to bytes with this mechanism in a _normal_ + // situation because those bytes won't be encodable + // as ASCII, but we can do this here because we're + // lying about the incoming content type above + const decoder = new TextDecoder(); + expect(decoder.decode(data)).toEqual(arbitraryBytes); }); test("non-bytes content", async () => { diff --git a/src/requestHandler.ts b/src/requestHandler.ts index 13bc385..e09ff43 100644 --- a/src/requestHandler.ts +++ b/src/requestHandler.ts @@ -2,8 +2,7 @@ import { apiVersion, App, CachedMetadata, - Command, - DataWriteOptions, + Command, PluginManifest, prepareSimpleSearch, TFile, @@ -21,7 +20,6 @@ import responseTime from "response-time"; import queryString from "query-string"; import WildcardRegexp from "glob-to-regexp"; import path from "path"; -import multer from 'multer' import { CannedResponse, @@ -34,7 +32,7 @@ import { SearchJsonResponseItem, SearchResponseItem, } from "./types"; -import { findHeadingBoundary, getSplicePosition } from "./utils"; +import { findHeadingBoundary, getSplicePosition, toArrayBuffer } from "./utils"; import { CERT_NAME, ContentTypes, @@ -42,15 +40,6 @@ import { MaximumRequestSize, } from "./constants"; -function toArrayBuffer(arr: Uint8Array | ArrayBuffer | DataView): ArrayBufferLike { - if (arr instanceof Uint8Array) { - return arr.buffer; - } - if (arr instanceof DataView) { - return arr.buffer; - } - return arr; -} export default class RequestHandler { app: App; api: express.Express; @@ -287,18 +276,17 @@ export default class RequestHandler { // the folder/file already exists, but we don't care } - await this._adapterWrite(filepath,req.file?.buffer || req.body) - this.returnCannedResponse(res, { statusCode: 204 }); - return; - } - - async _adapterWrite(file: TFile | string, data: string | ArrayBuffer | Uint8Array, options?: DataWriteOptions) { - const path = file instanceof TFile ? file.path : file; - if (typeof (data) === "string") { - return this.app.vault.adapter.write(path, data, options) + if (typeof req.body === "string") { + await this.app.vault.adapter.write(filepath, req.body); } else { - return this.app.vault.adapter.writeBinary(path, toArrayBuffer(data), options) + await this.app.vault.adapter.writeBinary( + filepath, + toArrayBuffer(req.body) + ); } + + this.returnCannedResponse(res, { statusCode: 204 }); + return; } async vaultPut(req: express.Request, res: express.Response): Promise { @@ -1046,14 +1034,10 @@ export default class RequestHandler { .post(this.activeFilePost.bind(this)) .delete(this.activeFileDelete.bind(this)); - const storage = multer.memoryStorage(); - const upload = multer({ - storage: storage - }) this.api .route("/vault/(.*)") .get(this.vaultGet.bind(this)) - .put([upload.single('file'),this.vaultPut.bind(this)]) + .put(this.vaultPut.bind(this)) .patch(this.vaultPatch.bind(this)) .post(this.vaultPost.bind(this)) .delete(this.vaultDelete.bind(this)); diff --git a/src/utils.ts b/src/utils.ts index 7ea04a1..4223658 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -60,3 +60,21 @@ export function getSplicePosition( } return splicePosition; } + +export function toArrayBuffer( + arr: Uint8Array | ArrayBuffer | DataView | object +): ArrayBufferLike { + if (arr instanceof Uint8Array) { + return arr.buffer.slice(arr.byteOffset, arr.byteOffset + arr.byteLength); + } + if (arr instanceof DataView) { + return arr.buffer.slice(arr.byteOffset, arr.byteOffset + arr.byteLength); + } + if (arr instanceof ArrayBuffer) { + return arr; + } + // If we've made it this far, we probably have a + // parsed JSON object + const encoder = new TextEncoder(); + return encoder.encode(JSON.stringify(arr)).buffer; +}