@clickup/rest-client 2.10.296 → 2.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.eslintrc.base.js +10 -1
  2. package/.eslintrc.js +4 -4
  3. package/.github/workflows/ci.yml +26 -0
  4. package/.github/workflows/semgrep.yml +36 -0
  5. package/.prettierrc +8 -0
  6. package/.vscode/extensions.json +8 -0
  7. package/.vscode/tasks.json +20 -0
  8. package/babel.config.js +5 -0
  9. package/dist/.eslintcache +1 -1
  10. package/dist/RestClient.d.ts +1 -3
  11. package/dist/RestClient.d.ts.map +1 -1
  12. package/dist/RestClient.js +3 -4
  13. package/dist/RestClient.js.map +1 -1
  14. package/dist/RestOptions.d.ts +2 -2
  15. package/dist/RestOptions.d.ts.map +1 -1
  16. package/dist/RestOptions.js +1 -0
  17. package/dist/RestOptions.js.map +1 -1
  18. package/dist/RestRequest.d.ts +0 -2
  19. package/dist/RestRequest.d.ts.map +1 -1
  20. package/dist/RestRequest.js +12 -5
  21. package/dist/RestRequest.js.map +1 -1
  22. package/dist/RestResponse.d.ts +0 -1
  23. package/dist/RestResponse.d.ts.map +1 -1
  24. package/dist/helpers/depaginate.js +1 -1
  25. package/dist/helpers/depaginate.js.map +1 -1
  26. package/dist/index.d.ts +2 -5
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -5
  29. package/dist/index.js.map +1 -1
  30. package/dist/internal/RestFetchReader.d.ts +3 -3
  31. package/dist/internal/RestFetchReader.d.ts.map +1 -1
  32. package/dist/internal/RestFetchReader.js +21 -11
  33. package/dist/internal/RestFetchReader.js.map +1 -1
  34. package/dist/internal/RestRangeUploader.d.ts +0 -1
  35. package/dist/internal/RestRangeUploader.d.ts.map +1 -1
  36. package/dist/internal/calcRetryDelay.js +1 -1
  37. package/dist/internal/calcRetryDelay.js.map +1 -1
  38. package/dist/internal/ellipsis.d.ts +6 -0
  39. package/dist/internal/ellipsis.d.ts.map +1 -0
  40. package/dist/internal/ellipsis.js +17 -0
  41. package/dist/internal/ellipsis.js.map +1 -0
  42. package/dist/internal/inferResBodyEncoding.d.ts +0 -1
  43. package/dist/internal/inferResBodyEncoding.d.ts.map +1 -1
  44. package/dist/internal/inferResBodyEncoding.js +1 -1
  45. package/dist/internal/inferResBodyEncoding.js.map +1 -1
  46. package/dist/internal/inspectPossibleJSON.d.ts +0 -2
  47. package/dist/internal/inspectPossibleJSON.d.ts.map +1 -1
  48. package/dist/internal/inspectPossibleJSON.js +6 -9
  49. package/dist/internal/inspectPossibleJSON.js.map +1 -1
  50. package/dist/internal/prependNewlineIfMultiline.js +1 -1
  51. package/dist/internal/prependNewlineIfMultiline.js.map +1 -1
  52. package/dist/internal/substituteParams.js +1 -1
  53. package/dist/internal/substituteParams.js.map +1 -1
  54. package/dist/internal/throwIfErrorResponse.js +2 -2
  55. package/dist/internal/throwIfErrorResponse.js.map +1 -1
  56. package/dist/internal/toFloatMs.js +1 -1
  57. package/dist/internal/toFloatMs.js.map +1 -1
  58. package/dist/middlewares/paceRequests.d.ts +21 -2
  59. package/dist/middlewares/paceRequests.d.ts.map +1 -1
  60. package/dist/middlewares/paceRequests.js +4 -3
  61. package/dist/middlewares/paceRequests.js.map +1 -1
  62. package/docs/interfaces/Pacer.md +7 -12
  63. package/docs/interfaces/PacerOutcome.md +25 -0
  64. package/docs/interfaces/RestOptions.md +22 -47
  65. package/docs/modules.md +4 -7
  66. package/internal/clean.sh +4 -0
  67. package/internal/deploy.sh +7 -0
  68. package/internal/docs.sh +6 -0
  69. package/internal/lint.sh +4 -0
  70. package/jest.config.base.js +18 -0
  71. package/jest.config.js +1 -10
  72. package/package.json +15 -10
  73. package/src/RestClient.ts +2 -2
  74. package/src/RestOptions.ts +3 -0
  75. package/src/RestRequest.ts +32 -5
  76. package/src/__tests__/RestClient.test.ts +53 -0
  77. package/src/__tests__/RestFetchReader.test.ts +154 -0
  78. package/src/__tests__/RestRequest.test.ts +262 -0
  79. package/src/__tests__/RestRequestCacheableLookup.test.ts +88 -0
  80. package/src/__tests__/RestStream.test.ts +67 -0
  81. package/src/__tests__/helpers.ts +173 -0
  82. package/src/index.ts +2 -7
  83. package/src/internal/RestFetchReader.ts +4 -1
  84. package/src/internal/ellipsis.ts +16 -0
  85. package/src/internal/inspectPossibleJSON.ts +1 -5
  86. package/src/internal/throwIfErrorResponse.ts +1 -1
  87. package/src/middlewares/paceRequests.ts +27 -2
  88. package/tsconfig.base.json +31 -0
  89. package/tsconfig.json +1 -31
  90. package/typedoc.config.js +20 -0
  91. package/dist/pacers/Pacer.d.ts +0 -21
  92. package/dist/pacers/Pacer.d.ts.map +0 -1
  93. package/dist/pacers/Pacer.js +0 -3
  94. package/dist/pacers/Pacer.js.map +0 -1
  95. package/dist/pacers/PacerComposite.d.ts +0 -14
  96. package/dist/pacers/PacerComposite.d.ts.map +0 -1
  97. package/dist/pacers/PacerComposite.js +0 -32
  98. package/dist/pacers/PacerComposite.js.map +0 -1
  99. package/dist/pacers/PacerQPS.d.ts +0 -53
  100. package/dist/pacers/PacerQPS.d.ts.map +0 -1
  101. package/dist/pacers/PacerQPS.js +0 -105
  102. package/dist/pacers/PacerQPS.js.map +0 -1
  103. package/docs/classes/PacerComposite.md +0 -66
  104. package/docs/classes/PacerQPS.md +0 -79
  105. package/docs/interfaces/PacerDelay.md +0 -25
  106. package/docs/interfaces/PacerQPSBackend.md +0 -44
  107. package/docs/interfaces/PacerQPSOptions.md +0 -40
  108. package/src/pacers/Pacer.ts +0 -22
  109. package/src/pacers/PacerComposite.ts +0 -29
  110. package/src/pacers/PacerQPS.ts +0 -147
  111. package/typedoc.json +0 -22
