diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..e279b72
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,63 @@
+name: CI
+
+on:
+ pull_request:
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
+ cancel-in-progress: true
+
+jobs:
+ tests:
+ strategy:
+ fail-fast: false
+
+ matrix:
+ node: [ 20, 22 ]
+
+ platform:
+ - { name: MacOS, os: macOS-latest }
+ - { name: Linux, os: ubuntu-latest }
+ - { name: Windows, os: windows-latest }
+
+ include:
+ - os: ubuntu-latest
+ node: 20
+ lint: true
+ coverage: true
+
+ name: Node ${{ matrix.node }} on ${{ matrix.platform.name }}
+ runs-on: ${{ matrix.platform.os }}
+ timeout-minutes: 5
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node.js v${{ matrix.node }}
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node }}
+ cache: npm
+ cache-dependency-path: package-lock.json
+
+ - run: npm ci
+
+ - if: ${{ matrix.lint }}
+ run: npm run lint
+
+ - run: npm run build
+
+ - run: npm test
+
+ - name: Upload artifacts
+ if: ${{ success() && matrix.coverage }}
+ uses: actions/upload-artifact@v4
+ with:
+ name: artifacts
+ path: |
+ ./packages/**/dist
+ ./packages/**/README.md
+ ./packages/**/package.json
+ ./packages/**/coverage/lcov.info
+ overwrite: 'true'
+ retention-days: 1
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..5c90d70
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,159 @@
+name: Release
+
+on:
+ workflow_run:
+ workflows: [ "CI" ]
+ types:
+ - completed
+
+jobs:
+ debug:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Debug
+ run: echo ${{ toJSON(github.event.workflow_run) }}
+
+# publish:
+# if: >
+# github.event.workflow_run.conclusion == 'success' &&
+# (
+# github.event.workflow_run.head_branch == 'main' ||
+# github.event.workflow_run.head_branch == 'staging'
+# )
+#
+# runs-on: ubuntu-latest
+#
+# permissions:
+# contents: write
+# id-token: write
+#
+# steps:
+# - uses: actions/checkout@v4
+# with:
+# fetch-depth: 0
+#
+# - uses: actions/setup-node@v4
+# with:
+# cache: npm
+# node-version: 22
+# registry-url: "https://registry.npmjs.org"
+#
+# - name: Download dist artifacts
+# uses: dawidd6/action-download-artifact@v2
+# with:
+# run_id: ${{ github.event.workflow_run.id }}
+# name: artifacts
+# path: ./artifacts
+#
+# ###############################################################
+# # 2. находим пакеты, у которых изменилась версия
+# ###############################################################
+# - name: Detect changed packages
+# id: detect
+# run: |
+# node ./scripts/changed-packages.js >> "$GITHUB_OUTPUT"
+#
+# ###############################################################
+# # 3. публикуем каждый изменившийся пакет
+# ###############################################################
+# - name: Publish to npm
+# if: steps.detect.outputs.changed != ''
+# env:
+# NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+# run: |
+# IFS=',' read -ra PKGS <<< "${{ steps.detect.outputs.changed }}"
+# for P in "${PKGS[@]}"; do
+# echo "Publishing $P"
+# npm publish "./artifacts/dist-$P" --tag latest --access public
+# done
+#
+# ###############################################################
+# # 4. создаём теги и Release-страницу
+# ###############################################################
+# - name: Push git tags
+# if: steps.detect.outputs.changed != ''
+# run: |
+# IFS=',' read -ra PKGS <<< "${{ steps.detect.outputs.changed }}"
+# for P in "${PKGS[@]}"; do
+# VER=$(jq -r .version < packages/$P/package.json)
+# git tag "$P@$VER"
+# done
+# git push --tags
+#
+# - name: GitHub Release
+# if: steps.detect.outputs.changed != ''
+# uses: softprops/action-gh-release@v1
+# with:
+# tag_name: ${{ github.ref_name }} # последний созданный тег
+# generate_release_notes: true
+#
+# bump:
+# runs-on: ubuntu-latest
+#
+# steps:
+# - name: Checkout code
+# uses: actions/checkout@v4
+# with:
+# fetch-tags: true
+# fetch-depth: 0
+#
+# - name: Setup Node.js
+# uses: actions/setup-node@v4
+# with:
+# cache: 'npm'
+# node-version: 22
+# registry-url: 'https://registry.npmjs.org/'
+#
+# - name: Install dependencies
+# run: npm ci
+#
+# - name: Create builds
+# run: npm run build
+#
+# - name: Configure Git for Lerna
+# run: |
+# git config user.name "github-actions[bot]"
+# git config user.email "github-actions[bot]@users.noreply.github.com"
+#
+# - name: Bump versions
+# env:
+# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+# NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+# run: |
+# npx lerna version --yes --no-push
+# git push origin HEAD:releases/pr-${{ github.event.pull_request.number }}
+#
+# for TAG in $(git tag); do
+# if git ls-remote --tags origin refs/tags/$TAG | grep -q $TAG; then
+# echo "Tag $TAG already exists on the remote server, skipping"
+# else
+# git push origin $TAG
+# gh release create "$TAG" --generate-notes
+#
+# echo "Tag $TAG successfully created"
+# fi
+# done
+#
+# npx lerna publish from-git --yes
+#
+# - name: Create Release Pull Request
+# id: cpr
+# uses: peter-evans/create-pull-request@v7
+# with:
+# token: ${{ secrets.GITHUB_TOKEN }}
+# commit-message: 'chore(release): bump versions'
+# title: 'chore(release): bump versions'
+# body: Automated version bump & changelog
+# base: main
+# branch: releases/pr-${{ github.event.pull_request.number }}
+# labels: automerge
+# delete-branch: true
+#
+# - name: Enable auto-merge on Release PR
+# if: steps.cpr.outputs.pull-request-number != ''
+# uses: peter-evans/enable-pull-request-automerge@v3
+# with:
+# token: ${{ secrets.GITHUB_TOKEN }}
+# pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
+# merge-method: squash
diff --git a/.github/workflows/releasing.yml b/.github/workflows/releasing.yml
index 7dbf307..3fe4b74 100644
--- a/.github/workflows/releasing.yml
+++ b/.github/workflows/releasing.yml
@@ -1,7 +1,8 @@
name: Releasing
on:
- pull_request:
+ push:
+# pull_request:
types:
- closed
branches:
diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml
index a7438cd..a9f10b5 100644
--- a/.github/workflows/report.yml
+++ b/.github/workflows/report.yml
@@ -1,34 +1,42 @@
-name: Testing
+name: Reporting
on:
- push:
- branches:
- - main
+ workflow_run:
+ workflows: [ "__CI__" ]
+ types:
+ - completed
jobs:
codecov:
- runs-on: ubuntu-latest
+ if: >
+ github.event.workflow_run.conclusion == 'success' &&
+ github.event.workflow_run.pull_requests[0].merged == true &&
+ (
+ github.event.workflow_run.pull_requests[0].base.ref == 'main' ||
+ github.event.workflow_run.pull_requests[0].base.ref == 'tests'
+ )
- steps:
- - uses: actions/checkout@v4
+ strategy:
+ fail-fast: false
- - name: Setup Node.js ${{ matrix.node_version }}
- uses: actions/setup-node@v4
- with:
- cache: 'npm'
- node-version: 22
+ matrix:
+ package: [ httio, rest ]
- - name: Install dependencies
- run: npm ci
+ runs-on: ubuntu-latest
- - name: Run tests
- run: npm test
+ steps:
+ - name: Download coverage artifact
+ uses: dawidd6/action-download-artifact@v2
+ with:
+ run_id: ${{ github.event.workflow_run.id }}
+ name: coverage
+ path: ./coverage
- - name: Upload coverage reports to Codecov
+ - name: Upload ${{ matrix.package }} coverage to Codecov
uses: codecov/codecov-action@v5
with:
- slug: vladstsk/httio
- flags: httio,rest
- files: ./packages/httio/coverage/lcov.info,./packages/rest/coverage/lcov.info
+ name: ${{ matrix.package }}
token: ${{ secrets.CODECOV_TOKEN }}
+ files: ./coverage/packages/${{ matrix.package }}/coverage/lcov.info
+ flags: ${{ matrix.package }}
fail_ci_if_error: true
diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
deleted file mode 100644
index 413d263..0000000
--- a/.github/workflows/testing.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-name: Testing
-
-on:
- pull_request:
- branches:
- - main
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: true
-
-jobs:
- test:
- name: Test on node ${{ matrix.node_version }} and ${{ matrix.os }}
- runs-on: ${{ matrix.os }}
- if: ${{ github.head_ref != 'release' }}
-
- strategy:
- matrix:
- os:
- - macOS-latest
- - ubuntu-latest
- - windows-latest
- node-version:
- - 20.x
- - 22.x
-
- steps:
- - uses: actions/checkout@v4
-
- - name: Setup Node.js ${{ matrix.node_version }}
- uses: actions/setup-node@v4
- with:
- cache: 'npm'
- node-version: ${{ matrix.node-version }}
-
- - name: Install dependencies
- run: npm ci
-
- - name: Run linter
- run: npm run lint
-
- - name: Create builds
- run: npm run build
-
- - name: Run tests
- run: npm test
diff --git a/README.md b/README.md
index 9bf39c2..d0eeb30 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# **Httio**
-[](https://codecov.io/gh/vladstsk/httio)
+[](https://codecov.io/gh/vladstsk/httio?flag=httio)
[](https://bundlephobia.com/package/httio)
[](https://bundlephobia.com/package/httio)
[](https://github.com/vladstsk/httio)
@@ -43,30 +43,30 @@
## Why Httio?
-| Feature | Description |
-|------------------------------|-------------------------------------------------------------------------------------------------------|
-| **TypeScript-first** | All public types are exported; strict compile-time checks. |
-| **Tiny footprint** | Ships as ESM + CJS, zero runtime dependencies. |
-| **Lazy parsing** | Body is not parsed automatically—_you_ decide when and how. |
-| **One interface everywhere** | Works in browsers, Node 18+, edge functions—no polyfills required. |
-| **Extensible** | Middleware chain for logging, auth, caching, etc. |
-| **Convenient cloning** | `extends()` lets you reuse and override base options elegantly. |
-| **Full control** | Everything from `fetch` is exposed plus syntactic sugar (`params`, `json`, `timeout`). |
+| Feature | Description |
+|------------------------------|----------------------------------------------------------------------------------------|
+| **TypeScript-first** | All public types are exported; strict compile-time checks. |
+| **Tiny footprint** | Ships as ESM + CJS, zero runtime dependencies. |
+| **Lazy parsing** | Body is not parsed automatically—_you_ decide when and how. |
+| **One interface everywhere** | Works in browsers, Node 18+, edge functions—no polyfills required. |
+| **Extensible** | Middleware chain for logging, auth, caching, etc. |
+| **Convenient cloning** | `extends()` lets you reuse and override base options elegantly. |
+| **Full control** | Everything from `fetch` is exposed plus syntactic sugar (`params`, `json`, `timeout`). |
---
## Httio vs. The Rest
-| Library | Size
(min + gzip) | TS‑first | Browser | Node | Native `fetch` | Middleware | Retries | Deps | Notes |
-|------------------|:--------------------------------------------------------------------------:|:--------------:|:-------:|:----:|:-------------------:|:----------:|:-------:|:--------------------------------------------------------------------------------------------------------------------------------------:|-------------------------------|
-| **Httio** |  | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | [](https://bundlephobia.com/package/httio) | Modern, tiny |
-| Axios |  | ⚠️ | ✅ | ✅ | ❌ | ⚠️ | ⚠️ | [](https://bundlephobia.com/package/axios) | Heavy |
-| isomorphic-fetch |  | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | [](https://bundlephobia.com/package/isomorphic-fetch) | Simple shim |
-| ky |  | ✅ | ✅ | ✅ | ✅ | ⚠️ | ✅ | [](https://bundlephobia.com/package/ky) | Small, fetch‑first |
-| superagent |  | ⚠️ | ✅ | ✅ | ❌ | ✅ | ⚠️ | [](https://bundlephobia.com/package/superagent) | Classic |
-| request |  | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | [](https://bundlephobia.com/package/request) | Deprecated |
-| r2 |  | ⚠️ | ❌ | ✅ | ✅ | ❌ | ❌ | [](https://bundlephobia.com/package/r2) | Minimal |
-| phin |  | ⚠️ | ❌ | ✅ | ❌ | ❌ | ✅ | [](https://bundlephobia.com/package/phin) | Promise client |
+| Library | Size
(min + gzip) | TS‑first | Browser | Node | Native `fetch` | Middleware | Retries | Deps | Notes |
+|------------------------|:-------------------------------------------------------------------------------------------------------------------------------:|:--------------:|:-------:|:----:|:-------------------:|:----------:|:-------:|:-------------------------------------------------------------------------------------------------------------------------------------:|-------------------------------|
+| **Httio** | [](https://bundlephobia.com/package/httio) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | [](https://bundlephobia.com/package/httio) | Modern, tiny |
+| Axios | [](https://bundlephobia.com/package/axios) | ⚠️ | ✅ | ✅ | ❌ | ⚠️ | ⚠️ | [](https://bundlephobia.com/package/axios) | Heavy |
+| isomorphic‑fetch | [](https://bundlephobia.com/package/isomorphic-fetch) | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | [](https://bundlephobia.com/package/isomorphic-fetch) | Simple shim |
+| ky | [](https://bundlephobia.com/package/ky) | ✅ | ✅ | ✅ | ✅ | ⚠️ | ✅ | [](https://bundlephobia.com/package/ky) | Small, fetch‑first |
+| superagent | [](https://bundlephobia.com/package/superagent) | ⚠️ | ✅ | ✅ | ❌ | ✅ | ⚠️ | [](https://bundlephobia.com/package/superagent) | Classic |
+| request | [](https://bundlephobia.com/package/request) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | [](https://bundlephobia.com/package/request) | Deprecated |
+| r2 | [](https://bundlephobia.com/package/r2) | ⚠️ | ❌ | ✅ | ✅ | ❌ | ❌ | [](https://bundlephobia.com/package/r2) | Minimal |
+| phin | [](https://bundlephobia.com/package/phin) | ⚠️ | ❌ | ✅ | ❌ | ❌ | ✅ | [](https://bundlephobia.com/package/phin) | Promise client |
### Key takeaways
diff --git a/packages/httio/README.md b/packages/httio/README.md
index 748cdb1..7446e38 100644
--- a/packages/httio/README.md
+++ b/packages/httio/README.md
@@ -43,30 +43,30 @@
## Why Httio?
-| Feature | Description |
-|------------------------------|-------------------------------------------------------------------------------------------------------|
-| **TypeScript-first** | All public types are exported; strict compile-time checks. |
-| **Tiny footprint** | Ships as ESM + CJS, zero runtime dependencies. |
-| **Lazy parsing** | Body is not parsed automatically—_you_ decide when and how. |
-| **One interface everywhere** | Works in browsers, Node 18+, edge functions—no polyfills required. |
-| **Extensible** | Middleware chain for logging, auth, caching, etc. |
-| **Convenient cloning** | `extends()` lets you reuse and override base options elegantly. |
-| **Full control** | Everything from `fetch` is exposed plus syntactic sugar (`params`, `json`, `timeout`). |
+| Feature | Description |
+|------------------------------|----------------------------------------------------------------------------------------|
+| **TypeScript-first** | All public types are exported; strict compile-time checks. |
+| **Tiny footprint** | Ships as ESM + CJS, zero runtime dependencies. |
+| **Lazy parsing** | Body is not parsed automatically—_you_ decide when and how. |
+| **One interface everywhere** | Works in browsers, Node 18+, edge functions—no polyfills required. |
+| **Extensible** | Middleware chain for logging, auth, caching, etc. |
+| **Convenient cloning** | `extends()` lets you reuse and override base options elegantly. |
+| **Full control** | Everything from `fetch` is exposed plus syntactic sugar (`params`, `json`, `timeout`). |
---
## Httio vs. The Rest
-| Library | Size
(min + gzip) | TS‑first | Browser | Node | Native `fetch` | Middleware | Retries | Deps | Notes |
-|------------------|:--------------------------------------------------------------------------:|:--------------:|:-------:|:----:|:-------------------:|:----------:|:-------:|:--------------------------------------------------------------------------------------------------------------------------------------:|-------------------------------|
-| **Httio** |  | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | [](https://bundlephobia.com/package/httio) | Modern, tiny |
-| Axios |  | ⚠️ | ✅ | ✅ | ❌ | ⚠️ | ⚠️ | [](https://bundlephobia.com/package/axios) | Heavy |
-| isomorphic-fetch |  | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | [](https://bundlephobia.com/package/isomorphic-fetch) | Simple shim |
-| ky |  | ✅ | ✅ | ✅ | ✅ | ⚠️ | ✅ | [](https://bundlephobia.com/package/ky) | Small, fetch‑first |
-| superagent |  | ⚠️ | ✅ | ✅ | ❌ | ✅ | ⚠️ | [](https://bundlephobia.com/package/superagent) | Classic |
-| request |  | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | [](https://bundlephobia.com/package/request) | Deprecated |
-| r2 |  | ⚠️ | ❌ | ✅ | ✅ | ❌ | ❌ | [](https://bundlephobia.com/package/r2) | Minimal |
-| phin |  | ⚠️ | ❌ | ✅ | ❌ | ❌ | ✅ | [](https://bundlephobia.com/package/phin) | Promise client |
+| Library | Size
(min + gzip) | TS‑first | Browser | Node | Native `fetch` | Middleware | Retries | Deps | Notes |
+|------------------------|:-------------------------------------------------------------------------------------------------------------------------------:|:--------------:|:-------:|:----:|:-------------------:|:----------:|:-------:|:-------------------------------------------------------------------------------------------------------------------------------------:|-------------------------------|
+| **Httio** | [](https://bundlephobia.com/package/httio) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | [](https://bundlephobia.com/package/httio) | Modern, tiny |
+| Axios | [](https://bundlephobia.com/package/axios) | ⚠️ | ✅ | ✅ | ❌ | ⚠️ | ⚠️ | [](https://bundlephobia.com/package/axios) | Heavy |
+| isomorphic‑fetch | [](https://bundlephobia.com/package/isomorphic-fetch) | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | [](https://bundlephobia.com/package/isomorphic-fetch) | Simple shim |
+| ky | [](https://bundlephobia.com/package/ky) | ✅ | ✅ | ✅ | ✅ | ⚠️ | ✅ | [](https://bundlephobia.com/package/ky) | Small, fetch‑first |
+| superagent | [](https://bundlephobia.com/package/superagent) | ⚠️ | ✅ | ✅ | ❌ | ✅ | ⚠️ | [](https://bundlephobia.com/package/superagent) | Classic |
+| request | [](https://bundlephobia.com/package/request) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | [](https://bundlephobia.com/package/request) | Deprecated |
+| r2 | [](https://bundlephobia.com/package/r2) | ⚠️ | ❌ | ✅ | ✅ | ❌ | ❌ | [](https://bundlephobia.com/package/r2) | Minimal |
+| phin | [](https://bundlephobia.com/package/phin) | ⚠️ | ❌ | ✅ | ❌ | ❌ | ✅ | [](https://bundlephobia.com/package/phin) | Promise client |
### Key takeaways