@browserless.io/browserless 2.4.0 → 2.5.0-beta-2

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 (57) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/bin/browserless.js +17 -127
  3. package/bin/scaffold/README.md +95 -14
  4. package/build/browserless.d.ts +5 -3
  5. package/build/browserless.js +10 -6
  6. package/build/browsers/index.d.ts +5 -3
  7. package/build/browsers/index.js +6 -4
  8. package/build/data/selectors.json +1 -1
  9. package/build/exports.d.ts +1 -0
  10. package/build/exports.js +1 -0
  11. package/build/file-system.d.ts +2 -3
  12. package/build/file-system.js +10 -21
  13. package/build/file-system.spec.js +35 -18
  14. package/build/hooks.d.ts +18 -4
  15. package/build/hooks.js +33 -4
  16. package/build/limiter.d.ts +3 -2
  17. package/build/limiter.js +5 -3
  18. package/build/limiter.spec.js +45 -26
  19. package/build/routes/chrome/http/content.post.body.json +8 -8
  20. package/build/routes/chrome/http/pdf.post.body.json +8 -8
  21. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  22. package/build/routes/chrome/http/screenshot.post.body.json +8 -8
  23. package/build/routes/chromium/http/content.post.body.json +8 -8
  24. package/build/routes/chromium/http/pdf.post.body.json +8 -8
  25. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  26. package/build/routes/chromium/http/screenshot.post.body.json +8 -8
  27. package/build/routes/management/http/metrics-total.get.js +1 -1
  28. package/build/routes/management/http/metrics.get.js +2 -2
  29. package/build/sdk-utils.d.ts +13 -0
  30. package/build/sdk-utils.js +94 -0
  31. package/build/server.d.ts +3 -2
  32. package/build/server.js +6 -4
  33. package/build/types.d.ts +2 -2
  34. package/build/utils.js +6 -10
  35. package/external/after.js +1 -1
  36. package/external/before.js +1 -1
  37. package/external/browser.js +1 -1
  38. package/external/page.js +1 -1
  39. package/package.json +7 -7
  40. package/src/browserless.ts +21 -3
  41. package/src/browsers/index.ts +9 -6
  42. package/src/exports.ts +1 -0
  43. package/src/file-system.spec.ts +43 -18
  44. package/src/file-system.ts +16 -30
  45. package/src/hooks.ts +46 -4
  46. package/src/limiter.spec.ts +82 -112
  47. package/src/limiter.ts +3 -3
  48. package/src/routes/management/http/metrics-total.get.ts +3 -3
  49. package/src/routes/management/http/metrics.get.ts +2 -2
  50. package/src/sdk-utils.ts +136 -0
  51. package/src/server.ts +4 -3
  52. package/src/shared/content.http.ts +0 -1
  53. package/src/types.ts +2 -2
  54. package/src/utils.ts +10 -11
  55. package/static/docs/swagger.json +11 -11
  56. package/static/docs/swagger.min.json +10 -10
  57. package/static/function/client.js +76 -63
@@ -9,6 +9,7 @@ export * from './metrics.js';
9
9
  export * from './mime-types.js';
10
10
  export * from './monitoring.js';
11
11
  export * from './router.js';
12
+ export * from './sdk-utils.js';
12
13
  export * from './server.js';
13
14
  export * from './shim.js';
14
15
  export * from './token.js';
package/build/exports.js CHANGED
@@ -10,6 +10,7 @@ export * from './metrics.js';
10
10
  export * from './mime-types.js';
11
11
  export * from './monitoring.js';
12
12
  export * from './router.js';
13
+ export * from './sdk-utils.js';
13
14
  export * from './server.js';
14
15
  export * from './shim.js';
15
16
  export * from './token.js';
