Skip to content

feat!: make the client's own code runtime-independent - #1052

Merged
vdusek merged 21 commits into
v3from
feat/runtime-independent
Sep 14, 2026
Merged

vdusek merged 21 commits into
v3from
feat/runtime-independent

Conversation

@vdusek

@vdusek vdusek commented Sep 9, 2026 •

Copy link
Copy Markdown
Contributor

Description

The client's own code imports no Node.js built-in. The Node-only parts, keep-alive HTTP agents with proxy support and request body compression, live in src/runtime/node.ts, with a Web API twin in src/runtime/web.ts. The #runtime entry in imports picks between them: the node condition resolves to the Node.js module, everything else to the Web API one, so a bundler targeting a browser or an edge runtime never sees node:zlib, node:os, node:util or proxy-agent. Node.js, Bun and Deno keep today's behavior.

Base64 encoding, byte counting, log chunk joining and response decoding go through TextEncoder, TextDecoder and btoa, so the isNode() sniff and the BROWSER_BUILD and VERSION globals are gone. rsbuild also needs aliasStrategy: 'prefer-alias', so the tsconfig.json paths entry stops beating the #runtime alias. The bundle is 324 kB, down from 335 kB.

Issues

Testing

  • test/runtime.test.ts covers both implementations and bundles dist with esbuild to assert that browser, Cloudflare Workers, neutral and Node.js targets each resolve #runtime to the right file, and that the Web API build imports no node: module.

Breaking changes

  • TextDecoder decodes response bodies instead of Buffer, so a content-type charset can be handled differently: iso-8859-1 and similar decode to a string, hex and base64 come back as raw bytes, ascii is read as windows-1252, and a leading UTF-8 BOM is stripped.
  • Request compression now accepts Uint8Array and ArrayBuffer bodies, which gain a content-encoding header.
  • Anything asking for the browser condition gets the Web API implementation even on Node.js. Jest's jsdom environment does, so a suite running under it loses log streaming, the stream record option, proxy support and compression unless testEnvironmentOptions.customExportConditions is set to ['node'].

The v3 upgrading guide covers all of these.

✍️ Drafted by Claude Code

@vdusek vdusek added the t-tooling Issues with this label are in the ownership of the tooling team. label Sep 9, 2026
@vdusek vdusek self-assigned this Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ There are broken links in the documentation.

See more at https://github.com/apify/apify-client-js/actions/runs/34865780956#summary-104049155831

@vdusek
vdusek requested a review from B4nan September 10, 2026 10:08
@vdusek
vdusek marked this pull request as ready for review September 10, 2026 10:08
@vdusek
vdusek requested a review from szaganek as a code owner September 10, 2026 10:08
# Conflicts:
#	src/interceptors.ts
#	src/utils.ts
@B4nan
B4nan requested a review from barjin September 11, 2026 07:07
# Conflicts:
#	src/apify_client.ts
#	src/http_client.ts
#	src/resource_clients/key_value_store.ts
#	src/resource_clients/log.ts
#	src/resource_clients/run.ts
# Conflicts:
#	docs/04_upgrading/upgrading_v3.md
#	src/http_client.ts
#	src/resource_clients/log.ts
#	test/utils.test.ts

@B4nan B4nan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. A few suggestions below, mostly one-liners.

Comment thread src/body_parser.ts Outdated
Comment thread test/body_parser.test.ts Outdated
Comment thread docs/04_upgrading/upgrading_v3.md Outdated
Comment thread docs/04_upgrading/upgrading_v3.md Outdated
Comment thread docs/04_upgrading/upgrading_v3.md Outdated
Comment thread src/utils.ts Outdated

@barjin barjin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the changes in the decoding could cause some very niche edge cases (e.g., when reading KVS records), but it's overall a step in the right direction imo, so approving.

Thanks @vdusek !

@vdusek
vdusek merged commit 480c34a into v3 Sep 14, 2026
8 checks passed
@vdusek
vdusek deleted the feat/runtime-independent branch September 14, 2026 16:11
B4nan pushed a commit that referenced this pull request Sep 30, 2026
## Description

The client's own code imports no Node.js built-in. The Node-only parts,
keep-alive HTTP agents with proxy support and request body compression,
live in `src/runtime/node.ts`, with a Web API twin in
`src/runtime/web.ts`. The `#runtime` entry in `imports` picks between
them: the `node` condition resolves to the Node.js module, everything
else to the Web API one, so a bundler targeting a browser or an edge
runtime never sees `node:zlib`, `node:os`, `node:util` or `proxy-agent`.
Node.js, Bun and Deno keep today's behavior.

Base64 encoding, byte counting, log chunk joining and response decoding
go through `TextEncoder`, `TextDecoder` and `btoa`, so the `isNode()`
sniff and the `BROWSER_BUILD` and `VERSION` globals are gone. rsbuild
also needs `aliasStrategy: 'prefer-alias'`, so the `tsconfig.json`
`paths` entry stops beating the `#runtime` alias. The bundle is 324 kB,
down from 335 kB.

## Issues

- Closes #753.
- `@apify/log` and `@apify/utilities` still import `node:events`,
`node:stream` and `node:crypto`, so bundling the ES module build for a
non-Node.js target needs polyfills for `events`, `process`, `stream` and
`buffer`; tracked in apify/apify-shared-js#537.

## Testing

- `test/runtime.test.ts` covers both implementations and bundles `dist`
with esbuild to assert that browser, Cloudflare Workers, neutral and
Node.js targets each resolve `#runtime` to the right file, and that the
Web API build imports no `node:` module.

## Breaking changes

- `TextDecoder` decodes response bodies instead of `Buffer`, so a
`content-type` charset can be handled differently: `iso-8859-1` and
similar decode to a string, `hex` and `base64` come back as raw bytes,
`ascii` is read as `windows-1252`, and a leading UTF-8 BOM is stripped.
- Request compression now accepts `Uint8Array` and `ArrayBuffer` bodies,
which gain a `content-encoding` header.
- Anything asking for the `browser` condition gets the Web API
implementation even on Node.js. Jest's `jsdom` environment does, so a
suite running under it loses log streaming, the `stream` record option,
proxy support and compression unless
`testEnvironmentOptions.customExportConditions` is set to `['node']`.

The v3 upgrading guide covers all of these.

*✍️ Drafted by Claude Code*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t-tooling Issues with this label are in the ownership of the tooling team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants