diff --git a/generator/typescript/index.d.tstemplate b/generator/typescript/index.d.tstemplate index 9e449484..654d368f 100644 --- a/generator/typescript/index.d.tstemplate +++ b/generator/typescript/index.d.tstemplate @@ -177,6 +177,8 @@ export interface DropboxOptions { domain?: string; // A custom delimiter to use when separating domain subdomain. This should only be used for testing as scaffolding. domainDelimiter?: string; + // An object (in the form of header: value) designed to set custom headers to use during a request. + customHeaders?: object; } export class DropboxResponseError { diff --git a/package.json b/package.json index 30569cc3..461f923d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dropbox", - "version": "10.11.0", + "version": "10.12.0", "registry": "npm", "description": "The Dropbox JavaScript SDK is a lightweight, promise based interface to the Dropbox v2 API that works in both nodejs and browser environments.", "main": "cjs/index.js", diff --git a/src/constants.js b/src/constants.js index abd19e2c..6012518b 100644 --- a/src/constants.js +++ b/src/constants.js @@ -6,6 +6,7 @@ export const APP_AUTH = 'app'; export const USER_AUTH = 'user'; export const TEAM_AUTH = 'team'; export const NO_AUTH = 'noauth'; +export const COOKIE = 'cookie'; export const DEFAULT_API_DOMAIN = 'dropboxapi.com'; export const DEFAULT_DOMAIN = 'dropbox.com'; diff --git a/src/dropbox.js b/src/dropbox.js index 57972e7f..925fc75a 100644 --- a/src/dropbox.js +++ b/src/dropbox.js @@ -6,6 +6,7 @@ import { TEAM_AUTH, USER_AUTH, NO_AUTH, + COOKIE, } from './constants.js'; import { routes } from '../lib/routes.js'; import DropboxAuth from './auth.js'; @@ -50,6 +51,8 @@ const b64 = typeof btoa === 'undefined' * should only be used for testing as scaffolding to avoid making network requests. * @arg {String} [options.domainDelimiter] - A custom delimiter to use when separating domain from * subdomain. This should only be used for testing as scaffolding. + * @arg {Object} [options.customHeaders] - An object (in the form of header: value) designed to set + * custom headers to use during a request. */ export default class Dropbox { constructor(options) { @@ -68,6 +71,7 @@ export default class Dropbox { this.domain = options.domain; this.domainDelimiter = options.domainDelimiter; + this.customHeaders = options.customHeaders; Object.assign(this, routes); } @@ -125,6 +129,8 @@ export default class Dropbox { break; case NO_AUTH: break; + case COOKIE: + break; default: throw new Error(`Unhandled auth type: ${auth}`); } @@ -206,5 +212,11 @@ export default class Dropbox { if (this.pathRoot) { options.headers['Dropbox-API-Path-Root'] = this.pathRoot; } + if (this.customHeaders) { + const headerKeys = Object.keys(this.customHeaders); + headerKeys.forEach((header) => { + options.headers[header] = this.customHeaders[header]; + }); + } } } diff --git a/test/unit/dropbox.js b/test/unit/dropbox.js index 31472efd..cad8a22f 100644 --- a/test/unit/dropbox.js +++ b/test/unit/dropbox.js @@ -11,6 +11,7 @@ import { TEAM_AUTH, APP_AUTH, NO_AUTH, + COOKIE, } from '../../src/constants.js'; import { Dropbox, DropboxAuth } from '../../index.js'; @@ -28,6 +29,18 @@ describe('Dropbox', () => { }); }); + describe('customHeaders', () => { + it('can be set in the constructor', () => { + const dbx = new Dropbox({ customHeaders: { foo: 'bar' } }); + chai.assert.equal(dbx.customHeaders.foo, 'bar'); + }); + + it('is undefined if not set in constructor', () => { + const dbx = new Dropbox(); + chai.assert.equal(dbx.customHeaders, undefined); + }); + }); + describe('RPC requests', () => { it('request() calls the correct request method', () => { const dbx = new Dropbox(); @@ -86,6 +99,20 @@ describe('Dropbox', () => { chai.assert.equal(APP_AUTH, dbx.rpcRequest.getCall(0).args[2]); }); + it('completes a cookie auth RPC request', () => { + const dbxAuth = new DropboxAuth(); + const dbx = new Dropbox({ auth: dbxAuth }); + const rpcSpy = sinon.spy(dbx, 'rpcRequest'); + dbx.request('path', {}, COOKIE, 'api', RPC) + .catch((error) => { + fail(error); + }); + chai.assert.isTrue(rpcSpy.calledOnce); + chai.assert.equal('path', dbx.rpcRequest.getCall(0).args[0]); + chai.assert.deepEqual({}, dbx.rpcRequest.getCall(0).args[1]); + chai.assert.equal(COOKIE, dbx.rpcRequest.getCall(0).args[2]); + }); + it('throws an error for invalid request styles', () => { chai.assert.throws( Dropbox.prototype.request.bind(Dropbox, '', {}, 'user', 'api', 'BADTYPE'), @@ -120,6 +147,10 @@ describe('Dropbox', () => { const dbx = new Dropbox(); return chai.assert.isRejected(dbx.uploadRequest('path', {}, NO_AUTH, 'api'), Error, `Unexpected auth type: ${NO_AUTH}`); }); + it('throws an error for cookie auth', () => { + const dbx = new Dropbox(); + return chai.assert.isRejected(dbx.uploadRequest('path', {}, COOKIE, 'api'), Error, `Unexpected auth type: ${COOKIE}`); + }); }); describe('Download Requests', () => { @@ -149,6 +180,11 @@ describe('Dropbox', () => { const dbx = new Dropbox(); return chai.assert.isRejected(dbx.downloadRequest('path', {}, NO_AUTH, 'api'), Error, `Unexpected auth type: ${NO_AUTH}`); }); + + it('throws an error for cookie auth', () => { + const dbx = new Dropbox(); + return chai.assert.isRejected(dbx.downloadRequest('path', {}, COOKIE, 'api'), Error, `Unexpected auth type: ${COOKIE}`); + }); }); describe('pathRoot', () => { @@ -186,5 +222,25 @@ describe('Dropbox', () => { } } }); + + it('sets custom headers correctly', () => { + const dbx = new Dropbox({ + customHeaders: { + foo: 'bar', + milk: 'shake', + cookie: 'hash', + }, + }); + + const fetchOptions = { + headers: {}, + }; + + dbx.setCommonHeaders(fetchOptions); + const { headers } = fetchOptions; + chai.assert.equal(headers.foo, 'bar'); + chai.assert.equal(headers.milk, 'shake'); + chai.assert.equal(headers.cookie, 'hash'); + }); }); }); diff --git a/types/index.d.ts b/types/index.d.ts index 5751e727..a32f2820 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -178,6 +178,8 @@ export interface DropboxOptions { domain?: string; // A custom delimiter to use when separating domain subdomain. This should only be used for testing as scaffolding. domainDelimiter?: string; + // An object (in the form of header: value) designed to set custom headers to use during a request. + customHeaders?: object; } export class DropboxResponseError {