From af506b878ec2dba3703ee8a503394291fd334f28 Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Tue, 23 Jun 2026 11:13:44 +0200 Subject: [PATCH 01/10] feat(ci): migrate aws credentials to secure oidc --- .github/workflows/main.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f7adecc..06f480c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,17 +8,18 @@ on: jobs: push_image: runs-on: ubuntu-latest + permissions: + id-token: write + contents: read steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: '14' - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 + uses: aws-actions/configure-aws-credentials@v4 with: - # Created the Secrets Under the Repo only with These Variables - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: arn:aws:iam::480535519801:role/github-actions-dev-story-scraper aws-region: ${{ secrets.AWS_REGION }} - name: install run: | From f608d6dd54590e7cf5c030247d5db658b557d9db Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Tue, 23 Jun 2026 12:39:36 +0200 Subject: [PATCH 02/10] chore(ci): upgrade actions to latest stable versions for node 24 --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 06f480c..3b611f8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,12 +12,12 @@ jobs: id-token: write contents: read steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v7 - uses: actions/setup-node@v2 with: node-version: '14' - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 + uses: aws-actions/configure-aws-credentials@v5 with: role-to-assume: arn:aws:iam::480535519801:role/github-actions-dev-story-scraper aws-region: ${{ secrets.AWS_REGION }} From a500e104c95da1e3292d7caa091c819b9a667187 Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Tue, 23 Jun 2026 13:25:11 +0200 Subject: [PATCH 03/10] chore(ci): upgrade setup-node and checkout to latest stable versions for node 24 --- .github/workflows/main.yml | 2 +- .github/workflows/pull-request.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3b611f8..ecd43a0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: contents: read steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v6 with: node-version: '14' - name: Configure AWS Credentials diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index a8ff180..f09ba57 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -8,9 +8,9 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v7 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v6 with: node-version: '14' From e933a6afad0596721d962b8b8a5809bd52bfd1b9 Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Tue, 23 Jun 2026 15:17:02 +0200 Subject: [PATCH 04/10] chore(ci): upgrade Node execution version to v20 in workflows --- .github/workflows/main.yml | 2 +- .github/workflows/pull-request.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ecd43a0..e05a264 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: - node-version: '14' + node-version: '20' - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v5 with: diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index f09ba57..31ae254 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/setup-node@v6 with: - node-version: '14' + node-version: '20' - name: install run: yarn install From dc35ed506d2d0033dcb79bbea092f2dac114d0ca Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Tue, 23 Jun 2026 15:23:44 +0200 Subject: [PATCH 05/10] fix(ci): define global ReadableStream for jest node 20 compatibility --- jest.config.ts | 1 + src/tests/setupTests.ts | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 src/tests/setupTests.ts diff --git a/jest.config.ts b/jest.config.ts index e73e314..a4d09b5 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -4,6 +4,7 @@ import type {Config} from '@jest/types'; const config: Config.InitialOptions = { preset: 'ts-jest', testEnvironment: 'node', + setupFilesAfterEnv: ['/src/tests/setupTests.ts'], }; export default config; diff --git a/src/tests/setupTests.ts b/src/tests/setupTests.ts new file mode 100644 index 0000000..0a74687 --- /dev/null +++ b/src/tests/setupTests.ts @@ -0,0 +1,5 @@ +import { ReadableStream } from 'node:stream/web'; + +if (typeof global.ReadableStream === 'undefined') { + global.ReadableStream = ReadableStream as any; +} From 6f6bc300f7e8c2bc87314f6d2d674aa2a8fd4d6c Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Tue, 23 Jun 2026 15:40:30 +0200 Subject: [PATCH 06/10] fix(ci): expose all native node 20 web apis in jest environment --- src/tests/setupTests.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/tests/setupTests.ts b/src/tests/setupTests.ts index 0a74687..c2b54dd 100644 --- a/src/tests/setupTests.ts +++ b/src/tests/setupTests.ts @@ -1,5 +1,24 @@ -import { ReadableStream } from 'node:stream/web'; +import { ReadableStream, WritableStream, TransformStream } from 'node:stream/web'; +import { Blob } from 'node:buffer'; +// 1. Inyectar Streams y Buffers nativos de Node 18+ que Jest aísla if (typeof global.ReadableStream === 'undefined') { global.ReadableStream = ReadableStream as any; } +if (typeof global.WritableStream === 'undefined') { + global.WritableStream = WritableStream as any; +} +if (typeof global.TransformStream === 'undefined') { + global.TransformStream = TransformStream as any; +} +if (typeof global.Blob === 'undefined') { + global.Blob = Blob as any; +} + +// 2. Copiar Web APIs nativas de Node (fetch, Headers, etc.) que Jest borra del entorno virtual +const webAPIs = ['fetch', 'Headers', 'Request', 'Response', 'FormData', 'File']; +for (const api of webAPIs) { + if (typeof (global as any)[api] === 'undefined' && typeof (globalThis as any)[api] !== 'undefined') { + (global as any)[api] = (globalThis as any)[api]; + } +} From 8dc415d2093de4273863c522e10f4d6ca7a6dd59 Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Tue, 23 Jun 2026 15:43:36 +0200 Subject: [PATCH 07/10] fix(ci): explicitly import and expose native Node File class in Jest setup --- src/tests/setupTests.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tests/setupTests.ts b/src/tests/setupTests.ts index c2b54dd..101b614 100644 --- a/src/tests/setupTests.ts +++ b/src/tests/setupTests.ts @@ -1,5 +1,5 @@ import { ReadableStream, WritableStream, TransformStream } from 'node:stream/web'; -import { Blob } from 'node:buffer'; +import { Blob, File } from 'node:buffer'; // 1. Inyectar Streams y Buffers nativos de Node 18+ que Jest aísla if (typeof global.ReadableStream === 'undefined') { @@ -14,9 +14,12 @@ if (typeof global.TransformStream === 'undefined') { if (typeof global.Blob === 'undefined') { global.Blob = Blob as any; } +if (typeof global.File === 'undefined') { + global.File = File as any; +} // 2. Copiar Web APIs nativas de Node (fetch, Headers, etc.) que Jest borra del entorno virtual -const webAPIs = ['fetch', 'Headers', 'Request', 'Response', 'FormData', 'File']; +const webAPIs = ['fetch', 'Headers', 'Request', 'Response', 'FormData']; for (const api of webAPIs) { if (typeof (global as any)[api] === 'undefined' && typeof (globalThis as any)[api] !== 'undefined') { (global as any)[api] = (globalThis as any)[api]; From 19a93e3b0222db11dbd804cc44619af4c12393c4 Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Tue, 23 Jun 2026 16:08:42 +0200 Subject: [PATCH 08/10] fix(ci): explicitly import and expose all native Node 20 Web APIs in Jest setup --- src/tests/setupTests.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/tests/setupTests.ts b/src/tests/setupTests.ts index 101b614..60a4245 100644 --- a/src/tests/setupTests.ts +++ b/src/tests/setupTests.ts @@ -1,7 +1,8 @@ import { ReadableStream, WritableStream, TransformStream } from 'node:stream/web'; import { Blob, File } from 'node:buffer'; +import { MessagePort, MessageChannel } from 'node:worker_threads'; -// 1. Inyectar Streams y Buffers nativos de Node 18+ que Jest aísla +// 1. Inyectar de forma explícita las clases WebIDL que Jest aísla de Node 18+ if (typeof global.ReadableStream === 'undefined') { global.ReadableStream = ReadableStream as any; } @@ -17,9 +18,15 @@ if (typeof global.Blob === 'undefined') { if (typeof global.File === 'undefined') { global.File = File as any; } +if (typeof global.MessagePort === 'undefined') { + global.MessagePort = MessagePort as any; +} +if (typeof global.MessageChannel === 'undefined') { + global.MessageChannel = MessageChannel as any; +} -// 2. Copiar Web APIs nativas de Node (fetch, Headers, etc.) que Jest borra del entorno virtual -const webAPIs = ['fetch', 'Headers', 'Request', 'Response', 'FormData']; +// 2. Copiar Web APIs nativas de Node (fetch, Headers, Cryptography, etc.) que Jest borra de su entorno virtual +const webAPIs = ['fetch', 'Headers', 'Request', 'Response', 'FormData', 'crypto', 'Crypto', 'CryptoKey']; for (const api of webAPIs) { if (typeof (global as any)[api] === 'undefined' && typeof (globalThis as any)[api] !== 'undefined') { (global as any)[api] = (globalThis as any)[api]; From d500f6835ca96bfe720bc5de1b81e78820b6503b Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Tue, 23 Jun 2026 16:10:30 +0200 Subject: [PATCH 09/10] fix(ci): define global DOMException for jest node 20 compatibility --- src/tests/setupTests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/setupTests.ts b/src/tests/setupTests.ts index 60a4245..fc6f21e 100644 --- a/src/tests/setupTests.ts +++ b/src/tests/setupTests.ts @@ -26,7 +26,7 @@ if (typeof global.MessageChannel === 'undefined') { } // 2. Copiar Web APIs nativas de Node (fetch, Headers, Cryptography, etc.) que Jest borra de su entorno virtual -const webAPIs = ['fetch', 'Headers', 'Request', 'Response', 'FormData', 'crypto', 'Crypto', 'CryptoKey']; +const webAPIs = ['fetch', 'Headers', 'Request', 'Response', 'FormData', 'crypto', 'Crypto', 'CryptoKey', 'DOMException']; for (const api of webAPIs) { if (typeof (global as any)[api] === 'undefined' && typeof (globalThis as any)[api] !== 'undefined') { (global as any)[api] = (globalThis as any)[api]; From 1755841a5f09ca3129815f018f6ec16ebaaa2b2a Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Wed, 24 Jun 2026 08:59:07 +0200 Subject: [PATCH 10/10] fix(ci): refactor cheerio imports to use import asterisk syntax for v1.2.0 compatibility --- src/devStoryScraper.ts | 2 +- src/parsers/companyUrlParser.ts | 2 +- .../devStory/devStoryArtifactParser.ts | 3 +- src/parsers/devStory/devStoryBookmarkParse.ts | 2 +- .../devStory/devStoryPositionParser.ts | 3 +- src/parsers/devStory/devStoryTopsParser.ts | 3 +- src/tests/setupTests.ts | 55 +++++++++++++------ 7 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/devStoryScraper.ts b/src/devStoryScraper.ts index e143bdc..50d4a6f 100644 --- a/src/devStoryScraper.ts +++ b/src/devStoryScraper.ts @@ -1,4 +1,4 @@ -import cheerio from 'cheerio'; +import * as cheerio from 'cheerio'; import cleanDeep from 'clean-deep'; import {DevStoryDownloader} from './downloader/devStoryDownloader'; diff --git a/src/parsers/companyUrlParser.ts b/src/parsers/companyUrlParser.ts index f5f01f3..79f2952 100644 --- a/src/parsers/companyUrlParser.ts +++ b/src/parsers/companyUrlParser.ts @@ -1,5 +1,5 @@ import {HttpClient} from '../clients/httpClient'; -import cheerio from 'cheerio'; +import * as cheerio from 'cheerio'; export class CompanyUrlParser { constructor(private readonly httpClient: HttpClient) {} diff --git a/src/parsers/devStory/devStoryArtifactParser.ts b/src/parsers/devStory/devStoryArtifactParser.ts index dfae024..238017f 100644 --- a/src/parsers/devStory/devStoryArtifactParser.ts +++ b/src/parsers/devStory/devStoryArtifactParser.ts @@ -1,4 +1,5 @@ -import cheerio, {CheerioAPI} from 'cheerio'; +import * as cheerio from 'cheerio'; +import {CheerioAPI} from 'cheerio'; import {DevStoryArtifact, DevStoryArtifactType} from '../../models/devStory/devStoryArtifact'; import {stripString} from '../../utils/utils'; diff --git a/src/parsers/devStory/devStoryBookmarkParse.ts b/src/parsers/devStory/devStoryBookmarkParse.ts index 40e38e7..7cf6441 100644 --- a/src/parsers/devStory/devStoryBookmarkParse.ts +++ b/src/parsers/devStory/devStoryBookmarkParse.ts @@ -1,5 +1,5 @@ import * as _ from 'lodash'; -import cheerio from 'cheerio'; +import * as cheerio from 'cheerio'; import {Author, Bookmark} from '../../models/bookmark'; import {asNameAndSurnames, stripString} from '../../utils/utils'; import {Markdown} from '../../utils/markdown'; diff --git a/src/parsers/devStory/devStoryPositionParser.ts b/src/parsers/devStory/devStoryPositionParser.ts index c8f9f0c..77c59b6 100644 --- a/src/parsers/devStory/devStoryPositionParser.ts +++ b/src/parsers/devStory/devStoryPositionParser.ts @@ -1,4 +1,5 @@ -import cheerio, {CheerioAPI} from 'cheerio'; +import * as cheerio from 'cheerio'; +import {CheerioAPI} from 'cheerio'; import {DevStoryPosition} from '../../models/devStory/devStoryPosition'; import {stripString} from '../../utils/utils'; diff --git a/src/parsers/devStory/devStoryTopsParser.ts b/src/parsers/devStory/devStoryTopsParser.ts index 9201685..84d408f 100644 --- a/src/parsers/devStory/devStoryTopsParser.ts +++ b/src/parsers/devStory/devStoryTopsParser.ts @@ -1,4 +1,5 @@ -import cheerio, {CheerioAPI} from 'cheerio'; +import * as cheerio from 'cheerio'; +import {CheerioAPI} from 'cheerio'; import {PublicArtifact} from '../../models/publicArtifact'; import {stripString} from '../../utils/utils'; diff --git a/src/tests/setupTests.ts b/src/tests/setupTests.ts index fc6f21e..6f5a405 100644 --- a/src/tests/setupTests.ts +++ b/src/tests/setupTests.ts @@ -1,34 +1,55 @@ -import { ReadableStream, WritableStream, TransformStream } from 'node:stream/web'; -import { Blob, File } from 'node:buffer'; -import { MessagePort, MessageChannel } from 'node:worker_threads'; +// 1. Requerir módulos nativos de forma imperativa sin colisionar con tipos globales de TS +const streamWeb = require('node:stream/web'); +const bufferModule = require('node:buffer'); +const workerThreads = require('node:worker_threads'); -// 1. Inyectar de forma explícita las clases WebIDL que Jest aísla de Node 18+ +// 2. Definir de forma prioritaria las clases de WebIDL en el global de Jest if (typeof global.ReadableStream === 'undefined') { - global.ReadableStream = ReadableStream as any; + global.ReadableStream = streamWeb.ReadableStream; } if (typeof global.WritableStream === 'undefined') { - global.WritableStream = WritableStream as any; + global.WritableStream = streamWeb.WritableStream; } if (typeof global.TransformStream === 'undefined') { - global.TransformStream = TransformStream as any; + global.TransformStream = streamWeb.TransformStream; } if (typeof global.Blob === 'undefined') { - global.Blob = Blob as any; + global.Blob = bufferModule.Blob; } if (typeof global.File === 'undefined') { - global.File = File as any; + global.File = bufferModule.File; } if (typeof global.MessagePort === 'undefined') { - global.MessagePort = MessagePort as any; + global.MessagePort = workerThreads.MessagePort; } if (typeof global.MessageChannel === 'undefined') { - global.MessageChannel = MessageChannel as any; + global.MessageChannel = workerThreads.MessageChannel; } -// 2. Copiar Web APIs nativas de Node (fetch, Headers, Cryptography, etc.) que Jest borra de su entorno virtual -const webAPIs = ['fetch', 'Headers', 'Request', 'Response', 'FormData', 'crypto', 'Crypto', 'CryptoKey', 'DOMException']; -for (const api of webAPIs) { - if (typeof (global as any)[api] === 'undefined' && typeof (globalThis as any)[api] !== 'undefined') { - (global as any)[api] = (globalThis as any)[api]; - } +if (typeof global.DOMException === 'undefined') { + global.DOMException = class DOMException extends Error { + constructor(message?: any, name?: any) { + super(message); + this.name = name || 'DOMException'; + } + } as any; +} + +// 3. Requerir undici de forma segura (una vez que todas las globales ya están inyectadas) +const undici = require('undici'); + +if (typeof global.fetch === 'undefined') { + global.fetch = undici.fetch; +} +if (typeof global.Headers === 'undefined') { + global.Headers = undici.Headers; +} +if (typeof global.Request === 'undefined') { + global.Request = undici.Request; +} +if (typeof global.Response === 'undefined') { + global.Response = undici.Response; +} +if (typeof global.FormData === 'undefined') { + global.FormData = undici.FormData; }