@@ -9,7 +9,6 @@ export declare class FileSystem extends EventEmitter {
9
9
  protected currentAESKey: Buffer;
10
10
  protected log: import("debug").Debugger;
11
11
  constructor(config: Config);
12
- private handleTokenChange;
13
12
  /**
14
13
  * Appends contents to a file-path for persistance. File contents are
15
14
  * encrypted before being saved to disk. Reads happen via the in-memory
@@ -19,7 +18,7 @@ export declare class FileSystem extends EventEmitter {
19
18
  * @param newContent A string of new content to add to the file
20
19
  * @returns void
21
20
  */
22
- append: (path: string, newContent: string) => Promise<void>;
21
+ append: (path: string, newContent: string, shouldEncode: boolean) => Promise<void>;
23
22
  /**
24
23
  * Reads contents from the local map, if any exist, or loads
25
24
  * from the file system and hydrates the cache for the particular filepath
@@ -27,7 +26,7 @@ export declare class FileSystem extends EventEmitter {
27
26
  * @param path The filepath of the contents to read
28
27
  * @returns Promise of the contents separated by newlines
29
28
  */
30
- read: (path: string) => Promise<string[]>;
29
+ read: (path: string, encoded: boolean) => Promise<string[]>;
31
30
  /**
32
31
  * Implement any browserless-core-specific shutdown logic here.
33
32
  * Calls the empty-SDK stop method for downstream implementations.
@@ -10,21 +10,7 @@ export class FileSystem extends EventEmitter {
10
10
  super();
11
11
  this.config = config;
12
12
  this.currentAESKey = config.getAESKey();
13
- this.config.on('token', this.handleTokenChange);
14
13
  }
15
- handleTokenChange = async () => {
16
- this.log(`Token has changed, updating file-system contents`);
17
- const start = Date.now();
18
- const newAESKey = this.config.getAESKey();
19
- await Promise.all(Array.from(this.fsMap).map(async ([filePath, contents]) => {
20
- const newlyEncoded = encrypt(contents.join('\n'), Buffer.from(newAESKey));
21
- return writeFile(filePath, newlyEncoded);
22
- })).catch((e) => {
23
- this.log(`Error in setting new token: "${e}"`);
24
- });
25
- this.log(`Successfully updated file encodings in ${Date.now() - start}ms`);
26
- this.currentAESKey = this.config.getAESKey();
27
- };
28
14
  /**
29
15
  * Appends contents to a file-path for persistance. File contents are
30
16
  * encrypted before being saved to disk. Reads happen via the in-memory
@@ -34,11 +20,13 @@ export class FileSystem extends EventEmitter {
34
20
  * @param newContent A string of new content to add to the file
35
21
  * @returns void
36
22
  */
37
- append = async (path, newContent) => {
38
- const contents = await this.read(path);
23
+ append = async (path, newContent, shouldEncode) => {
24
+ const contents = await this.read(path, shouldEncode);
39
25
  contents.push(newContent);
40
26
  this.fsMap.set(path, contents);
41
- const encoded = await encrypt(contents.join('\n'), Buffer.from(this.currentAESKey));
27
+ const encoded = shouldEncode
28
+ ? await encrypt(contents.join('\n'), this.currentAESKey)
29
+ : contents.join('\n');
42
30
  return writeFile(path, encoded.toString());
43
31
  };
44
32
  /**
@@ -48,15 +36,16 @@ export class FileSystem extends EventEmitter {
48
36
  * @param path The filepath of the contents to read
49
37
  * @returns Promise of the contents separated by newlines
50
38
  */
51
- read = async (path) => {
39
+ read = async (path, encoded) => {
52
40
  const hasKey = this.fsMap.has(path);
53
41
  if (hasKey) {
54
42
  return this.fsMap.get(path);
55
43
  }
56
44
  const contents = (await readFile(path).catch(() => '')).toString();
57
- const splitContents = contents.length
58
- ? (await decrypt(contents, Buffer.from(this.currentAESKey))).split('\n')
59
- : [];
45
+ const decoded = encoded && contents.length
46
+ ? await decrypt(contents, this.currentAESKey)
47
+ : contents;
48
+ const splitContents = decoded.length ? decoded.split('\n') : [];
60
49
  this.fsMap.set(path, splitContents);
61
50
  return splitContents;
62
51
  };
@@ -1,44 +1,61 @@
1
- import { Config, FileSystem, sleep } from '@browserless.io/browserless';
1
+ import { Config, FileSystem, noop } from '@browserless.io/browserless';
2
2
  import { readFile, unlink } from 'fs/promises';
3
3
  import { expect } from 'chai';
4
4
  const filePath = '/tmp/_browserless_test_fs_';
5
5
  describe('File-System', () => {
6
- afterEach(async () => unlink(filePath));
6
+ afterEach(async () => unlink(filePath).catch(noop));
7
7
  it('saves and encodes files', async () => {
8
8
  const mySecretContents = 'pony-foo';
9
9
  const config = new Config();
10
10
  config.setToken('browserless.io');
11
11
  const f = new FileSystem(config);
12
- await f.append(filePath, mySecretContents);
13
- expect(await f.read(filePath)).to.eql([mySecretContents]);
12
+ await f.append(filePath, mySecretContents, true);
13
+ expect(await f.read(filePath, true)).to.eql([mySecretContents]);
14
14
  const rawText = (await readFile(filePath)).toString();
15
15
  expect(rawText.toString()).to.not.include(mySecretContents);
16
16
  });
17
- it('appends newlines to files', async () => {
17
+ it('saves files without encoding', async () => {
18
+ const mySecretContents = 'pony-foo';
19
+ const config = new Config();
20
+ config.setToken('browserless.io');
21
+ const f = new FileSystem(config);
22
+ await f.append(filePath, mySecretContents, false);
23
+ expect(await f.read(filePath, false)).to.eql([mySecretContents]);
24
+ const rawText = (await readFile(filePath)).toString();
25
+ expect(rawText.toString()).to.include(mySecretContents);
26
+ });
27
+ it('appends newlines to files and encodes them', async () => {
18
28
  const mySecretContents = 'pony-foo';
19
29
  const moreSecretContents = 'pony-pony-foo-foo';
20
30
  const config = new Config();
21
31
  config.setToken('browserless.io');
22
32
  const f = new FileSystem(config);
23
- await f.append(filePath, mySecretContents);
24
- expect(await f.read(filePath)).to.eql([mySecretContents]);
25
- await f.append(filePath, moreSecretContents);
26
- expect(await f.read(filePath)).to.eql([
33
+ await f.append(filePath, mySecretContents, true);
34
+ expect(await f.read(filePath, true)).to.eql([mySecretContents]);
35
+ await f.append(filePath, moreSecretContents, true);
36
+ expect(await f.read(filePath, true)).to.eql([
27
37
  mySecretContents,
28
38
  moreSecretContents,
29
39
  ]);
40
+ const rawText = (await readFile(filePath)).toString();
41
+ expect(rawText).to.not.include(mySecretContents);
42
+ expect(rawText).to.not.include(moreSecretContents);
30
43
  });
31
- it('re-encodes files on token changes', async () => {
44
+ it('appends newlines to files and does not encode them', async () => {
45
+ const mySecretContents = 'pony-foo';
46
+ const moreSecretContents = 'pony-pony-foo-foo';
32
47
  const config = new Config();
33
48
  config.setToken('browserless.io');
34
49
  const f = new FileSystem(config);
35
- const mySecretContents = 'pony-foo';
36
- await f.append(filePath, mySecretContents);
37
- const oldText = (await readFile(filePath)).toString();
38
- config.setToken('super-browserless-64');
39
- await sleep(200);
40
- const newText = (await readFile(filePath)).toString();
41
- expect(oldText).to.not.equal(newText);
42
- expect(await f.read(filePath)).to.eql([mySecretContents]);
50
+ await f.append(filePath, mySecretContents, false);
51
+ expect(await f.read(filePath, false)).to.eql([mySecretContents]);
52
+ await f.append(filePath, moreSecretContents, false);
53
+ expect(await f.read(filePath, false)).to.eql([
54
+ mySecretContents,
55
+ moreSecretContents,
56
+ ]);
57
+ const rawText = (await readFile(filePath)).toString();
58
+ expect(rawText).to.include(mySecretContents);
59
+ expect(rawText).to.include(moreSecretContents);
43
60
  });
44
61
  });
package/build/hooks.d.ts CHANGED
@@ -1,4 +1,18 @@
1
- export { default as beforeRequest } from '../external/before.js';
2
- export { default as afterRequest } from '../external/after.js';
3
- export { default as pageHook } from '../external/page.js';
4
- export { default as browserHook } from '../external/browser.js';
1
+ /// <reference types="node" />
2
+ import { AfterResponse, BeforeRequest, BrowserHook, PageHook } from '@browserless.io/browserless';
3
+ import { EventEmitter } from 'events';
4
+ export declare class Hooks extends EventEmitter {
5
+ before(args: BeforeRequest): Promise<boolean>;
6
+ after(args: AfterResponse): Promise<unknown>;
7
+ page(args: PageHook): Promise<unknown>;
8
+ browser(args: BrowserHook): Promise<unknown>;
9
+ /**
10
+ * Implement any browserless-core-specific shutdown logic here.
11
+ * Calls the empty-SDK stop method for downstream implementations.
12
+ */
13
+ shutdown: () => Promise<void>;
14
+ /**
15
+ * Left blank for downstream SDK modules to optionally implement.
16
+ */
17
+ stop: () => void;
18
+ }
package/build/hooks.js CHANGED
@@ -1,8 +1,37 @@
1
+ import { EventEmitter } from 'events';
2
+ // KEPT for backwards compatibility reasons since some downstream
3
+ // docker images will override these files to inject their own hook
4
+ // behaviors
1
5
  // @ts-ignore
2
- export { default as beforeRequest } from '../external/before.js';
6
+ import { default as afterRequest } from '../external/after.js';
3
7
  // @ts-ignore
4
- export { default as afterRequest } from '../external/after.js';
8
+ import { default as beforeRequest } from '../external/before.js';
5
9
  // @ts-ignore
6
- export { default as pageHook } from '../external/page.js';
10
+ import { default as browserHook } from '../external/browser.js';
7
11
  // @ts-ignore
8
- export { default as browserHook } from '../external/browser.js';
12
+ import { default as pageHook } from '../external/page.js';
13
+ export class Hooks extends EventEmitter {
14
+ before(args) {
15
+ return beforeRequest(args);
16
+ }
17
+ after(args) {
18
+ return afterRequest(args);
19
+ }
20
+ page(args) {
21
+ return pageHook(args);
22
+ }
23
+ browser(args) {
24
+ return browserHook(args);
25
+ }
26
+ /**
27
+ * Implement any browserless-core-specific shutdown logic here.
28
+ * Calls the empty-SDK stop method for downstream implementations.
29
+ */
30
+ shutdown = async () => {
31
+ await this.stop();
32
+ };
33
+ /**
34
+ * Left blank for downstream SDK modules to optionally implement.
35
+ */
36
+ stop = () => { };
37
+ }
@@ -1,5 +1,5 @@
1
1
  /// <reference types="debug" />
2
- import { AfterResponse, Config, Metrics, Monitoring, WebHooks } from '@browserless.io/browserless';
2
+ import { AfterResponse, Config, Hooks, Metrics, Monitoring, WebHooks } from '@browserless.io/browserless';
3
3
  import q from 'queue';
4
4
  export type LimitFn<TArgs extends unknown[], TResult> = (...args: TArgs) => Promise<TResult>;
5
5
  export type ErrorFn<TArgs extends unknown[]> = (...args: TArgs) => void;
@@ -15,9 +15,10 @@ export declare class Limiter extends q {
15
15
  protected metrics: Metrics;
16
16
  protected monitor: Monitoring;
17
17
  protected webhooks: WebHooks;
18
+ protected hooks: Hooks;
18
19
  protected queued: number;
19
20
  protected debug: import("debug").Debugger;
20
- constructor(config: Config, metrics: Metrics, monitor: Monitoring, webhooks: WebHooks);
21
+ constructor(config: Config, metrics: Metrics, monitor: Monitoring, webhooks: WebHooks, hooks: Hooks);
21
22
  protected handleEnd(): void;
22
23
  protected jobEnd(jobInfo: AfterResponse): void;
23
24
  protected handleSuccess({ detail: { job } }: {
package/build/limiter.js CHANGED
@@ -1,13 +1,14 @@
1
- import { TooManyRequests, afterRequest, createLogger, } from '@browserless.io/browserless';
1
+ import { TooManyRequests, createLogger, } from '@browserless.io/browserless';
2
2
  import q from 'queue';
3
3
  export class Limiter extends q {
4
4
  config;
5
5
  metrics;
6
6
  monitor;
7
7
  webhooks;
8
+ hooks;
8
9
  queued;
9
10
  debug = createLogger('limiter');
10
- constructor(config, metrics, monitor, webhooks) {
11
+ constructor(config, metrics, monitor, webhooks, hooks) {
11
12
  super({
12
13
  autostart: true,
13
14
  concurrency: config.getConcurrent(),
@@ -17,6 +18,7 @@ export class Limiter extends q {
17
18
  this.metrics = metrics;
18
19
  this.monitor = monitor;
19
20
  this.webhooks = webhooks;
21
+ this.hooks = hooks;
20
22
  this.queued = config.getQueued();
21
23
  this.debug(`Concurrency: ${this.concurrency} queue: ${this.queued} timeout: ${this.timeout}ms`);
22
24
  config.on('concurrent', (concurrency) => {
@@ -43,7 +45,7 @@ export class Limiter extends q {
43
45
  this.logQueue('All jobs complete.');
44
46
  }
45
47
  jobEnd(jobInfo) {
46
- afterRequest(jobInfo);
48
+ this.hooks.after(jobInfo);
47
49
  }
48
50
  handleSuccess({ detail: { job } }) {
49
51
  const timeUsed = Date.now() - job.start;
@@ -1,15 +1,10 @@
1
- import { Config, Limiter, Metrics, Monitoring, sleep, } from '@browserless.io/browserless';
1
+ import { Config, Hooks, Limiter, Metrics, Monitoring, WebHooks, sleep, } from '@browserless.io/browserless';
2
+ import Sinon, { spy } from 'sinon';
2
3
  import { expect } from 'chai';
3
- import { spy } from 'sinon';
4
4
  const asyncNoop = () => Promise.resolve(undefined);
5
5
  const noop = () => undefined;
6
- const webHooks = {
7
- callErrorAlertURL: spy(),
8
- callFailedHealthURL: spy(),
9
- callQueueAlertURL: spy(),
10
- callRejectAlertURL: spy(),
11
- callTimeoutAlertURL: spy(),
12
- };
6
+ const webHooks = Sinon.createStubInstance(WebHooks);
7
+ const hooks = Sinon.createStubInstance(Hooks);
13
8
  describe(`Limiter`, () => {
14
9
  afterEach(() => {
15
10
  webHooks.callFailedHealthURL.resetHistory();
@@ -17,8 +12,12 @@ describe(`Limiter`, () => {
17
12
  webHooks.callRejectAlertURL.resetHistory();
18
13
  webHooks.callTimeoutAlertURL.resetHistory();
19
14
  webHooks.callErrorAlertURL.resetHistory();
15
+ hooks.before.resetHistory();
16
+ hooks.after.resetHistory();
17
+ hooks.browser.resetHistory();
18
+ hooks.page.resetHistory();
20
19
  });
21
- it('limits and queues function calls and calls queue alert urls', async () => {
20
+ it('limits and queues function calls, calls hooks, and calls queue alert urls', async () => {
22
21
  return new Promise((resolve, reject) => {
23
22
  const config = new Config();
24
23
  config.setQueueAlertURL('https://example.com');
@@ -27,7 +26,7 @@ describe(`Limiter`, () => {
27
26
  config.setConcurrent(1);
28
27
  config.setQueued(1);
29
28
  config.setTimeout(-1);
30
- const limiter = new Limiter(config, metrics, monitoring, webHooks);
29
+ const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
31
30
  const handler = spy();
32
31
  const job = limiter.limit(handler, asyncNoop, asyncNoop, noop);
33
32
  job();
@@ -35,6 +34,7 @@ describe(`Limiter`, () => {
35
34
  expect(handler.calledOnce).to.be.true;
36
35
  limiter.addEventListener('end', () => {
37
36
  try {
37
+ expect(hooks.after.called).to.be.true;
38
38
  expect(handler.calledTwice).to.be.true;
39
39
  expect(webHooks.callQueueAlertURL.calledOnce).to.be.true;
40
40
  expect(metrics.get().queued).to.equal(1);
@@ -48,7 +48,7 @@ describe(`Limiter`, () => {
48
48
  });
49
49
  });
50
50
  }).timeout(5000);
51
- it('passes through arguments', () => {
51
+ it('passes through arguments', () => new Promise((resolve, reject) => {
52
52
  const args = ['one', 'two', 'three'];
53
53
  const config = new Config();
54
54
  const metrics = new Metrics();
@@ -56,13 +56,23 @@ describe(`Limiter`, () => {
56
56
  config.setConcurrent(1);
57
57
  config.setQueued(0);
58
58
  config.setTimeout(-1);
59
- const limiter = new Limiter(config, metrics, monitoring, webHooks);
59
+ const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
60
60
  const handler = spy();
61
61
  const job = limiter.limit(handler, asyncNoop, asyncNoop, noop);
62
62
  // @ts-ignore will fix later
63
63
  job(...args);
64
64
  expect(handler.args[0]).to.eql(args);
65
- });
65
+ limiter.addEventListener('end', () => {
66
+ try {
67
+ expect(hooks.after.args[0][0]).to.have.property('start');
68
+ expect(hooks.after.args[0][0]).to.have.property('status', 'successful');
69
+ }
70
+ catch (e) {
71
+ return reject(e);
72
+ }
73
+ resolve(undefined);
74
+ });
75
+ }));
66
76
  it('waits to run jobs until the first are done', async () => {
67
77
  const config = new Config();
68
78
  const monitoring = new Monitoring(config);
@@ -70,7 +80,7 @@ describe(`Limiter`, () => {
70
80
  config.setConcurrent(1);
71
81
  config.setQueued(1);
72
82
  config.setTimeout(-1);
73
- const limiter = new Limiter(config, metrics, monitoring, webHooks);
83
+ const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
74
84
  const handlerOne = () => new Promise((r) => setTimeout(r, 50));
75
85
  const handlerTwo = spy();
76
86
  const jobOne = limiter.limit(handlerOne, asyncNoop, asyncNoop, noop);
@@ -89,7 +99,7 @@ describe(`Limiter`, () => {
89
99
  config.setConcurrent(1);
90
100
  config.setQueued(1);
91
101
  config.setTimeout(-1);
92
- const limiter = new Limiter(config, metrics, monitoring, webHooks);
102
+ const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
93
103
  const spy = () => new Promise((_r, rej) => rej(error));
94
104
  const job = limiter.limit(spy, asyncNoop, asyncNoop, noop);
95
105
  await job().catch(noop);
@@ -101,6 +111,7 @@ describe(`Limiter`, () => {
101
111
  expect(metrics.get().error).to.eql(1);
102
112
  expect(webHooks.callErrorAlertURL.getCalls()[0].firstArg).to.include(error);
103
113
  expect(webHooks.callErrorAlertURL.calledOnce).to.be.true;
114
+ expect(hooks.after.args[0][0]).to.have.property('status', 'error');
104
115
  });
105
116
  });
106
117
  });
@@ -112,7 +123,7 @@ describe(`Limiter`, () => {
112
123
  config.setConcurrent(1);
113
124
  config.setQueued(0);
114
125
  config.setTimeout(-1);
115
- const limiter = new Limiter(config, metrics, monitoring, webHooks);
126
+ const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
116
127
  const handler = spy();
117
128
  const onError = spy();
118
129
  const job = limiter.limit(handler, onError, noop, noop);
@@ -124,7 +135,7 @@ describe(`Limiter`, () => {
124
135
  expect(onError.calledOnce).to.be.true;
125
136
  expect(onError.args[0]).to.eql(args);
126
137
  });
127
- it('calls a timeout handler with arguments if a job takes too long', (r) => {
138
+ it('calls a timeout handler with arguments if a job takes too long', () => new Promise((resolve, reject) => {
128
139
  const args = ['one', 'two', 'three'];
129
140
  const config = new Config();
130
141
  const metrics = new Metrics();
@@ -133,18 +144,26 @@ describe(`Limiter`, () => {
133
144
  config.setQueued(0);
134
145
  config.setTimeout(10);
135
146
  let timer;
136
- const limiter = new Limiter(config, metrics, monitoring, webHooks);
147
+ const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
137
148
  const handler = () => new Promise((d) => (timer = global.setTimeout(d, 1000)));
138
149
  const onTimeout = (...calledArgs) => {
139
150
  clearTimeout(timer);
140
151
  expect(calledArgs).to.eql(args);
141
152
  expect(webHooks.callTimeoutAlertURL.calledOnce).to.be.true;
142
- r(null);
143
153
  };
144
154
  const job = limiter.limit(handler, noop, onTimeout, noop);
145
155
  // @ts-ignore
146
156
  job(...args);
147
- });
157
+ limiter.addEventListener('end', () => {
158
+ try {
159
+ expect(hooks.after.args[0][0]).to.have.property('status', 'timedout');
160
+ }
161
+ catch (e) {
162
+ return reject(e);
163
+ }
164
+ resolve(undefined);
165
+ });
166
+ }));
148
167
  it('allows overriding the timeouts', async () => {
149
168
  const config = new Config();
150
169
  const metrics = new Metrics();
@@ -152,7 +171,7 @@ describe(`Limiter`, () => {
152
171
  config.setConcurrent(2);
153
172
  config.setQueued(0);
154
173
  config.setTimeout(1);
155
- const limiter = new Limiter(config, metrics, monitoring, webHooks);
174
+ const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
156
175
  const onTimeout = spy();
157
176
  const handler = async () => new Promise((r) => setTimeout(r, 10));
158
177
  const job = limiter.limit(handler, noop, onTimeout, noop);
@@ -169,7 +188,7 @@ describe(`Limiter`, () => {
169
188
  config.setConcurrent(1);
170
189
  config.setQueued(0);
171
190
  config.setTimeout(20);
172
- const limiter = new Limiter(config, metrics, monitoring, webHooks);
191
+ const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
173
192
  const handler = () => new Promise((r) => setTimeout(r, 1));
174
193
  const timeout = spy();
175
194
  const job = limiter.limit(handler, noop, timeout, noop);
@@ -184,7 +203,7 @@ describe(`Limiter`, () => {
184
203
  config.setConcurrent(1);
185
204
  config.setQueued(0);
186
205
  config.setTimeout(-1);
187
- const limiter = new Limiter(config, metrics, monitoring, webHooks);
206
+ const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
188
207
  const handler = spy();
189
208
  const job = limiter.limit(handler, noop, noop, noop);
190
209
  job();
@@ -207,7 +226,7 @@ describe(`Limiter`, () => {
207
226
  config.setConcurrent(10);
208
227
  config.setQueued(10);
209
228
  config.setTimeout(-1);
210
- const limiter = new Limiter(config, metrics, monitoring, webHooks);
229
+ const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
211
230
  const handler = spy();
212
231
  const job = limiter.limit(handler, noop, noop, noop);
213
232
  job().catch(() => {
@@ -227,7 +246,7 @@ describe(`Limiter`, () => {
227
246
  config.setConcurrent(10);
228
247
  config.setQueued(10);
229
248
  config.setTimeout(-1);
230
- const limiter = new Limiter(config, metrics, monitoring, webHooks);
249
+ const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
231
250
  const handler = spy();
232
251
  const job = limiter.limit(handler, noop, noop, noop);
233
252
  job();
@@ -394,14 +394,14 @@
394
394
  "length": {
395
395
  "type": "number"
396
396
  },
397
- "__@toStringTag@10915": {
397
+ "__@toStringTag@10918": {
398
398
  "type": "string",
399
399
  "const": "Uint8Array"
400
400
  }
401
401
  },
402
402
  "required": [
403
403
  "BYTES_PER_ELEMENT",
404
- "__@toStringTag@10915",
404
+ "__@toStringTag@10918",
405
405
  "buffer",
406
406
  "byteLength",
407
407
  "byteOffset",
@@ -436,13 +436,13 @@
436
436
  "byteLength": {
437
437
  "type": "number"
438
438
  },
439
- "__@toStringTag@10915": {
439
+ "__@toStringTag@10918": {
440
440
  "type": "string"
441
441
  }
442
442
  },
443
443
  "additionalProperties": false,
444
444
  "required": [
445
- "__@toStringTag@10915",
445
+ "__@toStringTag@10918",
446
446
  "byteLength"
447
447
  ]
448
448
  },
@@ -452,18 +452,18 @@
452
452
  "byteLength": {
453
453
  "type": "number"
454
454
  },
455
- "__@species@11016": {
455
+ "__@species@11019": {
456
456
  "$ref": "#/definitions/SharedArrayBuffer"
457
457
  },
458
- "__@toStringTag@10915": {
458
+ "__@toStringTag@10918": {
459
459
  "type": "string",
460
460
  "const": "SharedArrayBuffer"
461
461
  }
462
462
  },
463
463
  "additionalProperties": false,
464
464
  "required": [
465
- "__@species@11016",
466
- "__@toStringTag@10915",
465
+ "__@species@11019",
466
+ "__@toStringTag@10918",
467
467
  "byteLength"
468
468
  ]
469
469
  },
@@ -535,14 +535,14 @@
535
535
  "length": {
536
536
  "type": "number"
537
537
  },
538
- "__@toStringTag@86785": {
538
+ "__@toStringTag@75984": {
539
539
  "type": "string",
540
540
  "const": "Uint8Array"
541
541
  }
542
542
  },
543
543
  "required": [
544
544
  "BYTES_PER_ELEMENT",
545
- "__@toStringTag@86785",
545
+ "__@toStringTag@75984",
546
546
  "buffer",
547
547
  "byteLength",
548
548
  "byteOffset",
@@ -577,13 +577,13 @@
577
577
  "byteLength": {
578
578
  "type": "number"
579
579
  },
580
- "__@toStringTag@86785": {
580
+ "__@toStringTag@75984": {
581
581
  "type": "string"
582
582
  }
583
583
  },
584
584
  "additionalProperties": false,
585
585
  "required": [
586
- "__@toStringTag@86785",
586
+ "__@toStringTag@75984",
587
587
  "byteLength"
588
588
  ]
589
589
  },
@@ -593,18 +593,18 @@
593
593
  "byteLength": {
594
594
  "type": "number"
595
595
  },
596
- "__@species@86886": {
596
+ "__@species@76085": {
597
597
  "$ref": "#/definitions/SharedArrayBuffer"
598
598
  },
599
- "__@toStringTag@86785": {
599
+ "__@toStringTag@75984": {
600
600
  "type": "string",
601
601
  "const": "SharedArrayBuffer"
602
602
  }
603
603
  },
604
604
  "additionalProperties": false,
605
605
  "required": [
606
- "__@species@86886",
607
- "__@toStringTag@86785",
606
+ "__@species@76085",
607
+ "__@toStringTag@75984",
608
608
  "byteLength"
609
609
  ]
610
610
  },