@@ -1,15 +1,38 @@
1
- import type Pacer from "../pacers/Pacer";
2
1
  import type { Middleware } from "../RestOptions";
3
2
  import type RestRequest from "../RestRequest";
4
3
 
5
4
  const MIN_LOG_DELAY_MS = 10;
6
5
 
6
+ /**
7
+ * Pacer is a class which allows to pace requests on some resource identified by
8
+ * the instance of this class.
9
+ */
10
+ export interface Pacer {
11
+ /** Human readable name of the pacer, used when composing multiple pacers. */
12
+ readonly key: string;
13
+
14
+ /**
15
+ * Signals that we're about to send a request. Returns the delay we need to
16
+ * wait for before actually sending.
17
+ */
18
+ pace(): Promise<PacerOutcome>;
19
+ }
20
+
21
+ /**
22
+ * A result of some Pacer work.
23
+ */
24
+ export interface PacerOutcome {
25
+ delayMs: number;
26
+ reason: string;
27
+ }
28
+
7
29
  /**
8
30
  * Rest Client middleware that adds some delay between requests using one of
9
31
  * Pacer implementations.
10
32
  */
11
33
  export default function paceRequests(
12
34
  pacer: Pacer | ((req: RestRequest) => Promise<Pacer | null>) | null,
35
+ delayMetric?: (delay: number, reason: string) => void,
13
36
  ): Middleware {
14
37
  return async (req, next) => {
15
38
  if (typeof pacer === "function") {
@@ -17,8 +40,10 @@ export default function paceRequests(
17
40
  }
18
41
 
19
42
  if (pacer) {
20
- const { delayMs, reason } = await pacer.touch();
43
+ const { delayMs, reason } = await pacer.pace();
44
+
21
45
  if (delayMs > 0) {
46
+ delayMetric?.(delayMs, reason);
22
47
  await req.options.heartbeater.delay(delayMs);
23
48
  }
24
49
 
@@ -0,0 +1,31 @@
1
+ {
2
+ "include": ["src/**/*"],
3
+ "compilerOptions": {
4
+ "allowJs": true,
5
+ "declaration": true,
6
+ "declarationMap": true,
7
+ "disableReferencedProjectLoad": true,
8
+ "disableSourceOfProjectReferenceRedirect": true,
9
+ "esModuleInterop": true,
10
+ "experimentalDecorators": true,
11
+ "incremental": true,
12
+ "lib": ["ES2019"],
13
+ "module": "Node16",
14
+ "noEmitOnError": true,
15
+ "noErrorTruncation": true,
16
+ "noImplicitOverride": true,
17
+ "noImplicitReturns": true,
18
+ "noPropertyAccessFromIndexSignature": true,
19
+ "outDir": "dist",
20
+ "pretty": true,
21
+ "removeComments": false,
22
+ "resolveJsonModule": true,
23
+ "rootDir": "src",
24
+ "skipLibCheck": true,
25
+ "sourceMap": true,
26
+ "strict": true,
27
+ "target": "ES2019",
28
+ "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo",
29
+ "types": ["node", "jest"]
30
+ }
31
+ }
package/tsconfig.json CHANGED
@@ -1,31 +1 @@
1
- {
2
- "include": ["src/**/*"],
3
- "compilerOptions": {
4
- "allowJs": true,
5
- "declaration": true,
6
- "declarationMap": true,
7
- "disableReferencedProjectLoad": true,
8
- "disableSourceOfProjectReferenceRedirect": true,
9
- "esModuleInterop": true,
10
- "experimentalDecorators": true,
11
- "incremental": true,
12
- "lib": ["ES2019"],
13
- "module": "Node16",
14
- "noEmitOnError": true,
15
- "noErrorTruncation": true,
16
- "noImplicitOverride": true,
17
- "noImplicitReturns": true,
18
- "noPropertyAccessFromIndexSignature": true,
19
- "outDir": "dist",
20
- "pretty": true,
21
- "removeComments": false,
22
- "resolveJsonModule": true,
23
- "rootDir": "src",
24
- "skipLibCheck": true,
25
- "sourceMap": true,
26
- "strict": true,
27
- "target": "ES2019",
28
- "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo",
29
- "types": ["node", "jest"]
30
- }
31
- }
1
+ { "extends": "./tsconfig.base.json" }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ const { basename } = require("path");
3
+
4
+ module.exports = {
5
+ entryPoints: ["src"],
6
+ exclude: ["**/internal/**", "**/__tests__/**", "**/node_modules/**"],
7
+ entryPointStrategy: "expand",
8
+ mergeModulesMergeMode: "project",
9
+ sort: ["source-order"],
10
+ out: "docs",
11
+ logLevel: "Warn",
12
+ hideGenerator: true,
13
+ excludeInternal: true,
14
+ excludePrivate: true,
15
+ categorizeByGroup: true,
16
+ hideInPageTOC: true,
17
+ gitRevision: "master",
18
+ sourceLinkTemplate: `https://github.com/clickup/${basename(__dirname)}/blob/master/{path}#L{line}`,
19
+ basePath: ".",
20
+ };
@@ -1,21 +0,0 @@
1
- /**
2
- * A result of some Pacer work.
3
- */
4
- export interface PacerDelay {
5
- delayMs: number;
6
- reason: string;
7
- }
8
- /**
9
- * Pacer is a class which allows to pace requests on some resource identified by
10
- * the instance of this class.
11
- */
12
- export default interface Pacer {
13
- /** Human readable name of the pacer, used when composing multiple pacers. */
14
- readonly name: string;
15
- /**
16
- * Signals that we're about to send a request. Returns the delay we need to
17
- * wait for before actually sending.
18
- */
19
- touch(): Promise<PacerDelay>;
20
- }
21
- //# sourceMappingURL=Pacer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Pacer.d.ts","sourceRoot":"","sources":["../../src/pacers/Pacer.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,WAAW,KAAK;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CAC9B"}
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=Pacer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Pacer.js","sourceRoot":"","sources":["../../src/pacers/Pacer.ts"],"names":[],"mappings":""}
@@ -1,14 +0,0 @@
1
- import type Pacer from "./Pacer";
2
- /**
3
- * A Pacer which runs all sub-pacers and chooses the largest delay.
4
- */
5
- export default class PacerComposite implements Pacer {
6
- private _pacers;
7
- readonly name = "";
8
- constructor(_pacers: Pacer[]);
9
- touch(): Promise<{
10
- reason: string;
11
- delayMs: number;
12
- }>;
13
- }
14
- //# sourceMappingURL=PacerComposite.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PacerComposite.d.ts","sourceRoot":"","sources":["../../src/pacers/PacerComposite.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AAEjC;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,cAAe,YAAW,KAAK;IAGtC,OAAO,CAAC,OAAO;IAF3B,QAAQ,CAAC,IAAI,MAAM;gBAEC,OAAO,EAAE,KAAK,EAAE;IAE9B,KAAK;;;;CAiBZ"}
@@ -1,32 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const maxBy_1 = __importDefault(require("lodash/maxBy"));
7
- /**
8
- * A Pacer which runs all sub-pacers and chooses the largest delay.
9
- */
10
- class PacerComposite {
11
- constructor(_pacers) {
12
- this._pacers = _pacers;
13
- this.name = "";
14
- }
15
- async touch() {
16
- const delays = await Promise["all"](this._pacers.map(async (pacer) => ({
17
- pacer,
18
- delay: await pacer.touch(),
19
- })));
20
- const pair = (0, maxBy_1.default)(delays, ({ delay }) => delay.delayMs);
21
- return pair
22
- ? {
23
- ...pair.delay,
24
- reason: pair.pacer.name
25
- ? `${pair.pacer.constructor.name} ${pair.pacer.name}\n${pair.delay.reason}`
26
- : pair.delay.reason,
27
- }
28
- : { delayMs: 0, reason: "no pacers" };
29
- }
30
- }
31
- exports.default = PacerComposite;
32
- //# sourceMappingURL=PacerComposite.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PacerComposite.js","sourceRoot":"","sources":["../../src/pacers/PacerComposite.ts"],"names":[],"mappings":";;;;;AAAA,yDAAiC;AAGjC;;GAEG;AACH,MAAqB,cAAc;IAGjC,YAAoB,OAAgB;QAAhB,YAAO,GAAP,OAAO,CAAS;QAF3B,SAAI,GAAG,EAAE,CAAC;IAEoB,CAAC;IAExC,KAAK,CAAC,KAAK;QACT,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CACjC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YACjC,KAAK;YACL,KAAK,EAAE,MAAM,KAAK,CAAC,KAAK,EAAE;SAC3B,CAAC,CAAC,CACJ,CAAC;QACF,MAAM,IAAI,GAAG,IAAA,eAAK,EAAC,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACzD,OAAO,IAAI;YACT,CAAC,CAAC;gBACE,GAAG,IAAI,CAAC,KAAK;gBACb,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;oBACrB,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;oBAC3E,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;aACtB;YACH,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC1C,CAAC;CACF;AAtBD,iCAsBC"}
@@ -1,53 +0,0 @@
1
- import type { PacerDelay } from "./Pacer";
2
- import type Pacer from "./Pacer";
3
- export interface PacerQPSBackend {
4
- /** Resource key which this backend is operating on. */
5
- readonly key: string;
6
- /**
7
- * Maintains the array of numbers somewhere in memory (time-value pairs),
8
- * inserts a new time-value pair to the end of this list, and removes all the
9
- * entries which are earlier than `minTime`. Returns the size of the resulting
10
- * array and some central tendency statistics about its values.
11
- */
12
- push(props: {
13
- time: number;
14
- minTime: number;
15
- value: number;
16
- minCountForCentralTendency: number;
17
- }): Promise<{
18
- count: number;
19
- sum: number;
20
- avg: number;
21
- median: number;
22
- }>;
23
- }
24
- export interface PacerQPSOptions {
25
- /** The maximum QPS allowed within the rolling window. */
26
- qps: number;
27
- /** The length of the rolling windows in milliseconds. */
28
- windowSec?: number;
29
- /** Decrease the delay if the number of requests in the window has dropped
30
- * below `decreaseThreshold` portion of the limit. */
31
- decreaseThreshold?: number;
32
- }
33
- /**
34
- * Implements a very simple heuristic:
35
- * - increase the delay if we're above the QPS within the rolling window;
36
- * - decrease the delay if we're below the desired QPS.
37
- *
38
- * Each worker keeps (and grows/shrinks) its delay individually; this way, we
39
- * don't need to elect, who's the "source of truth" for the delay.
40
- *
41
- * Backend is a concrete (and minimal) implementation of the storage logic for
42
- * the pacing algorithm.
43
- */
44
- export default class PacerQPS implements Pacer {
45
- private _options;
46
- private _backend;
47
- private _isFirstTouch;
48
- private _delay;
49
- constructor(_options: PacerQPSOptions, _backend: PacerQPSBackend);
50
- get name(): string;
51
- touch(): Promise<PacerDelay>;
52
- }
53
- //# sourceMappingURL=PacerQPS.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PacerQPS.d.ts","sourceRoot":"","sources":["../../src/pacers/PacerQPS.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AA4BjC,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB;;;;;OAKG;IACH,IAAI,CAAC,KAAK,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,0BAA0B,EAAE,MAAM,CAAC;KACpC,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1E;AAED,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;yDACqD;IACrD,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,OAAO,OAAO,QAAS,YAAW,KAAK;IAK1C,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,QAAQ;IALlB,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,MAAM,CAAK;gBAGT,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,eAAe;IAGnC,IAAI,IAAI,WAEP;IAEK,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC;CAgEnC"}
@@ -1,105 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const random_1 = __importDefault(require("lodash/random"));
7
- /** Start decreasing the delay (and thus speeding up requests) only when we have
8
- * less requests in the moving window than allowed by the desired QPS multiplied
9
- * by this factor. I.e. we don't speed up immediately when we're slow; we wait
10
- * until we're SLIGHTLY below the limits. */
11
- const DEFAULT_DECREASE_THRESHOLD = 0.75;
12
- /** Default moving window length. */
13
- const DEFAULT_WINDOW_SEC = 30;
14
- /** Below how many samples do we stop relying on samples to recalculate the
15
- * current fleet's average delay and instead keep using the previously
16
- * calculated (and saved) value for the delay. E.g. it doesn't make much sense
17
- * to rely on an average of 3-4 samples to calculate the average delay, it makes
18
- * sense to wait for more samples to come. */
19
- const MIN_COUNT_FOR_CENTRAL_TENDENCY = 10;
20
- /** The value here is multiplied by the fleet average to get the delay
21
- * increment/decrement step. It basically determines, in how many increments
22
- * would a "cold started" worker reach the current fleet's average delay. Or, in
23
- * how many steps would it reach delay=0 situation from the current fleet's
24
- * average if needed. */
25
- const DELAY_AVG_TO_STEP_FACTOR = 0.02;
26
- /** Delay increments are jittered by +/- this proportion. */
27
- const DELAY_STEP_JITTER = 0.1;
28
- /**
29
- * Implements a very simple heuristic:
30
- * - increase the delay if we're above the QPS within the rolling window;
31
- * - decrease the delay if we're below the desired QPS.
32
- *
33
- * Each worker keeps (and grows/shrinks) its delay individually; this way, we
34
- * don't need to elect, who's the "source of truth" for the delay.
35
- *
36
- * Backend is a concrete (and minimal) implementation of the storage logic for
37
- * the pacing algorithm.
38
- */
39
- class PacerQPS {
40
- constructor(_options, _backend) {
41
- this._options = _options;
42
- this._backend = _backend;
43
- this._isFirstTouch = true;
44
- this._delay = 0;
45
- }
46
- get name() {
47
- return this._backend.key;
48
- }
49
- async touch() {
50
- var _a, _b;
51
- const windowSec = (_a = this._options.windowSec) !== null && _a !== void 0 ? _a : DEFAULT_WINDOW_SEC;
52
- const limit = Math.round(windowSec * this._options.qps);
53
- const decreaseThreshold = (_b = this._options.decreaseThreshold) !== null && _b !== void 0 ? _b : DEFAULT_DECREASE_THRESHOLD;
54
- const time = Date.now();
55
- const delayPushed = this._delay;
56
- const { count, sum, avg, median } = await this._backend.push({
57
- time,
58
- minTime: time - windowSec * 1000,
59
- value: this._delay,
60
- minCountForCentralTendency: MIN_COUNT_FOR_CENTRAL_TENDENCY,
61
- });
62
- const sumDivCount = count ? sum / count : 0;
63
- // "Cold start": start with the fleet average delay.
64
- if (this._isFirstTouch && this._delay === 0) {
65
- this._delay = Math.round(avg);
66
- this._isFirstTouch = false;
67
- }
68
- // If we imagine there is only 1 worker in the fleet, what would be its
69
- // delay increment/decrement step. We use this number in a fallback
70
- // situation, when we don't know much about the entire fleet average delay
71
- // yet, or when this delay is too small to count on.
72
- const singleWorkerDelayStepMs = Math.round(((windowSec * 1000) / limit) * DELAY_AVG_TO_STEP_FACTOR);
73
- // Considering that there are multiple workers running, and that the current
74
- // average fleet's delay is representative, what would be a delay increment
75
- // to reach from delay=0 to that fleet's average delay.
76
- const multiWorkerDelayStepMs = Math.round(avg *
77
- DELAY_AVG_TO_STEP_FACTOR *
78
- (0, random_1.default)(1 - DELAY_STEP_JITTER, 1 + DELAY_STEP_JITTER, true));
79
- // If average fleet delay is not representative yet, we fallback to a
80
- // single-worker delay increment.
81
- const delayStepMs = multiWorkerDelayStepMs || singleWorkerDelayStepMs || 1;
82
- if (count > limit) {
83
- // Increase the delay if the limit is reached. There is no "max delay":
84
- // imagine we have 10 QPS limit and 10000 users; it's obvious that in this
85
- // case, the delay between requests per a single user will be gigantic.
86
- this._delay += delayStepMs;
87
- }
88
- else if (count < limit * decreaseThreshold) {
89
- // Decrease the delay if we're significantly under the limit.
90
- this._delay = Math.max(0, this._delay - delayStepMs);
91
- }
92
- return {
93
- delayMs: this._delay,
94
- reason: [
95
- `count=${count} per ${windowSec}s (limit=${limit})`,
96
- `delay=${this._delay} step=${delayStepMs} delayPushed=${delayPushed}`,
97
- `median=${Math.round(median)}`,
98
- `sum/count=${Math.round(sumDivCount)}`,
99
- `avg=${Math.round(avg)}`,
100
- ].join("\n"),
101
- };
102
- }
103
- }
104
- exports.default = PacerQPS;
105
- //# sourceMappingURL=PacerQPS.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PacerQPS.js","sourceRoot":"","sources":["../../src/pacers/PacerQPS.ts"],"names":[],"mappings":"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"}
@@ -1,66 +0,0 @@
1
- [@clickup/rest-client](../README.md) / [Exports](../modules.md) / PacerComposite
2
-
3
- # Class: PacerComposite
4
-
5
- A Pacer which runs all sub-pacers and chooses the largest delay.
6
-
7
- ## Implements
8
-
9
- - [`Pacer`](../interfaces/Pacer.md)
10
-
11
- ## Constructors
12
-
13
- ### constructor
14
-
15
- • **new PacerComposite**(`_pacers`): [`PacerComposite`](PacerComposite.md)
16
-
17
- #### Parameters
18
-
19
- | Name | Type |
20
- | :------ | :------ |
21
- | `_pacers` | [`Pacer`](../interfaces/Pacer.md)[] |
22
-
23
- #### Returns
24
-
25
- [`PacerComposite`](PacerComposite.md)
26
-
27
- #### Defined in
28
-
29
- [src/pacers/PacerComposite.ts:10](https://github.com/clickup/rest-client/blob/master/src/pacers/PacerComposite.ts#L10)
30
-
31
- ## Properties
32
-
33
- ### name
34
-
35
- • `Readonly` **name**: ``""``
36
-
37
- Human readable name of the pacer, used when composing multiple pacers.
38
-
39
- #### Implementation of
40
-
41
- [Pacer](../interfaces/Pacer.md).[name](../interfaces/Pacer.md#name)
42
-
43
- #### Defined in
44
-
45
- [src/pacers/PacerComposite.ts:8](https://github.com/clickup/rest-client/blob/master/src/pacers/PacerComposite.ts#L8)
46
-
47
- ## Methods
48
-
49
- ### touch
50
-
51
- ▸ **touch**(): `Promise`\<\{ `delayMs`: `number` ; `reason`: `string` }\>
52
-
53
- Signals that we're about to send a request. Returns the delay we need to
54
- wait for before actually sending.
55
-
56
- #### Returns
57
-
58
- `Promise`\<\{ `delayMs`: `number` ; `reason`: `string` }\>
59
-
60
- #### Implementation of
61
-
62
- [Pacer](../interfaces/Pacer.md).[touch](../interfaces/Pacer.md#touch)
63
-
64
- #### Defined in
65
-
66
- [src/pacers/PacerComposite.ts:12](https://github.com/clickup/rest-client/blob/master/src/pacers/PacerComposite.ts#L12)
@@ -1,79 +0,0 @@
1
- [@clickup/rest-client](../README.md) / [Exports](../modules.md) / PacerQPS
2
-
3
- # Class: PacerQPS
4
-
5
- Implements a very simple heuristic:
6
- - increase the delay if we're above the QPS within the rolling window;
7
- - decrease the delay if we're below the desired QPS.
8
-
9
- Each worker keeps (and grows/shrinks) its delay individually; this way, we
10
- don't need to elect, who's the "source of truth" for the delay.
11
-
12
- Backend is a concrete (and minimal) implementation of the storage logic for
13
- the pacing algorithm.
14
-
15
- ## Implements
16
-
17
- - [`Pacer`](../interfaces/Pacer.md)
18
-
19
- ## Constructors
20
-
21
- ### constructor
22
-
23
- • **new PacerQPS**(`_options`, `_backend`): [`PacerQPS`](PacerQPS.md)
24
-
25
- #### Parameters
26
-
27
- | Name | Type |
28
- | :------ | :------ |
29
- | `_options` | [`PacerQPSOptions`](../interfaces/PacerQPSOptions.md) |
30
- | `_backend` | [`PacerQPSBackend`](../interfaces/PacerQPSBackend.md) |
31
-
32
- #### Returns
33
-
34
- [`PacerQPS`](PacerQPS.md)
35
-
36
- #### Defined in
37
-
38
- [src/pacers/PacerQPS.ts:74](https://github.com/clickup/rest-client/blob/master/src/pacers/PacerQPS.ts#L74)
39
-
40
- ## Accessors
41
-
42
- ### name
43
-
44
- • `get` **name**(): `string`
45
-
46
- Human readable name of the pacer, used when composing multiple pacers.
47
-
48
- #### Returns
49
-
50
- `string`
51
-
52
- #### Implementation of
53
-
54
- [Pacer](../interfaces/Pacer.md).[name](../interfaces/Pacer.md#name)
55
-
56
- #### Defined in
57
-
58
- [src/pacers/PacerQPS.ts:79](https://github.com/clickup/rest-client/blob/master/src/pacers/PacerQPS.ts#L79)
59
-
60
- ## Methods
61
-
62
- ### touch
63
-
64
- ▸ **touch**(): `Promise`\<[`PacerDelay`](../interfaces/PacerDelay.md)\>
65
-
66
- Signals that we're about to send a request. Returns the delay we need to
67
- wait for before actually sending.
68
-
69
- #### Returns
70
-
71
- `Promise`\<[`PacerDelay`](../interfaces/PacerDelay.md)\>
72
-
73
- #### Implementation of
74
-
75
- [Pacer](../interfaces/Pacer.md).[touch](../interfaces/Pacer.md#touch)
76
-
77
- #### Defined in
78
-
79
- [src/pacers/PacerQPS.ts:83](https://github.com/clickup/rest-client/blob/master/src/pacers/PacerQPS.ts#L83)
@@ -1,25 +0,0 @@
1
- [@clickup/rest-client](../README.md) / [Exports](../modules.md) / PacerDelay
2
-
3
- # Interface: PacerDelay
4
-
5
- A result of some Pacer work.
6
-
7
- ## Properties
8
-
9
- ### delayMs
10
-
11
- • **delayMs**: `number`
12
-
13
- #### Defined in
14
-
15
- [src/pacers/Pacer.ts:5](https://github.com/clickup/rest-client/blob/master/src/pacers/Pacer.ts#L5)
16
-
17
- ___
18
-
19
- ### reason
20
-
21
- • **reason**: `string`
22
-
23
- #### Defined in
24
-
25
- [src/pacers/Pacer.ts:6](https://github.com/clickup/rest-client/blob/master/src/pacers/Pacer.ts#L6)
@@ -1,44 +0,0 @@
1
- [@clickup/rest-client](../README.md) / [Exports](../modules.md) / PacerQPSBackend
2
-
3
- # Interface: PacerQPSBackend
4
-
5
- ## Properties
6
-
7
- ### key
8
-
9
- • `Readonly` **key**: `string`
10
-
11
- Resource key which this backend is operating on.
12
-
13
- #### Defined in
14
-
15
- [src/pacers/PacerQPS.ts:33](https://github.com/clickup/rest-client/blob/master/src/pacers/PacerQPS.ts#L33)
16
-
17
- ## Methods
18
-
19
- ### push
20
-
21
- ▸ **push**(`props`): `Promise`\<\{ `count`: `number` ; `sum`: `number` ; `avg`: `number` ; `median`: `number` }\>
22
-
23
- Maintains the array of numbers somewhere in memory (time-value pairs),
24
- inserts a new time-value pair to the end of this list, and removes all the
25
- entries which are earlier than `minTime`. Returns the size of the resulting
26
- array and some central tendency statistics about its values.
27
-
28
- #### Parameters
29
-
30
- | Name | Type |
31
- | :------ | :------ |
32
- | `props` | `Object` |
33
- | `props.time` | `number` |
34
- | `props.minTime` | `number` |
35
- | `props.value` | `number` |
36
- | `props.minCountForCentralTendency` | `number` |
37
-
38
- #### Returns
39
-
40
- `Promise`\<\{ `count`: `number` ; `sum`: `number` ; `avg`: `number` ; `median`: `number` }\>
41
-
42
- #### Defined in
43
-
44
- [src/pacers/PacerQPS.ts:41](https://github.com/clickup/rest-client/blob/master/src/pacers/PacerQPS.ts#L41)
@@ -1,40 +0,0 @@
1
- [@clickup/rest-client](../README.md) / [Exports](../modules.md) / PacerQPSOptions
2
-
3
- # Interface: PacerQPSOptions
4
-
5
- ## Properties
6
-
7
- ### qps
8
-
9
- • **qps**: `number`
10
-
11
- The maximum QPS allowed within the rolling window.
12
-
13
- #### Defined in
14
-
15
- [src/pacers/PacerQPS.ts:51](https://github.com/clickup/rest-client/blob/master/src/pacers/PacerQPS.ts#L51)
16
-
17
- ___
18
-
19
- ### windowSec
20
-
21
- • `Optional` **windowSec**: `number`
22
-
23
- The length of the rolling windows in milliseconds.
24
-
25
- #### Defined in
26
-
27
- [src/pacers/PacerQPS.ts:53](https://github.com/clickup/rest-client/blob/master/src/pacers/PacerQPS.ts#L53)
28
-
29
- ___
30
-
31
- ### decreaseThreshold
32
-
33
- • `Optional` **decreaseThreshold**: `number`
34
-
35
- Decrease the delay if the number of requests in the window has dropped
36
- below `decreaseThreshold` portion of the limit.
37
-
38
- #### Defined in
39
-
40
- [src/pacers/PacerQPS.ts:56](https://github.com/clickup/rest-client/blob/master/src/pacers/PacerQPS.ts#L56)