From c8cdcbb2ff676030437df846da221da30980bcc5 Mon Sep 17 00:00:00 2001 From: Beka Baizhan Date: Mon, 6 Jul 2026 14:24:37 -0700 Subject: [PATCH 1/6] ci: migrate from Travis to GitHub Actions on node 22 - add CI workflow (push/PR to master) and tag-triggered publish workflow, matching the goodeggs-stats setup; npm publish runs the existing prepublishOnly build - upgrade nock to v14 so tests can intercept node's native fetch - fix two tests broken by the modern runtime: undici correctly strips the body from a 204 response (use 200), and V8 reworded JSON.parse error messages - pin dev node version via .nvmrc --- .github/workflows/ci.yml | 19 ++++++++++++ .github/workflows/publish.yml | 21 +++++++++++++ .nvmrc | 1 + .travis.yml | 29 ------------------ package.json | 2 +- src/index.test.ts | 4 +-- yarn.lock | 55 +++++++++++++++++++++++++++++++---- 7 files changed, 94 insertions(+), 37 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .nvmrc delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..561fe4b3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,19 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: yarn + - run: yarn install --frozen-lockfile + - run: yarn test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..8bd7ed92 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,21 @@ +name: Publish + +on: + push: + tags: + - 'v*' + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: yarn + registry-url: https://registry.npmjs.org + - run: yarn install --frozen-lockfile + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..2bd5a0a9 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a0d83929..00000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -dist: trusty -language: node_js -node_js: - - 14.21.3 -env: - global: - - PATH="/tmp/ci-tools:./node_modules/.bin/:$PATH" - # NPM_TOKEN: - - secure: 'VYRtwgXf8Ez7O2R8b6ppy6L/ZiJXGkog3Llx515VXU5/Cw2LK21ddVKDR4+mqcJ9jwSBRkS7SSHM8M9GKYILgo/h444ccX3ynnFqN8Vi57ikLWCTotiKtVrijXAaZVF+TV/l60Gyx05Nn6CytyyQc++2obx4u9VgDvuwldpO8y5K7pJeEjvJyxxb+/vvdrZlmgMTxyw7+oMzRiqRsDUqQBdUzItiiMqmZGdtGDoJXG2S4HHPT3MXfqZBaz0DeSs9z7yZ0sThG1p5jWEu64rWRzlDNN71ZNdwBvP8uneWqXsf+srZKLJKcF9XRe0q7i2RasM5pK6UoWoRg4x3LL91WxU5zi6aH6Dx66Ey14XjjL8EGDL+xM5DNBQ78ONV9ktTfBYIbKVTqlpN/umyrB+ZzLSW+ALnlxCacmR99KhQST9tFuEAKT517xGn4GM9Ywa9OBWvf2i0/OEsRpPIZGfAbg/bT0/Bf3etx6xuV1d7RrsALSSgHwwiI6rJvWEUvoRZT9o2O1mM4Wg+7k95JAk7q6J6n0SqaIzpwuhx2C9T1B/ZVmoMyhRDeyYuAOHD0QwQCzrRCd/KqSsm5dNgumthspq7mczEl3iUXn6EAp++gHSzj58M5+gePAvu3vo28HTz6IOUA9u9UOLLCh9gX3sEqumITaEIBcFVrRLAYn4VYM4=' -cache: - yarn: true - directories: - - '/tmp/ci-tools' -before_install: - - curl -sSL https://github.com/goodeggs/travis-utils/raw/master/install-ci-tools.sh - | CACHE_DIR=/tmp/ci-tools sh -s -- yarn=1.9.4 codecov -after_script: - - codecov -install: yarn install -script: yarn run test -deploy: - provider: npm - email: open-source@goodeggs.com - api_token: - secure: 'mclmG0+zHQnQ3HlOCUEY3ioec8NT0jhOpk5fgN+vWnIlepFJ7cqD0LjhaXytnv4/WEQic25ym0mSD6OxFunJ+0h9CzMg3GCIIXAq7lrdQyxwFGn40kNSLlWyW+SniOE0zjb+8ne3zzMdXyquV0Lg43VflSn+5TzCRSsNjAQIXH6LySWqT/rVOzXiYvnV64A1XUCIWofCeDvrSbMmtXHqAQPXdd+N0zMN7y7jmQHjdoI4ZGcaec6Q+ygo/HfTST4anmyoe8EKfv9NFEBZx8rPlxoGJBl1HWoADl9OJdmUIaQon2bdn1oIyyhz1Jloxvp6uxZ/rdhkVaJ9qykPSbZd/du1W4itivPUcSRqIN95WxPgNXVieDLm02v5OD4F8pJV2FsvLbS+Zr8uBe5l+HgFdsFVcZ11XtimZD0lZtb9amfvfuaAn46GqpiygPANVDHt7+3wuw9rr8VlZ575MuPvz9N74fJ5hmcb/UGCiHBD4mQowLrpCvBAWPjDjli532XzXBu9Z3tHgeD6/leggDNiNlwrxL5sTUbF/UUngKD6k4I00oys6DJtwpPu02KYGMeY4sMPNQ7SlxoiRU/uAgld1iDUm5jAZTUAB8N59Hxp9Ib027v1B+xdSTOfcMW8XOxATkofEG8paAW1WBTgJBZLNSI6OxEPiZjxo9NQnAblnnU=' - skip_cleanup: true - on: - tags: true - all_branches: true diff --git a/package.json b/package.json index 6a0e5e6e..8d47027a 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "goodeggs-test-helpers": "^8.3.2", "leasot": "^13.3.0", "mocha": "10.5.2", - "nock": "13.5.4", + "nock": "^14", "nyc": "^15.1.0", "typescript": "^4.3.5" }, diff --git a/src/index.test.ts b/src/index.test.ts index a9601a94..3eabff5f 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -47,7 +47,7 @@ describe('jsonFetch', () => { expect(response.headers).to.be.ok(); }); it('resolves with JSON body when content-type contains other values but includes application/json', async () => { - nock('http://www.test.com').get('/products/1234').reply(204, '[{}]', { + nock('http://www.test.com').get('/products/1234').reply(200, '[{}]', { 'Content-Type': 'application/json; charset=utf-8', }); const response = await jsonFetch('http://www.test.com/products/1234'); @@ -569,7 +569,7 @@ describe('jsonFetch', () => { try { await jsonFetch('http://www.test.com/products/1234'); } catch (err) { - expect(err.message).to.contain('Unexpected string'); + expect(err.message).to.contain('in JSON at position 16'); return; } diff --git a/yarn.lock b/yarn.lock index 8b043843..2af1ba15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1640,6 +1640,18 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@mswjs/interceptors@^0.41.0": + version "0.41.9" + resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.41.9.tgz#9d90bbd60d1ddc30dbcbb827a9bb2e470493530d" + integrity sha512-VVPPgHyQ6ShqnrmDWuxjmUIsO9gWyOZFmuOfLd9LfBGQJwZfy0gvv9pbHSJuoFNIYC7ZDX9aoFwowjcdSC4E8w== + dependencies: + "@open-draft/deferred-promise" "^2.2.0" + "@open-draft/logger" "^0.3.0" + "@open-draft/until" "^2.0.0" + is-node-process "^1.2.0" + outvariant "^1.4.3" + strict-event-emitter "^0.5.1" + "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" @@ -1668,6 +1680,24 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@open-draft/deferred-promise@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz#4a822d10f6f0e316be4d67b4d4f8c9a124b073bd" + integrity sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA== + +"@open-draft/logger@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@open-draft/logger/-/logger-0.3.0.tgz#2b3ab1242b360aa0adb28b85f5d7da1c133a0954" + integrity sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ== + dependencies: + is-node-process "^1.2.0" + outvariant "^1.4.0" + +"@open-draft/until@^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-2.1.0.tgz#0acf32f470af2ceaf47f095cdecd40d68666efda" + integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== + "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1": version "1.8.3" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" @@ -3639,6 +3669,11 @@ is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" +is-node-process@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134" + integrity sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw== + is-number-object@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.5.tgz#6edfaeed7950cff19afedce9fbfca9ee6dd289eb" @@ -4200,12 +4235,12 @@ nise@^5.0.1: just-extend "^4.0.2" path-to-regexp "^1.7.0" -nock@13.5.4: - version "13.5.4" - resolved "https://registry.yarnpkg.com/nock/-/nock-13.5.4.tgz#8918f0addc70a63736170fef7106a9721e0dc479" - integrity sha512-yAyTfdeNJGGBFxWdzSKCBYxs5FxLbCg5X5Q4ets974hcQzG1+qCxvIyOo4j2Ry6MUlhWVMX4OoYDefAIIwupjw== +nock@^14: + version "14.0.16" + resolved "https://registry.yarnpkg.com/nock/-/nock-14.0.16.tgz#d92dcc85ecf704791ef0bacb2447f81ea5ec52f4" + integrity sha512-8r4KEc6nT1D/fdLD/R1BO1CPaVEL8o40u/guFRJlXabN7vr3RmMqyjsY5Krt0nMwhsOAwXQ/mtN5vy5Jh3aErg== dependencies: - debug "^4.1.0" + "@mswjs/interceptors" "^0.41.0" json-stringify-safe "^5.0.1" propagate "^2.0.0" @@ -4389,6 +4424,11 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +outvariant@^1.4.0, outvariant@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.3.tgz#221c1bfc093e8fec7075497e7799fdbf43d14873" + integrity sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA== + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -5061,6 +5101,11 @@ sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" +strict-event-emitter@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz#1602ece81c51574ca39c6815e09f1a3e8550bd93" + integrity sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ== + string-argv@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" From df0bd8240664128d9da05ba7c8f294e803a0ab6c Mon Sep 17 00:00:00 2001 From: Beka Baizhan Date: Mon, 6 Jul 2026 16:17:08 -0700 Subject: [PATCH 2/6] ci: run tests on pull requests regardless of base branch --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 561fe4b3..e36c91aa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,6 @@ on: push: branches: [master] pull_request: - branches: [master] jobs: test: From 7dacc5929f2f28ac0b232dff35fd41b794b02027 Mon Sep 17 00:00:00 2001 From: Beka Baizhan Date: Mon, 6 Jul 2026 16:20:30 -0700 Subject: [PATCH 3/6] ci: authenticate to npm.goodeggs.com for @goodeggs scoped packages Same pattern as goodeggs-stats: .npmrc references NPM_TOKEN, workflows inject the secret. Needed to fetch @goodeggs/toolkit and tsconfig tarballs, which the registry gates behind auth. --- .github/workflows/ci.yml | 2 ++ .github/workflows/publish.yml | 2 ++ .npmrc | 2 ++ 3 files changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e36c91aa..b1ced2d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,8 @@ on: jobs: test: runs-on: ubuntu-latest + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8bd7ed92..08aa7b8d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -8,6 +8,8 @@ on: jobs: publish: runs-on: ubuntu-latest + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 diff --git a/.npmrc b/.npmrc index 75deb505..601fc5aa 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,3 @@ registry = https://registry.npmjs.org/ +@goodeggs:registry=https://npm.goodeggs.com/ +//npm.goodeggs.com/:_authToken=${NPM_TOKEN} From 248607ce85a7b18313cd2af3557381198439d2da Mon Sep 17 00:00:00 2001 From: Beka Baizhan Date: Mon, 6 Jul 2026 16:23:42 -0700 Subject: [PATCH 4/6] ci: use a dedicated npmjs token for publishing NPM_TOKEN is the npm.goodeggs.com read token used during install; the publish step targets the public npmjs registry and needs its own token. --- .github/workflows/publish.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 08aa7b8d..f63bc418 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -18,6 +18,8 @@ jobs: cache: yarn registry-url: https://registry.npmjs.org - run: yarn install --frozen-lockfile + # NPM_TOKEN reads @goodeggs packages from npm.goodeggs.com during install; + # NPMJS_PUBLISH_TOKEN publishes this package to the public npmjs registry. - run: npm publish env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPMJS_PUBLISH_TOKEN }} From fc5bf482f2354c8f37a647c835c94c62b77a841d Mon Sep 17 00:00:00 2001 From: Beka Baizhan Date: Mon, 6 Jul 2026 16:26:33 -0700 Subject: [PATCH 5/6] ci: write registry token at runtime; yarn 1 does not expand npmrc env vars --- .github/workflows/ci.yml | 2 ++ .github/workflows/publish.yml | 4 +++- .npmrc | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1ced2d4..48e141ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,5 +16,7 @@ jobs: with: node-version: 22 cache: yarn + # yarn 1 does not expand env vars in .npmrc, so write the token at runtime + - run: echo "//npm.goodeggs.com/:_authToken=${NPM_TOKEN}" >> .npmrc - run: yarn install --frozen-lockfile - run: yarn test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f63bc418..c6688756 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -17,9 +17,11 @@ jobs: node-version: 22 cache: yarn registry-url: https://registry.npmjs.org - - run: yarn install --frozen-lockfile + # yarn 1 does not expand env vars in .npmrc, so write the token at runtime. # NPM_TOKEN reads @goodeggs packages from npm.goodeggs.com during install; # NPMJS_PUBLISH_TOKEN publishes this package to the public npmjs registry. + - run: echo "//npm.goodeggs.com/:_authToken=${NPM_TOKEN}" >> .npmrc + - run: yarn install --frozen-lockfile - run: npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPMJS_PUBLISH_TOKEN }} diff --git a/.npmrc b/.npmrc index 601fc5aa..2b469737 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1,2 @@ registry = https://registry.npmjs.org/ @goodeggs:registry=https://npm.goodeggs.com/ -//npm.goodeggs.com/:_authToken=${NPM_TOKEN} From e2cf73de1edcc6010115020a73c6931e66139bba Mon Sep 17 00:00:00 2001 From: Beka Baizhan Date: Mon, 6 Jul 2026 16:29:38 -0700 Subject: [PATCH 6/6] ci: install via npm.goodeggs.com default registry with runtime auth yarn 1 neither expands env vars in .npmrc nor attaches credentials to scope-routed registries; setting the proxying registry as default with always-auth and a host-scoped token is the combination that works. --- .github/workflows/ci.yml | 9 +++++++-- .github/workflows/publish.yml | 12 +++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 48e141ba..3806f21e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,12 @@ jobs: with: node-version: 22 cache: yarn - # yarn 1 does not expand env vars in .npmrc, so write the token at runtime - - run: echo "//npm.goodeggs.com/:_authToken=${NPM_TOKEN}" >> .npmrc + # yarn 1 does not expand env vars in .npmrc and does not attach credentials to + # scope-routed registries, so write the token AND make npm.goodeggs.com (which + # proxies npmjs) the default registry at runtime. Later npmrc lines win. + - run: | + echo "registry=https://npm.goodeggs.com" >> .npmrc + echo "always-auth=true" >> .npmrc + echo "//npm.goodeggs.com/:_authToken=${NPM_TOKEN}" >> .npmrc - run: yarn install --frozen-lockfile - run: yarn test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c6688756..094c1559 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -17,10 +17,16 @@ jobs: node-version: 22 cache: yarn registry-url: https://registry.npmjs.org - # yarn 1 does not expand env vars in .npmrc, so write the token at runtime. + # yarn 1 does not expand env vars in .npmrc and does not attach credentials to + # scope-routed registries, so write the token AND make npm.goodeggs.com (which + # proxies npmjs) the default registry at runtime. Later npmrc lines win. # NPM_TOKEN reads @goodeggs packages from npm.goodeggs.com during install; - # NPMJS_PUBLISH_TOKEN publishes this package to the public npmjs registry. - - run: echo "//npm.goodeggs.com/:_authToken=${NPM_TOKEN}" >> .npmrc + # NPMJS_PUBLISH_TOKEN publishes this package to the public npmjs registry + # (npm publish targets publishConfig.registry, not the default registry). + - run: | + echo "registry=https://npm.goodeggs.com" >> .npmrc + echo "always-auth=true" >> .npmrc + echo "//npm.goodeggs.com/:_authToken=${NPM_TOKEN}" >> .npmrc - run: yarn install --frozen-lockfile - run: npm publish env: