@internetarchive/fetch-handler 1.1.0-webdev-7731.7 → 1.1.0-webdev-7731.8

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.
@@ -81,8 +81,8 @@ export class FetchRetrier {
81
81
  const status = response.status;
82
82
  (_a = this.analyticsHandler) === null || _a === void 0 ? void 0 : _a.sendEvent({
83
83
  category: this.eventCategory,
84
- action: `status4xx5xxResponse`,
85
- label: `http status ${status}, url: ${response.url}`,
84
+ action: `status${status}Response`,
85
+ label: `url: ${response.url}`,
86
86
  });
87
87
  }
88
88
  logContentBlockingEvent(urlString, error) {
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-retrier.js","sourceRoot":"","sources":["../../../src/fetch-retry/fetch-retrier.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AnalyticsHandlerInterface } from '@internetarchive/analytics-manager';\nimport { promisedSleep } from '../utils/promised-sleep';\nimport { type FetchOptions } from '../fetch-options';\nimport { legacyArgsAsFetchOptions } from './legacy-args';\nimport { DefaultRetryConfiguration } from './configuration/default-retry-configuration';\nimport type { RetryConfiguring } from './configuration/retry-configuring';\n\n/**\n * A class that retries a fetch request.\n */\nexport interface FetchRetrierInterface {\n /**\n * Execute a fetch with retry.\n *\n * @param request RequestInfo\n * @param options Optional RequestInit | FetchOptions\n * @returns Promise<Response>\n */\n fetchRetry(\n request: RequestInfo,\n options?: RequestInit | FetchOptions,\n ): Promise<Response>;\n}\n\n/** @inheritdoc */\nexport class FetchRetrier implements FetchRetrierInterface {\n private analyticsHandler?: AnalyticsHandlerInterface;\n\n private retryConfiguration: RetryConfiguring =\n new DefaultRetryConfiguration();\n\n constructor(options?: {\n analyticsHandler?: AnalyticsHandlerInterface;\n retryConfiguration?: RetryConfiguring;\n }) {\n if (options?.analyticsHandler)\n this.analyticsHandler = options.analyticsHandler;\n if (options?.retryConfiguration)\n this.retryConfiguration = options.retryConfiguration;\n }\n\n /** @inheritdoc */\n public async fetchRetry(\n request: RequestInfo,\n options?: RequestInit | FetchOptions,\n ): Promise<Response> {\n const fetchOptions = legacyArgsAsFetchOptions(options);\n return await this.fetchRetryWithOptions(request, 0, fetchOptions);\n }\n\n private async fetchRetryWithOptions(\n request: RequestInfo,\n retryNumber: number,\n options?: FetchOptions,\n ): Promise<Response> {\n const urlString = typeof request === 'string' ? request : request.url;\n\n try {\n const response = await fetch(request, options?.requestInit);\n if (response.ok) return response;\n\n if (response.status >= 400 && response.status < 600) {\n this.log4xx5xxResponse(response);\n }\n\n const retryConfig = options?.retryConfig ?? this.retryConfiguration;\n if (retryConfig.shouldRetry(response, retryNumber)) {\n const delay = retryConfig.retryDelay(retryNumber, response);\n await promisedSleep(delay);\n this.logRetryEvent(\n urlString,\n retryNumber,\n response.statusText,\n response.status,\n );\n return this.fetchRetryWithOptions(request, retryNumber + 1, options);\n }\n this.logFailureEvent(urlString, response.status);\n return response;\n } catch (error) {\n // if a content blocker is detected, log it and don't retry\n if (this.isContentBlockerError(error)) {\n this.logContentBlockingEvent(urlString, error);\n throw error;\n }\n\n const retryConfig = options?.retryConfig ?? this.retryConfiguration;\n if (retryConfig.shouldRetry(null, retryNumber)) {\n const delay = retryConfig.retryDelay(retryNumber);\n await promisedSleep(delay);\n this.logRetryEvent(urlString, retryNumber, error, error);\n return this.fetchRetryWithOptions(request, retryNumber + 1, options);\n }\n this.logFailureEvent(urlString, error);\n throw error;\n }\n }\n\n private isContentBlockerError(error: unknown): boolean {\n // all of the content blocker errors are `TypeError`\n if (!(error instanceof TypeError)) return false;\n const message = error.message.toLowerCase();\n return message.includes('content blocker');\n }\n\n private readonly eventCategory = 'offshootFetchRetry';\n\n private logRetryEvent(\n urlString: string,\n retryNumber: number,\n status: unknown,\n code: unknown,\n ) {\n this.analyticsHandler?.sendEvent({\n category: this.eventCategory,\n action: 'retryingFetch',\n label: `retryNumber: ${retryNumber}, code: ${code}, status: ${status}, url: ${urlString}`,\n });\n }\n\n private logFailureEvent(urlString: string, error: unknown) {\n this.analyticsHandler?.sendEvent({\n category: this.eventCategory,\n action: 'fetchFailed',\n label: `error: ${error}, url: ${urlString}`,\n });\n }\n\n private log4xx5xxResponse(response: Response) {\n const status = response.status;\n\n this.analyticsHandler?.sendEvent({\n category: this.eventCategory,\n action: `status4xx5xxResponse`,\n label: `http status ${status}, url: ${response.url}`,\n });\n }\n\n private logContentBlockingEvent(urlString: string, error: unknown) {\n this.analyticsHandler?.sendEvent({\n category: this.eventCategory,\n action: 'contentBlockerDetectedNotRetrying',\n label: `error: ${error}, url: ${urlString}`,\n });\n }\n}\n"]}
1
+ {"version":3,"file":"fetch-retrier.js","sourceRoot":"","sources":["../../../src/fetch-retry/fetch-retrier.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AnalyticsHandlerInterface } from '@internetarchive/analytics-manager';\nimport { promisedSleep } from '../utils/promised-sleep';\nimport { type FetchOptions } from '../fetch-options';\nimport { legacyArgsAsFetchOptions } from './legacy-args';\nimport { DefaultRetryConfiguration } from './configuration/default-retry-configuration';\nimport type { RetryConfiguring } from './configuration/retry-configuring';\n\n/**\n * A class that retries a fetch request.\n */\nexport interface FetchRetrierInterface {\n /**\n * Execute a fetch with retry.\n *\n * @param request RequestInfo\n * @param options Optional RequestInit | FetchOptions\n * @returns Promise<Response>\n */\n fetchRetry(\n request: RequestInfo,\n options?: RequestInit | FetchOptions,\n ): Promise<Response>;\n}\n\n/** @inheritdoc */\nexport class FetchRetrier implements FetchRetrierInterface {\n private analyticsHandler?: AnalyticsHandlerInterface;\n\n private retryConfiguration: RetryConfiguring =\n new DefaultRetryConfiguration();\n\n constructor(options?: {\n analyticsHandler?: AnalyticsHandlerInterface;\n retryConfiguration?: RetryConfiguring;\n }) {\n if (options?.analyticsHandler)\n this.analyticsHandler = options.analyticsHandler;\n if (options?.retryConfiguration)\n this.retryConfiguration = options.retryConfiguration;\n }\n\n /** @inheritdoc */\n public async fetchRetry(\n request: RequestInfo,\n options?: RequestInit | FetchOptions,\n ): Promise<Response> {\n const fetchOptions = legacyArgsAsFetchOptions(options);\n return await this.fetchRetryWithOptions(request, 0, fetchOptions);\n }\n\n private async fetchRetryWithOptions(\n request: RequestInfo,\n retryNumber: number,\n options?: FetchOptions,\n ): Promise<Response> {\n const urlString = typeof request === 'string' ? request : request.url;\n\n try {\n const response = await fetch(request, options?.requestInit);\n if (response.ok) return response;\n\n if (response.status >= 400 && response.status < 600) {\n this.log4xx5xxResponse(response);\n }\n\n const retryConfig = options?.retryConfig ?? this.retryConfiguration;\n if (retryConfig.shouldRetry(response, retryNumber)) {\n const delay = retryConfig.retryDelay(retryNumber, response);\n await promisedSleep(delay);\n this.logRetryEvent(\n urlString,\n retryNumber,\n response.statusText,\n response.status,\n );\n return this.fetchRetryWithOptions(request, retryNumber + 1, options);\n }\n this.logFailureEvent(urlString, response.status);\n return response;\n } catch (error) {\n // if a content blocker is detected, log it and don't retry\n if (this.isContentBlockerError(error)) {\n this.logContentBlockingEvent(urlString, error);\n throw error;\n }\n\n const retryConfig = options?.retryConfig ?? this.retryConfiguration;\n if (retryConfig.shouldRetry(null, retryNumber)) {\n const delay = retryConfig.retryDelay(retryNumber);\n await promisedSleep(delay);\n this.logRetryEvent(urlString, retryNumber, error, error);\n return this.fetchRetryWithOptions(request, retryNumber + 1, options);\n }\n this.logFailureEvent(urlString, error);\n throw error;\n }\n }\n\n private isContentBlockerError(error: unknown): boolean {\n // all of the content blocker errors are `TypeError`\n if (!(error instanceof TypeError)) return false;\n const message = error.message.toLowerCase();\n return message.includes('content blocker');\n }\n\n private readonly eventCategory = 'offshootFetchRetry';\n\n private logRetryEvent(\n urlString: string,\n retryNumber: number,\n status: unknown,\n code: unknown,\n ) {\n this.analyticsHandler?.sendEvent({\n category: this.eventCategory,\n action: 'retryingFetch',\n label: `retryNumber: ${retryNumber}, code: ${code}, status: ${status}, url: ${urlString}`,\n });\n }\n\n private logFailureEvent(urlString: string, error: unknown) {\n this.analyticsHandler?.sendEvent({\n category: this.eventCategory,\n action: 'fetchFailed',\n label: `error: ${error}, url: ${urlString}`,\n });\n }\n\n private log4xx5xxResponse(response: Response) {\n const status = response.status;\n\n this.analyticsHandler?.sendEvent({\n category: this.eventCategory,\n action: `status${status}Response`,\n label: `url: ${response.url}`,\n });\n }\n\n private logContentBlockingEvent(urlString: string, error: unknown) {\n this.analyticsHandler?.sendEvent({\n category: this.eventCategory,\n action: 'contentBlockerDetectedNotRetrying',\n label: `error: ${error}, url: ${urlString}`,\n });\n }\n}\n"]}
@@ -32,7 +32,7 @@ describe('FetchRetrier', () => {
32
32
  const res = await retrier.fetchRetry('https://foo.org/403');
33
33
  expect(res.status).to.equal(403);
34
34
  expect(fetchStub.callCount).to.equal(1);
35
- expect(analytics.events[0].action).to.equal('status4xx5xxResponse');
35
+ expect(analytics.events[0].action).to.equal('status403Response');
36
36
  });
37
37
  it('does not retry on 404 and logs event', async () => {
38
38
  fetchStub.resolves(new Response('not found', { status: 404 }));
@@ -42,7 +42,7 @@ describe('FetchRetrier', () => {
42
42
  const res = await retrier.fetchRetry('https://foo.org/404');
43
43
  expect(res.status).to.equal(404);
44
44
  expect(fetchStub.callCount).to.equal(1);
45
- expect(analytics.events[0].action).to.equal('status4xx5xxResponse');
45
+ expect(analytics.events[0].action).to.equal('status404Response');
46
46
  });
47
47
  it('retries on 4xx if shouldRetry is true in ApiRequestInit', async () => {
48
48
  fetchStub.onCall(0).resolves(new Response('bad request', { status: 400 }));
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-retrier.test.js","sourceRoot":"","sources":["../../test/fetch-retrier.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from '@open-wc/testing';\nimport sinon from 'sinon';\nimport { FetchRetrier } from '../src/fetch-retry/fetch-retrier';\nimport { MockAnalyticsHandler } from './mocks/mock-analytics-handler';\nimport { MockRetryConfig } from './mocks/mock-retry-config';\n\ndescribe('FetchRetrier', () => {\n let fetchStub: sinon.SinonStub;\n let analytics: MockAnalyticsHandler;\n\n beforeEach(() => {\n analytics = new MockAnalyticsHandler();\n fetchStub = sinon.stub(globalThis, 'fetch');\n });\n\n afterEach(() => {\n fetchStub.restore();\n });\n\n it('returns response on first success', async () => {\n fetchStub.resolves(new Response('ok', { status: 200 }));\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new MockRetryConfig(),\n });\n\n const res = await retrier.fetchRetry('https://foo.org/data');\n\n expect(res.status).to.equal(200);\n expect(fetchStub.callCount).to.equal(1);\n expect(analytics.events.length).to.equal(0);\n });\n\n it('does not retry on 4xx and logs event', async () => {\n fetchStub.resolves(new Response('forbidden', { status: 403 }));\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n });\n\n const res = await retrier.fetchRetry('https://foo.org/403');\n\n expect(res.status).to.equal(403);\n expect(fetchStub.callCount).to.equal(1);\n expect(analytics.events[0].action).to.equal('status4xx5xxResponse');\n });\n\n it('does not retry on 404 and logs event', async () => {\n fetchStub.resolves(new Response('not found', { status: 404 }));\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n });\n\n const res = await retrier.fetchRetry('https://foo.org/404');\n\n expect(res.status).to.equal(404);\n expect(fetchStub.callCount).to.equal(1);\n expect(analytics.events[0].action).to.equal('status4xx5xxResponse');\n });\n\n it('retries on 4xx if shouldRetry is true in ApiRequestInit', async () => {\n fetchStub.onCall(0).resolves(new Response('bad request', { status: 400 }));\n fetchStub.onCall(1).resolves(new Response('ok', { status: 200 }));\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n });\n\n const res = await retrier.fetchRetry('https://foo.org/should-retry', {\n retryConfig: new MockRetryConfig(),\n });\n\n expect(res.status).to.equal(200);\n expect(fetchStub.callCount).to.equal(2);\n expect(analytics.events.some(e => e.action === 'retryingFetch')).to.be.true;\n });\n\n it('retries on 500 and logs retry/failure events', async () => {\n fetchStub.onCall(0).resolves(new Response('fail', { status: 500 }));\n fetchStub.onCall(1).resolves(new Response('fail again', { status: 500 }));\n fetchStub.onCall(2).resolves(new Response('still fail', { status: 500 }));\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new MockRetryConfig(),\n });\n\n const res = await retrier.fetchRetry('https://foo.org/fail');\n\n expect(res.status).to.equal(500);\n expect(fetchStub.callCount).to.equal(3);\n expect(analytics.events.some(e => e.action === 'retryingFetch')).to.be.true;\n expect(analytics.events.some(e => e.action === 'fetchFailed')).to.be.true;\n });\n\n it('retries on fetch error and eventually succeeds', async () => {\n fetchStub.onCall(0).rejects(new Error('Network error'));\n fetchStub.onCall(1).resolves(new Response('ok', { status: 200 }));\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new MockRetryConfig(),\n });\n\n const res = await retrier.fetchRetry('https://foo.org/retry');\n\n expect(res.status).to.equal(200);\n expect(fetchStub.callCount).to.equal(2);\n expect(analytics.events.some(e => e.action === 'retryingFetch')).to.be.true;\n });\n\n it('throws and logs when retries are exhausted due to network error', async () => {\n fetchStub.rejects(new Error('Boom'));\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new MockRetryConfig(),\n });\n\n try {\n await retrier.fetchRetry('https://foo.org/networkfail');\n throw new Error('Should have thrown');\n } catch (err: unknown) {\n expect((err as Error).message).to.equal('Boom');\n }\n\n expect(fetchStub.callCount).to.equal(3);\n expect(analytics.events.some(e => e.action === 'fetchFailed')).to.be.true;\n });\n\n it('detects content blocker error and does not retry', async () => {\n const blockerError = new TypeError('Content Blocker denied request');\n fetchStub.rejects(blockerError);\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n });\n\n try {\n await retrier.fetchRetry('https://foo.org/blocked');\n throw new Error('Should have thrown');\n } catch (err: unknown) {\n expect(err).to.equal(blockerError);\n }\n\n expect(fetchStub.callCount).to.equal(1);\n expect(\n analytics.events.some(\n e => e.action === 'contentBlockerDetectedNotRetrying',\n ),\n ).to.be.true;\n });\n\n it('sleeps for each retry attempt', async () => {\n const retryConfig = new MockRetryConfig();\n const retryDelaySpy = sinon.spy(retryConfig, 'retryDelay');\n fetchStub.resolves(new Response(null, { status: 500 }));\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: retryConfig,\n });\n\n const res = await retrier.fetchRetry('https://foo.org/retry-fail');\n\n expect(res.status).to.equal(500);\n expect(fetchStub.callCount).to.equal(3);\n expect(retryDelaySpy.callCount).to.equal(2);\n });\n\n it('does not retry 5xx when NoRetryConfiguration is used', async () => {\n fetchStub.resolves(new Response('server error', { status: 500 }));\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new (class {\n shouldRetry() {\n return false;\n }\n retryDelay() {\n return 0;\n }\n })(),\n });\n\n const res = await retrier.fetchRetry('https://foo.org/no-retry-500');\n expect(res.status).to.equal(500);\n expect(fetchStub.callCount).to.equal(1);\n expect(analytics.events.some(e => e.action === 'fetchFailed')).to.be.true;\n });\n\n it('does not retry on error when configuration disables retries', async () => {\n fetchStub.rejects(new Error('Immediate failure'));\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new (class {\n shouldRetry() {\n return false;\n }\n retryDelay() {\n return 0;\n }\n })(),\n });\n\n try {\n await retrier.fetchRetry('https://foo.org/no-retry-error');\n throw new Error('Should have thrown');\n } catch (err: unknown) {\n expect((err as Error).message).to.equal('Immediate failure');\n }\n\n expect(fetchStub.callCount).to.equal(1);\n expect(analytics.events.some(e => e.action === 'fetchFailed')).to.be.true;\n });\n});\n"]}
1
+ {"version":3,"file":"fetch-retrier.test.js","sourceRoot":"","sources":["../../test/fetch-retrier.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from '@open-wc/testing';\nimport sinon from 'sinon';\nimport { FetchRetrier } from '../src/fetch-retry/fetch-retrier';\nimport { MockAnalyticsHandler } from './mocks/mock-analytics-handler';\nimport { MockRetryConfig } from './mocks/mock-retry-config';\n\ndescribe('FetchRetrier', () => {\n let fetchStub: sinon.SinonStub;\n let analytics: MockAnalyticsHandler;\n\n beforeEach(() => {\n analytics = new MockAnalyticsHandler();\n fetchStub = sinon.stub(globalThis, 'fetch');\n });\n\n afterEach(() => {\n fetchStub.restore();\n });\n\n it('returns response on first success', async () => {\n fetchStub.resolves(new Response('ok', { status: 200 }));\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new MockRetryConfig(),\n });\n\n const res = await retrier.fetchRetry('https://foo.org/data');\n\n expect(res.status).to.equal(200);\n expect(fetchStub.callCount).to.equal(1);\n expect(analytics.events.length).to.equal(0);\n });\n\n it('does not retry on 4xx and logs event', async () => {\n fetchStub.resolves(new Response('forbidden', { status: 403 }));\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n });\n\n const res = await retrier.fetchRetry('https://foo.org/403');\n\n expect(res.status).to.equal(403);\n expect(fetchStub.callCount).to.equal(1);\n expect(analytics.events[0].action).to.equal('status403Response');\n });\n\n it('does not retry on 404 and logs event', async () => {\n fetchStub.resolves(new Response('not found', { status: 404 }));\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n });\n\n const res = await retrier.fetchRetry('https://foo.org/404');\n\n expect(res.status).to.equal(404);\n expect(fetchStub.callCount).to.equal(1);\n expect(analytics.events[0].action).to.equal('status404Response');\n });\n\n it('retries on 4xx if shouldRetry is true in ApiRequestInit', async () => {\n fetchStub.onCall(0).resolves(new Response('bad request', { status: 400 }));\n fetchStub.onCall(1).resolves(new Response('ok', { status: 200 }));\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n });\n\n const res = await retrier.fetchRetry('https://foo.org/should-retry', {\n retryConfig: new MockRetryConfig(),\n });\n\n expect(res.status).to.equal(200);\n expect(fetchStub.callCount).to.equal(2);\n expect(analytics.events.some(e => e.action === 'retryingFetch')).to.be.true;\n });\n\n it('retries on 500 and logs retry/failure events', async () => {\n fetchStub.onCall(0).resolves(new Response('fail', { status: 500 }));\n fetchStub.onCall(1).resolves(new Response('fail again', { status: 500 }));\n fetchStub.onCall(2).resolves(new Response('still fail', { status: 500 }));\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new MockRetryConfig(),\n });\n\n const res = await retrier.fetchRetry('https://foo.org/fail');\n\n expect(res.status).to.equal(500);\n expect(fetchStub.callCount).to.equal(3);\n expect(analytics.events.some(e => e.action === 'retryingFetch')).to.be.true;\n expect(analytics.events.some(e => e.action === 'fetchFailed')).to.be.true;\n });\n\n it('retries on fetch error and eventually succeeds', async () => {\n fetchStub.onCall(0).rejects(new Error('Network error'));\n fetchStub.onCall(1).resolves(new Response('ok', { status: 200 }));\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new MockRetryConfig(),\n });\n\n const res = await retrier.fetchRetry('https://foo.org/retry');\n\n expect(res.status).to.equal(200);\n expect(fetchStub.callCount).to.equal(2);\n expect(analytics.events.some(e => e.action === 'retryingFetch')).to.be.true;\n });\n\n it('throws and logs when retries are exhausted due to network error', async () => {\n fetchStub.rejects(new Error('Boom'));\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new MockRetryConfig(),\n });\n\n try {\n await retrier.fetchRetry('https://foo.org/networkfail');\n throw new Error('Should have thrown');\n } catch (err: unknown) {\n expect((err as Error).message).to.equal('Boom');\n }\n\n expect(fetchStub.callCount).to.equal(3);\n expect(analytics.events.some(e => e.action === 'fetchFailed')).to.be.true;\n });\n\n it('detects content blocker error and does not retry', async () => {\n const blockerError = new TypeError('Content Blocker denied request');\n fetchStub.rejects(blockerError);\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n });\n\n try {\n await retrier.fetchRetry('https://foo.org/blocked');\n throw new Error('Should have thrown');\n } catch (err: unknown) {\n expect(err).to.equal(blockerError);\n }\n\n expect(fetchStub.callCount).to.equal(1);\n expect(\n analytics.events.some(\n e => e.action === 'contentBlockerDetectedNotRetrying',\n ),\n ).to.be.true;\n });\n\n it('sleeps for each retry attempt', async () => {\n const retryConfig = new MockRetryConfig();\n const retryDelaySpy = sinon.spy(retryConfig, 'retryDelay');\n fetchStub.resolves(new Response(null, { status: 500 }));\n\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: retryConfig,\n });\n\n const res = await retrier.fetchRetry('https://foo.org/retry-fail');\n\n expect(res.status).to.equal(500);\n expect(fetchStub.callCount).to.equal(3);\n expect(retryDelaySpy.callCount).to.equal(2);\n });\n\n it('does not retry 5xx when NoRetryConfiguration is used', async () => {\n fetchStub.resolves(new Response('server error', { status: 500 }));\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new (class {\n shouldRetry() {\n return false;\n }\n retryDelay() {\n return 0;\n }\n })(),\n });\n\n const res = await retrier.fetchRetry('https://foo.org/no-retry-500');\n expect(res.status).to.equal(500);\n expect(fetchStub.callCount).to.equal(1);\n expect(analytics.events.some(e => e.action === 'fetchFailed')).to.be.true;\n });\n\n it('does not retry on error when configuration disables retries', async () => {\n fetchStub.rejects(new Error('Immediate failure'));\n const retrier = new FetchRetrier({\n analyticsHandler: analytics,\n retryConfiguration: new (class {\n shouldRetry() {\n return false;\n }\n retryDelay() {\n return 0;\n }\n })(),\n });\n\n try {\n await retrier.fetchRetry('https://foo.org/no-retry-error');\n throw new Error('Should have thrown');\n } catch (err: unknown) {\n expect((err as Error).message).to.equal('Immediate failure');\n }\n\n expect(fetchStub.callCount).to.equal(1);\n expect(analytics.events.some(e => e.action === 'fetchFailed')).to.be.true;\n });\n});\n"]}
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "license": "AGPL-3.0-only",
9
9
  "author": "Internet Archive",
