Skip to content

fix(axios): restore typed async response access#6852

Open
TheHypnoo wants to merge 2 commits into
mainfrom
fix/axios-async-response-properties
Open

fix(axios): restore typed async response access#6852
TheHypnoo wants to merge 2 commits into
mainfrom
fix/axios-async-response-properties

Conversation

@TheHypnoo

@TheHypnoo TheHypnoo commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

Fix Axios editor types and preserve response properties through async lowering without exposing them on unrelated native handles.

Changes

  • Preserve Axios Response native-instance metadata before async lowering splits awaited values across synthetic locals.
  • Lower status, statusText, and data reads to the existing Axios accessors.
  • Add native axios.head() and axios.options() support across optimized and bundled runtime paths.
  • Type the callable Axios default export with its static methods.
  • Run the release fixture through Perry's supported native Axios path.
  • Add a mixed Axios and node:crypto regression check for handle collisions.
  • Regenerate the Perry declaration file and add a changelog fragment.

Related issue

Fixes #6851

Test plan

  • cargo build --release -p perry
  • cargo test -p perry-hir --test axios_response_property_lowering
  • cargo test -p perry-api-manifest
  • cargo check -p perry-ext-axios
  • PERRY_NO_CACHE=1 tests/release/packages/axios-get/fixture.sh
  • tsc --noEmit against docs/api/perry.d.ts
  • git diff --check

Output

status=200
head.status=200
options.status=200
data.ok=true
data.path=/json
foreign.status=undefined
PASS axios-get

Checklist

  • I have NOT bumped the workspace version or edited CLAUDE.md / CHANGELOG.md
  • My commit follows the repository's conventional prefix style
  • I have read CONTRIBUTING.md and agree to the Code of Conduct

@TheHypnoo TheHypnoo added the bug Confirmed defect or regression label Jul 26, 2026
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Axios default exports now retain typed static methods, while async Axios response properties are preserved through native-instance lowering and compilation. Native HEAD and OPTIONS requests are wired through the runtime, with unit and release tests covering response access and isolation from unrelated handles.

Changes

Axios integration fixes

