Skip to content

Commit 44ee159

Browse files
Merge master into feature/stepfunctions-workflow
2 parents 40a0298 + 928593c commit 44ee159

File tree

2 files changed

+39
-45
lines changed

2 files changed

+39
-45
lines changed

packages/core/src/auth/auth.ts

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { SsoClient } from './sso/clients'
2121
import { getLogger } from '../shared/logger'
2222
import { CredentialsProviderManager } from './providers/credentialsProviderManager'
2323
import { asString, CredentialsId, CredentialsProvider, fromString } from './providers/credentials'
24-
import { once } from '../shared/utilities/functionUtils'
24+
import { keyedDebounce, once } from '../shared/utilities/functionUtils'
2525
import { CredentialsSettings } from './credentials/utils'
2626
import {
2727
extractDataFromSection,
@@ -104,23 +104,6 @@ interface AuthService {
104104
updateConnection(connection: Pick<Connection, 'id'>, profile: Profile): Promise<Connection>
105105
}
106106

107-
function keyedDebounce<T, U extends any[], K extends string = string>(
108-
fn: (key: K, ...args: U) => Promise<T>
109-
): typeof fn {
110-
const pending = new Map<K, Promise<T>>()
111-
112-
return (key, ...args) => {
113-
if (pending.has(key)) {
114-
return pending.get(key)!
115-
}
116-
117-
const promise = fn(key, ...args).finally(() => pending.delete(key))
118-
pending.set(key, promise)
119-
120-
return promise
121-
}
122-
}
123-
124107
export interface ConnectionStateChangeEvent {
125108
readonly id: Connection['id']
126109
readonly state: ProfileMetadata['connectionState']

packages/core/src/shared/utilities/functionUtils.ts

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -85,38 +85,28 @@ export function memoize<T, U extends any[]>(fn: (...args: U) => T): (...args: U)
8585
* Multiple calls made during the debounce window will receive references to the
8686
* same Promise similar to {@link shared}. The window will also be 'rolled', delaying
8787
* the execution by another {@link delay} milliseconds.
88+
*
89+
* This function prevents execution until {@link delay} milliseconds have passed
90+
* since the last invocation regardless of arguments. If this should be
91+
* argument dependent, look into {@link keyedDebounce}
8892
*/
89-
export function debounce<T>(cb: () => T | Promise<T>, delay: number = 0): () => Promise<T> {
90-
let timeout: Timeout | undefined
91-
let promise: Promise<T> | undefined
92-
93-
return () => {
94-
timeout?.refresh()
95-
96-
return (promise ??= new Promise<T>((resolve, reject) => {
97-
timeout = new Timeout(delay)
98-
timeout.onCompletion(async () => {
99-
timeout = promise = undefined
100-
try {
101-
resolve(await cb())
102-
} catch (err) {
103-
reject(err)
104-
}
105-
})
106-
}))
107-
}
93+
export function debounce<Input extends any[], Output>(
94+
cb: (...args: Input) => Output | Promise<Output>,
95+
delay: number = 0
96+
): (...args: Input) => Promise<Output> {
97+
return cancellableDebounce(cb, delay).promise
10898
}
10999

110100
/**
111101
*
112-
* Similar to {@link debounce}, but allows the function to be cancelled and allow callbacks to pass function parameters.
102+
* Similar to {@link debounce}, but allows the function to be cancelled.
113103
*/
114-
export function cancellableDebounce<T, U extends any[]>(
115-
cb: (...args: U) => T | Promise<T>,
104+
export function cancellableDebounce<Input extends any[], Output>(
105+
cb: (...args: Input) => Output | Promise<Output>,
116106
delay: number = 0
117-
): { promise: (...args: U) => Promise<T>; cancel: () => void } {
107+
): { promise: (...args: Input) => Promise<Output>; cancel: () => void } {
118108
let timeout: Timeout | undefined
119-
let promise: Promise<T> | undefined
109+
let promise: Promise<Output> | undefined
120110

121111
const cancel = (): void => {
122112
if (timeout) {
@@ -127,15 +117,15 @@ export function cancellableDebounce<T, U extends any[]>(
127117
}
128118

129119
return {
130-
promise: (...arg) => {
120+
promise: (...args: Input) => {
131121
timeout?.refresh()
132122

133-
return (promise ??= new Promise<T>((resolve, reject) => {
123+
return (promise ??= new Promise<Output>((resolve, reject) => {
134124
timeout = new Timeout(delay)
135125
timeout.onCompletion(async () => {
136126
timeout = promise = undefined
137127
try {
138-
resolve(await cb(...arg))
128+
resolve(await cb(...args))
139129
} catch (err) {
140130
reject(err)
141131
}
@@ -145,3 +135,24 @@ export function cancellableDebounce<T, U extends any[]>(
145135
cancel: cancel,
146136
}
147137
}
138+
139+
/**
140+
*
141+
* Similar to {@link debounce}, but uses a key to determine if the function should be called yet rather than a timeout connected to the function itself.
142+
*/
143+
export function keyedDebounce<T, U extends any[], K extends string = string>(
144+
fn: (key: K, ...args: U) => Promise<T>
145+
): typeof fn {
146+
const pending = new Map<K, Promise<T>>()
147+
148+
return (key, ...args) => {
149+
if (pending.has(key)) {
150+
return pending.get(key)!
151+
}
152+
153+
const promise = fn(key, ...args).finally(() => pending.delete(key))
154+
pending.set(key, promise)
155+
156+
return promise
157+
}
158+
}

0 commit comments

Comments
 (0)