async-mutex#Mutex TypeScript Examples
The following examples show how to use
async-mutex#Mutex.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts From webminidisc with GNU General Public License v2.0 | 7 votes |
export function asyncMutex(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
// This is meant to be used only with classes having a "mutex" instance property
const oldValue = descriptor.value;
descriptor.value = async function(...args: any) {
const mutex = (this as any).mutex as Mutex;
const release = await mutex.acquire();
try {
return await oldValue.apply(this, args);
} finally {
release();
}
};
return descriptor;
}
Example #2
Source File: leopard.ts From leopard with Apache License 2.0 | 6 votes |
private constructor(handleWasm: LeopardWasmOutput) {
Leopard._sampleRate = handleWasm.sampleRate;
Leopard._version = handleWasm.version;
this._pvLeopardDelete = handleWasm.pvLeopardDelete;
this._pvLeopardProcess = handleWasm.pvLeopardProcess;
this._pvStatusToString = handleWasm.pvStatusToString;
this._wasmMemory = handleWasm.memory;
this._pvFree = handleWasm.pvFree;
this._objectAddress = handleWasm.objectAddress;
this._alignedAlloc = handleWasm.aligned_alloc;
this._transcriptionAddressAddress = handleWasm.transcriptionAddressAddress;
this._memoryBuffer = new Int16Array(handleWasm.memory.buffer);
this._memoryBufferUint8 = new Uint8Array(handleWasm.memory.buffer);
this._memoryBufferView = new DataView(handleWasm.memory.buffer);
this._processMutex = new Mutex();
}
Example #3
Source File: index.ts From zilswap-sdk with MIT License | 6 votes |
/**
* Creates the Zilswap SDK object. {@linkcode initalize} needs to be called after
* the object is created to begin watching the blockchain's state.
*
* @param network the Network to use, either `TestNet` or `MainNet`.
* @param walletProviderOrKey a Provider with Wallet or private key string to be used for signing txns.
* @param options a set of Options that will be used for all txns.
*/
constructor(readonly network: Network, walletProviderOrKey?: WalletProvider | string, options?: Options) {
this.rpcEndpoint = options?.rpcEndpoint || APIS[network]
if (typeof walletProviderOrKey === 'string') {
this.zilliqa = new Zilliqa(this.rpcEndpoint)
this.zilliqa.wallet.addByPrivateKey(walletProviderOrKey)
} else if (walletProviderOrKey) {
this.zilliqa = new Zilliqa(this.rpcEndpoint, walletProviderOrKey.provider)
this.walletProvider = walletProviderOrKey
} else {
this.zilliqa = new Zilliqa(this.rpcEndpoint)
}
this.contractAddress = CONTRACTS[network]
this.contract = (this.walletProvider || this.zilliqa).contracts.at(this.contractAddress)
this.contractHash = fromBech32Address(this.contractAddress).toLowerCase()
this.tokens = {}
this.zilos = {}
this._txParams.version = CHAIN_VERSIONS[network]
if (options) {
if (options.deadlineBuffer && options.deadlineBuffer > 0) this.deadlineBuffer = options.deadlineBuffer
if (options.gasPrice && options.gasPrice > 0) this._txParams.gasPrice = toPositiveQa(options.gasPrice, units.Units.Li)
if (options.gasLimit && options.gasLimit > 0) this._txParams.gasLimit = Long.fromNumber(options.gasLimit)
}
this.observerMutex = new Mutex()
}
Example #4
Source File: task.ts From command-bot with Apache License 2.0 | 5 votes |
tasksRepositoryLockMutex = new Mutex()
Example #5
Source File: makeBaselets.ts From edge-currency-plugins with MIT License | 5 votes |
makeBaselets = async (
config: MakeBaseletsConfig
): Promise<Baselets> => {
/* Tables */
const addressBases: AddressBaselets = {
addressByScriptPubkey: await createOrOpenHashBase(
config.disklet,
addressByScriptPubkeyOptions
),
scriptPubkeyByPath: await createOrOpenCountBase(
config.disklet,
scriptPubkeyByPathOptions
),
lastUsedByFormatPath: await createOrOpenHashBase(
config.disklet,
lastUsedByFormatPathOptions
)
}
const txBases: TransactionBaselets = {
txById: await createOrOpenHashBase(config.disklet, txByIdOptions),
txIdsByBlockHeight: await createOrOpenRangeBase(
config.disklet,
txIdsByBlockHeightOptions
),
txIdsByDate: await createOrOpenRangeBase(config.disklet, txIdsByDateOptions)
}
const utxoBases: UtxoBaselets = {
utxoById: await createOrOpenHashBase(config.disklet, utxoByIdOptions),
utxoIdsByScriptPubkey: await createOrOpenHashBase(
config.disklet,
utxoIdsByScriptPubkeyOptions
)
}
const addressMutex = new Mutex()
const txMutex = new Mutex()
const utxoMutex = new Mutex()
return {
async address(fn): Promise<ReturnType<typeof fn>> {
return await addressMutex.runExclusive(async () => await fn(addressBases))
},
async tx(fn): Promise<ReturnType<typeof fn>> {
return await txMutex.runExclusive(async () => await fn(txBases))
},
async utxo(fn): Promise<ReturnType<typeof fn>> {
return await utxoMutex.runExclusive(async () => await fn(utxoBases))
},
all: {
...addressBases,
...txBases,
...utxoBases
}
}
}
Example #6
Source File: github.ts From command-bot with Apache License 2.0 | 5 votes |
requestMutex = new Mutex()
Example #7
Source File: capacitor-storage-preferences.ts From capture-lite with GNU General Public License v3.0 | 5 votes |
private readonly mutex = new Mutex();
Example #8
Source File: media-store.service.ts From capture-lite with GNU General Public License v3.0 | 5 votes |
private readonly mutex = new Mutex();
Example #9
Source File: capacitor-filesystem-table.ts From capture-lite with GNU General Public License v3.0 | 5 votes |
private readonly mutex = new Mutex();
Example #10
Source File: capacitor-filesystem-table.ts From capture-lite with GNU General Public License v3.0 | 5 votes |
private static readonly initializationMutex = new Mutex();
Example #11
Source File: index.ts From integration-services with Apache License 2.0 | 5 votes |
acquire(key: string) {
if (!this.locks.has(key)) {
this.locks.set(key, new Mutex());
}
return this.locks.get(key).acquire();
}
Example #12
Source File: currency.ts From cloud-pricing-api with Apache License 2.0 | 5 votes |
mutex = new Mutex()
Example #13
Source File: nonce-tracker.ts From hoprnet with GNU General Public License v3.0 | 5 votes |
private lockMap: Record<string, Mutex>
Example #14
Source File: nonce-tracker.ts From hoprnet with GNU General Public License v3.0 | 5 votes |
private _lookupMutex(lockId: string): Mutex {
let mutex = this.lockMap[lockId]
if (!mutex) {
mutex = new Mutex()
this.lockMap[lockId] = mutex
}
return mutex
}
Example #15
Source File: daemon.ts From edge-impulse-cli with Apache License 2.0 | 5 votes |
private _snapshotMutex = new Mutex();
Example #16
Source File: netmd.ts From webminidisc with GNU General Public License v2.0 | 5 votes |
public mutex = new Mutex();
Example #17
Source File: netmd-mock.ts From webminidisc with GNU General Public License v2.0 | 5 votes |
public mutex = new Mutex();
Example #18
Source File: scheduler.ts From backend with MIT License | 5 votes |
activeConnectionMutex = new Mutex()
Example #19
Source File: manualExecution.ts From backend with MIT License | 5 votes |
executeJob = async (job) => {
const activeConnectionMutex = new Mutex();
const release = await activeConnectionMutex.acquire();
const jobConnection = await createConnection();
release();
switch (job) {
case 'initialInterestConfirmationRequests': {
initialInterestConfirmationRequests(jobConnection.manager);
break;
}
case 'screeningReminderJob': {
screeningReminderJob(jobConnection.manager);
break;
}
case 'courseReminderJob': {
courseReminderJob(jobConnection.manager);
break;
}
case 'feedbackRequestJob': {
feedbackRequestJob(jobConnection.manager);
break;
}
case 'matchFollowUpJob': {
matchFollowUpJob(jobConnection.manager);
break;
}
case 'jufoVerificationInfo': {
jufoVerificationInfo(jobConnection.manager);
break;
}
case 'projectMatchMaking': {
projectMatchMaking(jobConnection.manager);
break;
}
case 'tutoringMatchMaking': {
tutoringMatchMaking(jobConnection.manager);
break;
}
case 'interestConfirmationRequestReminders': {
interestConfirmationRequestReminders(jobConnection.manager);
break;
}
case 'Notification': {
Notification.checkReminders();
break;
}
case 'deactivateMissingCoc': {
deactivateMissingCoc();
break;
}
default: {
throw new Error(`Did not find job ${job}`);
}
}
}
Example #20
Source File: index.ts From zilswap-sdk with MIT License | 5 votes |
private observerMutex: Mutex
Example #21
Source File: revision_cache.ts From skynet-js with MIT License | 5 votes |
mutex: Mutex;
Example #22
Source File: revision_cache.ts From skynet-js with MIT License | 5 votes |
/**
* Creates a `CachedRevisionNumber`.
*/
constructor() {
this.mutex = new Mutex();
this.revision = BigInt(-1);
}
Example #23
Source File: revision_cache.ts From skynet-js with MIT License | 5 votes |
private mutex: Mutex;
Example #24
Source File: revision_cache.ts From skynet-js with MIT License | 5 votes |
/**
* Creates the `RevisionNumberCache`.
*/
constructor() {
this.mutex = new Mutex();
this.cache = {};
}
Example #25
Source File: FtxService.ts From sakeperp-arbitrageur with BSD 3-Clause "New" or "Revised" License | 5 votes |
private readonly txMutex = new Mutex()
Example #26
Source File: Arbitrageur.ts From sakeperp-arbitrageur with BSD 3-Clause "New" or "Revised" License | 5 votes |
private readonly nonceMutex = new Mutex()
Example #27
Source File: leopard.ts From leopard with Apache License 2.0 | 5 votes |
private static _leopardMutex = new Mutex();
Example #28
Source File: leopard.ts From leopard with Apache License 2.0 | 5 votes |
private readonly _processMutex: Mutex;
Example #29
Source File: endpoint-client.test.ts From smartthings-core-sdk with Apache License 2.0 | 4 votes |
describe('EndpointClient', () => {
const mockRequest = axios.request as jest.Mock<Promise<AxiosResponse>, [AxiosRequestConfig]>
mockRequest.mockResolvedValue({ status: 200, data: { status: 'ok' } } as AxiosResponse)
class TokenStore implements RefreshTokenStore {
public authData?: AuthData
getRefreshData(): Promise<RefreshData> {
return Promise.resolve({ refreshToken: 'xxx', clientId: 'aaa', clientSecret: 'bbb' })
}
putAuthData (data: AuthData): Promise<void> {
this.authData = data
return Promise.resolve()
}
}
const tokenStore = new TokenStore()
const token = 'authToken'
let client: EndpointClient
const configWithoutHeaders = {
urlProvider: defaultSmartThingsURLProvider,
authenticator: new RefreshTokenAuthenticator(token, tokenStore),
baseURL: 'https://api.smartthings.com',
authURL: 'https://auth.smartthings.com',
}
const headers = {
'Content-Type': 'application/json;charset=utf-8',
Accept: 'application/json',
}
const buildClient = (config: EndpointClientConfig = { ...configWithoutHeaders, headers }): EndpointClient =>
new EndpointClient('base/path', { ...config, headers: { ...config.headers }})
beforeEach(() => {
client = buildClient()
})
afterEach(() => {
jest.clearAllMocks()
})
describe('setHeader', () => {
it('adds header to config', () => {
client.setHeader('NewHeader', 'header value')
expect(client.config.headers?.NewHeader).toBe('header value')
})
it('works when no previous headers set', () => {
const client = new EndpointClient('base/path', { ...configWithoutHeaders })
client.setHeader('NewHeader', 'header value')
expect(client.config.headers?.NewHeader).toBe('header value')
})
})
describe('removeHeader', () => {
it('removes header from config', () => {
client.setHeader('NewHeader', 'header value')
expect(client.config.headers?.NewHeader).toBe('header value')
client.removeHeader('NewHeader')
expect(client.config.headers?.NewHeader).toBeUndefined()
})
it('ignores undefined headers', () => {
client.removeHeader('NewHeader')
expect(client.config.headers?.NewHeader).toBeUndefined()
})
})
describe('request', () => {
it('submits basic request', async () => {
const response = await client.request('GET', 'my/path')
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/my/path',
method: 'GET',
headers: {
...headers,
Authorization: `Bearer ${token}`,
},
data: undefined,
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
const stringifyMock = (qs.stringify as jest.Mock<string, [unknown]>)
.mockReturnValue('stringified parameters')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const paramsSerializer = mockRequest.mock.calls[0][0].paramsSerializer as (params: any) => string
expect(paramsSerializer).toBeDefined()
expect(paramsSerializer({ param: 'value' })).toBe('stringified parameters')
expect(stringifyMock).toHaveBeenCalledTimes(1)
expect(stringifyMock).toHaveBeenCalledWith({ param: 'value' }, { indices: false })
})
it('adds accept header for version', async () => {
const client = buildClient({
...configWithoutHeaders,
version: 'api-version',
headers: { Accept: 'accept-header' },
})
const response = await client.request('GET', 'my/path')
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/my/path',
method: 'GET',
headers: {
Accept: 'application/vnd.smartthings+json;v=api-version, accept-header',
Authorization: `Bearer ${token}`,
},
data: undefined,
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
it('includes version along with accept header', async () => {
const client = buildClient({ ...configWithoutHeaders, version: 'api-version' })
const response = await client.request('GET', 'my/path')
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/my/path',
method: 'GET',
headers: {
Accept: 'application/vnd.smartthings+json;v=api-version',
Authorization: `Bearer ${token}`,
},
data: undefined,
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
it('adds header overrides to headers submitted', async () => {
const headerOverrides = {
'Content-Type': 'overridden content type',
'X-ST-Organization': '00000000-0000-0000-0000-000000000008',
}
const response = await client.request('POST', 'my/path', { name: 'Bob' }, undefined, { headerOverrides })
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/my/path',
method: 'POST',
headers: {
'Content-Type': 'overridden content type',
Accept: 'application/json',
Authorization: `Bearer ${token}`,
'X-ST-Organization': '00000000-0000-0000-0000-000000000008',
},
data: { name: 'Bob' },
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
it('includes logging id when specified', async () => {
const client = buildClient({ ...configWithoutHeaders, loggingId: 'request-logging-id' })
const response = await client.request('GET', 'my/path')
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/my/path',
method: 'GET',
headers: {
Authorization: `Bearer ${token}`,
'X-ST-CORRELATION': 'request-logging-id',
},
data: undefined,
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
it('calls warningLogger when included and needed', async () => {
const warningLogger = jest.fn()
client = buildClient({ ...configWithoutHeaders, warningLogger })
mockRequest.mockResolvedValueOnce({
status: 200,
data: { status: 'ok' },
headers: { warning: '299 - "Danger, Will Robinson! Danger!"' },
} as AxiosResponse)
const response = await client.request('GET', 'my/path')
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/my/path',
method: 'GET',
headers: {
Authorization: `Bearer ${token}`,
},
data: undefined,
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
expect(warningLogger).toHaveBeenCalledTimes(1)
expect(warningLogger).toHaveBeenCalledWith([{
code: 299,
agent: '-',
text: 'Danger, Will Robinson! Danger!',
}])
})
it('is okay with no warningLogger', async () => {
mockRequest.mockResolvedValueOnce({
status: 200,
data: { status: 'ok' },
headers: { warning: 'warning message in header' },
} as AxiosResponse)
expect(client.request('GET', 'my/path')).resolves.not.toThrow
})
it('returns dryRunReturnValue in dry run mode', async () => {
const dryRunReturnValue = { usually: 'very similar to the input' }
const response = await client.request('GET', 'my/path', undefined, undefined, {
dryRun: true,
dryRunReturnValue,
})
expect(mockRequest).toHaveBeenCalledTimes(0)
expect(response).toBe(dryRunReturnValue)
})
it('throws error in dry run mode when return value not specified', async () => {
await expect(client.request('GET', 'my/path', undefined, undefined, {
dryRun: true,
})).rejects.toThrow('skipping request; dry run mode')
expect(mockRequest).toHaveBeenCalledTimes(0)
})
})
describe('get', () => {
it('submits basic request', async () => {
const response = await client.get('path2')
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/path2',
method: 'get',
headers: {
...headers,
Authorization: `Bearer ${token}`,
},
data: undefined,
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
it('includes query params when specified', async () => {
const response = await client.get('my/path', { locationId: 'XXX' })
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/my/path',
method: 'get',
headers: {
...headers,
Authorization: `Bearer ${token}`,
},
data: undefined,
params: {
locationId: 'XXX',
},
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
it('skips base path with absolute path', async () => {
const response = await client.get('/base2/this/path')
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base2/this/path',
method: 'get',
headers: {
...headers,
Authorization: `Bearer ${token}`,
},
data: undefined,
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
it('skips base URL and path with absolute URL', async () => {
const response = await client.get('https://api.smartthings.com/absolute/url')
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/absolute/url',
method: 'get',
headers: {
...headers,
Authorization: `Bearer ${token}`,
},
data: undefined,
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
})
test('post', async () => {
const response = await client.post('myotherpath', { name: 'Bill' })
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/myotherpath',
method: 'post',
headers: {
...headers,
Authorization: `Bearer ${token}`,
},
data: {
name: 'Bill',
},
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
test('put', async () => {
const response = await client.put('myotherpath', { name: 'Bill' })
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/myotherpath',
method: 'put',
headers: {
...headers,
Authorization: `Bearer ${token}`,
},
data: {
name: 'Bill',
},
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
test('patch', async () => {
const response = await client.patch('path3', { name: 'Joe' })
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/path3',
method: 'patch',
headers: {
...headers,
Authorization: `Bearer ${token}`,
},
data: {
name: 'Joe',
},
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
test('delete', async () => {
const response = await client.delete('path3')
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(mockRequest).toHaveBeenCalledWith({
url: 'https://api.smartthings.com/base/path/path3',
method: 'delete',
headers: {
...headers,
Authorization: `Bearer ${token}`,
},
data: undefined,
params: undefined,
paramsSerializer: expect.any(Function),
})
expect(response.status).toBe('ok')
})
test('expired token request', async () => {
mockRequest
.mockImplementationOnce(() => Promise.reject(
{ response: {status: 401, data: 'Unauthorized'} }))
.mockImplementationOnce(() => Promise.resolve(
{ status: 200, data: { access_token: 'my-access-token', refresh_token: 'my-refresh-token' } } as AxiosResponse))
.mockImplementationOnce(() => Promise.resolve(
{ status: 200, data: { status: 'ok' } } as AxiosResponse))
const response = await client.get('my/path')
expect(mockRequest).toHaveBeenCalledTimes(3)
expect(response.status).toBe('ok')
})
test('expired token request with mutex', async () => {
// TODO -- actually test mutex??
const mutex = new Mutex()
const mutexConfig = {
authenticator: new SequentialRefreshTokenAuthenticator(token, tokenStore, mutex),
baseURL: 'https://api.smartthings.com',
authURL: 'https://auth.smartthings.com',
headers: { ...headers },
}
const mutexClient = buildClient(mutexConfig)
mockRequest
.mockImplementationOnce(() => Promise.reject(
{response: { status: 401, data: 'Unauthorized' }}))
.mockImplementationOnce(() => Promise.resolve(
{ status: 200, data: { access_token: 'my-access-token', refresh_token: 'my-refresh-token' } } as AxiosResponse))
.mockImplementationOnce(() => Promise.resolve(
{ status: 200, data: { status: 'ok' } } as AxiosResponse))
const response = await mutexClient.get('my/path')
expect(mockRequest).toHaveBeenCalledTimes(3)
expect(response.status).toBe('ok')
})
test('get 404', async () => {
mockRequest.mockImplementationOnce(() => Promise.reject({response: { status: 404, data: 'Not Found' }}))
let threwError = false
try {
await client.get('path2')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
expect(error.response.status).toBe(404)
threwError = true
}
expect(mockRequest).toHaveBeenCalledTimes(1)
expect(threwError).toBe(true)
})
test('get refresh fail', async () => {
mockRequest
.mockImplementationOnce(() => Promise.reject({response: { status: 401, data: 'Unauthorized' }}))
.mockImplementationOnce(() => Promise.reject({response: { status: 500, data: 'Server error' }}))
let threwError = false
try {
await client.get('path2')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
expect(error.response.status).toBe(500)
threwError = true
}
expect(mockRequest).toHaveBeenCalledTimes(2)
expect(threwError).toBe(true)
})
describe('request logging', () => {
jest.spyOn(NoLogLogger.prototype, 'isDebugEnabled').mockReturnValue(true)
const debugSpy = jest.spyOn(NoLogLogger.prototype, 'debug')
it('partially redacts bearer token in request log', async () => {
const bearerToken = '00000000-0000-0000-0000-000000000000'
const config: EndpointClientConfig = {
authenticator: new BearerTokenAuthenticator(bearerToken),
logger: new NoLogLogger,
}
const bearerClient = new EndpointClient('basePath', config)
await bearerClient.get('')
expect(debugSpy).toBeCalled()
expect(debugSpy).not.toBeCalledWith(expect.stringContaining(bearerToken))
expect(debugSpy).toBeCalledWith(expect.stringContaining('Bearer 00000000'))
})
it('fully redacts Auth header when Bearer is not present', async () => {
const basicAuth = Buffer.from('username:password', 'ascii').toString('base64')
class BasicAuthenticator implements Authenticator {
authenticate(requestConfig: AxiosRequestConfig): Promise<AxiosRequestConfig> {
return Promise.resolve({
...requestConfig,
headers: {
...requestConfig.headers,
Authorization: `Basic ${basicAuth}`,
},
})
}
}
const config: EndpointClientConfig = {
authenticator: new BasicAuthenticator,
logger: new NoLogLogger(),
}
const basicClient = new EndpointClient('basePath', config)
await basicClient.get('')
expect(debugSpy).toBeCalled()
expect(debugSpy).not.toBeCalledWith(expect.stringContaining(basicAuth))
expect(debugSpy).toBeCalledWith(expect.stringContaining('Authorization":"(redacted)"'))
})
describe('getPagedItems', () => {
const getMock = jest.fn()
const client = new EndpointClient('paged-thing', {
authenticator: new NoOpAuthenticator(),
logger: new NoLogLogger(),
})
client.get = getMock
const item1 = { name: 'item-1' }
const item2 = { name: 'item-2' }
it('uses single get when full results returned in one go', async () => {
getMock.mockResolvedValueOnce({
items: [item1, item2],
})
expect(await client.getPagedItems()).toEqual([item1, item2])
expect(getMock).toHaveBeenCalledTimes(1)
expect(getMock).toHaveBeenCalledWith(undefined, undefined, undefined)
})
it('combines multiple pages', async () => {
const params = { paramName: 'param-value' }
const options = { dryRun: false }
getMock
.mockResolvedValueOnce({ items: [item1], _links: { next: { href: 'next-url' } } })
.mockResolvedValueOnce({ items: [item2] })
expect(await client.getPagedItems('first-url', params, options)).toEqual([item1, item2])
expect(getMock).toHaveBeenCalledTimes(2)
expect(getMock).toHaveBeenCalledWith('first-url', params, options)
expect(getMock).toHaveBeenCalledWith('next-url', undefined, options)
})
})
})
})