Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions generator/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,14 @@ function generateAPIClass({ apiName, operations = [], generatorType }) {
requestParams.push(`path: \`${url.replaceAll(/({.+?})/g, (_, p1) => `$${p1}`)}\``)
requestParams.push(`method: '${method}'`)

if (
generatorType === 'Manage' &&
method === 'post' &&
url === '/system/members/{memberIdentifier}/tokens'
) {
requestParams.push(`headers: { 'x-cw-usertype': 'member' }`)
}

if (requestBody) {
if (isMultipart) {
usedToFormData = true
Expand Down
6 changes: 3 additions & 3 deletions src/BaseAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export const makeRequest =
api: (args: RequestOptions) => Promise<unknown>
thisObj: InstanceType<typeof Automate | typeof Manage>
}): ((args: RequestOptions) => Promise<unknown>) =>
({ path, method = 'get', params, data }: RequestOptions): Promise<unknown> => {
({ path, method = 'get', params, data, contentType, responseType, headers }: RequestOptions): Promise<unknown> => {
const retryCodes = ['ECONNRESET', 'ETIMEDOUT', 'ESOCKETTIMEDOUT']
const boundApi = api.bind(thisObj)

Expand All @@ -102,7 +102,7 @@ export const makeRequest =
const { retry, retryOptions, logger } = config

if (!retry) {
return boundApi({ path, method, params, data })
return boundApi({ path, method, params, data, contentType, responseType, headers })
.then((result: any) => {
logger(
'info',
Expand All @@ -120,7 +120,7 @@ export const makeRequest =
})
} else {
return promiseRetry(retryOptions, (retry, number) => {
return boundApi({ path, method, params, data }).catch((error) => {
return boundApi({ path, method, params, data, contentType, responseType, headers }).catch((error) => {
logger(
'warn',
`${method} ${path} ${Date.now() - startTime}ms error occurred: ${
Expand Down
5 changes: 4 additions & 1 deletion src/Manage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,17 @@ export default class Manage {
data,
contentType,
responseType,
headers: requestHeaders,
}: RequestOptions): Promise<ErrorResponse | DataResponse> {
try {
// For multipart uploads let the runtime set Content-Type + boundary.
// Axios inspects FormData and builds the header itself; passing a plain
// object with contentType: 'multipart' falls back to the caller's
// FormData (consumers should use toFormData() from BaseAPI).
const headers: Record<string, string> | undefined =
contentType === 'multipart' ? { 'Content-Type': 'multipart/form-data' } : undefined
contentType === 'multipart'
? { ...requestHeaders, 'Content-Type': 'multipart/form-data' }
: requestHeaders

const result = await this.instance({
url: path,
Expand Down
1 change: 1 addition & 0 deletions src/Manage/SystemAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3124,6 +3124,7 @@ export class SystemAPI extends ManageBaseAPI {
return this.request({
path: `/system/members/${memberIdentifier}/tokens`,
method: 'post',
headers: { 'x-cw-usertype': 'member' },
})
}

Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export type RequestOptions = {
contentType?: ContentType
/** Hint for how axios should decode the response; generator sets this for binary endpoints. */
responseType?: ResponseType
/** Endpoint-specific headers to merge into the request. */
headers?: Record<string, string>
}

export type LoggingLevels = 'error' | 'warn' | 'info' | 'debug'
Expand Down
62 changes: 62 additions & 0 deletions test/test-manage-request-options.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import assert from 'node:assert'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import dotenv from 'dotenv'
import { beforeEach, describe, it } from 'mocha'
import pkg from '../dist/index.js'
const { ManageAPI } = pkg

const __dirname = path.dirname(fileURLToPath(import.meta.url))
dotenv.config({ path: path.join(__dirname, '.env') })

const {
MANAGE_API_COMPANY = 'test-company',
MANAGE_API_URL = 'example.com',
MANAGE_API_PUBLIC_KEY = 'test-public-key',
MANAGE_API_PRIVATE_KEY = 'test-private-key',
MANAGE_API_CLIENT_ID = 'test-client-id',
} = process.env

describe('Manage request options', () => {
let cwm = null
let requestArgs = null

beforeEach(() => {
cwm = new ManageAPI({
companyId: MANAGE_API_COMPANY,
companyUrl: MANAGE_API_URL,
publicKey: MANAGE_API_PUBLIC_KEY,
privateKey: MANAGE_API_PRIVATE_KEY,
clientId: MANAGE_API_CLIENT_ID,
apiVersion: '2021.2',
logger: () => {},
})
requestArgs = null
cwm.instance = async (args) => {
requestArgs = args
return { data: [] }
}
})

describe('request headers', () => {
it('adds member user type header when creating member tokens', async () => {
await cwm.SystemAPI.postSystemMembersByMemberIdentifierTokens('member-id')

assert.deepStrictEqual(requestArgs.headers, { 'x-cw-usertype': 'member' })
})
})

describe('binary downloads', () => {
it('requests document downloads as arraybuffers', async () => {
await cwm.SystemAPI.getSystemDocumentsByIdDownload(123)

assert.strictEqual(requestArgs.responseType, 'arraybuffer')
})

it('requests invoice PDFs as arraybuffers', async () => {
await cwm.FinanceAPI.getFinanceInvoicesByIdPdf(456)

assert.strictEqual(requestArgs.responseType, 'arraybuffer')
})
})
})
20 changes: 10 additions & 10 deletions test/test-manage.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ const {
MANAGE_API_CLIENT_ID = 'test-client-id',
} = process.env

const cwm = new ManageAPI({
companyId: MANAGE_API_COMPANY,
companyUrl: MANAGE_API_URL,
publicKey: MANAGE_API_PUBLIC_KEY,
privateKey: MANAGE_API_PRIVATE_KEY,
clientId: MANAGE_API_CLIENT_ID,
apiVersion: '2021.2',
logger: () => {},
})

describe('Manage', () => {
const cwm = new ManageAPI({
companyId: MANAGE_API_COMPANY,
companyUrl: MANAGE_API_URL,
publicKey: MANAGE_API_PUBLIC_KEY,
privateKey: MANAGE_API_PRIVATE_KEY,
clientId: MANAGE_API_CLIENT_ID,
apiVersion: '2021.2',
logger: () => {},
})

describe('instance', () => {
it('should be an instance of ManageAPI', () => {
assert(cwm instanceof ManageAPI)
Expand Down