Skip to content

Commit

Permalink
feat(js): add ReadableStream in Response.body (#28)
Browse files Browse the repository at this point in the history
Accessing `Response.body` now returns an instance of JS
`ReadableStream`. This API design matches the (browser) Fetch API spec.
In order to correctly manage the `Response` consumption, the current
codebase has been slightly refactored.

Note that the implementation relies on a prerelease version of the
`napi-rs` tooling.

Closes #24
  • Loading branch information
barjin authored Feb 5, 2025
1 parent a73a738 commit 092b155
Show file tree
Hide file tree
Showing 11 changed files with 1,345 additions and 405 deletions.
37 changes: 25 additions & 12 deletions .github/workflows/node-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,33 @@ jobs:
build: yarn --cwd impit-node build --target x86_64-unknown-linux-gnu
- host: ubuntu-latest
target: x86_64-unknown-linux-musl
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
docker: node:20-alpine
# Script taken from https://github.com/napi-rs/napi-rs/blob/main/alpine.Dockerfile
build: |
apk add perl &&
ln -s /usr/lib/gcc/x86_64-alpine-linux-musl/14.2.0/crtbeginS.o /usr/lib/crtbeginS.o &&
ln -s /usr/lib/gcc/x86_64-alpine-linux-musl/14.2.0/crtendS.o /usr/lib/crtendS.o &&
ln -s /usr/lib/gcc/x86_64-alpine-linux-musl/14.2.0/libgcc.a /usr/lib/libgcc.a &&
RUSTFLAGS="--cfg reqwest_unstable" yarn --cwd impit-node build --target x86_64-unknown-linux-musl
export PATH="/aarch64-linux-musl-cross/bin:/usr/local/cargo/bin/rustup:/root/.cargo/bin:$PATH" RUSTFLAGS="-C target-feature=-crt-static --cfg reqwest_unstable" CC="clang" CXX="clang++" GN_EXE=gn &&
apk add --update --no-cache bash wget cmake musl-dev clang llvm build-base python3 &&
sed -i -e 's/v[[:digit:]]\..*\//edge\//g' /etc/apk/repositories &&
apk add --update --no-cache --repository https://dl-cdn.alpinelinux.org/alpine/edge/testing rustup git gn tar ninja &&
apk update &&
apk upgrade &&
rustup-init -y &&
yarn global add pnpm lerna &&
rustup target add aarch64-unknown-linux-musl &&
wget https://github.com/napi-rs/napi-rs/releases/download/linux-musl-cross%4010/aarch64-linux-musl-cross.tgz &&
tar -xvf aarch64-linux-musl-cross.tgz &&
rm aarch64-linux-musl-cross.tgz &&
apk add perl &&
ln -s /usr/lib/gcc/x86_64-alpine-linux-musl/14.2.0/crtbeginS.o /usr/lib/crtbeginS.o &&
ln -s /usr/lib/gcc/x86_64-alpine-linux-musl/14.2.0/crtendS.o /usr/lib/crtendS.o &&
ln -s /usr/lib/gcc/x86_64-alpine-linux-musl/14.2.0/libgcc.a /usr/lib/libgcc.a &&
yarn --cwd impit-node build --target x86_64-unknown-linux-musl
- host: macos-latest
target: aarch64-apple-darwin
build: yarn --cwd impit-node build --target aarch64-apple-darwin
- host: windows-latest
target: aarch64-pc-windows-msvc
build: yarn --cwd impit-node build --target aarch64-pc-windows-msvc
name: stable - ${{ matrix.settings.target }} - node@20
name: stable - ${{ matrix.settings.target }} - node@22
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v4
Expand All @@ -67,7 +80,7 @@ jobs:
uses: actions/setup-node@v4
if: ${{ !matrix.settings.docker }}
with:
node-version: 20
node-version: 22
cache: yarn
cache-dependency-path: impit-node/yarn.lock
- name: Install
Expand Down Expand Up @@ -104,7 +117,7 @@ jobs:
uses: actions/setup-node@v4
if: matrix.settings.target == 'i686-pc-windows-msvc'
with:
node-version: 20
node-version: 22
cache: yarn
cache-dependency-path: impit-node/yarn.lock
architecture: x86
Expand Down Expand Up @@ -138,8 +151,8 @@ jobs:
- host: windows-latest
target: x86_64-pc-windows-msvc
node:
- '18'
- '20'
- '22'
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -170,8 +183,8 @@ jobs:
fail-fast: false
matrix:
node:
- '18'
- '20'
- '22'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -201,8 +214,8 @@ jobs:
fail-fast: false
matrix:
node:
- '18'
- '20'
- '22'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
55 changes: 40 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions impit-node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ crate-type = ["cdylib"]

[dependencies]
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { version = "2.12.2", default-features = false, features = ["napi4", "async"] }
napi-derive = "2.12.2"
napi = { version = "3.0.0-alpha.27", default-features = false, features = ["napi4", "async", "web_stream"] }
napi-derive = "3.0.0-alpha.25"
impit = { path="../impit" }
rustls = { version="0.23.16" }
tokio = { version="1.41.1", features = ["full"] }
h2 = "0.4.7"
reqwest = "0.12.9"
tokio-stream = "0.1.17"
bytes = "1.9.0"

[build-dependencies]
napi-build = "2.0.1"
napi-build = "2.1.4"

[target.x86_64-unknown-linux-gnu.dependencies]
openssl = { version = "*", features = ["vendored"] }
Expand Down
57 changes: 30 additions & 27 deletions impit-node/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
/* tslint:disable */
/* auto-generated by NAPI-RS */
/* eslint-disable */
export declare class Impit {
constructor(options?: ImpitOptions | undefined | null)
/** Fetch a URL with the given options. */
fetch(url: string, requestInit?: RequestInit | undefined | null): Promise<ImpitResponse>
}
export type ImpitWrapper = Impit

/* auto-generated by NAPI-RS */
export declare class ImpitResponse {
status: number
statusText: string
headers: Record<string, string>
ok: boolean
bytes(this: object): Promise<Uint8Array>
text(this: object): Promise<String>
json(this: object): Promise<any>
get body(): ReadableStream<Uint8Array>
}

export const enum Browser {
export declare const enum Browser {
Chrome = 'Chrome',
Firefox = 'Firefox'
}

export declare const enum HttpMethod {
Get = 'GET',
Post = 'POST',
Put = 'PUT',
Delete = 'DELETE',
Patch = 'PATCH',
Head = 'HEAD',
Options = 'OPTIONS'
}

export interface ImpitOptions {
browser?: Browser
ignoreTlsErrors?: boolean
Expand All @@ -25,15 +51,7 @@ export interface ImpitOptions {
*/
maxRedirects?: number
}
export const enum HttpMethod {
Get = 'GET',
Post = 'POST',
Put = 'PUT',
Delete = 'DELETE',
Patch = 'PATCH',
Head = 'HEAD',
Options = 'OPTIONS'
}

export interface RequestInit {
method?: HttpMethod
headers?: Record<string, string>
Expand All @@ -43,18 +61,3 @@ export interface RequestInit {
/** Force the request to use HTTP/3. If the server doesn't expect HTTP/3, the request will fail. */
forceHttp3?: boolean
}
export declare class ImpitResponse {
status: number
statusText: string
headers: Record<string, string>
ok: boolean
bytes(): Buffer
text(): string
json(): any
}
export type ImpitWrapper = Impit
export declare class Impit {
constructor(options?: ImpitOptions | undefined | null)
/** Fetch a URL with the given options. */
fetch(url: string, requestInit?: RequestInit | undefined | null): Promise<ImpitResponse>
}
Loading

0 comments on commit 092b155

Please sign in to comment.