10
- "version": "1.1.0-webdev-7731.7",
10
+ "version": "1.1.0-webdev-7731.8",
11
11
  "main": "dist/index.js",
12
12
  "module": "dist/index.js",
13
13
  "scripts": {
@@ -131,8 +131,8 @@ export class FetchRetrier implements FetchRetrierInterface {
131
131
 
132
132
  this.analyticsHandler?.sendEvent({
133
133
  category: this.eventCategory,
134
- action: `status4xx5xxResponse`,
135
- label: `http status ${status}, url: ${response.url}`,
134
+ action: `status${status}Response`,
135
+ label: `url: ${response.url}`,
136
136
  });
137
137
  }
138
138
 
@@ -41,7 +41,7 @@ describe('FetchRetrier', () => {
41
41
 
42
42
  expect(res.status).to.equal(403);
43
43
  expect(fetchStub.callCount).to.equal(1);
44
- expect(analytics.events[0].action).to.equal('status4xx5xxResponse');
44
+ expect(analytics.events[0].action).to.equal('status403Response');
45
45
  });
46
46
 
47
47
  it('does not retry on 404 and logs event', async () => {
@@ -54,7 +54,7 @@ describe('FetchRetrier', () => {
54
54
 
55
55
  expect(res.status).to.equal(404);
56
56
  expect(fetchStub.callCount).to.equal(1);
57
- expect(analytics.events[0].action).to.equal('status4xx5xxResponse');
57
+ expect(analytics.events[0].action).to.equal('status404Response');
58
58
  });
59
59
 
60
60
  it('retries on 4xx if shouldRetry is true in ApiRequestInit', async () => {