Layer / File(s) Summary
Callable Axios default export typing
crates/perry-api-manifest/src/emit.rs, docs/api/perry.d.ts
Generated and checked-in declarations represent Axios’s default export as a callable object with typed static methods, including the reserved-word delete alias.
Native Axios response property lowering
crates/perry-hir/src/js_transform/local_natives.rs, crates/perry/src/commands/compile/collect_modules.rs, crates/perry-hir/tests/axios_response_property_lowering.rs
Axios request calls are recognized as Response natives, and status, statusText, and data reads are rewritten to native dispatch, including inside string coercions and after module lowering.
Native HEAD and OPTIONS dispatch
crates/perry-codegen/..., crates/perry-ext-axios/src/lib.rs, crates/perry-stdlib/src/axios.rs, crates/perry-ui-android/src/stdlib_stubs.rs
HEAD and OPTIONS calls are routed through new FFI declarations, native request wrappers, shared no-body request handling, and Android stubs.
Release fixture validation
tests/release/packages/axios-get/*, changelog.d/6852-axios-async-response-properties.md
The native Axios fixture verifies GET, HEAD, and OPTIONS response fields and confirms status values do not leak onto unrelated hash objects. The changelog records the fixes.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TypeScript
  participant AxiosNative
  participant ResponseLowering
  participant Runtime
  TypeScript->>AxiosNative: call axios.get, axios.head, or axios.options
  AxiosNative->>Runtime: return response promise
  Runtime-->>TypeScript: resolve awaited response
  TypeScript->>ResponseLowering: access status or data
  ResponseLowering-->>TypeScript: preserve native response dispatch
Loading

Suggested labels: bug

Suggested reviewers: proggeramlug

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes address #6851 by fixing Axios default-export methods and preserving response properties after async lowering.
Out of Scope Changes check ✅ Passed No clear out-of-scope changes are present; the HEAD/OPTIONS additions support the stated Axios fix and fixture updates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title is concise and accurately reflects the main change: fixing Axios typing and async response access.
Description check ✅ Passed The description includes all required sections and sufficiently covers the summary, changes, related issue, and test plan.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/axios-async-response-properties

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@TheHypnoo
TheHypnoo force-pushed the fix/axios-async-response-properties branch from 099403c to 9a4c5fc Compare July 26, 2026 15:00

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/perry-ext-axios/src/lib.rs (1)

14-65: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Re-export NaN-boxing tags from perry-ffi instead of duplicating them here.

TAG_UNDEFINED is stable ABI documentation in perry-ffi, but the extension crate still hand-represents that ABI bit pattern. Add/forward the needed tag constants from perry-ffi and import them from crates/perry-ext-axios/src/lib.rs so this dispatch code cannot drift from its ABI contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/perry-ext-axios/src/lib.rs` around lines 14 - 65, Remove the locally
duplicated TAG_UNDEFINED definition in the axios extension and reuse the
corresponding NaN-boxing tag exported by perry-ffi. Add or re-export the
required tag constant in perry-ffi, then import that symbol in
axios_response_property_dispatch so the statusText null-pointer path uses the
shared ABI definition.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/perry-ext-axios/src/lib.rs`:
- Around line 14-65: Remove the locally duplicated TAG_UNDEFINED definition in
the axios extension and reuse the corresponding NaN-boxing tag exported by
perry-ffi. Add or re-export the required tag constant in perry-ffi, then import
that symbol in axios_response_property_dispatch so the statusText null-pointer
path uses the shared ABI definition.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 433a2c62-3257-4662-a0f3-48d74b57940c

📥 Commits

Reviewing files that changed from the base of the PR and between 6285f55 and 9a4c5fc.

📒 Files selected for processing (5)
  • changelog.d/6852-axios-async-response-properties.md
  • crates/perry-api-manifest/src/emit.rs
  • crates/perry-ext-axios/src/lib.rs
  • docs/api/perry.d.ts
  • tests/release/packages/axios-get/package.json

@TheHypnoo
TheHypnoo force-pushed the fix/axios-async-response-properties branch from 9a4c5fc to d309f8e Compare July 26, 2026 15:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/perry-hir/src/js_transform/local_natives.rs`:
- Line 1349: Update the axios method match in the native response tagging logic
to include head and options alongside get, post, put, delete, patch, and
request, ensuring their results are classified as Response and receive the
existing response-property lowering.

In `@crates/perry-hir/tests/axios_response_property_lowering.rs`:
- Around line 5-44: Add an equivalent cargo-test-visible unit regression test
alongside the local-native lowering implementation, reusing the awaited Axios
response property scenario and assertions from
awaited_axios_response_properties_keep_native_dispatch. Keep the existing
integration test unchanged while ensuring the unit test exercises
fix_local_native_instances and verifies native Response dispatch for both status
and data.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 370c4222-7871-490f-a283-b5be0fe553bc

📥 Commits

Reviewing files that changed from the base of the PR and between 9a4c5fc and d309f8e.

📒 Files selected for processing (9)
  • changelog.d/6852-axios-async-response-properties.md
  • crates/perry-api-manifest/src/emit.rs
  • crates/perry-hir/src/js_transform/local_natives.rs
  • crates/perry-hir/tests/axios_response_property_lowering.rs
  • crates/perry/src/commands/compile/collect_modules.rs
  • docs/api/perry.d.ts
  • tests/release/packages/axios-get/entry.ts
  • tests/release/packages/axios-get/expected.txt
  • tests/release/packages/axios-get/package.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/release/packages/axios-get/package.json
  • crates/perry-api-manifest/src/emit.rs

Comment thread crates/perry-hir/src/js_transform/local_natives.rs Outdated
Comment thread crates/perry-hir/tests/axios_response_property_lowering.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/release/packages/axios-get/entry.ts (1)

28-32: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the HTTP verbs, not only their status codes.

Because the fixture returns 200 for every request to /json, an implementation that routes axios.head or axios.options through GET would still pass. Record req.method or return method-specific responses and assert GET,HEAD,OPTIONS in the fixture output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/release/packages/axios-get/entry.ts` around lines 28 - 32, Update the
`/json` fixture and assertions in the axios request test to verify HTTP methods
rather than status codes alone. Capture `req.method` in the fixture output (or
provide method-specific responses) and assert that the GET, HEAD, and OPTIONS
calls produce `GET`, `HEAD`, and `OPTIONS` respectively, while preserving the
existing status checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/perry-ui-android/src/stdlib_stubs.rs`:
- Around line 71-79: Update js_axios_head and js_axios_options to match the
generated I64 -> I64 ABI by accepting the URL handle parameter and routing each
call through Android’s unsupported/rejected-Promise path; alternatively remove
these stubs if those calls are intentionally unreachable on Android. Do not
return raw 0 as a Promise handle.

---

Nitpick comments:
In `@tests/release/packages/axios-get/entry.ts`:
- Around line 28-32: Update the `/json` fixture and assertions in the axios
request test to verify HTTP methods rather than status codes alone. Capture
`req.method` in the fixture output (or provide method-specific responses) and
assert that the GET, HEAD, and OPTIONS calls produce `GET`, `HEAD`, and
`OPTIONS` respectively, while preserving the existing status checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 75361def-c2c1-4b26-b866-9d9a261ffd6b

📥 Commits

Reviewing files that changed from the base of the PR and between d309f8e and 8102cd6.

📒 Files selected for processing (10)
  • changelog.d/6852-axios-async-response-properties.md
  • crates/perry-codegen/src/lower_call/options/fetch.rs
  • crates/perry-codegen/src/runtime_decls/stdlib_ffi/third_party.rs
  • crates/perry-ext-axios/src/lib.rs
  • crates/perry-hir/src/js_transform/local_natives.rs
  • crates/perry-hir/tests/axios_response_property_lowering.rs
  • crates/perry-stdlib/src/axios.rs
  • crates/perry-ui-android/src/stdlib_stubs.rs
  • tests/release/packages/axios-get/entry.ts
  • tests/release/packages/axios-get/expected.txt
🚧 Files skipped from review as they are similar to previous changes (3)
  • changelog.d/6852-axios-async-response-properties.md
  • crates/perry-hir/tests/axios_response_property_lowering.rs
  • crates/perry-hir/src/js_transform/local_natives.rs

Comment on lines +71 to +79
#[no_mangle]
pub extern "C" fn js_axios_head() -> i64 {
0
}

#[no_mangle]
pub extern "C" fn js_axios_options() -> i64 {
0
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 3 'js_axios_(head|options)' \
  crates/perry-codegen/src/runtime_decls/stdlib_ffi/third_party.rs \
  crates/perry-codegen/src/lower_call/options/fetch.rs \
  crates/perry-ui-android/src/stdlib_stubs.rs

Repository: PerryTS/perry

Length of output: 2771


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== android stdlib stubs relevant section =="
fd -a 'stdlib_stubs.rs' . | sed 's#^\./##' | while read -r f; do
  echo "--- $f"
  wc -l "$f"
  sed -n '1,130p' "$f" | cat -n
done

echo "== android promise/runtime stubs/search for axios handlers =="
rg -n -C 2 'js_axios_(get|head|options)|axios|JsValue|promise|rejection|null|0' crates/perry-ui-android/src || true

echo "== android call/ffi setup search =="
rg -n -C 2 'extern "C"|#[no_mangle]|std::ffi::|CStr|CString|handle|promise|await|JsValue|FfiValue|ReturnType|Return' crates/perry-ui-android/src crates/perry-codegen/src -g '*.rs' | head -n 300

Repository: PerryTS/perry

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate stdlib_stubs.rs =="
fd 'stdlib_stubs.rs' . -t f

echo "== android stdlib_stubs.rs lines 1-140 =="
STUBS=$(fd 'stdlib_stubs.rs' crates/perry-ui-android/src -t f | sort | head -n 1)
if [ -n "$STUBS" ]; then
  wc -l "$STUBS"
  sed -n '1,140p' "$STUBS" | cat -n
fi

echo "== exact axios declarations in perry-codegen =="
sed -n '60,85p' crates/perry-codegen/src/runtime_decls/stdlib_ffi/third_party.rs | cat -n
echo
sed -n '155,180p' crates/perry-codegen/src/lower_call/options/fetch.rs | cat -n

echo "== android promise/extern/ffi stub-related symbols =="
python3 - <<'PY'
from pathlib import Path
root=Path('crates/perry-ui-android/src')
symbols = {'js_axios_get','js_axios_head','js_axios_options','js_axios_create','js_axios_delete','js_make_rejected_promise','js_make_resolved_promise','promise'}
for p in sorted(root.rglob('*.rs')):
    txt=p.read_text(errors='replace')
    hits=[i for i,l in enumerate(txt.splitlines(),1) if any(s in l for s in symbols) or 'fn ' in l and any(s in l.split('(')[0] for s in symbols)]
    if hits:
        print(f'--- {p}')
        for i in hits:
            print(f'{i}: {txt.splitlines()[i-1]}')
PY

echo "== check exported stub functions and call graph =="
rg -n -C 2 'pub extern "C" fn (js_axios_get|js_axios_head|js_axios_options|js_axios_create|js_axios_delete)|fn js_make.*promise|call.*js_axios|axios_handle|axios.*promise|nanbox_pointer' crates/perry-ui-android/src crates -g '*.rs' | head -n 500

Repository: PerryTS/perry

Length of output: 49076


Match the Android Axios stubs to the generated call ABI.

js_axios_head and js_axios_options are generated with an I64 -> I64 call passing the URL handle, but these no-op stubs are () -> i64, so the URL is discarded and the returned raw 0 is NaN-boxed as a Promise handle. Add the unused i64 parameter and route through Android’s unsupported/rejected-Promise path, or remove these from the stdlib stubs if the calls are intentionally unreachable on Android.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/perry-ui-android/src/stdlib_stubs.rs` around lines 71 - 79, Update
js_axios_head and js_axios_options to match the generated I64 -> I64 ABI by
accepting the URL handle parameter and routing each call through Android’s
unsupported/rejected-Promise path; alternatively remove these stubs if those
calls are intentionally unreachable on Android. Do not return raw 0 as a Promise
handle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Confirmed defect or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Axios default import loses methods and async response properties resolve undefined

1 participant